From f61c58dd35038b8326ad2cf680c8fdfdb736374c Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 11 Nov 2022 19:00:22 +0000 Subject: [PATCH] - added TLSConnection object to provide more context in TLS event callback (LIB61850-366) --- dotnet/IEC61850forCSharp/TLS.cs | 1 - .../tls_client_example/tls_client_example.c | 8 +- .../tls_server_example/tls_server_example.c | 10 +- hal/inc/hal_socket.h | 2 +- hal/inc/tls_config.h | 69 ++++++++++--- hal/tls/mbedtls/tls_mbedtls.c | 99 ++++++++++++++----- 6 files changed, 148 insertions(+), 41 deletions(-) diff --git a/dotnet/IEC61850forCSharp/TLS.cs b/dotnet/IEC61850forCSharp/TLS.cs index 69a273b0..da7b8d73 100644 --- a/dotnet/IEC61850forCSharp/TLS.cs +++ b/dotnet/IEC61850forCSharp/TLS.cs @@ -130,7 +130,6 @@ namespace IEC61850 } } - public void SetClientMode() { TLSConfiguration_setClientMode (self); diff --git a/examples/tls_client_example/tls_client_example.c b/examples/tls_client_example/tls_client_example.c index c546f425..5dd982d2 100644 --- a/examples/tls_client_example/tls_client_example.c +++ b/examples/tls_client_example/tls_client_example.c @@ -30,11 +30,15 @@ reportCallbackFunction(void* parameter, ClientReport report) } static void -securityEventHandler(void* parameter, TLSConfiguration_EventLevel eventLevel, int eventCode, const char* msg) +securityEventHandler(void* parameter, TLSConfiguration_EventLevel eventLevel, int eventCode, const char* msg, TLSConnection con) { (void)parameter; - printf("[SECURITY EVENT] %s (t: %i, c: %i)\n", msg, eventLevel, eventCode); + char* peerAddr = TLSConnection_getPeerAddress(con, NULL); + + printf("[SECURITY EVENT] %s (%s)(t: %i, c: %i)\n", msg, peerAddr, eventLevel, eventCode); + + free(peerAddr); } int main(int argc, char** argv) { diff --git a/examples/tls_server_example/tls_server_example.c b/examples/tls_server_example/tls_server_example.c index 08bfd662..e2324faf 100644 --- a/examples/tls_server_example/tls_server_example.c +++ b/examples/tls_server_example/tls_server_example.c @@ -103,11 +103,17 @@ clientAuthenticator(void* parameter, AcseAuthenticationParameter authParameter, } static void -securityEventHandler(void* parameter, TLSConfiguration_EventLevel eventLevel, int eventCode, const char* msg) +securityEventHandler(void* parameter, TLSConfiguration_EventLevel eventLevel, int eventCode, const char* msg, TLSConnection con) { (void)parameter; - printf("[SECURITY EVENT] %s (t: %i, c: %i)\n", msg, eventLevel, eventCode); + char* peerAddr = TLSConnection_getPeerAddress(con, NULL); + + const char* tlsVersionStr = TLSConfigVersion_toString(TLSConnection_getTLSVersion(con)); + + printf("[SECURITY EVENT - %s] %s (%s)(t: %i, c: %i)\n", tlsVersionStr, msg, peerAddr, eventLevel, eventCode); + + free(peerAddr); } int diff --git a/hal/inc/hal_socket.h b/hal/inc/hal_socket.h index 2f681cce..bddb98f1 100644 --- a/hal/inc/hal_socket.h +++ b/hal/inc/hal_socket.h @@ -322,7 +322,7 @@ Socket_getPeerAddress(Socket self); * * The peer address has to be returned as null terminated string * - * Implementation of this function is MANDATORY (lib60870) + * Implementation of this function is MANDATORY (lib60870 and libiec61850) * * \param self the client, connection or server socket instance * \param peerAddressString a string to store the peer address (the string should have space diff --git a/hal/inc/tls_config.h b/hal/inc/tls_config.h index 37af40c2..9a456752 100644 --- a/hal/inc/tls_config.h +++ b/hal/inc/tls_config.h @@ -3,7 +3,7 @@ * * TLS Configuration API for protocol stacks using TCP/IP * - * Copyright 2017-2021 Michael Zillgith + * Copyright 2017-2022 Michael Zillgith * * Abstraction layer for configuration of different TLS implementations * @@ -50,6 +50,25 @@ TLSConfiguration_create(void); PAL_API void TLSConfiguration_setClientMode(TLSConfiguration self); +typedef enum { + TLS_VERSION_NOT_SELECTED = 0, + TLS_VERSION_SSL_3_0 = 3, + TLS_VERSION_TLS_1_0 = 4, + TLS_VERSION_TLS_1_1 = 5, + TLS_VERSION_TLS_1_2 = 6, + TLS_VERSION_TLS_1_3 = 7 +} TLSConfigVersion; + +/** + * \brief Convert TLS version number to string + * + * \param version TLS version number + * + * \return the TLS version as null terminated string + */ +PAL_API const char* +TLSConfigVersion_toString(TLSConfigVersion version); + typedef enum { TLS_SEC_EVT_INFO = 0, TLS_SEC_EVT_WARNING = 1, @@ -71,10 +90,47 @@ typedef enum { #define TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED 13 #define TLS_EVENT_CODE_ALM_CERT_NOT_TRUSTED 12 -typedef void (*TLSConfiguration_EventHandler)(void* parameter, TLSConfiguration_EventLevel eventLevel, int eventCode, const char* message); +typedef struct sTLSConnection* TLSConnection; + +/** + * \brief Get the peer address of the TLS connection + * + * \param self the TLS connection instance + * \param peerAddrBuf user provided buffer that can hold at least 60 characters, or NULL to allow the function to allocate the memory for the buffer + * + * \returns peer address:port as null terminated string + */ +PAL_API char* +TLSConnection_getPeerAddress(TLSConnection self, char* peerAddrBuf); + +/** + * \brief Get the TLS certificate used by the peer + * + * \param self the TLS connection instance + * \param certSize[OUT] the certificate size in bytes + * + * \return address of the certificate buffer + */ +PAL_API uint8_t* +TLSConnection_getPeerCertificate(TLSConnection self, int* certSize); + +/** + * \brief Get the TLS version used by the connection + * + * \param self the TLS connection instance + * + * \return TLS version + */ +PAL_API TLSConfigVersion +TLSConnection_getTLSVersion(TLSConnection self); + +typedef void (*TLSConfiguration_EventHandler)(void* parameter, TLSConfiguration_EventLevel eventLevel, int eventCode, const char* message, TLSConnection con); /** * \brief Set the security event handler + * + * \param handler the security event callback handler + * \param parameter user provided parameter to be passed to the callback handler */ PAL_API void TLSConfiguration_setEventHandler(TLSConfiguration self, TLSConfiguration_EventHandler handler, void* parameter); @@ -209,15 +265,6 @@ TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* fil PAL_API void TLSConfiguration_setRenegotiationTime(TLSConfiguration self, int timeInMs); -typedef enum { - TLS_VERSION_NOT_SELECTED = 0, - TLS_VERSION_SSL_3_0 = 3, - TLS_VERSION_TLS_1_0 = 4, - TLS_VERSION_TLS_1_1 = 5, - TLS_VERSION_TLS_1_2 = 6, - TLS_VERSION_TLS_1_3 = 7 -} TLSConfigVersion; - /** * \brief Set minimal allowed TLS version to use */ diff --git a/hal/tls/mbedtls/tls_mbedtls.c b/hal/tls/mbedtls/tls_mbedtls.c index 65c96538..f7d7127e 100644 --- a/hal/tls/mbedtls/tls_mbedtls.c +++ b/hal/tls/mbedtls/tls_mbedtls.c @@ -105,10 +105,10 @@ struct sTLSSocket { }; static void -raiseSecurityEvent(TLSConfiguration config, TLSConfiguration_EventLevel eventCategory, int eventCode, const char* message) +raiseSecurityEvent(TLSConfiguration config, TLSConfiguration_EventLevel eventCategory, int eventCode, const char* message, TLSSocket socket) { if (config->eventHandler) { - config->eventHandler(config->eventHandlerParameter, eventCategory, eventCode, message); + config->eventHandler(config->eventHandlerParameter, eventCategory, eventCode, message, (TLSConnection)socket); } } @@ -174,7 +174,7 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth if (certMatches) *flags = 0; else { - raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED, "Incident: Certificate not configured"); + raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED, "Incident: Certificate not configured", self); *flags |= MBEDTLS_X509_BADCERT_OTHER; return 1; @@ -518,7 +518,7 @@ TLSConfiguration_destroy(TLSConfiguration self) } static void -createSecurityEvents(TLSConfiguration config, int ret, uint32_t flags) +createSecurityEvents(TLSConfiguration config, int ret, uint32_t flags, TLSSocket socket) { if (config->eventHandler == NULL) return; @@ -526,55 +526,55 @@ createSecurityEvents(TLSConfiguration config, int ret, uint32_t flags) switch (ret) { case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: - raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED, "Incident: Algorithm not supported"); + raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED, "Incident: Algorithm not supported", socket); break; case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION: - raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_UNSECURE_COMMUNICATION, "Incident: Unsecure communication"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_UNSECURE_COMMUNICATION, "Incident: Unsecure communication", socket); break; case MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE: - raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_UNAVAILABLE, "Incident: Certificate unavailable"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_UNAVAILABLE, "Incident: Certificate unavailable", socket); break; case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE: - raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_BAD_CERT, "Incident: Bad certificate"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_BAD_CERT, "Incident: Bad certificate", socket); break; case MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE: - raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_SIZE_EXCEEDED, "Incident: TLS certificate size exceeded"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_SIZE_EXCEEDED, "Incident: TLS certificate size exceeded", socket); break; case MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED: - raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Incident: certificate validation: certificate signature could not be validated"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Incident: certificate validation: certificate signature could not be validated", socket); break; case MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED: - raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REQUIRED, "Incident: Certificate required"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REQUIRED, "Incident: Certificate required", 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, "Incident: Certificate expired"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_EXPIRED, "Incident: Certificate expired", socket); } else if (flags & MBEDTLS_X509_BADCERT_REVOKED) { - raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REVOKED, "Incident: Certificate revoked"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REVOKED, "Incident: Certificate revoked", socket); } else if (flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) { - raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_TRUSTED, "Incident: Certificate validation: CA certificate not available"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_TRUSTED, "Incident: 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, "Incident: Certificate not configured"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED, "Incident: Certificate not configured", socket); } else { - raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Incident: Certificate verification failed"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Incident: Certificate verification failed", socket); } } break; default: - raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Incident: handshake failed for unknown reason"); + raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Incident: handshake failed for unknown reason", socket); break; } } @@ -753,7 +753,7 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient uint32_t flags = mbedtls_ssl_get_verify_result(&(self->ssl)); - createSecurityEvents(configuration, ret, flags); + createSecurityEvents(configuration, ret, flags, self); mbedtls_ssl_free(&(self->ssl)); @@ -793,7 +793,7 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient self->lastRenegotiationTime = Hal_getTimeInMs(); 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"); + raiseSecurityEvent(configuration, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_INSECURE_TLS_VERSION, "Warning: Insecure TLS version", self); } } @@ -817,7 +817,7 @@ TLSSocket_performHandshake(TLSSocket self) if (ret == 0) { 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"); + raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_INSECURE_TLS_VERSION, "Warning: Insecure TLS version", self); } return true; @@ -828,7 +828,7 @@ TLSSocket_performHandshake(TLSSocket self) if (self->tlsConfig->eventHandler) { uint32_t flags = mbedtls_ssl_get_verify_result(&(self->ssl)); - createSecurityEvents(self->tlsConfig, ret, flags); + createSecurityEvents(self->tlsConfig, ret, flags, self); } return false; @@ -849,7 +849,7 @@ TLSSocket_read(TLSSocket self, uint8_t* buf, int size) if (self->tlsConfig->renegotiationTimeInMs > 0) { if (Hal_getTimeInMs() > self->lastRenegotiationTime + self->tlsConfig->renegotiationTimeInMs) { - raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION, "Info: session renegotiation started"); + 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"); @@ -885,7 +885,7 @@ TLSSocket_read(TLSSocket self, uint8_t* buf, int size) { uint32_t flags = mbedtls_ssl_get_verify_result(&(self->ssl)); - createSecurityEvents(self->tlsConfig, ret, flags); + createSecurityEvents(self->tlsConfig, ret, flags, self); } return -1; @@ -912,7 +912,7 @@ TLSSocket_write(TLSSocket self, uint8_t* buf, int size) if (self->tlsConfig->renegotiationTimeInMs > 0) { if (Hal_getTimeInMs() > self->lastRenegotiationTime + self->tlsConfig->renegotiationTimeInMs) { - raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION, "Info: session renegotiation started"); + 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"); @@ -970,3 +970,54 @@ TLSSocket_close(TLSSocket self) 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; + + return getTLSVersion(socket->ssl.major_ver, socket->ssl.minor_ver); +} + +const char* +TLSConfigVersion_toString(TLSConfigVersion version) +{ + switch (version) + { + 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"; + 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"; + } +}