From e1f716944c686e934d671017663f810b9b506a35 Mon Sep 17 00:00:00 2001 From: Anthony Rossi <41394064+anrossi@users.noreply.github.com> Date: Sun, 4 Apr 2021 08:34:15 -0700 Subject: [PATCH] Support Cipher Suite Allow List (#1430) * 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 --- src/inc/msquic.h | 11 ++ src/inc/quic_platform.h | 3 +- src/platform/tls_openssl.c | 92 +++++++++++++++- src/platform/tls_schannel.c | 83 +++++++++++++-- src/platform/unittest/TlsTest.cpp | 170 +++++++++++++++++++++++++++++- 5 files changed, 347 insertions(+), 12 deletions(-) diff --git a/src/inc/msquic.h b/src/inc/msquic.h index 6ba0bf0e36..a8ed83cf06 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -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, @@ -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; // diff --git a/src/inc/quic_platform.h b/src/inc/quic_platform.h index bc8f6f36a9..deb3426a2a 100644 --- a/src/inc/quic_platform.h +++ b/src/inc/quic_platform.h @@ -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, diff --git a/src/platform/tls_openssl.c b/src/platform/tls_openssl.c index 9fcebadf61..0dc87368df 100644 --- a/src/platform/tls_openssl.c +++ b/src/platform/tls_openssl.c @@ -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. // @@ -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. @@ -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, @@ -1188,6 +1274,10 @@ CxPlatTlsSecConfigCreate( CxPlatTlsSecConfigDelete(SecurityConfig); } + if (CipherSuiteString != NULL) { + CxPlatFree(CipherSuiteString, QUIC_POOL_TLS_CIPHER_SUITE_STRING); + } + if (X509Cert != NULL) { X509_free(X509Cert); } diff --git a/src/platform/tls_schannel.c b/src/platform/tls_schannel.c index da526deda8..a817ae4adc 100644 --- a/src/platform/tls_schannel.c +++ b/src/platform/tls_schannel.c @@ -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. @@ -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 @@ -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, @@ -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. @@ -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 diff --git a/src/platform/unittest/TlsTest.cpp b/src/platform/unittest/TlsTest.cpp index ade64716c4..e17a5acc83 100644 --- a/src/platform/unittest/TlsTest.cpp +++ b/src/platform/unittest/TlsTest.cpp @@ -31,12 +31,15 @@ struct TlsTest : public ::testing::TestWithParam CXPLAT_SEC_CONFIG* ServerSecConfig {nullptr}; CXPLAT_SEC_CONFIG* ServerSecConfigClientAuth {nullptr}; CXPLAT_SEC_CONFIG* ServerSecConfigDeferClientAuth {nullptr}; + CXPLAT_SEC_CONFIG* ServerSecConfigAes128 {nullptr}; CXPLAT_SEC_CONFIG* ClientSecConfig {nullptr}; CXPLAT_SEC_CONFIG* ClientSecConfigDeferredCertValidation {nullptr}; CXPLAT_SEC_CONFIG* ClientSecConfigCustomCertValidation {nullptr}; CXPLAT_SEC_CONFIG* ClientSecConfigExtraCertValidation {nullptr}; CXPLAT_SEC_CONFIG* ClientSecConfigNoCertValidation {nullptr}; CXPLAT_SEC_CONFIG* ClientSecConfigClientCertNoCertValidation {nullptr}; + CXPLAT_SEC_CONFIG* ClientSecConfigAes128 {nullptr}; + CXPLAT_SEC_CONFIG* ClientSecConfigAes256 {nullptr}; CXPLAT_SEC_CONFIG* Pkcs12SecConfig {nullptr}; static QUIC_CREDENTIAL_FLAGS SelfSignedCertParamsFlags; static QUIC_CREDENTIAL_CONFIG* SelfSignedCertParams; @@ -155,7 +158,11 @@ struct TlsTest : public ::testing::TestWithParam void SetUp() override { - SelfSignedCertParams->Flags = SelfSignedCertParamsFlags; // Make sure to start fresh + // + // Make sure to start fresh + // + SelfSignedCertParams->AllowedCipherSuites = QUIC_ALLOWED_CIPHER_SUITE_NONE; + SelfSignedCertParams->Flags = SelfSignedCertParamsFlags; VERIFY_QUIC_SUCCESS( CxPlatTlsSecConfigCreate( SelfSignedCertParams, @@ -165,6 +172,19 @@ struct TlsTest : public ::testing::TestWithParam OnSecConfigCreateComplete)); ASSERT_NE(nullptr, ServerSecConfig); + SelfSignedCertParams->AllowedCipherSuites = QUIC_ALLOWED_CIPHER_SUITE_AES_128_GCM_SHA256; + SelfSignedCertParams->Flags |= QUIC_CREDENTIAL_FLAG_SET_ALLOWED_CIPHER_SUITES; + VERIFY_QUIC_SUCCESS( + CxPlatTlsSecConfigCreate( + SelfSignedCertParams, + CXPLAT_TLS_CREDENTIAL_FLAG_NONE, + &TlsContext::TlsServerCallbacks, + &ServerSecConfigAes128, + OnSecConfigCreateComplete)); + ASSERT_NE(nullptr, ServerSecConfigAes128); + SelfSignedCertParams->AllowedCipherSuites = QUIC_ALLOWED_CIPHER_SUITE_NONE; + SelfSignedCertParams->Flags &= ~QUIC_CREDENTIAL_FLAG_SET_ALLOWED_CIPHER_SUITES; + #ifndef QUIC_DISABLE_CLIENT_CERT_TESTS SelfSignedCertParams->Flags = SelfSignedCertParamsFlags | QUIC_CREDENTIAL_FLAG_REQUIRE_CLIENT_AUTHENTICATION; VERIFY_QUIC_SUCCESS( @@ -195,7 +215,8 @@ struct TlsTest : public ::testing::TestWithParam NULL, NULL, NULL, - NULL + NULL, + QUIC_ALLOWED_CIPHER_SUITE_NONE }; VERIFY_QUIC_SUCCESS( CxPlatTlsSecConfigCreate( @@ -269,10 +290,47 @@ struct TlsTest : public ::testing::TestWithParam OnSecConfigCreateComplete)); ASSERT_NE(nullptr, Pkcs12SecConfig); #endif + + QUIC_CREDENTIAL_CONFIG ClientCredConfigCipherSuite = { + QUIC_CREDENTIAL_TYPE_NONE, + QUIC_CREDENTIAL_FLAG_CLIENT | QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION | + QUIC_CREDENTIAL_FLAG_SET_ALLOWED_CIPHER_SUITES, + NULL, + NULL, + NULL, + NULL, + QUIC_ALLOWED_CIPHER_SUITE_AES_128_GCM_SHA256 + }; + VERIFY_QUIC_SUCCESS( + CxPlatTlsSecConfigCreate( + &ClientCredConfigCipherSuite, + CXPLAT_TLS_CREDENTIAL_FLAG_NONE, + &TlsContext::TlsClientCallbacks, + &ClientSecConfigAes128, + OnSecConfigCreateComplete)); + ASSERT_NE(nullptr, ClientSecConfigAes128); + + ClientCredConfigCipherSuite.AllowedCipherSuites = QUIC_ALLOWED_CIPHER_SUITE_AES_256_GCM_SHA384; + VERIFY_QUIC_SUCCESS( + CxPlatTlsSecConfigCreate( + &ClientCredConfigCipherSuite, + CXPLAT_TLS_CREDENTIAL_FLAG_NONE, + &TlsContext::TlsClientCallbacks, + &ClientSecConfigAes256, + OnSecConfigCreateComplete)); + ASSERT_NE(nullptr, ClientSecConfigAes256); } void TearDown() override { + if (ClientSecConfigAes128) { + CxPlatTlsSecConfigDelete(ClientSecConfigAes128); + ClientSecConfigAes128 = nullptr; + } + if (ClientSecConfigAes256) { + CxPlatTlsSecConfigDelete(ClientSecConfigAes256); + ClientSecConfigAes256 = nullptr; + } if (ClientSecConfigNoCertValidation) { CxPlatTlsSecConfigDelete(ClientSecConfigNoCertValidation); ClientSecConfigNoCertValidation = nullptr; @@ -305,6 +363,10 @@ struct TlsTest : public ::testing::TestWithParam CxPlatTlsSecConfigDelete(ServerSecConfigDeferClientAuth); ServerSecConfigDeferClientAuth = nullptr; } + if (ServerSecConfigAes128) { + CxPlatTlsSecConfigDelete(ServerSecConfigAes128); + ServerSecConfigAes128 = nullptr; + } if (ServerSecConfig) { CxPlatTlsSecConfigDelete(ServerSecConfig); ServerSecConfig = nullptr; @@ -1605,4 +1667,108 @@ TEST_F(TlsTest, ClientCertificateDeferValidation) } #endif +TEST_F(TlsTest, CipherSuiteSuccess) +{ + // + // Set Server to use explicit cipher suite, client use default. + // + { + TlsContext ServerContext, ClientContext; + ServerContext.InitializeServer(ServerSecConfigAes128); + ClientContext.InitializeClient(ClientSecConfigNoCertValidation); + + DoHandshake(ServerContext, ClientContext); + } + // + // Set Client to use explicit cipher suite, server use default. + // + { + TlsContext ServerContext, ClientContext; + ServerContext.InitializeServer(ServerSecConfig); + ClientContext.InitializeClient(ClientSecConfigAes128); + + DoHandshake(ServerContext, ClientContext); + } + // + // Set both Client and Server to use same cipher suite. + // + { + TlsContext ServerContext, ClientContext; + ServerContext.InitializeServer(ServerSecConfigAes128); + ClientContext.InitializeClient(ClientSecConfigAes128); + + DoHandshake(ServerContext, ClientContext); + } +} + +TEST_F(TlsTest, CipherSuiteFailure) +{ + // + // Use mutually-exclusive cipher suites on client and server. + // + { + TlsContext ServerContext, ClientContext; + ServerContext.InitializeServer(ServerSecConfigAes128); + ClientContext.InitializeClient(ClientSecConfigAes256); + + auto Result = ClientContext.ProcessData(nullptr); + ASSERT_TRUE(Result & CXPLAT_TLS_RESULT_DATA); + + Result = ServerContext.ProcessData(&ClientContext.State, DefaultFragmentSize, true); + ASSERT_TRUE(Result & CXPLAT_TLS_RESULT_ERROR); + } + for (auto Flag : { + QUIC_CREDENTIAL_FLAG_CLIENT | QUIC_CREDENTIAL_FLAG_SET_ALLOWED_CIPHER_SUITES, + QUIC_CREDENTIAL_FLAG_SET_ALLOWED_CIPHER_SUITES}) { + // + // Don't set any allowed cipher suites + // + { + QUIC_CREDENTIAL_CONFIG TestCredConfig = { + QUIC_CREDENTIAL_TYPE_NONE, + Flag, + NULL, + NULL, + NULL, + NULL, + QUIC_ALLOWED_CIPHER_SUITE_NONE + }; + CXPLAT_SEC_CONFIG* TestSecConfig = nullptr; + ASSERT_EQ( + QUIC_STATUS_INVALID_PARAMETER, + CxPlatTlsSecConfigCreate( + &TestCredConfig, + CXPLAT_TLS_CREDENTIAL_FLAG_NONE, + &TlsContext::TlsClientCallbacks, + &TestSecConfig, + OnSecConfigCreateComplete)); + ASSERT_EQ(TestSecConfig, nullptr); + } + // + // Set an unrecognized cipher suite + // + { + QUIC_CREDENTIAL_CONFIG TestCredConfig = { + QUIC_CREDENTIAL_TYPE_NONE, + Flag, + NULL, + NULL, + NULL, + NULL, + (QUIC_ALLOWED_CIPHER_SUITE_FLAGS)0x100 + }; + CXPLAT_SEC_CONFIG* TestSecConfig = nullptr; + ASSERT_EQ( + QUIC_STATUS_INVALID_PARAMETER, + CxPlatTlsSecConfigCreate( + &TestCredConfig, + CXPLAT_TLS_CREDENTIAL_FLAG_NONE, + &TlsContext::TlsClientCallbacks, + &TestSecConfig, + OnSecConfigCreateComplete)); + ASSERT_EQ(TestSecConfig, nullptr); + } + } +} + INSTANTIATE_TEST_SUITE_P(TlsTest, TlsTest, ::testing::Bool());