From 33488cdeee7c47f1eb8e4e36c97339fedf03af52 Mon Sep 17 00:00:00 2001 From: Tomas Weinfurt Date: Fri, 19 Jun 2020 17:46:07 -0700 Subject: [PATCH 1/4] add two SslStream tests for custom validation --- .../src/System/Net/Security/SecureChannel.cs | 1 - .../SslStreamNetworkStreamTest.cs | 69 +++++++++ .../tests/FunctionalTests/TestHelper.cs | 137 +++++++++++++++++- 3 files changed, 204 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SecureChannel.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SecureChannel.cs index 8b7e39f46c3c24..6fa02ac621ecec 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SecureChannel.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SecureChannel.cs @@ -1195,7 +1195,6 @@ private static TlsAlertMessage GetAlertMessageFromChain(X509Chain chain) return TlsAlertMessage.CertificateUnknown; } - Debug.Fail("GetAlertMessageFromChain was called but none of the chain elements had errors."); return TlsAlertMessage.BadCertificate; } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index 8aaf5439430471..419c4bc57ff8dc 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -17,6 +17,14 @@ namespace System.Net.Security.Tests public class SslStreamNetworkStreamTest { + private readonly X509Certificate2 _serverCert; + private readonly X509CertificateCollection _serverChain; + + public SslStreamNetworkStreamTest() + { + (_serverCert, _serverChain) = TestHelper.GenerateCertificates("localhost", DateTimeOffset.UtcNow.AddMinutes(-5)); + } + [Fact] public async Task SslStream_SendReceiveOverNetworkStream_Ok() { @@ -193,6 +201,67 @@ public async Task SslStream_NestedAuth_Throws() } } + [Fact] + public async Task SslStream_UntrustedCaWithCustomCallback_OK() + { + var options = new SslClientAuthenticationOptions() { TargetHost = "localhost" }; + options.RemoteCertificateValidationCallback = + (sender, certificate, chain, sslPolicyErrors) => + { + chain.ChainPolicy.ExtraStore.AddRange(_serverChain); + chain.ChainPolicy.CustomTrustStore.Add(_serverChain[_serverChain.Count -1]); + chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; + + bool result = chain.Build((X509Certificate2)certificate); + Assert.True(result); + + return result; + }; + + (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); + using (clientStream) + using (serverStream) + using (SslStream client = new SslStream(clientStream)) + using (SslStream server = new SslStream(serverStream)) + { + Task t1 = client.AuthenticateAsClientAsync(options, default); + Task t2 = server.AuthenticateAsServerAsync(_serverCert); + + await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); + } + } + + [Fact] + public async Task SslStream_UntrustedCaWithCustomCallback_Throws() + { + var options = new SslClientAuthenticationOptions() { TargetHost = "localhost" }; + options.RemoteCertificateValidationCallback = + (sender, certificate, chain, sslPolicyErrors) => + { + chain.ChainPolicy.ExtraStore.AddRange(_serverChain); + chain.ChainPolicy.CustomTrustStore.Add(_serverChain[_serverChain.Count -1]); + chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; + // This should work and we should be able to trust the chain. + Assert.True(chain.Build((X509Certificate2)certificate)); + // Reject it in custom callback to simulate for example pinning. + return false; + }; + + (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); + using (clientStream) + using (serverStream) + using (SslStream client = new SslStream(clientStream)) + using (SslStream server = new SslStream(serverStream)) + { + Task t1 = client.AuthenticateAsClientAsync(options, default); + Task t2 = server.AuthenticateAsServerAsync(_serverCert); + + await Assert.ThrowsAsync(() => t1); + // Server side should finish since we run custom callback after handshake is done. + await t2; + } + } + private static bool ValidateServerCertificate( object sender, X509Certificate retrievedServerPublicCertificate, diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs index fb8d77d5bb4e3e..f27aaa5d265a36 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs @@ -2,11 +2,12 @@ // 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; using System.IO; -using System.Net; using System.Net.Sockets; using System.Net.Test.Common; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; namespace System.Net.Security.Tests { @@ -47,5 +48,137 @@ internal static (VirtualNetworkStream ClientStream, VirtualNetworkStream ServerS return (new VirtualNetworkStream(vn, isServer: false), new VirtualNetworkStream(vn, isServer: true)); } + + internal static (X509Certificate2 certificate, X509Certificate2Collection) GenerateCertificates(string name, DateTimeOffset startTime, string? caUrl = null) + { + X509Certificate2Collection chain = new X509Certificate2Collection(); + + using (RSA root = RSA.Create()) + using (RSA intermediate = RSA.Create()) + using (RSA server = RSA.Create()) + { + CertificateRequest rootReq = new CertificateRequest( + "CN=Root", + root, + HashAlgorithmName.SHA256, + RSASignaturePadding.Pkcs1); + + rootReq.CertificateExtensions.Add( + new X509BasicConstraintsExtension(true, false, 0, true)); + rootReq.CertificateExtensions.Add( + new X509SubjectKeyIdentifierExtension(rootReq.PublicKey, false)); + rootReq.CertificateExtensions.Add( + new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign, false)); + + //DateTimeOffset start = DateTimeOffset.UtcNow.AddMinutes(-5); + DateTimeOffset endTime = startTime.AddMonths(1); + + X509Certificate2 rootCertWithKey = rootReq.CreateSelfSigned(startTime, endTime); + + CertificateRequest intermedReq = new CertificateRequest( + "CN=Intermediate", + intermediate, + HashAlgorithmName.SHA256, + RSASignaturePadding.Pkcs1); + + intermedReq.CertificateExtensions.Add( + new X509BasicConstraintsExtension(true, false, 0, true)); + intermedReq.CertificateExtensions.Add( + new X509SubjectKeyIdentifierExtension(intermedReq.PublicKey, false)); + intermedReq.CertificateExtensions.Add( + new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign, false)); + + byte[] serial = new byte[8]; + RandomNumberGenerator.Fill(serial); + + X509Certificate2 intermedCertWithKey; + using (X509Certificate2 intermedPub = intermedReq.Create(rootCertWithKey, startTime, endTime, serial)) + { + intermedCertWithKey = intermedPub.CopyWithPrivateKey(intermediate); + } + + CertificateRequest serverReq = new CertificateRequest( + $"CN={name}", + server, + HashAlgorithmName.SHA256, + RSASignaturePadding.Pkcs1); + + serverReq.CertificateExtensions.Add( + new X509BasicConstraintsExtension(false, false, 0, false)); + serverReq.CertificateExtensions.Add( + new X509SubjectKeyIdentifierExtension(serverReq.PublicKey, false)); + + // Add Issuer KeyIdentifier + using (SHA1 sha1 = SHA1.Create()) + { + byte[] data = new byte[24]; + data[0] = 0x30; //SEQUENCE + data[1] = 22; + data[2] = 0x80; + data[3] = 20; + Buffer.BlockCopy(sha1.ComputeHash(intermedCertWithKey.PublicKey.EncodedKeyValue.RawData), 0, data, 4, 20); + serverReq.CertificateExtensions.Add(new X509Extension(new Oid("2.5.29.35"), data, false)); + } + + // 1.3.6.1.5.5.7.1.1 + if (caUrl != null) + { + var urlBytes = Encoding.ASCII.GetBytes(caUrl); + + byte[] data = new byte[urlBytes.Length + 16]; + data[0] = 0x30; //SEQUENCE + data[1] = (byte)(urlBytes.Length + 14); + data[2] = 0x30; //SEQUENCE; + data[3] = (byte)(urlBytes.Length + 12); + data[4] = 6; // OBJECT + data[5] = 8; // LENGTH + // OID + data[6] = 0x2b; + data[7] = 0x6; + data[8] = 0x1; + data[9] = 0x5; + data[10] = 0x5; + data[11] = 0x7; + data[12] = 0x30; // SEQUENCE + data[13] = 02; + data[14] = 0x86; + data[15] = (byte)(urlBytes.Length); + data[16] = 0x74; + data[17] = 0x74; + data[18] = 0x70; + Buffer.BlockCopy(urlBytes, 0, data, 16, urlBytes.Length); + + serverReq.CertificateExtensions.Add(new X509Extension(new Oid("1.3.6.1.5.5.7.1.1"), data, false)); + } + + serverReq.CertificateExtensions.Add( + new X509KeyUsageExtension( + X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DataEncipherment, + false)); + serverReq.CertificateExtensions.Add( + new X509EnhancedKeyUsageExtension( + new OidCollection() + { + new Oid("1.3.6.1.5.5.7.3.1", null), + }, + false)); + + SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder(); + builder.AddDnsName(name); + builder.AddIpAddress(IPAddress.Loopback); + builder.AddIpAddress(IPAddress.IPv6Loopback); + serverReq.CertificateExtensions.Add(builder.Build()); + + RandomNumberGenerator.Fill(serial); + + X509Certificate2 serverCert = serverReq.Create(intermedCertWithKey, startTime, endTime, serial); + X509Certificate2 serverCertWithKey = serverCert.CopyWithPrivateKey(server); + + chain.Add(intermedCertWithKey); + chain.Add(rootCertWithKey); + + return (serverCertWithKey, chain); + } + } } } From 11aae3808813d5fd67a81422b0fdf518b950848e Mon Sep 17 00:00:00 2001 From: Tomas Weinfurt Date: Sat, 27 Jun 2020 22:02:36 -0700 Subject: [PATCH 2/4] use BuildPrivatePki --- .../X509Certificates}/CertificateAuthority.cs | 175 +++++++++++++++++- .../X509Certificates}/RevocationResponder.cs | 5 +- .../SslStreamNetworkStreamTest.cs | 2 +- .../System.Net.Security.Tests.csproj | 4 + .../tests/FunctionalTests/TestHelper.cs | 140 ++------------ .../tests/RevocationTests/AiaTests.cs | 5 +- .../RevocationTests/DynamicRevocationTests.cs | 127 +------------ ...Cryptography.X509Certificates.Tests.csproj | 6 +- 8 files changed, 205 insertions(+), 259 deletions(-) rename src/libraries/{System.Security.Cryptography.X509Certificates/tests/RevocationTests => Common/tests/System/Security/Cryptography/X509Certificates}/CertificateAuthority.cs (78%) rename src/libraries/{System.Security.Cryptography.X509Certificates/tests/RevocationTests => Common/tests/System/Security/Cryptography/X509Certificates}/RevocationResponder.cs (98%) diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/CertificateAuthority.cs b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs similarity index 78% rename from src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/CertificateAuthority.cs rename to src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs index 2f2666ebeeb86c..dcab14b8fe07ba 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/CertificateAuthority.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs @@ -7,7 +7,7 @@ using System.Linq; using Xunit; -namespace System.Security.Cryptography.X509Certificates.Tests.RevocationTests +namespace System.Security.Cryptography.X509Certificates.Tests.Common { // This class represents only a portion of what is required to be a proper Certificate Authority. // @@ -15,6 +15,29 @@ namespace System.Security.Cryptography.X509Certificates.Tests.RevocationTests // without understanding all of the portions of proper CA management that you're skipping. // // At minimum, read the current baseline requirements of the CA/Browser Forum. + + [Flags] + public enum PkiOptions + { + None = 0, + + IssuerRevocationViaCrl = 1 << 0, + IssuerRevocationViaOcsp = 1 << 1, + EndEntityRevocationViaCrl = 1 << 2, + EndEntityRevocationViaOcsp = 1 << 3, + + CrlEverywhere = IssuerRevocationViaCrl | EndEntityRevocationViaCrl, + OcspEverywhere = IssuerRevocationViaOcsp | EndEntityRevocationViaOcsp, + AllIssuerRevocation = IssuerRevocationViaCrl | IssuerRevocationViaOcsp, + AllEndEntityRevocation = EndEntityRevocationViaCrl | EndEntityRevocationViaOcsp, + AllRevocation = CrlEverywhere | OcspEverywhere, + + IssuerAuthorityHasDesignatedOcspResponder = 1 << 16, + RootAuthorityHasDesignatedOcspResponder = 1 << 17, + NoIssuerCertDistributionUri = 1 << 18, + NoRootCertDistributionUri = 1 << 18, + } + internal sealed class CertificateAuthority : IDisposable { private static readonly Asn1Tag s_context0 = new Asn1Tag(TagClass.ContextSpecific, 0); @@ -35,7 +58,7 @@ internal sealed class CertificateAuthority : IDisposable private static readonly X509KeyUsageExtension s_eeKeyUsage = new X509KeyUsageExtension( - X509KeyUsageFlags.DigitalSignature, + X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DataEncipherment, critical: false); private static readonly X509EnhancedKeyUsageExtension s_ocspResponderEku = @@ -46,6 +69,14 @@ 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 @@ -137,7 +168,7 @@ internal X509Certificate2 CreateSubordinateCA( ekuExtension: null); } - internal X509Certificate2 CreateEndEntity(string subject, RSA publicKey) + internal X509Certificate2 CreateEndEntity(string subject, RSA publicKey, X509Extension altName) { return CreateCertificate( subject, @@ -145,7 +176,8 @@ internal X509Certificate2 CreateEndEntity(string subject, RSA publicKey) TimeSpan.FromSeconds(2), s_eeConstraints, s_eeKeyUsage, - s_tlsClientEku); + s_tlsServerEku, + altName: altName); } internal X509Certificate2 CreateOcspSigner(string subject, RSA publicKey) @@ -219,7 +251,8 @@ private X509Certificate2 CreateCertificate( X509BasicConstraintsExtension basicConstraints, X509KeyUsageExtension keyUsage, X509EnhancedKeyUsageExtension ekuExtension, - bool ocspResponder = false) + bool ocspResponder = false, + X509Extension altName = null) { if (_cdpExtension == null && CdpUri != null) { @@ -262,6 +295,12 @@ private X509Certificate2 CreateCertificate( request.CertificateExtensions.Add(ekuExtension); } + if (altName != null) + { + request.CertificateExtensions.Add(altName); + } + + byte[] serial = new byte[sizeof(long)]; RandomNumberGenerator.Fill(serial); @@ -793,5 +832,131 @@ private enum CertStatus OK, Revoked, } + + internal static void BuildPrivatePki( + PkiOptions pkiOptions, + out RevocationResponder responder, + out CertificateAuthority rootAuthority, + out CertificateAuthority intermediateAuthority, + out X509Certificate2 endEntityCert, + string testName = null, + bool registerAuthorities = true, + bool pkiOptionsInSubject = false, + string subjectName = null) + { + bool rootDistributionViaHttp = !pkiOptions.HasFlag(PkiOptions.NoRootCertDistributionUri); + bool issuerRevocationViaCrl = pkiOptions.HasFlag(PkiOptions.IssuerRevocationViaCrl); + bool issuerRevocationViaOcsp = pkiOptions.HasFlag(PkiOptions.IssuerRevocationViaOcsp); + bool issuerDistributionViaHttp = !pkiOptions.HasFlag(PkiOptions.NoIssuerCertDistributionUri); + bool endEntityRevocationViaCrl = pkiOptions.HasFlag(PkiOptions.EndEntityRevocationViaCrl); + bool endEntityRevocationViaOcsp = pkiOptions.HasFlag(PkiOptions.EndEntityRevocationViaOcsp); + + Assert.True( + issuerRevocationViaCrl || issuerRevocationViaOcsp || + 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; + + 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), + rootKey, + HashAlgorithmName.SHA256, + RSASignaturePadding.Pkcs1); + + X509BasicConstraintsExtension caConstraints = + new X509BasicConstraintsExtension(true, false, 0, true); + + rootReq.CertificateExtensions.Add(caConstraints); + var rootSkid = new X509SubjectKeyIdentifierExtension(rootReq.PublicKey, false); + rootReq.CertificateExtensions.Add( + rootSkid); + + DateTimeOffset start = DateTimeOffset.UtcNow; + DateTimeOffset end = start.AddMonths(3); + + // Don't dispose this, it's being transferred to the CertificateAuthority + X509Certificate2 rootCert = rootReq.CreateSelfSigned(start.AddDays(-2), end.AddDays(2)); + responder = RevocationResponder.CreateAndListen(); + + string certUrl = $"{responder.UriPrefix}cert/{rootSkid.SubjectKeyIdentifier}.cer"; + string cdpUrl = $"{responder.UriPrefix}crl/{rootSkid.SubjectKeyIdentifier}.crl"; + string ocspUrl = $"{responder.UriPrefix}ocsp/{rootSkid.SubjectKeyIdentifier}"; + + rootAuthority = new CertificateAuthority( + rootCert, + rootDistributionViaHttp ? certUrl : null, + issuerRevocationViaCrl ? cdpUrl : null, + issuerRevocationViaOcsp ? ocspUrl : null); + + // Don't dispose this, it's being transferred to the CertificateAuthority + X509Certificate2 intermedCert; + + { + X509Certificate2 intermedPub = rootAuthority.CreateSubordinateCA( + BuildSubject("A Revocation Test CA", testName, pkiOptions, pkiOptionsInSubject), + intermedKey); + + intermedCert = intermedPub.CopyWithPrivateKey(intermedKey); + intermedPub.Dispose(); + } + + X509SubjectKeyIdentifierExtension intermedSkid = + intermedCert.Extensions.OfType().Single(); + + certUrl = $"{responder.UriPrefix}cert/{intermedSkid.SubjectKeyIdentifier}.cer"; + cdpUrl = $"{responder.UriPrefix}crl/{intermedSkid.SubjectKeyIdentifier}.crl"; + ocspUrl = $"{responder.UriPrefix}ocsp/{intermedSkid.SubjectKeyIdentifier}"; + + intermediateAuthority = new CertificateAuthority( + intermedCert, + issuerDistributionViaHttp ? certUrl : null, + 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); + endEntityCert = endEntityCert.CopyWithPrivateKey(eeKey); + } + + if (registerAuthorities) + { + responder.AddCertificateAuthority(rootAuthority); + responder.AddCertificateAuthority(intermediateAuthority); + } + } + + private static string BuildSubject( + string cn, + string testName, + PkiOptions pkiOptions, + bool includePkiOptions) + { + if (includePkiOptions) + { + return $"CN=\"{cn}\", O=\"{testName}\", OU=\"{pkiOptions}\""; + } + + return $"CN=\"{cn}\", O=\"{testName}\""; + } } } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/RevocationResponder.cs b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs similarity index 98% rename from src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/RevocationResponder.cs rename to src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs index e3de12320d7923..f08c4439674704 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/RevocationResponder.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs @@ -5,11 +5,12 @@ using System.Collections.Generic; using System.Formats.Asn1; using System.Net; +using System.Security.Cryptography.X509Certificates.Tests.Common; using System.Threading; using System.Threading.Tasks; using System.Web; -namespace System.Security.Cryptography.X509Certificates.Tests.RevocationTests +namespace System.Security.Cryptography.X509Certificates.Tests.Common { internal sealed class RevocationResponder : IDisposable { @@ -292,7 +293,7 @@ private static void DecodeOcspRequest( if (!versionReader.TryReadInt32(out int version) || version != 0) { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + throw new CryptographicException("ASN1 corrupted data"); } versionReader.ThrowIfNotEmpty(); diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index 419c4bc57ff8dc..f807a75542f2d7 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -22,7 +22,7 @@ public class SslStreamNetworkStreamTest public SslStreamNetworkStreamTest() { - (_serverCert, _serverChain) = TestHelper.GenerateCertificates("localhost", DateTimeOffset.UtcNow.AddMinutes(-5)); + (_serverCert, _serverChain) = TestHelper.GenerateCertificates("localhost"); } [Fact] diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj index 1e55f308659933..61887033897ed0 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -61,6 +61,10 @@ Link="Common\System\Net\VirtualNetwork\VirtualNetwork.cs" /> + + ().Single(); - - certUrl = $"{responder.UriPrefix}cert/{intermedSkid.SubjectKeyIdentifier}.cer"; - cdpUrl = $"{responder.UriPrefix}crl/{intermedSkid.SubjectKeyIdentifier}.crl"; - ocspUrl = $"{responder.UriPrefix}ocsp/{intermedSkid.SubjectKeyIdentifier}"; - - intermediateAuthority = new CertificateAuthority( - intermedCert, - issuerDistributionViaHttp ? certUrl : null, - endEntityRevocationViaCrl ? cdpUrl : null, - endEntityRevocationViaOcsp ? ocspUrl : null); - - endEntityCert = intermediateAuthority.CreateEndEntity( - BuildSubject("A Revocation Test Cert", testName, pkiOptions, pkiOptionsInSubject), - eeKey); - } - - if (registerAuthorities) - { - responder.AddCertificateAuthority(rootAuthority); - responder.AddCertificateAuthority(intermediateAuthority); - } - } - private static string BuildSubject( string cn, string testName, diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj b/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj index c5cd7e39fe0082..ebf9abffd3421c 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj @@ -55,9 +55,11 @@ - + - + From 1408d5a6165b00ea711b29d519d220a8265bb775 Mon Sep 17 00:00:00 2001 From: Tomas Weinfurt Date: Wed, 1 Jul 2020 11:29:34 -0700 Subject: [PATCH 3/4] feedback from review --- .../X509Certificates/CertificateAuthority.cs | 20 ++++++------- .../X509Certificates/RevocationResponder.cs | 1 - .../RevocationTests/DynamicRevocationTests.cs | 29 +++++++++++++++++-- 3 files changed, 35 insertions(+), 15 deletions(-) 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 dcab14b8fe07ba..1cb4e8a290f1df 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs @@ -300,7 +300,6 @@ private X509Certificate2 CreateCertificate( request.CertificateExtensions.Add(altName); } - byte[] serial = new byte[sizeof(long)]; RandomNumberGenerator.Fill(serial); @@ -834,15 +833,15 @@ private enum CertStatus } internal static void BuildPrivatePki( - PkiOptions pkiOptions, - out RevocationResponder responder, - out CertificateAuthority rootAuthority, - out CertificateAuthority intermediateAuthority, - out X509Certificate2 endEntityCert, - string testName = null, - bool registerAuthorities = true, - bool pkiOptionsInSubject = false, - string subjectName = null) + PkiOptions pkiOptions, + out RevocationResponder responder, + out CertificateAuthority rootAuthority, + out CertificateAuthority intermediateAuthority, + out X509Certificate2 endEntityCert, + string testName = null, + bool registerAuthorities = true, + bool pkiOptionsInSubject = false, + string subjectName = null) { bool rootDistributionViaHttp = !pkiOptions.HasFlag(PkiOptions.NoRootCertDistributionUri); bool issuerRevocationViaCrl = pkiOptions.HasFlag(PkiOptions.IssuerRevocationViaCrl); @@ -921,7 +920,6 @@ internal static void BuildPrivatePki( endEntityRevocationViaCrl ? cdpUrl : null, endEntityRevocationViaOcsp ? ocspUrl : null); - X509Extension altName = null; if (!String.IsNullOrEmpty(subjectName)) diff --git a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs index f08c4439674704..7dae6711cf995d 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Formats.Asn1; using System.Net; -using System.Security.Cryptography.X509Certificates.Tests.Common; using System.Threading; using System.Threading.Tasks; using System.Web; diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/DynamicRevocationTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/DynamicRevocationTests.cs index 6bf656d0a3071a..f1b9029ef0f358 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/DynamicRevocationTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/DynamicRevocationTests.cs @@ -642,7 +642,7 @@ public static void RevokeEndEntity_PolicyErrors_NotTimeValid(bool policyErrors, [MemberData(nameof(AllViableRevocation))] public static void RevokeEndEntity_RootRevocationOffline(PkiOptions pkiOptions) { - CertificateAuthority.BuildPrivatePki( + BuildPrivatePki( pkiOptions, out RevocationResponder responder, out CertificateAuthority root, @@ -715,7 +715,7 @@ public static void RevokeEndEntity_RootRevocationOffline(PkiOptions pkiOptions) [MemberData(nameof(AllViableRevocation))] public static void NothingRevoked_RootRevocationOffline(PkiOptions pkiOptions) { - CertificateAuthority.BuildPrivatePki( + BuildPrivatePki( pkiOptions, out RevocationResponder responder, out CertificateAuthority root, @@ -1167,7 +1167,7 @@ private static void SimpleTest( [CallerMemberName] string callerName = null, bool pkiOptionsInTestName = true) { - CertificateAuthority.BuildPrivatePki( + BuildPrivatePki( pkiOptions, out RevocationResponder responder, out CertificateAuthority root, @@ -1246,6 +1246,29 @@ private static void AssertChainStatus( } } + internal static void BuildPrivatePki( + PkiOptions pkiOptions, + out RevocationResponder responder, + out CertificateAuthority rootAuthority, + out CertificateAuthority intermediateAuthority, + out X509Certificate2 endEntityCert, + [CallerMemberName] string testName = null, + bool registerAuthorities = true, + bool pkiOptionsInSubject = false) + { + bool issuerRevocationViaCrl = pkiOptions.HasFlag(PkiOptions.IssuerRevocationViaCrl); + bool issuerRevocationViaOcsp = pkiOptions.HasFlag(PkiOptions.IssuerRevocationViaOcsp); + bool endEntityRevocationViaCrl = pkiOptions.HasFlag(PkiOptions.EndEntityRevocationViaCrl); + bool endEntityRevocationViaOcsp = pkiOptions.HasFlag(PkiOptions.EndEntityRevocationViaOcsp); + + Assert.True( + issuerRevocationViaCrl || issuerRevocationViaOcsp || + endEntityRevocationViaCrl || endEntityRevocationViaOcsp, + "At least one revocation mode is enabled"); + + CertificateAuthority.BuildPrivatePki(pkiOptions, out responder, out rootAuthority, out intermediateAuthority, out endEntityCert, testName, registerAuthorities, pkiOptionsInSubject); + } + private static string BuildSubject( string cn, string testName, From 9997a6397d036a84831b0050da05d1425c41cd34 Mon Sep 17 00:00:00 2001 From: Tomas Weinfurt Date: Wed, 1 Jul 2020 14:12:28 -0700 Subject: [PATCH 4/4] disable on windows --- .../tests/FunctionalTests/SslStreamNetworkStreamTest.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index f807a75542f2d7..739dd5d8004a50 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -202,6 +202,7 @@ public async Task SslStream_NestedAuth_Throws() } [Fact] + [PlatformSpecific(TestPlatforms.AnyUnix)] public async Task SslStream_UntrustedCaWithCustomCallback_OK() { var options = new SslClientAuthenticationOptions() { TargetHost = "localhost" }; @@ -232,6 +233,7 @@ public async Task SslStream_UntrustedCaWithCustomCallback_OK() } [Fact] + [PlatformSpecific(TestPlatforms.AnyUnix)] public async Task SslStream_UntrustedCaWithCustomCallback_Throws() { var options = new SslClientAuthenticationOptions() { TargetHost = "localhost" };