diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index c3af7ed608..197a435649 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -230,6 +230,10 @@ static const char* GetKdfTypeStr(int type) switch (type) { case WC_KDF_TYPE_HKDF: return "HKDF"; + case WC_KDF_TYPE_HKDF_EXTRACT: + return "HKDF Extract"; + case WC_KDF_TYPE_HKDF_EXPAND: + return "HKDF Expand"; case WC_KDF_TYPE_TWOSTEP_CMAC: return "TWOSTEP_CMAC"; } @@ -2527,6 +2531,64 @@ int wc_CryptoCb_Hkdf(int hashType, const byte* inKey, word32 inKeySz, return wc_CryptoCb_TranslateErrorCode(ret); } + +int wc_CryptoCb_Hkdf_Extract(int hashType, const byte* salt, word32 saltSz, + const byte* inKey, word32 inKeySz, byte* out, int devId) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + /* Find registered callback device */ + dev = wc_CryptoCb_FindDevice(devId, WC_ALGO_TYPE_KDF); + + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + + cryptoInfo.algo_type = WC_ALGO_TYPE_KDF; + cryptoInfo.kdf.type = WC_KDF_TYPE_HKDF_EXTRACT; + cryptoInfo.kdf.hkdf_extract.hashType = hashType; + cryptoInfo.kdf.hkdf_extract.salt = salt; + cryptoInfo.kdf.hkdf_extract.saltSz = saltSz; + cryptoInfo.kdf.hkdf_extract.inKey = inKey; + cryptoInfo.kdf.hkdf_extract.inKeySz = inKeySz; + cryptoInfo.kdf.hkdf_extract.out = out; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_Hkdf_Expand(int hashType, const byte* inKey, word32 inKeySz, + const byte* info, word32 infoSz, byte* out, word32 outSz, + int devId) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + /* Find registered callback device */ + dev = wc_CryptoCb_FindDevice(devId, WC_ALGO_TYPE_KDF); + + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + + cryptoInfo.algo_type = WC_ALGO_TYPE_KDF; + cryptoInfo.kdf.type = WC_KDF_TYPE_HKDF_EXPAND; + cryptoInfo.kdf.hkdf_expand.hashType = hashType; + cryptoInfo.kdf.hkdf_expand.inKey = inKey; + cryptoInfo.kdf.hkdf_expand.inKeySz = inKeySz; + cryptoInfo.kdf.hkdf_expand.info = info; + cryptoInfo.kdf.hkdf_expand.infoSz = infoSz; + cryptoInfo.kdf.hkdf_expand.out = out; + cryptoInfo.kdf.hkdf_expand.outSz = outSz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} #endif /* HAVE_HKDF && !NO_HMAC */ #ifdef WOLF_CRYPTO_CB_COPY diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index b18c0e0e49..48d84c60f7 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -1754,19 +1754,27 @@ int wolfSSL_GetHmacMaxSize(void) const byte* localSalt; /* either points to user input or tmp */ word32 hashSz; - if (out == NULL || (inKey == NULL && inKeySz > 0)) { + if (out == NULL || (inKey == NULL && inKeySz > 0)) return BAD_FUNC_ARG; + +#ifdef WOLF_CRYPTO_CB + /* Try crypto callback first */ + if (devId != INVALID_DEVID) { + ret = wc_CryptoCb_Hkdf_Extract(type, salt, saltSz, inKey, inKeySz, + out, devId); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; } +#endif ret = wc_HmacSizeByType(type); - if (ret < 0) { + if (ret < 0) return ret; - } + hashSz = (word32)ret; WC_ALLOC_VAR_EX(myHmac, Hmac, 1, NULL, DYNAMIC_TYPE_HMAC, return MEMORY_E); - hashSz = (word32)ret; localSalt = salt; if (localSalt == NULL) { XMEMSET(tmp, 0, hashSz); @@ -1822,25 +1830,35 @@ int wolfSSL_GetHmacMaxSize(void) word32 hashSz; byte n = 0x1; + if (out == NULL || (inKey == NULL && inKeySz > 0)) + return BAD_FUNC_ARG; + ret = wc_HmacSizeByType(type); - if (ret < 0) { + if (ret < 0) return ret; - } hashSz = (word32)ret; /* RFC 5869 states that the length of output keying material in * octets must be L <= 255*HashLen or N = ceil(L/HashLen) */ - - if (out == NULL || ((outSz/hashSz) + ((outSz % hashSz) != 0)) > 255) { + if (outSz/hashSz + ((outSz % hashSz) != 0) > 255) return BAD_FUNC_ARG; + +#ifdef WOLF_CRYPTO_CB + /* Try crypto callback first for complete operation */ + if (devId != INVALID_DEVID) { + ret = wc_CryptoCb_Hkdf_Expand(type, inKey, inKeySz, info, infoSz, + out, outSz, devId); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; } +#endif WC_ALLOC_VAR_EX(myHmac, Hmac, 1, NULL, DYNAMIC_TYPE_HMAC, return MEMORY_E); ret = wc_HmacInit(myHmac, heap, devId); if (ret != 0) { - WC_FREE_VAR_EX(myHmac, NULL, DYNAMIC_TYPE_HMAC); + WC_FREE_VAR_EX(myHmac, NULL, DYNAMIC_TYPE_HMAC); return ret; } @@ -1927,9 +1945,8 @@ int wolfSSL_GetHmacMaxSize(void) #endif ret = wc_HmacSizeByType(type); - if (ret < 0) { + if (ret < 0) return ret; - } hashSz = (word32)ret; ret = wc_HKDF_Extract_ex(type, salt, saltSz, inKey, inKeySz, prk, heap, diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index f3fc88c8a1..3dd430f947 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -34735,6 +34735,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hkdf_test(void) #if !defined(NO_SHA) || !defined(NO_SHA256) int L; + byte prk[WC_MAX_DIGEST_SIZE]; byte okm1[42]; byte ikm1[22] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, @@ -34799,7 +34800,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hkdf_test(void) #ifndef HAVE_FIPS /* fips can't have key size under 14 bytes, salt is key too */ L = (int)sizeof(okm1); -#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) +#if !defined(HAVE_SELFTEST) ret = wc_HKDF_ex(WC_SHA, ikm1, 11, salt1, (word32)sizeof(salt1), info1, (word32)sizeof(info1), okm1, (word32)L, HEAP_HINT, devId); #else @@ -34811,7 +34812,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hkdf_test(void) if (XMEMCMP(okm1, res2, (unsigned long)L) != 0) return WC_TEST_RET_ENC_NC; -#endif /* HAVE_FIPS */ +#endif /* !HAVE_FIPS */ #endif /* !NO_SHA */ #ifndef NO_SHA256 @@ -34844,7 +34845,106 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hkdf_test(void) if (XMEMCMP(okm1, res4, (unsigned long)L) != 0) return WC_TEST_RET_ENC_NC; -#endif /* HAVE_FIPS */ +#endif /* !HAVE_FIPS */ +#endif /* !NO_SHA256 */ + +#ifndef NO_SHA +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) + ret = wc_HKDF_Extract_ex(WC_SHA, NULL, 0, ikm1, (word32)sizeof(ikm1), + prk, HEAP_HINT, devId); +#else + ret = wc_HKDF_Extract(WC_SHA, NULL, 0, ikm1, (word32)sizeof(ikm1), prk); +#endif + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) + ret = wc_HKDF_Expand_ex(WC_SHA, prk, WC_SHA_DIGEST_SIZE, NULL, 0, + okm1, (word32)L, HEAP_HINT, devId); +#else + ret = wc_HKDF_Expand(WC_SHA, prk, WC_SHA_DIGEST_SIZE, NULL, 0, + okm1, (word32)L); +#endif + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(okm1, res1, (unsigned long)L) != 0) + return WC_TEST_RET_ENC_NC; + +#ifndef HAVE_FIPS + /* fips can't have key size under 14 bytes, salt is key too */ +#if !defined(HAVE_SELFTEST) + ret = wc_HKDF_Extract_ex(WC_SHA, salt1, (word32)sizeof(salt1), ikm1, 11, + prk, HEAP_HINT, devId); +#else + ret = wc_HKDF_Extract(WC_SHA, salt1, (word32)sizeof(salt1), ikm1, 11, prk); +#endif + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + +#if !defined(HAVE_SELFTEST) + ret = wc_HKDF_Expand_ex(WC_SHA, prk, WC_SHA_DIGEST_SIZE, info1, + (word32)sizeof(info1), okm1, (word32)L, HEAP_HINT, devId); +#else + ret = wc_HKDF_Expand(WC_SHA, prk, WC_SHA_DIGEST_SIZE, info1, + (word32)sizeof(info1), okm1, (word32)L); +#endif + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(okm1, res2, (unsigned long)L) != 0) + return WC_TEST_RET_ENC_NC; +#endif /* !HAVE_FIPS */ +#endif /* !NO_SHA */ + +#ifndef NO_SHA256 +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) + ret = wc_HKDF_Extract_ex(WC_SHA256, NULL, 0, ikm1, (word32)sizeof(ikm1), + prk, HEAP_HINT, devId); +#else + ret = wc_HKDF_Extract(WC_SHA256, NULL, 0, ikm1, (word32)sizeof(ikm1), prk); +#endif + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) + ret = wc_HKDF_Expand_ex(WC_SHA256, prk, WC_SHA256_DIGEST_SIZE, NULL, 0, + okm1, (word32)L, HEAP_HINT, devId); +#else + ret = wc_HKDF_Expand(WC_SHA256, prk, WC_SHA256_DIGEST_SIZE, NULL, 0, + okm1, (word32)L); +#endif + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(okm1, res3, (unsigned long)L) != 0) + return WC_TEST_RET_ENC_NC; + +#ifndef HAVE_FIPS + /* fips can't have key size under 14 bytes, salt is key too */ +#if !defined(HAVE_SELFTEST) + ret = wc_HKDF_Extract_ex(WC_SHA256, salt1, (word32)sizeof(salt1), ikm1, + (word32)sizeof(ikm1), prk, HEAP_HINT, devId); +#else + ret = wc_HKDF_Extract(WC_SHA256, salt1, (word32)sizeof(salt1), ikm1, + (word32)sizeof(ikm1), prk); +#endif + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + +#if !defined(HAVE_SELFTEST) + ret = wc_HKDF_Expand_ex(WC_SHA256, prk, WC_SHA256_DIGEST_SIZE, info1, + (word32)sizeof(info1), okm1, (word32)L, HEAP_HINT, devId); +#else + ret = wc_HKDF_Expand(WC_SHA256, prk, WC_SHA256_DIGEST_SIZE, info1, + (word32)sizeof(info1), okm1, (word32)L); +#endif + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(okm1, res4, (unsigned long)L) != 0) + return WC_TEST_RET_ENC_NC; +#endif /* !HAVE_FIPS */ #endif /* !NO_SHA256 */ #endif /* !NO_SHA || !NO_SHA256 */ @@ -34858,8 +34958,18 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hkdf_test(void) ret = wc_HKDF_Extract(WC_SHA256, NULL, 0, NULL, 5, okm1); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) return WC_TEST_RET_ENC_EC(ret); -#endif /* !NO_SHA256 && !HAVE_SELFTEST && */ - /* (!HAVE_FIPS || FIPS_VERSION3_GE(7,0,0)) */ + /* wc_HKDF_Expand bad arg: NULL out */ + ret = wc_HKDF_Expand(WC_SHA256, prk, WC_SHA256_DIGEST_SIZE, NULL, 0, + NULL, (word32)L); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_EC(ret); + /* wc_HKDF_Expand bad arg: NULL inKey with non-zero inKeySz */ + ret = wc_HKDF_Expand(WC_SHA256, NULL, WC_SHA256_DIGEST_SIZE, NULL, 0, + okm1, (word32)L); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_EC(ret); +#endif /* !NO_SHA256 && !HAVE_SELFTEST */ + /* && (!HAVE_FIPS || FIPS_VERSION3_GE(7,0,0)) */ return 0; } @@ -74152,6 +74262,36 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) info->kdf.hkdf.out, info->kdf.hkdf.outSz); #endif } + if (info->kdf.type == WC_KDF_TYPE_HKDF_EXTRACT) { + #if !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) + ret = wc_HKDF_Extract_ex(info->kdf.hkdf_extract.hashType, + info->kdf.hkdf_extract.salt, info->kdf.hkdf_extract.saltSz, + info->kdf.hkdf_extract.inKey, info->kdf.hkdf_extract.inKeySz, + info->kdf.hkdf_extract.out, + NULL, INVALID_DEVID); + #else + ret = wc_HKDF_Extract(info->kdf.hkdf_extract.hashType, + info->kdf.hkdf_extract.salt, info->kdf.hkdf_extract.saltSz, + info->kdf.hkdf_extract.inKey, info->kdf.hkdf_extract.inKeySz, + info->kdf.hkdf_extract.out); + #endif + } + if (info->kdf.type == WC_KDF_TYPE_HKDF_EXPAND) { + #if !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) + ret = wc_HKDF_Expand_ex(info->kdf.hkdf_expand.hashType, + info->kdf.hkdf_expand.inKey, info->kdf.hkdf_expand.inKeySz, + info->kdf.hkdf_expand.info, info->kdf.hkdf_expand.infoSz, + info->kdf.hkdf_expand.out, info->kdf.hkdf_expand.outSz, + NULL, INVALID_DEVID); + #else + ret = wc_HKDF_Expand(info->kdf.hkdf_expand.hashType, + info->kdf.hkdf_expand.inKey, info->kdf.hkdf_expand.inKeySz, + info->kdf.hkdf_expand.info, info->kdf.hkdf_expand.infoSz, + info->kdf.hkdf_expand.out, info->kdf.hkdf_expand.outSz); + #endif + } #endif /* HAVE_HKDF && !NO_HMAC */ #if defined(HAVE_CMAC_KDF) if (info->kdf.type == WC_KDF_TYPE_TWOSTEP_CMAC) { diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index b0aaad2f37..04ec375ca7 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -645,6 +645,23 @@ typedef struct wc_CryptoInfo { byte* out; /* Output key material */ word32 outSz; } hkdf; + struct { /* HKDF extract */ + int hashType; /* WC_SHA256, etc. */ + const byte* salt; /* Optional salt */ + word32 saltSz; + const byte* inKey; /* Input keying material */ + word32 inKeySz; + byte* out; /* Output key material */ + } hkdf_extract; + struct { /* HKDF expand */ + int hashType; /* WC_SHA256, etc. */ + const byte* inKey; /* Input keying material */ + word32 inKeySz; + const byte* info; /* Optional info */ + word32 infoSz; + byte* out; /* Output key material */ + word32 outSz; + } hkdf_expand; #endif #if defined(HAVE_CMAC_KDF) struct { /* NIST.SP.800-56Cr2 two-step cmac KDF */ @@ -894,6 +911,11 @@ WOLFSSL_LOCAL int wc_CryptoCb_Hkdf(int hashType, const byte* inKey, word32 saltSz, const byte* info, word32 infoSz, byte* out, word32 outSz, int devId); +WOLFSSL_LOCAL int wc_CryptoCb_Hkdf_Extract(int hashType, const byte* salt, + word32 saltSz, const byte* inKey, word32 inKeySz, byte* out, int devId); +WOLFSSL_LOCAL int wc_CryptoCb_Hkdf_Expand(int hashType, const byte* inKey, + word32 inKeySz, const byte* info, word32 infoSz, + byte* out, word32 outSz, int devId); #endif #if defined(HAVE_CMAC_KDF) diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index eb11f8436e..a71dadb7d8 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1440,8 +1440,10 @@ enum wc_AlgoType { enum wc_KdfType { WC_KDF_TYPE_NONE = 0, WC_KDF_TYPE_HKDF = 1, - WC_KDF_TYPE_TWOSTEP_CMAC = 2 /* NIST SP 800-56C two-step cmac kdf. */ - /* Future: WC_KDF_TYPE_PBKDF2 = 3, WC_KDF_TYPE_SCRYPT = 4, etc. */ + WC_KDF_TYPE_TWOSTEP_CMAC = 2, /* NIST SP 800-56C two-step cmac kdf. */ + WC_KDF_TYPE_HKDF_EXTRACT = 3, + WC_KDF_TYPE_HKDF_EXPAND = 4 + /* Future: WC_KDF_TYPE_PBKDF2 = 5, WC_KDF_TYPE_SCRYPT = 6, etc. */ }; /* hash types */