diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/CertificateValidationClientServer.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/CertificateValidationClientServer.cs index 6bd2a28a69f5ee..919c5079e29b8b 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/CertificateValidationClientServer.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/CertificateValidationClientServer.cs @@ -57,8 +57,10 @@ public async Task CertificateSelectionCallback_DelayedCertificate_OK(bool delayC using (server) { int count = 0; + bool validationCallbackCalled = false; SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions(); clientOptions.TargetHost = "localhost"; + clientOptions.AllowTlsResume = false; // 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; @@ -81,6 +83,7 @@ public async Task CertificateSelectionCallback_DelayedCertificate_OK(bool delayC serverOptions.ClientCertificateRequired = true; serverOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { + validationCallbackCalled = true; if (sendClientCertificate) { Assert.NotNull(certificate); @@ -100,6 +103,8 @@ await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(clientOptions), server.AuthenticateAsServerAsync(serverOptions)); + Assert.True(validationCallbackCalled); + // verify that the session is usable with or without client's certificate await TestHelper.PingPong(client, server); await TestHelper.PingPong(server, client); diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/CertificateValidationRemoteServer.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/CertificateValidationRemoteServer.cs index 54152711daeb36..b1f93ad3d3f348 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/CertificateValidationRemoteServer.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/CertificateValidationRemoteServer.cs @@ -41,17 +41,28 @@ public async Task CertificateValidationRemoteServer_EndToEnd_Ok(bool useAsync) throw new SkipTestException($"Unable to connect to '{Configuration.Security.TlsServer.IdnHost}': {ex.Message}"); } - using (SslStream sslStream = new SslStream(client.GetStream(), false, RemoteHttpsCertValidation, null)) + bool callbackCalled = false; + using (SslStream sslStream = new SslStream(client.GetStream())) { + var options = new SslClientAuthenticationOptions + { + TargetHost = Configuration.Security.TlsServer.IdnHost, + AllowTlsResume = false, + RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => + { + callbackCalled = true; + return RemoteHttpsCertValidation(sender, certificate, chain, errors); + } + }; try { if (useAsync) { - await sslStream.AuthenticateAsClientAsync(Configuration.Security.TlsServer.IdnHost); + await sslStream.AuthenticateAsClientAsync(options); } else { - sslStream.AuthenticateAsClient(Configuration.Security.TlsServer.IdnHost); + sslStream.AuthenticateAsClient(options); } } catch (IOException ex) when (ex.InnerException is SocketException && @@ -61,6 +72,8 @@ public async Task CertificateValidationRemoteServer_EndToEnd_Ok(bool useAsync) // caused most likely by environmental failures. throw new SkipTestException($"Unable to connect to '{Configuration.Security.TlsServer.IdnHost}': {ex.InnerException.Message}"); } + + Assert.True(callbackCalled); } } } @@ -135,7 +148,7 @@ public Task ConnectWithRevocation_ServerCertWithoutContext_NoStapledOcsp() [InlineData(X509RevocationMode.Offline)] [InlineData(X509RevocationMode.Online)] [InlineData(X509RevocationMode.NoCheck)] - public Task ConnectWithRevocation_RemoteServer_StapledOcsp_FromWindows(X509RevocationMode revocationMode) + public async Task ConnectWithRevocation_RemoteServer_StapledOcsp_FromWindows(X509RevocationMode revocationMode) { // This test could ideally end at the Client Hello, because it really only wants to // ensure that the status_request extension was asserted. Since the SslStream tests @@ -146,22 +159,26 @@ public Task ConnectWithRevocation_RemoteServer_StapledOcsp_FromWindows(X509Revoc // but it's the best we can do right now. string serverName = Configuration.Http.Http2Host; + bool callbackCalled = false; SslClientAuthenticationOptions clientOpts = new SslClientAuthenticationOptions { TargetHost = serverName, + AllowTlsResume = false, RemoteCertificateValidationCallback = CertificateValidationCallback, CertificateRevocationCheckMode = revocationMode, }; - return EndToEndHelper(clientOpts); + await EndToEndHelper(clientOpts); + Assert.True(callbackCalled); - static bool CertificateValidationCallback( + bool CertificateValidationCallback( object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors) { + callbackCalled = true; Assert.NotNull(certificate); using (SafeCertContextHandle ctx = new SafeCertContextHandle(certificate.Handle, ownsHandle: false)) diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs index addde8483c84a9..c95ea6b00fe98b 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs @@ -31,7 +31,14 @@ public async Task ClientAsyncAuthenticate_ServerRequireEncryption_ConnectWithEnc [ActiveIssue("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/dotnet/runtime/issues/115467", TestPlatforms.Android)] public async Task ClientAsyncAuthenticate_ConnectionInfoInCallback_DoesNotThrow() { - await ClientAsyncSslHelper(EncryptionPolicy.RequireEncryption, SslProtocols.Tls12, SslProtocolSupport.DefaultSslProtocols, AllowAnyServerCertificateAndVerifyConnectionInfo); + bool callbackCalled = false; + await ClientAsyncSslHelper(EncryptionPolicy.RequireEncryption, SslProtocols.Tls12, SslProtocolSupport.DefaultSslProtocols, + (sender, certificate, chain, errors) => + { + callbackCalled = true; + return AllowAnyServerCertificateAndVerifyConnectionInfo(sender, certificate, chain, errors); + }); + Assert.True(callbackCalled); } [Fact] @@ -147,6 +154,7 @@ private async Task ClientAsyncSslHelper( { EnabledSslProtocols = clientSslProtocols, RemoteCertificateValidationCallback = certificateCallback ?? AllowAnyServerCertificate, + AllowTlsResume = certificateCallback is null, TargetHost = serverName }); serverTask = server.AuthenticateAsServerAsync(new SslServerAuthenticationOptions diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs index 233f18267f23bc..0b497288e3f6fb 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs @@ -47,6 +47,7 @@ public async Task SslStream_AllowRenegotiation_True_Succeeds() ClientCertificates = certBundle, EnabledSslProtocols = SslProtocols.Tls12, CertificateRevocationCheckMode = X509RevocationMode.NoCheck, + AllowTlsResume = false, AllowRenegotiation = true }; diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index 42d031868ffea8..f250bc5d727ffa 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -160,7 +160,13 @@ public async Task SslStream_NetworkStream_Renegotiation_Succeeds(bool useSync) certBundle.Add(clientCert); // Perform handshake to establish secure connection. - await ssl.AuthenticateAsClientAsync(Configuration.Security.TlsRenegotiationServer, certBundle, SslProtocols.Tls12, false); + await ssl.AuthenticateAsClientAsync(new SslClientAuthenticationOptions + { + TargetHost = Configuration.Security.TlsRenegotiationServer, + ClientCertificates = certBundle, + EnabledSslProtocols = SslProtocols.Tls12, + AllowTlsResume = false, + }); Assert.True(ssl.IsAuthenticated); Assert.True(ssl.IsEncrypted); @@ -760,7 +766,8 @@ public async Task SslStream_TargetHostName_Succeeds(bool useEmptyName, bool useC Assert.Equal(string.Empty, client.TargetHostName); Assert.Equal(string.Empty, server.TargetHostName); - SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions() { TargetHost = targetName }; + // A resumed handshake skips the certificate validation callback. + SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions() { TargetHost = targetName, AllowTlsResume = false }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { @@ -811,7 +818,7 @@ public async Task SslStream_ServerUntrustedCaWithCustomTrust_OK(bool usePartialC int split = Random.Shared.Next(0, _certificates.ServerChain.Count - 1); - var clientOptions = new SslClientAuthenticationOptions() { TargetHost = "localhost" }; + var clientOptions = new SslClientAuthenticationOptions() { TargetHost = "localhost", AllowTlsResume = false }; clientOptions.CertificateChainPolicy = new X509ChainPolicy() { RevocationMode = X509RevocationMode.NoCheck, @@ -875,10 +882,13 @@ private async Task SslStream_ClientSendsChain_Core(SslClientAuthenticationOption { List streams = new List(); - var serverOptions = new SslServerAuthenticationOptions() { ClientCertificateRequired = true }; + int validationCount = 0; + // Exercise credential caching, but require the client to send its chain on every connection. + var serverOptions = new SslServerAuthenticationOptions() { ClientCertificateRequired = true, AllowTlsResume = false }; serverOptions.ServerCertificateContext = SslStreamCertificateContext.Create(Configuration.Certificates.GetServerCertificate(), null); serverOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { + validationCount++; // Client should send chain without root CA. There is no good way how to know if the chain was built from certificates // from wire or from system store. However, SslStream adds certificates from wire to ExtraStore in RemoteCertificateValidationCallback. // So we verify the operation by checking the ExtraStore. On Windows, that includes leaf itself. @@ -906,6 +916,8 @@ private async Task SslStream_ClientSendsChain_Core(SslClientAuthenticationOption Task t2 = server.AuthenticateAsServerAsync(serverOptions, CancellationToken.None); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); + Assert.Equal(i + 1, validationCount); + // hold to the streams so they stay in credential cache streams.Add(client); streams.Add(server); diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs index 520db2e7000b56..e981697fb47575 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs @@ -24,6 +24,7 @@ public class SslStreamSniTest public async Task SslStream_ClientSendsSNIServerReceives_Ok(string hostName) { using X509Certificate serverCert = Configuration.Certificates.GetSelfSignedServerCertificate(); + bool validationCallbackCalled = false; await WithVirtualConnection(async (server, client) => { @@ -33,6 +34,7 @@ await WithVirtualConnection(async (server, client) => }); SslServerAuthenticationOptions options = DefaultServerOptions(); + options.AllowTlsResume = false; int timesCallbackCalled = 0; options.ServerCertificateSelectionCallback = (sender, actualHostName) => @@ -50,10 +52,12 @@ await WithVirtualConnection(async (server, client) => }, (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => { + validationCallbackCalled = true; Assert.Equal(serverCert, certificate); return true; } ); + Assert.True(validationCallbackCalled); } [Theory] @@ -110,6 +114,7 @@ public async Task SslStream_ServerCallbackNotSet_UsesLocalCertificateSelection(s using X509Certificate serverCert = Configuration.Certificates.GetSelfSignedServerCertificate(); int timesCallbackCalled = 0; + bool validationCallbackCalled = false; var selectionCallback = new LocalCertificateSelectionCallback((object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] issuers) => { @@ -121,6 +126,7 @@ public async Task SslStream_ServerCallbackNotSet_UsesLocalCertificateSelection(s var validationCallback = new RemoteCertificateValidationCallback((object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => { + validationCallbackCalled = true; Assert.Equal(serverCert, certificate); return true; }); @@ -135,11 +141,13 @@ public async Task SslStream_ServerCallbackNotSet_UsesLocalCertificateSelection(s }); SslServerAuthenticationOptions options = DefaultServerOptions(); + options.AllowTlsResume = false; options.ServerCertificate = serverCert; await TaskTimeoutExtensions.WhenAllOrAnyFailed(new[] { clientJob, server.AuthenticateAsServerAsync(options, CancellationToken.None) }); Assert.Equal(1, timesCallbackCalled); + Assert.True(validationCallbackCalled); } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs index 8ac4ac9cea65b2..be1ac0b88eba04 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs @@ -103,7 +103,7 @@ public async Task SslStream_StreamToStream_Authentication_IncorrectServerName_Fa using (var server = new SslStream(stream2)) using (var certificate = Configuration.Certificates.GetServerCertificate()) { - Name = "incorrectServer"; + Name = $"incorrectServer-{Guid.NewGuid():N}"; Task t1 = client.AuthenticateAsClientAsync(Name); Task t2 = server.AuthenticateAsServerAsync(certificate);