From 390f88bce419d7065ba7c7c3936d9aaa33b8e94d Mon Sep 17 00:00:00 2001 From: Thad House <87844845+thhous-msft@users.noreply.github.com> Date: Thu, 28 Oct 2021 10:11:14 -0700 Subject: [PATCH] Enable use of OpenSSL 3 without deprecated functions (#2083) --- src/generated/linux/crypt_openssl.c.clog.h | 142 ++++++++++++++++ src/platform/crypt_openssl.c | 179 +++++++++++++++++++-- src/platform/tls_openssl.c | 63 +++++++- submodules/CMakeLists.txt | 18 ++- 4 files changed, 382 insertions(+), 20 deletions(-) diff --git a/src/generated/linux/crypt_openssl.c.clog.h b/src/generated/linux/crypt_openssl.c.clog.h index 8794f75f1..c8d249f48 100644 --- a/src/generated/linux/crypt_openssl.c.clog.h +++ b/src/generated/linux/crypt_openssl.c.clog.h @@ -436,6 +436,148 @@ tracepoint(CLOG_CRYPT_OPENSSL_C, AllocFailure , arg2, arg3);\ +#ifndef _clog_4_ARGS_TRACE_AllocFailure + + + +/*---------------------------------------------------------- +// Decoder Ring for AllocFailure +// Allocation of '%s' failed. (%llu bytes) +// QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "Crypt Hash Context", + sizeof(CXPLAT_HASH) + SaltLength); +// arg2 = arg2 = "Crypt Hash Context" +// arg3 = arg3 = sizeof(CXPLAT_HASH) + SaltLength +----------------------------------------------------------*/ +#define _clog_4_ARGS_TRACE_AllocFailure(uniqueId, encoded_arg_string, arg2, arg3)\ + +#endif + + + + +#ifndef _clog_3_ARGS_TRACE_LibraryError + + + +/*---------------------------------------------------------- +// Decoder Ring for LibraryError +// [ lib] ERROR, %s. +// QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_fetch failed"); +// arg2 = arg2 = "EVP_MAC_fetch failed" +----------------------------------------------------------*/ +#define _clog_3_ARGS_TRACE_LibraryError(uniqueId, encoded_arg_string, arg2)\ + +#endif + + + + +#ifndef _clog_3_ARGS_TRACE_LibraryError + + + +/*---------------------------------------------------------- +// Decoder Ring for LibraryError +// [ lib] ERROR, %s. +// QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_CTX_new failed"); +// arg2 = arg2 = "EVP_MAC_CTX_new failed" +----------------------------------------------------------*/ +#define _clog_3_ARGS_TRACE_LibraryError(uniqueId, encoded_arg_string, arg2)\ + +#endif + + + + +#ifndef _clog_3_ARGS_TRACE_LibraryError + + + +/*---------------------------------------------------------- +// Decoder Ring for LibraryError +// [ lib] ERROR, %s. +// QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_CTX_set_params failed"); +// arg2 = arg2 = "EVP_MAC_CTX_set_params failed" +----------------------------------------------------------*/ +#define _clog_3_ARGS_TRACE_LibraryError(uniqueId, encoded_arg_string, arg2)\ + +#endif + + + + +#ifndef _clog_3_ARGS_TRACE_LibraryError + + + +/*---------------------------------------------------------- +// Decoder Ring for LibraryError +// [ lib] ERROR, %s. +// QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_init failed"); +// arg2 = arg2 = "EVP_MAC_init failed" +----------------------------------------------------------*/ +#define _clog_3_ARGS_TRACE_LibraryError(uniqueId, encoded_arg_string, arg2)\ + +#endif + + + + +#ifndef _clog_3_ARGS_TRACE_LibraryError + + + +/*---------------------------------------------------------- +// Decoder Ring for LibraryError +// [ lib] ERROR, %s. +// QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_update failed"); +// arg2 = arg2 = "EVP_MAC_update failed" +----------------------------------------------------------*/ +#define _clog_3_ARGS_TRACE_LibraryError(uniqueId, encoded_arg_string, arg2)\ + +#endif + + + + +#ifndef _clog_3_ARGS_TRACE_LibraryError + + + +/*---------------------------------------------------------- +// Decoder Ring for LibraryError +// [ lib] ERROR, %s. +// QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_final failed"); +// arg2 = arg2 = "EVP_MAC_final failed" +----------------------------------------------------------*/ +#define _clog_3_ARGS_TRACE_LibraryError(uniqueId, encoded_arg_string, arg2)\ + +#endif + + + + #ifndef _clog_3_ARGS_TRACE_LibraryError diff --git a/src/platform/crypt_openssl.c b/src/platform/crypt_openssl.c index c1b059388..55ae45ba6 100644 --- a/src/platform/crypt_openssl.c +++ b/src/platform/crypt_openssl.c @@ -11,14 +11,22 @@ Abstract: #include "platform_internal.h" -#define OPENSSL_SUPPRESS_DEPRECATED 1 // For hmac.h, which was deprecated in 3.0 +#include "openssl/opensslv.h" +#if OPENSSL_VERSION_MAJOR >= 3 +#define IS_OPENSSL_3 +#endif + #ifdef _WIN32 #pragma warning(push) #pragma warning(disable:4100) // Unreferenced parameter errcode in inline function #endif #include "openssl/bio.h" -#include "openssl/err.h" +#ifdef IS_OPENSSL_3 +#include "openssl/core_names.h" +#else #include "openssl/hmac.h" +#endif +#include "openssl/err.h" #include "openssl/kdf.h" #include "openssl/pem.h" #include "openssl/pkcs12.h" @@ -414,19 +422,165 @@ CxPlatHpComputeMask( // Hash abstraction // +#ifdef IS_OPENSSL_3 +// +// OpenSSL 3.0 Hash implementation +// typedef struct CXPLAT_HASH { - // - // The message digest. - // - const EVP_MD *Md; - - // - // Context used for hashing. - // - HMAC_CTX* HashContext; - + EVP_MAC* Mac; + EVP_MAC_CTX* Ctx; + uint32_t SaltLength; + uint8_t Salt[0]; } CXPLAT_HASH; +_IRQL_requires_max_(DISPATCH_LEVEL) +QUIC_STATUS +CxPlatHashCreate( + _In_ CXPLAT_HASH_TYPE HashType, + _In_reads_(SaltLength) + const uint8_t* const Salt, + _In_ uint32_t SaltLength, + _Out_ CXPLAT_HASH** NewHash + ) +{ + QUIC_STATUS Status = QUIC_STATUS_SUCCESS; + CXPLAT_HASH* Hash; + const char* HashString; + OSSL_PARAM AlgParam[2]; + + Hash = CXPLAT_ALLOC_NONPAGED(sizeof(CXPLAT_HASH) + SaltLength, QUIC_POOL_TLS_HASH); + if (Hash == NULL) { + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "Crypt Hash Context", + sizeof(CXPLAT_HASH) + SaltLength); + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Exit; + } + CxPlatZeroMemory(Hash, sizeof(CXPLAT_HASH) + SaltLength); + + Hash->SaltLength = SaltLength; + CxPlatCopyMemory(Hash->Salt, Salt, SaltLength); + + Hash->Mac = EVP_MAC_fetch(NULL, "HMAC", NULL); + if (Hash->Mac == NULL) { + QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_fetch failed"); + Status = QUIC_STATUS_TLS_ERROR; + goto Exit; + } + + Hash->Ctx = EVP_MAC_CTX_new(Hash->Mac); + if (Hash->Ctx == NULL) { + QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_CTX_new failed"); + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Exit; + } + + switch (HashType) { + case CXPLAT_HASH_SHA256: + HashString = "sha256"; + break; + case CXPLAT_HASH_SHA384: + HashString = "sha384"; + break; + case CXPLAT_HASH_SHA512: + HashString = "sha512"; + break; + default: + Status = QUIC_STATUS_NOT_SUPPORTED; + goto Exit; + } + + AlgParam[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, (char*)HashString, 0); + AlgParam[1] = OSSL_PARAM_construct_end(); + + if (!EVP_MAC_CTX_set_params(Hash->Ctx, AlgParam)) { + QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_CTX_set_params failed"); + Status = QUIC_STATUS_TLS_ERROR; + goto Exit; + } + + *NewHash = Hash; + Hash = NULL; + +Exit: + + CxPlatHashFree(Hash); + + return Status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +CxPlatHashFree( + _In_opt_ CXPLAT_HASH* Hash + ) +{ + if (Hash) { + if (Hash->Ctx) { + EVP_MAC_CTX_free(Hash->Ctx); + } + if (Hash->Mac) { + EVP_MAC_free(Hash->Mac); + } + CXPLAT_FREE(Hash, QUIC_POOL_TLS_HASH); + } +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +QUIC_STATUS +CxPlatHashCompute( + _In_ CXPLAT_HASH* Hash, + _In_reads_(InputLength) + const uint8_t* const Input, + _In_ uint32_t InputLength, + _In_ uint32_t OutputLength, // CxPlatHashLength(HashType) + _Out_writes_all_(OutputLength) + uint8_t* const Output + ) +{ + if (!EVP_MAC_init(Hash->Ctx, Hash->Salt, Hash->SaltLength, NULL)) { + QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_init failed"); + return QUIC_STATUS_INTERNAL_ERROR; + } + + if (!EVP_MAC_update(Hash->Ctx, Input, InputLength)) { + QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_update failed"); + return QUIC_STATUS_INTERNAL_ERROR; + } + + size_t ActualOutputSize = OutputLength; + if (!EVP_MAC_final(Hash->Ctx, Output, &ActualOutputSize, OutputLength)) { + QuicTraceEvent( + LibraryError, + "[ lib] ERROR, %s.", + "EVP_MAC_final failed"); + return QUIC_STATUS_INTERNAL_ERROR; + } + + CXPLAT_FRE_ASSERT(ActualOutputSize == OutputLength); + return QUIC_STATUS_SUCCESS; +} +#else +// +// OpenSSL 1.1 Hash implementation +// _IRQL_requires_max_(DISPATCH_LEVEL) QUIC_STATUS CxPlatHashCreate( @@ -535,3 +689,4 @@ CxPlatHashCompute( CXPLAT_FRE_ASSERT(ActualOutputSize == OutputLength); return QUIC_STATUS_SUCCESS; } +#endif diff --git a/src/platform/tls_openssl.c b/src/platform/tls_openssl.c index 53fed933a..85baf9edc 100644 --- a/src/platform/tls_openssl.c +++ b/src/platform/tls_openssl.c @@ -11,14 +11,22 @@ Abstract: #include "platform_internal.h" -#define OPENSSL_SUPPRESS_DEPRECATED 1 // For hmac.h, which was deprecated in 3.0 +#include "openssl/opensslv.h" +#if OPENSSL_VERSION_MAJOR >= 3 +#define IS_OPENSSL_3 +#endif + #ifdef _WIN32 #pragma warning(push) #pragma warning(disable:4100) // Unreferenced parameter errcode in inline function #endif #include "openssl/bio.h" -#include "openssl/err.h" +#ifdef IS_OPENSSL_3 +#include "openssl/core_names.h" +#else #include "openssl/hmac.h" +#endif +#include "openssl/err.h" #include "openssl/kdf.h" #include "openssl/pem.h" #include "openssl/pkcs12.h" @@ -727,10 +735,17 @@ CxPlatTlsOnSessionTicketKeyNeeded( _When_(!enc, _In_reads_bytes_(EVP_MAX_IV_LENGTH)) unsigned char iv[EVP_MAX_IV_LENGTH], _Inout_ EVP_CIPHER_CTX *ctx, +#ifdef IS_OPENSSL_3 + _Inout_ EVP_MAC_CTX *hctx, +#else _Inout_ HMAC_CTX *hctx, +#endif _In_ int enc // Encryption or decryption ) { +#ifdef IS_OPENSSL_3 + OSSL_PARAM params[3]; +#endif CXPLAT_TLS* TlsContext = SSL_get_app_data(Ssl); QUIC_TICKET_KEY_CONFIG* TicketKey = TlsContext->SecConfig->TicketKey; @@ -754,8 +769,24 @@ CxPlatTlsOnSessionTicketKeyNeeded( } CxPlatCopyMemory(key_name, TicketKey->Id, 16); EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, TicketKey->Material, iv); - HMAC_Init_ex(hctx, TicketKey->Material, 32, EVP_sha256(), NULL); +#ifdef IS_OPENSSL_3 + params[0] = + OSSL_PARAM_construct_octet_string( + OSSL_MAC_PARAM_KEY, + TicketKey->Material, + 32); + params[1] = + OSSL_PARAM_construct_utf8_string( + OSSL_MAC_PARAM_DIGEST, + "sha256", + 0); + params[2] = + OSSL_PARAM_construct_end(); + EVP_MAC_CTX_set_params(hctx, params); +#else + HMAC_Init_ex(hctx, TicketKey->Material, 32, EVP_sha256(), NULL); +#endif } else { if (memcmp(key_name, TicketKey->Id, 16) != 0) { QuicTraceEvent( @@ -765,7 +796,23 @@ CxPlatTlsOnSessionTicketKeyNeeded( "Ticket key_name mismatch"); return 0; // No match } +#ifdef IS_OPENSSL_3 + params[0] = + OSSL_PARAM_construct_octet_string( + OSSL_MAC_PARAM_KEY, + TicketKey->Material, + 32); + params[1] = + OSSL_PARAM_construct_utf8_string( + OSSL_MAC_PARAM_DIGEST, + "sha256", + 0); + params[2] = + OSSL_PARAM_construct_end(); + EVP_MAC_CTX_set_params(hctx, params); +#else HMAC_Init_ex(hctx, TicketKey->Material, 32, EVP_sha256(), NULL); +#endif EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, TicketKey->Material, iv); } @@ -1531,9 +1578,15 @@ CxPlatTlsSecConfigSetTicketKeys( KeyConfig, sizeof(QUIC_TICKET_KEY_CONFIG)); +#ifdef IS_OPENSSL_3 + SSL_CTX_set_tlsext_ticket_key_evp_cb( + SecurityConfig->SSLCtx, + CxPlatTlsOnSessionTicketKeyNeeded); +#else SSL_CTX_set_tlsext_ticket_key_cb( SecurityConfig->SSLCtx, CxPlatTlsOnSessionTicketKeyNeeded); +#endif return QUIC_STATUS_SUCCESS; } @@ -1850,7 +1903,11 @@ CxPlatTlsProcessData( char buf[256]; const char* file; int line; +#ifdef IS_OPENSSL_3 + ERR_error_string_n(ERR_get_error_all(&file, &line, NULL, NULL, NULL), buf, sizeof(buf)); +#else ERR_error_string_n(ERR_get_error_line(&file, &line), buf, sizeof(buf)); +#endif QuicTraceLogConnError( OpenSslHandshakeErrorStr, TlsContext->Connection, diff --git a/submodules/CMakeLists.txt b/submodules/CMakeLists.txt index f9e3062ae..30a7db8a8 100644 --- a/submodules/CMakeLists.txt +++ b/submodules/CMakeLists.txt @@ -14,14 +14,18 @@ set(QUIC_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) set(OPENSSL_DIR ${QUIC_BUILD_DIR}/openssl) option(QUIC_USE_SYSTEM_LIBCRYPTO "Use system libcrypto if openssl TLS" OFF) +# Newer versions of OpenSSL switched to Markdown, so we can use that to detect +# the openssl version cloned +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/openssl/CHANGES") + message(STATUS "Configuring for OpenSSL 1.1") +else() + set(QUIC_USE_OPENSSL3 ON) + message(STATUS "Configuring for OpenSSL 3.0") +endif() + set(OPENSSL_CONFIG_FLAGS enable-tls1_3 no-makedepend no-dgram no-ssl3 no-psk no-srp - # - # The following line is needed for the 3.0 branch. - # - # no-uplink no-cmp no-acvp_tests no-fips no-padlockeng no-siv - no-zlib no-egd no-idea no-rc5 no-rc4 no-afalgeng no-comp no-cms no-ct no-srp no-srtp no-ts no-gost no-dso no-ec2m no-tls1 no-tls1_1 no-tls1_2 no-dtls no-dtls1 no-dtls1_2 no-ssl @@ -29,6 +33,10 @@ set(OPENSSL_CONFIG_FLAGS no-siphash no-whirlpool no-aria no-bf no-blake2 no-sm2 no-sm3 no-sm4 no-camellia no-cast no-md4 no-mdc2 no-ocb no-rc2 no-rmd160 no-scrypt no-weak-ssl-ciphers no-shared no-tests) +if (QUIC_USE_OPENSSL3) + list(APPEND OPENSSL_CONFIG_FLAGS no-uplink no-cmp no-fips no-padlockeng no-siv) +endif() + if (WIN32) if (DEFINED ENV{CommonProgramFiles})