@@ -1392,6 +1392,8 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(
13921392 int payloadOffset = 0;
13931393 int payloadLength = 0;
13941394 int option = payload[offset++];
1395+ bool serverSupportsEncryption = false;
1396+ bool serverSupportsCTAIP = false;
13951397
13961398 while (option != (byte)PreLoginOptions.LASTOPT)
13971399 {
@@ -1415,29 +1417,33 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(
14151417 break;
14161418
14171419 case (int)PreLoginOptions.ENCRYPT:
1420+ if (tlsFirst)
1421+ {
1422+ // Can skip/ignore this option if we are doing TDS 8.
1423+ offset += 4;
1424+ break;
1425+ }
1426+
14181427 payloadOffset = payload[offset++] << 8 | payload[offset++];
14191428 payloadLength = payload[offset++] << 8 | payload[offset++];
14201429
14211430 EncryptionOptions serverOption = (EncryptionOptions)payload[payloadOffset];
14221431 /* internal enum EncryptionOptions {
1423- OFF,
1424- ON,
1425- NOT_SUP,
1426- REQ,
1427- LOGIN
1428- } */
1432+ OFF,
1433+ ON,
1434+ NOT_SUP,
1435+ REQ,
1436+ LOGIN,
1437+ OPTIONS_MASK = 0x3f,
1438+ CTAIP = 0x40,
1439+ CLIENT_CERT = 0x80,
1440+ } */
1441+
1442+ // Any response other than NOT_SUP means the server supports encryption.
1443+ serverSupportsEncryption = (serverOption & EncryptionOptions.OPTIONS_MASK) != EncryptionOptions.NOT_SUP;
1444+
14291445 switch (_encryptionOption & EncryptionOptions.OPTIONS_MASK)
14301446 {
1431- case (EncryptionOptions.ON):
1432- if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.NOT_SUP)
1433- {
1434- _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
1435- _physicalStateObj.Dispose();
1436- ThrowExceptionAndWarning(_physicalStateObj);
1437- }
1438-
1439- break;
1440-
14411447 case (EncryptionOptions.OFF):
14421448 if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.OFF)
14431449 {
@@ -1453,8 +1459,9 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(
14531459 break;
14541460
14551461 case (EncryptionOptions.NOT_SUP):
1456- if (!tlsFirst && (serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.REQ)
1462+ if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.REQ)
14571463 {
1464+ // Server requires encryption, but client does not support it.
14581465 _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByClient(), "", 0));
14591466 _physicalStateObj.Dispose();
14601467 ThrowExceptionAndWarning(_physicalStateObj);
@@ -1463,37 +1470,20 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(
14631470 break;
14641471
14651472 default:
1466- Debug.Fail("Invalid client encryption option detected");
1473+ // Any other client option needs encryption
1474+ if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.NOT_SUP)
1475+ {
1476+ _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
1477+ _physicalStateObj.Dispose();
1478+ ThrowExceptionAndWarning(_physicalStateObj);
1479+ }
1480+
14671481 break;
14681482 }
14691483
14701484 // Check if the server will accept CTAIP.
14711485 //
1472- if ((_encryptionOption & EncryptionOptions.CTAIP) != 0 &&
1473- (serverOption & EncryptionOptions.CTAIP) == 0)
1474- {
1475- _physicalStateObj.AddError(new SqlError(TdsEnums.CTAIP_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.CTAIPNotSupportedByServer(), "", 0));
1476- _physicalStateObj.Dispose();
1477- ThrowExceptionAndWarning(_physicalStateObj);
1478- }
1479-
1480- if ((_encryptionOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.ON ||
1481- (_encryptionOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.LOGIN)
1482- {
1483-
1484- if (serverCallback != null)
1485- {
1486- trustServerCert = true;
1487- }
1488-
1489- // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server.
1490- bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || ((authType != SqlAuthenticationMethod.NotSpecified || _connHandler._accessTokenInBytes != null) && !trustServerCert);
1491-
1492- UInt32 info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0)
1493- | (is2005OrLater && (_encryptionOption & EncryptionOptions.CLIENT_CERT) == 0 ? TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE : 0);
1494-
1495- EnableSsl(info, encrypt, integratedSecurity, serverCertificateFilename, serverCallback, clientCallback);
1496- }
1486+ serverSupportsCTAIP = (serverOption & EncryptionOptions.CTAIP) != 0;
14971487
14981488 break;
14991489
@@ -1576,6 +1566,37 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(
15761566 }
15771567 }
15781568
1569+ if ((_encryptionOption & EncryptionOptions.CTAIP) != 0 && !serverSupportsCTAIP)
1570+ {
1571+ _physicalStateObj.AddError(new SqlError(TdsEnums.CTAIP_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.CTAIPNotSupportedByServer(), "", 0));
1572+ _physicalStateObj.Dispose();
1573+ ThrowExceptionAndWarning(_physicalStateObj);
1574+ }
1575+
1576+ if ((_encryptionOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.ON ||
1577+ (_encryptionOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.LOGIN)
1578+ {
1579+ if (!serverSupportsEncryption)
1580+ {
1581+ _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0));
1582+ _physicalStateObj.Dispose();
1583+ ThrowExceptionAndWarning(_physicalStateObj);
1584+ }
1585+
1586+ if (serverCallback != null)
1587+ {
1588+ trustServerCert = true;
1589+ }
1590+
1591+ // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server.
1592+ bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || ((authType != SqlAuthenticationMethod.NotSpecified || _connHandler._accessTokenInBytes != null) && !trustServerCert);
1593+
1594+ uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0)
1595+ | (is2005OrLater && (_encryptionOption & EncryptionOptions.CLIENT_CERT) == 0 ? TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE : 0);
1596+
1597+ EnableSsl(info, encrypt, integratedSecurity, serverCertificateFilename, serverCallback, clientCallback);
1598+ }
1599+
15791600 return PreLoginHandshakeStatus.Successful;
15801601 }
15811602
0 commit comments