diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Unix.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Unix.cs deleted file mode 100644 index c993df824c..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Unix.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Data.SqlClient.ManagedSni; - -namespace Microsoft.Data.SqlClient -{ - sealed internal partial class TdsParser - { - internal void PostReadAsyncForMars() - { - // No-Op - } - - private void LoadSSPILibrary() - { - // No - Op - } - - private void WaitForSSLHandShakeToComplete(ref uint error, ref int protocolVersion) - { - // No - Op - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs deleted file mode 100644 index 2c924b3b79..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Diagnostics; - -namespace Microsoft.Data.SqlClient -{ - internal sealed partial class TdsParser - { - internal void PostReadAsyncForMars() - { - if (TdsParserStateObjectFactory.UseManagedSNI) - return; - - // HACK HACK HACK - for Async only - // Have to post read to initialize MARS - will get callback on this when connection goes - // down or is closed. - - PacketHandle temp = default; - uint error = TdsEnums.SNI_SUCCESS; - - _pMarsPhysicalConObj.IncrementPendingCallbacks(); - SessionHandle handle = _pMarsPhysicalConObj.SessionHandle; - // we do not need to consider partial packets when making this read because we - // expect this read to pend. a partial packet should not exist at setup of the - // parser - Debug.Assert(_physicalStateObj.PartialPacket==null); - temp = _pMarsPhysicalConObj.ReadAsync(handle, out error); - - Debug.Assert(temp.Type == PacketHandle.NativePointerType, "unexpected packet type when requiring NativePointer"); - - if (temp.NativePointer != IntPtr.Zero) - { - // Be sure to release packet, otherwise it will be leaked by native. - _pMarsPhysicalConObj.ReleasePacket(temp); - } - - Debug.Assert(IntPtr.Zero == temp.NativePointer, "unexpected syncReadPacket without corresponding SNIPacketRelease"); - if (TdsEnums.SNI_SUCCESS_IO_PENDING != error) - { - Debug.Assert(TdsEnums.SNI_SUCCESS != error, "Unexpected successful read async on physical connection before enabling MARS!"); - _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); - ThrowExceptionAndWarning(_physicalStateObj); - } - } - - private void WaitForSSLHandShakeToComplete(ref uint error, ref int protocolVersion) - { - // in the case where an async connection is made, encryption is used and Windows Authentication is used, - // wait for SSL handshake to complete, so that the SSL context is fully negotiated before we try to use its - // Channel Bindings as part of the Windows Authentication context build (SSL handshake must complete - // before calling SNISecGenClientContext). - error = _physicalStateObj.WaitForSSLHandShakeToComplete(out protocolVersion); - if (error != TdsEnums.SNI_SUCCESS) - { - _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); - ThrowExceptionAndWarning(_physicalStateObj); - } - } - } // tdsparser -}//namespace diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index b5febf7add..ca1609cd96 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -11,9 +11,8 @@ using System.Diagnostics; using System.Globalization; using System.IO; -#if NET using System.Security.Authentication; -#else +#if NETFRAMEWORK using System.Runtime.CompilerServices; #endif using System.Text; @@ -646,7 +645,13 @@ internal void EnableMars() ThrowExceptionAndWarning(_physicalStateObj); } - PostReadAsyncForMars(); + error = _pMarsPhysicalConObj.PostReadAsyncForMars(_physicalStateObj); + if (error != TdsEnums.SNI_SUCCESS_IO_PENDING) + { + Debug.Assert(error != TdsEnums.SNI_SUCCESS, "Unexpected successful read async on physical connection before enabling MARS!"); + _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); + ThrowExceptionAndWarning(_physicalStateObj); + } _physicalStateObj = CreateSession(); // Create and open default MARS stateObj and connection. } @@ -902,8 +907,23 @@ private void EnableSsl(uint info, SqlConnectionEncryptOption encrypt, bool integ ThrowExceptionAndWarning(_physicalStateObj); } - int protocolVersion = 0; - WaitForSSLHandShakeToComplete(ref error, ref protocolVersion); + uint protocolVersion = 0; + + // in the case where an async connection is made, encryption is used and Windows Authentication is used, + // wait for SSL handshake to complete, so that the SSL context is fully negotiated before we try to use its + // Channel Bindings as part of the Windows Authentication context build (SSL handshake must complete + // before calling SNISecGenClientContext). +#if NET + if (OperatingSystem.IsWindows()) +#endif + { + error = _physicalStateObj.WaitForSSLHandShakeToComplete(out protocolVersion); + if (error != TdsEnums.SNI_SUCCESS) + { + _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); + ThrowExceptionAndWarning(_physicalStateObj); + } + } SslProtocols protocol = (SslProtocols)protocolVersion; string warningMessage = protocol.GetProtocolWarning(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs index 71ef5e9381..95dd0d9731 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs @@ -10,17 +10,6 @@ namespace Microsoft.Data.SqlClient { internal sealed partial class TdsParser { - internal struct SNIErrorDetails - { - public string errorMessage; - public uint nativeError; - public uint sniErrorNumber; - public int provider; - public uint lineNumber; - public string function; - public Exception exception; - } - internal static void FillGuidBytes(Guid guid, Span buffer) => guid.TryWriteBytes(buffer); internal static void FillDoubleBytes(double value, Span buffer) => BinaryPrimitives.TryWriteInt64LittleEndian(buffer, BitConverter.DoubleToInt64Bits(value)); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs index bb3b07b0e8..4cd52593e8 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs @@ -92,8 +92,6 @@ internal abstract void CreatePhysicalSNIHandle( internal abstract uint EnableSsl(ref uint info, bool tlsFirst, string serverCertificateFilename); - internal abstract uint WaitForSSLHandShakeToComplete(out int protocolVersion); - internal abstract void Dispose(); internal abstract uint CheckConnection(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs index 16be2e763c..82e95e127b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs @@ -365,6 +365,8 @@ internal override uint EnableMars(ref uint info) return TdsEnums.SNI_ERROR; } + internal override uint PostReadAsyncForMars(TdsParserStateObject physicalStateObject) => TdsEnums.SNI_SUCCESS_IO_PENDING; + internal override uint EnableSsl(ref uint info, bool tlsFirst, string serverCertificateFilename) { SniHandle sessionHandle = GetSessionSNIHandleHandleOrThrow(); @@ -386,10 +388,10 @@ internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) return TdsEnums.SNI_SUCCESS; } - internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) + internal override uint WaitForSSLHandShakeToComplete(out uint protocolVersion) { - protocolVersion = GetSessionSNIHandleHandleOrThrow().ProtocolVersion; - return 0; + protocolVersion = (uint)GetSessionSNIHandleHandleOrThrow().ProtocolVersion; + return TdsEnums.SNI_SUCCESS; } internal override SniErrorDetails GetErrorDetails() 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 895c46c7bf..9d0dfa385b 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 @@ -385,6 +385,43 @@ internal override uint DisableSsl() internal override uint EnableMars(ref uint info) => SniNativeWrapper.SniAddProvider(Handle, Provider.SMUX_PROV, ref info); + internal override uint PostReadAsyncForMars(TdsParserStateObject physicalStateObject) + { + // HACK HACK HACK - for Async only + // Have to post read to initialize MARS - will get callback on this when connection goes + // down or is closed. + + PacketHandle temp = default; + uint error = TdsEnums.SNI_SUCCESS; + +#if NETFRAMEWORK + RuntimeHelpers.PrepareConstrainedRegions(); +#endif + try + { } + finally + { + IncrementPendingCallbacks(); + SessionHandle handle = SessionHandle; + // we do not need to consider partial packets when making this read because we + // expect this read to pend. a partial packet should not exist at setup of the + // parser + Debug.Assert(physicalStateObject.PartialPacket == null); + temp = ReadAsync(handle, out error); + + Debug.Assert(temp.Type == PacketHandle.NativePointerType, "unexpected packet type when requiring NativePointer"); + + if (temp.NativePointer != IntPtr.Zero) + { + // Be sure to release packet, otherwise it will be leaked by native. + ReleasePacket(temp); + } + } + + Debug.Assert(IntPtr.Zero == temp.NativePointer, "unexpected syncReadPacket without corresponding SNIPacketRelease"); + return error; + } + internal override uint EnableSsl(ref uint info, bool tlsFirst, string serverCertificateFilename) { AuthProviderInfo authInfo = new AuthProviderInfo(); @@ -399,7 +436,7 @@ internal override uint EnableSsl(ref uint info, bool tlsFirst, string serverCert internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) => SniNativeWrapper.SniSetInfo(Handle, QueryType.SNI_QUERY_CONN_BUFSIZE, ref unsignedPacketSize); - internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) + internal override uint WaitForSSLHandShakeToComplete(out uint protocolVersion) { uint returnValue = SniNativeWrapper.SniWaitForSslHandshakeToComplete(Handle, GetTimeoutRemaining(), out uint nativeProtocolVersion); var nativeProtocol = (NativeProtocols)nativeProtocolVersion; @@ -407,35 +444,35 @@ internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) #pragma warning disable CA5398 // Avoid hardcoded SslProtocols values if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_2_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_2_SERVER)) { - protocolVersion = (int)SslProtocols.Tls12; + protocolVersion = (uint)SslProtocols.Tls12; } else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_3_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_3_SERVER)) { /* The SslProtocols.Tls13 is supported by netcoreapp3.1 and later */ - protocolVersion = (int)SslProtocols.Tls13; + protocolVersion = (uint)SslProtocols.Tls13; } else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_1_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_1_SERVER)) { - protocolVersion = (int)SslProtocols.Tls11; + protocolVersion = (uint)SslProtocols.Tls11; } else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_0_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_0_SERVER)) { - protocolVersion = (int)SslProtocols.Tls; + protocolVersion = (uint)SslProtocols.Tls; } else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL3_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL3_SERVER)) { // SSL 2.0 and 3.0 are only referenced to log a warning, not explicitly used for connections #pragma warning disable CS0618, CA5397 - protocolVersion = (int)SslProtocols.Ssl3; + protocolVersion = (uint)SslProtocols.Ssl3; } else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL2_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL2_SERVER)) { - protocolVersion = (int)SslProtocols.Ssl2; + protocolVersion = (uint)SslProtocols.Ssl2; #pragma warning restore CS0618, CA5397 } else //if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_NONE)) { - protocolVersion = (int)SslProtocols.None; + protocolVersion = (uint)SslProtocols.None; } #pragma warning restore CA5398 // Avoid hardcoded SslProtocols values return returnValue; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 3acd517f73..a97696f8b0 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -11,9 +11,8 @@ using System.Diagnostics; using System.Globalization; using System.IO; -#if NET using System.Security.Authentication; -#else +#if NETFRAMEWORK using System.Runtime.CompilerServices; #endif using System.Text; @@ -697,31 +696,10 @@ internal void EnableMars() ThrowExceptionAndWarning(_physicalStateObj); } - // HACK HACK HACK - for Async only - // Have to post read to intialize MARS - will get callback on this when connection goes - // down or is closed. - - IntPtr temp = IntPtr.Zero; - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { } - finally - { - _pMarsPhysicalConObj.IncrementPendingCallbacks(); - - error = SniNativeWrapper.SniReadAsync(_pMarsPhysicalConObj.Handle, ref temp); - - if (temp != IntPtr.Zero) - { - // Be sure to release packet, otherwise it will be leaked by native. - SniNativeWrapper.SniPacketRelease(temp); - } - } - Debug.Assert(IntPtr.Zero == temp, "unexpected syncReadPacket without corresponding SNIPacketRelease"); - if (TdsEnums.SNI_SUCCESS_IO_PENDING != error) + error = _pMarsPhysicalConObj.PostReadAsyncForMars(_physicalStateObj); + if (error != TdsEnums.SNI_SUCCESS_IO_PENDING) { - Debug.Assert(TdsEnums.SNI_SUCCESS != error, "Unexpected successful read async on physical connection before enabling MARS!"); + Debug.Assert(error != TdsEnums.SNI_SUCCESS, "Unexpected successful read async on physical connection before enabling MARS!"); _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); ThrowExceptionAndWarning(_physicalStateObj); } @@ -996,19 +974,26 @@ private void EnableSsl(uint info, SqlConnectionEncryptOption encrypt, bool integ ThrowExceptionAndWarning(_physicalStateObj); } + uint protocolVersion = 0; + // in the case where an async connection is made, encryption is used and Windows Authentication is used, // wait for SSL handshake to complete, so that the SSL context is fully negotiated before we try to use its // Channel Bindings as part of the Windows Authentication context build (SSL handshake must complete // before calling SNISecGenClientContext). - error = SniNativeWrapper.SniWaitForSslHandshakeToComplete(_physicalStateObj.Handle, _physicalStateObj.GetTimeoutRemaining(), out uint protocolVersion); - - if (error != TdsEnums.SNI_SUCCESS) +#if NET + if (OperatingSystem.IsWindows()) +#endif { - _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); - ThrowExceptionAndWarning(_physicalStateObj); + error = _physicalStateObj.WaitForSSLHandShakeToComplete(out protocolVersion); + if (error != TdsEnums.SNI_SUCCESS) + { + _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); + ThrowExceptionAndWarning(_physicalStateObj); + } } - string warningMessage = ((System.Security.Authentication.SslProtocols)protocolVersion).GetProtocolWarning(); + SslProtocols protocol = (SslProtocols)protocolVersion; + string warningMessage = protocol.GetProtocolWarning(); if (!string.IsNullOrEmpty(warningMessage)) { if (!encrypt && LocalAppContextSwitches.SuppressInsecureTlsWarning) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index 807474d98b..9fe5864696 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -172,9 +172,51 @@ internal override uint DisableSsl() internal override uint EnableMars(ref uint info) => SniNativeWrapper.SniAddProvider(Handle, Provider.SMUX_PROV, ref info); + internal override uint PostReadAsyncForMars(TdsParserStateObject physicalStateObject) + { + // HACK HACK HACK - for Async only + // Have to post read to initialize MARS - will get callback on this when connection goes + // down or is closed. + + PacketHandle temp = default; + uint error = TdsEnums.SNI_SUCCESS; + +#if NETFRAMEWORK + RuntimeHelpers.PrepareConstrainedRegions(); +#endif + try + { } + finally + { + IncrementPendingCallbacks(); + SessionHandle handle = SessionHandle; + // we do not need to consider partial packets when making this read because we + // expect this read to pend. a partial packet should not exist at setup of the + // parser + Debug.Assert(physicalStateObject.PartialPacket == null); + temp = ReadAsync(handle, out error); + + Debug.Assert(temp.Type == PacketHandle.NativePointerType, "unexpected packet type when requiring NativePointer"); + + if (temp.NativePointer != IntPtr.Zero) + { + // Be sure to release packet, otherwise it will be leaked by native. + ReleasePacket(temp); + } + } + + Debug.Assert(IntPtr.Zero == temp.NativePointer, "unexpected syncReadPacket without corresponding SNIPacketRelease"); + return error; + } + internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) => SniNativeWrapper.SniSetInfo(Handle, QueryType.SNI_QUERY_CONN_BUFSIZE, ref unsignedPacketSize); + internal override uint WaitForSSLHandShakeToComplete(out uint protocolVersion) + { + return SniNativeWrapper.SniWaitForSslHandshakeToComplete(Handle, GetTimeoutRemaining(), out protocolVersion); + } + internal override SniErrorDetails GetErrorDetails() { SniNativeWrapper.SniGetLastError(out SniError sniError); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index 781f360991..4d7684327e 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -533,12 +533,16 @@ internal long TimeoutTime internal abstract uint SniGetConnectionId(ref Guid clientConnectionId); + internal abstract uint WaitForSSLHandShakeToComplete(out uint protocolVersion); + internal abstract uint DisableSsl(); internal abstract SspiContextProvider CreateSspiContextProvider(); internal abstract uint EnableMars(ref uint info); + internal abstract uint PostReadAsyncForMars(TdsParserStateObject physicalStateObject); + internal abstract uint SetConnectionBufferSize(ref uint unsignedPacketSize); internal abstract void DisposePacketCache();