Debian 10/Win8.1 fixes: Allow explicitly using SSLv3, TLS1.0/1.1 (dotnet/corefx#39579)
authorKrzysztof Wicher <mordotymoja@gmail.com>
Fri, 26 Jul 2019 23:43:12 +0000 (16:43 -0700)
committerGitHub <noreply@github.com>
Fri, 26 Jul 2019 23:43:12 +0000 (16:43 -0700)
* debian 10 fixes

* Fix Windows 8.1 (product issue)

* expand SSL_CTX_set_min/max_proto_version macro in attempt to fix the build

* define SSL_CTRL_SET_MIN/MAX_PROTO_VERSION when not defined

* Apply Win8.1 fix to all platforms in attempt to fix OSX

* check if failing test with excluded SSL2 passes on OSX

* Filter out incompatible protocols at the source instead of each callsite

* Remove ResetProtocolRestrictions from header file

* Update src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs

Co-Authored-By: Jeremy Barton <jbarton@microsoft.com>
* revert files with only whitespace changes

Commit migrated from https://github.com/dotnet/corefx/commit/d5b91dc5e2b1c4bc73c4ba2070fd7cb8f7013b49

src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c
src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs
src/libraries/System.Net.Security/tests/FunctionalTests/CertificateValidationClientServer.cs
src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs
src/libraries/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs
src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNegotiatedCipherSuiteTest.cs
src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs
src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSystemDefaultsTest.cs

index d23d070..7764464 100644 (file)
@@ -106,6 +106,19 @@ static long TrySetECDHNamedCurve(SSL_CTX* ctx)
 #endif
 }
 
+static void ResetProtocolRestrictions(SSL_CTX* ctx)
+{
+#ifndef SSL_CTRL_SET_MIN_PROTO_VERSION
+#define SSL_CTRL_SET_MIN_PROTO_VERSION 123
+#endif
+#ifndef SSL_CTRL_SET_MAX_PROTO_VERSION
+#define SSL_CTRL_SET_MAX_PROTO_VERSION 124
+#endif
+
+    SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, 0, NULL);
+    SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, 0, NULL);
+}
+
 void CryptoNative_SetProtocolOptions(SSL_CTX* ctx, SslProtocols protocols)
 {
     // Ensure that ECDHE is available
@@ -152,6 +165,10 @@ void CryptoNative_SetProtocolOptions(SSL_CTX* ctx, SslProtocols protocols)
         protocolOptions |= SSL_OP_NO_TLSv1_3;
     }
 
+    // We manually set protocols - we need to reset OpenSSL restrictions
+    // to a maximum possible range
+    ResetProtocolRestrictions(ctx);
+
     // OpenSSL 1.0 calls this long, OpenSSL 1.1 calls it unsigned long.
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wsign-conversion"
@@ -327,6 +344,7 @@ int32_t CryptoNative_SetEncryptionPolicy(SSL_CTX* ctx, EncryptionPolicy policy)
         case NoEncryption:
             // No minimum security policy, same as OpenSSL 1.0
             SSL_CTX_set_security_level(ctx, 0);
+            ResetProtocolRestrictions(ctx);
             return true;
         case RequireEncryption:
             return true;
index 13fd8be..d7189ea 100644 (file)
@@ -17,7 +17,7 @@ namespace System.Net.Security
             ApplicationProtocols = sslClientAuthenticationOptions.ApplicationProtocols;
             CertValidationDelegate = remoteCallback;
             CheckCertName = true;
-            EnabledSslProtocols = sslClientAuthenticationOptions.EnabledSslProtocols;
+            EnabledSslProtocols = FilterOutIncompatibleSslProtocols(sslClientAuthenticationOptions.EnabledSslProtocols);
             EncryptionPolicy = sslClientAuthenticationOptions.EncryptionPolicy;
             IsServer = false;
             RemoteCertRequired = true;
@@ -36,7 +36,7 @@ namespace System.Net.Security
             AllowRenegotiation = sslServerAuthenticationOptions.AllowRenegotiation;
             ApplicationProtocols = sslServerAuthenticationOptions.ApplicationProtocols;
             CheckCertName = false;
-            EnabledSslProtocols = sslServerAuthenticationOptions.EnabledSslProtocols;
+            EnabledSslProtocols = FilterOutIncompatibleSslProtocols(sslServerAuthenticationOptions.EnabledSslProtocols);
             EncryptionPolicy = sslServerAuthenticationOptions.EncryptionPolicy;
             IsServer = true;
             RemoteCertRequired = sslServerAuthenticationOptions.ClientCertificateRequired;
@@ -52,6 +52,21 @@ namespace System.Net.Security
             CipherSuitesPolicy = sslServerAuthenticationOptions.CipherSuitesPolicy;
         }
 
+        private static SslProtocols FilterOutIncompatibleSslProtocols(SslProtocols protocols)
+        {
+            if (protocols.HasFlag(SslProtocols.Tls12) || protocols.HasFlag(SslProtocols.Tls13))
+            {
+#pragma warning disable 0618
+                // SSL2 is mutually exclusive with >= TLS1.2
+                // On Windows10 SSL2 flag has no effect but on earlier versions of the OS
+                // opting into both SSL2 and >= TLS1.2 causes negotiation to always fail.
+                protocols &= ~SslProtocols.Ssl2;
+#pragma warning restore 0618
+            }
+
+            return protocols;
+        }
+
         internal bool AllowRenegotiation { get; set; }
         internal string TargetHost { get; set; }
         internal X509CertificateCollection ClientCertificates { get; set; }
index 3f9764b..7d47353 100644 (file)
@@ -16,7 +16,7 @@ namespace System.Net.Security.Tests
 
     public class CertificateValidationClientServer : IDisposable
     {
-        private readonly ITestOutputHelper _output;        
+        private readonly ITestOutputHelper _output;
         private readonly X509Certificate2 _clientCertificate;
         private readonly X509Certificate2Collection _clientCertificateCollection;
         private readonly X509Certificate2 _serverCertificate;
@@ -47,7 +47,7 @@ namespace System.Net.Security.Tests
         [InlineData(true)]
         public async Task CertificateValidationClientServer_EndToEnd_Ok(bool useClientSelectionCallback)
         {
-            IPEndPoint endPoint = new IPEndPoint(IPAddress.IPv6Loopback, 0);
+            IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 0);
             var server = new TcpListener(endPoint);
             server.Start();
 
@@ -67,7 +67,7 @@ namespace System.Net.Security.Tests
                 _clientCertificateRemovedByFilter = true;
             }
 
-            using (var clientConnection = new TcpClient(AddressFamily.InterNetworkV6))
+            using (var clientConnection = new TcpClient())
             {
                 IPEndPoint serverEndPoint = (IPEndPoint)server.LocalEndpoint;
 
@@ -204,7 +204,7 @@ namespace System.Net.Security.Tests
             // Verify that the certificate is in the trustedChain.
             _output.WriteLine($"cert: subject={cert.Subject}, issuer={cert.Issuer}, thumbprint={cert.Thumbprint}");
             Assert.Equal(cert.Thumbprint, trustedChain.ChainElements[0].Certificate.Thumbprint);
-            
+
             // Verify that the root certificate in the chain is the one that issued the received certificate.
             foreach (X509ChainElement element in trustedChain.ChainElements)
             {
index d3a9f20..545111f 100644 (file)
@@ -139,10 +139,10 @@ namespace System.Net.Security.Tests
         {
             _log.WriteLine("Server: " + serverSslProtocols + "; Client: " + clientSslProtocols);
 
-            IPEndPoint endPoint = new IPEndPoint(IPAddress.IPv6Loopback, 0);
+            IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 0);
 
             using (var server = new DummyTcpServer(endPoint, encryptionPolicy))
-            using (var client = new TcpClient(AddressFamily.InterNetworkV6))
+            using (var client = new TcpClient())
             {
                 server.SslProtocols = serverSslProtocols;
                 await client.ConnectAsync(server.RemoteEndPoint.Address, server.RemoteEndPoint.Port);
index 0abb767..c2fe64a 100644 (file)
@@ -99,11 +99,11 @@ namespace System.Net.Security.Tests
             int timeOut = expectedToFail ? TestConfiguration.FailingTestTimeoutMiliseconds
                 : TestConfiguration.PassingTestTimeoutMilliseconds;
 
-            IPEndPoint endPoint = new IPEndPoint(IPAddress.IPv6Loopback, 0);
+            IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 0);
             var server = new TcpListener(endPoint);
             server.Start();
 
-            using (var clientConnection = new TcpClient(AddressFamily.InterNetworkV6))
+            using (var clientConnection = new TcpClient())
             {
                 IPEndPoint serverEndPoint = (IPEndPoint)server.LocalEndpoint;
 
index 971fa02..3d94a6d 100644 (file)
@@ -21,12 +21,12 @@ namespace System.Net.Security.Tests
     public class NegotiatedCipherSuiteTest
     {
 #pragma warning disable CS0618 // Ssl2 and Ssl3 are obsolete
-        private const SslProtocols AllProtocols =
+        public const SslProtocols AllProtocols =
             SslProtocols.Ssl2 | SslProtocols.Ssl3 |
             SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;
 #pragma warning restore CS0618
 
-        private const SslProtocols NonTls13Protocols = AllProtocols & (~SslProtocols.Tls13);
+        public const SslProtocols NonTls13Protocols = AllProtocols & (~SslProtocols.Tls13);
 
         private static bool IsKnownPlatformSupportingTls13 => PlatformDetection.SupportsTls13;
         private static bool CipherSuitesPolicySupported => s_cipherSuitePolicySupported.Value;
@@ -93,11 +93,17 @@ namespace System.Net.Security.Tests
             };
 
             NegotiatedParams ret = ConnectAndGetNegotiatedParams(p, p);
-            ret.Succeeded();
-
-            Assert.True(
-                s_protocolCipherSuiteLookup[protocol].Contains(ret.CipherSuite),
-                $"`{ret.CipherSuite}` is not recognized as {protocol} cipher suite");
+            if (ret.HasSucceeded)
+            {
+                Assert.True(
+                    s_protocolCipherSuiteLookup[protocol].Contains(ret.CipherSuite),
+                    $"`{ret.CipherSuite}` is not recognized as {protocol} cipher suite");
+            }
+            else
+            {
+                // currently TLS 1.2 should be enabled by all known implementations
+                Assert.NotEqual(SslProtocols.Tls12, protocol);
+            }
         }
 
         [Fact]
index 4e4ca99..07696a1 100644 (file)
@@ -67,7 +67,7 @@ namespace System.Net.Security.Tests
             var validationCallback = new RemoteCertificateValidationCallback((object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
             {
                 Assert.Equal(serverCert, certificate);
-                return true; 
+                return true;
             });
 
             VirtualNetwork vn = new VirtualNetwork();
@@ -192,7 +192,7 @@ namespace System.Net.Security.Tests
             return new SslServerAuthenticationOptions()
             {
                 ClientCertificateRequired = false,
-                EnabledSslProtocols = SslProtocols.Tls,
+                EnabledSslProtocols = SslProtocols.None,
                 CertificateRevocationCheckMode = X509RevocationMode.NoCheck,
             };
         }
index 311ea12..4943401 100644 (file)
@@ -39,15 +39,15 @@ namespace System.Net.Security.Tests
         [InlineData(SslProtocols.None, null)]
         [InlineData(null, SslProtocols.None)]
         [InlineData(SslProtocols.None, SslProtocols.None)]
-        [InlineData(null, SslProtocols.Tls11)]
-        [InlineData(SslProtocols.Tls11, null)]
+        [InlineData(NegotiatedCipherSuiteTest.NonTls13Protocols, SslProtocols.Tls11)]
+        [InlineData(SslProtocols.Tls11, NegotiatedCipherSuiteTest.NonTls13Protocols)]
         [InlineData(null, SslProtocols.Tls12)]
         [InlineData(SslProtocols.Tls12, null)]
         [InlineData(SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12, null)]
         [InlineData(null, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12)]
 #pragma warning disable 0618
-        [InlineData(SslProtocols.Default, null)]
-        [InlineData(null, SslProtocols.Default)]
+        [InlineData(SslProtocols.Default, NegotiatedCipherSuiteTest.NonTls13Protocols)]
+        [InlineData(NegotiatedCipherSuiteTest.NonTls13Protocols, SslProtocols.Default)]
 #pragma warning restore 0618
         public async Task ClientAndServer_OneOrBothUseDefault_Ok(SslProtocols? clientProtocols, SslProtocols? serverProtocols)
         {