Skip to content

Commit

Permalink
Support Cipher Suite Allow List (#1430)
Browse files Browse the repository at this point in the history
* Implement custom cipher suites on OpenSSL.

* Add unittests for cipher suite config

* Add Schannel support for allowed cipher suites.

* Switch to using a flags field on the QUIC_CREDENTIAL_CONFIG instead of a list of enums

* Expand failure tests to include parameter validation at creation time.

* Remove extra whitespace
  • Loading branch information
anrossi authored Apr 4, 2021
1 parent fa4e0d4 commit e1f7169
Show file tree
Hide file tree
Showing 5 changed files with 347 additions and 12 deletions.
11 changes: 11 additions & 0 deletions src/inc/msquic.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,20 @@ typedef enum QUIC_CREDENTIAL_FLAGS {
QUIC_CREDENTIAL_FLAG_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = 0x00000400, // Schannel only currently
QUIC_CREDENTIAL_FLAG_IGNORE_NO_REVOCATION_CHECK = 0x00000800, // Schannel only currently
QUIC_CREDENTIAL_FLAG_IGNORE_REVOCATION_OFFLINE = 0x00001000, // Schannel only currently
QUIC_CREDENTIAL_FLAG_SET_ALLOWED_CIPHER_SUITES = 0x00002000
} QUIC_CREDENTIAL_FLAGS;

DEFINE_ENUM_FLAG_OPERATORS(QUIC_CREDENTIAL_FLAGS)

typedef enum QUIC_ALLOWED_CIPHER_SUITE_FLAGS {
QUIC_ALLOWED_CIPHER_SUITE_NONE = 0x0,
QUIC_ALLOWED_CIPHER_SUITE_AES_128_GCM_SHA256 = 0x1,
QUIC_ALLOWED_CIPHER_SUITE_AES_256_GCM_SHA384 = 0x2,
QUIC_ALLOWED_CIPHER_SUITE_CHACHA20_POLY1305_SHA256 = 0x4, // Not supported on Schannel
} QUIC_ALLOWED_CIPHER_SUITE_FLAGS;

DEFINE_ENUM_FLAG_OPERATORS(QUIC_ALLOWED_CIPHER_SUITE_FLAGS);

typedef enum QUIC_CERTIFICATE_HASH_STORE_FLAGS {
QUIC_CERTIFICATE_HASH_STORE_FLAG_NONE = 0x0000,
QUIC_CERTIFICATE_HASH_STORE_FLAG_MACHINE_STORE = 0x0001,
Expand Down Expand Up @@ -269,6 +279,7 @@ typedef struct QUIC_CREDENTIAL_CONFIG {
const char* Principal;
void* Reserved; // Currently unused
QUIC_CREDENTIAL_LOAD_COMPLETE_HANDLER AsyncHandler; // Optional
QUIC_ALLOWED_CIPHER_SUITE_FLAGS AllowedCipherSuites;// Optional
} QUIC_CREDENTIAL_CONFIG;

//
Expand Down
3 changes: 2 additions & 1 deletion src/inc/quic_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ typedef struct CXPLAT_SLIST_ENTRY {
#define QUIC_POOL_TLS_TMP_TP '44cQ' // Qc44 - QUIC Platform TLS Temporary TP storage
#define QUIC_POOL_PCP '54cQ' // Qc45 - QUIC PCP
#define QUIC_POOL_DATAPATH_ADDRESSES '64cQ' // Qc46 - QUIC Datapath Addresses
#define QUIC_POOL_TLS_TICKET_KEY '74cQ' // Qc21 - QUIC Platform TLS ticket key
#define QUIC_POOL_TLS_TICKET_KEY '74cQ' // Qc47 - QUIC Platform TLS ticket key
#define QUIC_POOL_TLS_CIPHER_SUITE_STRING '84cQ' // Qc48 - QUIC TLS cipher suite string

typedef enum CXPLAT_THREAD_FLAGS {
CXPLAT_THREAD_FLAG_NONE = 0x0000,
Expand Down
92 changes: 91 additions & 1 deletion src/platform/tls_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ typedef struct CXPLAT_HP_KEY {
//
#define CXPLAT_TLS_DEFAULT_SSL_CIPHERS "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256"

#define CXPLAT_TLS_AES_128_GCM_SHA256 "TLS_AES_128_GCM_SHA256"
#define CXPLAT_TLS_AES_256_GCM_SHA384 "TLS_AES_256_GCM_SHA384"
#define CXPLAT_TLS_CHACHA20_POLY1305_SHA256 "TLS_CHACHA20_POLY1305_SHA256"

//
// Default list of curves for ECDHE ciphers.
//
Expand Down Expand Up @@ -805,12 +809,26 @@ CxPlatTlsSecConfigCreate(
}
}

if (CredConfig->Flags & QUIC_CREDENTIAL_FLAG_SET_ALLOWED_CIPHER_SUITES &&
((CredConfig->AllowedCipherSuites &
(QUIC_ALLOWED_CIPHER_SUITE_AES_128_GCM_SHA256 |
QUIC_ALLOWED_CIPHER_SUITE_AES_256_GCM_SHA384 |
QUIC_ALLOWED_CIPHER_SUITE_CHACHA20_POLY1305_SHA256)) == 0)) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
CredConfig->AllowedCipherSuites,
"No valid cipher suites presented");
return QUIC_STATUS_INVALID_PARAMETER;
}

QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
int Ret = 0;
CXPLAT_SEC_CONFIG* SecurityConfig = NULL;
RSA* RsaKey = NULL;
X509* X509Cert = NULL;
EVP_PKEY * PrivateKey = NULL;
char* CipherSuiteString = NULL;

//
// Create a security config.
Expand Down Expand Up @@ -873,10 +891,78 @@ CxPlatTlsSecConfigCreate(
goto Exit;
}

char* CipherSuites = CXPLAT_TLS_DEFAULT_SSL_CIPHERS;
if (CredConfig->Flags & QUIC_CREDENTIAL_FLAG_SET_ALLOWED_CIPHER_SUITES) {
//
// Calculate allowed cipher suite string length.
//
uint8_t CipherSuiteStringLength = 0;
uint8_t AllowedCipherSuitesCount = 0;
if (CredConfig->AllowedCipherSuites & QUIC_ALLOWED_CIPHER_SUITE_AES_128_GCM_SHA256) {
CipherSuiteStringLength += (uint8_t)sizeof(CXPLAT_TLS_AES_128_GCM_SHA256);
AllowedCipherSuitesCount++;
}
if (CredConfig->AllowedCipherSuites & QUIC_ALLOWED_CIPHER_SUITE_AES_256_GCM_SHA384) {
CipherSuiteStringLength += (uint8_t)sizeof(CXPLAT_TLS_AES_256_GCM_SHA384);
AllowedCipherSuitesCount++;
}
if (CredConfig->AllowedCipherSuites & QUIC_ALLOWED_CIPHER_SUITE_CHACHA20_POLY1305_SHA256) {
CipherSuiteStringLength += (uint8_t)sizeof(CXPLAT_TLS_CHACHA20_POLY1305_SHA256);
AllowedCipherSuitesCount++;
}

CipherSuiteString = CXPLAT_ALLOC_NONPAGED(CipherSuiteStringLength, QUIC_POOL_TLS_CIPHER_SUITE_STRING);
if (CipherSuiteString == NULL) {
QuicTraceEvent(
AllocFailure,
"Allocation of '%s' failed. (%llu bytes)",
"CipherSuiteString",
CipherSuiteStringLength);
Status = QUIC_STATUS_OUT_OF_MEMORY;
goto Exit;
}

//
// Order of if-statements matters here because OpenSSL uses the order
// of cipher suites to indicate preference. Below, we use the default
// order of preference for TLS 1.3 cipher suites.
//
uint8_t CipherSuiteStringCursor = 0;
if (CredConfig->AllowedCipherSuites & QUIC_ALLOWED_CIPHER_SUITE_AES_256_GCM_SHA384) {
CxPlatCopyMemory(
&CipherSuiteString[CipherSuiteStringCursor],
CXPLAT_TLS_AES_256_GCM_SHA384,
sizeof(CXPLAT_TLS_AES_256_GCM_SHA384));
CipherSuiteStringCursor += (uint8_t)sizeof(CXPLAT_TLS_AES_256_GCM_SHA384);
if (--AllowedCipherSuitesCount > 0) {
CipherSuiteString[CipherSuiteStringCursor - 1] = ':';
}
}
if (CredConfig->AllowedCipherSuites & QUIC_ALLOWED_CIPHER_SUITE_CHACHA20_POLY1305_SHA256) {
CxPlatCopyMemory(
&CipherSuiteString[CipherSuiteStringCursor],
CXPLAT_TLS_CHACHA20_POLY1305_SHA256,
sizeof(CXPLAT_TLS_CHACHA20_POLY1305_SHA256));
CipherSuiteStringCursor += (uint8_t)sizeof(CXPLAT_TLS_CHACHA20_POLY1305_SHA256);
if (--AllowedCipherSuitesCount > 0) {
CipherSuiteString[CipherSuiteStringCursor - 1] = ':';
}
}
if (CredConfig->AllowedCipherSuites & QUIC_ALLOWED_CIPHER_SUITE_AES_128_GCM_SHA256) {
CxPlatCopyMemory(
&CipherSuiteString[CipherSuiteStringCursor],
CXPLAT_TLS_AES_128_GCM_SHA256,
sizeof(CXPLAT_TLS_AES_128_GCM_SHA256));
CipherSuiteStringCursor += (uint8_t)sizeof(CXPLAT_TLS_AES_128_GCM_SHA256);
}
CXPLAT_DBG_ASSERT(CipherSuiteStringCursor == CipherSuiteStringLength);
CipherSuites = CipherSuiteString;
}

Ret =
SSL_CTX_set_ciphersuites(
SecurityConfig->SSLCtx,
CXPLAT_TLS_DEFAULT_SSL_CIPHERS);
CipherSuites);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
Expand Down Expand Up @@ -1188,6 +1274,10 @@ CxPlatTlsSecConfigCreate(
CxPlatTlsSecConfigDelete(SecurityConfig);
}

if (CipherSuiteString != NULL) {
CxPlatFree(CipherSuiteString, QUIC_POOL_TLS_CIPHER_SUITE_STRING);
}

if (X509Cert != NULL) {
X509_free(X509Cert);
}
Expand Down
83 changes: 75 additions & 8 deletions src/platform/tls_schannel.c
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ typedef struct QUIC_ACH_CONTEXT {
//
// Holds the blocked algorithms for the lifetime of the ACH call.
//
CRYPTO_SETTINGS CryptoSettings[2];
CRYPTO_SETTINGS CryptoSettings[4];

//
// Holds the list of blocked chaining modes for the lifetime of the ACH call.
Expand Down Expand Up @@ -1008,7 +1008,7 @@ CxPlatTlsAllocateAchContext(
AchContext->CompletionContext = Context;
AchContext->CompletionCallback = Callback;
AchContext->TlsParameters.pDisabledCrypto = AchContext->CryptoSettings;
AchContext->TlsParameters.cDisabledCrypto = ARRAYSIZE(AchContext->CryptoSettings);
AchContext->TlsParameters.cDisabledCrypto = 2; // initialized to the basic blocked cipher suites.
AchContext->Credentials.pTlsParameters = &AchContext->TlsParameters;
AchContext->Credentials.cTlsParameters = 1;
#ifdef _KERNEL_MODE
Expand Down Expand Up @@ -1214,6 +1214,19 @@ CxPlatTlsSecConfigCreate(
return QUIC_STATUS_NOT_SUPPORTED;
}

if (CredConfig->Flags & QUIC_CREDENTIAL_FLAG_SET_ALLOWED_CIPHER_SUITES &&
((CredConfig->AllowedCipherSuites &
(QUIC_ALLOWED_CIPHER_SUITE_AES_128_GCM_SHA256 |
QUIC_ALLOWED_CIPHER_SUITE_AES_256_GCM_SHA384)) == 0 ||
(CredConfig->AllowedCipherSuites & QUIC_ALLOWED_CIPHER_SUITE_CHACHA20_POLY1305_SHA256))) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
CredConfig->AllowedCipherSuites,
"No valid cipher suites presented");
return QUIC_STATUS_INVALID_PARAMETER;
}

QUIC_ACH_CONTEXT* AchContext =
CxPlatTlsAllocateAchContext(
CredConfig,
Expand Down Expand Up @@ -1281,11 +1294,13 @@ CxPlatTlsSecConfigCreate(
//
// Disallow ChaCha20-Poly1305 until full support is possible.
//
AchContext->CryptoSettings[0].eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
AchContext->CryptoSettings[0].strCngAlgId = (UNICODE_STRING){
uint8_t CryptoSettingsIdx = 0;
AchContext->CryptoSettings[CryptoSettingsIdx].eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
AchContext->CryptoSettings[CryptoSettingsIdx].strCngAlgId = (UNICODE_STRING){
sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM),
sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM),
BCRYPT_CHACHA20_POLY1305_ALGORITHM};
CryptoSettingsIdx++;

//
// Disallow AES_CCM algorithm, since there's no support for it yet.
Expand All @@ -1296,13 +1311,65 @@ CxPlatTlsSecConfigCreate(
sizeof(BCRYPT_CHAIN_MODE_CCM),
BCRYPT_CHAIN_MODE_CCM};

AchContext->CryptoSettings[1].eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
AchContext->CryptoSettings[1].rgstrChainingModes = AchContext->BlockedChainingModes;
AchContext->CryptoSettings[1].cChainingModes = ARRAYSIZE(AchContext->BlockedChainingModes);
AchContext->CryptoSettings[1].strCngAlgId = (UNICODE_STRING){
AchContext->CryptoSettings[CryptoSettingsIdx].eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
AchContext->CryptoSettings[CryptoSettingsIdx].rgstrChainingModes = AchContext->BlockedChainingModes;
AchContext->CryptoSettings[CryptoSettingsIdx].cChainingModes = ARRAYSIZE(AchContext->BlockedChainingModes);
AchContext->CryptoSettings[CryptoSettingsIdx].strCngAlgId = (UNICODE_STRING){
sizeof(BCRYPT_AES_ALGORITHM),
sizeof(BCRYPT_AES_ALGORITHM),
BCRYPT_AES_ALGORITHM};
CryptoSettingsIdx++;

if (CredConfig->Flags & QUIC_CREDENTIAL_FLAG_SET_ALLOWED_CIPHER_SUITES) {
QUIC_ALLOWED_CIPHER_SUITE_FLAGS DisallowedCipherSuites = ~CredConfig->AllowedCipherSuites;

if (DisallowedCipherSuites & QUIC_ALLOWED_CIPHER_SUITE_AES_256_GCM_SHA384 &&
DisallowedCipherSuites & QUIC_ALLOWED_CIPHER_SUITE_AES_128_GCM_SHA256) {
QuicTraceEvent(
LibraryError,
"[ lib] ERROR, %s.",
"No Allowed TLS Cipher Suites");
Status = QUIC_STATUS_INVALID_PARAMETER;
goto Error;
}

if (DisallowedCipherSuites & QUIC_ALLOWED_CIPHER_SUITE_AES_256_GCM_SHA384) {
AchContext->CryptoSettings[CryptoSettingsIdx].eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
AchContext->CryptoSettings[CryptoSettingsIdx].strCngAlgId = (UNICODE_STRING){
sizeof(BCRYPT_AES_ALGORITHM),
sizeof(BCRYPT_AES_ALGORITHM),
BCRYPT_AES_ALGORITHM};
AchContext->CryptoSettings[CryptoSettingsIdx].dwMaxBitLength = 256;
AchContext->CryptoSettings[CryptoSettingsIdx].dwMinBitLength = 256;
CryptoSettingsIdx++;

AchContext->CryptoSettings[CryptoSettingsIdx].eAlgorithmUsage = TlsParametersCngAlgUsageDigest;
AchContext->CryptoSettings[CryptoSettingsIdx].strCngAlgId = (UNICODE_STRING){
sizeof(BCRYPT_SHA384_ALGORITHM),
sizeof(BCRYPT_SHA384_ALGORITHM),
BCRYPT_SHA384_ALGORITHM};
CryptoSettingsIdx++;
}
if (DisallowedCipherSuites & QUIC_ALLOWED_CIPHER_SUITE_AES_128_GCM_SHA256) {
AchContext->CryptoSettings[CryptoSettingsIdx].eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
AchContext->CryptoSettings[CryptoSettingsIdx].strCngAlgId = (UNICODE_STRING){
sizeof(BCRYPT_AES_ALGORITHM),
sizeof(BCRYPT_AES_ALGORITHM),
BCRYPT_AES_ALGORITHM};
AchContext->CryptoSettings[CryptoSettingsIdx].dwMaxBitLength = 128;
AchContext->CryptoSettings[CryptoSettingsIdx].dwMinBitLength = 128;
CryptoSettingsIdx++;

AchContext->CryptoSettings[CryptoSettingsIdx].eAlgorithmUsage = TlsParametersCngAlgUsageDigest;
AchContext->CryptoSettings[CryptoSettingsIdx].strCngAlgId = (UNICODE_STRING){
sizeof(BCRYPT_SHA256_ALGORITHM),
sizeof(BCRYPT_SHA256_ALGORITHM),
BCRYPT_SHA256_ALGORITHM};
CryptoSettingsIdx++;
}
}

AchContext->TlsParameters.cDisabledCrypto = CryptoSettingsIdx;


#ifdef _KERNEL_MODE
Expand Down
Loading

0 comments on commit e1f7169

Please sign in to comment.