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