diff --git a/BUILDGUIDE.md b/BUILDGUIDE.md index cc9a60e538..1ebb710197 100644 --- a/BUILDGUIDE.md +++ b/BUILDGUIDE.md @@ -257,6 +257,12 @@ To use this feature, you must enable the following AppContext switch at applicat **"Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior"** +## Enabling OS secure protocols preference + +TLS 1.3 has been excluded due to the fact that the driver lacks full support. To enable OS preferences as before, enable the following AppContext switch on application startup: + +**"Switch.Microsoft.Data.SqlClient.EnableSecureProtocolsByOS"** + ## Debugging SqlClient on Linux from Windows For enhanced developer experience, we support debugging SqlClient on Linux from Windows, using the project "**Microsoft.Data.SqlClient.DockerLinuxTest**" that requires "Container Tools" to be enabled in Visual Studio. You may import configuration: [VS19Components.vsconfig](./tools/vsconfig/VS19Components.vsconfig) if not enabled already. diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs index 20159ca382..7f1b3e17ea 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -264,7 +264,7 @@ internal struct SNI_Error private static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out ProviderEnum provNum); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern uint SNIInitialize([In] IntPtr pmo); + private static extern uint SNIInitialize([In] bool useSystemDefaultSecureProtocols, [In] IntPtr pmo); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] private static extern uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn); @@ -340,7 +340,7 @@ internal static uint SniGetConnectionIPString(SNIHandle pConn, ref string connIP internal static uint SNIInitialize() { - return SNIInitialize(IntPtr.Zero); + return SNIInitialize(LocalAppContextSwitches.UseSystemDefaultSecureProtocols, IntPtr.Zero); } internal static unsafe uint SNIOpenMarsSession(ConsumerInfo consumerInfo, SNIHandle parent, ref IntPtr pConn, bool fSync, SqlConnectionIPAddressPreference ipPreference, SQLDNSInfo cachedDNSInfo) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs index bd3facd5fc..dbee403f41 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Security.Authentication; namespace Microsoft.Data.SqlClient.SNI { @@ -11,6 +12,16 @@ namespace Microsoft.Data.SqlClient.SNI /// internal abstract class SNIHandle { + /// + /// Exclude TLS 1.3 (not fully supported). + /// + protected readonly SslProtocols SupportedProtocols = LocalAppContextSwitches.UseSystemDefaultSecureProtocols ? SslProtocols.None : SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls + //protected readonly SslProtocols SupportedProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls +#pragma warning disable CS0618 // Type or member is obsolete + | SslProtocols.Ssl2 | SslProtocols.Ssl3 +#pragma warning restore CS0618 // Type or member is obsolete + ; + /// /// Dispose class /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index a11779870b..c0758f3ab5 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -355,8 +355,7 @@ public override uint EnableSsl(uint options) _validateCert = (options & TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE) != 0; try { - - _sslStream.AuthenticateAsClient(_targetServer); + _sslStream.AuthenticateAsClient(_targetServer, null, SupportedProtocols, true); _sslOverTdsStream.FinishHandshake(); } catch (AuthenticationException aue) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index 0ee3e91291..a38ff3207e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -587,7 +587,7 @@ public override uint EnableSsl(uint options) try { - _sslStream.AuthenticateAsClient(_targetServer); + _sslStream.AuthenticateAsClient(_targetServer, null, SupportedProtocols, true); _sslOverTdsStream.FinishHandshake(); } catch (AuthenticationException aue) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index ecb6e0bb43..89df41b417 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -421,14 +421,10 @@ internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) protocolVersion = (int)SslProtocols.Ssl2; #pragma warning restore CS0618 // Type or member is obsolete : SSL is depricated } - else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_NONE)) + else //if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_NONE)) { protocolVersion = (int)SslProtocols.None; } - else - { - throw new ArgumentException(StringsHelper.Format(StringsHelper.net_invalid_enum, nameof(NativeProtocols)), nameof(NativeProtocols)); - } return returnValue; } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs index b28c736977..abbfda7ede 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs @@ -89,7 +89,7 @@ internal static class SNINativeManagedWrapperX64 internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out ProviderEnum provNum); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIInitialize")] - internal static extern uint SNIInitialize([In] IntPtr pmo); + internal static extern uint SNIInitialize([In] bool useSystemDefaultSecureProtocols, [In] IntPtr pmo); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs index 2dc215ad36..b700e4b108 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs @@ -89,7 +89,7 @@ internal static class SNINativeManagedWrapperX86 internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out ProviderEnum provNum); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIInitialize")] - internal static extern uint SNIInitialize([In] IntPtr pmo); + internal static extern uint SNIInitialize([In] bool useSystemDefaultSecureProtocols, [In] IntPtr pmo); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index 19dd12587a..d1fb0ad3e5 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -585,11 +585,11 @@ private static uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapp SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out provNum); } - private static uint SNIInitialize([In] IntPtr pmo) + private static uint SNIInitialize([In] bool useSystemDefaultSecureProtocols, [In] IntPtr pmo) { return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIInitialize(pmo) : - SNINativeManagedWrapperX86.SNIInitialize(pmo); + SNINativeManagedWrapperX64.SNIInitialize(useSystemDefaultSecureProtocols, pmo) : + SNINativeManagedWrapperX86.SNIInitialize(useSystemDefaultSecureProtocols, pmo); } private static uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn) @@ -757,7 +757,7 @@ internal static uint SniGetConnectionIPString(SNIHandle pConn, ref string connIP internal static uint SNIInitialize() { - return SNIInitialize(IntPtr.Zero); + return SNIInitialize(LocalAppContextSwitches.UseSystemDefaultSecureProtocols, IntPtr.Zero); } internal static unsafe uint SNIOpenMarsSession(ConsumerInfo consumerInfo, SNIHandle parent, ref IntPtr pConn, bool fSync, SqlConnectionIPAddressPreference ipPreference, SQLDNSInfo cachedDNSInfo) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs index 9d2111ac24..c0947e5854 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs @@ -13,11 +13,13 @@ internal static partial class LocalAppContextSwitches private const string TypeName = nameof(LocalAppContextSwitches); internal const string MakeReadAsyncBlockingString = @"Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking"; internal const string LegacyRowVersionNullString = @"Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior"; + internal const string UseSystemDefaultSecureProtocolsString = @"Switch.Microsoft.Data.SqlClient.UseSystemDefaultSecureProtocols"; // safety switch internal const string EnableRetryLogicSwitch = "Switch.Microsoft.Data.SqlClient.EnableRetryLogic"; private static bool _makeReadAsyncBlocking; private static bool? s_LegacyRowVersionNullBehavior; + private static bool? s_UseSystemDefaultSecureProtocols; private static bool? s_isRetryEnabled = null; #if !NETFRAMEWORK @@ -70,15 +72,29 @@ public static bool LegacyRowVersionNullBehavior { if (s_LegacyRowVersionNullBehavior is null) { - bool value = false; - if (AppContext.TryGetSwitch(LegacyRowVersionNullString, out bool providedValue)) - { - value = providedValue; - } - s_LegacyRowVersionNullBehavior = value; + bool result; + result = AppContext.TryGetSwitch(LegacyRowVersionNullString, out result) ? result : false; + s_LegacyRowVersionNullBehavior = result; } return s_LegacyRowVersionNullBehavior.Value; } } + + /// + /// For backward compatibility, this switch can be on to jump back on OS preferences. + /// + public static bool UseSystemDefaultSecureProtocols + { + get + { + if (s_UseSystemDefaultSecureProtocols is null) + { + bool result; + result = AppContext.TryGetSwitch(UseSystemDefaultSecureProtocolsString, out result) ? result : false; + s_UseSystemDefaultSecureProtocols = result; + } + return s_UseSystemDefaultSecureProtocols.Value; + } + } } }