Skip to content

Commit

Permalink
Fix encryption NOT_SUP issue(#1210) (#1233)
Browse files Browse the repository at this point in the history
Co-authored-by: Davoud Eshtehari <v-daesht@microsoft.com>
  • Loading branch information
DavoudEshtehari and Davoud Eshtehari committed Sep 14, 2021
1 parent 8908b92 commit 4f15303
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,11 @@ public EncryptionOptions Options
return _encryptionOption;
}
}

/// <summary>
/// Verify client encryption possibility
/// </summary>
// TODO: by adding support ENCRYPT_NOT_SUP, it could be calculated.
public bool ClientOSEncryptionSupport => true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ internal sealed partial class TdsParser
internal readonly int _objectID = Interlocked.Increment(ref _objectTypeCount);
internal int ObjectID => _objectID;

/// <summary>
/// Verify client encryption possibility.
/// </summary>
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.

Expand Down Expand Up @@ -464,6 +469,18 @@ internal void ProcessPendingAck(TdsParserStateObject stateObj)
_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("<sc.TdsParser.Connect|SEC> Sending prelogin handshake");
SendPreLoginHandshake(instanceName, encrypt);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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
/// <summary>
/// Verify client encryption possibility.
/// </summary>
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("<sc.SNILoadHandle.EncryptClientPossible|SEC> 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)
Expand All @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
/// Verify client encryption possibility.
/// </summary>
public bool ClientOSEncryptionSupport => SNI.SNILoadHandle.SingletonInstance.ClientOSEncryptionSupport;

public TdsParserStateObject CreateTdsParserStateObject(TdsParser parser)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
/// Verify client encryption possibility.
/// </summary>
public bool ClientOSEncryptionSupport => UseManagedSNI ? SNI.SNILoadHandle.SingletonInstance.ClientOSEncryptionSupport : SNILoadHandle.SingletonInstance.ClientOSEncryptionSupport;

public TdsParserStateObject CreateTdsParserStateObject(TdsParser parser)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ internal int ObjectID
}
}

/// <summary>
/// Verify client encryption possibility.
/// </summary>
private bool ClientOSEncryptionSupport => SNILoadHandle.SingletonInstance.ClientOSEncryptionSupport;

// ReliabilitySection Usage:
//
Expand Down Expand Up @@ -644,6 +648,18 @@ internal void ProcessPendingAck(TdsParserStateObject stateObj)
// 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("<sc.TdsParser.Connect|SEC> Sending prelogin handshake");
SendPreLoginHandshake(instanceName, encrypt, !string.IsNullOrEmpty(certificate), useOriginalAddressInfo);
Expand Down Expand Up @@ -683,8 +699,8 @@ internal void ProcessPendingAck(TdsParserStateObject stateObj)
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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1189,7 +1205,7 @@ private void SendPreLoginHandshake(byte[] instanceName, bool encrypt, bool clien
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();
Expand All @@ -1209,7 +1225,7 @@ private void SendPreLoginHandshake(byte[] instanceName, bool encrypt, bool clien
// Encrypt all.
_encryptionOption = EncryptionOptions.ON | (_encryptionOption & ~EncryptionOptions.OPTIONS_MASK);
}

// NOT_SUP: No encryption.
break;

case (EncryptionOptions.NOT_SUP):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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
/// <summary>
/// Verify client encryption possibility.
/// </summary>
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("<sc.SNILoadHandle.EncryptClientPossible|SEC> 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)
Expand All @@ -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)
{
Expand Down

0 comments on commit 4f15303

Please sign in to comment.