@ -3,7 +3,7 @@
*
* TLS API for TCP / IP protocol stacks
*
* Copyright 2017 - 202 2 Michael Zillgith
* Copyright 2017 - 202 4 Michael Zillgith
*
* Implementation of the TLS abstraction layer for mbedtls
*
@ -38,9 +38,9 @@
# endif
# if (CONFIG_DEBUG_TLS == 1)
# define DEBUG_PRINT(appId, fmt, ...) fprintf(stderr, "%s: " fmt, appId, ## __VA_ARGS__) ;
# define DEBUG_PRINT(appId, fmt, ...) fprintf(stderr, "%s: " fmt, appId, ## __VA_ARGS__)
# else
# define DEBUG_PRINT(fmt, ...) { do {} while(0);}
# define DEBUG_PRINT(fmt, ...) do {} while(0)
# endif
static int psaInitCounter = 0 ;
@ -90,6 +90,9 @@ struct sTLSConfiguration {
bool useSessionResumption ;
int sessionResumptionInterval ; /* session resumption interval in seconds */
int * ciphersuites ;
int maxCiphersuites ;
} ;
struct sTLSSocket {
@ -144,28 +147,32 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth
DEBUG_PRINT ( " TLS " , " %s \n " , buffer ) ;
if ( self - > tlsConfig - > chainValidation = = false ) {
if ( self - > tlsConfig - > chainValidation = = false )
{
if ( certificate_depth ! = 0 )
* flags = 0 ;
}
if ( certificate_depth = = 0 ) {
if ( self - > tlsConfig - > allowOnlyKnownCertificates ) {
if ( certificate_depth = = 0 )
{
if ( self - > tlsConfig - > allowOnlyKnownCertificates )
{
DEBUG_PRINT ( " TLS " , " Check against list of allowed certs \n " ) ;
bool certMatches = false ;
LinkedList certList = LinkedList_getNext ( self - > tlsConfig - > allowedCertificates ) ;
while ( certList ) {
while ( certList )
{
mbedtls_x509_crt * allowedCert = ( mbedtls_x509_crt * ) LinkedList_getData ( certList ) ;
DEBUG_PRINT ( " TLS " , " Compare With: \n " ) ;
mbedtls_x509_crt_info ( buffer , 1023 , " " , allowedCert ) ;
DEBUG_PRINT ( " TLS " , " %s \n " , buffer ) ;
if ( compareCertificates ( allowedCert , crt ) ) {
if ( compareCertificates ( allowedCert , crt ) )
{
certMatches = true ;
break ;
}
@ -175,7 +182,8 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth
if ( certMatches )
* flags = 0 ;
else {
else
{
raiseSecurityEvent ( self - > tlsConfig , TLS_SEC_EVT_INCIDENT , TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED , " Alarm: certificate validation: trusted individual certificate not available " , self ) ;
* flags | = MBEDTLS_X509_BADCERT_OTHER ;
@ -183,20 +191,19 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth
}
}
if ( self - > storePeerCert ) {
if ( * flags = = 0 ) {
if ( self - > storePeerCert )
{
if ( * flags = = 0 )
{
self - > peerCertLength = 0 ;
self - > peerCert = ( uint8_t * ) GLOBAL_MALLOC ( crt - > raw . len ) ;
if ( self - > peerCert ) {
if ( self - > peerCert )
{
self - > peerCertLength = ( int ) crt - > raw . len ;
memcpy ( self - > peerCert , crt - > raw . p , self - > peerCertLength ) ;
}
}
}
}
@ -209,10 +216,12 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth
static bool
TLSConfiguration_setupComplete ( TLSConfiguration self )
{
if ( self - > setupComplete = = false ) {
if ( self - > setupComplete = = false )
{
mbedtls_ssl_conf_ca_chain ( & ( self - > conf ) , & ( self - > cacerts ) , & ( self - > crl ) ) ;
if ( self - > ownCertificate . version > 0 ) {
if ( self - > ownCertificate . version > 0 )
{
int ret = mbedtls_ssl_conf_own_cert ( & ( self - > conf ) , & ( self - > ownCertificate ) , & ( self - > ownKey ) ) ;
if ( ret ! = 0 ) {
@ -221,11 +230,13 @@ TLSConfiguration_setupComplete(TLSConfiguration self)
}
}
if ( self - > useSessionResumption ) {
if ( self - > useSessionResumption )
{
if ( mbedtls_ssl_conf_get_endpoint ( & ( self - > conf ) ) = = MBEDTLS_SSL_IS_CLIENT ) {
}
else {
else
{
mbedtls_ssl_cache_init ( & ( self - > cache ) ) ;
// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#most-structure-fields-are-now-private
@ -237,18 +248,70 @@ TLSConfiguration_setupComplete(TLSConfiguration self)
}
}
mbedtls_ssl_conf_ciphersuites ( & ( self - > conf ) , self - > ciphersuites ) ;
self - > setupComplete = true ;
}
return true ;
}
void
TLSConfiguration_addCipherSuite ( TLSConfiguration self , int ciphersuite )
{
/* search last index */
int nextIndex = 0 ;
int i ;
for ( i = 0 ; i < self - > maxCiphersuites ; i + + )
{
if ( self - > ciphersuites [ i ] = = 0 )
{
nextIndex = i ;
break ;
}
}
if ( nextIndex = = self - > maxCiphersuites )
{
/* reallocate space for ciphersuites list */
int newMaxCiphersuites = self - > maxCiphersuites + 10 ;
int * newCiphersuites = ( int * ) GLOBAL_CALLOC ( newMaxCiphersuites , sizeof ( int ) ) ;
if ( newCiphersuites )
{
for ( i = 0 ; i < self - > maxCiphersuites ; i + + )
{
newCiphersuites [ i ] = self - > ciphersuites [ i ] ;
}
GLOBAL_FREEMEM ( self - > ciphersuites ) ;
self - > ciphersuites = newCiphersuites ;
self - > maxCiphersuites = newMaxCiphersuites ;
TLSConfiguration_addCipherSuite ( self , ciphersuite ) ;
}
}
else
{
self - > ciphersuites [ nextIndex ] = ciphersuite ;
self - > ciphersuites [ nextIndex + 1 ] = 0 ;
}
}
void
TLSConfiguration_clearCipherSuiteList ( TLSConfiguration self )
{
self - > ciphersuites [ 0 ] = 0 ;
}
TLSConfiguration
TLSConfiguration_create ( )
{
TLSConfiguration self = ( TLSConfiguration ) GLOBAL_CALLOC ( 1 , sizeof ( struct sTLSConfiguration ) ) ;
if ( self ! = NULL )
if ( self )
{
/* call to psa_crypto_init required -> see https://github.com/Mbed-TLS/mbedtls/issues/9223 */
psa_status_t psaStatus = psa_crypto_init ( ) ;
@ -276,9 +339,6 @@ TLSConfiguration_create()
mbedtls_ssl_conf_renegotiation ( & ( self - > conf ) , MBEDTLS_SSL_RENEGOTIATION_ENABLED ) ;
/* static int hashes[] = {3,4,5,6,7,8,0}; */
/* mbedtls_ssl_conf_sig_hashes(&(self->conf), hashes); */
self - > minVersion = TLS_VERSION_TLS_1_2 ;
self - > maxVersion = TLS_VERSION_NOT_SELECTED ;
@ -298,6 +358,31 @@ TLSConfiguration_create()
self - > sessionResumptionInterval = 21600 ; /* default value: 6h */
self - > savedSession = NULL ;
self - > savedSessionTime = 0 ;
self - > ciphersuites = ( int * ) GLOBAL_CALLOC ( 20 , sizeof ( int ) ) ;
if ( self - > ciphersuites )
{
self - > maxCiphersuites = 20 ;
/* mandatory cipher suites by IEC 62351-4:2018 */
self - > ciphersuites [ 0 ] = MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 ;
/* self->ciphersuites[1] = MBEDTLS_TLS_DH_RSA_WITH_AES_128_GCM_SHA256; */ /* weak - not supported? */
self - > ciphersuites [ 1 ] = MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ;
self - > ciphersuites [ 2 ] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ;
/* recommended cipher suites by IEC 62351-4:2018 */
/* self->ciphersuites[1] = MBEDTLS_TLS_DH_RSA_WITH_AES_128_CBC_SHA256; */ /* weak - not supported?*/
/* self->ciphersuites[1] = MBEDTLS_TLS_DH_RSA_WITH_AES_256_GCM_SHA384; */ /* not supported?*/
self - > ciphersuites [ 3 ] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ;
self - > ciphersuites [ 4 ] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ;
self - > ciphersuites [ 5 ] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 ;
/* additional ciphersuites */
self - > ciphersuites [ 6 ] = MBEDTLS_TLS_RSA_WITH_NULL_SHA256 ;
self - > ciphersuites [ 7 ] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 ;
}
}
return self ;
@ -407,11 +492,13 @@ TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certifica
int ret = mbedtls_x509_crt_parse ( cert , certificate , certLen ) ;
if ( ret = = 0 ) {
if ( ret = = 0 )
{
LinkedList_add ( self - > allowedCertificates , cert ) ;
return true ;
}
else {
else
{
GLOBAL_FREEMEM ( cert ) ;
return false ;
}
@ -424,11 +511,13 @@ TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self, const char
int ret = mbedtls_x509_crt_parse_file ( cert , filename ) ;
if ( ret = = 0 ) {
if ( ret = = 0 )
{
LinkedList_add ( self - > allowedCertificates , cert ) ;
return true ;
}
else {
else
{
GLOBAL_FREEMEM ( cert ) ;
return false ;
}
@ -439,7 +528,8 @@ TLSConfiguration_addCACertificate(TLSConfiguration self, uint8_t* certificate, i
{
int ret = mbedtls_x509_crt_parse ( & ( self - > cacerts ) , certificate , certLen ) ;
if ( ret ! = 0 ) {
if ( ret ! = 0 )
{
DEBUG_PRINT ( " TLS " , " mbedtls_x509_crt_parse returned -0x%x \n " , - ret ) ;
return false ;
}
@ -469,14 +559,6 @@ udpatedCRL(TLSConfiguration self)
if ( mbedtls_ssl_conf_get_endpoint ( & ( self - > conf ) ) = = MBEDTLS_SSL_IS_SERVER )
{
// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#most-structure-fields-are-now-private
// mbedtls_ssl_cache_entry *cur = self->cache.chain;
// while (cur) {
// cur->timestamp = 0;
// cur = cur->next;
// }
// TODO: @Michael: Confirm if this is a valid replacement for the above code
mbedtls_ssl_cache_free ( & ( self - > cache ) ) ;
}
}
@ -528,14 +610,18 @@ TLSConfiguration_setRenegotiationTime(TLSConfiguration self, int timeInMs)
void
TLSConfiguration_destroy ( TLSConfiguration self )
{
if ( self - > useSessionResumption ) {
if ( mbedtls_ssl_conf_get_endpoint ( & ( self - > conf ) ) = = MBEDTLS_SSL_IS_CLIENT ) {
if ( self - > savedSession ) {
if ( self - > useSessionResumption )
{
if ( mbedtls_ssl_conf_get_endpoint ( & ( self - > conf ) ) = = MBEDTLS_SSL_IS_CLIENT )
{
if ( self - > savedSession )
{
mbedtls_ssl_session_free ( self - > savedSession ) ;
GLOBAL_FREEMEM ( self - > savedSession ) ;
}
}
else {
else
{
mbedtls_ssl_cache_free ( & ( self - > cache ) ) ;
}
}
@ -550,7 +636,8 @@ TLSConfiguration_destroy(TLSConfiguration self)
LinkedList certElem = LinkedList_getNext ( self - > allowedCertificates ) ;
while ( certElem ) {
while ( certElem )
{
mbedtls_x509_crt * cert = ( mbedtls_x509_crt * ) LinkedList_getData ( certElem ) ;
mbedtls_x509_crt_free ( cert ) ;
@ -688,7 +775,8 @@ readFunction(void* ctx, unsigned char* buf, size_t len)
{
int ret = Socket_read ( ( Socket ) ctx , buf , ( int ) len ) ;
if ( ( ret = = 0 ) & & ( len > 0 ) ) {
if ( ( ret = = 0 ) & & ( len > 0 ) )
{
return MBEDTLS_ERR_SSL_WANT_READ ;
}
@ -698,7 +786,14 @@ readFunction(void* ctx, unsigned char* buf, size_t len)
static int
writeFunction ( void * ctx , unsigned char * buf , size_t len )
{
return Socket_write ( ( Socket ) ctx , buf , ( int ) len ) ;
int ret = Socket_write ( ( Socket ) ctx , buf , ( int ) len ) ;
if ( ( ret = = 0 ) & & ( len > 0 ) )
{
return MBEDTLS_ERR_SSL_WANT_WRITE ;
}
return ret ;
}
static TLSConfigVersion
@ -707,7 +802,8 @@ getTLSVersion(int majorVersion, int minorVersion)
if ( majorVersion ! = 3 ) {
return TLS_VERSION_NOT_SELECTED ;
}
else {
else
{
switch ( minorVersion ) {
/* TODO: Remove from here (MIGRATE 2.28->3.x.x) */
case 0 :
@ -794,7 +890,8 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
self - > crlUpdated = configuration - > crlUpdated ;
if ( configuration - > minVersion ! = TLS_VERSION_NOT_SELECTED ) {
if ( configuration - > minVersion ! = TLS_VERSION_NOT_SELECTED )
{
/* set minimum TLS version */
int majorVer = getMajorVersion ( configuration - > minVersion ) ;
@ -803,7 +900,8 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
mbedtls_ssl_conf_min_version ( & ( self - > conf ) , majorVer , minorVer ) ;
}
if ( configuration - > maxVersion ! = TLS_VERSION_NOT_SELECTED ) {
if ( configuration - > maxVersion ! = TLS_VERSION_NOT_SELECTED )
{
/* set maximum TLS version */
int majorVer = getMajorVersion ( configuration - > maxVersion ) ;
@ -812,7 +910,8 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
mbedtls_ssl_conf_max_version ( & ( self - > conf ) , majorVer , minorVer ) ;
}
if ( configuration - > ownCertificate . version > 0 ) {
if ( configuration - > ownCertificate . version > 0 )
{
ret = mbedtls_ssl_conf_own_cert ( & ( self - > conf ) , & ( configuration - > ownCertificate ) , & ( configuration - > ownKey ) ) ;
if ( ret ! = 0 )
@ -827,30 +926,31 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
mbedtls_ssl_set_bio ( & ( self - > ssl ) , socket , ( mbedtls_ssl_send_t * ) writeFunction ,
( mbedtls_ssl_recv_t * ) readFunction , NULL ) ;
bool reuseSession = false ;
if ( configuration - > useSessionResumption ) {
if ( mbedtls_ssl_conf_get_endpoint ( & ( configuration - > conf ) ) = = MBEDTLS_SSL_IS_CLIENT ) {
if ( configuration - > savedSession & & configuration - > savedSessionTime > 0 ) {
if ( Hal_getTimeInMs ( ) < ( configuration - > savedSessionTime + configuration - > sessionResumptionInterval * 1000 ) ) {
if ( configuration - > useSessionResumption )
{
if ( mbedtls_ssl_conf_get_endpoint ( & ( configuration - > conf ) ) = = MBEDTLS_SSL_IS_CLIENT )
{
if ( configuration - > savedSession & & configuration - > savedSessionTime > 0 )
{
if ( Hal_getTimeInMs ( ) < ( configuration - > savedSessionTime + configuration - > sessionResumptionInterval * 1000 ) )
{
ret = mbedtls_ssl_set_session ( & ( self - > ssl ) , configuration - > savedSession ) ;
if ( ret ! = 0 ) {
if ( ret ! = 0 )
{
DEBUG_PRINT ( " TLS " , " mbedtls_ssl_set_session returned %d \n " , ret ) ;
configuration - > savedSessionTime = 0 ;
}
else {
else
{
DEBUG_PRINT ( " TLS " , " resume TLS session \n " ) ;
reuseSession = true ;
}
}
else {
else
{
configuration - > savedSessionTime = 0 ;
DEBUG_PRINT ( " TLS " , " cached session expired \n " ) ;
}
}
}
}
@ -877,22 +977,27 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
}
}
if ( configuration - > useSessionResumption ) {
if ( mbedtls_ssl_conf_get_endpoint ( & ( configuration - > conf ) ) = = MBEDTLS_SSL_IS_CLIENT ) {
if ( configuration - > savedSession = = NULL ) {
if ( configuration - > useSessionResumption )
{
if ( mbedtls_ssl_conf_get_endpoint ( & ( configuration - > conf ) ) = = MBEDTLS_SSL_IS_CLIENT )
{
if ( configuration - > savedSession = = NULL )
{
configuration - > savedSession = ( mbedtls_ssl_session * ) GLOBAL_CALLOC ( 1 , sizeof ( mbedtls_ssl_session ) ) ;
}
if ( configuration - > savedSession ) {
if ( configuration - > savedSessionTime = = 0 ) {
if ( configuration - > savedSession )
{
if ( configuration - > savedSessionTime = = 0 )
{
ret = mbedtls_ssl_get_session ( & ( self - > ssl ) , configuration - > savedSession ) ;
if ( ret ! = 0 ) {
if ( ret ! = 0 )
{
DEBUG_PRINT ( " TLS " , " mbedtls_ssl_get_session returned %d \n " , ret ) ;
}
else {
else
{
configuration - > savedSessionTime = Hal_getTimeInMs ( ) ;
}
}
@ -907,6 +1012,16 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
// raiseSecurityEvent(configuration, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_INSECURE_TLS_VERSION, "Warning: Insecure TLS version", self);
// }
/* create event that TLS session is established */
{
char msg [ 256 ] ;
const char * cipherSuite = mbedtls_ssl_get_ciphersuite ( & ( self - > ssl ) ) ;
snprintf ( msg , 255 , " Info: Session established with cipher suite %s " , cipherSuite ) ;
raiseSecurityEvent ( configuration , TLS_SEC_EVT_INFO , TLS_EVENT_CODE_INF_SESSION_ESTABLISHED , msg , self ) ;
}
}
return self ;
@ -927,7 +1042,8 @@ TLSSocket_performHandshake(TLSSocket self)
int ret = mbedtls_ssl_renegotiate ( & ( self - > ssl ) ) ;
if ( ret = = 0 | | ret = = MBEDTLS_ERR_SSL_WANT_READ | | ret = = MBEDTLS_ERR_SSL_WANT_WRITE | |
ret = = MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS | | ret = = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ) {
ret = = MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS | | ret = = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS )
{
// MIGRATE 2.28->3.x.x: impossible since mbedtls 3.x.x doesn't support insecure TLS versions
// if (getTLSVersion(self->ssl.major_ver, self->ssl.minor_ver) < TLS_VERSION_TLS_1_2) {
// raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_INSECURE_TLS_VERSION, "Warning: Insecure TLS version", self);
@ -940,6 +1056,7 @@ TLSSocket_performHandshake(TLSSocket self)
raiseSecurityEvent ( self - > tlsConfig , TLS_SEC_EVT_INFO , TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION , " Alarm: Renegotiation failed " , self ) ;
/* mbedtls_ssl_renegotiate mandates to reset the ssl session in case of errors */
ret = mbedtls_ssl_session_reset ( & ( self - > ssl ) ) ;
if ( ret ! = 0 ) {
DEBUG_PRINT ( " TLS " , " mbedtls_ssl_session_reset failed -> ret: -0x%X \n " , - ret ) ;
@ -977,7 +1094,8 @@ startRenegotiationIfRequired(TLSSocket self)
raiseSecurityEvent ( self - > tlsConfig , TLS_SEC_EVT_INFO , TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION , " Info: session renegotiation started " , self ) ;
if ( TLSSocket_performHandshake ( self ) = = false ) {
if ( TLSSocket_performHandshake ( self ) = = false )
{
DEBUG_PRINT ( " TLS " , " renegotiation failed \n " ) ;
return false ;
}
@ -1033,8 +1151,7 @@ TLSSocket_read(TLSSocket self, uint8_t* buf, int size)
int
TLSSocket_write ( TLSSocket self , uint8_t * buf , int size )
{
int ret ;
int len = size ;
int len = 0 ;
checkForCRLUpdate ( self ) ;
@ -1042,22 +1159,26 @@ TLSSocket_write(TLSSocket self, uint8_t* buf, int size)
return - 1 ;
}
while ( ( ret = mbedtls_ssl_write ( & ( self - > ssl ) , buf , len ) ) < = 0 )
while ( len < size )
{
if ( ret = = MBEDTLS_ERR_NET_CONN_RESET )
{
DEBUG_PRINT ( " TLS " , " peer closed the connection \n " ) ;
return - 1 ;
int ret = mbedtls_ssl_write ( & ( self - > ssl ) , ( buf + len ) , ( size - len ) ) ;
if ( ( ret = = MBEDTLS_ERR_SSL_WANT_READ ) | | ( ret = = MBEDTLS_ERR_SSL_WANT_WRITE ) | |
( ret = = MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) | | ( ret = = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ) ) {
continue ;
}
if ( ( ret ! = MBEDTLS_ERR_SSL_WANT_READ ) & & ( ret ! = MBEDTLS_ERR_SSL_WANT_WRITE ) )
{
DEBUG_PRINT ( " TLS " , " mbedtls_ssl_write returned %d \n " , ret ) ;
if ( ret < 0 ) {
DEBUG_PRINT ( " TLS " , " mbedtls_ssl_write returned -0x%X \n " , - ret ) ;
if ( 0 ! = ( ret = mbedtls_ssl_session_reset ( & ( self - > ssl ) ) ) ) {
DEBUG_PRINT ( " TLS " , " mbedtls_ssl_session_reset failed -0x%X \n " , - ret ) ;
}
return - 1 ;
}
}
len = ret ;
len + = ret ;
}
return len ;
}