From ebe783666f66f5139e787d38b268feab8cc2c1dd Mon Sep 17 00:00:00 2001 From: Gijs Peskens Date: Thu, 22 Feb 2024 00:21:15 +0100 Subject: [PATCH] Support for upstream mbedtls versions 2 and 3 when compiled with SRTP support Co-authored-by: Thulinma --- lib/certificate.cpp | 8 +++- lib/certificate.h | 8 +++- lib/socket.cpp | 74 +++++++++++++++++++++++++++++++++++++ lib/socket.h | 20 ++++++++++ meson.build | 43 +++++++++++++-------- src/output/output_https.cpp | 4 ++ src/output/output_https.h | 8 ++++ 7 files changed, 147 insertions(+), 18 deletions(-) diff --git a/lib/certificate.cpp b/lib/certificate.cpp index fa329211..a7f8a0f0 100644 --- a/lib/certificate.cpp +++ b/lib/certificate.cpp @@ -7,12 +7,12 @@ Certificate::Certificate(){ mbedtls_pk_init(&key); mbedtls_x509_crt_init(&cert); + mbedtls_ctr_drbg_init(&rand_ctx); } int Certificate::init(const std::string &countryName, const std::string &organization, const std::string &commonName){ - mbedtls_ctr_drbg_context rand_ctx ={}; mbedtls_entropy_context entropy_ctx ={}; mbedtls_x509write_cert write_cert ={}; mbedtls_rsa_context *rsa_ctx; @@ -49,7 +49,6 @@ int Certificate::init(const std::string &countryName, const std::string &organiz } // initialize random number generator - mbedtls_ctr_drbg_init(&rand_ctx); mbedtls_entropy_init(&entropy_ctx); r = mbedtls_ctr_drbg_seed(&rand_ctx, mbedtls_entropy_func, &entropy_ctx, (const unsigned char *)personalisation, strlen(personalisation)); @@ -205,6 +204,7 @@ error: Certificate::~Certificate(){ mbedtls_pk_free(&key); mbedtls_x509_crt_free(&cert); + mbedtls_ctr_drbg_free(&rand_ctx); } /// Loads a single file into the certificate. Returns true on success. @@ -216,7 +216,11 @@ bool Certificate::loadCert(const std::string & certFile){ /// Loads a single key. Returns true on success. bool Certificate::loadKey(const std::string & keyFile){ if (!keyFile.size()){return true;} +#if MBEDTLS_VERSION_MAJOR > 2 + return mbedtls_pk_parse_keyfile(&key, keyFile.c_str(), NULL, mbedtls_ctr_drbg_random, &rand_ctx) == 0; +#else return mbedtls_pk_parse_keyfile(&key, keyFile.c_str(), 0) == 0; +#endif } /// Calculates SHA256 fingerprint over the loaded certificate(s) diff --git a/lib/certificate.h b/lib/certificate.h index a8ccf747..350fc665 100644 --- a/lib/certificate.h +++ b/lib/certificate.h @@ -9,8 +9,12 @@ communication. This certificate uses a 2048 bits RSA key. */ - +#include +#if MBEDTLS_VERSION_MAJOR > 2 +#include +#else #include +#endif #include #include #include @@ -32,4 +36,6 @@ public: public: mbedtls_x509_crt cert; mbedtls_pk_context key; /* key context, stores private and public key. */ +private: + mbedtls_ctr_drbg_context rand_ctx; }; diff --git a/lib/socket.cpp b/lib/socket.cpp index f4bcc883..c42e353f 100644 --- a/lib/socket.cpp +++ b/lib/socket.cpp @@ -1663,6 +1663,23 @@ void Socket::UDPConnection::init(bool _nonblock, int _family){ #endif } +#if HAVE_UPSTREAM_MBEDTLS_SRTP +#if MBEDTLS_VERSION_MAJOR > 2 +static void dtlsExtractKeyData( void *user, mbedtls_ssl_key_export_type type, const unsigned char *ms, size_t, const unsigned char client_random[32], const unsigned char server_random[32], mbedtls_tls_prf_types tls_prf_type){ +#else +static int dtlsExtractKeyData( void *user, const unsigned char *ms, const unsigned char *, size_t, size_t, size_t, const unsigned char client_random[32], const unsigned char server_random[32], mbedtls_tls_prf_types tls_prf_type){ +#endif + Socket::UDPConnection *udpSock = static_cast(user); + memcpy(udpSock->master_secret, ms, sizeof(udpSock->master_secret)); + memcpy(udpSock->randbytes, client_random, 32); + memcpy(udpSock->randbytes + 32, server_random, 32); + udpSock->tls_prf_type = tls_prf_type; +#if MBEDTLS_VERSION_MAJOR == 2 + return 0; +#endif +} +#endif + void Socket::UDPConnection::initDTLS(mbedtls_x509_crt *cert, mbedtls_pk_context *key){ hasDTLS = true; nextDTLSRead = 0; @@ -1710,13 +1727,22 @@ void Socket::UDPConnection::initDTLS(mbedtls_x509_crt *cert, mbedtls_pk_context //mbedtls_debug_set_threshold(10); // enable SRTP support (non-fatal on error) +#if !HAVE_UPSTREAM_MBEDTLS_SRTP mbedtls_ssl_srtp_profile srtpPro[] ={MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80, MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32}; r = mbedtls_ssl_conf_dtls_srtp_protection_profiles(&ssl_conf, srtpPro, sizeof(srtpPro) / sizeof(srtpPro[0])); +#else + static mbedtls_ssl_srtp_profile srtpPro[] ={MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_80, MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_32, MBEDTLS_TLS_SRTP_UNSET}; + r = mbedtls_ssl_conf_dtls_srtp_protection_profiles(&ssl_conf, srtpPro); +#endif if (r){ mbedtls_strerror(r, mbedtls_msg, sizeof(mbedtls_msg)); WARN_MSG("dTLS could not set SRTP profiles: %s", mbedtls_msg); } +#if HAVE_UPSTREAM_MBEDTLS_SRTP && MBEDTLS_VERSION_MAJOR == 2 + mbedtls_ssl_conf_export_keys_ext_cb(&ssl_conf, dtlsExtractKeyData, this); +#endif + /* cert certificate chain + key, so we can verify the client-hello signed data */ r = mbedtls_ssl_conf_own_cert(&ssl_conf, cert, key); if (r){ @@ -1742,6 +1768,10 @@ void Socket::UDPConnection::initDTLS(mbedtls_x509_crt *cert, mbedtls_pk_context return; } +#if MBEDTLS_VERSION_MAJOR > 2 + mbedtls_ssl_set_export_keys_cb(&ssl_ctx, dtlsExtractKeyData, this); +#endif + // set input/output callbacks mbedtls_ssl_set_bio(&ssl_ctx, (void *)this, dTLS_send, dTLS_recv, NULL); mbedtls_ssl_set_timer_cb(&ssl_ctx, &timer_ctx, mbedtls_timing_set_delay, mbedtls_timing_get_delay); @@ -2194,7 +2224,11 @@ void Socket::UDPConnection::SendNow(const char *sdata, size_t len, sockaddr * dA /// Note: Only actually encrypts if initDTLS was called in the past. void Socket::UDPConnection::sendPaced(const char *sdata, size_t len, bool encrypt){ if (hasDTLS && encrypt){ +#if MBEDTLS_VERSION_MAJOR > 2 + if (!mbedtls_ssl_is_handshake_over(&ssl_ctx)){ +#else if (ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER){ +#endif WARN_MSG("Attempting to write encrypted data before handshake completed! Data was thrown away."); return; } @@ -2622,12 +2656,18 @@ bool Socket::UDPConnection::onData(){ nextDTLSRead = data; nextDTLSReadLen = data.size(); // Complete dTLS handshake if needed +#if MBEDTLS_VERSION_MAJOR > 2 + if (!mbedtls_ssl_is_handshake_over(&ssl_ctx)){ +#else if (ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER){ +#endif do{ r = mbedtls_ssl_handshake(&ssl_ctx); switch (r){ case 0:{ // Handshake complete INFO_MSG("dTLS handshake complete!"); + +#if !HAVE_UPSTREAM_MBEDTLS_SRTP int extrRes = 0; uint8_t keying_material[MBEDTLS_DTLS_SRTP_MAX_KEY_MATERIAL_LENGTH]; size_t keying_material_len = sizeof(keying_material); @@ -2654,6 +2694,40 @@ bool Socket::UDPConnection::onData(){ return Receive(); } } +#else + uint8_t keying_material[MBEDTLS_TLS_SRTP_MAX_MKI_LENGTH] = {}; + mbedtls_dtls_srtp_info info = {}; + mbedtls_ssl_get_dtls_srtp_negotiation_result(&ssl_ctx, &info); + + if (mbedtls_ssl_tls_prf(tls_prf_type, master_secret, sizeof(master_secret), "EXTRACTOR-dtls_srtp", randbytes,sizeof( randbytes ), keying_material, sizeof( keying_material )) != 0){ + ERROR_MSG("mbedtls_ssl_tls_prf failed to create keying_material"); + return Receive(); + } +#if MBEDTLS_VERSION_MAJOR > 2 + mbedtls_ssl_srtp_profile chosen_profile = info.private_chosen_dtls_srtp_profile; +#else + mbedtls_ssl_srtp_profile chosen_profile = info.chosen_dtls_srtp_profile; +#endif + switch (chosen_profile){ + case MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_80:{ + cipher = "SRTP_AES128_CM_SHA1_80"; + break; + } + case MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_32:{ + cipher = "SRTP_AES128_CM_SHA1_32"; + break; + } + case MBEDTLS_TLS_SRTP_UNSET: { + WARN_MSG("Wasn't able to negotiate the use of DTLS-SRTP"); + return Receive(); + } + default:{ + WARN_MSG("Unhandled SRTP profile: %hu, cannot extract keying material.", chosen_profile); + return Receive(); + } + } +#endif + remote_key.assign((char *)(&keying_material[0]) + 0, 16); local_key.assign((char *)(&keying_material[0]) + 16, 16); remote_salt.assign((char *)(&keying_material[0]) + 32, 14); diff --git a/lib/socket.h b/lib/socket.h index f73f93cf..871fa7e9 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -22,10 +22,25 @@ #include #include #include + +#if !HAVE_UPSTREAM_MBEDTLS_SRTP #include +#else +#include +#endif + #include #include #include +#include + +#if MBEDTLS_VERSION_MAJOR == 2 +#include +#include +#else +#include +#endif + #endif #include "util.h" @@ -270,5 +285,10 @@ namespace Socket{ // dTLS-related public members std::string cipher, remote_key, local_key, remote_salt, local_salt; +#if HAVE_UPSTREAM_MBEDTLS_SRTP + unsigned char master_secret[48]; + unsigned char randbytes[64]; + mbedtls_tls_prf_types tls_prf_type; +#endif }; }// namespace Socket diff --git a/meson.build b/meson.build index 03ff3690..0765aec2 100644 --- a/meson.build +++ b/meson.build @@ -106,27 +106,40 @@ if usessl mbedx509 = ccpp.find_library('mbedx509', required: false) mbedcrypto = ccpp.find_library('mbedcrypto', required: false) - # Test if we can compile the way we expect - code_ddvtech = ''' + ##This currently only works for MbedTLS < 3 + code_upstream = ''' #include - mbedtls_ssl_srtp_profile srtp_profiles[] ={MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80, - MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32}; - static int test() - { + static mbedtls_ssl_srtp_profile srtp_profiles[] ={MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_80, MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_32, MBEDTLS_TLS_SRTP_UNSET}; + static int test(){ mbedtls_ssl_config ssl_conf; - mbedtls_ssl_conf_dtls_srtp_protection_profiles(&ssl_conf, srtp_profiles, - sizeof(srtp_profiles) / sizeof(srtp_profiles[0])); + mbedtls_ssl_conf_dtls_srtp_protection_profiles(&ssl_conf, srtp_profiles); return 0; } ''' - ddvtech_mbedtls = ccpp.compiles(code_ddvtech, dependencies: [mbedtls, mbedx509, mbedcrypto], name: 'MbedTLS is DDVTech fork') - if not mbedtls.found() or not ddvtech_mbedtls - mbedtls_proj = subproject('mbedtls') - mbedtls = mbedtls_proj.get_variable('mbedtls_dep') - mbedx509 = mbedtls_proj.get_variable('mbedx509_dep') - mbedcrypto = mbedtls_proj.get_variable('mbedcrypto_dep') - endif + # Test if we can compile the way we expect + code_ddvtech = ''' + #include + mbedtls_ssl_srtp_profile srtp_profiles[]={MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80, MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32}; + static int test(){ + mbedtls_ssl_config ssl_conf; + mbedtls_ssl_conf_dtls_srtp_protection_profiles(&ssl_conf, srtp_profiles, sizeof(srtp_profiles) / sizeof(srtp_profiles[0])); + return 0; + } + ''' + + have_upstream_mbedtls_srtp = ccpp.compiles(code_upstream, dependencies: [mbedtls, mbedx509, mbedcrypto], name: 'MbedTLS SRTP is upstream') + option_defines += int_opt.format('HAVE_UPSTREAM_MBEDTLS_SRTP', have_upstream_mbedtls_srtp.to_int()) + if not have_upstream_mbedtls_srtp + ddvtech_mbedtls = ccpp.compiles(code_ddvtech, dependencies: [mbedtls, mbedx509, mbedcrypto], name: 'MbedTLS is DDVTech fork') + if not mbedtls.found() or not ddvtech_mbedtls + mbedtls_proj = subproject('mbedtls') + mbedtls = mbedtls_proj.get_variable('mbedtls_dep') + mbedx509 = mbedtls_proj.get_variable('mbedx509_dep') + mbedcrypto = mbedtls_proj.get_variable('mbedcrypto_dep') + endif + + endif mist_deps += [mbedtls, mbedx509, mbedcrypto] mist_deps += dependency('libsrtp2', default_options: ['tests=disabled'], fallback: ['libsrtp2', 'libsrtp2_dep']) diff --git a/src/output/output_https.cpp b/src/output/output_https.cpp index 6d10d0f0..2003e3c7 100644 --- a/src/output/output_https.cpp +++ b/src/output/output_https.cpp @@ -239,7 +239,11 @@ namespace Mist{ } // Read key from cmdline option +#if MBEDTLS_VERSION_MAJOR > 2 + ret = mbedtls_pk_parse_keyfile(&pkey, config->getString("key").c_str(), NULL, mbedtls_ctr_drbg_random, &ctr_drbg); +#else ret = mbedtls_pk_parse_keyfile(&pkey, config->getString("key").c_str(), 0); +#endif if (ret != 0){ FAIL_MSG("Could not load any keys from file: %s", config->getString("key").c_str()); return; diff --git a/src/output/output_https.h b/src/output/output_https.h index 386cd1f9..e3811216 100644 --- a/src/output/output_https.h +++ b/src/output/output_https.h @@ -1,9 +1,16 @@ #pragma once #include "output.h" +#include +#if MBEDTLS_VERSION_MAJOR == 2 #include +#endif #include #include +#if !HAVE_UPSTREAM_MBEDTLS_SRTP #include +#else +#include +#endif #include #include #include @@ -29,6 +36,7 @@ namespace Mist{ static mbedtls_ssl_config sslConf; static mbedtls_x509_crt srvcert; static mbedtls_pk_context pkey; + }; }// namespace Mist