diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 00000000..1b218504 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,57 @@ +name: Static Analysis + +on: + pull_request: + branches: [ main, master ] + push: + branches: [ main, master ] + +jobs: + cppcheck: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install cppcheck + run: | + sudo apt-get update + sudo apt-get install -y cppcheck + + - name: Run cppcheck + id: cppcheck + continue-on-error: true + run: | + chmod +x tools/static-analysis/run_cppcheck.sh + tools/static-analysis/run_cppcheck.sh + + - name: Display errors and warnings + if: always() + run: | + if [ -f tools/static-analysis/reports/cppcheck_summary.txt ]; then + ERROR_COUNT=$(grep -c "error:" tools/static-analysis/reports/cppcheck_summary.txt 2>/dev/null) || ERROR_COUNT=0 + WARNING_COUNT=$(grep -c "warning:" tools/static-analysis/reports/cppcheck_summary.txt 2>/dev/null) || WARNING_COUNT=0 + STYLE_COUNT=$(grep -c "style:" tools/static-analysis/reports/cppcheck_summary.txt 2>/dev/null) || STYLE_COUNT=0 + + echo "## Static Analysis Summary" + echo "- Errors: $ERROR_COUNT" + echo "- Warnings: $WARNING_COUNT" + echo "- Style issues: $STYLE_COUNT (informational only)" + + if [ "$ERROR_COUNT" -gt 0 ] || [ "$WARNING_COUNT" -gt 0 ]; then + echo "" + echo "### Issues that must be fixed:" + echo "" + # Show only errors and warnings, not style issues + grep -E "(error|warning):" tools/static-analysis/reports/cppcheck_summary.txt || true + fi + else + echo "⚠️ No cppcheck summary file found" + fi + + - name: Fail if issues found + if: steps.cppcheck.outcome == 'failure' + run: | + echo "❌ Static analysis failed - errors or warnings were found" + exit 1 diff --git a/.gitignore b/.gitignore index 1015f64b..b42a8f3d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,16 @@ -.DS_Store -Build/ -*.o -*.a -*.la -**/.gdb_history -tools/testcertgen/ca/ -tools/testcertgen/*.der -*.code-workspace -.vscode - +.DS_Store +Build/ +*.o +*.a +*.la +**/.gdb_history +tools/testcertgen/ca/ +tools/testcertgen/*.der +*.code-workspace +.vscode + +# Static analysis reports +tools/static-analysis/reports/ +*.xml +*.html + diff --git a/src/wh_client.c b/src/wh_client.c index 28bed4f8..1ed60964 100644 --- a/src/wh_client.c +++ b/src/wh_client.c @@ -97,10 +97,12 @@ int wh_Client_Init(whClientContext* c, const whClientConfig* config) } #ifdef WOLFHSM_CFG_DMA - rc = wc_CryptoCb_RegisterDevice(WH_DEV_ID_DMA, - wh_Client_CryptoCbDma, c); - if (rc != 0) { - rc = WH_ERROR_ABORTED; + if (rc == 0) { + rc = wc_CryptoCb_RegisterDevice(WH_DEV_ID_DMA, + wh_Client_CryptoCbDma, c); + if (rc != 0) { + rc = WH_ERROR_ABORTED; + } } #endif /* WOLFHSM_CFG_DMA */ } @@ -1498,4 +1500,4 @@ int wh_Client_KeyExportDma(whClientContext* c, uint16_t keyId, #endif /* WOLFHSM_CFG_DMA */ -#endif /* WOLFHSM_CFG_ENABLE_CLIENT */ \ No newline at end of file +#endif /* WOLFHSM_CFG_ENABLE_CLIENT */ diff --git a/src/wh_client_she.c b/src/wh_client_she.c index 32a45788..1d5cfa29 100644 --- a/src/wh_client_she.c +++ b/src/wh_client_she.c @@ -120,11 +120,9 @@ int wh_Client_SheSecureBoot(whClientContext* c, uint8_t* bootloader, { int ret; uint32_t bootloaderSent = 0; - uint32_t justSent = 0; uint16_t group; uint16_t action; uint16_t dataSz; - uint8_t* in; uint8_t* respBuf; whMessageShe_SecureBootInitRequest* initReq = NULL; @@ -141,9 +139,6 @@ int wh_Client_SheSecureBoot(whClientContext* c, uint8_t* bootloader, (whMessageShe_SecureBootInitRequest*)wh_CommClient_GetDataPtr(c->comm); respBuf = (uint8_t*)wh_CommClient_GetDataPtr(c->comm); - /* in is after the size argument */ - in = (uint8_t*)(initReq + 1); - /* send init sub command */ initReq->sz = bootloaderLen; ret = @@ -159,6 +154,9 @@ int wh_Client_SheSecureBoot(whClientContext* c, uint8_t* bootloader, /* send update sub command until we've sent the entire bootloader */ while (ret == 0 && bootloaderSent < bootloaderLen) { + uint8_t* in; + uint32_t justSent; + if (initResp->rc != WH_SHE_ERC_NO_ERROR) { return initResp->rc; } diff --git a/src/wh_nvm_flash.c b/src/wh_nvm_flash.c index 6b68c84e..04a1c1a2 100644 --- a/src/wh_nvm_flash.c +++ b/src/wh_nvm_flash.c @@ -442,6 +442,12 @@ static int nfPartition_ProgramCount(whNvmFlashContext* context, static int nfPartition_ProgramInit(whNvmFlashContext* context, int partition) { + int ret = 0; + + if ((context == NULL) || (context->cb == NULL)) { + return WH_ERROR_BADARGS; + } + /* Valid initial state values for a partition */ nfMemState init_state = { @@ -450,11 +456,6 @@ static int nfPartition_ProgramInit(whNvmFlashContext* context, int partition) .start = NF_PARTITION_DATA_OFFSET, .count = context->partition_units, }; - int ret = 0; - - if ((context == NULL) || (context->cb == NULL)) { - return WH_ERROR_BADARGS; - } /* Blankcheck/Erase partition */ ret = nfPartition_BlankCheck(context, partition); @@ -735,12 +736,11 @@ static int nfObject_Copy(whNvmFlashContext* context, int object_index, } ret = nfObject_ProgramFinish(context, partition, dest_object, data_len); if (ret != 0) return ret; + dest_object++; + *inout_next_object = dest_object; + *inout_next_data = dest_data; - if (ret == 0) { - *inout_next_object = dest_object; - *inout_next_data = dest_data; - } return ret; } diff --git a/src/wh_she_crypto.c b/src/wh_she_crypto.c index 3f189359..bbf13d6b 100644 --- a/src/wh_she_crypto.c +++ b/src/wh_she_crypto.c @@ -1,259 +1,256 @@ -/* - * Copyright (C) 2024 wolfSSL Inc. - * - * This file is part of wolfHSM. - * - * wolfHSM 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. - * - * wolfHSM 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 wolfHSM. If not, see . - */ -/* - * src/wh_she_crypto.c - * - */ - -/* Pick up compile-time configuration */ -#include "wolfhsm/wh_settings.h" - -#ifdef WOLFHSM_CFG_SHE_EXTENSION -#ifndef WOLFHSM_CFG_NO_CRYPTO - -/* System libraries */ -#include -#include /* For NULL */ -#include /* For memset, memcpy */ - - -#include "wolfssl/wolfcrypt/settings.h" -#include "wolfssl/wolfcrypt/types.h" -#include "wolfssl/wolfcrypt/error-crypt.h" -#include "wolfssl/wolfcrypt/wc_port.h" -#include "wolfssl/wolfcrypt/aes.h" -#include "wolfssl/wolfcrypt/cmac.h" - -#include "wolfhsm/wh_common.h" -#include "wolfhsm/wh_error.h" -#include "wolfhsm/wh_utils.h" - -#include "wolfhsm/wh_she_common.h" -#include "wolfhsm/wh_she_crypto.h" - -static const uint8_t _SHE_KEY_UPDATE_ENC_C[] = WH_SHE_KEY_UPDATE_ENC_C; -static const uint8_t _SHE_KEY_UPDATE_MAC_C[] = WH_SHE_KEY_UPDATE_MAC_C; - -int wh_She_AesMp16_ex(Aes* aes, void* heap, int devid, - uint8_t* in, word32 inSz, uint8_t* out) -{ - int ret; - int i = 0; - int j; - uint8_t paddedInput[AES_BLOCK_SIZE]; - uint8_t messageZero[WH_SHE_KEY_SZ] = {0}; - /* check valid inputs */ - if (aes == NULL || in == NULL || inSz == 0 || out == NULL) - return WH_ERROR_BADARGS; - ret = wc_AesInit(aes, heap, devid); - /* do the first block with messageZero as the key */ - if (ret == 0) { - ret = wc_AesSetKeyDirect(aes, messageZero, AES_BLOCK_SIZE, NULL, - AES_ENCRYPTION); - } - while (ret == 0 && i < (int)inSz) { - /* copy a block and pad it if we're short */ - if ((int)inSz - i < (int)AES_BLOCK_SIZE) { - memcpy(paddedInput, in + i, inSz - i); - memset(paddedInput + inSz - i, 0, AES_BLOCK_SIZE - (inSz - i)); - } - else - memcpy(paddedInput, in + i, AES_BLOCK_SIZE); - /* encrypt this block */ - ret = wc_AesEncryptDirect(aes, out, paddedInput); - /* xor with the original message and then the previous block */ - for (j = 0; j < (int)AES_BLOCK_SIZE; j++) { - out[j] ^= paddedInput[j]; - /* use messageZero as our previous output buffer */ - out[j] ^= messageZero[j]; - } - /* set the key for the next block */ - if (ret == 0) { - ret = wc_AesSetKeyDirect(aes, out, AES_BLOCK_SIZE, - NULL, AES_ENCRYPTION); - } - if (ret == 0) { - /* store previous output in messageZero */ - memcpy(messageZero, out, AES_BLOCK_SIZE); - /* increment to next block */ - i += AES_BLOCK_SIZE; - } - } - /* free aes for protection */ - wc_AesFree(aes); - return ret; -} - -static int wh_AesMp16(uint8_t* in, word32 inSz, uint8_t* out) -{ - Aes aes[1]; - return wh_She_AesMp16_ex(aes, NULL, INVALID_DEVID, in, inSz, out); -} - -int wh_She_GenerateLoadableKey(uint8_t keyId, - uint8_t authKeyId, uint32_t count, uint32_t flags, uint8_t* uid, - uint8_t* key, uint8_t* authKey, uint8_t* messageOne, uint8_t* messageTwo, - uint8_t* messageThree, uint8_t* messageFour, uint8_t* messageFive) -{ - int ret = 0; - uint32_t field; - uint8_t tmpKey[WH_SHE_KEY_SZ]; - uint8_t cmacOutput[AES_BLOCK_SIZE]; - uint8_t kdfInput[WH_SHE_KEY_SZ * 2]; - Cmac cmac[1]; - Aes aes[1]; - - if (uid == NULL || key == NULL || authKey == NULL || messageOne == NULL || - messageTwo == NULL || messageThree == NULL || messageFour == NULL || - messageFive == NULL || keyId > WH_SHE_PRNG_SEED_ID || - authKeyId > WH_SHE_PRNG_SEED_ID) { - return WH_ERROR_BADARGS; - } - - /* Build KDF input for K1. add authKey to kdfInput */ - memcpy(kdfInput, authKey, WH_SHE_KEY_SZ); - /* add _SHE_KEY_UPDATE_ENC_C to the input */ - memcpy(kdfInput + WH_SHE_KEY_SZ, _SHE_KEY_UPDATE_ENC_C, - sizeof(_SHE_KEY_UPDATE_ENC_C)); - /* generate K1 */ - ret = wh_AesMp16(kdfInput, - WH_SHE_KEY_SZ + sizeof(_SHE_KEY_UPDATE_ENC_C), tmpKey); - - /* Build M1. set UID, key id and authId */ - if (ret == 0) { - memcpy(messageOne, uid, WH_SHE_UID_SZ); - messageOne[WH_SHE_M1_KID_OFFSET] = - (keyId << WH_SHE_M1_KID_SHIFT) | - (authKeyId << WH_SHE_M1_AID_SHIFT); - } - - /* build cleartext M2 */ - if (ret == 0) { - /* set the counter, flags and key */ - memset(messageTwo, 0, WH_SHE_M2_SZ); - *((uint32_t*)messageTwo) = wh_Utils_htonl( - (count << WH_SHE_M2_COUNT_SHIFT) | - (flags << WH_SHE_M2_FLAGS_SHIFT) ); - memcpy(messageTwo + WH_SHE_M2_KEY_OFFSET, key, WH_SHE_KEY_SZ); - } - /* encrypt M2 with K1 */ - if (ret == 0) { - ret = wc_AesInit(aes, NULL, INVALID_DEVID); - if (ret == 0) { - ret = wc_AesSetKey(aes, tmpKey, WH_SHE_KEY_SZ, NULL, - AES_ENCRYPTION); - if (ret == 0) { - /* copy the key to cmacOutput before it gets encrypted */ - memcpy(cmacOutput, messageTwo + WH_SHE_M2_KEY_OFFSET, - WH_SHE_KEY_SZ); - ret = - wc_AesCbcEncrypt(aes, messageTwo, messageTwo, WH_SHE_M2_SZ); - } - /* free aes for protection */ - wc_AesFree(aes); - } - } - - /* Update KDF input to create K2 */ - if (ret == 0) { - /* add _SHE_KEY_UPDATE_MAC_C to the input */ - memcpy(kdfInput + WH_SHE_KEY_SZ, _SHE_KEY_UPDATE_MAC_C, - sizeof(_SHE_KEY_UPDATE_MAC_C)); - /* generate K2 */ - ret = wh_AesMp16(kdfInput, - WH_SHE_KEY_SZ + sizeof(_SHE_KEY_UPDATE_MAC_C), tmpKey); - } - - /* cmac messageOne and messageTwo using K2 as the cmac key */ - if (ret == 0) { - ret = wc_InitCmac_ex(cmac, tmpKey, WH_SHE_KEY_SZ, - WC_CMAC_AES, NULL, NULL, INVALID_DEVID); - } - /* hash M1 | M2 */ - if (ret == 0) - ret = wc_CmacUpdate(cmac, messageOne, WH_SHE_M1_SZ); - if (ret == 0) - ret = wc_CmacUpdate(cmac, messageTwo, WH_SHE_M2_SZ); - /* get the digest */ - if (ret == 0) { - field = AES_BLOCK_SIZE; - ret = wc_CmacFinal(cmac, messageThree, (word32*)&field); - } - - /* Update the kdf input to create K3 */ - if (ret == 0) { - /* copy the ram key to kdfInput */ - memcpy(kdfInput, cmacOutput, WH_SHE_KEY_SZ); - /* add _SHE_KEY_UPDATE_ENC_C to the input */ - memcpy(kdfInput + WH_SHE_KEY_SZ, _SHE_KEY_UPDATE_ENC_C, - sizeof(_SHE_KEY_UPDATE_ENC_C)); - /* generate K3 */ - ret = wh_AesMp16(kdfInput, - WH_SHE_KEY_SZ + sizeof(_SHE_KEY_UPDATE_ENC_C), tmpKey); - } - - /* Create M4 using K3 as encryption key */ - if (ret == 0) { - memset(messageFour, 0, WH_SHE_M4_SZ); - /* set UID, key id and authId */ - memcpy(messageFour, uid, WH_SHE_UID_SZ); - messageFour[WH_SHE_M4_KID_OFFSET] = - (keyId << WH_SHE_M4_KID_SHIFT) | - (authKeyId << WH_SHE_M4_AID_SHIFT); - /* set counter, pad with 1 bit */ - *((uint32_t*)(messageFour + WH_SHE_M4_COUNT_OFFSET)) = - wh_Utils_htonl( (count << WH_SHE_M4_COUNT_SHIFT) | - (WH_SHE_M4_COUNT_PAD) ); - - ret = wc_AesInit(aes, NULL, INVALID_DEVID); - if (ret == 0) { - ret = wc_AesSetKey(aes, tmpKey, WH_SHE_KEY_SZ, NULL, - AES_ENCRYPTION); - if (ret == 0) { - /* encrypt the new counter */ - ret = wc_AesEncryptDirect(aes, - messageFour + WH_SHE_M4_COUNT_OFFSET, - messageFour + WH_SHE_M4_COUNT_OFFSET); - } - /* free aes for protection */ - wc_AesFree(aes); - } - } - - if (ret == 0) { - /* add _SHE_KEY_UPDATE_MAC_C to the kdf input */ - memcpy(kdfInput + WH_SHE_KEY_SZ, _SHE_KEY_UPDATE_MAC_C, - sizeof(_SHE_KEY_UPDATE_MAC_C)); - /* generate K4 */ - ret = wh_AesMp16(kdfInput, - WH_SHE_KEY_SZ + sizeof(_SHE_KEY_UPDATE_MAC_C), tmpKey); - } - /* Build M5 as cmac messageFour using K4 as the cmac key */ - if (ret == 0) { - field = AES_BLOCK_SIZE; - ret = wc_AesCmacGenerate_ex(cmac, messageFive, (word32*)&field, - messageFour, WH_SHE_M4_SZ, tmpKey, WH_SHE_KEY_SZ, NULL, - INVALID_DEVID); - } - return ret; -} - -#endif /* !WOLFHSM_CFG_NO_CRYPTO */ -#endif /* WOLFHSM_CFG_SHE_EXTENSION */ - +/* + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM 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. + * + * wolfHSM 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 wolfHSM. If not, see . + */ +/* + * src/wh_she_crypto.c + * + */ + +/* Pick up compile-time configuration */ +#include "wolfhsm/wh_settings.h" + +#ifdef WOLFHSM_CFG_SHE_EXTENSION +#ifndef WOLFHSM_CFG_NO_CRYPTO + +/* System libraries */ +#include +#include /* For NULL */ +#include /* For memset, memcpy */ + + +#include "wolfssl/wolfcrypt/settings.h" +#include "wolfssl/wolfcrypt/types.h" +#include "wolfssl/wolfcrypt/error-crypt.h" +#include "wolfssl/wolfcrypt/wc_port.h" +#include "wolfssl/wolfcrypt/aes.h" +#include "wolfssl/wolfcrypt/cmac.h" + +#include "wolfhsm/wh_common.h" +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_utils.h" + +#include "wolfhsm/wh_she_common.h" +#include "wolfhsm/wh_she_crypto.h" + +static const uint8_t _SHE_KEY_UPDATE_ENC_C[] = WH_SHE_KEY_UPDATE_ENC_C; +static const uint8_t _SHE_KEY_UPDATE_MAC_C[] = WH_SHE_KEY_UPDATE_MAC_C; + +int wh_She_AesMp16_ex(Aes* aes, void* heap, int devid, + uint8_t* in, word32 inSz, uint8_t* out) +{ + int ret; + int i = 0; + int j; + uint8_t paddedInput[AES_BLOCK_SIZE]; + uint8_t messageZero[WH_SHE_KEY_SZ] = {0}; + /* check valid inputs */ + if (aes == NULL || in == NULL || inSz == 0 || out == NULL) + return WH_ERROR_BADARGS; + ret = wc_AesInit(aes, heap, devid); + /* do the first block with messageZero as the key */ + if (ret == 0) { + ret = wc_AesSetKeyDirect(aes, messageZero, AES_BLOCK_SIZE, NULL, + AES_ENCRYPTION); + } + while (ret == 0 && i < (int)inSz) { + /* copy a block and pad it if we're short */ + if ((int)inSz - i < (int)AES_BLOCK_SIZE) { + memcpy(paddedInput, in + i, inSz - i); + memset(paddedInput + inSz - i, 0, AES_BLOCK_SIZE - (inSz - i)); + } + else + memcpy(paddedInput, in + i, AES_BLOCK_SIZE); + /* encrypt this block */ + ret = wc_AesEncryptDirect(aes, out, paddedInput); + /* xor with the original message and then the previous block */ + for (j = 0; j < (int)AES_BLOCK_SIZE; j++) { + out[j] ^= paddedInput[j]; + /* use messageZero as our previous output buffer */ + out[j] ^= messageZero[j]; + } + /* set the key for the next block */ + if (ret == 0) { + ret = wc_AesSetKeyDirect(aes, out, AES_BLOCK_SIZE, + NULL, AES_ENCRYPTION); + } + if (ret == 0) { + /* store previous output in messageZero */ + memcpy(messageZero, out, AES_BLOCK_SIZE); + /* increment to next block */ + i += AES_BLOCK_SIZE; + } + } + /* free aes for protection */ + wc_AesFree(aes); + return ret; +} + +static int wh_AesMp16(uint8_t* in, word32 inSz, uint8_t* out) +{ + Aes aes[1]; + return wh_She_AesMp16_ex(aes, NULL, INVALID_DEVID, in, inSz, out); +} + +int wh_She_GenerateLoadableKey(uint8_t keyId, + uint8_t authKeyId, uint32_t count, uint32_t flags, uint8_t* uid, + uint8_t* key, uint8_t* authKey, uint8_t* messageOne, uint8_t* messageTwo, + uint8_t* messageThree, uint8_t* messageFour, uint8_t* messageFive) +{ + int ret = 0; + uint32_t field; + uint8_t tmpKey[WH_SHE_KEY_SZ]; + uint8_t cmacOutput[AES_BLOCK_SIZE]; + uint8_t kdfInput[WH_SHE_KEY_SZ * 2]; + Cmac cmac[1]; + Aes aes[1]; + + if (uid == NULL || key == NULL || authKey == NULL || messageOne == NULL || + messageTwo == NULL || messageThree == NULL || messageFour == NULL || + messageFive == NULL || keyId > WH_SHE_PRNG_SEED_ID || + authKeyId > WH_SHE_PRNG_SEED_ID) { + return WH_ERROR_BADARGS; + } + + /* Build KDF input for K1. add authKey to kdfInput */ + memcpy(kdfInput, authKey, WH_SHE_KEY_SZ); + /* add _SHE_KEY_UPDATE_ENC_C to the input */ + memcpy(kdfInput + WH_SHE_KEY_SZ, _SHE_KEY_UPDATE_ENC_C, + sizeof(_SHE_KEY_UPDATE_ENC_C)); + /* generate K1 */ + ret = wh_AesMp16(kdfInput, + WH_SHE_KEY_SZ + sizeof(_SHE_KEY_UPDATE_ENC_C), tmpKey); + + /* Build M1 and cleartext M2, then encrypt M2 with K1 */ + if (ret == 0) { + /* Build M1: set UID, key id and authId */ + memcpy(messageOne, uid, WH_SHE_UID_SZ); + messageOne[WH_SHE_M1_KID_OFFSET] = + (keyId << WH_SHE_M1_KID_SHIFT) | + (authKeyId << WH_SHE_M1_AID_SHIFT); + + /* Build cleartext M2: set the counter, flags and key */ + memset(messageTwo, 0, WH_SHE_M2_SZ); + *((uint32_t*)messageTwo) = wh_Utils_htonl( + (count << WH_SHE_M2_COUNT_SHIFT) | + (flags << WH_SHE_M2_FLAGS_SHIFT) ); + memcpy(messageTwo + WH_SHE_M2_KEY_OFFSET, key, WH_SHE_KEY_SZ); + + /* encrypt M2 with K1 */ + ret = wc_AesInit(aes, NULL, INVALID_DEVID); + if (ret == 0) { + ret = wc_AesSetKey(aes, tmpKey, WH_SHE_KEY_SZ, NULL, + AES_ENCRYPTION); + if (ret == 0) { + /* copy the key to cmacOutput before it gets encrypted */ + memcpy(cmacOutput, messageTwo + WH_SHE_M2_KEY_OFFSET, + WH_SHE_KEY_SZ); + ret = + wc_AesCbcEncrypt(aes, messageTwo, messageTwo, WH_SHE_M2_SZ); + } + /* free aes for protection */ + wc_AesFree(aes); + } + } + + /* Update KDF input to create K2 */ + if (ret == 0) { + /* add _SHE_KEY_UPDATE_MAC_C to the input */ + memcpy(kdfInput + WH_SHE_KEY_SZ, _SHE_KEY_UPDATE_MAC_C, + sizeof(_SHE_KEY_UPDATE_MAC_C)); + /* generate K2 */ + ret = wh_AesMp16(kdfInput, + WH_SHE_KEY_SZ + sizeof(_SHE_KEY_UPDATE_MAC_C), tmpKey); + } + + /* cmac messageOne and messageTwo using K2 as the cmac key */ + if (ret == 0) { + ret = wc_InitCmac_ex(cmac, tmpKey, WH_SHE_KEY_SZ, + WC_CMAC_AES, NULL, NULL, INVALID_DEVID); + } + /* hash M1 | M2 */ + if (ret == 0) + ret = wc_CmacUpdate(cmac, messageOne, WH_SHE_M1_SZ); + if (ret == 0) + ret = wc_CmacUpdate(cmac, messageTwo, WH_SHE_M2_SZ); + /* get the digest */ + if (ret == 0) { + field = AES_BLOCK_SIZE; + ret = wc_CmacFinal(cmac, messageThree, (word32*)&field); + } + + /* Update the kdf input to create K3 */ + if (ret == 0) { + /* copy the ram key to kdfInput */ + memcpy(kdfInput, cmacOutput, WH_SHE_KEY_SZ); + /* add _SHE_KEY_UPDATE_ENC_C to the input */ + memcpy(kdfInput + WH_SHE_KEY_SZ, _SHE_KEY_UPDATE_ENC_C, + sizeof(_SHE_KEY_UPDATE_ENC_C)); + /* generate K3 */ + ret = wh_AesMp16(kdfInput, + WH_SHE_KEY_SZ + sizeof(_SHE_KEY_UPDATE_ENC_C), tmpKey); + } + + /* Create M4 using K3 as encryption key */ + if (ret == 0) { + memset(messageFour, 0, WH_SHE_M4_SZ); + /* set UID, key id and authId */ + memcpy(messageFour, uid, WH_SHE_UID_SZ); + messageFour[WH_SHE_M4_KID_OFFSET] = + (keyId << WH_SHE_M4_KID_SHIFT) | + (authKeyId << WH_SHE_M4_AID_SHIFT); + /* set counter, pad with 1 bit */ + *((uint32_t*)(messageFour + WH_SHE_M4_COUNT_OFFSET)) = + wh_Utils_htonl( (count << WH_SHE_M4_COUNT_SHIFT) | + (WH_SHE_M4_COUNT_PAD) ); + + ret = wc_AesInit(aes, NULL, INVALID_DEVID); + if (ret == 0) { + ret = wc_AesSetKey(aes, tmpKey, WH_SHE_KEY_SZ, NULL, + AES_ENCRYPTION); + if (ret == 0) { + /* encrypt the new counter */ + ret = wc_AesEncryptDirect(aes, + messageFour + WH_SHE_M4_COUNT_OFFSET, + messageFour + WH_SHE_M4_COUNT_OFFSET); + } + /* free aes for protection */ + wc_AesFree(aes); + } + } + + if (ret == 0) { + /* add _SHE_KEY_UPDATE_MAC_C to the kdf input */ + memcpy(kdfInput + WH_SHE_KEY_SZ, _SHE_KEY_UPDATE_MAC_C, + sizeof(_SHE_KEY_UPDATE_MAC_C)); + /* generate K4 */ + ret = wh_AesMp16(kdfInput, + WH_SHE_KEY_SZ + sizeof(_SHE_KEY_UPDATE_MAC_C), tmpKey); + } + /* Build M5 as cmac messageFour using K4 as the cmac key */ + if (ret == 0) { + field = AES_BLOCK_SIZE; + ret = wc_AesCmacGenerate_ex(cmac, messageFive, (word32*)&field, + messageFour, WH_SHE_M4_SZ, tmpKey, WH_SHE_KEY_SZ, NULL, + INVALID_DEVID); + } + return ret; +} + +#endif /* !WOLFHSM_CFG_NO_CRYPTO */ +#endif /* WOLFHSM_CFG_SHE_EXTENSION */ + diff --git a/src/wh_transport_mem.c b/src/wh_transport_mem.c index 3fe56afa..6069341e 100644 --- a/src/wh_transport_mem.c +++ b/src/wh_transport_mem.c @@ -96,8 +96,8 @@ int wh_TransportMem_Cleanup(void* c) int wh_TransportMem_SendRequest(void* c, uint16_t len, const void* data) { whTransportMemContext* context = c; - volatile whTransportMemCsr* ctx_req = context->req; - volatile whTransportMemCsr* ctx_resp = context->resp; + volatile whTransportMemCsr* ctx_req; + volatile whTransportMemCsr* ctx_resp; whTransportMemCsr resp; whTransportMemCsr req; @@ -107,6 +107,9 @@ int wh_TransportMem_SendRequest(void* c, uint16_t len, const void* data) return WH_ERROR_BADARGS; } + ctx_req = context->req; + ctx_resp = context->resp; + /* Don't send more data than we have space for in the request buffer */ if (len > (context->req_size - sizeof(whTransportMemCsr))) { return WH_ERROR_BADARGS; @@ -142,8 +145,8 @@ int wh_TransportMem_SendRequest(void* c, uint16_t len, const void* data) int wh_TransportMem_RecvRequest(void* c, uint16_t *out_len, void* data) { whTransportMemContext* context = c; - volatile whTransportMemCsr* ctx_req = context->req; - volatile whTransportMemCsr* ctx_resp = context->resp; + volatile whTransportMemCsr* ctx_req; + volatile whTransportMemCsr* ctx_resp; whTransportMemCsr req; whTransportMemCsr resp; @@ -152,6 +155,9 @@ int wh_TransportMem_RecvRequest(void* c, uint16_t *out_len, void* data) return WH_ERROR_BADARGS; } + ctx_req = context->req; + ctx_resp = context->resp; + /* Read current request CSR's. ctx_resp does not need to be invalidated */ XMEMFENCE(); XCACHEINVLD(ctx_req); @@ -176,8 +182,8 @@ int wh_TransportMem_RecvRequest(void* c, uint16_t *out_len, void* data) int wh_TransportMem_SendResponse(void* c, uint16_t len, const void* data) { whTransportMemContext* context = c; - volatile whTransportMemCsr* ctx_req = context->req; - volatile whTransportMemCsr* ctx_resp = context->resp; + volatile whTransportMemCsr* ctx_req; + volatile whTransportMemCsr* ctx_resp; whTransportMemCsr req; whTransportMemCsr resp; @@ -187,6 +193,9 @@ int wh_TransportMem_SendResponse(void* c, uint16_t len, const void* data) return WH_ERROR_BADARGS; } + ctx_req = context->req; + ctx_resp = context->resp; + /* Check against available data space (total size minus CSR size) */ if (len > (context->resp_size - sizeof(whTransportMemCsr))) { return WH_ERROR_BADARGS; @@ -217,8 +226,8 @@ int wh_TransportMem_SendResponse(void* c, uint16_t len, const void* data) int wh_TransportMem_RecvResponse(void* c, uint16_t *out_len, void* data) { whTransportMemContext* context = c; - volatile whTransportMemCsr* ctx_req = context->req; - volatile whTransportMemCsr* ctx_resp = context->resp; + volatile whTransportMemCsr* ctx_req; + volatile whTransportMemCsr* ctx_resp; whTransportMemCsr req; whTransportMemCsr resp; @@ -227,6 +236,9 @@ int wh_TransportMem_RecvResponse(void* c, uint16_t *out_len, void* data) return WH_ERROR_BADARGS; } + ctx_req = context->req; + ctx_resp = context->resp; + /* Read both CSR's. ctx_req does not need to be invalidated */ XMEMFENCE(); XCACHEINVLD(ctx_resp); diff --git a/tools/static-analysis/cppcheck-suppressions.txt b/tools/static-analysis/cppcheck-suppressions.txt new file mode 100644 index 00000000..a0d41239 --- /dev/null +++ b/tools/static-analysis/cppcheck-suppressions.txt @@ -0,0 +1,12 @@ +# cppcheck suppressions for wolfHSM +# Format: [error id]:[filename]:[line] (filename and line are optional) + +# System includes are not our concern +missingIncludeSystem + +# Unused functions may be part of the public API +unusedFunction + +# Const parameters and variables are often design choices +constParameter +constVariable \ No newline at end of file diff --git a/tools/static-analysis/run_cppcheck.sh b/tools/static-analysis/run_cppcheck.sh new file mode 100755 index 00000000..e142016d --- /dev/null +++ b/tools/static-analysis/run_cppcheck.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +# Simple cppcheck script for wolfHSM static analysis + +# Don't exit on error immediately since we want to handle cppcheck exit codes +set +e + +# Script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +# Output directory +OUTPUT_DIR="$SCRIPT_DIR/reports" +mkdir -p "$OUTPUT_DIR" + +# Run cppcheck with sane defaults +echo "Running cppcheck static analysis on wolfHSM..." + +# Run cppcheck and capture exit code +# Note: --error-exitcode only triggers on errors, not warnings +cppcheck \ + --enable=warning,style,performance,portability \ + --std=c99 \ + --platform=native \ + --suppressions-list="$SCRIPT_DIR/cppcheck-suppressions.txt" \ + --inline-suppr \ + --force \ + --quiet \ + --error-exitcode=1 \ + --xml \ + --xml-version=2 \ + -I "$PROJECT_ROOT/wolfhsm/" \ + -I "$PROJECT_ROOT/src/" \ + "$PROJECT_ROOT/src/" \ + "$PROJECT_ROOT/wolfhsm/" \ + 2> "$OUTPUT_DIR/cppcheck.xml" +CPPCHECK_EXIT_CODE=$? + +# Generate HTML report +echo "Generating HTML report..." +cppcheck-htmlreport \ + --source-dir="$PROJECT_ROOT" \ + --report-dir="$OUTPUT_DIR/html" \ + --file="$OUTPUT_DIR/cppcheck.xml" \ + --title="wolfHSM Static Analysis Report" + +# Also generate a simple text summary +echo "Generating text summary..." +cppcheck \ + --enable=warning,style,performance,portability \ + --std=c99 \ + --platform=native \ + --suppressions-list="$SCRIPT_DIR/cppcheck-suppressions.txt" \ + --inline-suppr \ + --force \ + --quiet \ + --template='{file}:{line}: {severity}: {message} [{id}]' \ + -I "$PROJECT_ROOT/wolfhsm/" \ + -I "$PROJECT_ROOT/src/" \ + "$PROJECT_ROOT/src/" \ + "$PROJECT_ROOT/wolfhsm/" \ + > "$OUTPUT_DIR/cppcheck_summary.txt" 2>&1 || true + +echo "Static analysis complete!" +echo "XML report: $OUTPUT_DIR/cppcheck.xml" +echo "HTML report: $OUTPUT_DIR/html/index.html" +echo "Text summary: $OUTPUT_DIR/cppcheck_summary.txt" + +# Check for warnings in addition to the exit code +WARNING_COUNT=$(grep -c "warning:" "$OUTPUT_DIR/cppcheck_summary.txt" 2>/dev/null) || WARNING_COUNT=0 +ERROR_COUNT=$(grep -c "error:" "$OUTPUT_DIR/cppcheck_summary.txt" 2>/dev/null) || ERROR_COUNT=0 + +echo "" +echo "Cppcheck returned $CPPCHECK_EXIT_CODE" +echo "Results:" +echo " Errors: $ERROR_COUNT" +echo " Warnings: $WARNING_COUNT" + +# Exit with error if we have errors (from cppcheck) or warnings +# Note: we should be able to use $CPPCHECK_EXIT_CODE here but for some reason +# it is returning 1 even with no errors in stdout. This might be a bug +if [ $ERROR_COUNT -gt 0 ] || [ $WARNING_COUNT -gt 0 ]; then + exit 1 +fi + +exit 0