diff --git a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs index 1cb4e8a290f1df..45f7a784fdd4fd 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs @@ -69,14 +69,6 @@ internal sealed class CertificateAuthority : IDisposable }, critical: false); - private static readonly X509EnhancedKeyUsageExtension s_tlsServerEku = - new X509EnhancedKeyUsageExtension( - new OidCollection - { - new Oid("1.3.6.1.5.5.7.3.1", null) - }, - false); - private static readonly X509EnhancedKeyUsageExtension s_tlsClientEku = new X509EnhancedKeyUsageExtension( new OidCollection @@ -106,6 +98,11 @@ internal sealed class CertificateAuthority : IDisposable internal DateTimeOffset? RevocationExpiration { get; set; } internal bool CorruptRevocationIssuerName { get; set; } + // All keys created in this method are smaller than recommended, + // but they only live for a few seconds (at most), + // and never communicate out of process. + const int DefaultKeySize = 1024; + internal CertificateAuthority( X509Certificate2 cert, string aiaHttpUrl, @@ -159,25 +156,22 @@ internal X509Certificate2 CreateSubordinateCA( subject, publicKey, TimeSpan.FromMinutes(1), - new X509BasicConstraintsExtension( - certificateAuthority: true, - depthLimit.HasValue, - depthLimit.GetValueOrDefault(), - critical: true), - s_caKeyUsage, - ekuExtension: null); + new X509ExtensionCollection() { + new X509BasicConstraintsExtension( + certificateAuthority: true, + depthLimit.HasValue, + depthLimit.GetValueOrDefault(), + critical: true), + s_caKeyUsage }); } - internal X509Certificate2 CreateEndEntity(string subject, RSA publicKey, X509Extension altName) + internal X509Certificate2 CreateEndEntity(string subject, RSA publicKey, X509ExtensionCollection extensions) { return CreateCertificate( subject, publicKey, TimeSpan.FromSeconds(2), - s_eeConstraints, - s_eeKeyUsage, - s_tlsServerEku, - altName: altName); + extensions); } internal X509Certificate2 CreateOcspSigner(string subject, RSA publicKey) @@ -186,9 +180,7 @@ internal X509Certificate2 CreateOcspSigner(string subject, RSA publicKey) subject, publicKey, TimeSpan.FromSeconds(1), - s_eeConstraints, - s_eeKeyUsage, - s_ocspResponderEku, + new X509ExtensionCollection() { s_eeConstraints, s_eeKeyUsage, s_ocspResponderEku}, ocspResponder: true); } @@ -248,11 +240,8 @@ private X509Certificate2 CreateCertificate( string subject, RSA publicKey, TimeSpan nestingBuffer, - X509BasicConstraintsExtension basicConstraints, - X509KeyUsageExtension keyUsage, - X509EnhancedKeyUsageExtension ekuExtension, - bool ocspResponder = false, - X509Extension altName = null) + X509ExtensionCollection extensions, + bool ocspResponder = false) { if (_cdpExtension == null && CdpUri != null) { @@ -275,8 +264,10 @@ private X509Certificate2 CreateCertificate( HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); - request.CertificateExtensions.Add(basicConstraints); - request.CertificateExtensions.Add(keyUsage); + foreach (X509Extension extension in extensions) + { + request.CertificateExtensions.Add(extension); + } // Windows does not accept OCSP Responder certificates which have // a CDP extension, or an AIA extension with an OCSP endpoint. @@ -290,16 +281,6 @@ private X509Certificate2 CreateCertificate( request.CertificateExtensions.Add( new X509SubjectKeyIdentifierExtension(request.PublicKey, false)); - if (ekuExtension != null) - { - request.CertificateExtensions.Add(ekuExtension); - } - - if (altName != null) - { - request.CertificateExtensions.Add(altName); - } - byte[] serial = new byte[sizeof(long)]; RandomNumberGenerator.Fill(serial); @@ -841,7 +822,9 @@ internal static void BuildPrivatePki( string testName = null, bool registerAuthorities = true, bool pkiOptionsInSubject = false, - string subjectName = null) + string subjectName = null, + int keySize = DefaultKeySize, + X509ExtensionCollection extensions = null) { bool rootDistributionViaHttp = !pkiOptions.HasFlag(PkiOptions.NoRootCertDistributionUri); bool issuerRevocationViaCrl = pkiOptions.HasFlag(PkiOptions.IssuerRevocationViaCrl); @@ -855,14 +838,15 @@ internal static void BuildPrivatePki( endEntityRevocationViaCrl || endEntityRevocationViaOcsp, "At least one revocation mode is enabled"); - // All keys created in this method are smaller than recommended, - // but they only live for a few seconds (at most), - // and never communicate out of process. - const int KeySize = 1024; + if (extensions == null) + { + // default to client + extensions = new X509ExtensionCollection() { s_eeConstraints, s_eeKeyUsage, s_tlsClientEku }; + } - using (RSA rootKey = RSA.Create(KeySize)) - using (RSA intermedKey = RSA.Create(KeySize)) - using (RSA eeKey = RSA.Create(KeySize)) + using (RSA rootKey = RSA.Create(keySize)) + using (RSA intermedKey = RSA.Create(keySize)) + using (RSA eeKey = RSA.Create(keySize)) { var rootReq = new CertificateRequest( BuildSubject("A Revocation Test Root", testName, pkiOptions, pkiOptionsInSubject), @@ -920,19 +904,11 @@ internal static void BuildPrivatePki( endEntityRevocationViaCrl ? cdpUrl : null, endEntityRevocationViaOcsp ? ocspUrl : null); - X509Extension altName = null; - - if (!String.IsNullOrEmpty(subjectName)) - { - SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder(); - builder.AddDnsName(subjectName); - altName = builder.Build(); - } - endEntityCert = intermediateAuthority.CreateEndEntity( - BuildSubject(subjectName ?? "A Revocation Test Cert", testName, pkiOptions, pkiOptionsInSubject), - eeKey, - altName); + BuildSubject(subjectName ?? "A Revocation Test Cert", testName, pkiOptions, pkiOptionsInSubject), + eeKey, + extensions); + endEntityCert = endEntityCert.CopyWithPrivateKey(eeKey); } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs index 5d95d0826ec622..2aac8a37a05422 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs @@ -14,6 +14,22 @@ namespace System.Net.Security.Tests { public static class TestHelper { + private static readonly X509KeyUsageExtension s_eeKeyUsage = + new X509KeyUsageExtension( + X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DataEncipherment, + critical: false); + + private static readonly X509EnhancedKeyUsageExtension s_tlsServerEku = + new X509EnhancedKeyUsageExtension( + new OidCollection + { + new Oid("1.3.6.1.5.5.7.3.1", null) + }, + false); + + private static readonly X509BasicConstraintsExtension s_eeConstraints = + new X509BasicConstraintsExtension(false, false, 0, false); + public static (Stream ClientStream, Stream ServerStream) GetConnectedStreams() { if (Capability.SecurityForceSocketStreams()) @@ -54,6 +70,15 @@ internal static (X509Certificate2 certificate, X509Certificate2Collection) Gener { X509Certificate2Collection chain = new X509Certificate2Collection(); + X509ExtensionCollection extensions = new X509ExtensionCollection(); + + SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder(); + builder.AddDnsName(name); + extensions.Add(builder.Build()); + extensions.Add(s_eeConstraints); + extensions.Add(s_eeKeyUsage); + extensions.Add(s_tlsServerEku); + CertificateAuthority.BuildPrivatePki( PkiOptions.IssuerRevocationViaCrl, out RevocationResponder responder, @@ -61,7 +86,9 @@ internal static (X509Certificate2 certificate, X509Certificate2Collection) Gener out CertificateAuthority intermediate, out X509Certificate2 endEntity, subjectName: name, - testName: testName); + testName: testName, + keySize: 2048, + extensions: extensions); chain.Add(intermediate.CloneIssuerCert()); chain.Add(root.CloneIssuerCert());