From 6830e85d8c4c9395e42424ddbc6fa4e08d4a6d39 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 19 Jul 2024 19:04:05 +0100 Subject: [PATCH] - added code and cmake build system support for mbedtls 3.6 --- CMakeLists.txt | 9 +- hal/CMakeLists.txt | 35 +- hal/tls/mbedtls3/mbedtls_config.h | 72 ++ hal/tls/mbedtls3/tls_mbedtls.c | 1152 +++++++++++++++++++++++++++++ src/CMakeLists.txt | 9 +- 5 files changed, 1272 insertions(+), 5 deletions(-) create mode 100644 hal/tls/mbedtls3/mbedtls_config.h create mode 100644 hal/tls/mbedtls3/tls_mbedtls.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ba9aa90e..e9542e73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,12 +144,17 @@ set(FOUND_SQLITE3_SOURCE 1) message("Found sqlite3 source in third_party folder -> can compile with log service support") endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/sqlite/sqlite3.h) +if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0) +set(WITH_MBEDTLS3 1) +set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0/include") +else() if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28) set(WITH_MBEDTLS 1) set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/include") endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28) +endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0) -if(WITH_MBEDTLS) +if(WITH_MBEDTLS OR WITH_MBEDTLS3) add_definitions(-DCONFIG_MMS_SUPPORT_TLS=1) @@ -165,7 +170,7 @@ if (CONFIG_IEC61850_SNTP_CLIENT) set(BUILD_SNTP_CLIENT_EXAMPLES 1) endif (CONFIG_IEC61850_SNTP_CLIENT) -endif(WITH_MBEDTLS) +endif(WITH_MBEDTLS OR WITH_MBEDTLS3) include(CheckCCompilerFlag) diff --git a/hal/CMakeLists.txt b/hal/CMakeLists.txt index 2ef87d31..834b951d 100644 --- a/hal/CMakeLists.txt +++ b/hal/CMakeLists.txt @@ -10,7 +10,7 @@ endif() project(hal) set(LIBHAL_VERSION_MAJOR "2") -set(LIBHAL_VERSION_MINOR "1") +set(LIBHAL_VERSION_MINOR "2") set(LIBHAL_VERSION_PATCH "0") # feature checks @@ -116,10 +116,15 @@ ENDIF(WIN32) #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC" ) if(WITH_MBEDTLS) -message("Found mbedtls -> can compile HAL with TLS support") +message("Found mbedtls 2.28 -> can compile HAL with TLS 1.2 support") set(WITH_MBEDTLS 1) endif(WITH_MBEDTLS) +if (WITH_MBEDTLS3) +message("Found mbedtls 3.6 -> can compile HAL with TLS 1.3 support") +set(WITH_MBEDTLS3 1) +endif(WITH_MBEDTLS3) + if(WITH_MBEDTLS) include_directories( ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls @@ -147,6 +152,32 @@ list (APPEND libhal_SRCS ${tls_SRCS}) endif(WITH_MBEDTLS) +if(WITH_MBEDTLS3) +include_directories( + ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls3 + ${MBEDTLS_INCLUDE_DIR} +) + +if(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB) +link_directories(${CONFIG_EXTERNAL_MBEDTLS_DYNLIB_PATH}) +else() +file(GLOB tls_SRCS ${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-3.6.0/library/*.c) +endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB) + +add_definitions(-DMBEDTLS_CONFIG_FILE="mbedtls_config.h") + +set (libhal_SRCS ${libhal_SRCS} + ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls3/tls_mbedtls.c +) + +IF(MSVC) +set_source_files_properties(${libhal_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF() + +list (APPEND libhal_SRCS ${tls_SRCS}) +endif(WITH_MBEDTLS3) + add_library (hal STATIC ${libhal_SRCS}) add_library (hal-shared STATIC ${libhal_SRCS}) diff --git a/hal/tls/mbedtls3/mbedtls_config.h b/hal/tls/mbedtls3/mbedtls_config.h new file mode 100644 index 00000000..68168f77 --- /dev/null +++ b/hal/tls/mbedtls3/mbedtls_config.h @@ -0,0 +1,72 @@ +// https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#introduce-a-level-of-indirection-and-versioning-in-the-config-files +// #ifndef MBEDTLS_CONFIG_H +// #define MBEDTLS_CONFIG_H + +/* System support */ +#define MBEDTLS_HAVE_ASM +#define MBEDTLS_HAVE_TIME +#define MBEDTLS_HAVE_TIME_DATE +#define MBEDTLS_NO_UDBL_DIVISION +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_DEBUG_C + +/* mbed TLS feature support */ +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_PROTO_TLS1_3 +// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#remove-support-for-tls-10-11-and-dtls-10 +// #define MBEDTLS_SSL_PROTO_TLS1_1 +// #define MBEDTLS_SSL_PROTO_TLS1 +#define MBEDTLS_SSL_RENEGOTIATION + +#error "MBEDTLS" + +#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES + +/* mbed TLS modules */ +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +/* #define MBEDTLS_DES_C */ +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_MD_C +#define MBEDTLS_MD5_C +#define MBEDTLS_NET_C +#define MBEDTLS_OID_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_CRL_PARSE_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_SSL_CACHE_C + +/* For test certificates */ +#define MBEDTLS_BASE64_C +#define MBEDTLS_CERTS_C +#define MBEDTLS_PEM_PARSE_C + +#define MBEDTLS_PKCS12_C +#define MBEDTLS_PKCS5_C + +/* For testing with compat.sh */ +#define MBEDTLS_FS_IO + +// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#remove-mbedtls_x509_check__key_usage-options-from-mbedtls_configh +// #define MBEDTLS_X509_CHECK_KEY_USAGE +// #define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#introduce-a-level-of-indirection-and-versioning-in-the-config-files +// #include "mbedtls/check_config.h" + +// #endif /* MBEDTLS_CONFIG_H */ diff --git a/hal/tls/mbedtls3/tls_mbedtls.c b/hal/tls/mbedtls3/tls_mbedtls.c new file mode 100644 index 00000000..8db5dacb --- /dev/null +++ b/hal/tls/mbedtls3/tls_mbedtls.c @@ -0,0 +1,1152 @@ +/* + * tls_mbedtls.c + * + * TLS API for TCP/IP protocol stacks + * + * Copyright 2017-2022 Michael Zillgith + * + * Implementation of the TLS abstraction layer for mbedtls + * + */ + +#include + +#include "tls_socket.h" +#include "hal_thread.h" +#include "lib_memory.h" +#include "hal_time.h" +#include "linked_list.h" + +#include "mbedtls/platform.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#remove-the-certs-module-from-the-library +// #include "mbedtls/certs.h" (MIGRATE 2.28->3.x.x) +#include "mbedtls/x509.h" +#include "mbedtls/ssl.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/error.h" +#include "mbedtls/debug.h" +#include "mbedtls/ssl_cache.h" + +#define SEC_EVENT_ALARM 2 +#define SEC_EVENT_WARNING 1 +#define SEC_EVENT_INFO 0 + +#ifndef CONFIG_DEBUG_TLS +#define CONFIG_DEBUG_TLS 1 +#endif + +#if (CONFIG_DEBUG_TLS == 1) +#define DEBUG_PRINT(appId, fmt, ...) fprintf(stderr, "%s: " fmt, appId, ## __VA_ARGS__); +#else +#define DEBUG_PRINT(fmt, ...) {do {} while(0);} +#endif + +static int psaInitCounter = 0; + +struct sTLSConfiguration { + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + + mbedtls_x509_crt ownCertificate; + mbedtls_pk_context ownKey; + + mbedtls_x509_crt cacerts; + + mbedtls_x509_crl crl; + + mbedtls_ssl_config conf; + LinkedList /* */ allowedCertificates; + + /* session cache for server */ + mbedtls_ssl_cache_context cache; + + /* client side cached session */ + mbedtls_ssl_session* savedSession; + uint64_t savedSessionTime; + + bool chainValidation; + bool allowOnlyKnownCertificates; + + /* TLS session renegotiation interval in milliseconds */ + int renegotiationTimeInMs; + + // MIGRATE 2.28->3.x.x: Changed min version to 1.2 to reflect the removal of 1.1 and 1.0 + /* TLS minimum version allowed (default: TLS_VERSION_TLS_1_2) */ + TLSConfigVersion minVersion; + + // MIGRATE 2.28->3.x.x: Kept the max version but changed documentation + /* TLS maximum version allowed (default: TLS_VERSION_NOT_SELECTED) */ + TLSConfigVersion maxVersion; + + TLSConfiguration_EventHandler eventHandler; + void* eventHandlerParameter; + + /* time of the last CRL update */ + uint64_t crlUpdated; + + bool setupComplete; + + bool useSessionResumption; + int sessionResumptionInterval; /* session resumption interval in seconds */ +}; + +struct sTLSSocket { + mbedtls_ssl_context ssl; + Socket socket; + mbedtls_ssl_config conf; + TLSConfiguration tlsConfig; + bool storePeerCert; + uint8_t* peerCert; + int peerCertLength; + + /* time of last session renegotiation (used to calculate next renegotiation time) */ + uint64_t lastRenegotiationTime; + + /* time of the last CRL update */ + uint64_t crlUpdated; +}; + +static void +raiseSecurityEvent(TLSConfiguration config, TLSEventLevel eventCategory, int eventCode, const char* message, TLSSocket socket) +{ + if (config->eventHandler) { + config->eventHandler(config->eventHandlerParameter, eventCategory, eventCode, message, (TLSConnection)socket); + } +} + +static bool +compareCertificates(mbedtls_x509_crt *crt1, mbedtls_x509_crt *crt2) +{ + // 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 + if (crt1 != NULL && crt2 != NULL && + crt1->raw.len == crt2->raw.len && + memcmp(crt1->raw.p, crt2->raw.p, crt1->raw.len) == 0) { + return true; + } + + return false; +} + +static int +verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth, uint32_t *flags) +{ + TLSSocket self = (TLSSocket) parameter; + + DEBUG_PRINT("TLS", "Verify cert: depth %i\n", certificate_depth); + + DEBUG_PRINT("TLS", " flags: %08x\n", *flags); + + char buffer[1024]; + + mbedtls_x509_crt_info(buffer, 1023, " ", crt); + + DEBUG_PRINT("TLS", "%s\n", buffer); + + if (self->tlsConfig->chainValidation == false) { + if (certificate_depth != 0) + *flags = 0; + } + + 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) { + 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)) { + certMatches = true; + break; + } + + certList = LinkedList_getNext(certList); + } + + if (certMatches) + *flags = 0; + 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; + return 1; + } + } + + if (self->storePeerCert) { + + if (*flags == 0) { + + self->peerCertLength = 0; + self->peerCert = (uint8_t*) GLOBAL_MALLOC(crt->raw.len); + + if (self->peerCert) { + self->peerCertLength = (int)crt->raw.len; + memcpy(self->peerCert, crt->raw.p, self->peerCertLength); + } + + } + + } + } + + return 0; +} + +/* + * Finish configuration when used the first time. + */ +static bool +TLSConfiguration_setupComplete(TLSConfiguration self) +{ + if (self->setupComplete == false) { + mbedtls_ssl_conf_ca_chain( &(self->conf), &(self->cacerts), &(self->crl) ); + + if (self->ownCertificate.version > 0) { + int ret = mbedtls_ssl_conf_own_cert( &(self->conf), &(self->ownCertificate), &(self->ownKey)); + + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned -0x%x\n", -ret); + return false; + } + } + + if (self->useSessionResumption) { + if (mbedtls_ssl_conf_get_endpoint(&(self->conf)) == MBEDTLS_SSL_IS_CLIENT) { + + } + 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 + mbedtls_ssl_cache_set_timeout(&(self->cache), self->sessionResumptionInterval); + + mbedtls_ssl_conf_session_cache( &(self->conf), &(self->cache), + mbedtls_ssl_cache_get, + mbedtls_ssl_cache_set ); + } + } + + self->setupComplete = true; + } + + return true; +} + +TLSConfiguration +TLSConfiguration_create() +{ + TLSConfiguration self = (TLSConfiguration) GLOBAL_CALLOC(1, sizeof(struct sTLSConfiguration)); + + if (self != NULL) + { + /* call to psa_crypto_init required -> see https://github.com/Mbed-TLS/mbedtls/issues/9223 */ + psa_status_t psaStatus = psa_crypto_init(); + + psaInitCounter++; + + mbedtls_ssl_config_init( &(self->conf) ); + mbedtls_x509_crt_init( &(self->ownCertificate) ); + mbedtls_x509_crt_init( &(self->cacerts) ); + mbedtls_x509_crl_init( &(self->crl) ); + mbedtls_pk_init( &(self->ownKey) ); + mbedtls_entropy_init( &(self->entropy) ); + mbedtls_ctr_drbg_init( &(self->ctr_drbg) ); + + /* WARINING is fixed to server! */ + mbedtls_ssl_config_defaults( &(self->conf), + MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT ); + + mbedtls_ctr_drbg_seed( &(self->ctr_drbg), mbedtls_entropy_func, &(self->entropy), NULL, 0); + mbedtls_ssl_conf_rng( &(self->conf), mbedtls_ctr_drbg_random, &(self->ctr_drbg) ); + + mbedtls_ssl_conf_authmode(&(self->conf), MBEDTLS_SSL_VERIFY_REQUIRED); + + 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; + + self->renegotiationTimeInMs = -1; /* no automatic renegotiation */ + + self->allowedCertificates = LinkedList_create(); + + /* default behavior is to allow all certificates that are signed by the CA */ + self->chainValidation = true; + self->allowOnlyKnownCertificates = false; + self->setupComplete = false; + + self->eventHandler = NULL; + self->eventHandlerParameter = NULL; + + self->useSessionResumption = true; + self->sessionResumptionInterval = 21600; /* default value: 6h */ + self->savedSession = NULL; + self->savedSessionTime = 0; + } + + return self; +} + +void +TLSConfiguration_setClientMode(TLSConfiguration self) +{ + mbedtls_ssl_conf_endpoint(&(self->conf), MBEDTLS_SSL_IS_CLIENT); +} + +void +TLSConfiguration_enableSessionResumption(TLSConfiguration self, bool enable) +{ + self->useSessionResumption = enable; +} + +void +TLSConfiguration_setSessionResumptionInterval(TLSConfiguration self, int intervalInSeconds) +{ + self->sessionResumptionInterval = intervalInSeconds; +} + +void +TLSConfiguration_setEventHandler(TLSConfiguration self, TLSConfiguration_EventHandler handler, void* parameter) +{ + self->eventHandler = handler; + self->eventHandlerParameter = parameter; +} + +void +TLSConfiguration_setMinTlsVersion(TLSConfiguration self, TLSConfigVersion version) +{ + self->minVersion = version; +} + +void +TLSConfiguration_setMaxTlsVersion(TLSConfiguration self, TLSConfigVersion version) +{ + self->maxVersion = version; +} + +void +TLSConfiguration_setChainValidation(TLSConfiguration self, bool value) +{ + self->chainValidation = value; +} + +void +TLSConfiguration_setAllowOnlyKnownCertificates(TLSConfiguration self, bool value) +{ + self->allowOnlyKnownCertificates = value; +} + +bool +TLSConfiguration_setOwnCertificate(TLSConfiguration self, uint8_t* certificate, int certLen) +{ + int ret = mbedtls_x509_crt_parse(&(self->ownCertificate), certificate, certLen); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse returned -0x%x\n", -ret); + + return (ret == 0); +} + +bool +TLSConfiguration_setOwnCertificateFromFile(TLSConfiguration self, const char* filename) +{ + int ret = mbedtls_x509_crt_parse_file(&(self->ownCertificate), filename); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse_file returned -0x%x\n", -ret); + + return (ret == 0); +} + +bool +TLSConfiguration_setOwnKey(TLSConfiguration self, uint8_t* key, int keyLen, const char* keyPassword) +{ + // MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#some-functions-gained-an-rng-parameter + // MIGRATE 2.28->3.x.x: drbg needs to be initialized, but it seems to be done in TLSConfiguration_create + int ret = mbedtls_pk_parse_key(&(self->ownKey), key, keyLen, (const uint8_t*) keyPassword, (keyPassword == NULL) ? 0 : strlen(keyPassword), mbedtls_ctr_drbg_random, &(self->ctr_drbg)); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_pk_parse_key returned -0x%x\n", -ret); + + return (ret == 0); +} + +bool +TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self, const char* filename, const char* keyPassword) +{ + // MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#some-functions-gained-an-rng-parameter + // MIGRATE 2.28->3.x.x: drbg needs to be initialized, but it seems to be done in TLSConfiguration_create + int ret = mbedtls_pk_parse_keyfile(&(self->ownKey), filename, keyPassword, mbedtls_ctr_drbg_random, &(self->ctr_drbg)); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_pk_parse_keyfile returned -0x%x\n", -ret); + + return (ret == 0); +} + +bool +TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certificate, int certLen) +{ + mbedtls_x509_crt* cert = (mbedtls_x509_crt*) GLOBAL_CALLOC(1, sizeof(mbedtls_x509_crt)); + + int ret = mbedtls_x509_crt_parse(cert, certificate, certLen); + + if (ret == 0) { + LinkedList_add(self->allowedCertificates, cert); + return true; + } + else { + GLOBAL_FREEMEM(cert); + return false; + } +} + +bool +TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self, const char* filename) +{ + mbedtls_x509_crt* cert = (mbedtls_x509_crt*) GLOBAL_CALLOC(1, sizeof(mbedtls_x509_crt)); + + int ret = mbedtls_x509_crt_parse_file(cert, filename); + + if (ret == 0) { + LinkedList_add(self->allowedCertificates, cert); + return true; + } + else { + GLOBAL_FREEMEM(cert); + return false; + } +} + +bool +TLSConfiguration_addCACertificate(TLSConfiguration self, uint8_t* certificate, int certLen) +{ + int ret = mbedtls_x509_crt_parse(&(self->cacerts), certificate, certLen); + + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse returned -0x%x\n", -ret); + return false; + } + + return (ret == 0); +} + +bool +TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* filename) +{ + int ret = mbedtls_x509_crt_parse_file(&(self->cacerts), filename); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse returned -0x%x\n", -ret); + + return (ret == 0); +} + +static void +udpatedCRL(TLSConfiguration self) +{ + self->crlUpdated = Hal_getTimeInMs(); + + /* We need to clean-up resumption cache (if enabled) to make sure we renegotiate as CRL may have changed data */ + if (self->useSessionResumption == false) + return; + + 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)); + } +} + +bool +TLSConfiguration_addCRL(TLSConfiguration self, uint8_t* crl, int crlLen) +{ + int ret = mbedtls_x509_crl_parse(&(self->crl), crl, crlLen); + + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_x509_crl_parse returned -0x%x\n", -ret); + } + else { + udpatedCRL(self); + } + + return (ret == 0); +} + +bool +TLSConfiguration_addCRLFromFile(TLSConfiguration self, const char* filename) +{ + int ret = mbedtls_x509_crl_parse_file(&(self->crl), filename); + + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_x509_crl_parse_file returned %d\n", ret); + } + else { + udpatedCRL(self); + } + + return (ret == 0); +} + +void +TLSConfiguration_resetCRL(TLSConfiguration self) +{ + mbedtls_x509_crl_free(&(self->crl)); + mbedtls_x509_crl_init(&(self->crl)); + self->crlUpdated = Hal_getTimeInMs(); +} + +void +TLSConfiguration_setRenegotiationTime(TLSConfiguration self, int timeInMs) +{ + self->renegotiationTimeInMs = timeInMs; +} + +void +TLSConfiguration_destroy(TLSConfiguration self) +{ + 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 { + mbedtls_ssl_cache_free(&(self->cache)); + } + } + + mbedtls_x509_crt_free(&(self->ownCertificate)); + mbedtls_x509_crt_free(&(self->cacerts)); + mbedtls_x509_crl_free(&(self->crl)); + mbedtls_pk_free(&(self->ownKey)); + mbedtls_ssl_config_free(&(self->conf)); + mbedtls_ctr_drbg_free(&(self->ctr_drbg)); + mbedtls_entropy_free(&(self->entropy)); + + LinkedList certElem = LinkedList_getNext(self->allowedCertificates); + + while (certElem) { + mbedtls_x509_crt* cert = (mbedtls_x509_crt*) LinkedList_getData(certElem); + + mbedtls_x509_crt_free(cert); + + certElem = LinkedList_getNext(certElem); + } + + LinkedList_destroy(self->allowedCertificates); + + psaInitCounter--; + + if (psaInitCounter < 1) + mbedtls_psa_crypto_free(); + + GLOBAL_FREEMEM(self); +} + +static void +createSecurityEvents(TLSConfiguration config, int ret, uint32_t flags, TLSSocket socket) +{ + if (config->eventHandler == NULL) + return; + + switch (ret) { + case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG: + raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_NO_CIPHER, "Alarm: Algorithm not supported", socket); + break; + + // MIGRATE 2.28->3.x.x:https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#changes-in-the-ssl-error-code-space + // case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN: (MIGRATE 2.28->3.x.x) + // raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_NO_CIPHER, "Alarm: no matching TLS ciphers", socket); + // break; + + // case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: (MIGRATE 2.28->3.x.x) + // raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED, "Alarm: Algorithm not supported", socket); + // break; + + + case MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE: + raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED, "Alarm: Handshake failure", socket); + break; + + // case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION: (MIGRATE 2.28->3.x.x) + // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_UNSECURE_COMMUNICATION, "Alarm: Unsecure communication", socket); + // break; + + case MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_UNAVAILABLE, "Alarm: certificate unavailable", socket); + break; + + // case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE: (MIGRATE 2.28->3.x.x) + // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_BAD_CERT, "Alarm: Bad certificate", socket); + // break; + + case MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_SIZE_EXCEEDED, "Alarm: TLS certificate size exceeded", socket); + break; + + // MIGRATE 2.28->3.x.x: the removal of this is undocumented TODO: Verify migration path + // case MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED: (MIGRATE 2.28->3.x.x) + // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Alarm: certificate validation: certificate signature could not be validated", socket); + // break; + + // MIGRATE 2.28->3.x.x: the removal of this is undocumented. The docs say migrating users are affected but don't provide a migration path TODO: Verify migration path (MIGRATE 2.28->3.x.x) + // case MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED: + // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REQUIRED, "Alarm: Certificate required", socket); + // break; + + case MBEDTLS_ERR_SSL_DECODE_ERROR: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Decode error", socket); + break; + + case MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Illegal parameter", socket); + break; + + case MBEDTLS_ERR_SSL_BAD_PROTOCOL_VERSION: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Bad protocol version", socket); + break; + + case MBEDTLS_ERR_SSL_BAD_CERTIFICATE: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Bad certificate", socket); + break; + + case MBEDTLS_ERR_SSL_UNRECOGNIZED_NAME: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Unrecognized name", socket); + break; + + case MBEDTLS_ERR_SSL_UNSUPPORTED_EXTENSION: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Unsupported extension", socket); + break; + + case MBEDTLS_ERR_SSL_NO_APPLICATION_PROTOCOL: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: No application protocol", socket); + break; + + case MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Unexpected message", socket); + break; + + case MBEDTLS_ERR_SSL_INTERNAL_ERROR: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Internal error", socket); + break; + + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + { + if (flags & MBEDTLS_X509_BADCERT_EXPIRED) { + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_EXPIRED, "Alarm: expired certificate", socket); + } + else if (flags & MBEDTLS_X509_BADCERT_REVOKED) { + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REVOKED, "Alarm: revoked certificate", socket); + } + else if (flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) { + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_TRUSTED, "Alarm: Certificate validation: CA certificate not available", socket); + } + else if (flags & MBEDTLS_X509_BADCERT_OTHER) { + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED, "Alarm: Certificate not configured", socket); + } + else if (flags & MBEDTLS_X509_BADCERT_BAD_KEY) { + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED, "Alarm: Insufficient key length", socket); + } + + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Alarm: Certificate verification failed", socket); + } + break; + + default: + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: handshake failed for unknown reason", socket); + break; + } +} + +static int +readFunction(void* ctx, unsigned char* buf, size_t len) +{ + int ret = Socket_read((Socket) ctx, buf, (int)len); + + if ((ret == 0) && (len > 0)) { + return MBEDTLS_ERR_SSL_WANT_READ; + } + + return ret; +} + +static int +writeFunction(void* ctx, unsigned char* buf, size_t len) +{ + return Socket_write((Socket)ctx, buf, (int)len); +} + +static TLSConfigVersion +getTLSVersion(int majorVersion, int minorVersion) +{ + if (majorVersion != 3) { + return TLS_VERSION_NOT_SELECTED; + } + else { + switch (minorVersion) { + /* TODO: Remove from here (MIGRATE 2.28->3.x.x) */ + case 0: + return TLS_VERSION_SSL_3_0; + case 1: + return TLS_VERSION_TLS_1_0; + case 2: + return TLS_VERSION_TLS_1_1; + /* Up until here (MIGRATE 2.28->3.x.x) */ + case 3: + return TLS_VERSION_TLS_1_2; + case 4: + return TLS_VERSION_TLS_1_3; + default: + return TLS_VERSION_NOT_SELECTED; + } + } +} + +static int +getMajorVersion(TLSConfigVersion version) +{ + switch(version) { + case TLS_VERSION_NOT_SELECTED: + return 0; + /* TODO: Remove from here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_SSL_3_0: + case TLS_VERSION_TLS_1_0: + case TLS_VERSION_TLS_1_1: + /* Up until here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_TLS_1_2: + case TLS_VERSION_TLS_1_3: + return 3; + default: + return 0; + } +} + +static int +getMinorVersion(TLSConfigVersion version) +{ + switch(version) { + case TLS_VERSION_NOT_SELECTED: + return 0; + /* TODO: Remove from here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_SSL_3_0: + return 0; + case TLS_VERSION_TLS_1_0: + return 1; + case TLS_VERSION_TLS_1_1: + return 2; + /* Up until here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_TLS_1_2: + return 3; + case TLS_VERSION_TLS_1_3: + return 4; + default: + return 0; + } +} + +TLSSocket +TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClientCert) +{ + TLSSocket self = (TLSSocket) GLOBAL_CALLOC(1, sizeof(struct sTLSSocket)); + + if (self) + { + self->socket = socket; + self->tlsConfig = configuration; + self->storePeerCert = storeClientCert; + self->peerCert = NULL; + self->peerCertLength = 0; + + TLSConfiguration_setupComplete(configuration); + + memcpy(&(self->conf), &(configuration->conf), sizeof(mbedtls_ssl_config)); + + mbedtls_ssl_conf_verify(&(self->conf), verifyCertificate, (void*) self); + + int ret; + + mbedtls_ssl_conf_ca_chain( &(self->conf), &(configuration->cacerts), &(configuration->crl) ); + + self->crlUpdated = configuration->crlUpdated; + + if (configuration->minVersion != TLS_VERSION_NOT_SELECTED) { + /* set minimum TLS version */ + + int majorVer = getMajorVersion(configuration->minVersion); + int minorVer = getMinorVersion(configuration->minVersion); + + mbedtls_ssl_conf_min_version( &(self->conf), majorVer, minorVer); + } + + if (configuration->maxVersion != TLS_VERSION_NOT_SELECTED) { + /* set maximum TLS version */ + + int majorVer = getMajorVersion(configuration->maxVersion); + int minorVer = getMinorVersion(configuration->maxVersion); + + mbedtls_ssl_conf_max_version( &(self->conf), majorVer, minorVer); + } + + if (configuration->ownCertificate.version > 0) { + ret = mbedtls_ssl_conf_own_cert( &(self->conf), &(configuration->ownCertificate), &(configuration->ownKey)); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned %d\n", ret); + } + + ret = mbedtls_ssl_setup( &(self->ssl), &(self->conf) ); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_ssl_setup returned %d\n", ret); + + 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)) { + + ret = mbedtls_ssl_set_session(&(self->ssl), configuration->savedSession); + + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_ssl_set_session returned %d\n", ret); + configuration->savedSessionTime = 0; + } + else { + DEBUG_PRINT("TLS", "resume TLS session\n"); + reuseSession = true; + } + } + else { + configuration->savedSessionTime = 0; + DEBUG_PRINT("TLS", "cached session expired\n"); + } + + } + } + } + + while( (ret = mbedtls_ssl_handshake(&(self->ssl)) ) != 0 ) + { + if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + DEBUG_PRINT("TLS", "handshake failed - mbedtls_ssl_handshake returned -0x%x\n", -ret ); + + uint32_t flags = mbedtls_ssl_get_verify_result(&(self->ssl)); + + createSecurityEvents(configuration, ret, flags, self); + + mbedtls_ssl_free(&(self->ssl)); + + if (self->peerCert) { + GLOBAL_FREEMEM(self->peerCert); + } + + GLOBAL_FREEMEM(self); + + return 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) { + ret = mbedtls_ssl_get_session(&(self->ssl), configuration->savedSession); + + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_ssl_get_session returned %d\n", ret); + } + else { + configuration->savedSessionTime = Hal_getTimeInMs(); + } + } + } + } + } + + self->lastRenegotiationTime = Hal_getTimeInMs(); + + // 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(configuration, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_INSECURE_TLS_VERSION, "Warning: Insecure TLS version", self); + // } + + } + + return self; +} + +uint8_t* +TLSSocket_getPeerCertificate(TLSSocket self, int* certSize) +{ + if (certSize) + *certSize = self->peerCertLength; + + return self->peerCert; +} + +bool +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) { + // 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); + // } + + return true; + } + else { + DEBUG_PRINT("TLS", "TLSSocket_performHandshake failed -> ret=%i\n", ret); + + raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION, "Alarm: Renegotiation failed", self); + + ret = mbedtls_ssl_session_reset(&(self->ssl)); + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_ssl_session_reset failed -> ret: -0x%X\n", -ret); + } + + return false; + } +} + +static void +checkForCRLUpdate(TLSSocket self) +{ + if (self->crlUpdated == self->tlsConfig->crlUpdated) + return; + + DEBUG_PRINT("TLS", "CRL updated -> refresh CA chain\n"); + + mbedtls_ssl_conf_ca_chain( &(self->conf), &( self->tlsConfig->cacerts), &( self->tlsConfig->crl) ); + + self->crlUpdated = self->tlsConfig->crlUpdated; + + /* IEC TS 62351-100-3 Conformance test 6.2.6 requires that upon CRL update a TLS renegotiation should occur */ + self->lastRenegotiationTime = 0; +} + +/* true = renegotiation is not needed or it is successfull, false = Failed */ +static bool +startRenegotiationIfRequired(TLSSocket self) +{ + if (self->tlsConfig->renegotiationTimeInMs <= 0) + return true; + + if (Hal_getTimeInMs() <= self->lastRenegotiationTime + self->tlsConfig->renegotiationTimeInMs) + return true; + + raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION, "Info: session renegotiation started", self); + + if (TLSSocket_performHandshake(self) == false) { + DEBUG_PRINT("TLS", " renegotiation failed\n"); + return false; + } + + DEBUG_PRINT("TLS", " started renegotiation\n"); + self->lastRenegotiationTime = Hal_getTimeInMs(); + + return true; +} + +int +TLSSocket_read(TLSSocket self, uint8_t* buf, int size) +{ + checkForCRLUpdate(self); + + if (startRenegotiationIfRequired(self) == false) { + return -1; + } + + int ret = mbedtls_ssl_read(&(self->ssl), buf, size); + + if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE)) + return 0; + + if (ret < 0) { + + switch (ret) + { + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + DEBUG_PRINT("TLS", " connection was closed gracefully\n"); + return -1; + + case MBEDTLS_ERR_NET_CONN_RESET: + DEBUG_PRINT("TLS", " connection was reset by peer\n"); + return -1; + + default: + DEBUG_PRINT("TLS", " mbedtls_ssl_read returned -0x%x\n", -ret); + + { + uint32_t flags = mbedtls_ssl_get_verify_result(&(self->ssl)); + + createSecurityEvents(self->tlsConfig, ret, flags, self); + } + + return -1; + } + } + + return ret; +} + +int +TLSSocket_write(TLSSocket self, uint8_t* buf, int size) +{ + int ret; + int len = size; + + checkForCRLUpdate(self); + + if (startRenegotiationIfRequired(self) == false) { + return -1; + } + + while ((ret = mbedtls_ssl_write(&(self->ssl), buf, len)) <= 0) + { + if (ret == MBEDTLS_ERR_NET_CONN_RESET) + { + DEBUG_PRINT("TLS", "peer closed the connection\n"); + return -1; + } + + if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) + { + DEBUG_PRINT("TLS", "mbedtls_ssl_write returned %d\n", ret); + return -1; + } + } + + len = ret; + + return len; +} + +void +TLSSocket_close(TLSSocket self) +{ + int ret; + + /* TODO add timeout? */ + + while ((ret = mbedtls_ssl_close_notify(&(self->ssl))) < 0) + { + if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) + { + DEBUG_PRINT("TLS", "mbedtls_ssl_close_notify returned -0x%x\n", -ret); + break; + } + } + + Thread_sleep(10); + + mbedtls_ssl_free(&(self->ssl)); + + if (self->peerCert) + GLOBAL_FREEMEM(self->peerCert); + + GLOBAL_FREEMEM(self); +} + +char* +TLSConnection_getPeerAddress(TLSConnection self, char* peerAddrBuf) +{ + TLSSocket socket = (TLSSocket)self; + + if (peerAddrBuf == NULL) { + peerAddrBuf = (char*)GLOBAL_MALLOC(61); + } + + if (peerAddrBuf) + return Socket_getPeerAddressStatic(socket->socket, peerAddrBuf); + else + return NULL; +} + +uint8_t* +TLSConnection_getPeerCertificate(TLSConnection self, int* certSize) +{ + TLSSocket socket = (TLSSocket)self; + + return TLSSocket_getPeerCertificate(socket, certSize); +} + +TLSConfigVersion +TLSConnection_getTLSVersion(TLSConnection self) +{ + TLSSocket socket = (TLSSocket)self; + // 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_protocol_version version = mbedtls_ssl_get_version_number(&(socket->ssl)); + + switch(version) { + case MBEDTLS_SSL_VERSION_TLS1_2: + return TLS_VERSION_TLS_1_2; + case MBEDTLS_SSL_VERSION_TLS1_3: + return TLS_VERSION_TLS_1_3; + case MBEDTLS_SSL_VERSION_UNKNOWN: + default: + return TLS_VERSION_NOT_SELECTED; + } +} + +const char* +TLSConfigVersion_toString(TLSConfigVersion version) +{ + switch (version) + { + /* TODO: Remove from here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_SSL_3_0: + return "SSL 3.0"; + case TLS_VERSION_TLS_1_0: + return "TLS 1.0"; + case TLS_VERSION_TLS_1_1: + return "TLS 1.1"; + /* Up until here (MIGRATE 2.28->3.x.x) */ + case TLS_VERSION_TLS_1_2: + return "TLS 1.2"; + case TLS_VERSION_TLS_1_3: + return "TLS 1.3"; + default: + return "unknown TLS version"; + } +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8c08bb6f..98f647e7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,16 @@ +if(WITH_MBEDTLS3) +include_directories( + ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls3 + ${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-3.6.0/include +) +else() if(WITH_MBEDTLS) include_directories( ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls ${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-2.28/include ) endif(WITH_MBEDTLS) +endif(WITH_MBEDTLS3) set (lib_common_SRCS ./common/string_map.c @@ -189,7 +196,7 @@ set (lib_sv_SRCS ./sampled_values/sv_publisher.c ) -if(WITH_MBEDTLS AND (CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV)) +if((WITH_MBEDTLS OR WITH_MBEDTLS3) AND (CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV)) set (lib_rsession_SRCS ./r_session/r_session.c ./r_session/r_session_crypto_mbedtls.c