From 7b72cf6acff7a785f330b1783526306b203c97fc Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 8 Jul 2026 16:37:08 +0200 Subject: [PATCH 1/2] riscv: add missing argument checks in AES port Align the RISC-V AES port's argument validation with the generic aes.c implementations (and with the port's own vector/scalar-crypto siblings): * wc_AesSetKey (base assembly variant, i.e. neither WOLFSSL_RISCV_VECTOR_CRYPTO_ASM nor WOLFSSL_RISCV_SCALAR_CRYPTO_ASM): reject key == NULL. The vector and scalar-crypto variants of the same function already check it; the base variant passed NULL through to the key expansion and wc_AesGcmSetKey then dereferenced the uninitialized schedule, crashing on e.g. wc_AesGcmSetKey(aes, NULL, 16). * wc_AesCcmEncrypt / wc_AesCcmDecrypt: reject authIn == NULL when authInSz > 0, as the generic implementation does. The port otherwise walks the NULL authIn buffer while computing the CBC-MAC. Found by the ISO 26262 per-module MC/DC campaign's argument-matrix tests (test_wc_AesGcmSetKey, test_wc_AesCcmArgMcdc) running the RISC-V port under qemu-riscv64: upstream CI only exercises this port with the KAT suite, which never passes invalid arguments. --- wolfcrypt/src/port/riscv/riscv-64-aes.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/port/riscv/riscv-64-aes.c b/wolfcrypt/src/port/riscv/riscv-64-aes.c index 4e1c14c842..80d3bc8dcf 100644 --- a/wolfcrypt/src/port/riscv/riscv-64-aes.c +++ b/wolfcrypt/src/port/riscv/riscv-64-aes.c @@ -2946,7 +2946,7 @@ int wc_AesSetKey(Aes* aes, const byte* key, word32 keyLen, const byte* iv, int ret = 0; /* Validate parameters. */ - if (aes == NULL) { + if ((aes == NULL) || (key == NULL)) { ret = BAD_FUNC_ARG; } /* Check key size is supported by AES object. */ @@ -9097,6 +9097,7 @@ int wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz, /* sanity check on arguments */ if ((aes == NULL) || ((inSz != 0) && ((in == NULL) || (out == NULL))) || + ((authInSz > 0) && (authIn == NULL)) || (nonce == NULL) || (authTag == NULL) || (nonceSz < 7) || (nonceSz > 13)) { ret = BAD_FUNC_ARG; @@ -9188,6 +9189,7 @@ int wc_AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz, /* sanity check on arguments */ if ((aes == NULL) || ((inSz != 0) && ((in == NULL) || (out == NULL))) || + ((authInSz > 0) && (authIn == NULL)) || (nonce == NULL) || (authTag == NULL) || (nonceSz < 7) || (nonceSz > 13)) { ret = BAD_FUNC_ARG; From fc1bb6395d46d2ec6c0f3b67d4c48a5d17bcc57a Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 8 Jul 2026 18:29:52 +0200 Subject: [PATCH 2/2] riscv: return KEYUSAGE_E for AES use without a key schedule The generic wc_AesEncrypt/wc_AesDecrypt (aes.c) reject an AES object whose key schedule was never set (rounds outside 1..7 after halving) with KEYUSAGE_E, and every mode inherits that through their int return. The RISC-V port's block helpers are void, so nothing reported unkeyed use: wc_AesEncryptDirect and wc_AesCcmEncrypt/Decrypt silently processed with a garbage schedule, and wc_AesCtrEncrypt classified it as BAD_FUNC_ARG instead of KEYUSAGE_E. Align the port with the generic error contract: * wc_AesEncryptDirect / wc_AesDecryptDirect: add the generic rounds check (also fixes wc_CmacUpdate error reporting, which goes through wc_AesEncryptDirect on this port) * wc_AesCcmEncrypt / wc_AesCcmDecrypt: same check after the argument sanity block * wc_AesCtrEncrypt (both variants): the existing rounds switch now returns KEYUSAGE_E instead of BAD_FUNC_ARG Found by the ISO 26262 MC/DC campaign argument-matrix tests (test_wc_AesSetKeyArgMcdc, test_wc_AesModesArgMcdc, test_wc_AesCcmArgMcdc, test_wc_CmacArgMcdc) under qemu-riscv64. --- wolfcrypt/src/port/riscv/riscv-64-aes.c | 34 +++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/port/riscv/riscv-64-aes.c b/wolfcrypt/src/port/riscv/riscv-64-aes.c index 80d3bc8dcf..603763cdcb 100644 --- a/wolfcrypt/src/port/riscv/riscv-64-aes.c +++ b/wolfcrypt/src/port/riscv/riscv-64-aes.c @@ -1375,8 +1375,10 @@ int wc_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz) #endif /* WOLFSSL_AES_256 */ break; default: + /* Not set or corrupted: match the generic wc_AesEncrypt + * (aes.c) behavior for an unusable key schedule. */ WOLFSSL_MSG("Bad AES-CTR round value"); - ret = BAD_FUNC_ARG; + ret = KEYUSAGE_E; } } @@ -4125,8 +4127,10 @@ int wc_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz) #endif /* WOLFSSL_AES_256 */ break; default: + /* Not set or corrupted: match the generic wc_AesEncrypt + * (aes.c) behavior for an unusable key schedule. */ WOLFSSL_MSG("Bad AES-CTR round value"); - ret = BAD_FUNC_ARG; + ret = KEYUSAGE_E; } } @@ -4236,6 +4240,12 @@ int wc_AesEncryptDirect(Aes* aes, byte* out, const byte* in) WOLFSSL_MSG("Invalid input to wc_AesEncryptDirect"); ret = BAD_FUNC_ARG; } + /* wc_AesEncrypt is void here so it cannot report an unusable key + * schedule itself; match the generic wc_AesEncrypt (aes.c) check. */ + if ((ret == 0) && + (((aes->rounds >> 1) > 7) || ((aes->rounds >> 1) == 0))) { + ret = KEYUSAGE_E; + } if (ret == 0) { wc_AesEncrypt(aes, in, out); } @@ -4259,6 +4269,12 @@ int wc_AesDecryptDirect(Aes* aes, byte* out, const byte* in) WOLFSSL_MSG("Invalid input to wc_AesDecryptDirect"); ret = BAD_FUNC_ARG; } + /* wc_AesDecrypt is void here so it cannot report an unusable key + * schedule itself; match the generic wc_AesDecrypt (aes.c) check. */ + if ((ret == 0) && + (((aes->rounds >> 1) > 7) || ((aes->rounds >> 1) == 0))) { + ret = KEYUSAGE_E; + } if (ret == 0) { wc_AesDecrypt(aes, in, out); } @@ -9102,6 +9118,13 @@ int wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz, (nonceSz > 13)) { ret = BAD_FUNC_ARG; } + /* The block cipher helpers are void here so they cannot report an + * unusable key schedule; match the generic wc_AesEncrypt (aes.c) + * check. */ + if ((ret == 0) && + (((aes->rounds >> 1) > 7) || ((aes->rounds >> 1) == 0))) { + ret = KEYUSAGE_E; + } if ((ret == 0) && (wc_AesCcmCheckTagSize(authTagSz) != 0)) { ret = BAD_FUNC_ARG; @@ -9194,6 +9217,13 @@ int wc_AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz, (nonceSz > 13)) { ret = BAD_FUNC_ARG; } + /* The block cipher helpers are void here so they cannot report an + * unusable key schedule; match the generic wc_AesEncrypt (aes.c) + * check. */ + if ((ret == 0) && + (((aes->rounds >> 1) > 7) || ((aes->rounds >> 1) == 0))) { + ret = KEYUSAGE_E; + } if ((ret == 0) && (wc_AesCcmCheckTagSize(authTagSz) != 0)) { ret = BAD_FUNC_ARG;