From 36a79fcffc6beac9490f1828b3344a09c0f87d07 Mon Sep 17 00:00:00 2001 From: Tomas Weinfurt Date: Wed, 16 Feb 2022 17:26:59 -0800 Subject: [PATCH] update SSL tests to deal better with disabled protocols (#65120) * update SSL tests to deal better with disabled protocols * Improve detection of Null encryption on Windows * update expectation for Mismatched protocols * update detection * wrap win32 exception * update ProtocolMismatchData sets * remove debug print * final cleanup * generate mismatch data * avoid SslProtocols.Default --- .../tests/System/Net/SslProtocolSupport.cs | 4 +- .../Net/Security/SslStreamPal.Windows.cs | 23 +++++++---- .../ClientAsyncAuthenticateTest.cs | 28 +++++++------ .../tests/FunctionalTests/LoggingTest.cs | 2 +- .../ServerAsyncAuthenticateTest.cs | 41 +++++-------------- .../FunctionalTests/ServerNoEncryptionTest.cs | 5 ++- .../FunctionalTests/TestConfiguration.cs | 16 +++++++- 7 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/SslProtocolSupport.cs b/src/libraries/Common/tests/System/Net/SslProtocolSupport.cs index e6ac1884c358e..302021b8c0853 100644 --- a/src/libraries/Common/tests/System/Net/SslProtocolSupport.cs +++ b/src/libraries/Common/tests/System/Net/SslProtocolSupport.cs @@ -61,10 +61,12 @@ public IEnumerator GetEnumerator() { foreach (SslProtocols protocol in Enum.GetValues(typeof(SslProtocols))) { - if (protocol != SslProtocols.None && (protocol & SupportedSslProtocols) == protocol) +#pragma warning disable 0618 // SSL2/3 are deprecated + if (protocol != SslProtocols.None && protocol != SslProtocols.Default && (protocol & SupportedSslProtocols) == protocol) { yield return new object[] { protocol }; } +#pragma warning restore 0618 } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs index 2cb0f2ec14e66..00c4de0f43750 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs @@ -140,16 +140,23 @@ public static SecurityStatusPal Renegotiate( public static SafeFreeCredentials AcquireCredentialsHandle(SslStreamCertificateContext? certificateContext, SslProtocols protocols, EncryptionPolicy policy, bool isServer) { - // New crypto API supports TLS1.3 but it does not allow to force NULL encryption. - SafeFreeCredentials cred = !UseNewCryptoApi || policy == EncryptionPolicy.NoEncryption ? - AcquireCredentialsHandleSchannelCred(certificateContext, protocols, policy, isServer) : - AcquireCredentialsHandleSchCredentials(certificateContext, protocols, policy, isServer); - if (certificateContext != null && certificateContext.Trust != null && certificateContext.Trust._sendTrustInHandshake) + try { - AttachCertificateStore(cred, certificateContext.Trust._store!); - } + // New crypto API supports TLS1.3 but it does not allow to force NULL encryption. + SafeFreeCredentials cred = !UseNewCryptoApi || policy == EncryptionPolicy.NoEncryption ? + AcquireCredentialsHandleSchannelCred(certificateContext, protocols, policy, isServer) : + AcquireCredentialsHandleSchCredentials(certificateContext, protocols, policy, isServer); + if (certificateContext != null && certificateContext.Trust != null && certificateContext.Trust._sendTrustInHandshake) + { + AttachCertificateStore(cred, certificateContext.Trust._store!); + } - return cred; + return cred; + } + catch (Win32Exception e) + { + throw new AuthenticationException(SR.net_auth_SSPI, e); + } } private static unsafe void AttachCertificateStore(SafeFreeCredentials cred, X509Store store) diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs index a0e76e49354fb..fae4ac37ba322 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs @@ -55,11 +55,11 @@ public async Task ClientAsyncAuthenticate_EachSupportedProtocol_Success(SslProto [Theory] [MemberData(nameof(ProtocolMismatchData))] public async Task ClientAsyncAuthenticate_MismatchProtocols_Fails( - SslProtocols serverProtocol, SslProtocols clientProtocol, + SslProtocols serverProtocol, Type expectedException) { - Exception e = await Record.ExceptionAsync(() => ClientAsyncSslHelper(serverProtocol, clientProtocol)); + Exception e = await Record.ExceptionAsync(() => ClientAsyncSslHelper(clientProtocol, serverProtocol)); Assert.NotNull(e); Assert.IsAssignableFrom(expectedException, e); } @@ -92,17 +92,19 @@ public async Task ClientAsyncAuthenticate_IndividualServerVsAllClientSupportedPr public static IEnumerable ProtocolMismatchData() { -#pragma warning disable 0618 - yield return new object[] { SslProtocols.Ssl2, SslProtocols.Ssl3, typeof(Exception) }; - yield return new object[] { SslProtocols.Ssl2, SslProtocols.Tls12, typeof(Exception) }; - yield return new object[] { SslProtocols.Ssl3, SslProtocols.Tls12, typeof(Exception) }; -#pragma warning restore 0618 - yield return new object[] { SslProtocols.Tls, SslProtocols.Tls11, typeof(AuthenticationException) }; - yield return new object[] { SslProtocols.Tls, SslProtocols.Tls12, typeof(AuthenticationException) }; - yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls, typeof(AuthenticationException) }; - yield return new object[] { SslProtocols.Tls12, SslProtocols.Tls, typeof(AuthenticationException) }; - yield return new object[] { SslProtocols.Tls12, SslProtocols.Tls11, typeof(AuthenticationException) }; - yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls12, typeof(AuthenticationException) }; + var supportedProtocols = new SslProtocolSupport.SupportedSslProtocolsTestData(); + + foreach (var serverProtocols in supportedProtocols) + foreach (var clientProtocols in supportedProtocols) + { + SslProtocols serverProtocol = (SslProtocols)serverProtocols[0]; + SslProtocols clientProtocol = (SslProtocols)clientProtocols[0]; + + if (clientProtocol != serverProtocol) + { + yield return new object[] { clientProtocol, serverProtocol, typeof(AuthenticationException) }; + } + } } #region Helpers diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/LoggingTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/LoggingTest.cs index db0c4e9d702c5..87de0e09dc278 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/LoggingTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/LoggingTest.cs @@ -27,7 +27,7 @@ public void EventSource_ExistsWithCorrectId() [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "X509 certificate store is not supported on iOS or tvOS.")] // Match SslStream_StreamToStream_Authentication_Success public void EventSource_EventsRaisedAsExpected() { - RemoteExecutor.Invoke(async () => + RemoteExecutor.Invoke(async () => { try { diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs index 1a452e8f89309..ef7eb8fac06aa 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs @@ -46,8 +46,8 @@ public async Task ServerAsyncAuthenticate_EachSupportedProtocol_Success(SslProto [Theory] [MemberData(nameof(ProtocolMismatchData))] public async Task ServerAsyncAuthenticate_MismatchProtocols_Fails( - SslProtocols serverProtocol, SslProtocols clientProtocol, + SslProtocols serverProtocol, Type expectedException) { Exception e = await Record.ExceptionAsync( @@ -236,7 +236,7 @@ public async Task ServerAsyncAuthenticate_ConstructorVerificationDelegate_Succes (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); var client = new SslStream(clientStream); - var server = new SslStream(serverStream, false, (sender, certificate, chain, sslPolicyErrors) => { validationCallbackCalled = true; return true;}); + var server = new SslStream(serverStream, false, (sender, certificate, chain, sslPolicyErrors) => { validationCallbackCalled = true; return true; }); using (client) using (server) @@ -323,37 +323,18 @@ public async Task ServerAsyncAuthenticate_InvalidHello_Throws(bool close) public static IEnumerable ProtocolMismatchData() { - if (PlatformDetection.SupportsSsl3) - { -#pragma warning disable 0618 - yield return new object[] { SslProtocols.Ssl3, SslProtocols.Tls12, typeof(Exception) }; - if (PlatformDetection.SupportsSsl2) - { - yield return new object[] { SslProtocols.Ssl2, SslProtocols.Ssl3, typeof(Exception) }; - yield return new object[] { SslProtocols.Ssl2, SslProtocols.Tls12, typeof(Exception) }; - } -#pragma warning restore 0618 - } - - // It is OK if server does not support given protocol. It should still fail. - // But if client does not support it, it will simply fail without sending out any data. - - if (PlatformDetection.SupportsTls10) - { - yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls, typeof(AuthenticationException) }; - yield return new object[] { SslProtocols.Tls12, SslProtocols.Tls, typeof(AuthenticationException) }; - } + var supportedProtocols = new SslProtocolSupport.SupportedSslProtocolsTestData(); - if (PlatformDetection.SupportsTls11) + foreach (var serverProtocols in supportedProtocols) + foreach (var clientProtocols in supportedProtocols) { - yield return new object[] { SslProtocols.Tls, SslProtocols.Tls11, typeof(AuthenticationException) }; - yield return new object[] { SslProtocols.Tls12, SslProtocols.Tls11, typeof(AuthenticationException) }; - } + SslProtocols serverProtocol = (SslProtocols)serverProtocols[0]; + SslProtocols clientProtocol = (SslProtocols)clientProtocols[0]; - if (PlatformDetection.SupportsTls12) - { - yield return new object[] { SslProtocols.Tls, SslProtocols.Tls12, typeof(AuthenticationException) }; - yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls12, typeof(AuthenticationException) }; + if (clientProtocol != serverProtocol) + { + yield return new object[] { clientProtocol, serverProtocol, typeof(AuthenticationException) }; + } } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs index 4515f15843004..6d43dc8f32017 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs @@ -96,7 +96,10 @@ public async Task ServerNoEncryption_ClientNoEncryption_ConnectWithNoEncryption( else { var ae = await Assert.ThrowsAsync(() => sslStream.AuthenticateAsClientAsync("localhost", null, SslProtocolSupport.DefaultSslProtocols, false)); - Assert.IsType(ae.InnerException); + if (!OperatingSystem.IsWindows()) + { + Assert.IsType(ae.InnerException); + } } } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs index 21e5385bdb9c2..b3493381933ad 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs @@ -38,7 +38,21 @@ public static Task WhenAllOrAnyFailedWithTimeout(params Task[] tasks) // On Windows, null ciphers (no encryption) are supported. if (OperatingSystem.IsWindows()) { - return true; + if (!PlatformDetection.IsWindows10OrLater) + { + // All old versions support null encryption + return true; + } + + try + { + // New Windows can support null but it may be disabled in Azure images + using (Process p = Process.Start(new ProcessStartInfo("powershell", "-Command Get-TlsCipherSuite") { RedirectStandardOutput = true, RedirectStandardError = true })) + { + return p.StandardOutput.ReadToEnd().Contains("WITH_NULL"); + } + } + catch { return true; } // assume availability } // On macOS and Android, the null cipher (no encryption) is not supported.