From 00dab2325bc10b1c07117b1173afb80e3118d1bc Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Tue, 13 May 2025 12:02:38 +0100 Subject: [PATCH] - Added L2 GOOSE security mbedtls code compatible with mbedtls 3.6 --- src/CMakeLists.txt | 12 +- src/r_session/r_session_crypto_mbedtls.c | 4 +- src/r_session/r_session_crypto_mbedtls3.c | 211 ++++++++++++++++++++++ 3 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 src/r_session/r_session_crypto_mbedtls3.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3c4d0dca..b9540769 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -89,7 +89,6 @@ set (lib_common_SRCS ./iec61850/server/mms_mapping/mms_goose.c ./iec61850/server/mms_mapping/mms_sv.c ./iec61850/server/mms_mapping/logging.c -./r_session/r_session_crypto_mbedtls.c ./logging/log_storage.c ) @@ -208,10 +207,21 @@ set (lib_sv_SRCS ) if((WITH_MBEDTLS OR WITH_MBEDTLS3) AND (CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV)) + +if (WITH_MBEDTLS) set (lib_rsession_SRCS ./r_session/r_session.c ./r_session/r_session_crypto_mbedtls.c ) +endif (WITH_MBEDTLS) + +if (WITH_MBEDTLS3) +set (lib_rsession_SRCS +./r_session/r_session.c +./r_session/r_session_crypto_mbedtls3.c +) +endif (WITH_MBEDTLS3) + else() set (lib_rsession_SRCS ) diff --git a/src/r_session/r_session_crypto_mbedtls.c b/src/r_session/r_session_crypto_mbedtls.c index 1f537fe2..c9947867 100644 --- a/src/r_session/r_session_crypto_mbedtls.c +++ b/src/r_session/r_session_crypto_mbedtls.c @@ -1,9 +1,9 @@ /* * r_session_crpyto_mbedtls.c * - * Implementation of RSessionCrypto interface using mbedtls + * Implementation of RSessionCrypto interface using mbedtls 2.28 * - * Copyright 2013-2024 Michael Zillgith + * Copyright 2013-2025 Michael Zillgith * * This file is part of libIEC61850. * diff --git a/src/r_session/r_session_crypto_mbedtls3.c b/src/r_session/r_session_crypto_mbedtls3.c new file mode 100644 index 00000000..3b84d518 --- /dev/null +++ b/src/r_session/r_session_crypto_mbedtls3.c @@ -0,0 +1,211 @@ +/* + * r_session_crpyto_mbedtls3.c + * + * Implementation of RSessionCrypto interface using mbedtls 3.6 + * + * Copyright 2013-2025 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "mbedtls/cipher.h" +#include "mbedtls/md.h" +#include "mbedtls/platform_util.h" +#include "mbedtls/gcm.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" + +#include "libiec61850_platform_includes.h" + +#include "r_session_crypto.h" + +#ifndef DEBUG_RSESSION_CRYPTO +#define DEBUG_RSESSION_CRYPTO 1 +#endif + +bool +RSessionCrypto_createHMAC(uint8_t* buffer, int bufSize, uint8_t* key, int keySize, uint8_t* hmac, int hmacMaxSize) +{ + const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + + mbedtls_md_context_t md_ctx; + + mbedtls_md_init( &md_ctx ); + + mbedtls_md_setup(&md_ctx, md_info, 1); + + if (mbedtls_md_hmac_starts(&md_ctx, key, keySize)) + { + if (DEBUG_RSESSION_CRYPTO) + printf("RSESSION_CRYPTO: Error in initializing HMAC\n"); + + return false; + } + + if (mbedtls_md_hmac_update(&md_ctx, buffer, bufSize)) + { + if (DEBUG_RSESSION_CRYPTO) + printf("RSESSION_CRYPTO: Failed to calculate HMAC\n"); + + return false; + } + + if (mbedtls_md_hmac_finish(&md_ctx, hmac)) + { + if (DEBUG_RSESSION_CRYPTO) + printf("RSESSION_CRYPTO: Failed to finish HMAC\n"); + + return false; + } + + mbedtls_md_free(&md_ctx); + + return true; +} + +bool +RSessionCrypto_createAES_GMAC(uint8_t* key, int keySize, uint8_t* iv, int ivSize, uint8_t* addData, int addDataSize, uint8_t* tag, int tagSize) +{ + mbedtls_gcm_context gcmCtx; + + mbedtls_gcm_init(&gcmCtx); + + if (mbedtls_gcm_setkey(&gcmCtx, MBEDTLS_CIPHER_ID_AES , (const unsigned char*) key, keySize * 8)) + { + printf("AES-GCM: Failed to set key\n"); + mbedtls_gcm_free(&gcmCtx); + return false; + } + + if (mbedtls_gcm_starts(&gcmCtx, MBEDTLS_GCM_ENCRYPT, iv, ivSize)) + { + printf("AES-GCM: Failed to start tag calculation\n"); + mbedtls_gcm_free(&gcmCtx); + return false; + } + + if (mbedtls_gcm_update_ad(&gcmCtx, addData, addDataSize)) + { + printf("AES-GCM: Failed to add authenticated data\n"); + mbedtls_gcm_free(&gcmCtx); + return false; + } + + size_t outLen = 0; + + if (mbedtls_gcm_finish(&gcmCtx, NULL, 0, &outLen, tag, tagSize)) + { + printf("AES-GCM: Failed to finish tag calculation\n"); + mbedtls_gcm_free(&gcmCtx); + return false; + } + + mbedtls_gcm_free(&gcmCtx); + + return true; +} + +bool +RSessionCrypto_gcmEncryptAndTag(uint8_t* key, int keySize, uint8_t* iv, int ivSize, uint8_t* addData, int addDataSize, uint8_t* encryptData, int encryptDataSize, uint8_t* tag, int tagSize) +{ + mbedtls_gcm_context gcmCtx; + + mbedtls_gcm_init(&gcmCtx); + + if (mbedtls_gcm_setkey(&gcmCtx, MBEDTLS_CIPHER_ID_AES , (const unsigned char*) key, keySize * 8)) + { + if (DEBUG_RSESSION_CRYPTO) + printf("RSESSION_CRYPTO: AES-GCM: Failed to set key\n"); + + mbedtls_gcm_free(&gcmCtx); + return false; + } + + if (mbedtls_gcm_crypt_and_tag(&gcmCtx, MBEDTLS_GCM_ENCRYPT, (size_t) encryptDataSize, iv, (size_t) ivSize, addData, (size_t) addDataSize, encryptData, encryptData, (size_t)tagSize, tag)) + { + if (DEBUG_RSESSION_CRYPTO) + printf("RSESSION_CRYPTO: AES-GCM: Failed to authenticate/encrypt data\n"); + + mbedtls_gcm_free(&gcmCtx); + return false; + } + + mbedtls_gcm_free(&gcmCtx); + + return true; +} + +bool +RSessionCrypto_gcmAuthAndDecrypt(uint8_t* key, int keySize, uint8_t* iv, int ivSize, uint8_t* addData, int addDataSize, uint8_t* encryptData, int encryptDataSize, uint8_t* decryptedData, uint8_t* tag, int tagSize) +{ + mbedtls_gcm_context gcmCtx; + + mbedtls_gcm_init(&gcmCtx); + + if (mbedtls_gcm_setkey(&gcmCtx, MBEDTLS_CIPHER_ID_AES , (const unsigned char*) key, keySize * 8)) + { + if (DEBUG_RSESSION_CRYPTO) + printf("RSESSION_CRYPTO: AES-GCM: Failed to set key\n"); + + mbedtls_gcm_free(&gcmCtx); + return false; + } + + if (mbedtls_gcm_auth_decrypt(&gcmCtx, (size_t) encryptDataSize, iv, (size_t) ivSize, addData, (size_t) addDataSize, tag, (size_t) tagSize, encryptData, decryptedData)) + { + if (DEBUG_RSESSION_CRYPTO) + printf("RSESSION_CRYPTO: AES-GCM: Failed to authentication and decrypt!\n"); + + mbedtls_gcm_free(&gcmCtx); + return false; + } + + mbedtls_gcm_free(&gcmCtx); + + return true; +} + +bool +RSessionCrypto_createRandomData(uint8_t* data, int dataSize) +{ + int ret; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_context entropy; + + mbedtls_entropy_init( &entropy ); + mbedtls_ctr_drbg_init( &ctr_drbg ); + + if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, + NULL, 0) ) != 0 ) + { + if (DEBUG_RSESSION_CRYPTO) + printf("RSESSION_CRYPTO: failed! mbedtls_ctr_drbg_init returned -0x%04x\n", -ret); + + return false; + } + + if( ( ret = mbedtls_ctr_drbg_random( &ctr_drbg, data, dataSize ) ) != 0 ) + { + if (DEBUG_RSESSION_CRYPTO) + printf("RSESSION_CRYPTO: failed! mbedtls_ctr_drbg_random returned -0x%04x\n", -ret); + + return false; + } + + return true; +}