mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 14:50:49 +02:00
Merge pull request #9658 from sameehj/aes-offload
cryptocb: add AES CryptoCB key import support and tests
This commit is contained in:
@@ -70,6 +70,9 @@ jobs:
|
||||
'--enable-all --enable-certgencache',
|
||||
'--enable-sessionexport --enable-dtls --enable-dtls13',
|
||||
'--enable-sessionexport',
|
||||
'--enable-cryptocb --enable-aesgcm CPPFLAGS="-DWOLF_CRYPTO_CB_AES_SETKEY -DWOLF_CRYPTO_CB_FREE"',
|
||||
'--disable-tls --enable-cryptocb --enable-aesgcm CPPFLAGS="-DWOLF_CRYPTO_CB_AES_SETKEY -DWOLF_CRYPTO_CB_FREE"',
|
||||
'--enable-cryptocb --enable-aesgcm CPPFLAGS="-DWOLF_CRYPTO_CB_AES_SETKEY"',
|
||||
'--disable-examples CPPFLAGS=-DWOLFSSL_NO_MALLOC',
|
||||
'CPPFLAGS=-DNO_WOLFSSL_CLIENT',
|
||||
'CPPFLAGS=-DNO_WOLFSSL_SERVER',
|
||||
|
||||
@@ -57,6 +57,29 @@ suites are available. You can remove this error by defining
|
||||
`WOLFSSL_ALLOW_NO_SUITES` in the event that you desire that, i.e., you're
|
||||
not using TLS cipher suites.
|
||||
|
||||
### AES CryptoCB Key Import Support
|
||||
|
||||
wolfSSL supports hardware-accelerated AES operations via CryptoCB.
|
||||
|
||||
When `WOLF_CRYPTO_CB_AES_SETKEY` is defined, wolfSSL invokes a CryptoCB
|
||||
callback during AES key setup. The callback behavior determines the mode:
|
||||
|
||||
**If callback returns 0 (success):**
|
||||
- Key is imported to Secure Element/HSM
|
||||
- Key is NOT copied to wolfSSL RAM (true key isolation)
|
||||
- GCM tables are NOT generated (full hardware offload)
|
||||
- All subsequent AES operations route through CryptoCB
|
||||
|
||||
**If callback returns CRYPTOCB_UNAVAILABLE:**
|
||||
- SE doesn't support key import
|
||||
- Normal software AES path is used
|
||||
- Key is copied to devKey for CryptoCB encrypt/decrypt acceleration
|
||||
|
||||
This feature enables TLS 1.3 traffic key protection on embedded platforms
|
||||
where symmetric keys must never exist in main RAM.
|
||||
|
||||
Enable with: `CPPFLAGS="-DWOLF_CRYPTO_CB_AES_SETKEY -DWOLF_CRYPTO_CB_FREE"`
|
||||
|
||||
### Note 2
|
||||
wolfSSL takes a different approach to certificate verification than OpenSSL
|
||||
does. The default policy for the client is to verify the server, this means
|
||||
|
||||
@@ -180,3 +180,63 @@ void wc_CryptoCb_SetDeviceFindCb(CryptoDevCallbackFind cb);
|
||||
\sa wc_CryptoCb_RegisterDevice
|
||||
*/
|
||||
void wc_CryptoCb_InfoString(wc_CryptoInfo* info);
|
||||
|
||||
/*!
|
||||
\ingroup CryptoCb
|
||||
|
||||
\brief Import an AES key into a CryptoCB device for hardware offload.
|
||||
|
||||
This function allows AES keys to be handled by an external device
|
||||
(e.g. Secure Element or HSM). When supported, the device callback stores
|
||||
the key internally and sets an opaque handle in aes->devCtx.
|
||||
|
||||
When CryptoCB AES SetKey support is enabled
|
||||
(WOLF_CRYPTO_CB_AES_SETKEY), wolfCrypt routes AES-GCM operations
|
||||
through the CryptoCB interface.
|
||||
|
||||
**TLS Builds (Default):**
|
||||
- Key bytes ARE stored in wolfCrypt memory (devKey) for fallback
|
||||
- GCM tables ARE generated for software fallback
|
||||
- Provides hardware acceleration with automatic fallback
|
||||
|
||||
**Crypto-Only Builds (--disable-tls):**
|
||||
- Key bytes NOT stored in wolfCrypt memory (true key isolation)
|
||||
- GCM tables skipped (true hardware offload)
|
||||
- Callback must handle all GCM operations (SetKey, Encrypt, Decrypt, Free)
|
||||
|
||||
If the callback returns success (0), full AES-GCM offload is assumed.
|
||||
The callback must handle SetKey, Encrypt, Decrypt, and Free operations.
|
||||
|
||||
\param aes AES context
|
||||
\param key Pointer to raw AES key material
|
||||
\param keySz Size of key in bytes
|
||||
|
||||
\return 0 on success
|
||||
\return CRYPTOCB_UNAVAILABLE if device does not support this operation
|
||||
\return BAD_FUNC_ARG on invalid parameters
|
||||
|
||||
_Example_
|
||||
\code
|
||||
#include <wolfssl/wolfcrypt/cryptocb.h>
|
||||
#include <wolfssl/wolfcrypt/aes.h>
|
||||
|
||||
Aes aes;
|
||||
byte key[32] = { /* 256-bit key */ };
|
||||
int devId = 1;
|
||||
|
||||
/* Register your CryptoCB callback first */
|
||||
wc_CryptoCb_RegisterDevice(devId, myCryptoCallback, NULL);
|
||||
|
||||
wc_AesInit(&aes, NULL, devId);
|
||||
/* wc_AesGcmSetKey internally calls wc_CryptoCb_AesSetKey */
|
||||
if (wc_CryptoCb_AesSetKey(&aes, key, sizeof(key)) == 0) {
|
||||
/* Key successfully imported to device via callback */
|
||||
/* aes.devCtx now contains device handle */
|
||||
/* Full GCM offload is assumed - callback must handle all operations */
|
||||
}
|
||||
\endcode
|
||||
|
||||
\sa wc_CryptoCb_RegisterDevice
|
||||
\sa wc_AesInit
|
||||
*/
|
||||
int wc_CryptoCb_AesSetKey(Aes* aes, const byte* key, word32 keySz);
|
||||
|
||||
@@ -74,4 +74,27 @@
|
||||
- \ref SAKKE_RSK
|
||||
- \ref SAKKE_Operations
|
||||
*/
|
||||
/*!
|
||||
\page AES_CryptoCB_KeyImport AES CryptoCB Key Import
|
||||
|
||||
When enabled via WOLF_CRYPTO_CB_AES_SETKEY, wolfSSL invokes a CryptoCB
|
||||
callback during AES key setup. The callback behavior determines the mode:
|
||||
|
||||
**If callback returns 0 (success):**
|
||||
- Key is imported to Secure Element/HSM
|
||||
- Key is NOT copied to wolfSSL RAM (true key isolation)
|
||||
- GCM tables are NOT generated (full hardware offload)
|
||||
- All subsequent AES operations route through CryptoCB
|
||||
|
||||
**If callback returns CRYPTOCB_UNAVAILABLE:**
|
||||
- SE doesn't support key import
|
||||
- Normal software AES path is used
|
||||
- Key is copied to devKey for CryptoCB encrypt/decrypt acceleration
|
||||
|
||||
This mode is compatible with Secure Elements and hardware-backed
|
||||
key storage and is intended for protecting TLS traffic keys.
|
||||
|
||||
\sa wc_CryptoCb_AesSetKey
|
||||
\sa \ref Crypto Callbacks
|
||||
*/
|
||||
|
||||
|
||||
@@ -5222,3 +5222,742 @@ int test_wc_AesEaxDecryptAuth(void)
|
||||
* (!HAVE_FIPS || FIPS_VERSION_GE(5, 3)) && !HAVE_SELFTEST
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------*
|
||||
| CryptoCB AES SetKey Test
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \
|
||||
!defined(NO_AES) && defined(HAVE_AESGCM)
|
||||
|
||||
#include <wolfssl/wolfcrypt/cryptocb.h>
|
||||
|
||||
#define TEST_CRYPTOCB_AES_DEVID 7
|
||||
|
||||
/* Test state tracking */
|
||||
static int cryptoCbAesSetKeyCalled = 0;
|
||||
static int cryptoCbAesFreeCalled = 0;
|
||||
|
||||
/* Simulated SE key storage - in real SE this would be in secure hardware */
|
||||
typedef struct {
|
||||
byte key[AES_256_KEY_SIZE];
|
||||
word32 keySz;
|
||||
int valid;
|
||||
} MockSeKeySlot;
|
||||
|
||||
static MockSeKeySlot mockSeKey = {0};
|
||||
|
||||
/* Mock handle pointing to our key slot */
|
||||
static void* cryptoCbAesMockHandle = (void*)&mockSeKey;
|
||||
|
||||
/* Test CryptoCB callback for AES key import operations
|
||||
* This emulates a Secure Element by:
|
||||
* - Storing the key on SetKey (simulating SE key import)
|
||||
* - Using stored key for encrypt/decrypt (simulating SE crypto)
|
||||
* - Clearing key on Free (simulating SE key deletion)
|
||||
*/
|
||||
static int test_CryptoCb_Aes_Cb(int devId, wc_CryptoInfo* info, void* ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
|
||||
if (devId != TEST_CRYPTOCB_AES_DEVID)
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
|
||||
/* AES SetKey operation - simulate SE key import */
|
||||
if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
|
||||
info->cipher.type == WC_CIPHER_AES &&
|
||||
info->cipher.aessetkey.aes != NULL) {
|
||||
|
||||
Aes* aes = info->cipher.aessetkey.aes;
|
||||
const byte* key = info->cipher.aessetkey.key;
|
||||
word32 keySz = info->cipher.aessetkey.keySz;
|
||||
|
||||
/* Validate key */
|
||||
if (key == NULL || keySz == 0 || keySz > AES_256_KEY_SIZE) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* "Import" key to simulated SE storage */
|
||||
XMEMCPY(mockSeKey.key, key, keySz);
|
||||
mockSeKey.keySz = keySz;
|
||||
mockSeKey.valid = 1;
|
||||
|
||||
/* Store handle in aes->devCtx - this is what wolfSSL will use */
|
||||
aes->devCtx = cryptoCbAesMockHandle;
|
||||
|
||||
|
||||
cryptoCbAesSetKeyCalled++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* AES-GCM Encrypt - simulate SE encryption using stored key */
|
||||
if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
|
||||
info->cipher.type == WC_CIPHER_AES_GCM &&
|
||||
info->cipher.enc) {
|
||||
|
||||
Aes* aes = info->cipher.aesgcm_enc.aes;
|
||||
MockSeKeySlot* slot;
|
||||
Aes tempAes;
|
||||
int ret;
|
||||
|
||||
/* Verify handle points to our key slot */
|
||||
if (aes == NULL || aes->devCtx != cryptoCbAesMockHandle) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
slot = (MockSeKeySlot*)aes->devCtx;
|
||||
if (!slot->valid) {
|
||||
return BAD_STATE_E;
|
||||
}
|
||||
|
||||
/* Initialize a temporary Aes for software crypto (simulating SE internal operation) */
|
||||
XMEMSET(&tempAes, 0, sizeof(tempAes));
|
||||
ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID); /* No CryptoCB for internal use */
|
||||
if (ret != 0) return ret;
|
||||
|
||||
ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz);
|
||||
if (ret != 0) {
|
||||
wc_AesFree(&tempAes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Perform the actual encryption */
|
||||
ret = wc_AesGcmEncrypt(&tempAes,
|
||||
info->cipher.aesgcm_enc.out,
|
||||
info->cipher.aesgcm_enc.in,
|
||||
info->cipher.aesgcm_enc.sz,
|
||||
info->cipher.aesgcm_enc.iv,
|
||||
info->cipher.aesgcm_enc.ivSz,
|
||||
info->cipher.aesgcm_enc.authTag,
|
||||
info->cipher.aesgcm_enc.authTagSz,
|
||||
info->cipher.aesgcm_enc.authIn,
|
||||
info->cipher.aesgcm_enc.authInSz);
|
||||
|
||||
wc_AesFree(&tempAes);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* AES-GCM Decrypt - simulate SE decryption using stored key */
|
||||
if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
|
||||
info->cipher.type == WC_CIPHER_AES_GCM &&
|
||||
!info->cipher.enc) {
|
||||
|
||||
Aes* aes = info->cipher.aesgcm_dec.aes;
|
||||
MockSeKeySlot* slot;
|
||||
Aes tempAes;
|
||||
int ret;
|
||||
|
||||
/* Verify handle points to our key slot */
|
||||
if (aes == NULL || aes->devCtx != cryptoCbAesMockHandle) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
slot = (MockSeKeySlot*)aes->devCtx;
|
||||
if (!slot->valid) {
|
||||
return BAD_STATE_E;
|
||||
}
|
||||
|
||||
/* Initialize a temporary Aes for software crypto (simulating SE internal operation) */
|
||||
XMEMSET(&tempAes, 0, sizeof(tempAes));
|
||||
ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID);
|
||||
if (ret != 0) return ret;
|
||||
|
||||
ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz);
|
||||
if (ret != 0) {
|
||||
wc_AesFree(&tempAes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Perform the actual decryption */
|
||||
ret = wc_AesGcmDecrypt(&tempAes,
|
||||
info->cipher.aesgcm_dec.out,
|
||||
info->cipher.aesgcm_dec.in,
|
||||
info->cipher.aesgcm_dec.sz,
|
||||
info->cipher.aesgcm_dec.iv,
|
||||
info->cipher.aesgcm_dec.ivSz,
|
||||
info->cipher.aesgcm_dec.authTag,
|
||||
info->cipher.aesgcm_dec.authTagSz,
|
||||
info->cipher.aesgcm_dec.authIn,
|
||||
info->cipher.aesgcm_dec.authInSz);
|
||||
|
||||
wc_AesFree(&tempAes);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB_FREE
|
||||
/* Free operation - simulate SE key deletion */
|
||||
if (info->algo_type == WC_ALGO_TYPE_FREE &&
|
||||
info->free.algo == WC_ALGO_TYPE_CIPHER &&
|
||||
info->free.type == WC_CIPHER_AES) {
|
||||
|
||||
Aes* aes = (Aes*)info->free.obj;
|
||||
|
||||
if (aes != NULL && aes->devCtx == cryptoCbAesMockHandle) {
|
||||
/* "Delete" key from simulated SE */
|
||||
ForceZero(&mockSeKey, sizeof(mockSeKey));
|
||||
cryptoCbAesFreeCalled++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test: CryptoCB AES SetKey hook for key import / secure element support
|
||||
*/
|
||||
int test_wc_CryptoCb_AesSetKey(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
Aes* aes = NULL;
|
||||
byte* key = NULL;
|
||||
byte* iv = NULL;
|
||||
byte* plain = NULL;
|
||||
byte* cipher = NULL;
|
||||
byte* decrypted = NULL;
|
||||
byte* authTag = NULL;
|
||||
#else
|
||||
Aes aes[1];
|
||||
byte key[AES_128_KEY_SIZE];
|
||||
byte iv[GCM_NONCE_MID_SZ];
|
||||
byte plain[16];
|
||||
byte cipher[16];
|
||||
byte decrypted[16];
|
||||
byte authTag[AES_BLOCK_SIZE];
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
aes = (Aes*)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
key = (byte*)XMALLOC(AES_128_KEY_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
iv = (byte*)XMALLOC(GCM_NONCE_MID_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
plain = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
cipher = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
decrypted = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
authTag = (byte*)XMALLOC(AES_BLOCK_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
if (aes == NULL || key == NULL || iv == NULL || plain == NULL ||
|
||||
cipher == NULL || decrypted == NULL || authTag == NULL) {
|
||||
ret = MEMORY_E;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize key, iv, plain arrays */
|
||||
{
|
||||
static const byte keyData[AES_128_KEY_SIZE] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
||||
};
|
||||
static const byte plainData[16] = {
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77,
|
||||
0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x21, 0x00
|
||||
};
|
||||
XMEMCPY(key, keyData, AES_128_KEY_SIZE);
|
||||
XMEMSET(iv, 0, GCM_NONCE_MID_SZ);
|
||||
XMEMCPY(plain, plainData, 16);
|
||||
}
|
||||
|
||||
XMEMSET(aes, 0, sizeof(Aes));
|
||||
XMEMSET(&mockSeKey, 0, sizeof(mockSeKey));
|
||||
|
||||
/* Reset test state */
|
||||
cryptoCbAesSetKeyCalled = 0;
|
||||
cryptoCbAesFreeCalled = 0;
|
||||
|
||||
/* Register test callback */
|
||||
ret = wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_AES_DEVID,
|
||||
test_CryptoCb_Aes_Cb, NULL);
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* Initialize Aes with device ID */
|
||||
ret = wc_AesInit(aes, NULL, TEST_CRYPTOCB_AES_DEVID);
|
||||
ExpectIntEQ(ret, 0);
|
||||
ExpectIntEQ(aes->devId, TEST_CRYPTOCB_AES_DEVID);
|
||||
|
||||
/* Set key - should trigger CryptoCB and "import" to mock SE */
|
||||
ret = wc_AesGcmSetKey(aes, key, sizeof(key));
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* Verify callback was invoked */
|
||||
ExpectIntEQ(cryptoCbAesSetKeyCalled, 1);
|
||||
|
||||
/* Verify handle stored in devCtx */
|
||||
ExpectPtrEq(aes->devCtx, cryptoCbAesMockHandle);
|
||||
|
||||
/* Verify key was "imported" to mock SE */
|
||||
ExpectIntEQ(mockSeKey.valid, 1);
|
||||
ExpectIntEQ(mockSeKey.keySz, (int)sizeof(key));
|
||||
|
||||
/* Verify keylen metadata stored in Aes struct */
|
||||
ExpectIntEQ(aes->keylen, (int)sizeof(key));
|
||||
|
||||
/* After SetKey succeeds via CryptoCB, verify key NOT in devKey */
|
||||
{
|
||||
byte zeroKey[AES_128_KEY_SIZE] = {0};
|
||||
/* Key should NOT be copied to devKey - SE owns it */
|
||||
ExpectIntEQ(XMEMCMP(aes->devKey, zeroKey, sizeof(key)), 0);
|
||||
}
|
||||
|
||||
/* Test encrypt - callback performs crypto using stored key */
|
||||
ret = wc_AesGcmEncrypt(aes, cipher, plain, sizeof(plain),
|
||||
iv, sizeof(iv), authTag, sizeof(authTag),
|
||||
NULL, 0);
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* Test decrypt - callback performs crypto using stored key */
|
||||
ret = wc_AesGcmDecrypt(aes, decrypted, cipher, sizeof(cipher),
|
||||
iv, sizeof(iv), authTag, sizeof(authTag),
|
||||
NULL, 0);
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* Verify round-trip */
|
||||
ExpectIntEQ(XMEMCMP(plain, decrypted, sizeof(plain)), 0);
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB_FREE
|
||||
/* Free should trigger callback and "delete" key from mock SE */
|
||||
cryptoCbAesFreeCalled = 0;
|
||||
wc_AesFree(aes);
|
||||
|
||||
/* Verify free callback invoked */
|
||||
ExpectIntEQ(cryptoCbAesFreeCalled, 1);
|
||||
|
||||
/* Verify devCtx cleared */
|
||||
ExpectPtrEq(aes->devCtx, NULL);
|
||||
|
||||
/* Verify key was "deleted" from mock SE */
|
||||
ExpectIntEQ(mockSeKey.valid, 0);
|
||||
#else
|
||||
wc_AesFree(aes);
|
||||
#endif
|
||||
|
||||
/* Cleanup */
|
||||
wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_AES_DEVID);
|
||||
|
||||
/* Test software path (no devId) still works */
|
||||
XMEMSET(aes, 0, sizeof(Aes));
|
||||
cryptoCbAesSetKeyCalled = 0;
|
||||
|
||||
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
ret = wc_AesGcmSetKey(aes, key, sizeof(key));
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* Callback should NOT have been invoked */
|
||||
ExpectIntEQ(cryptoCbAesSetKeyCalled, 0);
|
||||
|
||||
/* devCtx should be NULL */
|
||||
ExpectPtrEq(aes->devCtx, NULL);
|
||||
|
||||
wc_AesFree(aes);
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
out:
|
||||
XFREE(aes, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(iv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(cipher, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(decrypted, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(authTag, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_AES_SETKEY && !NO_AES && HAVE_AESGCM */
|
||||
|
||||
/*----------------------------------------------------------------------------*
|
||||
| CryptoCB AES-GCM End-to-End Offload Test
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \
|
||||
!defined(NO_AES) && defined(HAVE_AESGCM)
|
||||
|
||||
#define TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID 8
|
||||
|
||||
/* Test state tracking for end-to-end offload test */
|
||||
static int cryptoCbAesGcmSetKeyCalled = 0;
|
||||
static int cryptoCbAesGcmEncryptCalled = 0;
|
||||
static int cryptoCbAesGcmDecryptCalled = 0;
|
||||
static int cryptoCbAesGcmFreeCalled = 0;
|
||||
|
||||
/* Mock SE key storage for offload test */
|
||||
typedef struct {
|
||||
byte key[AES_256_KEY_SIZE];
|
||||
word32 keySz;
|
||||
int valid;
|
||||
} MockSeKeySlotOffload;
|
||||
|
||||
static MockSeKeySlotOffload mockSeKeyOffload = {0};
|
||||
|
||||
/* Mock handle pointing to our key slot */
|
||||
static void* cryptoCbAesGcmMockHandle = (void*)&mockSeKeyOffload;
|
||||
|
||||
/* Mock CryptoCB callback for end-to-end AES-GCM offload test
|
||||
* This emulates a Secure Element that:
|
||||
* - Stores the key on SetKey (simulating SE key import)
|
||||
* - Performs encryption/decryption using stored key (simulating SE crypto)
|
||||
* - Tracks all callback invocations to verify offload is working
|
||||
* - Uses software AES internally (simulating SE internal operation)
|
||||
*/
|
||||
static int test_CryptoCb_AesGcm_Offload_Cb(int devId, wc_CryptoInfo* info, void* ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
|
||||
if (devId != TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID)
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
|
||||
/* AES SetKey operation - simulate SE key import */
|
||||
if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
|
||||
info->cipher.type == WC_CIPHER_AES &&
|
||||
info->cipher.aessetkey.aes != NULL) {
|
||||
|
||||
Aes* aes = info->cipher.aessetkey.aes;
|
||||
const byte* key = info->cipher.aessetkey.key;
|
||||
word32 keySz = info->cipher.aessetkey.keySz;
|
||||
|
||||
/* Validate key */
|
||||
if (key == NULL || keySz == 0 || keySz > AES_256_KEY_SIZE) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* "Import" key to simulated SE storage */
|
||||
XMEMCPY(mockSeKeyOffload.key, key, keySz);
|
||||
mockSeKeyOffload.keySz = keySz;
|
||||
mockSeKeyOffload.valid = 1;
|
||||
|
||||
/* Store handle in aes->devCtx - this is what wolfSSL will use */
|
||||
aes->devCtx = cryptoCbAesGcmMockHandle;
|
||||
|
||||
|
||||
cryptoCbAesGcmSetKeyCalled++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* AES-GCM Encrypt - simulate SE encryption using stored key */
|
||||
if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
|
||||
info->cipher.type == WC_CIPHER_AES_GCM &&
|
||||
info->cipher.enc) {
|
||||
|
||||
Aes* aes = info->cipher.aesgcm_enc.aes;
|
||||
MockSeKeySlotOffload* slot;
|
||||
Aes tempAes;
|
||||
int ret;
|
||||
|
||||
/* Verify handle points to our key slot */
|
||||
if (aes == NULL || aes->devCtx != cryptoCbAesGcmMockHandle) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
slot = (MockSeKeySlotOffload*)aes->devCtx;
|
||||
if (!slot->valid) {
|
||||
return BAD_STATE_E;
|
||||
}
|
||||
|
||||
/* Track that encrypt callback was invoked */
|
||||
cryptoCbAesGcmEncryptCalled++;
|
||||
|
||||
/* Initialize a temporary Aes for software crypto (simulating SE internal operation) */
|
||||
XMEMSET(&tempAes, 0, sizeof(tempAes));
|
||||
ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID); /* No CryptoCB for internal use */
|
||||
if (ret != 0) return ret;
|
||||
|
||||
ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz);
|
||||
if (ret != 0) {
|
||||
wc_AesFree(&tempAes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Perform the actual encryption using software AES (simulating SE internal operation) */
|
||||
ret = wc_AesGcmEncrypt(&tempAes,
|
||||
info->cipher.aesgcm_enc.out,
|
||||
info->cipher.aesgcm_enc.in,
|
||||
info->cipher.aesgcm_enc.sz,
|
||||
info->cipher.aesgcm_enc.iv,
|
||||
info->cipher.aesgcm_enc.ivSz,
|
||||
info->cipher.aesgcm_enc.authTag,
|
||||
info->cipher.aesgcm_enc.authTagSz,
|
||||
info->cipher.aesgcm_enc.authIn,
|
||||
info->cipher.aesgcm_enc.authInSz);
|
||||
|
||||
wc_AesFree(&tempAes);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* AES-GCM Decrypt - simulate SE decryption using stored key */
|
||||
if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
|
||||
info->cipher.type == WC_CIPHER_AES_GCM &&
|
||||
!info->cipher.enc) {
|
||||
|
||||
Aes* aes = info->cipher.aesgcm_dec.aes;
|
||||
MockSeKeySlotOffload* slot;
|
||||
Aes tempAes;
|
||||
int ret;
|
||||
|
||||
/* Verify handle points to our key slot */
|
||||
if (aes == NULL || aes->devCtx != cryptoCbAesGcmMockHandle) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
slot = (MockSeKeySlotOffload*)aes->devCtx;
|
||||
if (!slot->valid) {
|
||||
return BAD_STATE_E;
|
||||
}
|
||||
|
||||
/* Track that decrypt callback was invoked */
|
||||
cryptoCbAesGcmDecryptCalled++;
|
||||
|
||||
/* Initialize a temporary Aes for software crypto (simulating SE internal operation) */
|
||||
XMEMSET(&tempAes, 0, sizeof(tempAes));
|
||||
ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID);
|
||||
if (ret != 0) return ret;
|
||||
|
||||
ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz);
|
||||
if (ret != 0) {
|
||||
wc_AesFree(&tempAes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Perform the actual decryption using software AES (simulating SE internal operation) */
|
||||
ret = wc_AesGcmDecrypt(&tempAes,
|
||||
info->cipher.aesgcm_dec.out,
|
||||
info->cipher.aesgcm_dec.in,
|
||||
info->cipher.aesgcm_dec.sz,
|
||||
info->cipher.aesgcm_dec.iv,
|
||||
info->cipher.aesgcm_dec.ivSz,
|
||||
info->cipher.aesgcm_dec.authTag,
|
||||
info->cipher.aesgcm_dec.authTagSz,
|
||||
info->cipher.aesgcm_dec.authIn,
|
||||
info->cipher.aesgcm_dec.authInSz);
|
||||
|
||||
wc_AesFree(&tempAes);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB_FREE
|
||||
/* Free operation - simulate SE key deletion */
|
||||
if (info->algo_type == WC_ALGO_TYPE_FREE &&
|
||||
info->free.algo == WC_ALGO_TYPE_CIPHER &&
|
||||
info->free.type == WC_CIPHER_AES) {
|
||||
|
||||
Aes* aes = (Aes*)info->free.obj;
|
||||
|
||||
if (aes != NULL && aes->devCtx == cryptoCbAesGcmMockHandle) {
|
||||
/* "Delete" key from simulated SE */
|
||||
ForceZero(&mockSeKeyOffload, sizeof(mockSeKeyOffload));
|
||||
cryptoCbAesGcmFreeCalled++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test: End-to-End AES-GCM Offload via CryptoCB
|
||||
* This test verifies that:
|
||||
* - AES-GCM encryption/decryption operations are routed through CryptoCb
|
||||
* - Software AES is bypassed when offload is enabled
|
||||
* - Encrypted output and auth tag are correct
|
||||
* - Decryption via CryptoCb restores the original plaintext
|
||||
*/
|
||||
int test_wc_CryptoCb_AesGcm_EncryptDecrypt(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
Aes* aes = NULL;
|
||||
byte* key = NULL;
|
||||
byte* iv = NULL;
|
||||
byte* aad = NULL;
|
||||
byte* plaintext = NULL;
|
||||
byte* ciphertext = NULL;
|
||||
byte* decrypted = NULL;
|
||||
byte* authTag = NULL;
|
||||
#else
|
||||
Aes aes[1];
|
||||
byte key[AES_128_KEY_SIZE];
|
||||
byte iv[GCM_NONCE_MID_SZ];
|
||||
byte aad[16];
|
||||
byte plaintext[32];
|
||||
byte ciphertext[32];
|
||||
byte decrypted[32];
|
||||
byte authTag[AES_BLOCK_SIZE];
|
||||
#endif
|
||||
int ret;
|
||||
int i;
|
||||
int hasNonZero = 0;
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
aes = (Aes*)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
key = (byte*)XMALLOC(AES_128_KEY_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
iv = (byte*)XMALLOC(GCM_NONCE_MID_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
aad = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
plaintext = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
ciphertext = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
decrypted = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
authTag = (byte*)XMALLOC(AES_BLOCK_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
if (aes == NULL || key == NULL || iv == NULL || aad == NULL ||
|
||||
plaintext == NULL || ciphertext == NULL || decrypted == NULL ||
|
||||
authTag == NULL) {
|
||||
ret = MEMORY_E;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize key, iv, aad, plaintext arrays */
|
||||
{
|
||||
static const byte keyData[AES_128_KEY_SIZE] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
||||
};
|
||||
static const byte ivData[GCM_NONCE_MID_SZ] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b
|
||||
};
|
||||
static const byte aadData[16] = {
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
|
||||
};
|
||||
static const byte plaintextData[32] = {
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77,
|
||||
0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x21, 0x00,
|
||||
0x54, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x20, 0x32, 0x21, 0x00
|
||||
};
|
||||
XMEMCPY(key, keyData, AES_128_KEY_SIZE);
|
||||
XMEMCPY(iv, ivData, GCM_NONCE_MID_SZ);
|
||||
XMEMCPY(aad, aadData, 16);
|
||||
XMEMCPY(plaintext, plaintextData, 32);
|
||||
}
|
||||
|
||||
XMEMSET(aes, 0, sizeof(Aes));
|
||||
XMEMSET(&mockSeKeyOffload, 0, sizeof(mockSeKeyOffload));
|
||||
XMEMSET(ciphertext, 0, 32);
|
||||
XMEMSET(decrypted, 0, 32);
|
||||
XMEMSET(authTag, 0, AES_BLOCK_SIZE);
|
||||
|
||||
/* Reset test state */
|
||||
cryptoCbAesGcmSetKeyCalled = 0;
|
||||
cryptoCbAesGcmEncryptCalled = 0;
|
||||
cryptoCbAesGcmDecryptCalled = 0;
|
||||
cryptoCbAesGcmFreeCalled = 0;
|
||||
|
||||
/* Register test callback */
|
||||
ret = wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID,
|
||||
test_CryptoCb_AesGcm_Offload_Cb, NULL);
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* Initialize Aes with device ID */
|
||||
ret = wc_AesInit(aes, NULL, TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID);
|
||||
ExpectIntEQ(ret, 0);
|
||||
ExpectIntEQ(aes->devId, TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID);
|
||||
|
||||
/* Set key - should trigger CryptoCB and "import" to mock SE */
|
||||
ret = wc_AesGcmSetKey(aes, key, sizeof(key));
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* Verify SetKey callback was invoked */
|
||||
ExpectIntEQ(cryptoCbAesGcmSetKeyCalled, 1);
|
||||
|
||||
/* Verify handle stored in devCtx */
|
||||
ExpectPtrEq(aes->devCtx, cryptoCbAesGcmMockHandle);
|
||||
|
||||
/* Verify key was "imported" to mock SE */
|
||||
ExpectIntEQ(mockSeKeyOffload.valid, 1);
|
||||
ExpectIntEQ(mockSeKeyOffload.keySz, (int)sizeof(key));
|
||||
|
||||
/* Verify keylen metadata stored in Aes struct */
|
||||
ExpectIntEQ(aes->keylen, (int)sizeof(key));
|
||||
|
||||
/* Encrypt via wolfCrypt API - should route through CryptoCb */
|
||||
ret = wc_AesGcmEncrypt(aes, ciphertext, plaintext, 32,
|
||||
iv, sizeof(iv), authTag, sizeof(authTag),
|
||||
aad, 16);
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* Assert: Encrypt callback was invoked */
|
||||
ExpectIntEQ(cryptoCbAesGcmEncryptCalled, 1);
|
||||
|
||||
/* Assert: Ciphertext is different from plaintext */
|
||||
ExpectIntNE(XMEMCMP(plaintext, ciphertext, 32), 0);
|
||||
|
||||
/* Assert: Auth tag is non-zero */
|
||||
hasNonZero = 0;
|
||||
for (i = 0; i < (int)sizeof(authTag); i++) {
|
||||
if (authTag[i] != 0) {
|
||||
hasNonZero = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ExpectIntEQ(hasNonZero, 1);
|
||||
|
||||
/* Decrypt via wolfCrypt API - should route through CryptoCb */
|
||||
ret = wc_AesGcmDecrypt(aes, decrypted, ciphertext, 32,
|
||||
iv, sizeof(iv), authTag, sizeof(authTag),
|
||||
aad, 16);
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* Assert: Decrypt callback was invoked */
|
||||
ExpectIntEQ(cryptoCbAesGcmDecryptCalled, 1);
|
||||
|
||||
/* Assert: Decrypted plaintext matches original */
|
||||
ExpectIntEQ(XMEMCMP(plaintext, decrypted, 32), 0);
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB_FREE
|
||||
/* Free should trigger callback and "delete" key from mock SE */
|
||||
cryptoCbAesGcmFreeCalled = 0;
|
||||
wc_AesFree(aes);
|
||||
|
||||
/* Verify free callback invoked */
|
||||
ExpectIntEQ(cryptoCbAesGcmFreeCalled, 1);
|
||||
|
||||
/* Verify devCtx cleared */
|
||||
ExpectPtrEq(aes->devCtx, NULL);
|
||||
|
||||
/* Verify key was "deleted" from mock SE */
|
||||
ExpectIntEQ(mockSeKeyOffload.valid, 0);
|
||||
#else
|
||||
wc_AesFree(aes);
|
||||
#endif
|
||||
|
||||
/* Cleanup */
|
||||
wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID);
|
||||
|
||||
/* Verify lifecycle: SetKey -> Encrypt -> Decrypt -> Free */
|
||||
ExpectIntEQ(cryptoCbAesGcmSetKeyCalled, 1);
|
||||
ExpectIntEQ(cryptoCbAesGcmEncryptCalled, 1);
|
||||
ExpectIntEQ(cryptoCbAesGcmDecryptCalled, 1);
|
||||
#ifdef WOLF_CRYPTO_CB_FREE
|
||||
ExpectIntEQ(cryptoCbAesGcmFreeCalled, 1);
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
out:
|
||||
XFREE(aes, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(iv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(aad, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(plaintext, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(ciphertext, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(decrypted, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(authTag, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_AES_SETKEY && !NO_AES && HAVE_AESGCM */
|
||||
|
||||
|
||||
+15
-1
@@ -53,6 +53,19 @@ int test_wc_AesEaxDecryptAuth(void);
|
||||
|
||||
int test_wc_GmacSetKey(void);
|
||||
int test_wc_GmacUpdate(void);
|
||||
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \
|
||||
!defined(NO_AES) && defined(HAVE_AESGCM)
|
||||
int test_wc_CryptoCb_AesSetKey(void);
|
||||
int test_wc_CryptoCb_AesGcm_EncryptDecrypt(void);
|
||||
#endif
|
||||
|
||||
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \
|
||||
!defined(NO_AES) && defined(HAVE_AESGCM)
|
||||
#define TEST_CRYPTOCB_AES_SETKEY_DECL , TEST_DECL_GROUP("aes", test_wc_CryptoCb_AesSetKey), \
|
||||
TEST_DECL_GROUP("aes", test_wc_CryptoCb_AesGcm_EncryptDecrypt)
|
||||
#else
|
||||
#define TEST_CRYPTOCB_AES_SETKEY_DECL
|
||||
#endif
|
||||
|
||||
#define TEST_AES_DECLS \
|
||||
TEST_DECL_GROUP("aes", test_wc_AesSetKey), \
|
||||
@@ -74,7 +87,8 @@ int test_wc_GmacUpdate(void);
|
||||
TEST_DECL_GROUP("aes", test_wc_AesCcmEncryptDecrypt), \
|
||||
TEST_DECL_GROUP("aes", test_wc_AesXtsSetKey), \
|
||||
TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt_Sizes), \
|
||||
TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt)
|
||||
TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt) \
|
||||
TEST_CRYPTOCB_AES_SETKEY_DECL
|
||||
|
||||
#if defined(WOLFSSL_AES_EAX) && defined(WOLFSSL_AES_256) && \
|
||||
(!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 3)) && !defined(HAVE_SELFTEST)
|
||||
|
||||
+83
-25
@@ -4341,6 +4341,7 @@ static WARN_UNUSED_RESULT int wc_AesDecrypt(
|
||||
int wc_AesSetKey(Aes* aes, const byte* userKey, word32 keylen,
|
||||
const byte* iv, int dir)
|
||||
{
|
||||
int ret;
|
||||
if ((aes == NULL) || (userKey == NULL)) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
@@ -4365,6 +4366,24 @@ static WARN_UNUSED_RESULT int wc_AesDecrypt(
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
if (aes->devId != INVALID_DEVID) {
|
||||
#ifdef WOLF_CRYPTO_CB_AES_SETKEY
|
||||
ret = wc_CryptoCb_AesSetKey(aes, userKey, keylen);
|
||||
if (ret == 0) {
|
||||
/* Callback succeeded - SE owns the key */
|
||||
aes->keylen = (int)keylen;
|
||||
if (iv != NULL)
|
||||
XMEMCPY(aes->reg, iv, WC_AES_BLOCK_SIZE);
|
||||
else
|
||||
XMEMSET(aes->reg, 0, WC_AES_BLOCK_SIZE);
|
||||
return 0;
|
||||
}
|
||||
else if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
|
||||
aes->devCtx = NULL;
|
||||
return ret;
|
||||
}
|
||||
/* CRYPTOCB_UNAVAILABLE: continue to software setup */
|
||||
#endif
|
||||
/* Standard CryptoCB path - copy key to devKey for encrypt/decrypt offload */
|
||||
if (keylen > sizeof(aes->devKey)) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
@@ -4791,6 +4810,33 @@ static void AesSetKey_C(Aes* aes, const byte* key, word32 keySz, int dir)
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
if (aes->devId != INVALID_DEVID) {
|
||||
#ifdef WOLF_CRYPTO_CB_AES_SETKEY
|
||||
ret = wc_CryptoCb_AesSetKey(aes, userKey, keylen);
|
||||
if (ret == 0) {
|
||||
/* Callback succeeded - SE owns the key */
|
||||
aes->keylen = (int)keylen;
|
||||
if (iv != NULL)
|
||||
XMEMCPY(aes->reg, iv, WC_AES_BLOCK_SIZE);
|
||||
else
|
||||
XMEMSET(aes->reg, 0, WC_AES_BLOCK_SIZE);
|
||||
return 0;
|
||||
}
|
||||
else if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
|
||||
aes->devCtx = NULL;
|
||||
return ret;
|
||||
}
|
||||
/* CRYPTOCB_UNAVAILABLE: continue to software setup */
|
||||
#endif
|
||||
/* Standard CryptoCB path - copy key to devKey */
|
||||
if (keylen > sizeof(aes->devKey)) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
XMEMCPY(aes->devKey, userKey, keylen);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_MAXQ10XX_CRYPTO
|
||||
if (wc_MAXQ10XX_AesSetKey(aes, userKey, keylen) != 0) {
|
||||
return WC_HW_E;
|
||||
@@ -7454,46 +7500,55 @@ int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len)
|
||||
}
|
||||
#else
|
||||
#if !defined(FREESCALE_LTC_AES_GCM) && !defined(WOLFSSL_PSOC6_CRYPTO)
|
||||
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB_AES_SETKEY
|
||||
if ((ret == 0) && (aes->devId != INVALID_DEVID && aes->devCtx != NULL)) {
|
||||
/* SE owns key - skip H and M table generation */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (ret == 0) {
|
||||
VECTOR_REGISTERS_PUSH;
|
||||
/* AES-NI code generates its own H value, but generate it here too, to
|
||||
* assure pure-C fallback is always usable.
|
||||
*/
|
||||
|
||||
/* Generate H = AES_Encrypt(key, 0^128) */
|
||||
ret = wc_AesEncrypt(aes, iv, aes->gcm.H);
|
||||
|
||||
if (ret == 0) {
|
||||
#if defined(GCM_TABLE) || defined(GCM_TABLE_4BIT)
|
||||
#if defined(GCM_TABLE) || defined(GCM_TABLE_4BIT)
|
||||
#if defined(WOLFSSL_AESNI) && defined(GCM_TABLE_4BIT)
|
||||
if (aes->use_aesni) {
|
||||
#if defined(WC_C_DYNAMIC_FALLBACK)
|
||||
#ifdef HAVE_INTEL_AVX2
|
||||
if (IS_INTEL_AVX2(intel_flags)) {
|
||||
GCM_generate_m0_avx2(aes->gcm.H, (byte*)aes->gcm.M0);
|
||||
GCM_generate_m0_avx2(aes->gcm.H,
|
||||
(byte*)aes->gcm.M0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if defined(HAVE_INTEL_AVX1)
|
||||
if (IS_INTEL_AVX1(intel_flags)) {
|
||||
GCM_generate_m0_avx1(aes->gcm.H, (byte*)aes->gcm.M0);
|
||||
GCM_generate_m0_avx1(aes->gcm.H,
|
||||
(byte*)aes->gcm.M0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
GCM_generate_m0_aesni(aes->gcm.H, (byte*)aes->gcm.M0);
|
||||
GCM_generate_m0_aesni(aes->gcm.H,
|
||||
(byte*)aes->gcm.M0);
|
||||
}
|
||||
#endif
|
||||
#endif /* WC_C_DYNAMIC_FALLBACK */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#endif /* AESNI */
|
||||
{
|
||||
GenerateM0(&aes->gcm);
|
||||
}
|
||||
#endif /* GCM_TABLE || GCM_TABLE_4BIT */
|
||||
#endif /* GCM_TABLE || GCM_TABLE_4BIT */
|
||||
}
|
||||
|
||||
VECTOR_REGISTERS_POP;
|
||||
}
|
||||
|
||||
#endif /* !FREESCALE_LTC_AES_GCM && !WOLFSSL_PSOC6_CRYPTO */
|
||||
#endif
|
||||
|
||||
@@ -7503,7 +7558,15 @@ int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len)
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
if (aes->devId != INVALID_DEVID) {
|
||||
XMEMCPY(aes->devKey, key, len);
|
||||
#ifdef WOLF_CRYPTO_CB_AES_SETKEY
|
||||
if (aes->devCtx != NULL) {
|
||||
/* SE owns key - don't copy to devKey */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
XMEMCPY(aes->devKey, key, len);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -13302,6 +13365,7 @@ int wc_AesInit(Aes* aes, void* heap, int devId)
|
||||
|
||||
#if defined(WOLF_CRYPTO_CB) || defined(WOLFSSL_STM32U5_DHUK)
|
||||
aes->devId = devId;
|
||||
aes->devCtx = NULL;
|
||||
#else
|
||||
(void)devId;
|
||||
#endif
|
||||
@@ -13383,10 +13447,6 @@ int wc_AesInit_Label(Aes* aes, const char* label, void* heap, int devId)
|
||||
/* Free Aes resources */
|
||||
void wc_AesFree(Aes* aes)
|
||||
{
|
||||
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE)
|
||||
int ret = 0;
|
||||
#endif
|
||||
|
||||
if (aes == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -13396,19 +13456,17 @@ void wc_AesFree(Aes* aes)
|
||||
if (aes->devId != INVALID_DEVID)
|
||||
#endif
|
||||
{
|
||||
ret = wc_CryptoCb_Free(aes->devId, WC_ALGO_TYPE_CIPHER,
|
||||
WC_CIPHER_AES, (void*)aes);
|
||||
/* If they want the standard free, they can call it themselves */
|
||||
/* via their callback setting devId to INVALID_DEVID */
|
||||
/* otherwise assume the callback handled it */
|
||||
int ret = wc_CryptoCb_Free(aes->devId, WC_ALGO_TYPE_CIPHER,
|
||||
WC_CIPHER_AES, aes);
|
||||
#ifdef WOLF_CRYPTO_CB_AES_SETKEY
|
||||
aes->devCtx = NULL; /* Clear device context handle */
|
||||
#endif
|
||||
/* If callback wants standard free, it can set devId to INVALID_DEVID.
|
||||
* Otherwise assume the callback handled cleanup. */
|
||||
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
|
||||
return;
|
||||
/* fall-through when unavailable */
|
||||
}
|
||||
|
||||
/* silence compiler warning */
|
||||
(void)ret;
|
||||
|
||||
#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_FREE */
|
||||
|
||||
#ifdef WC_DEBUG_CIPHER_LIFECYCLE
|
||||
|
||||
@@ -1537,6 +1537,36 @@ int wc_CryptoCb_AesEcbDecrypt(Aes* aes, byte* out,
|
||||
return wc_CryptoCb_TranslateErrorCode(ret);
|
||||
}
|
||||
#endif /* HAVE_AES_ECB */
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB_AES_SETKEY
|
||||
int wc_CryptoCb_AesSetKey(Aes* aes, const byte* key, word32 keySz)
|
||||
{
|
||||
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
CryptoCb* dev;
|
||||
|
||||
if (aes == NULL || key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
if (aes->devId == INVALID_DEVID)
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
|
||||
/* locate registered callback */
|
||||
dev = wc_CryptoCb_FindDevice(aes->devId, WC_ALGO_TYPE_CIPHER);
|
||||
if (dev && dev->cb) {
|
||||
wc_CryptoInfo cryptoInfo;
|
||||
XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo));
|
||||
cryptoInfo.algo_type = WC_ALGO_TYPE_CIPHER;
|
||||
cryptoInfo.cipher.type = WC_CIPHER_AES;
|
||||
cryptoInfo.cipher.aessetkey.aes = aes;
|
||||
cryptoInfo.cipher.aessetkey.key = key;
|
||||
cryptoInfo.cipher.aessetkey.keySz = keySz;
|
||||
|
||||
ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx);
|
||||
}
|
||||
|
||||
return wc_CryptoCb_TranslateErrorCode(ret);
|
||||
}
|
||||
#endif /* WOLF_CRYPTO_CB_AES_SETKEY */
|
||||
#endif /* !NO_AES */
|
||||
|
||||
#ifndef NO_DES3
|
||||
|
||||
@@ -334,7 +334,7 @@ struct Aes {
|
||||
#endif /* __aarch64__ && WOLFSSL_ARMASM && !WOLFSSL_ARMASM_NO_HW_CRYPTO */
|
||||
#if defined(WOLF_CRYPTO_CB) || defined(WOLFSSL_STM32U5_DHUK)
|
||||
int devId;
|
||||
void* devCtx;
|
||||
void* devCtx; /* Opaque handle for CryptoCB device */
|
||||
#endif
|
||||
#ifdef WOLF_PRIVATE_KEY_ID
|
||||
byte id[AES_MAX_ID_LEN];
|
||||
|
||||
@@ -376,6 +376,13 @@ typedef struct wc_CryptoInfo {
|
||||
const byte* in;
|
||||
word32 sz;
|
||||
} des3;
|
||||
#endif
|
||||
#if !defined(NO_AES) && defined(WOLF_CRYPTO_CB_AES_SETKEY)
|
||||
struct {
|
||||
Aes* aes;
|
||||
const byte* key;
|
||||
word32 keySz;
|
||||
} aessetkey;
|
||||
#endif
|
||||
void* ctx;
|
||||
#ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES
|
||||
@@ -678,6 +685,9 @@ WOLFSSL_LOCAL int wc_CryptoCb_AesEcbEncrypt(Aes* aes, byte* out,
|
||||
WOLFSSL_LOCAL int wc_CryptoCb_AesEcbDecrypt(Aes* aes, byte* out,
|
||||
const byte* in, word32 sz);
|
||||
#endif /* HAVE_AES_ECB */
|
||||
#ifdef WOLF_CRYPTO_CB_AES_SETKEY
|
||||
WOLFSSL_API int wc_CryptoCb_AesSetKey(Aes* aes, const byte* key, word32 keySz);
|
||||
#endif /* WOLF_CRYPTO_CB_AES_SETKEY */
|
||||
#endif /* !NO_AES */
|
||||
|
||||
#ifndef NO_DES3
|
||||
|
||||
Reference in New Issue
Block a user