diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNILoadHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNILoadHandle.cs
index 1fa6c58a3f..9f50b85a7d 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNILoadHandle.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNILoadHandle.cs
@@ -55,5 +55,11 @@ public EncryptionOptions Options
return _encryptionOption;
}
}
+
+ ///
+ /// Verify client encryption possibility
+ ///
+ // TODO: by adding support ENCRYPT_NOT_SUP, it could be calculated.
+ public bool ClientOSEncryptionSupport => true;
}
}
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 04ec52be41..1e55b8626a 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
@@ -47,6 +47,11 @@ internal sealed partial class TdsParser
internal readonly int _objectID = Interlocked.Increment(ref _objectTypeCount);
internal int ObjectID => _objectID;
+ ///
+ /// Verify client encryption possibility.
+ ///
+ private bool ClientOSEncryptionSupport => TdsParserStateObjectFactory.Singleton.ClientOSEncryptionSupport;
+
// Default state object for parser
internal TdsParserStateObject _physicalStateObj = null; // Default stateObj and connection for Dbnetlib and non-MARS SNI.
@@ -464,6 +469,18 @@ internal void Connect(
_physicalStateObj.AssignPendingDNSInfo(serverInfo.UserProtocol, FQDNforDNSCahce, ref _connHandler.pendingSQLDNSObject);
}
+ if (!ClientOSEncryptionSupport)
+ {
+ //If encryption is required, an error will be thrown.
+ if (encrypt)
+ {
+ _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByClient(), "", 0));
+ _physicalStateObj.Dispose();
+ ThrowExceptionAndWarning(_physicalStateObj);
+ }
+ _encryptionOption = EncryptionOptions.NOT_SUP;
+ }
+
SqlClientEventSource.Log.TryTraceEvent(" Sending prelogin handshake");
SendPreLoginHandshake(instanceName, encrypt);
@@ -674,7 +691,7 @@ private void SendPreLoginHandshake(byte[] instanceName, bool encrypt)
case (int)PreLoginOptions.ENCRYPT:
if (_encryptionOption == EncryptionOptions.NOT_SUP)
{
- // If OS doesn't support encryption, inform server not supported.
+ //If OS doesn't support encryption and encryption is not required, inform server "not supported" by client.
payload[payloadLength] = (byte)EncryptionOptions.NOT_SUP;
}
else
@@ -885,7 +902,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
// Encrypt all.
_encryptionOption = EncryptionOptions.ON;
}
-
+ // NOT_SUP: No encryption.
break;
case (EncryptionOptions.NOT_SUP):
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs
index 62411969ff..980e0d556c 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs
@@ -18,7 +18,8 @@ internal sealed partial class SNILoadHandle : SafeHandle
internal readonly SNINativeMethodWrapper.SqlAsyncCallbackDelegate WriteAsyncCallbackDispatcher = new SNINativeMethodWrapper.SqlAsyncCallbackDelegate(WriteDispatcher);
private readonly uint _sniStatus = TdsEnums.SNI_UNINITIALIZED;
- private readonly EncryptionOptions _encryptionOption;
+ private readonly EncryptionOptions _encryptionOption = EncryptionOptions.OFF;
+ private bool? _clientOSEncryptionSupport = null;
private SNILoadHandle() : base(IntPtr.Zero, true)
{
@@ -30,30 +31,41 @@ private SNILoadHandle() : base(IntPtr.Zero, true)
finally
{
_sniStatus = SNINativeMethodWrapper.SNIInitialize();
-
- uint value = 0;
-
- // VSDevDiv 479597: If initialize fails, don't call QueryInfo.
- if (TdsEnums.SNI_SUCCESS == _sniStatus)
- {
- // Query OS to find out whether encryption is supported.
- SNINativeMethodWrapper.SNIQueryInfo(SNINativeMethodWrapper.QTypes.SNI_QUERY_CLIENT_ENCRYPT_POSSIBLE, ref value);
- }
-
- _encryptionOption = (value == 0) ? EncryptionOptions.NOT_SUP : EncryptionOptions.OFF;
-
base.handle = (IntPtr)1; // Initialize to non-zero dummy variable.
}
}
- public override bool IsInvalid
+ ///
+ /// Verify client encryption possibility.
+ ///
+ public bool ClientOSEncryptionSupport
{
get
{
- return (IntPtr.Zero == base.handle);
+ if (_clientOSEncryptionSupport is null)
+ {
+ // VSDevDiv 479597: If initialize fails, don't call QueryInfo.
+ if (TdsEnums.SNI_SUCCESS == _sniStatus)
+ {
+ try
+ {
+ UInt32 value = 0;
+ // Query OS to find out whether encryption is supported.
+ SNINativeMethodWrapper.SNIQueryInfo(SNINativeMethodWrapper.QTypes.SNI_QUERY_CLIENT_ENCRYPT_POSSIBLE, ref value);
+ _clientOSEncryptionSupport = value != 0;
+ }
+ catch (Exception e)
+ {
+ SqlClientEventSource.Log.TryTraceEvent(" Exception occurs during resolving encryption possibility: {0}", e.Message);
+ }
+ }
+ }
+ return _clientOSEncryptionSupport.Value;
}
}
+ public override bool IsInvalid => (IntPtr.Zero == base.handle);
+
override protected bool ReleaseHandle()
{
if (base.handle != IntPtr.Zero)
@@ -69,21 +81,9 @@ override protected bool ReleaseHandle()
return true;
}
- public uint Status
- {
- get
- {
- return _sniStatus;
- }
- }
+ public uint Status => _sniStatus;
- public EncryptionOptions Options
- {
- get
- {
- return _encryptionOption;
- }
- }
+ public EncryptionOptions Options => _encryptionOption;
private static void ReadDispatcher(IntPtr key, IntPtr packet, uint error)
{
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectFactory.Managed.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectFactory.Managed.cs
index 5c6a463d7c..86bc3013a9 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectFactory.Managed.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectFactory.Managed.cs
@@ -13,21 +13,14 @@ internal sealed class TdsParserStateObjectFactory
public static readonly TdsParserStateObjectFactory Singleton = new TdsParserStateObjectFactory();
- public EncryptionOptions EncryptionOptions
- {
- get
- {
- return SNI.SNILoadHandle.SingletonInstance.Options;
- }
- }
+ public EncryptionOptions EncryptionOptions => SNI.SNILoadHandle.SingletonInstance.Options;
- public uint SNIStatus
- {
- get
- {
- return SNI.SNILoadHandle.SingletonInstance.Status;
- }
- }
+ public uint SNIStatus => SNI.SNILoadHandle.SingletonInstance.Status;
+
+ ///
+ /// Verify client encryption possibility.
+ ///
+ public bool ClientOSEncryptionSupport => SNI.SNILoadHandle.SingletonInstance.ClientOSEncryptionSupport;
public TdsParserStateObject CreateTdsParserStateObject(TdsParser parser)
{
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectFactory.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectFactory.Windows.cs
index add6430499..6785d7c2fd 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectFactory.Windows.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectFactory.Windows.cs
@@ -16,24 +16,17 @@ internal sealed class TdsParserStateObjectFactory
private static bool shouldUseManagedSNI;
// If the appcontext switch is set then Use Managed SNI based on the value. Otherwise Native SNI.dll will be used by default.
- public static bool UseManagedSNI { get; } =
+ public static bool UseManagedSNI =>
AppContext.TryGetSwitch(UseManagedNetworkingOnWindows, out shouldUseManagedSNI) ? shouldUseManagedSNI : false;
- public EncryptionOptions EncryptionOptions
- {
- get
- {
- return UseManagedSNI ? SNI.SNILoadHandle.SingletonInstance.Options : SNILoadHandle.SingletonInstance.Options;
- }
- }
+ public EncryptionOptions EncryptionOptions => UseManagedSNI ? SNI.SNILoadHandle.SingletonInstance.Options : SNILoadHandle.SingletonInstance.Options;
- public uint SNIStatus
- {
- get
- {
- return UseManagedSNI ? SNI.SNILoadHandle.SingletonInstance.Status : SNILoadHandle.SingletonInstance.Status;
- }
- }
+ public uint SNIStatus => UseManagedSNI ? SNI.SNILoadHandle.SingletonInstance.Status : SNILoadHandle.SingletonInstance.Status;
+
+ ///
+ /// Verify client encryption possibility.
+ ///
+ public bool ClientOSEncryptionSupport => UseManagedSNI ? SNI.SNILoadHandle.SingletonInstance.ClientOSEncryptionSupport : SNILoadHandle.SingletonInstance.ClientOSEncryptionSupport;
public TdsParserStateObject CreateTdsParserStateObject(TdsParser parser)
{
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 f1a714f319..550065ba52 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
@@ -58,6 +58,10 @@ internal int ObjectID
}
}
+ ///
+ /// Verify client encryption possibility.
+ ///
+ private bool ClientOSEncryptionSupport => SNILoadHandle.SingletonInstance.ClientOSEncryptionSupport;
// ReliabilitySection Usage:
//
@@ -644,6 +648,18 @@ internal void Connect(ServerInfo serverInfo,
// for DNS Caching phase 1
AssignPendingDNSInfo(serverInfo.UserProtocol, FQDNforDNSCahce);
+ if(!ClientOSEncryptionSupport)
+ {
+ //If encryption is required, an error will be thrown.
+ if (encrypt)
+ {
+ _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByClient(), "", 0));
+ _physicalStateObj.Dispose();
+ ThrowExceptionAndWarning(_physicalStateObj);
+ }
+ _encryptionOption = EncryptionOptions.NOT_SUP;
+ }
+
// UNDONE - send "" for instance now, need to fix later
SqlClientEventSource.Log.TryTraceEvent(" Sending prelogin handshake");
SendPreLoginHandshake(instanceName, encrypt, !string.IsNullOrEmpty(certificate), useOriginalAddressInfo);
@@ -683,8 +699,8 @@ internal void Connect(ServerInfo serverInfo,
AssignPendingDNSInfo(serverInfo.UserProtocol, FQDNforDNSCahce);
SendPreLoginHandshake(instanceName, encrypt, !string.IsNullOrEmpty(certificate), useOriginalAddressInfo);
- status = ConsumePreLoginHandshake(authType, encrypt, trustServerCert, integratedSecurity, serverCallback, clientCallback, out marsCapable,
- out _connHandler._fedAuthRequired);
+ status = ConsumePreLoginHandshake(authType, encrypt, trustServerCert, integratedSecurity, serverCallback, clientCallback,
+ out marsCapable, out _connHandler._fedAuthRequired);
// Don't need to check for Sphinx failure, since we've already consumed
// one pre-login packet and know we are connecting to Shiloh.
@@ -983,7 +999,7 @@ private void SendPreLoginHandshake(byte[] instanceName, bool encrypt, bool clien
case (int)PreLoginOptions.ENCRYPT:
if (_encryptionOption == EncryptionOptions.NOT_SUP)
{
- // If OS doesn't support encryption, inform server not supported.
+ //If OS doesn't support encryption and encryption is not required, inform server "not supported" by client.
payload[payloadLength] = (byte)EncryptionOptions.NOT_SUP;
}
else
@@ -1189,7 +1205,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(SqlAuthenticationMethod
switch (_encryptionOption & EncryptionOptions.OPTIONS_MASK)
{
case (EncryptionOptions.ON):
- if (serverOption == EncryptionOptions.NOT_SUP)
+ if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.NOT_SUP)
{
_physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
_physicalStateObj.Dispose();
@@ -1209,7 +1225,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(SqlAuthenticationMethod
// Encrypt all.
_encryptionOption = EncryptionOptions.ON | (_encryptionOption & ~EncryptionOptions.OPTIONS_MASK);
}
-
+ // NOT_SUP: No encryption.
break;
case (EncryptionOptions.NOT_SUP):
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs
index b61ed1dd34..591bd4f0a7 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs
@@ -20,7 +20,8 @@ internal sealed class SNILoadHandle : SafeHandle
internal readonly SNINativeMethodWrapper.SqlAsyncCallbackDelegate WriteAsyncCallbackDispatcher = new SNINativeMethodWrapper.SqlAsyncCallbackDelegate(WriteDispatcher);
private readonly UInt32 _sniStatus = TdsEnums.SNI_UNINITIALIZED;
- private readonly EncryptionOptions _encryptionOption;
+ private readonly EncryptionOptions _encryptionOption = EncryptionOptions.OFF;
+ private bool? _clientOSEncryptionSupport = null;
private SNILoadHandle() : base(IntPtr.Zero, true)
{
@@ -32,32 +33,42 @@ private SNILoadHandle() : base(IntPtr.Zero, true)
{ }
finally
{
-
_sniStatus = SNINativeMethodWrapper.SNIInitialize();
-
- UInt32 value = 0;
-
- // VSDevDiv 479597: If initialize fails, don't call QueryInfo.
- if (TdsEnums.SNI_SUCCESS == _sniStatus)
- {
- // Query OS to find out whether encryption is supported.
- SNINativeMethodWrapper.SNIQueryInfo(SNINativeMethodWrapper.QTypes.SNI_QUERY_CLIENT_ENCRYPT_POSSIBLE, ref value);
- }
-
- _encryptionOption = (value == 0) ? EncryptionOptions.NOT_SUP : EncryptionOptions.OFF;
-
base.handle = (IntPtr)1; // Initialize to non-zero dummy variable.
}
}
- public override bool IsInvalid
+ ///
+ /// Verify client encryption possibility.
+ ///
+ public bool ClientOSEncryptionSupport
{
get
{
- return (IntPtr.Zero == base.handle);
+ if (_clientOSEncryptionSupport is null)
+ {
+ // VSDevDiv 479597: If initialize fails, don't call QueryInfo.
+ if (TdsEnums.SNI_SUCCESS == _sniStatus)
+ {
+ try
+ {
+ UInt32 value = 0;
+ // Query OS to find out whether encryption is supported.
+ SNINativeMethodWrapper.SNIQueryInfo(SNINativeMethodWrapper.QTypes.SNI_QUERY_CLIENT_ENCRYPT_POSSIBLE, ref value);
+ _clientOSEncryptionSupport = value != 0;
+ }
+ catch (Exception e)
+ {
+ SqlClientEventSource.Log.TryTraceEvent(" Exception occurs during resolving encryption possibility: {0}", e.Message);
+ }
+ }
+ }
+ return _clientOSEncryptionSupport.Value;
}
}
+ public override bool IsInvalid => (IntPtr.Zero == base.handle);
+
override protected bool ReleaseHandle()
{
if (base.handle != IntPtr.Zero)
@@ -73,21 +84,9 @@ override protected bool ReleaseHandle()
return true;
}
- public UInt32 SNIStatus
- {
- get
- {
- return _sniStatus;
- }
- }
+ public UInt32 SNIStatus => _sniStatus;
- public EncryptionOptions Options
- {
- get
- {
- return _encryptionOption;
- }
- }
+ public EncryptionOptions Options => _encryptionOption;
static private void ReadDispatcher(IntPtr key, IntPtr packet, UInt32 error)
{