@@ -851,6 +851,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
851
851
int payloadOffset = 0;
852
852
int payloadLength = 0;
853
853
int option = payload[offset++];
854
+ bool serverSupportsEncryption = false;
854
855
855
856
while (option != (byte)PreLoginOptions.LASTOPT)
856
857
{
@@ -887,18 +888,11 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
887
888
LOGIN
888
889
} */
889
890
891
+ // Any response other than NOT_SUP means the server supports encryption.
892
+ serverSupportsEncryption = serverOption != EncryptionOptions.NOT_SUP;
893
+
890
894
switch (_encryptionOption)
891
895
{
892
- case (EncryptionOptions.ON):
893
- if (serverOption == EncryptionOptions.NOT_SUP)
894
- {
895
- _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
896
- _physicalStateObj.Dispose();
897
- ThrowExceptionAndWarning(_physicalStateObj);
898
- }
899
-
900
- break;
901
-
902
896
case (EncryptionOptions.OFF):
903
897
if (serverOption == EncryptionOptions.OFF)
904
898
{
@@ -916,6 +910,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
916
910
case (EncryptionOptions.NOT_SUP):
917
911
if (serverOption == EncryptionOptions.REQ)
918
912
{
913
+ // Server requires encryption, but client does not support it.
919
914
_physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByClient(), "", 0));
920
915
_physicalStateObj.Dispose();
921
916
ThrowExceptionAndWarning(_physicalStateObj);
@@ -924,57 +919,15 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
924
919
break;
925
920
926
921
default:
927
- Debug.Fail("Invalid client encryption option detected");
928
- break;
929
- }
930
-
931
- if (_encryptionOption == EncryptionOptions.ON ||
932
- _encryptionOption == EncryptionOptions.LOGIN)
933
- {
934
- uint error = 0;
935
-
936
- // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server.
937
- bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || (_connHandler._accessTokenInBytes != null && !trustServerCert);
938
- uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0)
939
- | (isYukonOrLater ? TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE : 0);
940
-
941
- if (encrypt && !integratedSecurity)
942
- {
943
- // optimization: in case of SQL Authentication and encryption, set SNI_SSL_IGNORE_CHANNEL_BINDINGS to let SNI
944
- // know that it does not need to allocate/retrieve the Channel Bindings from the SSL context.
945
- // This applies to Native SNI
946
- info |= TdsEnums.SNI_SSL_IGNORE_CHANNEL_BINDINGS;
947
- }
948
-
949
- error = _physicalStateObj.EnableSsl(ref info);
950
-
951
- if (error != TdsEnums.SNI_SUCCESS)
952
- {
953
- _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj));
954
- ThrowExceptionAndWarning(_physicalStateObj);
955
- }
956
-
957
- int protocolVersion = 0;
958
- WaitForSSLHandShakeToComplete(ref error, ref protocolVersion);
959
-
960
- SslProtocols protocol = (SslProtocols)protocolVersion;
961
- string warningMessage = protocol.GetProtocolWarning();
962
- if (!string.IsNullOrEmpty(warningMessage))
963
- {
964
- if (!encrypt && LocalAppContextSwitches.SuppressInsecureTLSWarning)
965
- {
966
- // Skip console warning
967
- SqlClientEventSource.Log.TryTraceEvent("<sc|{0}|{1}|{2}>{3}", nameof(TdsParser), nameof(ConsumePreLoginHandshake), SqlClientLogger.LogLevel.Warning, warningMessage);
968
- }
969
- else
922
+ // Any other client option needs encryption
923
+ if (serverOption == EncryptionOptions.NOT_SUP)
970
924
{
971
- // This logs console warning of insecure protocol in use.
972
- _logger.LogWarning(nameof(TdsParser), nameof(ConsumePreLoginHandshake), warningMessage);
925
+ _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
926
+ _physicalStateObj.Dispose();
927
+ ThrowExceptionAndWarning(_physicalStateObj);
973
928
}
974
- }
975
929
976
- // create a new packet encryption changes the internal packet size
977
- _physicalStateObj.ClearAllWritePackets();
930
+ break;
978
931
}
979
932
980
933
break;
@@ -1057,6 +1010,62 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
1057
1010
}
1058
1011
}
1059
1012
1013
+ if (_encryptionOption == EncryptionOptions.ON ||
1014
+ _encryptionOption == EncryptionOptions.LOGIN)
1015
+ {
1016
+ if (!serverSupportsEncryption)
1017
+ {
1018
+ _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
1019
+ _physicalStateObj.Dispose();
1020
+ ThrowExceptionAndWarning(_physicalStateObj);
1021
+ }
1022
+
1023
+ uint error = 0;
1024
+
1025
+ // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server.
1026
+ bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || (_connHandler._accessTokenInBytes != null && !trustServerCert);
1027
+ uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0)
1028
+ | (isYukonOrLater ? TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE : 0);
1029
+
1030
+ if (encrypt && !integratedSecurity)
1031
+ {
1032
+ // optimization: in case of SQL Authentication and encryption, set SNI_SSL_IGNORE_CHANNEL_BINDINGS to let SNI
1033
+ // know that it does not need to allocate/retrieve the Channel Bindings from the SSL context.
1034
+ // This applies to Native SNI
1035
+ info |= TdsEnums.SNI_SSL_IGNORE_CHANNEL_BINDINGS;
1036
+ }
1037
+
1038
+ error = _physicalStateObj.EnableSsl(ref info);
1039
+
1040
+ if (error != TdsEnums.SNI_SUCCESS)
1041
+ {
1042
+ _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj));
1043
+ ThrowExceptionAndWarning(_physicalStateObj);
1044
+ }
1045
+
1046
+ int protocolVersion = 0;
1047
+ WaitForSSLHandShakeToComplete(ref error, ref protocolVersion);
1048
+
1049
+ SslProtocols protocol = (SslProtocols)protocolVersion;
1050
+ string warningMessage = protocol.GetProtocolWarning();
1051
+ if (!string.IsNullOrEmpty(warningMessage))
1052
+ {
1053
+ if (!encrypt && LocalAppContextSwitches.SuppressInsecureTLSWarning)
1054
+ {
1055
+ // Skip console warning
1056
+ SqlClientEventSource.Log.TryTraceEvent("<sc|{0}|{1}|{2}>{3}", nameof(TdsParser), nameof(ConsumePreLoginHandshake), SqlClientLogger.LogLevel.Warning, warningMessage);
1057
+ }
1058
+ else
1059
+ {
1060
+ // This logs console warning of insecure protocol in use.
1061
+ _logger.LogWarning(nameof(TdsParser), nameof(ConsumePreLoginHandshake), warningMessage);
1062
+ }
1063
+ }
1064
+
1065
+ // create a new packet encryption changes the internal packet size
1066
+ _physicalStateObj.ClearAllWritePackets();
1067
+ }
1068
+
1060
1069
return PreLoginHandshakeStatus.Successful;
1061
1070
}
1062
1071
0 commit comments