@@ -982,7 +982,12 @@ static int wolfPKCS11_Store_GetMaxSize(int type, int variableSz)
982982 FIELD_SIZE (WP11_Token , userFailedLogin ) +
983983 FIELD_SIZE (WP11_Token , userLastFailedLogin ) +
984984 FIELD_SIZE (WP11_Token , userFailLoginTimeout ) +
985+ #ifdef WOLFSSL_STM32U5_DHUK
986+ (sizeof (word32 ) + 16 + PIN_SEED_SZ ) + /* length + IV +
987+ * encrypted seed */
988+ #else
985989 FIELD_SIZE (WP11_Token , seed ) +
990+ #endif
986991 FIELD_SIZE (WP11_Token , objCnt ) +
987992 FIELD_SIZE (WP11_Token , tokenFlags ) +
988993 FIELD_SIZE (WP11_Token , nextObjId ) +
@@ -5150,6 +5155,137 @@ static void wp11_Token_Final(WP11_Token* token)
51505155static int HashPIN (char * pin , int pinLen , byte * seed , int seedLen , byte * hash ,
51515156 int hashLen , WP11_Slot * slot );
51525157
5158+ #ifdef WOLFSSL_STM32U5_DHUK
5159+ /* DHUK seed storage: IV (16) + AES-CBC ciphertext of seed (16).
5160+ * Uses AES-CBC with DHUK so the decrypted seed is placed in token->seed
5161+ * for use by AES-GCM and other operations. */
5162+ #define WP11_SEED_DHUK_IV_SZ 16
5163+ #define WP11_SEED_WRAPPED_SZ (WP11_SEED_DHUK_IV_SZ + PIN_SEED_SZ)
5164+
5165+ #if defined(HAVE_AES_CBC )
5166+ /* Dummy key for wc_AesSetKey when using DHUK; hardware uses DHUK. */
5167+ static const byte wp11_dhuk_dummy_key [32 ] = {0 };
5168+
5169+ static int wp11_token_write_seed_dhuk (void * storage , WP11_Token * token )
5170+ {
5171+ int ret ;
5172+ Aes aes ;
5173+ byte iv [WP11_SEED_DHUK_IV_SZ ];
5174+ byte wrappedSeed [PIN_SEED_SZ ];
5175+ /* Single buffer: big-endian word32 length + IV + encrypted seed */
5176+ byte buf [sizeof (word32 ) + WP11_SEED_DHUK_IV_SZ + PIN_SEED_SZ ];
5177+
5178+ WP11_Lock_LockRW (& token -> rngLock );
5179+ ret = wc_RNG_GenerateBlock (& token -> rng , iv , sizeof (iv ));
5180+ WP11_Lock_UnlockRW (& token -> rngLock );
5181+ if (ret != 0 )
5182+ return ret ;
5183+
5184+ ret = wc_AesInit (& aes , NULL , WOLFSSL_STM32U5_DHUK_DEVID );
5185+ if (ret != 0 )
5186+ return ret ;
5187+ ret = wc_AesSetKey (& aes , wp11_dhuk_dummy_key , sizeof (wp11_dhuk_dummy_key ),
5188+ iv , AES_ENCRYPTION );
5189+ if (ret != 0 ) {
5190+ wc_AesFree (& aes );
5191+ return ret ;
5192+ }
5193+ ret = wc_AesCbcEncrypt (& aes , wrappedSeed , (const byte * )token -> seed ,
5194+ (word32 )PIN_SEED_SZ );
5195+ wc_AesFree (& aes );
5196+ if (ret != 0 )
5197+ return ret ;
5198+
5199+ /* Assemble length (big-endian) + IV + encrypted seed into one buffer */
5200+ buf [0 ] = (byte )(WP11_SEED_WRAPPED_SZ >> 24 );
5201+ buf [1 ] = (byte )(WP11_SEED_WRAPPED_SZ >> 16 );
5202+ buf [2 ] = (byte )(WP11_SEED_WRAPPED_SZ >> 8 );
5203+ buf [3 ] = (byte )(WP11_SEED_WRAPPED_SZ >> 0 );
5204+ XMEMCPY (buf + sizeof (word32 ), iv , WP11_SEED_DHUK_IV_SZ );
5205+ XMEMCPY (buf + sizeof (word32 ) + WP11_SEED_DHUK_IV_SZ , wrappedSeed ,
5206+ PIN_SEED_SZ );
5207+
5208+ /* Single write to avoid multiple flash size-update round-trips */
5209+ return wp11_storage_write (storage , buf , (int )sizeof (buf ));
5210+ }
5211+
5212+ static int wp11_token_read_seed_dhuk (void * storage , WP11_Token * token )
5213+ {
5214+ int ret ;
5215+ Aes aes ;
5216+ byte iv [WP11_SEED_DHUK_IV_SZ ];
5217+ word32 wrappedLen ;
5218+ byte wrappedSeed [PIN_SEED_SZ ];
5219+ /* Single buffer: big-endian word32 length + IV + encrypted seed */
5220+ byte buf [sizeof (word32 ) + WP11_SEED_DHUK_IV_SZ + PIN_SEED_SZ ];
5221+
5222+ /* Single read to mirror the single write */
5223+ ret = wp11_storage_read (storage , buf , (int )sizeof (buf ));
5224+ if (ret != 0 )
5225+ return ret ;
5226+
5227+ /* Parse length (big-endian word32) from the first 4 bytes */
5228+ wrappedLen = ((word32 )buf [0 ] << 24 ) |
5229+ ((word32 )buf [1 ] << 16 ) |
5230+ ((word32 )buf [2 ] << 8 ) |
5231+ ((word32 )buf [3 ] << 0 );
5232+ if (wrappedLen != WP11_SEED_WRAPPED_SZ ) {
5233+ return BUFFER_E ; /* This size check will likely catch if an older style
5234+ * token was read without DHUK wrapping. Treating it
5235+ * as a failure rather than continuing on to avoid
5236+ * using an unwrapped key when it is assumed that the
5237+ * seed was wrapped. */
5238+ }
5239+
5240+ /* Extract IV and encrypted seed from the buffer */
5241+ XMEMCPY (iv , buf + sizeof (word32 ), WP11_SEED_DHUK_IV_SZ );
5242+ XMEMCPY (wrappedSeed , buf + sizeof (word32 ) + WP11_SEED_DHUK_IV_SZ ,
5243+ PIN_SEED_SZ );
5244+
5245+ ret = wc_AesInit (& aes , NULL , WOLFSSL_STM32U5_DHUK_DEVID );
5246+ if (ret != 0 )
5247+ return ret ;
5248+ ret = wc_AesSetKey (& aes , wp11_dhuk_dummy_key , sizeof (wp11_dhuk_dummy_key ),
5249+ iv , AES_DECRYPTION );
5250+ if (ret != 0 ) {
5251+ wc_AesFree (& aes );
5252+ return ret ;
5253+ }
5254+ ret = wc_AesCbcDecrypt (& aes , token -> seed , wrappedSeed , PIN_SEED_SZ );
5255+ wc_AesFree (& aes );
5256+ return ret ;
5257+ }
5258+ #else /* !HAVE_AES_CBC */
5259+ #error WOLFSSL_STM32U5_DHUK token seed storage requires HAVE_AES_CBC
5260+ #endif /* HAVE_AES_CBC */
5261+ #endif /* WOLFSSL_STM32U5_DHUK */
5262+
5263+ /**
5264+ * Read token seed from storage.
5265+ */
5266+ static int wp11_token_read_seed (void * storage , WP11_Token * token )
5267+ {
5268+ #ifdef WOLFSSL_STM32U5_DHUK
5269+ return wp11_token_read_seed_dhuk (storage , token );
5270+ #else
5271+ return wp11_storage_read_fixed_array (storage , token -> seed ,
5272+ sizeof (token -> seed ));
5273+ #endif
5274+ }
5275+
5276+ /**
5277+ * Write token seed to storage.
5278+ */
5279+ static int wp11_token_write_seed (void * storage , WP11_Token * token )
5280+ {
5281+ #ifdef WOLFSSL_STM32U5_DHUK
5282+ return wp11_token_write_seed_dhuk (storage , token );
5283+ #else
5284+ return wp11_storage_write_fixed_array (storage , token -> seed ,
5285+ sizeof (token -> seed ));
5286+ #endif
5287+ }
5288+
51535289/**
51545290 * Load a token from storage.
51555291 *
@@ -5225,9 +5361,8 @@ static int wp11_Token_Load(WP11_Slot* slot, int tokenId, WP11_Token* token)
52255361 ret = wp11_storage_read_time (storage , & token -> userFailLoginTimeout );
52265362 }
52275363 if (ret == 0 ) {
5228- /* Read seed used to calculate key. (16) */
5229- ret = wp11_storage_read_fixed_array (storage , token -> seed ,
5230- sizeof (token -> seed ));
5364+ /* Read seed used to calculate key. */
5365+ ret = wp11_token_read_seed (storage , token );
52315366 }
52325367 if (ret == 0 ) {
52335368 /* Read count of object on token. (4) */
@@ -5426,9 +5561,8 @@ static int wp11_Token_Store(WP11_Token* token, int tokenId)
54265561 ret = wp11_storage_write_time (storage , token -> userFailLoginTimeout );
54275562 }
54285563 if (ret == 0 ) {
5429- /* Write seed used to calculate key. (16) */
5430- ret = wp11_storage_write_fixed_array (storage , token -> seed ,
5431- sizeof (token -> seed ));
5564+ /* Write seed used to calculate key. */
5565+ ret = wp11_token_write_seed (storage , token );
54325566 }
54335567
54345568 if (ret == 0 ) {
@@ -6304,6 +6438,7 @@ int WP11_Slot_UserLogin(WP11_Slot* slot, char* pin, int pinLen)
63046438 if (ret == 0 ) {
63056439 ret = WP11_Slot_CheckUserPin (slot , pin , pinLen );
63066440 #ifndef WOLFPKCS11_NO_STORE
6441+ /* Re-create token->key from PIN + token->seed (HashPIN) on load. */
63076442 if (ret == 0 ) {
63086443 ret = HashPIN (pin , pinLen , token -> seed , sizeof (token -> seed ),
63096444 token -> key , sizeof (token -> key ), slot );
0 commit comments