1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Net.Http; 6 using System.Net.Test.Common; 7 using System.Security.Cryptography.X509Certificates; 8 using System.Security.Authentication; 9 using System.Threading.Tasks; 10 11 using Xunit; 12 13 namespace System.Net.Security.Tests 14 { 15 using Configuration = System.Net.Test.Common.Configuration; 16 17 public abstract class SslStreamSystemDefaultTest 18 { 19 protected readonly SslStream _clientStream; 20 protected readonly SslStream _serverStream; 21 SslStreamSystemDefaultTest()22 public SslStreamSystemDefaultTest() 23 { 24 var network = new VirtualNetwork(); 25 var clientNet = new VirtualNetworkStream(network, isServer:false); 26 var serverNet = new VirtualNetworkStream(network, isServer: true); 27 28 _clientStream = new SslStream(clientNet, false, ClientCertCallback); 29 _serverStream = new SslStream(serverNet, false, ServerCertCallback); 30 } 31 32 public static bool IsNotWindows7 => !PlatformDetection.IsWindows7; 33 AuthenticateClientAsync(string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation, SslProtocols? protocols = null)34 protected abstract Task AuthenticateClientAsync(string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation, SslProtocols? protocols = null); AuthenticateServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation, SslProtocols? protocols = null)35 protected abstract Task AuthenticateServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation, SslProtocols? protocols = null); 36 37 [ConditionalTheory(nameof(IsNotWindows7))] 38 [InlineData(null, null)] 39 [InlineData(SslProtocols.None, null)] 40 [InlineData(null, SslProtocols.None)] 41 [InlineData(SslProtocols.None, SslProtocols.None)] 42 [InlineData(null, SslProtocols.Tls11)] 43 [InlineData(SslProtocols.Tls11, null)] 44 [InlineData(null, SslProtocols.Tls12)] 45 [InlineData(SslProtocols.Tls12, null)] 46 [InlineData(SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12, null)] 47 [InlineData(null, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12)] 48 public async Task ClientAndServer_OneOrBothUseDefault_Ok(SslProtocols? clientProtocols, SslProtocols? serverProtocols) 49 { 50 const int SEC_E_BUFFER_TOO_SMALL = unchecked((int)0x80090321); 51 52 X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate(); 53 string serverHost = serverCertificate.GetNameInfo(X509NameType.SimpleName, false); 54 var clientCertificates = new X509CertificateCollection(); 55 clientCertificates.Add(Configuration.Certificates.GetClientCertificate()); 56 57 var tasks = new Task[2]; 58 tasks[0] = AuthenticateClientAsync(serverHost, clientCertificates, checkCertificateRevocation: false, protocols: clientProtocols); 59 tasks[1] = AuthenticateServerAsync(serverCertificate, clientCertificateRequired: true, checkCertificateRevocation: false, protocols: serverProtocols); 60 61 try 62 { 63 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(tasks); 64 if (PlatformDetection.IsWindows && PlatformDetection.WindowsVersion >= 10) 65 { 66 Assert.True( 67 (_clientStream.SslProtocol == SslProtocols.Tls11 && _clientStream.HashAlgorithm == HashAlgorithmType.Sha1) || 68 _clientStream.HashAlgorithm == HashAlgorithmType.Sha256 || 69 _clientStream.HashAlgorithm == HashAlgorithmType.Sha384 || 70 _clientStream.HashAlgorithm == HashAlgorithmType.Sha512); 71 } 72 } 73 catch (HttpRequestException e) when (e.InnerException?.GetType().Name == "WinHttpException" && 74 e.InnerException.HResult == SEC_E_BUFFER_TOO_SMALL && 75 !PlatformDetection.IsWindows10Version1607OrGreater) 76 { 77 // Testing on old Windows versions can hit https://github.com/dotnet/corefx/issues/7812 78 // Ignore SEC_E_BUFFER_TOO_SMALL error on such cases. 79 } 80 } 81 ClientCertCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)82 private bool ClientCertCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 83 { 84 switch (sslPolicyErrors) 85 { 86 case SslPolicyErrors.None: 87 case SslPolicyErrors.RemoteCertificateChainErrors: 88 case SslPolicyErrors.RemoteCertificateNameMismatch: 89 return true; 90 case SslPolicyErrors.RemoteCertificateNotAvailable: 91 default: 92 return false; 93 } 94 } 95 ServerCertCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)96 private bool ServerCertCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 97 { 98 switch (sslPolicyErrors) 99 { 100 case SslPolicyErrors.None: 101 case SslPolicyErrors.RemoteCertificateChainErrors: 102 case SslPolicyErrors.RemoteCertificateNameMismatch: 103 return true; 104 case SslPolicyErrors.RemoteCertificateNotAvailable: 105 // https://technet.microsoft.com/en-us/library/hh831771.aspx#BKMK_Changes2012R2 106 // Starting with Windows 8, the "Management of trusted issuers for client authentication" has changed: 107 // The behavior to send the Trusted Issuers List by default is off. 108 // 109 // In Windows 7 the Trusted Issuers List is sent within the Server Hello TLS record. This list is built 110 // by the server using certificates from the Trusted Root Authorities certificate store. 111 // The client side will use the Trusted Issuers List, if not empty, to filter proposed certificates. 112 return PlatformDetection.IsWindows7 && !Capability.IsTrustedRootCertificateInstalled(); 113 default: 114 return false; 115 } 116 } 117 Dispose()118 public void Dispose() 119 { 120 _clientStream?.Dispose(); 121 _serverStream?.Dispose(); 122 } 123 } 124 125 public sealed class SyncSslStreamSystemDefaultTest : SslStreamSystemDefaultTest 126 { AuthenticateClientAsync(string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation, SslProtocols? protocols)127 protected override Task AuthenticateClientAsync(string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation, SslProtocols? protocols) => 128 Task.Run(() => 129 { 130 if (protocols.HasValue) 131 { 132 _clientStream.AuthenticateAsClient(targetHost, clientCertificates, protocols.Value, checkCertificateRevocation); 133 } 134 else 135 { 136 _clientStream.AuthenticateAsClient(targetHost, clientCertificates, checkCertificateRevocation); 137 } 138 }); 139 AuthenticateServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation, SslProtocols? protocols)140 protected override Task AuthenticateServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation, SslProtocols? protocols) => 141 Task.Run(() => 142 { 143 if (protocols.HasValue) 144 { 145 _serverStream.AuthenticateAsServer(serverCertificate, clientCertificateRequired, protocols.Value, checkCertificateRevocation); 146 } 147 else 148 { 149 _serverStream.AuthenticateAsServer(serverCertificate, clientCertificateRequired, checkCertificateRevocation); 150 } 151 }); 152 } 153 154 public sealed class ApmSslStreamSystemDefaultTest : SslStreamSystemDefaultTest 155 { AuthenticateClientAsync(string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation, SslProtocols? protocols)156 protected override Task AuthenticateClientAsync(string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation, SslProtocols? protocols) => 157 Task.Factory.FromAsync( 158 (callback, state) => protocols.HasValue ? 159 _clientStream.BeginAuthenticateAsClient(targetHost, clientCertificates, protocols.Value, checkCertificateRevocation, callback, state) : 160 _clientStream.BeginAuthenticateAsClient(targetHost, clientCertificates, checkCertificateRevocation, callback, state), 161 _clientStream.EndAuthenticateAsClient, 162 state: null); 163 AuthenticateServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation, SslProtocols? protocols)164 protected override Task AuthenticateServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation, SslProtocols? protocols) => 165 Task.Factory.FromAsync( 166 (callback, state) => protocols.HasValue ? 167 _serverStream.BeginAuthenticateAsServer(serverCertificate, clientCertificateRequired, protocols.Value, checkCertificateRevocation, callback, state) : 168 _serverStream.BeginAuthenticateAsServer(serverCertificate, clientCertificateRequired, checkCertificateRevocation, callback, state), 169 _serverStream.EndAuthenticateAsServer, 170 state: null); 171 } 172 173 public sealed class AsyncSslStreamSystemDefaultTest : SslStreamSystemDefaultTest 174 { AuthenticateClientAsync(string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation, SslProtocols? protocols)175 protected override Task AuthenticateClientAsync(string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation, SslProtocols? protocols) => 176 protocols.HasValue ? 177 _clientStream.AuthenticateAsClientAsync(targetHost, clientCertificates, protocols.Value, checkCertificateRevocation) : 178 _clientStream.AuthenticateAsClientAsync(targetHost, clientCertificates, checkCertificateRevocation); 179 AuthenticateServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation, SslProtocols? protocols)180 protected override Task AuthenticateServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation, SslProtocols? protocols) => 181 protocols.HasValue ? 182 _serverStream.AuthenticateAsServerAsync(serverCertificate, clientCertificateRequired, protocols.Value, checkCertificateRevocation) : 183 _serverStream.AuthenticateAsServerAsync(serverCertificate, clientCertificateRequired, checkCertificateRevocation); 184 } 185 } 186