From 51f5129049af2ae5ac4e4e925ed3fea89f6970e5 Mon Sep 17 00:00:00 2001 From: night1rider Date: Fri, 30 Oct 2026 16:25:11 -0600 Subject: [PATCH 1/2] Add wc_CryptoCb_SetKeyLocation for SetKey callbacks A callback can mark an HMAC key as kept on the device only. --- .wolfssl_known_macro_extras | 1 + wolfcrypt/src/cryptocb.c | 29 +++++++++++++++++++++++++++++ wolfcrypt/src/hmac.c | 29 +++++++++++++++++++++++++++++ wolfssl/wolfcrypt/cryptocb.h | 7 +++++++ wolfssl/wolfcrypt/hmac.h | 14 ++++++++++++++ 5 files changed, 80 insertions(+) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 02a88c29308..c29d62333d1 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -1098,6 +1098,7 @@ WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK WOLFSSL_NO_ETM_ALERT WOLFSSL_NO_FCHMOD WOLFSSL_NO_FENCE +WOLFSSL_NO_HMAC_KEY_LOCATION WOLFSSL_NO_ISSUERHASH_TDPEER WOLFSSL_NO_KCAPI_AES_CBC WOLFSSL_NO_KCAPI_HMAC_SHA1 diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index 5b3864969e3..e93a9b867cc 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -4637,6 +4637,35 @@ int wc_CryptoCb_SetKey(int devId, int type, void* obj, return wc_CryptoCb_TranslateErrorCode(ret); } + +/* Lets a SetKey callback say where the key in its info is kept (default + * WC_KEY_SW_STORED), using the setter for the key's algorithm. + * Returns 0, BAD_FUNC_ARG on bad args, NOT_COMPILED_IN for other types. */ +int wc_CryptoCb_SetKeyLocation(wc_CryptoInfo* info, int location) +{ + if (info == NULL || info->algo_type != WC_ALGO_TYPE_SETKEY || + info->setkey.obj == NULL) { + return BAD_FUNC_ARG; + } + + switch (info->setkey.type) { + #ifndef NO_AES + case WC_SETKEY_AES: + /* The AES key guards already refuse a claimed key with no + * schedule, so there is nothing to record. */ + if (location != WC_KEY_SW_STORED && location != WC_KEY_HW_STORED) + return BAD_FUNC_ARG; + return 0; + #endif + #ifdef WC_HMAC_HAVE_KEY_LOCATION + case WC_SETKEY_HMAC: + return wc_HmacSetKeyLocation((Hmac*)info->setkey.obj, location); + #endif + default: + (void)location; + return NOT_COMPILED_IN; + } +} #endif /* WOLF_CRYPTO_CB_SETKEY */ #ifdef WOLF_CRYPTO_CB_EXPORT_KEY diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index fb1c447bfc2..6b2fe826f5f 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -728,6 +728,9 @@ int wc_HmacSetKey_ex(Hmac* hmac, int type, const byte* key, word32 length, hmac->innerHashKeyed = 0; hmac->macType = (byte)type; +#ifdef WC_HMAC_HAVE_KEY_LOCATION + hmac->keyLocation = WC_KEY_SW_STORED; +#endif ret = _InitHmac(hmac, type, heap); if (ret != 0) @@ -1180,6 +1183,20 @@ static int HmacKeyNotInSoftware(const Hmac* hmac) } #endif +#ifdef WC_HMAC_HAVE_KEY_LOCATION +/* Records where the key is kept, for wc_CryptoCb_SetKeyLocation(). + * WC_KEY_HW_STORED makes software Update and Final fail with MISSING_KEY. + * Returns 0, or BAD_FUNC_ARG for an unknown location. */ +int wc_HmacSetKeyLocation(Hmac* hmac, int location) +{ + if (location != WC_KEY_SW_STORED && location != WC_KEY_HW_STORED) { + return BAD_FUNC_ARG; + } + hmac->keyLocation = (byte)location; + return 0; +} +#endif + int wc_HmacUpdate(Hmac* hmac, const byte* msg, word32 length) { int ret = 0; @@ -1203,6 +1220,12 @@ int wc_HmacUpdate(Hmac* hmac, const byte* msg, word32 length) if (HmacKeyNotInSoftware(hmac)) return MISSING_KEY; #endif +#ifdef WC_HMAC_HAVE_KEY_LOCATION + /* The key is on the device only: software has no ipad/opad to use. */ + if (hmac->keyLocation == WC_KEY_HW_STORED) { + return MISSING_KEY; + } +#endif #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC) if (hmac->asyncDev.marker == WOLFSSL_ASYNC_MARKER_HMAC) { #if defined(HAVE_CAVIUM) @@ -1343,6 +1366,12 @@ int wc_HmacFinal(Hmac* hmac, byte* hash) if (HmacKeyNotInSoftware(hmac)) return MISSING_KEY; #endif +#ifdef WC_HMAC_HAVE_KEY_LOCATION + /* The key is on the device only: software has no ipad/opad to use. */ + if (hmac->keyLocation == WC_KEY_HW_STORED) { + return MISSING_KEY; + } +#endif #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC) if (hmac->asyncDev.marker == WOLFSSL_ASYNC_MARKER_HMAC) { int hashLen = wc_HmacSizeByType(hmac->macType); diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index 34cf2212e65..ecd4f8cc2d2 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -201,6 +201,11 @@ enum wc_SetKeyType { WC_SETKEY_ECC_PRIV = 5, WC_SETKEY_AES = 6, }; + +/* Where a key given to a SetKey callback is kept; see + * wc_CryptoCb_SetKeyLocation() */ +#define WC_KEY_SW_STORED 0 /* default: software has the key */ +#define WC_KEY_HW_STORED 1 /* the key is on the device only */ #endif /* WOLF_CRYPTO_CB_SETKEY */ #ifdef WOLF_CRYPTO_CB_KEYSTORE @@ -1694,6 +1699,8 @@ WOLFSSL_LOCAL int wc_CryptoCb_Free(int devId, int algo, int type, int subType, void* obj); #endif /* WOLF_CRYPTO_CB_FREE */ #ifdef WOLF_CRYPTO_CB_SETKEY +WOLFSSL_API int wc_CryptoCb_SetKeyLocation(wc_CryptoInfo* info, + int location); WOLFSSL_LOCAL int wc_CryptoCb_SetKey(int devId, int type, void* obj, void* key, word32 keySz, void* aux, word32 auxSz, diff --git a/wolfssl/wolfcrypt/hmac.h b/wolfssl/wolfcrypt/hmac.h index 1dd946f3d40..a874c31d3f3 100644 --- a/wolfssl/wolfcrypt/hmac.h +++ b/wolfssl/wolfcrypt/hmac.h @@ -65,6 +65,14 @@ #define WC_HMAC_INNER_HASH_KEYED_SW 1 #define WC_HMAC_INNER_HASH_KEYED_DEV 2 +/* Hmac.keyLocation exists for the generic SetKey crypto callback, which sets + * it with wc_CryptoCb_SetKeyLocation() (WC_KEY_* values in cryptocb.h). + * Define WOLFSSL_NO_HMAC_KEY_LOCATION to compile it out. */ +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_SETKEY) && \ + !defined(WOLFSSL_NO_HMAC_KEY_LOCATION) + #define WC_HMAC_HAVE_KEY_LOCATION +#endif + enum { HMAC_FIPS_MIN_KEY = 14, /* 112 bit key length minimum. Note that this * minimum also applies to the salt length for @@ -135,6 +143,9 @@ struct Hmac { void* heap; /* heap hint */ byte macType; /* md5 sha or sha256 */ byte innerHashKeyed; /* keyed flag */ +#ifdef WC_HMAC_HAVE_KEY_LOCATION + byte keyLocation; /* WC_KEY_SW_STORED or WC_KEY_HW_STORED */ +#endif #ifdef WOLFSSL_KCAPI_HMAC struct kcapi_handle* handle; #endif @@ -204,6 +215,9 @@ WOLFSSL_API int wolfSSL_GetHmacMaxSize(void); WOLFSSL_LOCAL int _InitHmac(Hmac* hmac, int type, void* heap); WOLFSSL_LOCAL int _HmacInitIOHashes(Hmac* hmac); +#ifdef WC_HMAC_HAVE_KEY_LOCATION +WOLFSSL_LOCAL int wc_HmacSetKeyLocation(Hmac* hmac, int location); +#endif #ifdef HAVE_HKDF From ac289354e8fb7b493aa99c6c77041bd5b83bb60b Mon Sep 17 00:00:00 2001 From: night1rider Date: Fri, 30 Oct 2026 16:25:11 -0600 Subject: [PATCH 2/2] Add tests for SetKey callbacks that keep the key in hardware Covers wc_CryptoCb_SetKeyLocation and AES and HMAC device-only keys. --- tests/api/test_aes.c | 177 ++++++++++++++++++++++++++++++++++++++++++ tests/api/test_aes.h | 21 +++++ tests/api/test_hmac.c | 64 +++++++++++++++ tests/api/test_hmac.h | 2 + 4 files changed, 264 insertions(+) diff --git a/tests/api/test_aes.c b/tests/api/test_aes.c index a4167fc9c7b..84d5c30d53d 100644 --- a/tests/api/test_aes.c +++ b/tests/api/test_aes.c @@ -12524,6 +12524,183 @@ int test_wc_CryptoCb_AesDirect(void) #endif /* WC_AES_DIRECT_CRYPTO_CB && WOLFSSL_AES_128 && HAVE_AES_DECRYPT */ +/*----------------------------------------------------------------------------* + | CryptoCB SetKey location API + *----------------------------------------------------------------------------*/ + +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_SETKEY) && \ + !defined(NO_AES) + +#include + +int test_wc_CryptoCb_SetKeyLocation(void) +{ + EXPECT_DECLS; + Aes aes; + wc_CryptoInfo info; + + XMEMSET(&aes, 0, sizeof(aes)); + XMEMSET(&info, 0, sizeof(info)); + info.setkey.type = WC_SETKEY_AES; + info.setkey.obj = &aes; + + /* Bad arguments */ + ExpectIntEQ(wc_CryptoCb_SetKeyLocation(NULL, WC_KEY_HW_STORED), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_CryptoCb_SetKeyLocation(&info, WC_KEY_HW_STORED), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + info.algo_type = WC_ALGO_TYPE_SETKEY; + info.setkey.obj = NULL; + ExpectIntEQ(wc_CryptoCb_SetKeyLocation(&info, WC_KEY_HW_STORED), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + info.setkey.obj = &aes; + ExpectIntEQ(wc_CryptoCb_SetKeyLocation(&info, 2), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* AES accepts both locations */ + ExpectIntEQ(wc_CryptoCb_SetKeyLocation(&info, WC_KEY_HW_STORED), 0); + ExpectIntEQ(wc_CryptoCb_SetKeyLocation(&info, WC_KEY_SW_STORED), 0); + + /* A key type with no location support */ + info.setkey.type = WC_SETKEY_NONE; + ExpectIntEQ(wc_CryptoCb_SetKeyLocation(&info, WC_KEY_HW_STORED), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + + return EXPECT_RESULT(); +} + +#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_SETKEY && !NO_AES */ + +/*----------------------------------------------------------------------------* + | CryptoCB AES SetKey: device-only key + *----------------------------------------------------------------------------*/ + +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_SETKEY) && \ + defined(HAVE_AES_CBC) && defined(HAVE_AES_DECRYPT) && \ + defined(WOLFSSL_AES_128) && defined(WOLFSSL_AES_REQUIRE_KEY_SET) + +#include + +#define TEST_CRYPTOCB_AES_NOSW_DEVID 16 + +/* Set to make the mock decline SetKey, so software keeps the key. */ +static int test_CryptoCb_AesNoSw_Decline = 0; + +/* Mock device that keeps the key in hardware: the generic SetKey succeeds and + * marks the key HW stored. Every other request is declined, + * including the AES-specific SetKey, so the generic one is used. */ +static int test_CryptoCb_AesNoSw_Cb(int devId, wc_CryptoInfo* info, + void* ctx) +{ + (void)ctx; + if (devId != TEST_CRYPTOCB_AES_NOSW_DEVID || info == NULL) + return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + if (info->algo_type == WC_ALGO_TYPE_SETKEY && + info->setkey.type == WC_SETKEY_AES && + !test_CryptoCb_AesNoSw_Decline) { + return wc_CryptoCb_SetKeyLocation(info, WC_KEY_HW_STORED); + } + return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); +} + +int test_wc_CryptoCb_AesNoSwKey(void) +{ + EXPECT_DECLS; + Aes aes; + WOLFSSL_SMALL_STACK_STATIC const byte key[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + byte iv[WC_AES_BLOCK_SIZE]; + byte in[WC_AES_BLOCK_SIZE]; + byte out[WC_AES_BLOCK_SIZE]; +#ifdef WOLFSSL_AES_XTS + XtsAes xts; + WOLFSSL_SMALL_STACK_STATIC const byte xtsKey[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; +#endif + + XMEMSET(iv, 0, sizeof(iv)); + XMEMSET(in, 0, sizeof(in)); + + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_AES_NOSW_DEVID, + test_CryptoCb_AesNoSw_Cb, NULL), 0); + XMEMSET(&aes, 0, sizeof(aes)); + ExpectIntEQ(wc_AesInit(&aes, NULL, TEST_CRYPTOCB_AES_NOSW_DEVID), 0); + + /* The device took the key; software has none to fall back on */ + ExpectIntEQ(wc_AesSetKey(&aes, key, (word32)sizeof(key), iv, + AES_ENCRYPTION), 0); + ExpectIntEQ(wc_AesCbcEncrypt(&aes, out, in, sizeof(in)), + WC_NO_ERR_TRACE(MISSING_KEY)); + + ExpectIntEQ(wc_AesSetKey(&aes, key, (word32)sizeof(key), iv, + AES_DECRYPTION), 0); + ExpectIntEQ(wc_AesCbcDecrypt(&aes, out, in, sizeof(in)), + WC_NO_ERR_TRACE(MISSING_KEY)); + +#if defined(HAVE_AESGCM) && defined(WOLFSSL_AESGCM_STREAM) + /* Streaming GCM has no device path, so a HW-stored key must not pass */ + ExpectIntEQ(wc_AesGcmSetKey(&aes, key, (word32)sizeof(key)), 0); + ExpectIntEQ(wc_AesGcmEncryptUpdate(&aes, out, in, sizeof(in), NULL, 0), + WC_NO_ERR_TRACE(MISSING_KEY)); + /* Init caches the IV until a usable key is set; data still fails */ + ExpectIntEQ(wc_AesGcmInit(&aes, NULL, 0, iv, GCM_NONCE_MID_SZ), 0); + ExpectIntEQ(wc_AesGcmEncryptUpdate(&aes, out, in, sizeof(in), NULL, 0), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_AesGcmInit(&aes, key, (word32)sizeof(key), iv, + GCM_NONCE_MID_SZ), 0); + ExpectIntEQ(wc_AesGcmEncryptUpdate(&aes, out, in, sizeof(in), NULL, 0), + WC_NO_ERR_TRACE(MISSING_KEY)); + + /* A HW-stored rekey must also stop a streaming GCM started in software */ + test_CryptoCb_AesNoSw_Decline = 1; + ExpectIntEQ(wc_AesGcmInit(&aes, key, (word32)sizeof(key), iv, + GCM_NONCE_MID_SZ), 0); + test_CryptoCb_AesNoSw_Decline = 0; + ExpectIntEQ(wc_AesSetKey(&aes, key, (word32)sizeof(key), iv, + AES_ENCRYPTION), 0); + ExpectIntEQ(wc_AesGcmEncryptFinal(&aes, out, sizeof(out)), + WC_NO_ERR_TRACE(MISSING_KEY)); +#endif + + /* A new key the device declines is kept in software and must work */ + test_CryptoCb_AesNoSw_Decline = 1; + ExpectIntEQ(wc_AesSetKey(&aes, key, (word32)sizeof(key), iv, + AES_ENCRYPTION), 0); + ExpectIntEQ(wc_AesCbcEncrypt(&aes, out, in, sizeof(in)), 0); + test_CryptoCb_AesNoSw_Decline = 0; + +#ifdef WOLFSSL_AES_XTS + /* A HW-stored key replacing a software one must not leave the old + * schedule usable: XTS only checks rounds */ + XMEMSET(&xts, 0, sizeof(xts)); + ExpectIntEQ(wc_AesXtsInit(&xts, NULL, TEST_CRYPTOCB_AES_NOSW_DEVID), 0); + test_CryptoCb_AesNoSw_Decline = 1; + ExpectIntEQ(wc_AesXtsSetKeyNoInit(&xts, xtsKey, (word32)sizeof(xtsKey), + AES_ENCRYPTION), 0); + test_CryptoCb_AesNoSw_Decline = 0; + ExpectIntEQ(wc_AesXtsSetKeyNoInit(&xts, xtsKey, (word32)sizeof(xtsKey), + AES_ENCRYPTION), 0); + ExpectIntEQ(wc_AesXtsEncrypt(&xts, out, in, sizeof(in), iv, sizeof(iv)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_AesXtsFree(&xts); +#endif + + wc_AesFree(&aes); + wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_AES_NOSW_DEVID); + + return EXPECT_RESULT(); +} + +#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_SETKEY && HAVE_AES_CBC && + * HAVE_AES_DECRYPT && WOLFSSL_AES_128 && + * WOLFSSL_AES_REQUIRE_KEY_SET */ + /*----------------------------------------------------------------------------* | CryptoCB AES SetKey Test *----------------------------------------------------------------------------*/ diff --git a/tests/api/test_aes.h b/tests/api/test_aes.h index e23560a39ad..34ad473a494 100644 --- a/tests/api/test_aes.h +++ b/tests/api/test_aes.h @@ -202,6 +202,25 @@ int test_wc_CryptoCb_AesDirect(void); #define TEST_CRYPTOCB_AES_DIRECT_DECL #endif +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_SETKEY) && \ + !defined(NO_AES) +int test_wc_CryptoCb_SetKeyLocation(void); +#define TEST_CRYPTOCB_SETKEY_LOCATION_DECL \ + , TEST_DECL_GROUP("aes", test_wc_CryptoCb_SetKeyLocation) +#else +#define TEST_CRYPTOCB_SETKEY_LOCATION_DECL +#endif + +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_SETKEY) && \ + defined(HAVE_AES_CBC) && defined(HAVE_AES_DECRYPT) && \ + defined(WOLFSSL_AES_128) && defined(WOLFSSL_AES_REQUIRE_KEY_SET) +int test_wc_CryptoCb_AesNoSwKey(void); +#define TEST_CRYPTOCB_AES_NOSW_KEY_DECL \ + , TEST_DECL_GROUP("aes", test_wc_CryptoCb_AesNoSwKey) +#else +#define TEST_CRYPTOCB_AES_NOSW_KEY_DECL +#endif + #define TEST_AES_DECLS \ TEST_DECL_GROUP("aes", test_wc_AesSetKey), \ TEST_DECL_GROUP("aes", test_wc_AesSetIV), \ @@ -280,6 +299,8 @@ int test_wc_CryptoCb_AesDirect(void); TEST_CRYPTOCB_AES_SETKEY_DECL \ TEST_CRYPTOCB_AES_KEYWRAP_DECL \ TEST_CRYPTOCB_AES_DIRECT_DECL \ + TEST_CRYPTOCB_SETKEY_LOCATION_DECL \ + TEST_CRYPTOCB_AES_NOSW_KEY_DECL \ TEST_CRYPTOCB_TLS13_KEY_ZERO_DECL \ TEST_CRYPTOCB_AESCFB_DECL \ TEST_CRYPTOCB_AESOFB_DECL diff --git a/tests/api/test_hmac.c b/tests/api/test_hmac.c index 6b7e46a6f57..916f5c48ab4 100644 --- a/tests/api/test_hmac.c +++ b/tests/api/test_hmac.c @@ -1265,6 +1265,70 @@ int test_wc_HmacId_NoDevice(void) return EXPECT_RESULT(); } /* END test_wc_HmacId_NoDevice */ +#if !defined(NO_HMAC) && !defined(NO_SHA256) && defined(WOLF_CRYPTO_CB) && \ + defined(WOLF_CRYPTO_CB_SETKEY) && \ + !defined(WOLFSSL_NO_HMAC_KEY_LOCATION) && !defined(WOLFSSL_KCAPI_HMAC) +#define TEST_HMAC_NOSW_DEVID 0x484d4b48 /* "HMKH" */ + +/* Set to make the mock decline SetKey, so software keeps the key. */ +static int test_hmac_nosw_decline = 0; + +/* Mock device that keeps the key in hardware: SetKey succeeds and marks the + * key HW stored. Every HMAC request is declined. */ +static int test_hmac_nosw_cb(int cbDevId, wc_CryptoInfo* info, void* ctx) +{ + (void)ctx; + if (cbDevId != TEST_HMAC_NOSW_DEVID || info == NULL) + return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + if (info->algo_type == WC_ALGO_TYPE_SETKEY && + info->setkey.type == WC_SETKEY_HMAC && !test_hmac_nosw_decline) { + return wc_CryptoCb_SetKeyLocation(info, WC_KEY_HW_STORED); + } + return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); +} +#endif + +/* A SetKey callback that keeps the key in hardware leaves software with no + * ipad/opad, so a declined update/final must fail rather than MAC with an + * empty key. */ +int test_wc_HmacNoSwKey_CryptoCb(void) +{ + EXPECT_DECLS; +#if !defined(NO_HMAC) && !defined(NO_SHA256) && defined(WOLF_CRYPTO_CB) && \ + defined(WOLF_CRYPTO_CB_SETKEY) && \ + !defined(WOLFSSL_NO_HMAC_KEY_LOCATION) && !defined(WOLFSSL_KCAPI_HMAC) + Hmac hmac; + byte msg[16]; + byte out[WC_SHA256_DIGEST_SIZE]; + + XMEMSET(msg, 0, sizeof(msg)); + XMEMSET(&hmac, 0, sizeof(hmac)); + + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_HMAC_NOSW_DEVID, + test_hmac_nosw_cb, NULL), 0); + ExpectIntEQ(wc_HmacInit(&hmac, NULL, TEST_HMAC_NOSW_DEVID), 0); + + /* The device took the key; software has none to fall back on */ + ExpectIntEQ(wc_HmacSetKey(&hmac, WC_SHA256, + (const byte*)"0123456789abcdef", 16), 0); + ExpectIntEQ(wc_HmacUpdate(&hmac, msg, sizeof(msg)), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_HmacFinal(&hmac, out), WC_NO_ERR_TRACE(MISSING_KEY)); + + /* A new key the device declines is kept in software and must work */ + test_hmac_nosw_decline = 1; + ExpectIntEQ(wc_HmacSetKey(&hmac, WC_SHA256, + (const byte*)"0123456789abcdef", 16), 0); + ExpectIntEQ(wc_HmacUpdate(&hmac, msg, sizeof(msg)), 0); + ExpectIntEQ(wc_HmacFinal(&hmac, out), 0); + test_hmac_nosw_decline = 0; + + wc_HmacFree(&hmac); + wc_CryptoCb_UnRegisterDevice(TEST_HMAC_NOSW_DEVID); +#endif + return EXPECT_RESULT(); +} /* END test_wc_HmacNoSwKey_CryptoCb */ + /* * MC/DC: wc_HKDF_Extract_ex()/wc_HKDF_Expand_ex() share the guard shape * (out == NULL || (inKey == NULL && inKeySz > 0)) at two physical diff --git a/tests/api/test_hmac.h b/tests/api/test_hmac.h index 7847fce049c..639a65f7814 100644 --- a/tests/api/test_hmac.h +++ b/tests/api/test_hmac.h @@ -48,6 +48,7 @@ int test_wc_HmacInit_Label(void); int test_wc_HmacFree_CryptoCb(void); int test_wc_HmacId_CryptoCb(void); int test_wc_HmacId_NoDevice(void); +int test_wc_HmacNoSwKey_CryptoCb(void); int test_wc_HKDF_NullKeyEdgeCases(void); int test_wc_Tls13_HKDF_Extract_ZeroLenIkm(void); @@ -76,6 +77,7 @@ int test_wc_Tls13_HKDF_Extract_ZeroLenIkm(void); TEST_DECL_GROUP("hmac", test_wc_HmacFree_CryptoCb), \ TEST_DECL_GROUP("hmac", test_wc_HmacId_CryptoCb), \ TEST_DECL_GROUP("hmac", test_wc_HmacId_NoDevice), \ + TEST_DECL_GROUP("hmac", test_wc_HmacNoSwKey_CryptoCb), \ TEST_DECL_GROUP("hmac", test_wc_HKDF_NullKeyEdgeCases), \ TEST_DECL_GROUP("hmac", test_wc_Tls13_HKDF_Extract_ZeroLenIkm)