From 600ce882ef8f5a71b2b3d4938a4f4d61665ac542 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Mon, 17 Feb 2025 19:34:09 +0000 Subject: [PATCH 1/4] - L2 GOOSE/SMV security: added code to calculate AES-GMAC (LIB61850-446) --- CMakeLists.txt | 6 +-- hal/CMakeLists.txt | 2 +- src/goose/goose_sec.c | 50 +++++++++++++++++++++++- src/r_session/r_session_crypto.h | 3 ++ src/r_session/r_session_crypto_mbedtls.c | 33 ++++++++++++++++ 5 files changed, 89 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a538fb97..af292c0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,10 +132,10 @@ set(USE_PREBUILD_MBEDTLS 1) set(MBEDTLS_INCLUDE_DIR ${CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH}) endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB) -if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.16) +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.16/include") -endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.16) +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) if(WITH_MBEDTLS) diff --git a/hal/CMakeLists.txt b/hal/CMakeLists.txt index 33975c28..ed407d90 100644 --- a/hal/CMakeLists.txt +++ b/hal/CMakeLists.txt @@ -129,7 +129,7 @@ include_directories( 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-2.16/library/*.c) +file(GLOB tls_SRCS ${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-2.28/library/*.c) endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB) add_definitions(-DMBEDTLS_CONFIG_FILE="mbedtls_config.h") diff --git a/src/goose/goose_sec.c b/src/goose/goose_sec.c index 72569389..4fa55945 100644 --- a/src/goose/goose_sec.c +++ b/src/goose/goose_sec.c @@ -99,8 +99,15 @@ L2Security_addSecurityExtension(L2Security self, uint8_t* buffer, int start, int else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_HMAC_SHA256_256) { mACSize = 2 + 32; } + else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_64) { + mACSize = 2 + 8; + } + else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_128) { + mACSize = 2 + 16; + } else { /* signature algorithm not supported */ + printf("Signature algorithm not supported\n"); return 0; } @@ -178,11 +185,52 @@ L2Security_addSecurityExtension(L2Security self, uint8_t* buffer, int start, int RSessionCrypto_createHMAC(buffer + start, macEnd - start, self->currentKey, self->currentKeySize, buffer + bufPos, 32); bufPos += 32; } + else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_64) + { + /* create IV */ + uint8_t iv[12]; + int ivSize = 12; + + if (RSessionCrypto_createRandomData(iv, ivSize) == false) { + printf("ERROR - Failed to create random IV\n"); + } + + if (RSessionCrypto_createAES_GMAC(self->currentKey, self->currentKeySize, iv, ivSize, buffer + start, macEnd - start, buffer + bufPos, 8) == false) + { + printf("ERROR - Failed to create GMAC\n"); + } + + bufPos += 8; + } + else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_128) + { + /* create IV */ + uint8_t iv[12]; + int ivSize = 12; + + if (RSessionCrypto_createRandomData(iv, ivSize) == false) { + printf("ERROR - Failed to create random IV\n"); + } + + if (RSessionCrypto_createAES_GMAC(self->currentKey, self->currentKeySize, iv, ivSize, buffer + start, macEnd - start, buffer + bufPos, 16) == false) + { + printf("ERROR - Failed to create GMAC\n"); + } + + bufPos += 16; + } + else { + /* signature algorithm not supported */ + printf("Signature algorithm not supported\n"); + return 0; + } } return securityExtensionSize + 2; } - else { + else + { + printf("L2_SECURITY: no signature algorithm set\n"); return 0; } } diff --git a/src/r_session/r_session_crypto.h b/src/r_session/r_session_crypto.h index d7a76a48..86fa254d 100644 --- a/src/r_session/r_session_crypto.h +++ b/src/r_session/r_session_crypto.h @@ -32,6 +32,9 @@ LIB61850_INTERNAL bool RSessionCrypto_createHMAC(uint8_t* buffer, int bufSize, uint8_t* key, int keySize, uint8_t* hmac, int hmacMaxSize); +LIB61850_INTERNAL bool +RSessionCrypto_createAES_GMAC(uint8_t* key, int keySize, uint8_t* iv, int ivSize, uint8_t* addData, int addDataSize, uint8_t* tag, int tagSize); + LIB61850_INTERNAL 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); diff --git a/src/r_session/r_session_crypto_mbedtls.c b/src/r_session/r_session_crypto_mbedtls.c index ae31b34e..f5e94fd4 100644 --- a/src/r_session/r_session_crypto_mbedtls.c +++ b/src/r_session/r_session_crypto_mbedtls.c @@ -72,6 +72,39 @@ RSessionCrypto_createHMAC(uint8_t* buffer, int bufSize, uint8_t* key, int keySiz 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, addData, addDataSize)) + { + printf("AES-GCM: Failed to start tag calculation\n"); + mbedtls_gcm_free(&gcmCtx); + return false; + } + + if (mbedtls_gcm_finish(&gcmCtx, 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) { From 8316bdebeb3f70360d8db1e0e20514044c55ebcc Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Mon, 17 Feb 2025 22:14:23 +0000 Subject: [PATCH 2/4] - L2 GOOSE/SMV security: finished implementation of AES-GMAC support (LIB61850-446) --- src/goose/goose_sec.c | 135 +++++++++++++++++++++++++++++++++------- src/goose/l2_security.h | 6 +- 2 files changed, 114 insertions(+), 27 deletions(-) diff --git a/src/goose/goose_sec.c b/src/goose/goose_sec.c index 4fa55945..775744c1 100644 --- a/src/goose/goose_sec.c +++ b/src/goose/goose_sec.c @@ -1,3 +1,26 @@ +/* + * goose_sec.c + * + * 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 #include @@ -6,7 +29,8 @@ #include "ber_decode.h" #include "r_session_crypto.h" -struct sL2Security { +struct sL2Security +{ RSignatureAlgorithm currentSigAlgo; uint32_t timeOfCurrentKey; @@ -73,6 +97,16 @@ L2Security_calculateCRC16(uint8_t* data, int size) return calculateCRC(data, size); } +static void +printBuffer(uint8_t* buffer, int size) +{ + for (int i = 0; i < size; i++) + { + printf("%02x", buffer[i]); + } + printf("\n"); +} + /** * \brief Create the security extension * @@ -88,9 +122,9 @@ L2Security_addSecurityExtension(L2Security self, uint8_t* buffer, int start, int printf("L2Security_addSecurityExtension: start=%i, length=%i, maxBufSize=%i\n", start, length, maxBufSize); if (self->currentSigAlgo != MC_SEC_SIG_ALGO_NONE) { - bool hasIV = false; int ivSize = 0; int mACSize = 0; + uint8_t* ivBuf = NULL; /* determine length of the mAC */ if (self->currentSigAlgo == MC_SEC_SIG_ALGO_HMAC_SHA256_128) { @@ -99,11 +133,13 @@ L2Security_addSecurityExtension(L2Security self, uint8_t* buffer, int start, int else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_HMAC_SHA256_256) { mACSize = 2 + 32; } - else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_64) { - mACSize = 2 + 8; - } else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_128) { mACSize = 2 + 16; + ivSize = 12; + } + else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_256) { + mACSize = 2 + 32; + ivSize = 12; } else { /* signature algorithm not supported */ @@ -126,7 +162,8 @@ L2Security_addSecurityExtension(L2Security self, uint8_t* buffer, int start, int authValueSize += (2 + BerEncoder_Int32determineEncodedSize(self->timeToNextKey)); /* IV */ - if (hasIV) { + if (ivSize > 0) + { authValueSize += (2 + ivSize); } @@ -164,14 +201,16 @@ L2Security_addSecurityExtension(L2Security self, uint8_t* buffer, int start, int bufPos = BerEncoder_encodeInt32WithTL(0x82, self->timeToNextKey, buffer, bufPos); /* IV */ - if (hasIV) { - //TODO encode IV + if (ivSize > 0) + { + bufPos = BerEncoder_encodeTL(0x83, ivSize, buffer, bufPos); + ivBuf = buffer + bufPos; + bufPos += ivSize; } /* KeyID */ bufPos = BerEncoder_encodeInt32WithTL(0x84, self->currentKeyId, buffer, bufPos); - int macEnd = bufPos; /* encode mAC */ @@ -185,39 +224,33 @@ L2Security_addSecurityExtension(L2Security self, uint8_t* buffer, int start, int RSessionCrypto_createHMAC(buffer + start, macEnd - start, self->currentKey, self->currentKeySize, buffer + bufPos, 32); bufPos += 32; } - else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_64) + else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_128) { /* create IV */ - uint8_t iv[12]; - int ivSize = 12; - - if (RSessionCrypto_createRandomData(iv, ivSize) == false) { + if (RSessionCrypto_createRandomData(ivBuf, ivSize) == false) { printf("ERROR - Failed to create random IV\n"); } - if (RSessionCrypto_createAES_GMAC(self->currentKey, self->currentKeySize, iv, ivSize, buffer + start, macEnd - start, buffer + bufPos, 8) == false) + if (RSessionCrypto_createAES_GMAC(self->currentKey, self->currentKeySize, ivBuf, ivSize, buffer + start, macEnd - start, buffer + bufPos, 16) == false) { printf("ERROR - Failed to create GMAC\n"); } - bufPos += 8; + bufPos += 16; } - else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_128) + else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_256) { /* create IV */ - uint8_t iv[12]; - int ivSize = 12; - - if (RSessionCrypto_createRandomData(iv, ivSize) == false) { + if (RSessionCrypto_createRandomData(ivBuf, ivSize) == false) { printf("ERROR - Failed to create random IV\n"); } - if (RSessionCrypto_createAES_GMAC(self->currentKey, self->currentKeySize, iv, ivSize, buffer + start, macEnd - start, buffer + bufPos, 16) == false) + if (RSessionCrypto_createAES_GMAC(self->currentKey, self->currentKeySize, ivBuf, ivSize, buffer + start, macEnd - start, buffer + bufPos, 32) == false) { printf("ERROR - Failed to create GMAC\n"); } - bufPos += 16; + bufPos += 32; } else { /* signature algorithm not supported */ @@ -252,6 +285,12 @@ checkSecurityExtension(L2Security self, uint8_t* buffer, int secExtLen, uint8_t* else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_HMAC_SHA256_256) { mACSize = 2 + 32; } + else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_128) { + mACSize = 2 + 16; + } + else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_256) { + mACSize = 2 + 32; + } else { /* signature algorithm not supported */ printf("L2_SECURITY: signature algorithm not supported\n"); @@ -368,7 +407,7 @@ checkSecurityExtension(L2Security self, uint8_t* buffer, int secExtLen, uint8_t* } else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_HMAC_SHA256_256) { - printf("Algo: HMAC_SHA256_256\n"); + printf("Algo: HMAC_SHA256_256\n"); uint8_t calculatedMac[32]; @@ -380,6 +419,54 @@ checkSecurityExtension(L2Security self, uint8_t* buffer, int secExtLen, uint8_t* return false; } } + else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_128) + { + printf("Algo: AES_GMAC_128\n"); + + uint8_t calculatedMac[16]; + + printf("IV: "); + printBuffer(ivBuffer, ivSize); + + printf("MAC: "); + printBuffer(mACBuffer, mACSize); + + if (RSessionCrypto_createAES_GMAC(self->currentKey, self->currentKeySize, ivBuffer, ivSize, macStart, macEnd, calculatedMac, 16) == false) + { + printf("L2_SECURITY: GMAC calculation failed\n"); + return false; + } + + if (memcmp(calculatedMac, mACBuffer, 16) != 0) + { + printf("L2_SECURITY: GMAC mismatch\n"); + return false; + } + } + else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_256) + { + printf("Algo: AES_GMAC_256\n"); + + printf("IV: "); + printBuffer(ivBuffer, ivSize); + + printf("MAC: "); + printBuffer(mACBuffer, mACSize); + + uint8_t calculatedMac[8]; + + if (RSessionCrypto_createAES_GMAC(self->currentKey, self->currentKeySize, ivBuffer, ivSize, macStart, macEnd, calculatedMac, 32) == false) + { + printf("L2_SECURITY: GMAC calculation failed\n"); + return false; + } + + if (memcmp(calculatedMac, mACBuffer, 8) != 0) + { + printf("L2_SECURITY: GMAC mismatch\n"); + return false; + } + } else { printf("L2_SECURITY: signature algorithm not supported\n"); diff --git a/src/goose/l2_security.h b/src/goose/l2_security.h index 4e0f8525..2f0533d5 100644 --- a/src/goose/l2_security.h +++ b/src/goose/l2_security.h @@ -1,7 +1,7 @@ /* * l2_security.h * - * Copyright 2022 Michael Zillgith + * Copyright 2022-2025 Michael Zillgith * * This file is part of libIEC61850. * @@ -53,8 +53,8 @@ typedef enum { MC_SEC_SIG_ALGO_HMAC_SHA256_80 = 1, MC_SEC_SIG_ALGO_HMAC_SHA256_128 = 2, MC_SEC_SIG_ALGO_HMAC_SHA256_256 = 3, - MC_SEC_SIG_ALGO_AES_GMAC_64 = 4, - MC_SEC_SIG_ALGO_AES_GMAC_128 = 5, + MC_SEC_SIG_ALGO_AES_GMAC_128 = 4, + MC_SEC_SIG_ALGO_AES_GMAC_256 = 5, MC_SEC_SIG_ALGO_HMAC_SHA3_80 = 6, MC_SEC_SIG_ALGO_HMAC_SHA3_128 = 7, MC_SEC_SIG_ALGO_HMAC_SHA3_256 = 8 From 74005ceee81f3325ad631a367b612c366f30f6ca Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Tue, 18 Feb 2025 07:14:39 +0000 Subject: [PATCH 3/4] - updated comments --- src/goose/goose_sec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/goose/goose_sec.c b/src/goose/goose_sec.c index 775744c1..b340d738 100644 --- a/src/goose/goose_sec.c +++ b/src/goose/goose_sec.c @@ -1,5 +1,5 @@ /* - * goose_sec.c + * l2_security.c * * Copyright 2013-2025 Michael Zillgith * @@ -135,11 +135,11 @@ L2Security_addSecurityExtension(L2Security self, uint8_t* buffer, int start, int } else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_128) { mACSize = 2 + 16; - ivSize = 12; + ivSize = 12; /* IV size for AES GMAC (recommendation from NIST: https://web.cs.ucdavis.edu/~rogaway/ocb/gcm.pdf) */ } else if (self->currentSigAlgo == MC_SEC_SIG_ALGO_AES_GMAC_256) { mACSize = 2 + 32; - ivSize = 12; + ivSize = 12; /* IV size for AES GMAC (recommendation from NIST: https://web.cs.ucdavis.edu/~rogaway/ocb/gcm.pdf) */ } else { /* signature algorithm not supported */ From d5f3db4091f077cf5fcd2fc250dadabef5f60451 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Tue, 18 Feb 2025 07:16:03 +0000 Subject: [PATCH 4/4] - update GOOSE pub/sub examples --- examples/goose_publisher/goose_publisher_example.c | 3 ++- examples/goose_subscriber/goose_subscriber_example.c | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/goose_publisher/goose_publisher_example.c b/examples/goose_publisher/goose_publisher_example.c index 083cfa59..ec89fc90 100644 --- a/examples/goose_publisher/goose_publisher_example.c +++ b/examples/goose_publisher/goose_publisher_example.c @@ -62,7 +62,8 @@ main(int argc, char **argv) L2Security l2Sec = L2Security_create(); - L2Security_addKey(l2Sec, 0x12345678, (uint8_t*)key, 16, MC_SEC_SEC_ALGO_NONE, MC_SEC_SIG_ALGO_HMAC_SHA256_256); + //L2Security_addKey(l2Sec, 0x12345678, (uint8_t*)key, 16, MC_SEC_SEC_ALGO_NONE, MC_SEC_SIG_ALGO_HMAC_SHA256_256); + L2Security_addKey(l2Sec, 0x12345678, (uint8_t*)key, 16, MC_SEC_SEC_ALGO_NONE, MC_SEC_SIG_ALGO_AES_GMAC_128); L2Security_setActiveKey(l2Sec, 1); GoosePublisher_setL2Security(publisher, l2Sec); diff --git a/examples/goose_subscriber/goose_subscriber_example.c b/examples/goose_subscriber/goose_subscriber_example.c index 3edd3db0..ff767206 100644 --- a/examples/goose_subscriber/goose_subscriber_example.c +++ b/examples/goose_subscriber/goose_subscriber_example.c @@ -65,12 +65,13 @@ main(int argc, char** argv) GooseSubscriber_setDstMac(subscriber, dstMac); GooseSubscriber_setAppId(subscriber, 1000); - //char* key = "0123456789ABCDEF"; - char* key = "0123456789ABCDEG"; + char* key = "0123456789ABCDEF"; + //char* key = "0123456789ABCDEG"; L2Security l2Sec = L2Security_create(); - L2Security_addKey(l2Sec, 0x12345678, (uint8_t*)key, 16, MC_SEC_SEC_ALGO_NONE, MC_SEC_SIG_ALGO_HMAC_SHA256_256); + //L2Security_addKey(l2Sec, 0x12345678, (uint8_t*)key, 16, MC_SEC_SEC_ALGO_NONE, MC_SEC_SIG_ALGO_HMAC_SHA256_256); + L2Security_addKey(l2Sec, 0x12345678, (uint8_t*)key, 16, MC_SEC_SEC_ALGO_NONE, MC_SEC_SIG_ALGO_AES_GMAC_128); L2Security_setActiveKey(l2Sec, 1); GooseReceiver_setL2Security(receiver, l2Sec);