From ec0231bed598be1ca22116e57aae6aac956ca96b Mon Sep 17 00:00:00 2001 From: ucko Date: Tue, 23 Apr 2024 19:21:48 +0000 Subject: [PATCH] [PATCH] Accommodate Mbed TLS 3.x (specifically, 3.6.0 LTS). - Conditionally pass mbedtls_pk_parse_key the existing pRNG and its state. - Call psa_crypto_init during setup, as PSA may be in play even when not explicitly enabled. Documentation suggests calling it as early as possible; in practice, though, holding off until after pRNG initialization avoids "insufficient entropy" errors under 2.x (at least 2.28.8 LTS on Linux) and still works fine as of 3.6.0. - At least for now, ensure that MBEDTLS_SSL_VERIFY_NONE remains effective by additionally capping the TLS version at 1.2; as of 1.3, certificate checking has become mandatory, and Mbed TLS respects that requirement. - Additional tuneups to ncbi_mbedtls.c-only code: -- Account for error-code macro repertoire changes by conditionalizing major-version-specific macros on their availability and specifically checking for or emitting MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED (new) as appropriate, -- x_ErrorToStatus: Conditionally use MBEDTLS_PRIVATE for p_bio, which has no accessor. -- x_MbedTlsWrite: Substitute mbedtls_ssl_get_max_out_record_payload for mbedtls_ssl_get_output_max_frag_len, which didn't account for other relevant considerations and is now fully private. https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md supplied useful guidance. JIRA: CXX-13565. git-svn-id: https://anonsvn.ncbi.nlm.nih.gov/repos/v1/trunk/c++@102329 78c7ea69-d796-4a43-9a09-de51944f1b03 Gbp-Pq: Name support_mbedtls3 --- c++/src/connect/ncbi_mbedtls.c | 44 +++++++++++++++++++++++++++-- c++/src/connect/ncbi_priv.h | 2 +- c++/src/connect/ncbi_uv_nghttp2.cpp | 22 ++++++++++++++- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/c++/src/connect/ncbi_mbedtls.c b/c++/src/connect/ncbi_mbedtls.c index 9b26f1b9..c0aeaa1a 100644 --- a/c++/src/connect/ncbi_mbedtls.c +++ b/c++/src/connect/ncbi_mbedtls.c @@ -52,6 +52,7 @@ # include # include # include +# include # if defined(ENOTSUP) # define NCBI_NOTSUPPORTED ENOTSUP @@ -101,7 +102,11 @@ static int mbtls_user_mutex_lock(MT_LOCK* lock) if (lock) { switch (MT_LOCK_Do(*lock, eMT_Lock)) { case -1: +#ifdef MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE return MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE; +#else + return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; +#endif case 0: return MBEDTLS_ERR_THREADING_MUTEX_ERROR; case 1: @@ -117,7 +122,11 @@ static int mbtls_user_mutex_unlock(MT_LOCK* lock) if (lock) { switch (MT_LOCK_Do(*lock, eMT_Unlock)) { case -1: +#ifdef MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE return MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE; +#else + return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; +#endif case 0: return MBEDTLS_ERR_THREADING_MUTEX_ERROR; case 1: @@ -214,7 +223,11 @@ static EIO_Status x_ErrorToStatus(int error, mbedtls_ssl_context* session, if (!error) return eIO_Success; +#if MBEDTLS_VERSION_MAJOR >= 3 + sock = ((SNcbiSSLctx*)(session->MBEDTLS_PRIVATE(p_bio)))->sock; +#else sock = ((SNcbiSSLctx*)(session->p_bio))->sock; +#endif switch (error) { case MBEDTLS_ERR_SSL_WANT_READ: status = x_RetryStatus(sock, direction); @@ -225,11 +238,20 @@ static EIO_Status x_ErrorToStatus(int error, mbedtls_ssl_context* session, case MBEDTLS_ERR_SSL_TIMEOUT: status = eIO_Timeout; break; +#ifdef MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE case MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE: +#endif +#ifdef MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: +#endif case MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE: +#ifdef MBEDTLS_ERR_SSL_UNKNOWN_CIPHER case MBEDTLS_ERR_SSL_UNKNOWN_CIPHER: +#endif case MBEDTLS_ERR_SSL_INTERNAL_ERROR: +#ifdef MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED + case MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED: +#endif status = eIO_NotSupported; break; case MBEDTLS_ERR_THREADING_BAD_INPUT_DATA: @@ -574,8 +596,8 @@ static EIO_Status x_MbedTlsWrite(void* session, const void* data, static EIO_Status s_MbedTlsWrite(void* session, const void* data, size_t n_todo, size_t* n_done, int* error) { - size_t max_size - = mbedtls_ssl_get_output_max_frag_len((mbedtls_ssl_context*) session); + size_t max_size = mbedtls_ssl_get_max_out_record_payload + ((mbedtls_ssl_context*) session); EIO_Status status; *n_done = 0; @@ -714,6 +736,7 @@ static EIO_Status s_MbedTlsInit(FSSLPull pull, FSSLPush push) char version[80]; const char* val; char buf[32]; + psa_status_t psa_status; mbedtls_version_get_string(version); if (strcasecmp(MBEDTLS_VERSION_STRING, version) != 0) { @@ -734,6 +757,11 @@ static EIO_Status s_MbedTlsInit(FSSLPull pull, FSSLPush push) MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); mbedtls_ssl_conf_authmode(&s_MbedTlsConf, MBEDTLS_SSL_VERIFY_NONE); +#if MBEDTLS_VERSION_MAJOR >= 3 + /* The above line can otherwise be ineffective. */ + mbedtls_ssl_conf_max_tls_version(&s_MbedTlsConf, + MBEDTLS_SSL_VERSION_TLS1_2); +#endif /* Check CONN_[MBED]TLS_LOGLEVEL or [CONN][MBED]TLS_LOGLEVEL */ val = ConnNetInfo_GetValueInternal(0, "MBED" REG_CONN_TLS_LOGLEVEL, @@ -781,6 +809,12 @@ static EIO_Status s_MbedTlsInit(FSSLPull pull, FSSLPush push) mbedtls_ssl_conf_rng(&s_MbedTlsConf, mbedtls_ctr_drbg_random, &s_MbedTlsCtrDrbg); + if ((psa_status = psa_crypto_init()) != PSA_SUCCESS) { + CORE_LOGF_X(51, eLOG_Error, + ("psa_crypto_init failed with status %d", psa_status)); + return eIO_NotSupported; + } + s_Pull = pull; s_Push = push; @@ -957,7 +991,11 @@ NCBI_CRED NcbiCreateMbedTlsCertCredentials(const void* cert, err = mbedtls_pk_parse_key(xcred->pkey, (const unsigned char*) pkey, pkeysz ? pkeysz - : strlen((const char*) pkey) + 1, 0, 0); + : strlen((const char*) pkey) + 1, 0, 0 +#if MBEDTLS_VERSION_MAJOR >= 3 + , mbedtls_ctr_drbg_random, &s_MbedTlsCtrDrbg +#endif + ); if (err) { mbedtls_strerror(err, errbuf, sizeof(errbuf) - 1); CORE_LOG_ERRNO_EXX(12, eLOG_Error, err, errbuf, diff --git a/c++/src/connect/ncbi_priv.h b/c++/src/connect/ncbi_priv.h index 60d1c361..c4dcc19f 100644 --- a/c++/src/connect/ncbi_priv.h +++ b/c++/src/connect/ncbi_priv.h @@ -101,7 +101,7 @@ NCBI_C_DEFINE_ERRCODE_X(Connect_SMTP, 306, 33); NCBI_C_DEFINE_ERRCODE_X(Connect_HTTP, 307, 26); NCBI_C_DEFINE_ERRCODE_X(Connect_Service, 308, 10); NCBI_C_DEFINE_ERRCODE_X(Connect_HeapMgr, 309, 34); -NCBI_C_DEFINE_ERRCODE_X(Connect_TLS, 310, 50); +NCBI_C_DEFINE_ERRCODE_X(Connect_TLS, 310, 51); NCBI_C_DEFINE_ERRCODE_X(Connect_Mghbn, 311, 16); NCBI_C_DEFINE_ERRCODE_X(Connect_Crypt, 312, 5); NCBI_C_DEFINE_ERRCODE_X(Connect_LocalIP, 313, 5); diff --git a/c++/src/connect/ncbi_uv_nghttp2.cpp b/c++/src/connect/ncbi_uv_nghttp2.cpp index 74a46d6e..154045dd 100644 --- a/c++/src/connect/ncbi_uv_nghttp2.cpp +++ b/c++/src/connect/ncbi_uv_nghttp2.cpp @@ -40,6 +40,8 @@ #include #include +#include + BEGIN_NCBI_SCOPE #define NCBI_UV_WRITE_TRACE(message) _TRACE(message) @@ -701,6 +703,10 @@ SUvNgHttp2_TlsImpl::SUvNgHttp2_TlsImpl(const TAddrNCred& addr_n_cred, size_t rd_ } mbedtls_ssl_conf_authmode(&m_Conf, MBEDTLS_SSL_VERIFY_NONE); +#if MBEDTLS_VERSION_MAJOR >= 3 + /* The above line can otherwise be ineffective. */ + mbedtls_ssl_conf_max_tls_version(&m_Conf, MBEDTLS_SSL_VERSION_TLS1_2); +#endif mbedtls_entropy_init(&m_Entropy); mbedtls_ctr_drbg_init(&m_CtrDrbg); mbedtls_x509_crt_init(&m_Cert); @@ -714,6 +720,14 @@ SUvNgHttp2_TlsImpl::SUvNgHttp2_TlsImpl(const TAddrNCred& addr_n_cred, size_t rd_ } mbedtls_ssl_conf_rng(&m_Conf, mbedtls_ctr_drbg_random, &m_CtrDrbg); + auto p_rv = psa_crypto_init(); + + if (p_rv != PSA_SUCCESS) { + NCBI_UVNGHTTP2_TLS_TRACE(this << " psa_crypto_init: error code" + << p_rv); + return; + } + mbedtls_ssl_conf_alpn_protocols(&m_Conf, m_Protocols.data()); mbedtls_ssl_init(&m_Ssl); @@ -748,7 +762,13 @@ SUvNgHttp2_TlsImpl::SUvNgHttp2_TlsImpl(const TAddrNCred& addr_n_cred, size_t rd_ return; } - auto pk_rv = mbedtls_pk_parse_key(&m_Pkey, reinterpret_cast(pkey.data()), pkey.size() + 1, nullptr, 0); + auto pk_rv = mbedtls_pk_parse_key( + &m_Pkey, reinterpret_cast(pkey.data()), + pkey.size() + 1, nullptr, 0 +#if MBEDTLS_VERSION_MAJOR >= 3 + , mbedtls_ctr_drbg_random, &m_CtrDrbg +#endif + ); if (pk_rv) { NCBI_UVNGHTTP2_TLS_TRACE(this << " mbedtls_pk_parse_key: " << SUvNgHttp2_Error::MbedTlsStr(pk_rv)); -- 2.30.2