@@ -843,6 +843,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
843843 int payloadOffset = 0;
844844 int payloadLength = 0;
845845 int option = payload[offset++];
846+ bool serverSupportsEncryption = false;
846847
847848 while (option != (byte)PreLoginOptions.LASTOPT)
848849 {
@@ -879,18 +880,11 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
879880 LOGIN
880881 } */
881882
883+ // Any response other than NOT_SUP means the server supports encryption.
884+ serverSupportsEncryption = serverOption != EncryptionOptions.NOT_SUP;
885+
882886 switch (_encryptionOption)
883887 {
884- case (EncryptionOptions.ON):
885- if (serverOption == EncryptionOptions.NOT_SUP)
886- {
887- _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
888- _physicalStateObj.Dispose();
889- ThrowExceptionAndWarning(_physicalStateObj);
890- }
891-
892- break;
893-
894888 case (EncryptionOptions.OFF):
895889 if (serverOption == EncryptionOptions.OFF)
896890 {
@@ -908,6 +902,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
908902 case (EncryptionOptions.NOT_SUP):
909903 if (serverOption == EncryptionOptions.REQ)
910904 {
905+ // Server requires encryption, but client does not support it.
911906 _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByClient(), "", 0));
912907 _physicalStateObj.Dispose();
913908 ThrowExceptionAndWarning(_physicalStateObj);
@@ -916,49 +911,15 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
916911 break;
917912
918913 default:
919- Debug.Fail("Invalid client encryption option detected");
920- break;
921- }
922-
923- if (_encryptionOption == EncryptionOptions.ON ||
924- _encryptionOption == EncryptionOptions.LOGIN)
925- {
926- uint error = 0;
927-
928- // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server.
929- bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || (_connHandler._accessTokenInBytes != null && !trustServerCert);
930- uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0)
931- | (isYukonOrLater ? TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE : 0);
932-
933- if (encrypt && !integratedSecurity)
934- {
935- // optimization: in case of SQL Authentication and encryption, set SNI_SSL_IGNORE_CHANNEL_BINDINGS to let SNI
936- // know that it does not need to allocate/retrieve the Channel Bindings from the SSL context.
937- // This applies to Native SNI
938- info |= TdsEnums.SNI_SSL_IGNORE_CHANNEL_BINDINGS;
939- }
940-
941- error = _physicalStateObj.EnableSsl(ref info);
942-
943- if (error != TdsEnums.SNI_SUCCESS)
944- {
945- _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj));
946- ThrowExceptionAndWarning(_physicalStateObj);
947- }
948-
949- int protocolVersion = 0;
950- WaitForSSLHandShakeToComplete(ref error, ref protocolVersion);
951-
952- SslProtocols protocol = (SslProtocols)protocolVersion;
953- string warningMessage = protocol.GetProtocolWarning();
954- if (!string.IsNullOrEmpty(warningMessage))
955- {
956- // This logs console warning of insecure protocol in use.
957- _logger.LogWarning(_typeName, MethodBase.GetCurrentMethod().Name, warningMessage);
958- }
914+ // Any other client option needs encryption
915+ if (serverOption == EncryptionOptions.NOT_SUP)
916+ {
917+ _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
918+ _physicalStateObj.Dispose();
919+ ThrowExceptionAndWarning(_physicalStateObj);
920+ }
959921
960- // create a new packet encryption changes the internal packet size
961- _physicalStateObj.ClearAllWritePackets();
922+ break;
962923 }
963924
964925 break;
@@ -1041,6 +1002,54 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
10411002 }
10421003 }
10431004
1005+ if (_encryptionOption == EncryptionOptions.ON ||
1006+ _encryptionOption == EncryptionOptions.LOGIN)
1007+ {
1008+ if (!serverSupportsEncryption)
1009+ {
1010+ _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
1011+ _physicalStateObj.Dispose();
1012+ ThrowExceptionAndWarning(_physicalStateObj);
1013+ }
1014+
1015+ uint error = 0;
1016+
1017+ // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server.
1018+ bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || (_connHandler._accessTokenInBytes != null && !trustServerCert);
1019+ uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0)
1020+ | (isYukonOrLater ? TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE : 0);
1021+
1022+ if (encrypt && !integratedSecurity)
1023+ {
1024+ // optimization: in case of SQL Authentication and encryption, set SNI_SSL_IGNORE_CHANNEL_BINDINGS to let SNI
1025+ // know that it does not need to allocate/retrieve the Channel Bindings from the SSL context.
1026+ // This applies to Native SNI
1027+ info |= TdsEnums.SNI_SSL_IGNORE_CHANNEL_BINDINGS;
1028+ }
1029+
1030+ error = _physicalStateObj.EnableSsl(ref info);
1031+
1032+ if (error != TdsEnums.SNI_SUCCESS)
1033+ {
1034+ _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj));
1035+ ThrowExceptionAndWarning(_physicalStateObj);
1036+ }
1037+
1038+ int protocolVersion = 0;
1039+ WaitForSSLHandShakeToComplete(ref error, ref protocolVersion);
1040+
1041+ SslProtocols protocol = (SslProtocols)protocolVersion;
1042+ string warningMessage = protocol.GetProtocolWarning();
1043+ if (!string.IsNullOrEmpty(warningMessage))
1044+ {
1045+ // This logs console warning of insecure protocol in use.
1046+ _logger.LogWarning(_typeName, MethodBase.GetCurrentMethod().Name, warningMessage);
1047+ }
1048+
1049+ // create a new packet encryption changes the internal packet size
1050+ _physicalStateObj.ClearAllWritePackets();
1051+ }
1052+
10441053 return PreLoginHandshakeStatus.Successful;
10451054 }
10461055
0 commit comments