From b5c84cc45aad3826d2ea03f4285386f1f5a4c0a1 Mon Sep 17 00:00:00 2001 From: Yosuke Shimizu Date: Wed, 12 Aug 2026 16:47:33 +0900 Subject: [PATCH] Reject out-of-range SHE counter, flags and key IDs --- doc/dox_comments/header_files-ja/wc_she.h | 12 +++--- doc/dox_comments/header_files/wc_she.h | 18 +++++---- tests/api/test_she.c | 49 +++++++++++++++++++++++ wolfcrypt/src/wc_she.c | 12 ++++++ wolfssl/wolfcrypt/wc_she.h | 9 ++++- 5 files changed, 84 insertions(+), 16 deletions(-) diff --git a/doc/dox_comments/header_files-ja/wc_she.h b/doc/dox_comments/header_files-ja/wc_she.h index 7632d9047d5..d79a8772e67 100644 --- a/doc/dox_comments/header_files-ja/wc_she.h +++ b/doc/dox_comments/header_files-ja/wc_she.h @@ -265,15 +265,15 @@ int wc_SHE_ImportM1M2M3(wc_SHE* she, \brief SHEの鍵更新メッセージM1、M2、M3を生成し、呼び出し側が用意したバッファへ書き込みます。認可鍵からK1とK2を導出するためにMiyaguchi-Preneel AES-128 KDFを、新しい鍵の暗号化(M2)にAES-CBCを、認証(M3)にAES-CMACを使用します。 \return 0 成功した場合に返されます - \return BAD_FUNC_ARG 必要なポインタのいずれかがNULLの場合、またはサイズが正しくない場合に返されます + \return BAD_FUNC_ARG 必要なポインタのいずれかがNULLの場合、サイズが正しくない場合、またはcounter、flags、authKeyId、targetKeyIdがパックされるフィールドの幅を超える場合に返されます \param she 初期化済みのSHEコンテキスト \param uid 15バイトのSHE UID(120ビットのECU/モジュール識別子) \param uidSz WC_SHE_UID_SZ(15)でなければなりません - \param authKeyId 認可鍵のスロットID(0〜14) + \param authKeyId 認可鍵の4ビットのスロットID \param authKey 認可鍵の16バイトの値 \param authKeySz WC_SHE_KEY_SZ(16)でなければなりません - \param targetKeyId ロード対象の鍵のスロットID(1〜14) + \param targetKeyId ロード対象の鍵の4ビットのスロットID \param newKey ロードする新しい鍵の16バイトの値 \param newKeySz WC_SHE_KEY_SZ(16)でなければなりません \param counter 28ビットの単調増加カウンタ値(対象スロットに格納されているカウンタより大きい値でなければなりません。同じ値は使用できません) @@ -317,13 +317,13 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she, \brief SHEの検証メッセージM4とM5を生成し、呼び出し側が用意したバッファへ書き込みます。新しい鍵からK3とK4を導出するためにMiyaguchi-Preneel AES-128 KDFを、M4のカウンタブロックにAES-ECBを、M5にAES-CMACを使用します。M1/M2/M3とは独立しており、別のコンテキストで呼び出すこともできます。 \return 0 成功した場合に返されます - \return BAD_FUNC_ARG 必要なポインタのいずれかがNULLの場合、またはサイズが正しくない場合に返されます + \return BAD_FUNC_ARG 必要なポインタのいずれかがNULLの場合、サイズが正しくない場合、またはcounter、authKeyId、targetKeyIdがパックされるフィールドの幅を超える場合に返されます \param she 初期化済みのSHEコンテキスト \param uid 15バイトのSHE UID(M1で使用したものと同じUID) \param uidSz WC_SHE_UID_SZ(15)でなければなりません - \param authKeyId 認可鍵のスロットID(M1と同じ) - \param targetKeyId ロード対象の鍵のスロットID(M1と同じ) + \param authKeyId 認可鍵の4ビットのスロットID(M1と同じ) + \param targetKeyId ロード対象の鍵の4ビットのスロットID(M1と同じ) \param newKey 新しい鍵の16バイトの値 \param newKeySz WC_SHE_KEY_SZ(16)でなければなりません \param counter 28ビットの単調増加カウンタ(M2と同じ値) diff --git a/doc/dox_comments/header_files/wc_she.h b/doc/dox_comments/header_files/wc_she.h index 312a40c4847..405ae323c58 100644 --- a/doc/dox_comments/header_files/wc_she.h +++ b/doc/dox_comments/header_files/wc_she.h @@ -294,16 +294,17 @@ int wc_SHE_ImportM1M2M3(wc_SHE* she, new key (M2), and AES-CMAC for authentication (M3). \return 0 on success - \return BAD_FUNC_ARG if any required pointer is NULL or sizes are - incorrect + \return BAD_FUNC_ARG if any required pointer is NULL, sizes are + incorrect, or counter, flags, authKeyId or targetKeyId is wider than + its packed field \param she initialized SHE context \param uid 15-byte SHE UID (120-bit ECU/module identifier) \param uidSz must be WC_SHE_UID_SZ (15) - \param authKeyId slot ID of the authorizing key (0-14) + \param authKeyId 4-bit slot ID of the authorizing key \param authKey 16-byte value of the authorizing key \param authKeySz must be WC_SHE_KEY_SZ (16) - \param targetKeyId slot ID of the key being loaded (1-14) + \param targetKeyId 4-bit slot ID of the key being loaded \param newKey 16-byte value of the new key to load \param newKeySz must be WC_SHE_KEY_SZ (16) \param counter 28-bit monotonic counter value (must be strictly greater @@ -352,14 +353,15 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she, separate context. \return 0 on success - \return BAD_FUNC_ARG if any required pointer is NULL or sizes are - incorrect + \return BAD_FUNC_ARG if any required pointer is NULL, sizes are + incorrect, or counter, authKeyId or targetKeyId is wider than its + packed field \param she initialized SHE context \param uid 15-byte SHE UID (same UID used for M1) \param uidSz must be WC_SHE_UID_SZ (15) - \param authKeyId slot ID of the authorizing key (same as in M1) - \param targetKeyId slot ID of the key being loaded (same as in M1) + \param authKeyId 4-bit slot ID of the authorizing key (same as in M1) + \param targetKeyId 4-bit slot ID of the key being loaded (same as in M1) \param newKey 16-byte value of the new key \param newKeySz must be WC_SHE_KEY_SZ (16) \param counter 28-bit monotonic counter (same value as in M2) diff --git a/tests/api/test_she.c b/tests/api/test_she.c index 3e4a155784d..b20ac93b73f 100644 --- a/tests/api/test_she.c +++ b/tests/api/test_she.c @@ -227,6 +227,15 @@ int test_wc_SHE_GenerateM1M2M3(void) m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ), 0); ExpectIntEQ(XMEMCMP(m1, sheTestExpM1, WC_SHE_M1_SZ), 0); + /* Largest encodable counter, flags and key IDs are still accepted */ + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_KEY_ID_MAX, sheTestAuthKey, sizeof(sheTestAuthKey), + WC_SHE_KEY_ID_MAX, sheTestNewKey, sizeof(sheTestNewKey), + WC_SHE_COUNTER_MAX, WC_SHE_FLAGS_MAX, + m1, WC_SHE_M1_SZ, m2, WC_SHE_M2_SZ, m3, WC_SHE_M3_SZ), 0); + ExpectIntEQ(m1[WC_SHE_M1_KID_OFFSET], 0xFF); + /* Bad args */ ExpectIntEQ(wc_SHE_GenerateM1M2M3(NULL, sheTestUid, sizeof(sheTestUid), @@ -260,6 +269,14 @@ int test_wc_SHE_GenerateM4M5(void) ExpectIntEQ(XMEMCMP(m4, sheTestExpM4, WC_SHE_M4_SZ), 0); ExpectIntEQ(XMEMCMP(m5, sheTestExpM5, WC_SHE_M5_SZ), 0); + /* Largest encodable counter and key IDs are still accepted */ + ExpectIntEQ(wc_SHE_GenerateM4M5(&she, + sheTestUid, sizeof(sheTestUid), + WC_SHE_KEY_ID_MAX, WC_SHE_KEY_ID_MAX, + sheTestNewKey, sizeof(sheTestNewKey), WC_SHE_COUNTER_MAX, + m4, WC_SHE_M4_SZ, m5, WC_SHE_M5_SZ), 0); + ExpectIntEQ(m4[WC_SHE_M4_KID_OFFSET], 0xFF); + /* Bad args */ ExpectIntEQ(wc_SHE_GenerateM4M5(NULL, sheTestUid, sizeof(sheTestUid), @@ -837,6 +854,25 @@ int test_wc_SHE_DecisionCoverage(void) WC_SHE_KEY_SZ, 2, key, WC_SHE_KEY_SZ, 1, 0, m1, sizeof(m1), m2, sizeof(m2), m3, WC_SHE_M3_SZ - 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* wc_SHE_GenerateM1M2M3: packed field widths, one invalid per call. + * Each of these silently wrapped or bled into a neighbouring field. */ + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, uid, WC_SHE_UID_SZ, 1, key, + WC_SHE_KEY_SZ, 2, key, WC_SHE_KEY_SZ, WC_SHE_COUNTER_MAX + 1, 0, + m1, sizeof(m1), m2, sizeof(m2), m3, sizeof(m3)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, uid, WC_SHE_UID_SZ, 1, key, + WC_SHE_KEY_SZ, 2, key, WC_SHE_KEY_SZ, 1, WC_SHE_FLAGS_MAX + 1, + m1, sizeof(m1), m2, sizeof(m2), m3, sizeof(m3)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, uid, WC_SHE_UID_SZ, + WC_SHE_KEY_ID_MAX + 1, key, + WC_SHE_KEY_SZ, 2, key, WC_SHE_KEY_SZ, 1, 0, m1, sizeof(m1), m2, + sizeof(m2), m3, sizeof(m3)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she, uid, WC_SHE_UID_SZ, 1, key, + WC_SHE_KEY_SZ, WC_SHE_KEY_ID_MAX + 1, key, + WC_SHE_KEY_SZ, 1, 0, m1, sizeof(m1), m2, + sizeof(m2), m3, sizeof(m3)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* wc_SHE_GenerateM4M5: 8 operands, one invalid per call. */ ExpectIntEQ(wc_SHE_GenerateM4M5(&she, NULL, WC_SHE_UID_SZ, 1, 2, key, WC_SHE_KEY_SZ, 1, m4, sizeof(m4), m5, sizeof(m5)), @@ -862,6 +898,19 @@ int test_wc_SHE_DecisionCoverage(void) ExpectIntEQ(wc_SHE_GenerateM4M5(&she, uid, WC_SHE_UID_SZ, 1, 2, key, WC_SHE_KEY_SZ, 1, m4, sizeof(m4), m5, WC_SHE_M5_SZ - 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* wc_SHE_GenerateM4M5: packed field widths, one invalid per call. */ + ExpectIntEQ(wc_SHE_GenerateM4M5(&she, uid, WC_SHE_UID_SZ, 1, 2, key, + WC_SHE_KEY_SZ, WC_SHE_COUNTER_MAX + 1, m4, sizeof(m4), m5, + sizeof(m5)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_GenerateM4M5(&she, uid, WC_SHE_UID_SZ, + WC_SHE_KEY_ID_MAX + 1, 2, key, + WC_SHE_KEY_SZ, 1, m4, sizeof(m4), m5, sizeof(m5)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SHE_GenerateM4M5(&she, uid, WC_SHE_UID_SZ, 1, + WC_SHE_KEY_ID_MAX + 1, key, + WC_SHE_KEY_SZ, 1, m4, sizeof(m4), m5, sizeof(m5)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); } if (inited) wc_SHE_Free(&she); diff --git a/wolfcrypt/src/wc_she.c b/wolfcrypt/src/wc_she.c index c4e70607363..9c6d08d681c 100644 --- a/wolfcrypt/src/wc_she.c +++ b/wolfcrypt/src/wc_she.c @@ -501,6 +501,12 @@ int wc_SHE_GenerateM1M2M3(wc_SHE* she, return BAD_FUNC_ARG; } + /* Reject values wider than their packed field */ + if (counter > WC_SHE_COUNTER_MAX || flags > WC_SHE_FLAGS_MAX || + authKeyId > WC_SHE_KEY_ID_MAX || targetKeyId > WC_SHE_KEY_ID_MAX) { + return BAD_FUNC_ARG; + } + #ifdef WOLF_CRYPTO_CB /* Try callback first -- callback handles its own parameter validation. * This allows callers to pass NULL authKey/newKey when a secure element @@ -676,6 +682,12 @@ int wc_SHE_GenerateM4M5(wc_SHE* she, return BAD_FUNC_ARG; } + /* Reject values wider than their packed field */ + if (counter > WC_SHE_COUNTER_MAX || + authKeyId > WC_SHE_KEY_ID_MAX || targetKeyId > WC_SHE_KEY_ID_MAX) { + return BAD_FUNC_ARG; + } + #ifdef WOLF_CRYPTO_CB /* Try callback first -- useful for uploading M1/M2/M3 to an HSM which * loads the key and returns the correct M4/M5 proof values. The callback diff --git a/wolfssl/wolfcrypt/wc_she.h b/wolfssl/wolfcrypt/wc_she.h index 0381c114ef9..8f454feb890 100644 --- a/wolfssl/wolfcrypt/wc_she.h +++ b/wolfssl/wolfcrypt/wc_she.h @@ -73,6 +73,11 @@ enum wc_SheType { #define WC_SHE_M4_COUNT_SHIFT 4 #define WC_SHE_M4_COUNT_PAD 0x8 +/* largest value each packed field can hold */ +#define WC_SHE_COUNTER_MAX 0x0FFFFFFFU +#define WC_SHE_FLAGS_MAX 0x0F +#define WC_SHE_KEY_ID_MAX 0x0F + /* SHE KDF constants (Miyaguchi-Preneel input) */ #define WC_SHE_KEY_UPDATE_ENC_C { \ 0x01, 0x01, 0x53, 0x48, \ @@ -240,12 +245,12 @@ WOLFSSL_API int wc_SHE_ImportM1M2M3(wc_SHE* she, * she - initialized SHE context * uid - 15-byte SHE UID (120-bit ECU/module identifier) * uidSz - must be WC_SHE_UID_SZ (15) - * authKeyId - slot ID of the authorizing key (0-14, e.g. + * authKeyId - 4-bit slot ID of the authorizing key (e.g. * MASTER_ECU_KEY=1, KEY_1..KEY_10=4..13) * authKey - 16-byte value of the authorizing key. Used to derive * K1 (encryption) and K2 (MAC). * authKeySz - must be WC_SHE_KEY_SZ (16) - * targetKeyId - slot ID of the key being loaded (1-14) + * targetKeyId - 4-bit slot ID of the key being loaded * newKey - 16-byte value of the new key to load. Placed in M2 * cleartext and used to derive K3/K4 for M4/M5. * newKeySz - must be WC_SHE_KEY_SZ (16)