Make default SocketsHttpHandler SslProtocols include Tls11/12 on Win7/2008R2 (dotnet...
authorStephen Toub <stoub@microsoft.com>
Wed, 4 Apr 2018 16:59:09 +0000 (09:59 -0700)
committerGitHub <noreply@github.com>
Wed, 4 Apr 2018 16:59:09 +0000 (09:59 -0700)
Windows 7 and Windows 2008 R2 support TLS 1.1 and 1.2, but for legacy reasons by default those protocols are not enabled when a developer elects to use the system default.  However, in .NET Core 2.0 and earlier, HttpClientHandler would enable them, due to being a wrapper for WinHTTP, which enabled them.  Both for compatibility and because we prefer those higher protocols whenever possible, SocketsHttpHandler also pretends they're part of the default when running on Win7/2008R2.

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

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs
src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs

index 65e2bf4..ec205ff 100644 (file)
@@ -9,6 +9,7 @@ using System.Net.Security;
 using System.Net.Sockets;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
+using System.Security.Authentication;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
@@ -18,6 +19,8 @@ namespace System.Net.Http
     /// <summary>Provides a pool of connections to the same endpoint.</summary>
     internal sealed class HttpConnectionPool : IDisposable
     {
+        private static readonly bool s_isWindows7Or2008R2 = GetIsWindows7Or2008R2();
+
         private readonly HttpConnectionPoolManager _poolManager;
         private readonly HttpConnectionKind _kind;
         private readonly string _host;
@@ -144,6 +147,16 @@ namespace System.Net.Http
             sslOptions.ApplicationProtocols = null; // explicitly ignore any ApplicationProtocols set
             sslOptions.TargetHost = sslHostName; // always use the key's name rather than whatever was specified
 
+            // Windows 7 and Windows 2008 R2 support TLS 1.1 and 1.2, but for legacy reasons by default those protocols
+            // are not enabled when a developer elects to use the system default.  However, in .NET Core 2.0 and earlier,
+            // HttpClientHandler would enable them, due to being a wrapper for WinHTTP, which enabled them.  Both for
+            // compatibility and because we prefer those higher protocols whenever possible, SocketsHttpHandler also
+            // pretends they're part of the default when running on Win7/2008R2.
+            if (s_isWindows7Or2008R2 && sslOptions.EnabledSslProtocols == SslProtocols.None)
+            {
+                sslOptions.EnabledSslProtocols = SecurityProtocol.DefaultSecurityProtocols;
+            }
+
             return sslOptions;
         }
 
@@ -736,6 +749,19 @@ namespace System.Net.Http
             return false;
         }
 
+        /// <summary>Gets whether we're running on Windows 7 or Windows 2008 R2.</summary>
+        private static bool GetIsWindows7Or2008R2()
+        {
+            OperatingSystem os = Environment.OSVersion;
+            if (os.Platform == PlatformID.Win32NT)
+            {
+                // Both Windows 7 and Windows 2008 R2 report version 6.1.
+                Version v = os.Version;
+                return v.Major == 6 && v.Minor == 1;
+            }
+            return false;
+        }
+
         // For diagnostic purposes
         public override string ToString() =>
             $"{nameof(HttpConnectionPool)}" +
index e578aa7..4f77978 100644 (file)
@@ -210,7 +210,7 @@ namespace System.Net.Http.Functional.Tests
         }
 
         [OuterLoop] // TODO: Issue #11345
-        [ConditionalFact(nameof(SslDefaultsToTls12))]
+        [Fact]
         public async Task GetAsync_NoSpecifiedProtocol_DefaultsToTls12()
         {
             if (!BackendSupportsSslConfiguration)
@@ -223,7 +223,7 @@ namespace System.Net.Http.Functional.Tests
             {
                 handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
 
-                var options = new LoopbackServer.Options { UseSsl = true };
+                var options = new LoopbackServer.Options { UseSsl = true, SslProtocols = SslProtocols.Tls12 };
                 await LoopbackServer.CreateServerAsync(async (server, url) =>
                 {
                     await TestHelper.WhenAllCompletedOrAnyFailed(
@@ -329,9 +329,5 @@ namespace System.Net.Http.Functional.Tests
                 }
             }
         }
-
-        private static bool SslDefaultsToTls12 => !PlatformDetection.IsWindows7;
-        // TLS 1.2 may not be enabled on Win7
-        // https://technet.microsoft.com/en-us/library/dn786418.aspx#BKMK_SchannelTR_TLS12
     }
 }
index d11df7b..c134274 100644 (file)
@@ -25,7 +25,7 @@ namespace System.Net.Security.Tests
         }
 
         [Fact]
-        [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "CI uses old Framework version, which doesn't support using SslProtocols.None for SystemDefaultTlsVersions behavior")]
+        [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "CI uses old Framework version, which doesn't support using SslProtocols.None for default system behavior")]
         public async Task ClientAsyncAuthenticate_SslStreamClientServerNone_UseStrongCryptoSet()
         {
             SslProtocols protocol = SslProtocols.None;