diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 42d31cf0dd4..5268b4d80d1 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -777,6 +777,7 @@ WOLFSSL_HARDEN_TLS_ALLOW_TRUNCATED_HMAC WOLFSSL_HARDEN_TLS_NO_PKEY_CHECK WOLFSSL_HARDEN_TLS_NO_SCR_CHECK WOLFSSL_HOSTNAME_VERIFY_ALT_NAME_ONLY +WOLFSSL_HWPUF WOLFSSL_I2D_ECDSA_SIG_ALLOC WOLFSSL_IAR_ARM_TIME WOLFSSL_IGNORE_BAD_CERT_PATH @@ -860,6 +861,7 @@ WOLFSSL_NO_XOR_OPS WOLFSSL_NRF51_AES WOLFSSL_NXP_CASPER_ECC_MUL2ADD WOLFSSL_NXP_CASPER_ECC_MULMOD +WOLFSSL_NXP_HWPUF WOLFSSL_NXP_LPC55S6X WOLFSSL_OLDTLS_AEAD_CIPHERSUITES WOLFSSL_OLD_SET_CURVES_LIST diff --git a/doc/dox_comments/header_files/hwpuf.h b/doc/dox_comments/header_files/hwpuf.h new file mode 100644 index 00000000000..479dede9f4d --- /dev/null +++ b/doc/dox_comments/header_files/hwpuf.h @@ -0,0 +1,255 @@ +/*! + \ingroup HWPUF + + For a complete bare-metal example (tested on LPC55S69), see + https://github.com/wolfSSL/wolfBoot/tree/master/config/examples/lpc55s69-hwpuf.config +*/ + +/*! + \ingroup HWPUF + + \brief Initialize the wc_HWPUF context and register the CryptoCb device. + Must be called before any other HWPUF operations. + + \return 0 on success + \return BAD_FUNC_ARG if hwpuf is NULL + \return HWPUF_REGISTER_E if already registered + \return CRYPTOCB_UNAVAILABLE if nothing to register + + \param hwpuf pointer to wc_HWPUF context to initialize + \param heap heap hint, can be NULL + \param devId device ID for crypto callbacks. Specify INVALID_DEVID to use + the default compiled into the driver. + + _Example_ + \code + wc_HWPUF s_hwpuf; + ret = wc_HWPUF_Register(&s_hwpuf, NULL, INVALID_DEVID); + \endcode + + \sa wc_HWPUF_Init + \sa wc_HWPUF_Deinit + \sa wc_HWPUF_Unregister +*/ +int wc_HWPUF_Register(wc_HWPUF* hwpuf, void* heap, int devId); + +/*! + \ingroup HWPUF + + \brief Unregister the CryptoCb device and zero the wc_HWPUF context. + + \return 0 on success, or if not registered + \return BAD_FUNC_ARG if hwpuf is NULL + \return CRYPTOCB_UNAVAILABLE if nothing to unregister + + \param hwpuf pointer to wc_HWPUF context + + _Example_ + \code + wc_HWPUF s_hwpuf; + ret = wc_HWPUF_Unregister(&s_hwpuf); + \endcode + + \sa wc_HWPUF_Register + \sa wc_HWPUF_Init + \sa wc_HWPUF_Deinit + \sa wc_HWPUF_Zeroize +*/ +int wc_HWPUF_Unregister(wc_HWPUF* hwpuf); + +/*! + \ingroup HWPUF + + \brief Initialize the hardware device into a functional state. + May include turning on the clock and taking the peripheral out of reset. + + \return 0 on success, or if already initialized + \return BAD_FUNC_ARG if hwpuf is NULL + \return HWPUF_REGISTER_E if not registered + \return HWPUF_INIT_E if hardware initialization failed, leaving device in + a deinitialized state + + \param hwpuf pointer to wc_HWPUF context + + _Example_ + \code + wc_HWPUF s_hwpuf; + ret = wc_HWPUF_Init(&s_hwpuf); + \endcode + + \sa wc_HWPUF_Start + \sa wc_HWPUF_Deinit + \sa wc_HWPUF_Unregister +*/ +int wc_HWPUF_Init(wc_HWPUF* hwpuf); + +/*! + \ingroup HWPUF + + \brief Deinitialize the hardware device into a non-functional state. + May include turning off the clock and putting the peripheral into reset. + + \return 0 on success + \return BAD_FUNC_ARG if hwpuf is NULL + \return HWPUF_REGISTER_E if not registered + + \param hwpuf pointer to wc_HWPUF context + + _Example_ + \code + wc_HWPUF s_hwpuf; + ret = wc_HWPUF_Deinit(&s_hwpuf); + \endcode + + \sa wc_HWPUF_Unregister + \sa wc_HWPUF_Init +*/ +int wc_HWPUF_Deinit(wc_HWPUF* hwpuf); + +/*! + \ingroup HWPUF + + \brief Perform HWPUF enrollment. Enrollment is usually a one-time + operation, which generates an activation code (or helper data). + The activation code should be stored in NVM and used whenever the device + is started for key operations, i.e., wc_HWPUF_Start(). + After a successful enrollment, device must go through a + wc_HWPUF_Deinit() / wc_HWPUF_Init() cycle before wc_HWPUF_Start(). + + \return 0 on success + \return BAD_FUNC_ARG if hwpuf or actCode is NULL, or if invalid actCodeSz + \return HWPUF_INIT_E if not yet initialized + \return HWPUF_ENROLL_E if already enrolled, or if enrollment failed + + \param hwpuf pointer to wc_HWPUF context + \param actCode output buffer for activation code + \param actCodeSz size of activation code (HWPUF_ACTIVATION_CODE_SIZE) + + _Example_ + \code + wc_HWPUF s_hwpuf; + byte activationCode[HWPUF_ACTIVATION_CODE_SIZE]; + ret = wc_HWPUF_Enroll(&s_hwpuf, activationCode, sizeof(activationCode)); + < write activationCode to nvm > + \endcode + + \sa wc_HWPUF_Start + \sa wc_HWPUF_Init + \sa wc_HWPUF_Deinit +*/ +int wc_HWPUF_Enroll(wc_HWPUF* hwpuf, byte* actCode, word32 actCodeSz); + +/*! + \ingroup HWPUF + + \brief Start the device with an activation code (helper data). + Starting puts the device into a ready state for key operations. + + \return 0 on success + \return BAD_FUNC_ARG if hwpuf or actCode is NULL, or if invalid actCodeSz + \return HWPUF_INIT_E if not yet initialized + \return HWPUF_START_E if already started, or if start failed + + \param hwpuf pointer to wc_HWPUF context + \param actCode pointer to the activation code + \param actCodeSz size of activation code in bytes + + _Example_ + \code + wc_HWPUF s_hwpuf; + byte activationCode[HWPUF_ACTIVATION_CODE_SIZE]; + XMEMCPY(activationCode, nvm.activationCode, HWPUF_ACTIVATION_CODE_SIZE); + ret = wc_HWPUF_Start(&s_hwpuf, activationCode, sizeof(activationCode)); + \endcode + + \sa wc_HWPUF_Init + \sa wc_HWPUF_Deinit + \sa wc_HWPUF_Enroll +*/ +int wc_HWPUF_Start(wc_HWPUF* hwpuf, byte* actCode, word32 actCodeSz); + +/*! + \ingroup HWPUF + + \brief Generate a key and return a key code. + The key code should be stored in NVM and used whenever the key is + requested from the device, i.e., wc_HWPUF_GetKey(). + + \return 0 on success + \return BAD_FUNC_ARG if hwpuf NULL, or a problem with other params + \return HWPUF_START_E if device is not started (ready) + \return HWPUF_GENERATE_KEY_E if the device failed to generate the key + + \param hwpuf pointer to wc_HWPUF context + \param keyIdx index to associate with the generated key/keyCode pair + \param keySz size of the generated key in bytes + \param keyCode output buffer for key code + \param keyCodeSz size of the key code in bytes + + _Example_ + \code + wc_HWPUF s_hwpuf; + byte keyCode1[HWPUF_KEY_SIZE_TO_KEY_CODE_SIZE(32)]; + XMEMCPY(keyCode1, nvm.keyCode1, sizeof(keyCode1)); + ret = wc_HWPUF_GenerateKey(&s_hwpuf, 1, 32, keyCode1, sizeof(keyCode1)); + < write keyCode1 to nvm > + \endcode + + \sa wc_HWPUF_Start + \sa wc_HWPUF_GetKey +*/ +int wc_HWPUF_GenerateKey(wc_HWPUF* hwpuf, byte keyIdx, word32 keySz, + byte* keyCode, word32 keyCodeSz); + +/*! + \ingroup HWPUF + + \brief Get a key from a key code + + \return 0 on success + \return BAD_FUNC_ARG if hwpuf NULL, or a problem with other params + \return HWPUF_START_E if device is not started (ready) + \return HWPUF_GET_KEY_E if the device failed to get the key + + \param hwpuf pointer to wc_HWPUF context + \param keyCode input buffer with key code + \param keyCodeSz size of the key code in bytes + \param key output buffer for key + \param keySz size of the key in bytes + + _Example_ + \code + byte key2[16]; + byte keyCode2[HWPUF_KEY_SIZE_TO_KEY_CODE_SIZE(16)]; + XMEMCPY(keyCode2, nvm.keyCode2, sizeof(keyCode2)); + ret = wc_HWPUF_GetKey(&s_hwpuf, keyCode2, sizeof(keyCode2), + key2, sizeof(key2)); + \endcode + + \sa wc_HWPUF_GenerateKey + \sa wc_HWPUF_Start +*/ +int wc_HWPUF_GetKey(wc_HWPUF* hwpuf, byte* keyCode, word32 keyCodeSz, + byte* key, word32 keySz); + +/*! + \ingroup HWPUF + + \brief Securely zeroize all sensitive data in both the device and context. + Call when the device is no longer needed. Leaves the device in the + deinitialized state. + + \return 0 on success + \return BAD_FUNC_ARG if hwpuf is NULL + \return HWPUF_ZEROIZE_E if the device failed the zeroize operation + + \param hwpuf pointer to wc_HWPUF context + + _Example_ + \code + wc_HWPUF_Zeroize(&s_hwpuf); + \endcode + + \sa wc_HWPUF_Deinit +*/ +int wc_HWPUF_Zeroize(wc_HWPUF* hwpuf); diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index 3218e6efb27..140ace23ebe 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -111,6 +111,7 @@ static const char* GetAlgoTypeStr(int algo) case WC_ALGO_TYPE_CMAC: return "CMAC"; case WC_ALGO_TYPE_CERT: return "Cert"; case WC_ALGO_TYPE_KDF: return "KDF"; + case WC_ALGO_TYPE_HWPUF: return "HWPUF"; #ifdef WOLF_CRYPTO_CB_COPY case WC_ALGO_TYPE_COPY: return "Copy"; #endif /* WOLF_CRYPTO_CB_COPY */ @@ -233,7 +234,6 @@ static const char* GetCryptoCbCmdTypeStr(int type) } #endif - #if (defined(HAVE_HKDF) && !defined(NO_HMAC)) || defined(HAVE_CMAC_KDF) static const char* GetKdfTypeStr(int type) { @@ -247,6 +247,29 @@ static const char* GetKdfTypeStr(int type) } #endif +#ifdef WOLFSSL_HWPUF +static const char* GetHwpufTypeStr(int type) +{ + switch (type) { + case WC_HWPUF_TYPE_INIT: + return "INIT"; + case WC_HWPUF_TYPE_DEINIT: + return "DEINIT"; + case WC_HWPUF_TYPE_ENROLL: + return "ENROLL"; + case WC_HWPUF_TYPE_START: + return "START"; + case WC_HWPUF_TYPE_GENERATE_KEY: + return "GENERATE_KEY"; + case WC_HWPUF_TYPE_GET_KEY: + return "GET_KEY"; + case WC_HWPUF_TYPE_ZEROIZE: + return "ZEROIZE"; + } + return NULL; +} +#endif + void wc_CryptoCb_InfoString(wc_CryptoInfo* info) { if (info == NULL) @@ -346,6 +369,12 @@ void wc_CryptoCb_InfoString(wc_CryptoInfo* info) printf("Crypto CB: %s %s (%d)\n", GetAlgoTypeStr(info->algo_type), GetKdfTypeStr(info->kdf.type), info->kdf.type); } +#endif +#ifdef WOLFSSL_HWPUF + else if (info->algo_type == WC_ALGO_TYPE_HWPUF) { + printf("Crypto CB: %s %s (%d)\n", GetAlgoTypeStr(info->algo_type), + GetHwpufTypeStr(info->hwpuf.type), info->hwpuf.type); + } #endif else { printf("CryptoCb: %s \n", GetAlgoTypeStr(info->algo_type)); @@ -2551,6 +2580,177 @@ int wc_CryptoCb_SheExportKey(wc_SHE* she, } #endif /* WOLFSSL_SHE */ +#ifdef WOLFSSL_HWPUF +int wc_CryptoCb_HwpufInit(wc_HWPUF* hwpuf) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + dev = wc_CryptoCb_FindDevice(hwpuf->devId, WC_ALGO_TYPE_HWPUF); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_HWPUF; + cryptoInfo.hwpuf.hwpuf = hwpuf; + cryptoInfo.hwpuf.type = WC_HWPUF_TYPE_INIT; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_HwpufDeinit(wc_HWPUF* hwpuf) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + dev = wc_CryptoCb_FindDevice(hwpuf->devId, WC_ALGO_TYPE_HWPUF); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_HWPUF; + cryptoInfo.hwpuf.hwpuf = hwpuf; + cryptoInfo.hwpuf.type = WC_HWPUF_TYPE_DEINIT; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_HwpufEnroll(wc_HWPUF* hwpuf, byte* actCode, word32 actCodeSz) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + dev = wc_CryptoCb_FindDevice(hwpuf->devId, WC_ALGO_TYPE_HWPUF); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_HWPUF; + cryptoInfo.hwpuf.hwpuf = hwpuf; + cryptoInfo.hwpuf.type = WC_HWPUF_TYPE_ENROLL; + cryptoInfo.hwpuf.op.enroll.actCode = actCode; + cryptoInfo.hwpuf.op.enroll.actCodeSz = actCodeSz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_HwpufStart(wc_HWPUF* hwpuf, byte* actCode, word32 actCodeSz) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + dev = wc_CryptoCb_FindDevice(hwpuf->devId, WC_ALGO_TYPE_HWPUF); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_HWPUF; + cryptoInfo.hwpuf.hwpuf = hwpuf; + cryptoInfo.hwpuf.type = WC_HWPUF_TYPE_START; + cryptoInfo.hwpuf.op.start.actCode = actCode; + cryptoInfo.hwpuf.op.start.actCodeSz = actCodeSz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_HwpufGenerateKey(wc_HWPUF* hwpuf, byte keyIdx, word32 keySz, + byte* keyCode, word32 keyCodeSz) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + dev = wc_CryptoCb_FindDevice(hwpuf->devId, WC_ALGO_TYPE_HWPUF); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_HWPUF; + cryptoInfo.hwpuf.hwpuf = hwpuf; + cryptoInfo.hwpuf.type = WC_HWPUF_TYPE_GENERATE_KEY; + cryptoInfo.hwpuf.op.generateKey.keyIdx = keyIdx; + cryptoInfo.hwpuf.op.generateKey.keySz = keySz; + cryptoInfo.hwpuf.op.generateKey.keyCode = keyCode; + cryptoInfo.hwpuf.op.generateKey.keyCodeSz = keyCodeSz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_HwpufGetKey(wc_HWPUF* hwpuf, + byte* keyCode, word32 keyCodeSz, + byte* key, word32 keySz) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + dev = wc_CryptoCb_FindDevice(hwpuf->devId, WC_ALGO_TYPE_HWPUF); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_HWPUF; + cryptoInfo.hwpuf.hwpuf = hwpuf; + cryptoInfo.hwpuf.type = WC_HWPUF_TYPE_GET_KEY; + cryptoInfo.hwpuf.op.getKey.keyCode = keyCode; + cryptoInfo.hwpuf.op.getKey.keyCodeSz = keyCodeSz; + cryptoInfo.hwpuf.op.getKey.key = key; + cryptoInfo.hwpuf.op.getKey.keySz = keySz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_HwpufZeroize(wc_HWPUF* hwpuf) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + dev = wc_CryptoCb_FindDevice(hwpuf->devId, WC_ALGO_TYPE_HWPUF); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_HWPUF; + cryptoInfo.hwpuf.hwpuf = hwpuf; + cryptoInfo.hwpuf.type = WC_HWPUF_TYPE_ZEROIZE; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} +#endif /* WOLFSSL_HWPUF */ + /* returns the default dev id for the current build */ int wc_CryptoCb_DefaultDevID(void) { diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index 8826d9b1988..3e60789854e 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -713,6 +713,27 @@ const char* wc_GetErrorString(int error) case PUF_IDENTITY_E: return "PUF identity retrieval failed"; + case HWPUF_REGISTER_E: + return "HWPUF registration failed"; + + case HWPUF_INIT_E: + return "HWPUF initialization failed"; + + case HWPUF_ENROLL_E: + return "HWPUF enrollment failed"; + + case HWPUF_START_E: + return "HWPUF start failed"; + + case HWPUF_GENERATE_KEY_E: + return "HWPUF generate key failed"; + + case HWPUF_GET_KEY_E: + return "HWPUF get key failed"; + + case HWPUF_ZEROIZE_E: + return "HWPUF zeroize failed"; + case MAX_CODE_E: case WC_SPAN1_MIN_CODE_E: case MIN_CODE_E: diff --git a/wolfcrypt/src/hwpuf.c b/wolfcrypt/src/hwpuf.c new file mode 100644 index 00000000000..a767da2b529 --- /dev/null +++ b/wolfcrypt/src/hwpuf.c @@ -0,0 +1,210 @@ +/* hwpuf.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include + +#ifdef WOLFSSL_HWPUF + +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +/* The various supported device ports... One must be defined. */ +#ifdef WOLFSSL_NXP_HWPUF + #include +#endif + +static int hwpuf_registered = 0; + +WOLFSSL_API int wc_HWPUF_Register(wc_HWPUF* hwpuf, void* heap, int devId) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + if (hwpuf_registered) + return HWPUF_REGISTER_E; + + ForceZero(hwpuf, sizeof(wc_HWPUF)); + hwpuf->heap = heap; + hwpuf->devId = devId; + +#ifdef WOLFSSL_NXP_HWPUF + ret = nxp_hwpuf_RegisterDevice(hwpuf); +#endif + if (ret != 0) { + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + ret = HWPUF_REGISTER_E; + } + ForceZero(hwpuf, sizeof(wc_HWPUF)); + return ret; + } + hwpuf_registered = 1; + return ret; +} + +WOLFSSL_API int wc_HWPUF_Unregister(wc_HWPUF* hwpuf) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + if (!hwpuf_registered) + return 0; + +#ifdef WOLFSSL_NXP_HWPUF + ret = nxp_hwpuf_UnregisterDevice(hwpuf); +#endif + + ForceZero(hwpuf, sizeof(wc_HWPUF)); + hwpuf_registered = 0; + return ret; +} + +WOLFSSL_API int wc_HWPUF_Init(wc_HWPUF* hwpuf) +{ + int ret; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + if (!hwpuf_registered) + return HWPUF_REGISTER_E; + if ((hwpuf->flags & WC_HWPUF_FLAG_INITED) != 0) + return 0; + + ret = wc_CryptoCb_HwpufInit(hwpuf); + if (ret == 0) + hwpuf->flags |= WC_HWPUF_FLAG_INITED; + + return ret; +} + +WOLFSSL_API int wc_HWPUF_Deinit(wc_HWPUF* hwpuf) +{ + int ret; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + if (!hwpuf_registered) + return HWPUF_REGISTER_E; + + ret = wc_CryptoCb_HwpufDeinit(hwpuf); + hwpuf->flags = 0; + + return ret; +} + +WOLFSSL_API int wc_HWPUF_Enroll(wc_HWPUF* hwpuf, + byte* actCode, word32 actCodeSz) +{ + int ret; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + if (actCode == NULL || actCodeSz != HWPUF_ACTIVATION_CODE_SIZE) + return BAD_FUNC_ARG; + if ((hwpuf->flags & WC_HWPUF_FLAG_INITED) == 0) + return HWPUF_INIT_E; + if ((hwpuf->flags & WC_HWPUF_FLAG_ENROLLED) != 0) + return HWPUF_ENROLL_E; + if ((hwpuf->flags & WC_HWPUF_FLAG_READY) != 0) + return HWPUF_ENROLL_E; + + ret = wc_CryptoCb_HwpufEnroll(hwpuf, actCode, actCodeSz); + if (ret == 0) + hwpuf->flags |= WC_HWPUF_FLAG_ENROLLED; + + return ret; +} + +WOLFSSL_API int wc_HWPUF_Start(wc_HWPUF* hwpuf, + byte* actCode, word32 actCodeSz) +{ + int ret; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + if (actCode == NULL || actCodeSz != HWPUF_ACTIVATION_CODE_SIZE) + return BAD_FUNC_ARG; + if ((hwpuf->flags & WC_HWPUF_FLAG_INITED) == 0) + return HWPUF_INIT_E; + if ((hwpuf->flags & WC_HWPUF_FLAG_ENROLLED) != 0) + return HWPUF_START_E; + if ((hwpuf->flags & WC_HWPUF_FLAG_READY) != 0) + return HWPUF_START_E; + + ret = wc_CryptoCb_HwpufStart(hwpuf, actCode, actCodeSz); + if (ret == 0) + hwpuf->flags |= WC_HWPUF_FLAG_READY; + + return ret; +} + +WOLFSSL_API int wc_HWPUF_GenerateKey(wc_HWPUF* hwpuf, + byte keyIdx, word32 keySz, + byte* keyCode, word32 keyCodeSz) +{ + int ret; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + if ((hwpuf->flags & WC_HWPUF_FLAG_READY) == 0) + return HWPUF_START_E; + + ret = wc_CryptoCb_HwpufGenerateKey(hwpuf, keyIdx, keySz, + keyCode, keyCodeSz); + return ret; +} + +WOLFSSL_API int wc_HWPUF_GetKey(wc_HWPUF* hwpuf, + byte* keyCode, word32 keyCodeSz, + byte* key, word32 keySz) +{ + int ret; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + if ((hwpuf->flags & WC_HWPUF_FLAG_READY) == 0) + return HWPUF_START_E; + + ret = wc_CryptoCb_HwpufGetKey(hwpuf, keyCode, keyCodeSz, key, keySz); + return ret; +} + +WOLFSSL_API int wc_HWPUF_Zeroize(wc_HWPUF* hwpuf) +{ + int ret; + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + ret = wc_CryptoCb_HwpufZeroize(hwpuf); + hwpuf->flags = 0; + + return ret; +} +#endif /* WOLFSSL_HWPUF */ diff --git a/wolfcrypt/src/include.am b/wolfcrypt/src/include.am index 18d7a339cd5..c649f80f19a 100644 --- a/wolfcrypt/src/include.am +++ b/wolfcrypt/src/include.am @@ -23,6 +23,7 @@ EXTRA_DIST += wolfcrypt/src/poly1305_asm.asm EXTRA_DIST += wolfcrypt/src/wc_dsp.c EXTRA_DIST += wolfcrypt/src/sp_dsp32.c EXTRA_DIST += wolfcrypt/src/sp_x86_64_asm.asm +EXTRA_DIST += wolfcrypt/src/hwpuf.c EXTRA_DIST += \ wolfcrypt/src/ecc_fp.c \ @@ -73,6 +74,7 @@ EXTRA_DIST += wolfcrypt/src/port/ti/ti-aes.c \ wolfcrypt/src/port/nxp/README.md \ wolfcrypt/src/port/nxp/casper_port.c \ wolfcrypt/src/port/nxp/hashcrypt_port.c \ + wolfcrypt/src/port/nxp/hwpuf_port.c \ wolfcrypt/src/port/atmel/README.md \ wolfcrypt/src/port/xilinx/xil-sha3.c \ wolfcrypt/src/port/xilinx/xil-aesgcm.c \ diff --git a/wolfcrypt/src/port/nxp/hwpuf_port.c b/wolfcrypt/src/port/nxp/hwpuf_port.c new file mode 100644 index 00000000000..6cf2f318989 --- /dev/null +++ b/wolfcrypt/src/port/nxp/hwpuf_port.c @@ -0,0 +1,335 @@ +/* hwpuf_port.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#include + +#if defined(WOLFSSL_HWPUF) && defined(WOLFSSL_NXP_HWPUF) + +#ifndef WOLF_CRYPTO_CB + #error WOLFSSL_HWPUF support requires ./configure --enable-cryptocb or WOLF_CRYPTO_CB to be defined +#endif + +#include +#include +#include +#include +#include "fsl_iap_ffr.h" +#include "fsl_puf.h" +#include "fsl_rng.h" + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +typedef enum nxp_hwpuf_keytype { + nxp_hwpuf_keytype_user = 0, + nxp_hwpuf_keytype_intrinsic = 1, + nxp_hwpuf_keytype_max = nxp_hwpuf_keytype_intrinsic +} nxp_hwpuf_keytype; + +typedef struct nxp_hwpuf_ctx { + word32 keyMask; /* unique per reset */ +} nxp_hwpuf_ctx; + +static nxp_hwpuf_ctx ctx; +static puf_config_t conf; + + +#define NXP_HWPUF_USER_KEY 0 +#define NXP_HWPUF_INTRINSIC_KEY 0 + +static int keyCodeCheck(byte* keyCode, word32* keytype, + word32* keyidx, word32* keysize) +{ + *keytype = keyCode[0]; + *keyidx = keyCode[1]; + *keysize = keyCode[3] == 0 ? 512 : 8 * keyCode[3] ; + + if (*keytype > nxp_hwpuf_keytype_max) + return 1; + if (*keyidx > kPUF_KeyIndexMax) + return 2; + if ( !HWPUF_KEY_SIZE_IS_VALID(*keysize) ) + return 3; + + return 0; +} + +static int nxp_rng_initialized = 0; + +static int nxp_hwpuf_Init(wc_HWPUF* hwpuf) +{ + WOLFSSL_ENTER("nxp_hwpuf_Init"); + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + PUF_GetDefaultConfig(&conf); + if (PUF_Init(PUF, &conf) != kStatus_Success) { + PUF_Deinit(PUF, &conf); + return HWPUF_INIT_E; + } + if (!nxp_rng_initialized) { + RNG_Init(RNG); + nxp_rng_initialized = 1; + } + ctx.keyMask = RNG->RANDOM_NUMBER; + return 0; +} + +static int nxp_hwpuf_Deinit(wc_HWPUF* hwpuf) +{ + WOLFSSL_ENTER("nxp_hwpuf_Deinit"); + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + PUF_Deinit(PUF, &conf); + + return 0; +} + +static int nxp_hwpuf_Enroll(wc_HWPUF* hwpuf, byte* actCode, word32 actCodeSz) +{ + int ret; + + WOLFSSL_ENTER("nxp_hwpuf_Enroll"); + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + ret = PUF_Enroll(PUF, actCode, actCodeSz); + if (ret == kStatus_EnrollNotAllowed) { + /* power cycle and try again */ + (void)PUF_PowerCycle(PUF, &conf); + ret = PUF_Enroll(PUF, actCode, actCodeSz); + } + if (ret != kStatus_Success) { + return HWPUF_ENROLL_E; + } + + /* wipe ctx if enroll succeeded (re-enroll will render ctx moot) */ + XMEMSET(&ctx, 0, sizeof(ctx)); + + return 0; +} + +static int nxp_hwpuf_Start(wc_HWPUF* hwpuf, byte* actCode, word32 actCodeSz) +{ + int ret; + + WOLFSSL_ENTER("nxp_hwpuf_Start"); + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + ret = PUF_Start(PUF, actCode, actCodeSz); + if (ret == kStatus_StartNotAllowed) { + /* power cycle and try again */ + (void)PUF_PowerCycle(PUF, &conf); + ret = PUF_Start(PUF, actCode, actCodeSz); + } + if (ret != kStatus_Success) { + return HWPUF_START_E; + } + + return 0; +} + +static int nxp_hwpuf_GenerateKey(wc_HWPUF* hwpuf, byte keyIdx, word32 keySz, + byte* keyCode, word32 keyCodeSz) +{ + int ret; + word32 kcSz; + + WOLFSSL_ENTER("nxp_hwpuf_GenerateKey"); + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + if (keyIdx > kPUF_KeyIndexMax) + return BAD_FUNC_ARG; + if ( !HWPUF_KEY_SIZE_IS_VALID(keySz) ) + return BAD_FUNC_ARG; + kcSz = PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySz); + if (keyCode == NULL || kcSz != keyCodeSz) + return BAD_FUNC_ARG; + + ret = PUF_SetIntrinsicKey(PUF, (puf_key_index_register_t)keyIdx, keySz, + keyCode, keyCodeSz); + if (ret != kStatus_Success) + return HWPUF_GENERATE_KEY_E; + + return 0; +} + +static int nxp_hwpuf_GetKey(wc_HWPUF* hwpuf, byte* keyCode, word32 keyCodeSz, + byte* key, word32 keySz) +{ + int ret; + word32 keytype, keyidx, keysize; + word32 kcSz; + + WOLFSSL_ENTER("nxp_hwpuf_GetKey"); + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + if (keyCode == NULL || keyCodeSz < PUF_MIN_KEY_CODE_SIZE) + return BAD_FUNC_ARG; + + ret = keyCodeCheck(keyCode, &keytype, &keyidx, &keysize); + if (ret != kStatus_Success) + return BAD_FUNC_ARG; + + kcSz = PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keysize); + if (kcSz != keyCodeSz) + return BAD_FUNC_ARG; + if (keyidx != kPUF_KeyIndex_00 && (key == NULL || keysize != keySz)) + return BAD_FUNC_ARG; + + /* keyidx 0 means key is sent directly on hw bus, never exposed */ + if (keyidx == kPUF_KeyIndex_00) { + /* keyslot 0 means send to aes engine */ + ret = PUF_GetHwKey(PUF, keyCode, keyCodeSz, kPUF_KeySlot0, + ctx.keyMask); + if (ret != kStatus_Success) + return HWPUF_GET_KEY_E; + if (key) + XMEMSET(key, 0, keySz); /* no key to return, zero out */ + } + else { + ret = PUF_GetKey(PUF, keyCode, keyCodeSz, key, keySz); + if (ret != kStatus_Success) + return HWPUF_GET_KEY_E; + } + return 0; +} + +static int nxp_hwpuf_Zeroize(wc_HWPUF* hwpuf) +{ + int ret; + + WOLFSSL_ENTER("nxp_hwpuf_Zeroize"); + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + ForceZero(&ctx, sizeof(ctx)); + + ret = PUF_Zeroize(PUF); + PUF_Deinit(PUF, &conf); + if (ret != kStatus_Success) { + return HWPUF_ZEROIZE_E; + } + return 0; +} + +static int nxp_hwpuf_CryptoDevCb(int devId, wc_CryptoInfo* info, void* devCtx) +{ + int ret = CRYPTOCB_UNAVAILABLE; + + WOLFSSL_ENTER("nxp_hwpuf_CryptoDevCb"); + + (void)devCtx; + + if (info == NULL) + return BAD_FUNC_ARG; + if (devId == INVALID_DEVID) + return CRYPTOCB_UNAVAILABLE; + if (info->algo_type != WC_ALGO_TYPE_HWPUF) + return CRYPTOCB_UNAVAILABLE; + +#ifdef DEBUG_CRYPTOCB + wc_CryptoCb_InfoString(info); +#endif + + if (info->hwpuf.type == WC_HWPUF_TYPE_INIT) { + ret = nxp_hwpuf_Init(info->hwpuf.hwpuf); + } + else if (info->hwpuf.type == WC_HWPUF_TYPE_DEINIT) { + ret = nxp_hwpuf_Deinit(info->hwpuf.hwpuf); + } + else if (info->hwpuf.type == WC_HWPUF_TYPE_ENROLL) { + ret = nxp_hwpuf_Enroll(info->hwpuf.hwpuf, + info->hwpuf.op.enroll.actCode, + info->hwpuf.op.enroll.actCodeSz); + } + else if (info->hwpuf.type == WC_HWPUF_TYPE_START) { + ret = nxp_hwpuf_Start(info->hwpuf.hwpuf, + info->hwpuf.op.start.actCode, + info->hwpuf.op.start.actCodeSz); + } + else if (info->hwpuf.type == WC_HWPUF_TYPE_GENERATE_KEY) { + ret = nxp_hwpuf_GenerateKey(info->hwpuf.hwpuf, + info->hwpuf.op.generateKey.keyIdx, + info->hwpuf.op.generateKey.keySz, + info->hwpuf.op.generateKey.keyCode, + info->hwpuf.op.generateKey.keyCodeSz); + } + else if (info->hwpuf.type == WC_HWPUF_TYPE_GET_KEY) { + ret = nxp_hwpuf_GetKey(info->hwpuf.hwpuf, + info->hwpuf.op.getKey.keyCode, + info->hwpuf.op.getKey.keyCodeSz, + info->hwpuf.op.getKey.key, + info->hwpuf.op.getKey.keySz); + } + else if (info->hwpuf.type == WC_HWPUF_TYPE_ZEROIZE) { + ret = nxp_hwpuf_Zeroize(info->hwpuf.hwpuf); + } + return ret; +} + +WOLFSSL_API int nxp_hwpuf_RegisterDevice(wc_HWPUF* hwpuf) +{ + int ret; + + WOLFSSL_ENTER("nxp_hwpuf_RegisterDevice"); + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + if (hwpuf->devId == INVALID_DEVID) + hwpuf->devId = WOLFSSL_NXP_HWPUF_DEVID; + + ret = wc_CryptoCb_RegisterDevice(hwpuf->devId, nxp_hwpuf_CryptoDevCb, NULL); + if (ret != 0) { + WOLFSSL_ERROR_MSG("NXP_HWPUF: nxp_hwpuf_CryptoDevCb, " + "wc_CryptoCb_RegisterDevice() failed"); + } + return ret; +} + +WOLFSSL_API int nxp_hwpuf_UnregisterDevice(wc_HWPUF* hwpuf) +{ + WOLFSSL_ENTER("nxp_hwpuf_UnregisterDevice"); + + if (hwpuf == NULL) + return BAD_FUNC_ARG; + + wc_CryptoCb_UnRegisterDevice(hwpuf->devId); + + return 0; +} + +#endif /* WOLFSSL_HWPUF && WOLFSSL_NXP_HWPUF */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index d76dd112c99..38510a6f414 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -428,6 +428,9 @@ static const byte const_byte_array[] = "A+Gd\0\0\0"; #ifdef WOLFSSL_PUF #include #endif +#ifdef WOLFSSL_HWPUF + #include +#endif #ifdef HAVE_LIBZ #include #endif @@ -887,6 +890,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sm4_test(void); #ifdef WOLFSSL_PUF WOLFSSL_TEST_SUBROUTINE wc_test_ret_t puf_test(void); #endif +#ifdef WOLFSSL_HWPUF +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hwpuf_test(void); +#endif #ifdef WC_RSA_NO_PADDING WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rsa_no_pad_test(void); #endif @@ -2946,6 +2952,13 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_PASS("PUF test passed!\n"); #endif +#ifdef WOLFSSL_HWPUF + if ( (ret = hwpuf_test()) != 0) + return err_sys("HWPUF test failed!\n", ret); + else + TEST_PASS("HWPUF test passed!\n"); +#endif + #if !defined(NO_RSA) && !defined(HAVE_RENESAS_SYNC) #ifdef WC_RSA_NO_PADDING if ( (ret = rsa_no_pad_test()) != 0) @@ -23324,6 +23337,176 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t puf_test(void) } #endif /* WOLFSSL_PUF */ +#ifdef WOLFSSL_HWPUF +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hwpuf_test(void) +{ + wc_test_ret_t ret = 0; + wc_HWPUF hwpuf; + byte activationCode[HWPUF_ACTIVATION_CODE_SIZE]; + byte keyCode16[HWPUF_KEY_SIZE_TO_KEY_CODE_SIZE(16)]; + byte key16_1[16]; + byte key16_2[16]; + byte keyCode24[HWPUF_KEY_SIZE_TO_KEY_CODE_SIZE(24)]; + byte key24_1[24]; + byte key24_2[24]; + byte keyCode32[HWPUF_KEY_SIZE_TO_KEY_CODE_SIZE(32)]; + byte key32_1[32]; + byte key32_2[32]; + + WOLFSSL_ENTER("hwpuf_test"); + + ret = wc_HWPUF_Register(&hwpuf, NULL, INVALID_DEVID); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* ---- Test 1: Init ---- */ + ret = wc_HWPUF_Init(&hwpuf); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* ---- Test 2: Enroll ---- */ + ret = wc_HWPUF_Enroll(&hwpuf, activationCode, sizeof(activationCode)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* hw puf requires a deinit/init cycle after enroll */ + (void)wc_HWPUF_Deinit(&hwpuf); + (void)wc_HWPUF_Init(&hwpuf); + + /* ---- Test 3: Start ---- */ + ret = wc_HWPUF_Start(&hwpuf, activationCode, sizeof(activationCode)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* ---- Test 4: Generate keys of size 16, 24, 32 bytes ---- */ + /* generate a 16-byte key and get a keyCode */ + ret = wc_HWPUF_GenerateKey(&hwpuf, 1, 16, keyCode16, sizeof(keyCode16)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* get key from keyCode */ + ret = wc_HWPUF_GetKey(&hwpuf, keyCode16, sizeof(keyCode16), key16_1, sizeof(key16_1)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* generate a 24-byte key and get a keyCode */ + ret = wc_HWPUF_GenerateKey(&hwpuf, 1, 24, keyCode24, sizeof(keyCode24)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* get key from keyCode */ + ret = wc_HWPUF_GetKey(&hwpuf, keyCode24, sizeof(keyCode24), key24_1, sizeof(key24_1)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* generate a 32-byte key and get a keyCode */ + ret = wc_HWPUF_GenerateKey(&hwpuf, 1, 32, keyCode32, sizeof(keyCode32)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* get key from keyCode */ + ret = wc_HWPUF_GetKey(&hwpuf, keyCode32, sizeof(keyCode32), key32_1, sizeof(key32_1)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* ---- Test 5: restart and derive the same 3 keys ---- */ + (void)wc_HWPUF_Deinit(&hwpuf); + (void)wc_HWPUF_Init(&hwpuf); + ret = wc_HWPUF_Start(&hwpuf, activationCode, sizeof(activationCode)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* 16-byte */ + ret = wc_HWPUF_GetKey(&hwpuf, keyCode16, sizeof(keyCode16), key16_2, sizeof(key16_2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* 24-byte */ + ret = wc_HWPUF_GetKey(&hwpuf, keyCode24, sizeof(keyCode24), key24_2, sizeof(key24_2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* 32-byte */ + ret = wc_HWPUF_GetKey(&hwpuf, keyCode32, sizeof(keyCode32), key32_2, sizeof(key32_2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* all keys match? */ + if (XMEMCMP(key16_1, key16_2, 16) != 0) + return WC_TEST_RET_ENC_NC; + if (XMEMCMP(key24_1, key24_2, 24) != 0) + return WC_TEST_RET_ENC_NC; + if (XMEMCMP(key32_1, key32_2, 32) != 0) + return WC_TEST_RET_ENC_NC; + + /* ---- Test 6: generate a key and send directly to hw bus ---- */ + ret = wc_HWPUF_GenerateKey(&hwpuf, 0, 32, keyCode32, sizeof(keyCode32)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* get key from keyCode */ + ret = wc_HWPUF_GetKey(&hwpuf, keyCode32, sizeof(keyCode32), key32_2, sizeof(key32_2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + { /* key1 should be zeroed */ + word32 idx; + for (idx = 0; idx < sizeof(key32_2); ++idx) { + if (key32_2[idx]) + return WC_TEST_RET_ENC_NC; + } + } + + /* ---- Test 7: Bad argument checks ---- */ + /* null hwpuf */ + if (wc_HWPUF_Init(NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + if (wc_HWPUF_Deinit(NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + if (wc_HWPUF_Enroll(NULL, NULL, 0) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + if (wc_HWPUF_Zeroize(NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + /* out of bounds key index */ + if (wc_HWPUF_GenerateKey(&hwpuf, 16, 32, keyCode32, sizeof(keyCode32)) + != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + /* invalid key code storage size */ + if (wc_HWPUF_GenerateKey(&hwpuf, 1, 32, keyCode32, 99) + != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + /* null key code storage */ + if (wc_HWPUF_GenerateKey(&hwpuf, 1, 32, NULL, sizeof(keyCode32)) + != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + /* invalid key storage size */ + ret = wc_HWPUF_GenerateKey(&hwpuf, 7, 32, keyCode32, sizeof(keyCode32)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (wc_HWPUF_GetKey(&hwpuf, keyCode32, sizeof(keyCode32), key32_1, sizeof(key16_1)) + != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + /* null key storage */ + if (wc_HWPUF_GetKey(&hwpuf, keyCode32, sizeof(keyCode32), NULL, sizeof(key32_1)) + != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + + /* ---- Test 8: Zeroize ---- */ + ret = wc_HWPUF_GetKey(&hwpuf, keyCode24, sizeof(keyCode24), key24_1, sizeof(key24_1)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_HWPUF_Zeroize(&hwpuf); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (wc_HWPUF_GetKey(&hwpuf, keyCode24, sizeof(keyCode24), key24_2, sizeof(key24_2)) + != WC_NO_ERR_TRACE(HWPUF_START_E)) + return WC_TEST_RET_ENC_NC; + + /* ---- Test 9: double register fails ---- */ + if (wc_HWPUF_Register(&hwpuf, NULL, INVALID_DEVID) + != WC_NO_ERR_TRACE(HWPUF_REGISTER_E)) + return WC_TEST_RET_ENC_NC; + + /* ---- clean up ---- */ + (void)wc_HWPUF_Deinit(&hwpuf); + ret = wc_HWPUF_Unregister(&hwpuf); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + return 0; +} +#endif /* WOLFSSL_HWPUF */ + #ifdef HAVE_XCHACHA WOLFSSL_TEST_SUBROUTINE wc_test_ret_t XChaCha_test(void) { diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index b0aaad2f374..3cf2a51108c 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -68,6 +68,9 @@ #ifdef WOLFSSL_SHE #include #endif +#ifdef WOLFSSL_HWPUF + #include +#endif #ifdef HAVE_ED25519 #include #endif @@ -575,6 +578,35 @@ typedef struct wc_CryptoInfo { } op; } she; #endif +#ifdef WOLFSSL_HWPUF + struct { + wc_HWPUF* hwpuf; /* wc_HWPUF* context */ + int type; /* enum wc_HwpufType - discriminator */ + const void* ctx; /* read-only caller context */ + union { + struct { + byte* actCode; + word32 actCodeSz; + } enroll; + struct { + byte* actCode; + word32 actCodeSz; + } start; + struct { + byte keyIdx; + word32 keySz; + byte* keyCode; + word32 keyCodeSz; + } generateKey; + struct { + byte* keyCode; + word32 keyCodeSz; + byte* key; + word32 keySz; + } getKey; + } op; + } hwpuf; +#endif #ifndef NO_CERTS struct { const byte *id; @@ -943,7 +975,22 @@ WOLFSSL_LOCAL int wc_CryptoCb_SheExportKey(wc_SHE* she, byte* m4, word32 m4Sz, byte* m5, word32 m5Sz, const void* ctx); -#endif +#endif /* WOLFSSL_SHE */ + +#ifdef WOLFSSL_HWPUF +WOLFSSL_LOCAL int wc_CryptoCb_HwpufInit(wc_HWPUF* hwpuf); +WOLFSSL_LOCAL int wc_CryptoCb_HwpufDeinit(wc_HWPUF* hwpuf); +WOLFSSL_LOCAL int wc_CryptoCb_HwpufEnroll(wc_HWPUF* hwpuf, + byte* actCode, word32 actCodeSz); +WOLFSSL_LOCAL int wc_CryptoCb_HwpufStart(wc_HWPUF* hwpuf, + byte* actCode, word32 actCodeSz); +WOLFSSL_LOCAL int wc_CryptoCb_HwpufGenerateKey(wc_HWPUF* hwpuf, byte keyIdx, + word32 keySz, byte* keyCode, word32 keyCodeSz); +WOLFSSL_LOCAL int wc_CryptoCb_HwpufGetKey(wc_HWPUF* hwpuf, + byte* keyCode, word32 keyCodeSz, + byte* key, word32 keySz); +WOLFSSL_LOCAL int wc_CryptoCb_HwpufZeroize(wc_HWPUF* hwpuf); +#endif /* WOLFSSL_HWPUF */ #ifndef NO_CERTS WOLFSSL_LOCAL int wc_CryptoCb_GetCert(int devId, const char *label, diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 736954a0a76..95242f23dc1 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -328,8 +328,16 @@ enum wolfCrypt_ErrorCodes { DRBG_SHA512_KAT_FIPS_E = -1017, /* SHA-512 DRBG KAT failure */ SLH_DSA_KAT_FIPS_E = -1018, /* SLH-DSA CAST KAT failure */ - WC_SPAN2_LAST_E = -1018, /* Update to indicate last used error code */ - WC_LAST_E = -1018, /* the last code used either here or in + HWPUF_REGISTER_E = -1019, /* HWPUF registration failed */ + HWPUF_INIT_E = -1020, /* HWPUF initialization failed */ + HWPUF_ENROLL_E = -1021, /* HWPUF enrollment failed */ + HWPUF_START_E = -1022, /* HWPUF start failed */ + HWPUF_GENERATE_KEY_E= -1023, /* HWPUF generate key failed */ + HWPUF_GET_KEY_E = -1024, /* HWPUF get key failed */ + HWPUF_ZEROIZE_E = -1025, /* HWPUF zeroize failed */ + + WC_SPAN2_LAST_E = -1025, /* Update to indicate last used error code */ + WC_LAST_E = -1025, /* the last code used either here or in * error-ssl.h */ WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */ diff --git a/wolfssl/wolfcrypt/hwpuf.h b/wolfssl/wolfcrypt/hwpuf.h new file mode 100644 index 00000000000..eb579dfb124 --- /dev/null +++ b/wolfssl/wolfcrypt/hwpuf.h @@ -0,0 +1,94 @@ +/* hwpuf.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#ifndef WOLF_CRYPT_HWPUF_H +#define WOLF_CRYPT_HWPUF_H + +#include +#include + +#ifdef WOLFSSL_HWPUF + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef WOLFSSL_NXP_HWPUF + #define HWPUF_ACTIVATION_CODE_SIZE 1192 + /* keyCode size is 52 for key sizes of 16, 24, or 32 */ + #define HWPUF_KEY_SIZE_TO_KEY_CODE_SIZE(keysz) 52 +#else + #error HWPUF: No valid port defined +#endif + + +/* flags stored in wc_HWPUF.flags */ +enum wc_HwpufFlags { + WC_HWPUF_FLAG_NONE = 0, /* Deinit() clears all flags */ + WC_HWPUF_FLAG_INITED = 0x01, /* Init() called successfully */ + WC_HWPUF_FLAG_ENROLLED = 0x02, /* Enroll() called successfully */ + WC_HWPUF_FLAG_READY = 0x04, /* Start() called successfully */ + WOLF_ENUM_DUMMY_LAST_ELEMENT(WC_HWPUF_FLAG) +}; + +/* operation type passed to CryptoCb via wc_CryptoInfo.hwpuf.type */ +enum wc_HwpufType { + WC_HWPUF_TYPE_NONE = 0, + WC_HWPUF_TYPE_INIT = 1, + WC_HWPUF_TYPE_DEINIT = 2, + WC_HWPUF_TYPE_ENROLL = 3, + WC_HWPUF_TYPE_START = 4, + WC_HWPUF_TYPE_GENERATE_KEY = 5, + WC_HWPUF_TYPE_GET_KEY = 6, + WC_HWPUF_TYPE_ZEROIZE = 7, + WOLF_ENUM_DUMMY_LAST_ELEMENT(WC_HWPUF_TYPE) +}; + +typedef struct wc_HWPUF { + word32 flags; + int devId; + void* heap; +} wc_HWPUF; + +WOLFSSL_API int wc_HWPUF_Register(wc_HWPUF* hwpuf, void* heap, int devId); +WOLFSSL_API int wc_HWPUF_Unregister(wc_HWPUF* hwpuf); + +WOLFSSL_API int wc_HWPUF_Init(wc_HWPUF* hwpuf); +WOLFSSL_API int wc_HWPUF_Deinit(wc_HWPUF* hwpuf); +WOLFSSL_API int wc_HWPUF_Enroll(wc_HWPUF* hwpuf, + byte* actCode, word32 actCodeSz); +WOLFSSL_API int wc_HWPUF_Start(wc_HWPUF* hwpuf, + byte* actCode, word32 actCodeSz); +WOLFSSL_API int wc_HWPUF_GenerateKey(wc_HWPUF* hwpuf, + byte keyIdx, word32 keySz, + byte* keyCode, word32 keyCodeSz); +WOLFSSL_API int wc_HWPUF_GetKey(wc_HWPUF* hwpuf, + byte* keyCode, word32 keyCodeSz, + byte* key, word32 keySz); +WOLFSSL_API int wc_HWPUF_Zeroize(wc_HWPUF* hwpuf); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* WOLFSSL_HWPUF */ +#endif /* WOLF_CRYPT_HWPUF_H */ diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 9635e1a6cfd..1a775e2c896 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -85,6 +85,7 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/wc_xmss.h \ wolfssl/wolfcrypt/wc_slhdsa.h \ wolfssl/wolfcrypt/puf.h \ + wolfssl/wolfcrypt/hwpuf.h \ wolfssl/wolfcrypt/oid_sum.h noinst_HEADERS+= \ @@ -98,6 +99,7 @@ noinst_HEADERS+= \ wolfssl/wolfcrypt/port/nxp/dcp_port.h \ wolfssl/wolfcrypt/port/nxp/casper_port.h \ wolfssl/wolfcrypt/port/nxp/hashcrypt_port.h \ + wolfssl/wolfcrypt/port/nxp/hwpuf_port.h \ wolfssl/wolfcrypt/port/xilinx/xil-sha3.h \ wolfssl/wolfcrypt/port/xilinx/xil-versal-glue.h \ wolfssl/wolfcrypt/port/xilinx/xil-versal-trng.h \ diff --git a/wolfssl/wolfcrypt/port/nxp/hwpuf_port.h b/wolfssl/wolfcrypt/port/nxp/hwpuf_port.h new file mode 100644 index 00000000000..1b6d44a35c0 --- /dev/null +++ b/wolfssl/wolfcrypt/port/nxp/hwpuf_port.h @@ -0,0 +1,40 @@ +/* hwpuf_port.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#ifndef _NXP_HWPUF_PORT_H_ +#define _NXP_HWPUF_PORT_H_ + +#include + +#if defined(WOLFSSL_HWPUF) && defined(WOLFSSL_NXP_HWPUF) + +#include + +#define WOLFSSL_NXP_HWPUF_DEVID 5569 + +#define HWPUF_KEY_SIZE_IS_VALID(keysz) \ + (keysz == 16 || keysz == 24 || keysz == 32) + +WOLFSSL_API int nxp_hwpuf_RegisterDevice(wc_HWPUF* hwpuf); +WOLFSSL_API int nxp_hwpuf_UnregisterDevice(wc_HWPUF* hwpuf); + +#endif /* WOLFSSL_HWPUF && WOLFSSL_NXP_HWPUF */ + +#endif /* _NXP_HWPUF_PORT_H_ */ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index e574273d746..e5af479d233 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -2205,6 +2205,12 @@ #define NO_WOLFSSL_SHA256_INTERLEAVE #endif +#if defined(WOLFSSL_HWPUF) && defined(WOLFSSL_NXP_HWPUF) +#ifndef WOLF_CRYPTO_CB + #define WOLF_CRYPTO_CB +#endif +#endif + #ifdef FREESCALE_LTC_TFM_RSA_4096_ENABLE #undef USE_CERT_BUFFERS_4096 #define USE_CERT_BUFFERS_4096 diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index cf8900f6ee0..68e3bccb5d0 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1433,7 +1433,8 @@ enum wc_AlgoType { WC_ALGO_TYPE_SETKEY = 12, WC_ALGO_TYPE_EXPORT_KEY = 13, WC_ALGO_TYPE_SHE = 14, - WC_ALGO_TYPE_MAX = WC_ALGO_TYPE_SHE + WC_ALGO_TYPE_HWPUF = 15, + WC_ALGO_TYPE_MAX = WC_ALGO_TYPE_HWPUF }; /* KDF types */