@@ -5222,3 +5222,299 @@ int test_wc_AesEaxDecryptAuth(void)
52225222 * (!HAVE_FIPS || FIPS_VERSION_GE(5, 3)) && !HAVE_SELFTEST
52235223 */
52245224
5225+ /*----------------------------------------------------------------------------*
5226+ | CryptoCB AES SetKey Proxy-Key Test
5227+ *----------------------------------------------------------------------------*/
5228+
5229+ #if defined(WOLF_CRYPTO_CB ) && !defined(NO_AES ) && defined(HAVE_AESGCM )
5230+
5231+ #include <wolfssl/wolfcrypt/cryptocb.h>
5232+
5233+ #define TEST_CRYPTOCB_AES_DEVID 7
5234+
5235+ /* Test state tracking */
5236+ static int g_ccAesSetKeyCalled = 0 ;
5237+ static int g_ccAesFreeCalled = 0 ;
5238+
5239+ /* Simulated SE key storage - in real SE this would be in secure hardware */
5240+ typedef struct {
5241+ byte key [AES_256_KEY_SIZE ];
5242+ word32 keySz ;
5243+ int valid ;
5244+ } MockSeKeySlot ;
5245+
5246+ static MockSeKeySlot g_mockSeKey = {0 };
5247+
5248+ /* Mock handle pointing to our key slot */
5249+ static void * g_ccAesMockHandle = (void * )& g_mockSeKey ;
5250+
5251+ /* Test CryptoCB callback for AES proxy-key operations
5252+ * This emulates a Secure Element by:
5253+ * - Storing the key on SetKey (simulating SE key import)
5254+ * - Using stored key for encrypt/decrypt (simulating SE crypto)
5255+ * - Clearing key on Free (simulating SE key deletion)
5256+ */
5257+ static int test_CryptoCb_Aes_Cb (int devId , wc_CryptoInfo * info , void * ctx )
5258+ {
5259+ (void )ctx ;
5260+
5261+ if (devId != TEST_CRYPTOCB_AES_DEVID )
5262+ return CRYPTOCB_UNAVAILABLE ;
5263+
5264+ /* AES SetKey operation - simulate SE key import */
5265+ if (info -> algo_type == WC_ALGO_TYPE_CIPHER &&
5266+ info -> cipher .type == WC_CIPHER_AES &&
5267+ info -> cipher .aessetkey .aes != NULL ) {
5268+
5269+ Aes * aes = info -> cipher .aessetkey .aes ;
5270+ const byte * key = info -> cipher .aessetkey .key ;
5271+ word32 keySz = info -> cipher .aessetkey .keySz ;
5272+
5273+ /* Validate key */
5274+ if (key == NULL || keySz == 0 || keySz > AES_256_KEY_SIZE ) {
5275+ return BAD_FUNC_ARG ;
5276+ }
5277+
5278+ /* "Import" key to simulated SE storage */
5279+ XMEMCPY (g_mockSeKey .key , key , keySz );
5280+ g_mockSeKey .keySz = keySz ;
5281+ g_mockSeKey .valid = 1 ;
5282+
5283+ /* Store handle in aes->devCtx - this is what wolfSSL will use */
5284+ aes -> devCtx = g_ccAesMockHandle ;
5285+
5286+ g_ccAesSetKeyCalled ++ ;
5287+
5288+ return 0 ;
5289+ }
5290+
5291+ /* AES-GCM Encrypt - simulate SE encryption using stored key */
5292+ if (info -> algo_type == WC_ALGO_TYPE_CIPHER &&
5293+ info -> cipher .type == WC_CIPHER_AES_GCM &&
5294+ info -> cipher .enc ) {
5295+
5296+ Aes * aes = info -> cipher .aesgcm_enc .aes ;
5297+ MockSeKeySlot * slot ;
5298+ Aes tempAes ;
5299+ int ret ;
5300+
5301+ /* Verify handle points to our key slot */
5302+ if (aes == NULL || aes -> devCtx != g_ccAesMockHandle ) {
5303+ return BAD_FUNC_ARG ;
5304+ }
5305+
5306+ slot = (MockSeKeySlot * )aes -> devCtx ;
5307+ if (!slot -> valid ) {
5308+ return BAD_STATE_E ;
5309+ }
5310+
5311+ /* Initialize a temporary Aes for software crypto (simulating SE internal operation) */
5312+ XMEMSET (& tempAes , 0 , sizeof (tempAes ));
5313+ ret = wc_AesInit (& tempAes , NULL , INVALID_DEVID ); /* No CryptoCB for internal use */
5314+ if (ret != 0 ) return ret ;
5315+
5316+ ret = wc_AesGcmSetKey (& tempAes , slot -> key , slot -> keySz );
5317+ if (ret != 0 ) {
5318+ wc_AesFree (& tempAes );
5319+ return ret ;
5320+ }
5321+
5322+ /* Perform the actual encryption */
5323+ ret = wc_AesGcmEncrypt (& tempAes ,
5324+ info -> cipher .aesgcm_enc .out ,
5325+ info -> cipher .aesgcm_enc .in ,
5326+ info -> cipher .aesgcm_enc .sz ,
5327+ info -> cipher .aesgcm_enc .iv ,
5328+ info -> cipher .aesgcm_enc .ivSz ,
5329+ info -> cipher .aesgcm_enc .authTag ,
5330+ info -> cipher .aesgcm_enc .authTagSz ,
5331+ info -> cipher .aesgcm_enc .authIn ,
5332+ info -> cipher .aesgcm_enc .authInSz );
5333+
5334+ wc_AesFree (& tempAes );
5335+
5336+ return ret ;
5337+ }
5338+
5339+ /* AES-GCM Decrypt - simulate SE decryption using stored key */
5340+ if (info -> algo_type == WC_ALGO_TYPE_CIPHER &&
5341+ info -> cipher .type == WC_CIPHER_AES_GCM &&
5342+ !info -> cipher .enc ) {
5343+
5344+ Aes * aes = info -> cipher .aesgcm_dec .aes ;
5345+ MockSeKeySlot * slot ;
5346+ Aes tempAes ;
5347+ int ret ;
5348+
5349+ /* Verify handle points to our key slot */
5350+ if (aes == NULL || aes -> devCtx != g_ccAesMockHandle ) {
5351+ return BAD_FUNC_ARG ;
5352+ }
5353+
5354+ slot = (MockSeKeySlot * )aes -> devCtx ;
5355+ if (!slot -> valid ) {
5356+ return BAD_STATE_E ;
5357+ }
5358+
5359+ /* Initialize a temporary Aes for software crypto (simulating SE internal operation) */
5360+ XMEMSET (& tempAes , 0 , sizeof (tempAes ));
5361+ ret = wc_AesInit (& tempAes , NULL , INVALID_DEVID );
5362+ if (ret != 0 ) return ret ;
5363+
5364+ ret = wc_AesGcmSetKey (& tempAes , slot -> key , slot -> keySz );
5365+ if (ret != 0 ) {
5366+ wc_AesFree (& tempAes );
5367+ return ret ;
5368+ }
5369+
5370+ /* Perform the actual decryption */
5371+ ret = wc_AesGcmDecrypt (& tempAes ,
5372+ info -> cipher .aesgcm_dec .out ,
5373+ info -> cipher .aesgcm_dec .in ,
5374+ info -> cipher .aesgcm_dec .sz ,
5375+ info -> cipher .aesgcm_dec .iv ,
5376+ info -> cipher .aesgcm_dec .ivSz ,
5377+ info -> cipher .aesgcm_dec .authTag ,
5378+ info -> cipher .aesgcm_dec .authTagSz ,
5379+ info -> cipher .aesgcm_dec .authIn ,
5380+ info -> cipher .aesgcm_dec .authInSz );
5381+
5382+ wc_AesFree (& tempAes );
5383+
5384+ return ret ;
5385+ }
5386+
5387+ #ifdef WOLF_CRYPTO_CB_FREE
5388+ /* Free operation - simulate SE key deletion */
5389+ if (info -> algo_type == WC_ALGO_TYPE_FREE &&
5390+ info -> free .algo == WC_ALGO_TYPE_CIPHER &&
5391+ info -> free .type == WC_CIPHER_AES ) {
5392+
5393+ Aes * aes = (Aes * )info -> free .obj ;
5394+
5395+ if (aes != NULL && aes -> devCtx == g_ccAesMockHandle ) {
5396+ /* "Delete" key from simulated SE */
5397+ ForceZero (& g_mockSeKey , sizeof (g_mockSeKey ));
5398+ g_ccAesFreeCalled ++ ;
5399+ }
5400+
5401+ return 0 ;
5402+ }
5403+ #endif
5404+
5405+ return CRYPTOCB_UNAVAILABLE ;
5406+ }
5407+
5408+ /*
5409+ * Test: CryptoCB AES SetKey hook for proxy-key / secure element support
5410+ */
5411+ int test_wc_CryptoCb_AesSetKey (void )
5412+ {
5413+ EXPECT_DECLS ;
5414+ Aes aes ;
5415+ byte key [AES_128_KEY_SIZE ] = {
5416+ 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 ,
5417+ 0x08 , 0x09 , 0x0a , 0x0b , 0x0c , 0x0d , 0x0e , 0x0f
5418+ };
5419+ byte iv [GCM_NONCE_MID_SZ ] = {0 };
5420+ byte plain [16 ] = {
5421+ 0x48 , 0x65 , 0x6c , 0x6c , 0x6f , 0x2c , 0x20 , 0x77 ,
5422+ 0x6f , 0x6c , 0x66 , 0x53 , 0x53 , 0x4c , 0x21 , 0x00
5423+ };
5424+ byte cipher [16 ];
5425+ byte decrypted [16 ];
5426+ byte authTag [AES_BLOCK_SIZE ];
5427+ int ret ;
5428+
5429+ XMEMSET (& aes , 0 , sizeof (aes ));
5430+ XMEMSET (& g_mockSeKey , 0 , sizeof (g_mockSeKey ));
5431+
5432+ /* Reset test state */
5433+ g_ccAesSetKeyCalled = 0 ;
5434+ g_ccAesFreeCalled = 0 ;
5435+
5436+ /* Register test callback */
5437+ ret = wc_CryptoCb_RegisterDevice (TEST_CRYPTOCB_AES_DEVID ,
5438+ test_CryptoCb_Aes_Cb , NULL );
5439+ ExpectIntEQ (ret , 0 );
5440+
5441+ /* Initialize Aes with device ID */
5442+ ret = wc_AesInit (& aes , NULL , TEST_CRYPTOCB_AES_DEVID );
5443+ ExpectIntEQ (ret , 0 );
5444+ ExpectIntEQ (aes .devId , TEST_CRYPTOCB_AES_DEVID );
5445+
5446+ /* Set key - should trigger CryptoCB and "import" to mock SE */
5447+ ret = wc_AesGcmSetKey (& aes , key , sizeof (key ));
5448+ ExpectIntEQ (ret , 0 );
5449+
5450+ /* Verify callback was invoked */
5451+ ExpectIntEQ (g_ccAesSetKeyCalled , 1 );
5452+
5453+ /* Verify handle stored in devCtx */
5454+ ExpectPtrEq (aes .devCtx , g_ccAesMockHandle );
5455+
5456+ /* Verify key was "imported" to mock SE */
5457+ ExpectIntEQ (g_mockSeKey .valid , 1 );
5458+ ExpectIntEQ (g_mockSeKey .keySz , (int )sizeof (key ));
5459+
5460+ /* Verify keylen metadata stored in Aes struct */
5461+ ExpectIntEQ (aes .keylen , (int )sizeof (key ));
5462+
5463+ /* Test encrypt - callback performs crypto using stored key */
5464+ ret = wc_AesGcmEncrypt (& aes , cipher , plain , sizeof (plain ),
5465+ iv , sizeof (iv ), authTag , sizeof (authTag ),
5466+ NULL , 0 );
5467+ ExpectIntEQ (ret , 0 );
5468+
5469+ /* Test decrypt - callback performs crypto using stored key */
5470+ ret = wc_AesGcmDecrypt (& aes , decrypted , cipher , sizeof (cipher ),
5471+ iv , sizeof (iv ), authTag , sizeof (authTag ),
5472+ NULL , 0 );
5473+ ExpectIntEQ (ret , 0 );
5474+
5475+ /* Verify round-trip */
5476+ ExpectIntEQ (XMEMCMP (plain , decrypted , sizeof (plain )), 0 );
5477+
5478+ #ifdef WOLF_CRYPTO_CB_FREE
5479+ /* Free should trigger callback and "delete" key from mock SE */
5480+ g_ccAesFreeCalled = 0 ;
5481+ wc_AesFree (& aes );
5482+
5483+ /* Verify free callback invoked */
5484+ ExpectIntEQ (g_ccAesFreeCalled , 1 );
5485+
5486+ /* Verify devCtx cleared */
5487+ ExpectPtrEq (aes .devCtx , NULL );
5488+
5489+ /* Verify key was "deleted" from mock SE */
5490+ ExpectIntEQ (g_mockSeKey .valid , 0 );
5491+ #else
5492+ wc_AesFree (& aes );
5493+ #endif
5494+
5495+ /* Cleanup */
5496+ wc_CryptoCb_UnRegisterDevice (TEST_CRYPTOCB_AES_DEVID );
5497+
5498+ /* Test software path (no devId) still works */
5499+ XMEMSET (& aes , 0 , sizeof (aes ));
5500+ g_ccAesSetKeyCalled = 0 ;
5501+
5502+ ret = wc_AesInit (& aes , NULL , INVALID_DEVID );
5503+ ExpectIntEQ (ret , 0 );
5504+
5505+ ret = wc_AesGcmSetKey (& aes , key , sizeof (key ));
5506+ ExpectIntEQ (ret , 0 );
5507+
5508+ /* Callback should NOT have been invoked */
5509+ ExpectIntEQ (g_ccAesSetKeyCalled , 0 );
5510+
5511+ /* devCtx should be NULL */
5512+ ExpectPtrEq (aes .devCtx , NULL );
5513+
5514+ wc_AesFree (& aes );
5515+
5516+ return EXPECT_RESULT ();
5517+ }
5518+
5519+ #endif /* WOLF_CRYPTO_CB && !NO_AES && HAVE_AESGCM */
5520+
0 commit comments