Support for upstream mbedtls versions 2 and 3 when compiled with SRTP support

Co-authored-by: Thulinma <jaron@vietors.com>
This commit is contained in:
Gijs Peskens 2024-02-22 00:21:15 +01:00 committed by Thulinma
parent 3987cfec3f
commit ebe783666f
7 changed files with 147 additions and 18 deletions

View file

@ -7,12 +7,12 @@
Certificate::Certificate(){ Certificate::Certificate(){
mbedtls_pk_init(&key); mbedtls_pk_init(&key);
mbedtls_x509_crt_init(&cert); mbedtls_x509_crt_init(&cert);
mbedtls_ctr_drbg_init(&rand_ctx);
} }
int Certificate::init(const std::string &countryName, const std::string &organization, int Certificate::init(const std::string &countryName, const std::string &organization,
const std::string &commonName){ const std::string &commonName){
mbedtls_ctr_drbg_context rand_ctx ={};
mbedtls_entropy_context entropy_ctx ={}; mbedtls_entropy_context entropy_ctx ={};
mbedtls_x509write_cert write_cert ={}; mbedtls_x509write_cert write_cert ={};
mbedtls_rsa_context *rsa_ctx; mbedtls_rsa_context *rsa_ctx;
@ -49,7 +49,6 @@ int Certificate::init(const std::string &countryName, const std::string &organiz
} }
// initialize random number generator // initialize random number generator
mbedtls_ctr_drbg_init(&rand_ctx);
mbedtls_entropy_init(&entropy_ctx); mbedtls_entropy_init(&entropy_ctx);
r = mbedtls_ctr_drbg_seed(&rand_ctx, mbedtls_entropy_func, &entropy_ctx, r = mbedtls_ctr_drbg_seed(&rand_ctx, mbedtls_entropy_func, &entropy_ctx,
(const unsigned char *)personalisation, strlen(personalisation)); (const unsigned char *)personalisation, strlen(personalisation));
@ -205,6 +204,7 @@ error:
Certificate::~Certificate(){ Certificate::~Certificate(){
mbedtls_pk_free(&key); mbedtls_pk_free(&key);
mbedtls_x509_crt_free(&cert); mbedtls_x509_crt_free(&cert);
mbedtls_ctr_drbg_free(&rand_ctx);
} }
/// Loads a single file into the certificate. Returns true on success. /// 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. /// Loads a single key. Returns true on success.
bool Certificate::loadKey(const std::string & keyFile){ bool Certificate::loadKey(const std::string & keyFile){
if (!keyFile.size()){return true;} 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; return mbedtls_pk_parse_keyfile(&key, keyFile.c_str(), 0) == 0;
#endif
} }
/// Calculates SHA256 fingerprint over the loaded certificate(s) /// Calculates SHA256 fingerprint over the loaded certificate(s)

View file

@ -9,8 +9,12 @@
communication. This certificate uses a 2048 bits RSA key. communication. This certificate uses a 2048 bits RSA key.
*/ */
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_MAJOR > 2
#include <mbedtls/build_info.h>
#else
#include <mbedtls/config.h> #include <mbedtls/config.h>
#endif
#include <mbedtls/ctr_drbg.h> #include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h> #include <mbedtls/entropy.h>
#include <mbedtls/error.h> #include <mbedtls/error.h>
@ -32,4 +36,6 @@ public:
public: public:
mbedtls_x509_crt cert; mbedtls_x509_crt cert;
mbedtls_pk_context key; /* key context, stores private and public key. */ mbedtls_pk_context key; /* key context, stores private and public key. */
private:
mbedtls_ctr_drbg_context rand_ctx;
}; };

View file

@ -1663,6 +1663,23 @@ void Socket::UDPConnection::init(bool _nonblock, int _family){
#endif #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<Socket::UDPConnection *>(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){ void Socket::UDPConnection::initDTLS(mbedtls_x509_crt *cert, mbedtls_pk_context *key){
hasDTLS = true; hasDTLS = true;
nextDTLSRead = 0; nextDTLSRead = 0;
@ -1710,13 +1727,22 @@ void Socket::UDPConnection::initDTLS(mbedtls_x509_crt *cert, mbedtls_pk_context
//mbedtls_debug_set_threshold(10); //mbedtls_debug_set_threshold(10);
// enable SRTP support (non-fatal on error) // 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}; 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])); 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){ if (r){
mbedtls_strerror(r, mbedtls_msg, sizeof(mbedtls_msg)); mbedtls_strerror(r, mbedtls_msg, sizeof(mbedtls_msg));
WARN_MSG("dTLS could not set SRTP profiles: %s", 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 */ /* cert certificate chain + key, so we can verify the client-hello signed data */
r = mbedtls_ssl_conf_own_cert(&ssl_conf, cert, key); r = mbedtls_ssl_conf_own_cert(&ssl_conf, cert, key);
if (r){ if (r){
@ -1742,6 +1768,10 @@ void Socket::UDPConnection::initDTLS(mbedtls_x509_crt *cert, mbedtls_pk_context
return; return;
} }
#if MBEDTLS_VERSION_MAJOR > 2
mbedtls_ssl_set_export_keys_cb(&ssl_ctx, dtlsExtractKeyData, this);
#endif
// set input/output callbacks // set input/output callbacks
mbedtls_ssl_set_bio(&ssl_ctx, (void *)this, dTLS_send, dTLS_recv, NULL); 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); 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. /// Note: Only actually encrypts if initDTLS was called in the past.
void Socket::UDPConnection::sendPaced(const char *sdata, size_t len, bool encrypt){ void Socket::UDPConnection::sendPaced(const char *sdata, size_t len, bool encrypt){
if (hasDTLS && 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){ if (ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER){
#endif
WARN_MSG("Attempting to write encrypted data before handshake completed! Data was thrown away."); WARN_MSG("Attempting to write encrypted data before handshake completed! Data was thrown away.");
return; return;
} }
@ -2622,12 +2656,18 @@ bool Socket::UDPConnection::onData(){
nextDTLSRead = data; nextDTLSRead = data;
nextDTLSReadLen = data.size(); nextDTLSReadLen = data.size();
// Complete dTLS handshake if needed // 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){ if (ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER){
#endif
do{ do{
r = mbedtls_ssl_handshake(&ssl_ctx); r = mbedtls_ssl_handshake(&ssl_ctx);
switch (r){ switch (r){
case 0:{ // Handshake complete case 0:{ // Handshake complete
INFO_MSG("dTLS handshake complete!"); INFO_MSG("dTLS handshake complete!");
#if !HAVE_UPSTREAM_MBEDTLS_SRTP
int extrRes = 0; int extrRes = 0;
uint8_t keying_material[MBEDTLS_DTLS_SRTP_MAX_KEY_MATERIAL_LENGTH]; uint8_t keying_material[MBEDTLS_DTLS_SRTP_MAX_KEY_MATERIAL_LENGTH];
size_t keying_material_len = sizeof(keying_material); size_t keying_material_len = sizeof(keying_material);
@ -2654,6 +2694,40 @@ bool Socket::UDPConnection::onData(){
return Receive(); 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); remote_key.assign((char *)(&keying_material[0]) + 0, 16);
local_key.assign((char *)(&keying_material[0]) + 16, 16); local_key.assign((char *)(&keying_material[0]) + 16, 16);
remote_salt.assign((char *)(&keying_material[0]) + 32, 14); remote_salt.assign((char *)(&keying_material[0]) + 32, 14);

View file

@ -22,10 +22,25 @@
#include <mbedtls/debug.h> #include <mbedtls/debug.h>
#include <mbedtls/entropy.h> #include <mbedtls/entropy.h>
#include <mbedtls/error.h> #include <mbedtls/error.h>
#if !HAVE_UPSTREAM_MBEDTLS_SRTP
#include <mbedtls/net.h> #include <mbedtls/net.h>
#else
#include <mbedtls/net_sockets.h>
#endif
#include <mbedtls/ssl.h> #include <mbedtls/ssl.h>
#include <mbedtls/ssl_cookie.h> #include <mbedtls/ssl_cookie.h>
#include <mbedtls/timing.h> #include <mbedtls/timing.h>
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_MAJOR == 2
#include <mbedtls/certs.h>
#include <mbedtls/config.h>
#else
#include <mbedtls/build_info.h>
#endif
#endif #endif
#include "util.h" #include "util.h"
@ -270,5 +285,10 @@ namespace Socket{
// dTLS-related public members // dTLS-related public members
std::string cipher, remote_key, local_key, remote_salt, local_salt; 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 }// namespace Socket

View file

@ -106,27 +106,40 @@ if usessl
mbedx509 = ccpp.find_library('mbedx509', required: false) mbedx509 = ccpp.find_library('mbedx509', required: false)
mbedcrypto = ccpp.find_library('mbedcrypto', required: false) mbedcrypto = ccpp.find_library('mbedcrypto', required: false)
# Test if we can compile the way we expect ##This currently only works for MbedTLS < 3
code_ddvtech = ''' code_upstream = '''
#include <mbedtls/ssl.h> #include <mbedtls/ssl.h>
mbedtls_ssl_srtp_profile srtp_profiles[] ={MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80, 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};
MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32}; static int test(){
static int test()
{
mbedtls_ssl_config ssl_conf; mbedtls_ssl_config ssl_conf;
mbedtls_ssl_conf_dtls_srtp_protection_profiles(&ssl_conf, srtp_profiles, mbedtls_ssl_conf_dtls_srtp_protection_profiles(&ssl_conf, srtp_profiles);
sizeof(srtp_profiles) / sizeof(srtp_profiles[0]));
return 0; 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.h>
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 += [mbedtls, mbedx509, mbedcrypto]
mist_deps += dependency('libsrtp2', default_options: ['tests=disabled'], fallback: ['libsrtp2', 'libsrtp2_dep']) mist_deps += dependency('libsrtp2', default_options: ['tests=disabled'], fallback: ['libsrtp2', 'libsrtp2_dep'])

View file

@ -239,7 +239,11 @@ namespace Mist{
} }
// Read key from cmdline option // 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); ret = mbedtls_pk_parse_keyfile(&pkey, config->getString("key").c_str(), 0);
#endif
if (ret != 0){ if (ret != 0){
FAIL_MSG("Could not load any keys from file: %s", config->getString("key").c_str()); FAIL_MSG("Could not load any keys from file: %s", config->getString("key").c_str());
return; return;

View file

@ -1,9 +1,16 @@
#pragma once #pragma once
#include "output.h" #include "output.h"
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_MAJOR == 2
#include <mbedtls/certs.h> #include <mbedtls/certs.h>
#endif
#include <mbedtls/ctr_drbg.h> #include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h> #include <mbedtls/entropy.h>
#if !HAVE_UPSTREAM_MBEDTLS_SRTP
#include <mbedtls/net.h> #include <mbedtls/net.h>
#else
#include <mbedtls/net_sockets.h>
#endif
#include <mbedtls/ssl.h> #include <mbedtls/ssl.h>
#include <mbedtls/timing.h> #include <mbedtls/timing.h>
#include <mbedtls/x509.h> #include <mbedtls/x509.h>
@ -29,6 +36,7 @@ namespace Mist{
static mbedtls_ssl_config sslConf; static mbedtls_ssl_config sslConf;
static mbedtls_x509_crt srvcert; static mbedtls_x509_crt srvcert;
static mbedtls_pk_context pkey; static mbedtls_pk_context pkey;
}; };
}// namespace Mist }// namespace Mist