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