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()); } }
public async Task SslStream_TargetHostName_Succeeds(bool useEmptyName) { string targetName = useEmptyName ? string.Empty : Guid.NewGuid().ToString("N"); int count = 0; (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); using (clientStream) using (serverStream) using (var client = new SslStream(clientStream)) using (var server = new SslStream(serverStream)) using (X509Certificate2 certificate = Configuration.Certificates.GetServerCertificate()) { // It should be empty before handshake. Assert.Equal(string.Empty, client.TargetHostName); Assert.Equal(string.Empty, server.TargetHostName); SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions() { TargetHost = targetName }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { SslStream stream = (SslStream)sender; Assert.Equal(targetName, stream.TargetHostName); count++; return(true); }; SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions(); serverOptions.ServerCertificateSelectionCallback = (sender, name) => { SslStream stream = (SslStream)sender; Assert.Equal(targetName, stream.TargetHostName); return(certificate); }; await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(clientOptions), server.AuthenticateAsServerAsync(serverOptions)); await TestHelper.PingPong(client, server); Assert.Equal(targetName, client.TargetHostName); Assert.Equal(targetName, server.TargetHostName); Assert.Equal(1, count); } }
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); } }