@@ -851,6 +851,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
851851 int payloadOffset = 0;
852852 int payloadLength = 0;
853853 int option = payload[offset++];
854+ bool serverSupportsEncryption = false;
854855
855856 while (option != (byte)PreLoginOptions.LASTOPT)
856857 {
@@ -887,18 +888,11 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
887888 LOGIN
888889 } */
889890
891+ // Any response other than NOT_SUP means the server supports encryption.
892+ serverSupportsEncryption = serverOption != EncryptionOptions.NOT_SUP;
893+
890894 switch (_encryptionOption)
891895 {
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-
902896 case (EncryptionOptions.OFF):
903897 if (serverOption == EncryptionOptions.OFF)
904898 {
@@ -916,6 +910,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
916910 case (EncryptionOptions.NOT_SUP):
917911 if (serverOption == EncryptionOptions.REQ)
918912 {
913+ // Server requires encryption, but client does not support it.
919914 _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByClient(), "", 0));
920915 _physicalStateObj.Dispose();
921916 ThrowExceptionAndWarning(_physicalStateObj);
@@ -924,57 +919,15 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
924919 break;
925920
926921 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)
970924 {
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);
973928 }
974- }
975929
976- // create a new packet encryption changes the internal packet size
977- _physicalStateObj.ClearAllWritePackets();
930+ break;
978931 }
979932
980933 break;
@@ -1057,6 +1010,62 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
10571010 }
10581011 }
10591012
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+
10601069 return PreLoginHandshakeStatus.Successful;
10611070 }
10621071
0 commit comments