@@ -1392,6 +1392,8 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(
1392
1392
int payloadOffset = 0;
1393
1393
int payloadLength = 0;
1394
1394
int option = payload[offset++];
1395
+ bool serverSupportsEncryption = false;
1396
+ bool serverSupportsCTAIP = false;
1395
1397
1396
1398
while (option != (byte)PreLoginOptions.LASTOPT)
1397
1399
{
@@ -1415,29 +1417,33 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(
1415
1417
break;
1416
1418
1417
1419
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
+
1418
1427
payloadOffset = payload[offset++] << 8 | payload[offset++];
1419
1428
payloadLength = payload[offset++] << 8 | payload[offset++];
1420
1429
1421
1430
EncryptionOptions serverOption = (EncryptionOptions)payload[payloadOffset];
1422
1431
/* 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
+
1429
1445
switch (_encryptionOption & EncryptionOptions.OPTIONS_MASK)
1430
1446
{
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
-
1441
1447
case (EncryptionOptions.OFF):
1442
1448
if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.OFF)
1443
1449
{
@@ -1453,8 +1459,9 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(
1453
1459
break;
1454
1460
1455
1461
case (EncryptionOptions.NOT_SUP):
1456
- if (!tlsFirst && (serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.REQ)
1462
+ if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.REQ)
1457
1463
{
1464
+ // Server requires encryption, but client does not support it.
1458
1465
_physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByClient(), "", 0));
1459
1466
_physicalStateObj.Dispose();
1460
1467
ThrowExceptionAndWarning(_physicalStateObj);
@@ -1463,37 +1470,20 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(
1463
1470
break;
1464
1471
1465
1472
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
+
1467
1481
break;
1468
1482
}
1469
1483
1470
1484
// Check if the server will accept CTAIP.
1471
1485
//
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;
1497
1487
1498
1488
break;
1499
1489
@@ -1576,6 +1566,37 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(
1576
1566
}
1577
1567
}
1578
1568
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
+
1579
1600
return PreLoginHandshakeStatus.Successful;
1580
1601
}
1581
1602
0 commit comments