From 760bae8c309a2bcf62aacf46ed24372c374d7512 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Sun, 1 Feb 2026 15:42:50 -0700 Subject: [PATCH 1/4] use DHUK to wrap/unwrap seed value used for token --- src/internal.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 6 deletions(-) diff --git a/src/internal.c b/src/internal.c index 0e5f192c..c3d2c687 100644 --- a/src/internal.c +++ b/src/internal.c @@ -5150,6 +5150,117 @@ static void wp11_Token_Final(WP11_Token* token) static int HashPIN(char* pin, int pinLen, byte* seed, int seedLen, byte* hash, int hashLen, WP11_Slot* slot); +#ifdef WOLFSSL_STM32U5_DHUK +/* DHUK seed storage: IV (16) + AES-CBC ciphertext of seed (16). + * Uses AES-CBC with DHUK so the decrypted seed is placed in token->seed + * for use by AES-GCM and other operations. */ +#define WP11_SEED_DHUK_IV_SZ 16 +#define WP11_SEED_WRAPPED_SZ (WP11_SEED_DHUK_IV_SZ + PIN_SEED_SZ) + +#if defined(HAVE_AES_CBC) +/* Dummy key for wc_AesSetKey when using DHUK; hardware uses DHUK. */ +static const byte wp11_dhuk_dummy_key[32] = {0}; + +static int wp11_token_write_seed_dhuk(void* storage, WP11_Token* token) +{ + int ret; + Aes aes; + byte iv[WP11_SEED_DHUK_IV_SZ]; + byte wrappedSeed[PIN_SEED_SZ]; + + WP11_Lock_LockRW(&token->rngLock); + ret = wc_RNG_GenerateBlock(&token->rng, iv, sizeof(iv)); + WP11_Lock_UnlockRW(&token->rngLock); + if (ret != 0) + return ret; + + ret = wc_AesInit(&aes, NULL, WOLFSSL_STM32U5_DHUK_DEVID); + if (ret != 0) + return ret; + ret = wc_AesSetKey(&aes, wp11_dhuk_dummy_key, sizeof(wp11_dhuk_dummy_key), + iv, AES_ENCRYPTION); + if (ret != 0) { + wc_AesFree(&aes); + return ret; + } + ret = wc_AesCbcEncrypt(&aes, wrappedSeed, (const byte*)token->seed, + (word32)PIN_SEED_SZ); + wc_AesFree(&aes); + if (ret != 0) + return ret; + + ret = wp11_storage_write_word32(storage, WP11_SEED_WRAPPED_SZ); + if (ret == 0) + ret = wp11_storage_write_fixed_array(storage, iv, WP11_SEED_DHUK_IV_SZ); + if (ret == 0) + ret = wp11_storage_write(storage, wrappedSeed, (int)WP11_SEED_WRAPPED_SZ); + return ret; +} + +static int wp11_token_read_seed_dhuk(void* storage, WP11_Token* token) +{ + int ret; + Aes aes; + byte iv[WP11_SEED_DHUK_IV_SZ]; + word32 wrappedLen; + byte wrappedSeed[PIN_SEED_SZ]; + + ret = wp11_storage_read_word32(storage, &wrappedLen); + if (ret != 0) + return ret; + if (wrappedLen != WP11_SEED_WRAPPED_SZ) + return BUFFER_E; + ret = wp11_storage_read_fixed_array(storage, iv, WP11_SEED_DHUK_IV_SZ); + if (ret != 0) + return ret; + ret = wp11_storage_read(storage, wrappedSeed, PIN_SEED_SZ); + if (ret != 0) + return ret; + + ret = wc_AesInit(&aes, NULL, WOLFSSL_STM32U5_DHUK_DEVID); + if (ret != 0) + return ret; + ret = wc_AesSetKey(&aes, wp11_dhuk_dummy_key, sizeof(wp11_dhuk_dummy_key), + iv, AES_DECRYPTION); + if (ret != 0) { + wc_AesFree(&aes); + return ret; + } + ret = wc_AesCbcDecrypt(&aes, token->seed, wrappedSeed, PIN_SEED_SZ); + wc_AesFree(&aes); + return ret; +} +#else /* !HAVE_AES_CBC */ +#error WOLFSSL_STM32U5_DHUK token seed storage requires HAVE_AES_CBC +#endif /* HAVE_AES_CBC */ +#endif /* WOLFSSL_STM32U5_DHUK */ + +/** + * Read token seed from storage. + */ +static int wp11_token_read_seed(void* storage, WP11_Token* token) +{ +#ifdef WOLFSSL_STM32U5_DHUK + return wp11_token_read_seed_dhuk(storage, token); +#else + return wp11_storage_read_fixed_array(storage, token->seed, + sizeof(token->seed)); +#endif +} + +/** + * Write token seed to storage. + */ +static int wp11_token_write_seed(void* storage, WP11_Token* token) +{ +#ifdef WOLFSSL_STM32U5_DHUK + return wp11_token_write_seed_dhuk(storage, token); +#else + return wp11_storage_write_fixed_array(storage, token->seed, + sizeof(token->seed)); +#endif +} + /** * Load a token from storage. * @@ -5225,9 +5336,8 @@ static int wp11_Token_Load(WP11_Slot* slot, int tokenId, WP11_Token* token) ret = wp11_storage_read_time(storage, &token->userFailLoginTimeout); } if (ret == 0) { - /* Read seed used to calculate key. (16) */ - ret = wp11_storage_read_fixed_array(storage, token->seed, - sizeof(token->seed)); + /* Read seed used to calculate key. */ + ret = wp11_token_read_seed(storage, token); } if (ret == 0) { /* Read count of object on token. (4) */ @@ -5426,9 +5536,8 @@ static int wp11_Token_Store(WP11_Token* token, int tokenId) ret = wp11_storage_write_time(storage, token->userFailLoginTimeout); } if (ret == 0) { - /* Write seed used to calculate key. (16) */ - ret = wp11_storage_write_fixed_array(storage, token->seed, - sizeof(token->seed)); + /* Write seed used to calculate key. */ + ret = wp11_token_write_seed(storage, token); } if (ret == 0) { @@ -6304,6 +6413,7 @@ int WP11_Slot_UserLogin(WP11_Slot* slot, char* pin, int pinLen) if (ret == 0) { ret = WP11_Slot_CheckUserPin(slot, pin, pinLen); #ifndef WOLFPKCS11_NO_STORE + /* Re-create token->key from PIN + token->seed (HashPIN) on load. */ if (ret == 0) { ret = HashPIN(pin, pinLen, token->seed, sizeof(token->seed), token->key, sizeof(token->key), slot); From 4f1cb4baf07e1a7a5e5656c8ca13de1024a58a08 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Tue, 10 Feb 2026 10:17:48 -0700 Subject: [PATCH 2/4] write and read iv+seed in one call --- src/internal.c | 50 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/internal.c b/src/internal.c index c3d2c687..6b9d1149 100644 --- a/src/internal.c +++ b/src/internal.c @@ -5167,6 +5167,8 @@ static int wp11_token_write_seed_dhuk(void* storage, WP11_Token* token) Aes aes; byte iv[WP11_SEED_DHUK_IV_SZ]; byte wrappedSeed[PIN_SEED_SZ]; + /* Single buffer: big-endian word32 length + IV + encrypted seed */ + byte buf[sizeof(word32) + WP11_SEED_DHUK_IV_SZ + PIN_SEED_SZ]; WP11_Lock_LockRW(&token->rngLock); ret = wc_RNG_GenerateBlock(&token->rng, iv, sizeof(iv)); @@ -5189,12 +5191,17 @@ static int wp11_token_write_seed_dhuk(void* storage, WP11_Token* token) if (ret != 0) return ret; - ret = wp11_storage_write_word32(storage, WP11_SEED_WRAPPED_SZ); - if (ret == 0) - ret = wp11_storage_write_fixed_array(storage, iv, WP11_SEED_DHUK_IV_SZ); - if (ret == 0) - ret = wp11_storage_write(storage, wrappedSeed, (int)WP11_SEED_WRAPPED_SZ); - return ret; + /* Assemble length (big-endian) + IV + encrypted seed into one buffer */ + buf[0] = (byte)(WP11_SEED_WRAPPED_SZ >> 24); + buf[1] = (byte)(WP11_SEED_WRAPPED_SZ >> 16); + buf[2] = (byte)(WP11_SEED_WRAPPED_SZ >> 8); + buf[3] = (byte)(WP11_SEED_WRAPPED_SZ >> 0); + XMEMCPY(buf + sizeof(word32), iv, WP11_SEED_DHUK_IV_SZ); + XMEMCPY(buf + sizeof(word32) + WP11_SEED_DHUK_IV_SZ, wrappedSeed, + PIN_SEED_SZ); + + /* Single write to avoid multiple flash size-update round-trips */ + return wp11_storage_write(storage, buf, (int)sizeof(buf)); } static int wp11_token_read_seed_dhuk(void* storage, WP11_Token* token) @@ -5204,19 +5211,32 @@ static int wp11_token_read_seed_dhuk(void* storage, WP11_Token* token) byte iv[WP11_SEED_DHUK_IV_SZ]; word32 wrappedLen; byte wrappedSeed[PIN_SEED_SZ]; + /* Single buffer: big-endian word32 length + IV + encrypted seed */ + byte buf[sizeof(word32) + WP11_SEED_DHUK_IV_SZ + PIN_SEED_SZ]; - ret = wp11_storage_read_word32(storage, &wrappedLen); - if (ret != 0) - return ret; - if (wrappedLen != WP11_SEED_WRAPPED_SZ) - return BUFFER_E; - ret = wp11_storage_read_fixed_array(storage, iv, WP11_SEED_DHUK_IV_SZ); - if (ret != 0) - return ret; - ret = wp11_storage_read(storage, wrappedSeed, PIN_SEED_SZ); + /* Single read to mirror the single write */ + ret = wp11_storage_read(storage, buf, (int)sizeof(buf)); if (ret != 0) return ret; + /* Parse length (big-endian word32) from the first 4 bytes */ + wrappedLen = ((word32)buf[0] << 24) | + ((word32)buf[1] << 16) | + ((word32)buf[2] << 8) | + ((word32)buf[3] << 0); + if (wrappedLen != WP11_SEED_WRAPPED_SZ) { + return BUFFER_E; /* This size check will likely catch if an older style + * token was read without DHUK wrapping. Treating it + * as a failure rather than continuing on to avoid + * using an unwrapped key when it is assumed that the + * seed was wrapped. */ + } + + /* Extract IV and encrypted seed from the buffer */ + XMEMCPY(iv, buf + sizeof(word32), WP11_SEED_DHUK_IV_SZ); + XMEMCPY(wrappedSeed, buf + sizeof(word32) + WP11_SEED_DHUK_IV_SZ, + PIN_SEED_SZ); + ret = wc_AesInit(&aes, NULL, WOLFSSL_STM32U5_DHUK_DEVID); if (ret != 0) return ret; From 33bac4ed83750fdb8acf3356f1acb315f9797bd9 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Thu, 12 Feb 2026 15:43:23 -0700 Subject: [PATCH 3/4] update storage to TPM to factor in larger seed size with DHUK use enabled --- src/internal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/internal.c b/src/internal.c index 6b9d1149..0b761236 100644 --- a/src/internal.c +++ b/src/internal.c @@ -982,7 +982,11 @@ static int wolfPKCS11_Store_GetMaxSize(int type, int variableSz) FIELD_SIZE(WP11_Token, userFailedLogin) + FIELD_SIZE(WP11_Token, userLastFailedLogin) + FIELD_SIZE(WP11_Token, userFailLoginTimeout) + +#ifdef WOLFSSL_STM32U5_DHUK + (sizeof(word32) + 16 + PIN_SEED_SZ) + /* length + IV + encrypted seed */ +#else FIELD_SIZE(WP11_Token, seed) + +#endif FIELD_SIZE(WP11_Token, objCnt) + FIELD_SIZE(WP11_Token, tokenFlags) + FIELD_SIZE(WP11_Token, nextObjId) + From 3e013feddfbbc780086508e2cf90c0c81000d94a Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Thu, 12 Feb 2026 17:05:20 -0700 Subject: [PATCH 4/4] fix for line length too long --- src/internal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index 0b761236..d06b8738 100644 --- a/src/internal.c +++ b/src/internal.c @@ -983,7 +983,8 @@ static int wolfPKCS11_Store_GetMaxSize(int type, int variableSz) FIELD_SIZE(WP11_Token, userLastFailedLogin) + FIELD_SIZE(WP11_Token, userFailLoginTimeout) + #ifdef WOLFSSL_STM32U5_DHUK - (sizeof(word32) + 16 + PIN_SEED_SZ) + /* length + IV + encrypted seed */ + (sizeof(word32) + 16 + PIN_SEED_SZ) + /* length + IV + + * encrypted seed */ #else FIELD_SIZE(WP11_Token, seed) + #endif