From f32984761c997f38f42a2501e35d76d0962253c5 Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Wed, 7 Oct 2026 11:25:01 +0900 Subject: [PATCH 1/2] Accept zero-length ciphertext in TSIP AES-GCM decrypt - Add zero-length decrypt cases to the RX72N TSIP unit test. --- .../wolfssl_demo/wolfssl_tsip_unit_test.c | 45 +++++++++++++++++-- wolfcrypt/src/port/Renesas/renesas_tsip_aes.c | 31 +++++++------ 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/wolfssl_tsip_unit_test.c b/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/wolfssl_tsip_unit_test.c index fc21332fd7e..6b9edd6784a 100644 --- a/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/wolfssl_tsip_unit_test.c +++ b/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/wolfssl_tsip_unit_test.c @@ -989,7 +989,7 @@ static void tskAes128_Gcm_Test(void *pvParam) * used to XMALLOC(0, ...) a same-sized scratch buffer for it and treat a * NULL result as an allocation failure -- whether that happened depended on * the platform allocator's handling of a zero-byte request, not on the - * actual GCM inputs. + * actual GCM inputs. Decrypt also rejected sz == 0; now it is accepted. */ static int tsip_aesgcm_zerolen_test(int prnt, int devId) { @@ -1041,9 +1041,7 @@ static int tsip_aesgcm_zerolen_test(int prnt, int devId) wc_AesGcmSetKey(dec, key, sizeof(key)); /* (a) empty payload, non-empty AAD -- used to fail because plainBuf was - * XMALLOC(0, ...)'d in wc_tsip_AesGcmEncrypt(). TSIP rejects a - * zero-length decrypt by design (unrelated to this fix), so this case - * is encrypt-only. */ + * XMALLOC(0, ...)'d in wc_tsip_AesGcmEncrypt(). */ XMEMSET(resultT, 0, sizeof(resultT)); ret = wc_AesGcmEncrypt(enc, NULL, NULL, 0, iv, sizeof(iv), resultT, sizeof(resultT), aad, sizeof(aad)); @@ -1086,6 +1084,45 @@ static int tsip_aesgcm_zerolen_test(int prnt, int devId) goto out; } + /* (d) empty payload, non-empty AAD, round trip */ + XMEMSET(resultT, 0, sizeof(resultT)); + ret = wc_AesGcmEncrypt(enc, NULL, NULL, 0, iv, sizeof(iv), + resultT, sizeof(resultT), aad, sizeof(aad)); + if (ret != 0) { + ret = -8; + goto out; + } + ret = wc_AesGcmDecrypt(dec, NULL, NULL, 0, iv, sizeof(iv), + resultT, sizeof(resultT), aad, sizeof(aad)); + if (ret != 0) { + ret = -9; + goto out; + } + + /* (e) corrupted tag must fail */ + resultT[0] ^= 0x01; + ret = wc_AesGcmDecrypt(dec, NULL, NULL, 0, iv, sizeof(iv), + resultT, sizeof(resultT), aad, sizeof(aad)); + if (ret == 0) { + ret = -10; + goto out; + } + + /* (f) empty payload and empty AAD, round trip */ + XMEMSET(resultT, 0, sizeof(resultT)); + ret = wc_AesGcmEncrypt(enc, NULL, NULL, 0, iv, sizeof(iv), + resultT, sizeof(resultT), NULL, 0); + if (ret != 0) { + ret = -11; + goto out; + } + ret = wc_AesGcmDecrypt(dec, NULL, NULL, 0, iv, sizeof(iv), + resultT, sizeof(resultT), NULL, 0); + if (ret != 0) { + ret = -12; + goto out; + } + ret = 0; out: diff --git a/wolfcrypt/src/port/Renesas/renesas_tsip_aes.c b/wolfcrypt/src/port/Renesas/renesas_tsip_aes.c index 881a6748723..724c8f1ba3d 100644 --- a/wolfcrypt/src/port/Renesas/renesas_tsip_aes.c +++ b/wolfcrypt/src/port/Renesas/renesas_tsip_aes.c @@ -993,6 +993,7 @@ int wc_tsip_AesGcmEncrypt( * - authInSz: AAD size * return 0 on success, otherwise on error. * Note: As of TSIPv1.13, only accept 128 and 256 bit of key size + * Note: sz == 0 and/or authInSz == 0 are legal (GMAC / AAD-only input) * */ int wc_tsip_AesGcmDecrypt( @@ -1026,8 +1027,8 @@ int wc_tsip_AesGcmDecrypt( WOLFSSL_ENTER("wc_tsip_AesGcmDecrypt"); - if (aes == NULL || in == NULL || out == NULL || sz == 0 || ctx == NULL || - iv == 0 || + if (aes == NULL || ctx == NULL || iv == 0 || + (sz != 0 && (in == NULL || out == NULL)) || (authInSz != 0 && authIn == NULL) || (authInSz == 0 && authIn != NULL) || (authTagSz != 0 && authTag == NULL) || @@ -1059,30 +1060,27 @@ int wc_tsip_AesGcmDecrypt( if ((ret = tsip_hw_lock()) == 0) { - /* allocate buffers for plaintext, cipher-text, authTag and AAD. - * TSIP requests those buffers 32bit aligned. - * authInSz may legally be 0 (no AAD); XMALLOC(0, ...) is - * implementation-defined and may return NULL, so skip allocating - * (and later copying into) aadBuf when there is no AAD, rather than - * treating that NULL as an allocation failure. (sz == 0 is already - * rejected by the argument validation above, so cipherBuf/plainBuf - * are never zero-size here.) + /* Allocate 32-bit aligned buffers required by TSIP. + * Skip zero-size buffers since XMALLOC(0, ...) may return NULL. + * plainBufSz is always at least one AES block. */ - cipherBuf = XMALLOC(sz, aes->heap, DYNAMIC_TYPE_AES); + if (sz != 0) + cipherBuf = XMALLOC(sz, aes->heap, DYNAMIC_TYPE_AES); plainBuf = XMALLOC(plainBufSz, aes->heap, DYNAMIC_TYPE_AES); aTagBuf = XMALLOC(TSIP_AES_GCM_AUTH_TAG_SIZE, aes->heap, DYNAMIC_TYPE_AES); if (authInSz != 0) aadBuf = XMALLOC(authInSz, aes->heap, DYNAMIC_TYPE_AES); - if (plainBuf == NULL || cipherBuf == NULL || aTagBuf == NULL || - (authInSz != 0 && aadBuf == NULL)) { + if (plainBuf == NULL || (sz != 0 && cipherBuf == NULL) || + aTagBuf == NULL || (authInSz != 0 && aadBuf == NULL)) { ret = -1; } if (ret == 0) { ForceZero(plainBuf, plainBufSz); - XMEMCPY(cipherBuf, in, sz); + if (sz != 0) + XMEMCPY(cipherBuf, in, sz); ForceZero(aTagBuf, TSIP_AES_GCM_AUTH_TAG_SIZE); XMEMCPY(aTagBuf,authTag,min(authTagSz, TSIP_AES_GCM_AUTH_TAG_SIZE)); if (authInSz != 0) @@ -1164,8 +1162,9 @@ int wc_tsip_AesGcmDecrypt( min(16, authTagSz)); /* TSIP accepts upto 16 byte */ if (err == TSIP_SUCCESS) { - /* copy plain data to out */ - XMEMCPY(out, plainBuf, sz); + /* Copy plain data to out (sz may be 0). */ + if (sz != 0) + XMEMCPY(out, plainBuf, sz); } else { WOLFSSL_MSG("R_TSIP_AesXXXGcmDecryptFinal: failed"); From 4ae1d4e77ff2bb1a9f0e8c4854a8bf5f21818b86 Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Thu, 8 Oct 2026 14:29:25 +0900 Subject: [PATCH 2/2] Add AES-256 zero-length coverage to TSIP GCM unit test --- .../wolfssl_demo/wolfssl_tsip_unit_test.c | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/wolfssl_tsip_unit_test.c b/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/wolfssl_tsip_unit_test.c index 6b9edd6784a..8a406be70be 100644 --- a/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/wolfssl_tsip_unit_test.c +++ b/IDE/Renesas/e2studio/RX72N/EnvisionKit/wolfssl_demo/wolfssl_tsip_unit_test.c @@ -982,7 +982,10 @@ static void tskAes128_Gcm_Test(void *pvParam) vTaskDelete(NULL); } #endif /* FREERTOS */ +#endif /* WOLFSSL_AES_128 && HAVE_AESGCM */ +#if defined(HAVE_AESGCM) && \ + (defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_256)) /* Regression test for zero-length payload/AAD handling in * wc_tsip_AesGcmEncrypt()/wc_tsip_AesGcmDecrypt() (renesas_tsip_aes.c): a * payload or AAD length of 0 is a legal AES-GCM input, but those functions @@ -990,8 +993,9 @@ static void tskAes128_Gcm_Test(void *pvParam) * NULL result as an allocation failure -- whether that happened depended on * the platform allocator's handling of a zero-byte request, not on the * actual GCM inputs. Decrypt also rejected sz == 0; now it is accepted. + * keySz (16 or 32) selects the TSIP AES-128 or AES-256 GCM entry points. */ -static int tsip_aesgcm_zerolen_test(int prnt, int devId) +static int tsip_aesgcm_zerolen_test(int prnt, int devId, int keySz) { Aes enc[1]; Aes dec[1]; @@ -999,7 +1003,9 @@ static int tsip_aesgcm_zerolen_test(int prnt, int devId) WOLFSSL_SMALL_STACK_STATIC const byte key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }; WOLFSSL_SMALL_STACK_STATIC const byte iv[] = @@ -1026,7 +1032,7 @@ static int tsip_aesgcm_zerolen_test(int prnt, int devId) int ret; if (prnt) { - printf(" tsip_aesgcm_zerolen_test() "); + printf(" tsip_aes%d_gcm_zerolen_test() ", keySz * 8); } if (wc_AesInit(enc, NULL, devId) != 0) { @@ -1037,8 +1043,8 @@ static int tsip_aesgcm_zerolen_test(int prnt, int devId) ret = -2; goto out; } - wc_AesGcmSetKey(enc, key, sizeof(key)); - wc_AesGcmSetKey(dec, key, sizeof(key)); + wc_AesGcmSetKey(enc, key, keySz); + wc_AesGcmSetKey(dec, key, keySz); /* (a) empty payload, non-empty AAD -- used to fail because plainBuf was * XMALLOC(0, ...)'d in wc_tsip_AesGcmEncrypt(). */ @@ -1135,7 +1141,7 @@ static int tsip_aesgcm_zerolen_test(int prnt, int devId) return ret; } -#endif +#endif /* HAVE_AESGCM && (WOLFSSL_AES_128 || WOLFSSL_AES_256) */ #ifdef FREERTOS @@ -1912,7 +1918,15 @@ int tsip_crypt_test(void) Clr_CallbackCtx(&userContext); ret = TSIP_AesKeyGeneration(&userContext, 16); if (ret == 0) - ret = tsip_aesgcm_zerolen_test(1, devId); + ret = tsip_aesgcm_zerolen_test(1, devId, 16); + } + #endif + #if defined(WOLFSSL_AES_256) + if (ret == 0) { + Clr_CallbackCtx(&userContext); + ret = TSIP_AesKeyGeneration(&userContext, 32); + if (ret == 0) + ret = tsip_aesgcm_zerolen_test(1, devId, 32); } #endif #endif