}
}
+ [Fact]
+ public static void BasicConstraints_ExceedMaximumPathLength()
+ {
+ X509Extension[] rootExtensions = new [] {
+ new X509BasicConstraintsExtension(
+ certificateAuthority: true,
+ hasPathLengthConstraint: true,
+ pathLengthConstraint: 0,
+ critical: true)
+ };
+
+ X509Extension[] intermediateExtensions = new [] {
+ new X509BasicConstraintsExtension(
+ certificateAuthority: true,
+ hasPathLengthConstraint: true,
+ pathLengthConstraint: 0,
+ critical: true)
+ };
+
+ TestDataGenerator.MakeTestChain4(
+ out X509Certificate2 endEntityCert,
+ out X509Certificate2 intermediateCert1,
+ out X509Certificate2 intermediateCert2,
+ out X509Certificate2 rootCert,
+ rootExtensions: rootExtensions,
+ intermediateExtensions: intermediateExtensions);
+
+ using (endEntityCert)
+ using (intermediateCert1)
+ using (intermediateCert2)
+ using (rootCert)
+ using (ChainHolder chainHolder = new ChainHolder())
+ {
+ X509Chain chain = chainHolder.Chain;
+ chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
+ chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1);
+ chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
+ chain.ChainPolicy.CustomTrustStore.Add(rootCert);
+ chain.ChainPolicy.ExtraStore.Add(intermediateCert1);
+ chain.ChainPolicy.ExtraStore.Add(intermediateCert2);
+
+ Assert.False(chain.Build(endEntityCert));
+ Assert.Equal(X509ChainStatusFlags.InvalidBasicConstraints, chain.AllStatusFlags());
+ }
+ }
+
+ [Fact]
+ public static void BasicConstraints_ViolatesCaFalse()
+ {
+ X509Extension[] intermediateExtensions = new [] {
+ new X509BasicConstraintsExtension(
+ certificateAuthority: false,
+ hasPathLengthConstraint: false,
+ pathLengthConstraint: 0,
+ critical: true)
+ };
+
+ TestDataGenerator.MakeTestChain3(
+ out X509Certificate2 endEntityCert,
+ out X509Certificate2 intermediateCert,
+ out X509Certificate2 rootCert,
+ intermediateExtensions: intermediateExtensions);
+
+ using (endEntityCert)
+ using (intermediateCert)
+ using (rootCert)
+ using (ChainHolder chainHolder = new ChainHolder())
+ {
+ X509Chain chain = chainHolder.Chain;
+ chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
+ chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1);
+ chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
+ chain.ChainPolicy.CustomTrustStore.Add(rootCert);
+ chain.ChainPolicy.ExtraStore.Add(intermediateCert);
+
+ Assert.False(chain.Build(endEntityCert));
+ Assert.Equal(X509ChainStatusFlags.InvalidBasicConstraints, chain.AllStatusFlags());
+ }
+ }
+
[Fact]
public static void TestInvalidAia()
{
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
+
namespace System.Security.Cryptography.X509Certificates.Tests
{
internal static class TestDataGenerator
internal static void MakeTestChain3(
out X509Certificate2 endEntityCert,
out X509Certificate2 intermediateCert,
- out X509Certificate2 rootCert)
+ out X509Certificate2 rootCert,
+ IEnumerable<X509Extension> endEntityExtensions = null,
+ IEnumerable<X509Extension> intermediateExtensions = null,
+ IEnumerable<X509Extension> rootExtensions = null)
{
using (RSA rootKey = RSA.Create())
using (RSA intermediateKey = RSA.Create())
};
Span<X509Certificate2> certs = new X509Certificate2[keys.Length];
- MakeTestChain(keys, certs);
+ MakeTestChain(
+ keys,
+ certs,
+ endEntityExtensions,
+ intermediateExtensions,
+ rootExtensions);
endEntityCert = certs[0];
intermediateCert = certs[1];
}
}
+
+ internal static void MakeTestChain4(
+ out X509Certificate2 endEntityCert,
+ out X509Certificate2 intermediateCert1,
+ out X509Certificate2 intermediateCert2,
+ out X509Certificate2 rootCert,
+ IEnumerable<X509Extension> endEntityExtensions = null,
+ IEnumerable<X509Extension> intermediateExtensions = null,
+ IEnumerable<X509Extension> rootExtensions = null)
+ {
+ using (RSA rootKey = RSA.Create())
+ using (RSA intermediateKey = RSA.Create())
+ using (RSA endEntityKey = RSA.Create())
+ {
+ ReadOnlySpan<RSA> keys = new[]
+ {
+ rootKey,
+ intermediateKey,
+ intermediateKey,
+ endEntityKey,
+ };
+
+ Span<X509Certificate2> certs = new X509Certificate2[keys.Length];
+ MakeTestChain(
+ keys,
+ certs,
+ endEntityExtensions,
+ intermediateExtensions,
+ rootExtensions);
+
+ endEntityCert = certs[0];
+ intermediateCert1 = certs[1];
+ intermediateCert2 = certs[2];
+ rootCert = certs[3];
+ }
+ }
+
internal static void MakeTestChain(
ReadOnlySpan<RSA> keys,
Span<X509Certificate2> certs,
- string eeName = "CN=End-Entity",
- OidCollection eeEku = null)
+ IEnumerable<X509Extension> endEntityExtensions,
+ IEnumerable<X509Extension> intermediateExtensions,
+ IEnumerable<X509Extension> rootExtensions)
{
if (keys.Length < 2)
throw new ArgumentException(nameof(keys));
if (keys.Length != certs.Length)
throw new ArgumentException(nameof(certs));
- if (string.IsNullOrEmpty(eeName))
- throw new ArgumentOutOfRangeException(nameof(eeName));
-
- var caUnlimited = new X509BasicConstraintsExtension(true, false, 0, true);
- var eeConstraint = new X509BasicConstraintsExtension(false, false, 0, true);
- var caUsage = new X509KeyUsageExtension(
- X509KeyUsageFlags.CrlSign |
- X509KeyUsageFlags.KeyCertSign |
- X509KeyUsageFlags.DigitalSignature,
- false);
-
- var eeUsage = new X509KeyUsageExtension(
+ rootExtensions ??= new X509Extension[] {
+ new X509BasicConstraintsExtension(true, false, 0, true),
+ new X509KeyUsageExtension(
+ X509KeyUsageFlags.CrlSign |
+ X509KeyUsageFlags.KeyCertSign |
+ X509KeyUsageFlags.DigitalSignature,
+ false)
+ };
+
+ intermediateExtensions ??= new X509Extension[] {
+ new X509BasicConstraintsExtension(true, false, 0, true),
+ new X509KeyUsageExtension(
+ X509KeyUsageFlags.CrlSign |
+ X509KeyUsageFlags.KeyCertSign |
+ X509KeyUsageFlags.DigitalSignature,
+ false)
+ };
+
+ endEntityExtensions ??= new X509Extension[] {
+ new X509BasicConstraintsExtension(false, false, 0, true),
+ new X509KeyUsageExtension(
X509KeyUsageFlags.DigitalSignature |
X509KeyUsageFlags.NonRepudiation |
X509KeyUsageFlags.KeyEncipherment,
- false);
+ false)
+ };
TimeSpan notBeforeInterval = TimeSpan.FromDays(30);
TimeSpan notAfterInterval = TimeSpan.FromDays(90);
hashAlgorithm,
signaturePadding);
- rootReq.CertificateExtensions.Add(caUnlimited);
- rootReq.CertificateExtensions.Add(caUsage);
+ foreach (X509Extension extension in rootExtensions)
+ {
+ rootReq.CertificateExtensions.Add(extension);
+ }
+
+ X509SignatureGenerator lastGenerator = X509SignatureGenerator.CreateForRSA(keys[rootIndex], RSASignaturePadding.Pkcs1);
+ X500DistinguishedName lastSubject = rootReq.SubjectName;
- X509Certificate2 lastWithKey = rootReq.CreateSelfSigned(
+ certs[rootIndex] = rootReq.Create(
+ lastSubject,
+ lastGenerator,
eeStart - (notBeforeInterval * rootIndex),
- eeEnd + (notAfterInterval * rootIndex));
-
- certs[rootIndex] = new X509Certificate2(lastWithKey.RawData);
+ eeEnd + (notAfterInterval * rootIndex),
+ CreateSerial());
int presentationNumber = 0;
hashAlgorithm,
signaturePadding);
- intermediateReq.CertificateExtensions.Add(caUnlimited);
- intermediateReq.CertificateExtensions.Add(caUsage);
-
- // Leave serialBuf[0] as 0 to avoid a realloc in the signer
- RandomNumberGenerator.Fill(serialBuf.AsSpan(1));
+ foreach (X509Extension extension in intermediateExtensions)
+ {
+ intermediateReq.CertificateExtensions.Add(extension);
+ }
certs[i] = intermediateReq.Create(
- lastWithKey,
+ lastSubject,
+ lastGenerator,
eeStart - (notBeforeInterval * i),
eeEnd + (notAfterInterval * i),
- serialBuf);
+ CreateSerial());
- lastWithKey.Dispose();
- lastWithKey = certs[i].CopyWithPrivateKey(keys[i]);
+ lastSubject = intermediateReq.SubjectName;
+ lastGenerator = X509SignatureGenerator.CreateForRSA(keys[i], RSASignaturePadding.Pkcs1);
}
CertificateRequest eeReq = new CertificateRequest(
- eeName,
+ "CN=End-Entity",
keys[0],
hashAlgorithm,
signaturePadding);
- eeReq.CertificateExtensions.Add(eeConstraint);
- eeReq.CertificateExtensions.Add(eeUsage);
-
- if (eeEku != null)
+ foreach (X509Extension extension in endEntityExtensions)
{
- eeReq.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(eeEku, false));
+ eeReq.CertificateExtensions.Add(extension);
}
- // Leave serialBuf[0] as 0 to avoid a realloc in the signer
- RandomNumberGenerator.Fill(serialBuf.AsSpan(1));
+ certs[0] = eeReq.Create(lastSubject, lastGenerator, eeStart, eeEnd, CreateSerial());
+ }
- certs[0] = eeReq.Create(lastWithKey, eeStart, eeEnd, serialBuf);
- lastWithKey.Dispose();
+ private static byte[] CreateSerial()
+ {
+ byte[] bytes = new byte[8];
+ RandomNumberGenerator.Fill(bytes);
+ return bytes;
}
}
}