public async Task ClientOptions_TargetHostNull_OK() { (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); using (client) using (server) { var serverOptions = new SslServerAuthenticationOptions() { ServerCertificate = Configuration.Certificates.GetServerCertificate() }; var clientOptions = new SslClientAuthenticationOptions() { RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true }; Assert.Null(clientOptions.TargetHost); await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(clientOptions), server.AuthenticateAsServerAsync(serverOptions)); Assert.Equal(string.Empty, client.TargetHostName); Assert.Equal(string.Empty, server.TargetHostName); } }
public async Task ServerAsyncAuthenticate_NoCertificate_Throws(bool useAsync) { var serverOptions = new SslServerAuthenticationOptions(); var clientOptions = new SslClientAuthenticationOptions() { TargetHost = _serverCertificate.GetNameInfo(X509NameType.SimpleName, false) }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); using (client) using (server) { Task t1 = client.AuthenticateAsClientAsync(clientOptions, CancellationToken.None); Task t2 = server.AuthenticateAsServerAsync( (stream, clientHelloInfo, userState, cancellationToken) => { if (useAsync) { return(new ValueTask <SslServerAuthenticationOptions>(serverOptions)); } return(new ValueTask <SslServerAuthenticationOptions>(OptionsTask(serverOptions))); }, null, CancellationToken.None); await Assert.ThrowsAsync <System.NotSupportedException>(() => t2); } }
public async Task ServerAsyncAuthenticate_SimpleSniOptions_Success() { var state = new object(); var serverOptions = new SslServerAuthenticationOptions() { ServerCertificate = _serverCertificate }; var clientOptions = new SslClientAuthenticationOptions() { TargetHost = _serverCertificate.GetNameInfo(X509NameType.SimpleName, false) }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); using (client) using (server) { Task t1 = client.AuthenticateAsClientAsync(clientOptions, CancellationToken.None); Task t2 = server.AuthenticateAsServerAsync( (stream, clientHelloInfo, userState, cancellationToken) => { Assert.Equal(server, stream); Assert.Equal(clientOptions.TargetHost, clientHelloInfo.ServerName); Assert.True(object.ReferenceEquals(state, userState)); return(new ValueTask <SslServerAuthenticationOptions>(serverOptions)); }, state, CancellationToken.None); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); } }
public async Task ServerAsyncAuthenticate_SniSetVersion_Success(SslProtocols version) { var serverOptions = new SslServerAuthenticationOptions() { ServerCertificate = _serverCertificate, EnabledSslProtocols = version }; var clientOptions = new SslClientAuthenticationOptions() { TargetHost = _serverCertificate.GetNameInfo(X509NameType.SimpleName, forIssuer: false) }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); using (client) using (server) { Task t1 = client.AuthenticateAsClientAsync(clientOptions, CancellationToken.None); Task t2 = server.AuthenticateAsServerAsync( (stream, clientHelloInfo, userState, cancellationToken) => { Assert.Equal(server, stream); Assert.Equal(clientOptions.TargetHost, clientHelloInfo.ServerName); return(new ValueTask <SslServerAuthenticationOptions>(serverOptions)); }, null, CancellationToken.None); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); // Verify that the SNI callback can impact version. Assert.Equal(version, client.SslProtocol); } }
public async Task SslStream_SecondNegotiateClientCertificateAsync_Throws(bool sendClientCertificate) { using CancellationTokenSource cts = new CancellationTokenSource(); cts.CancelAfter(TestConfiguration.PassingTestTimeout); (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); using (client) using (server) using (X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate()) using (X509Certificate2 clientCertificate = Configuration.Certificates.GetClientCertificate()) { SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions() { TargetHost = Guid.NewGuid().ToString("N"), EnabledSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12, }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; clientOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => { return(sendClientCertificate ? clientCertificate : null); }; SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions() { ServerCertificate = serverCertificate }; serverOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(clientOptions, cts.Token), server.AuthenticateAsServerAsync(serverOptions, cts.Token)); await TestHelper.PingPong(client, server, cts.Token); Assert.Null(server.RemoteCertificate); // Client needs to be reading for renegotiation to happen. byte[] buffer = new byte[TestHelper.s_ping.Length]; ValueTask <int> t = client.ReadAsync(buffer, cts.Token); await server.NegotiateClientCertificateAsync(cts.Token); if (sendClientCertificate) { Assert.NotNull(server.RemoteCertificate); } else { Assert.Null(server.RemoteCertificate); } // Finish the client's read await server.WriteAsync(TestHelper.s_ping, cts.Token); await t; await Assert.ThrowsAsync <InvalidOperationException>(() => server.NegotiateClientCertificateAsync()); } }
private async Task ClientAsyncSslHelper( EncryptionPolicy encryptionPolicy, SslProtocols clientSslProtocols, SslProtocols serverSslProtocols, RemoteCertificateValidationCallback certificateCallback = null) { _log.WriteLine("Server: " + serverSslProtocols + "; Client: " + clientSslProtocols); (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); using (client) using (server) { // Use a different SNI for each connection to prevent TLS 1.3 renegotiation issue: https://github.com/dotnet/runtime/issues/47378 string serverName = TestHelper.GetTestSNIName(nameof(ClientAsyncSslHelper), clientSslProtocols, serverSslProtocols); Task serverTask = default; try { Task clientTask = client.AuthenticateAsClientAsync(new SslClientAuthenticationOptions { EnabledSslProtocols = clientSslProtocols, RemoteCertificateValidationCallback = AllowAnyServerCertificate, TargetHost = serverName }); serverTask = server.AuthenticateAsServerAsync(new SslServerAuthenticationOptions { EncryptionPolicy = encryptionPolicy, EnabledSslProtocols = serverSslProtocols, ServerCertificate = TestConfiguration.ServerCertificate, CertificateRevocationCheckMode = X509RevocationMode.NoCheck }); await clientTask.WaitAsync(TestConfiguration.PassingTestTimeout); _log.WriteLine("Client authenticated to server with encryption cipher: {0} {1}-bit strength", client.CipherAlgorithm, client.CipherStrength); Assert.True(client.CipherAlgorithm != CipherAlgorithmType.Null, "Cipher algorithm should not be NULL"); Assert.True(client.CipherStrength > 0, "Cipher strength should be greater than 0"); } finally { // make sure we signal server in case of client failures client.Close(); try { await serverTask; } catch (Exception ex) { // We generally don't care about server but can log exception to help diagnose test failures _log.WriteLine(ex.ToString()); } } } }
public async Task SslStream_StreamToStream_Alpn_NonMatchingProtocols_Fail() { (SslStream clientStream, SslStream serverStream) = TestHelper.GetConnectedSslStreams(); using (serverStream) using (clientStream) using (X509Certificate2 certificate = Configuration.Certificates.GetServerCertificate()) { SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions { ApplicationProtocols = new List <SslApplicationProtocol> { SslApplicationProtocol.Http2 }, ServerCertificate = certificate, }; SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions { ApplicationProtocols = new List <SslApplicationProtocol> { SslApplicationProtocol.Http11 }, RemoteCertificateValidationCallback = AllowAnyServerCertificate, TargetHost = certificate.GetNameInfo(X509NameType.SimpleName, false), }; // Test ALPN failure only on platforms that supports ALPN. if (BackendSupportsAlpn) { Task t1 = Assert.ThrowsAsync <AuthenticationException>(() => clientStream.AuthenticateAsClientAsync(TestAuthenticateAsync, clientOptions)); await Assert.ThrowsAsync <AuthenticationException>(() => serverStream.AuthenticateAsServerAsync(TestAuthenticateAsync, serverOptions)); serverStream.Dispose(); await t1.WaitAsync(TestConfiguration.PassingTestTimeout); } else { Task t1 = clientStream.AuthenticateAsClientAsync(TestAuthenticateAsync, clientOptions); Task t2 = serverStream.AuthenticateAsServerAsync(TestAuthenticateAsync, serverOptions); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); Assert.Equal(default(SslApplicationProtocol), clientStream.NegotiatedApplicationProtocol); Assert.Equal(default(SslApplicationProtocol), serverStream.NegotiatedApplicationProtocol); } } }
private async Task <string[]> ConnectAndGatherAcceptableIssuers(SslCertificateTrust trust) { (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); using (client) using (server) using (X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate()) using (X509Certificate2 clientCertificate = Configuration.Certificates.GetClientCertificate()) { SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions { ServerCertificate = serverCertificate, ClientCertificateRequired = true, RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true, ServerCertificateContext = SslStreamCertificateContext.Create(serverCertificate, null, false, trust) }; string[] acceptableIssuers = Array.Empty <string>(); SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions { TargetHost = "localhost", // Force Tls 1.2 to avoid issues with certain OpenSSL versions and Tls 1.3 // https://github.com/openssl/openssl/issues/7384 EnabledSslProtocols = SslProtocols.Tls12, RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true, LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, issuers) => { if (remoteCertificate == null) { // ignore the first call that is called before handshake return(null); } acceptableIssuers = issuers; return(clientCertificate); }, }; await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(clientOptions), server.AuthenticateAsServerAsync(serverOptions)); return(acceptableIssuers); } }
public async Task SslStream_NegotiateClientCertificateAsyncConcurrentIO_Throws(bool doRead) { using CancellationTokenSource cts = new CancellationTokenSource(); cts.CancelAfter(TestConfiguration.PassingTestTimeout); (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); using (client) using (server) using (X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate()) using (X509Certificate2 clientCertificate = Configuration.Certificates.GetClientCertificate()) { SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions() { TargetHost = Guid.NewGuid().ToString("N"), ClientCertificates = new X509CertificateCollection(new X509Certificate2[] { clientCertificate }) }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions() { ServerCertificate = serverCertificate }; serverOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(clientOptions, cts.Token), server.AuthenticateAsServerAsync(serverOptions, cts.Token)); await TestHelper.PingPong(client, server, cts.Token); Assert.Null(server.RemoteCertificate); Task t = server.NegotiateClientCertificateAsync(cts.Token); if (doRead) { byte[] buffer = new byte[TestHelper.s_ping.Length]; await Assert.ThrowsAsync <NotSupportedException>(() => server.ReadAsync(buffer).AsTask()); } else { await Assert.ThrowsAsync <NotSupportedException>(() => server.WriteAsync(TestHelper.s_ping).AsTask()); } } }
public async Task NegotiateClientCertificateAsync_PendingData_Throws() { using CancellationTokenSource cts = new CancellationTokenSource(); cts.CancelAfter(TestConfiguration.PassingTestTimeout); (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); using (client) using (server) using (X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate()) using (X509Certificate2 clientCertificate = Configuration.Certificates.GetClientCertificate()) { SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions() { TargetHost = Guid.NewGuid().ToString("N"), ClientCertificates = new X509CertificateCollection(new X509Certificate2[] { clientCertificate }) }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions() { ServerCertificate = serverCertificate }; serverOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(clientOptions, cts.Token), server.AuthenticateAsServerAsync(serverOptions, cts.Token)); await TestHelper.PingPong(client, server, cts.Token); Assert.Null(server.RemoteCertificate); // This should go out in single TLS frame await client.WriteAsync(new byte[200], cts.Token); byte[] readBuffer = new byte[10]; // when we read part of the frame, remaining part should left decrypted await server.ReadAsync(readBuffer, cts.Token); await Assert.ThrowsAsync <InvalidOperationException>(() => server.NegotiateClientCertificateAsync(cts.Token)); } }
public async Task CertificateSelectionCallback_DelayedCertificate_OK(bool delayCertificate, bool sendClientCertificate) { X509Certificate?remoteCertificate = null; (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); using (client) using (server) { int count = 0; SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions(); clientOptions.TargetHost = "localhost"; // Force Tls 1.2 to avoid issues with certain OpenSSL versions and Tls 1.3 // https://github.com/openssl/openssl/issues/7384 clientOptions.EnabledSslProtocols = SslProtocols.Tls12; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; clientOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, certificate, acceptableIssuers) => { count++; remoteCertificate = certificate; if (delayCertificate && count == 1) { // wait until we get remote certificate from peer e.g. handshake started. return(null); } return(sendClientCertificate ? _clientCertificate : null); }; SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions(); serverOptions.ServerCertificate = _serverCertificate; serverOptions.ClientCertificateRequired = true; serverOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { if (sendClientCertificate) { Assert.NotNull(certificate); // The client chain may be incomplete. Assert.True(sslPolicyErrors == SslPolicyErrors.None || sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors); } else { Assert.Equal(SslPolicyErrors.RemoteCertificateNotAvailable, sslPolicyErrors); } return(true); }; await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(clientOptions), server.AuthenticateAsServerAsync(serverOptions)); // verify that the session is usable with or without client's certificate await TestHelper.PingPong(client, server); await TestHelper.PingPong(server, client); if (delayCertificate) { // LocalCertificateSelectionCallback should be called with real remote certificate. Assert.NotNull(remoteCertificate); } } }
public async Task SslStream_NegotiateClientCertificateAsyncTls13_Succeeds(bool sendClientCertificate) { bool negotiateClientCertificateCalled = false; using CancellationTokenSource cts = new CancellationTokenSource(); cts.CancelAfter(TestConfiguration.PassingTestTimeout); (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); using (client) using (server) using (X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate()) using (X509Certificate2 clientCertificate = Configuration.Certificates.GetClientCertificate()) { SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions() { TargetHost = Guid.NewGuid().ToString("N"), EnabledSslProtocols = SslProtocols.Tls13, }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; clientOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => { return(sendClientCertificate ? clientCertificate : null); }; SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions() { ServerCertificate = serverCertificate }; serverOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { if (negotiateClientCertificateCalled && sendClientCertificate) { Assert.Equal(clientCertificate.GetCertHash(), certificate?.GetCertHash()); } else { Assert.Null(certificate); } return(true); }; await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(clientOptions, cts.Token), server.AuthenticateAsServerAsync(serverOptions, cts.Token)); // need this to complete TLS 1.3 handshake await TestHelper.PingPong(client, server); Assert.Null(server.RemoteCertificate); // Client needs to be reading for renegotiation to happen. byte[] buffer = new byte[TestHelper.s_ping.Length]; ValueTask <int> t = client.ReadAsync(buffer, cts.Token); negotiateClientCertificateCalled = true; await server.NegotiateClientCertificateAsync(cts.Token); if (sendClientCertificate) { Assert.NotNull(server.RemoteCertificate); } else { Assert.Null(server.RemoteCertificate); } // Finish the client's read await server.WriteAsync(TestHelper.s_ping, cts.Token); await t; // verify that the session is usable with or without client's certificate await TestHelper.PingPong(client, server, cts.Token); await TestHelper.PingPong(server, client, cts.Token); } }