@@ -864,6 +864,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
864864 int payloadOffset = 0;
865865 int payloadLength = 0;
866866 int option = payload[offset++];
867+ bool serverSupportsEncryption = false;
867868
868869 while (option != (byte)PreLoginOptions.LASTOPT)
869870 {
@@ -900,18 +901,11 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
900901 LOGIN
901902 } */
902903
904+ // Any response other than NOT_SUP means the server supports encryption.
905+ serverSupportsEncryption = serverOption != EncryptionOptions.NOT_SUP;
906+
903907 switch (_encryptionOption)
904908 {
905- case (EncryptionOptions.ON):
906- if (serverOption == EncryptionOptions.NOT_SUP)
907- {
908- _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
909- _physicalStateObj.Dispose();
910- ThrowExceptionAndWarning(_physicalStateObj);
911- }
912-
913- break;
914-
915909 case (EncryptionOptions.OFF):
916910 if (serverOption == EncryptionOptions.OFF)
917911 {
@@ -929,6 +923,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
929923 case (EncryptionOptions.NOT_SUP):
930924 if (serverOption == EncryptionOptions.REQ)
931925 {
926+ // Server requires encryption, but client does not support it.
932927 _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByClient(), "", 0));
933928 _physicalStateObj.Dispose();
934929 ThrowExceptionAndWarning(_physicalStateObj);
@@ -937,49 +932,15 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
937932 break;
938933
939934 default:
940- Debug.Fail("Invalid client encryption option detected");
941- break;
942- }
943-
944- if (_encryptionOption == EncryptionOptions.ON ||
945- _encryptionOption == EncryptionOptions.LOGIN)
946- {
947- uint error = 0;
948-
949- // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server.
950- bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || (_connHandler._accessTokenInBytes != null && !trustServerCert);
951- uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0)
952- | (isYukonOrLater ? TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE : 0);
953-
954- if (encrypt && !integratedSecurity)
955- {
956- // optimization: in case of SQL Authentication and encryption, set SNI_SSL_IGNORE_CHANNEL_BINDINGS to let SNI
957- // know that it does not need to allocate/retrieve the Channel Bindings from the SSL context.
958- // This applies to Native SNI
959- info |= TdsEnums.SNI_SSL_IGNORE_CHANNEL_BINDINGS;
960- }
961-
962- error = _physicalStateObj.EnableSsl(ref info);
963-
964- if (error != TdsEnums.SNI_SUCCESS)
965- {
966- _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj));
967- ThrowExceptionAndWarning(_physicalStateObj);
968- }
969-
970- int protocolVersion = 0;
971- WaitForSSLHandShakeToComplete(ref error, ref protocolVersion);
972-
973- SslProtocols protocol = (SslProtocols)protocolVersion;
974- string warningMessage = protocol.GetProtocolWarning();
975- if (!string.IsNullOrEmpty(warningMessage))
976- {
977- // This logs console warning of insecure protocol in use.
978- _logger.LogWarning(_typeName, MethodBase.GetCurrentMethod().Name, warningMessage);
979- }
935+ // Any other client option needs encryption
936+ if (serverOption == EncryptionOptions.NOT_SUP)
937+ {
938+ _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
939+ _physicalStateObj.Dispose();
940+ ThrowExceptionAndWarning(_physicalStateObj);
941+ }
980942
981- // create a new packet encryption changes the internal packet size
982- _physicalStateObj.ClearAllWritePackets();
943+ break;
983944 }
984945
985946 break;
@@ -1062,6 +1023,54 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
10621023 }
10631024 }
10641025
1026+ if (_encryptionOption == EncryptionOptions.ON ||
1027+ _encryptionOption == EncryptionOptions.LOGIN)
1028+ {
1029+ if (!serverSupportsEncryption)
1030+ {
1031+ _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
1032+ _physicalStateObj.Dispose();
1033+ ThrowExceptionAndWarning(_physicalStateObj);
1034+ }
1035+
1036+ uint error = 0;
1037+
1038+ // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server.
1039+ bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || (_connHandler._accessTokenInBytes != null && !trustServerCert);
1040+ uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0)
1041+ | (isYukonOrLater ? TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE : 0);
1042+
1043+ if (encrypt && !integratedSecurity)
1044+ {
1045+ // optimization: in case of SQL Authentication and encryption, set SNI_SSL_IGNORE_CHANNEL_BINDINGS to let SNI
1046+ // know that it does not need to allocate/retrieve the Channel Bindings from the SSL context.
1047+ // This applies to Native SNI
1048+ info |= TdsEnums.SNI_SSL_IGNORE_CHANNEL_BINDINGS;
1049+ }
1050+
1051+ error = _physicalStateObj.EnableSsl(ref info);
1052+
1053+ if (error != TdsEnums.SNI_SUCCESS)
1054+ {
1055+ _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj));
1056+ ThrowExceptionAndWarning(_physicalStateObj);
1057+ }
1058+
1059+ int protocolVersion = 0;
1060+ WaitForSSLHandShakeToComplete(ref error, ref protocolVersion);
1061+
1062+ SslProtocols protocol = (SslProtocols)protocolVersion;
1063+ string warningMessage = protocol.GetProtocolWarning();
1064+ if (!string.IsNullOrEmpty(warningMessage))
1065+ {
1066+ // This logs console warning of insecure protocol in use.
1067+ _logger.LogWarning(_typeName, MethodBase.GetCurrentMethod().Name, warningMessage);
1068+ }
1069+
1070+ // create a new packet encryption changes the internal packet size
1071+ _physicalStateObj.ClearAllWritePackets();
1072+ }
1073+
10651074 return PreLoginHandshakeStatus.Successful;
10661075 }
10671076
0 commit comments