diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index c4a26205436..04b83e6705c 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -775,6 +775,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_NRF51_AES WOLFSSL_NXP_CASPER_ECC_MUL2ADD WOLFSSL_NXP_CASPER_ECC_MULMOD WOLFSSL_NXP_LPC55S6X +WOLFSSL_NXP_PUF WOLFSSL_OLDTLS_AEAD_CIPHERSUITES WOLFSSL_OLD_SET_CURVES_LIST WOLFSSL_OLD_TIMINGPADVERIFY diff --git a/doc/dox_comments/header_files/puf.h b/doc/dox_comments/header_files/puf.h index 73e5a2340bb..431edcdc766 100644 --- a/doc/dox_comments/header_files/puf.h +++ b/doc/dox_comments/header_files/puf.h @@ -9,7 +9,8 @@ \ingroup PUF \brief Initialize a wc_PufCtx structure, zeroing all fields. - Must be called before any other PUF operations. + Hardware PUF (WOLFSSL_HWPUF) may turn on power/clock and reset the + peripheral. Must be called before any other PUF operations. \return 0 on success \return BAD_FUNC_ARG if ctx is NULL @@ -22,17 +23,45 @@ ret = wc_PufInit(&ctx); \endcode + \sa wc_PufDeinit \sa wc_PufReadSram \sa wc_PufEnroll \sa wc_PufZeroize */ int wc_PufInit(wc_PufCtx* ctx); +/*! + \ingroup PUF + + \brief Deinitialize a wc_PufCtx structure, zeroing all fields. + Hardware PUF (WOLFSSL_HWPUF) may turn off power/clock and reset the + peripheral. + + \return 0 on success + \return BAD_FUNC_ARG if ctx is NULL + + \param ctx pointer to wc_PufCtx structure to initialize + + _Example_ + \code + wc_PufCtx ctx; + ret = wc_PufDeinit(&ctx); + \endcode + + \sa wc_PufInit + \sa wc_PufReadSram + \sa wc_PufEnroll + \sa wc_PufZeroize +*/ +int wc_PufDeinit(wc_PufCtx* ctx); + /*! \ingroup PUF \brief Read raw SRAM data into the PUF context. The sramAddr should point to a NOLOAD linker section to preserve the power-on state. + This function is valid for software PUF (WOLFSSL_PUF), but invalid for + hardware PUF (WOLFSSL_HWPUF) \return 0 on success \return BAD_FUNC_ARG if ctx or sramAddr is NULL @@ -58,9 +87,14 @@ int wc_PufReadSram(wc_PufCtx* ctx, const byte* sramAddr, word32 sramSz); /*! \ingroup PUF - \brief Perform PUF enrollment. Encodes raw SRAM using BCH(127,64,t=10) + \brief Perform PUF enrollment. + For software PUF (WOLFSSL_PUF), encodes raw SRAM using BCH(127,64,t=10) and generates public helper data. After enrollment the context is ready for key derivation and identity retrieval. + For hardware PUF (WOLFSSL_HWPUF), encodes raw SRAM using a proprietary + method and generates an Activation Code. After enrollment, device must + go through a deinit/init/reconstruct cycle, before device is ready for + key generation/derivation. There is no helperData for hardware puf. \return 0 on success \return BAD_FUNC_ARG if ctx is NULL @@ -76,6 +110,7 @@ int wc_PufReadSram(wc_PufCtx* ctx, const byte* sramAddr, word32 sramSz); \sa wc_PufReadSram \sa wc_PufReconstruct + \sa wc_PufGenerateKey \sa wc_PufDeriveKey */ int wc_PufEnroll(wc_PufCtx* ctx); @@ -83,9 +118,13 @@ int wc_PufEnroll(wc_PufCtx* ctx); /*! \ingroup PUF - \brief Reconstruct stable PUF bits from noisy SRAM using stored helper - data. BCH error correction (t=10) corrects up to 10 bit flips per - 127-bit codeword. + \brief Performs reconstruction (starts puf) with data from enrollment. + For software PUF (WOLFSSL_PUF), reconstructs stable PUF bits from noisy + SRAM using stored helper data. BCH error correction (t=10) corrects up to + 10 bit flips per 127-bit codeword. + For hardware PUF (WOLFSSL_HWPUF), starts PUF peripheral with an activation + code, which is stored internally in RAM during a previous enrollment, or + is stored in flash in a known location. helperData is ignored for hw puf. \return 0 on success \return BAD_FUNC_ARG if ctx or helperData is NULL @@ -110,18 +149,58 @@ int wc_PufReconstruct(wc_PufCtx* ctx, const byte* helperData, word32 helperSz); /*! \ingroup PUF - \brief Derive a cryptographic key from PUF stable bits using HKDF. + \brief Generates a key and returns a key code (WOLFSSL_HWPUF only). + The key code can be later used to derive the key. + This function is invalid for software PUF (WOLFSSL_PUF). + + \return 0 on success + \return BAD_FUNC_ARG if ctx or kcBuf is NULL, or keyIdx/keySz/kcBufSz is bad + \return PUF_GENERATE_KEY_E if PUF not ready or key generation fails + + \param ctx pointer to wc_PufCtx (must be enrolled or reconstructed) + \param keyIdx key index 0 to 15. If 0, when derived, will be sent directly + to hardware bus (never exposed in ram) + \param keySz size of key in bytes, 16, 24, 32 are valid + \param kcBuf key code output buffer + \param kcBufSz size of key code output buffer + + _Example_ + \code + byte key[32]; + const byte info[] = "my-app-key"; + wc_PufDeriveKey(&ctx, info, sizeof(info), key, sizeof(key)); + \endcode + + \sa wc_PufEnroll + \sa wc_PufReconstruct + \sa wc_PufGetIdentity + \sa wc_PufDeriveKey +*/ +int wc_PufGenerateKey(wc_PufCtx* ctx, byte keyIdx, word32 keySz, + byte* kcBuf, word32 kcBufSz); + +/*! + \ingroup PUF + + \brief Derive a cryptographic key + For software PUF (WOLFSSL_PUF), derives key from stable bits using HKDF. Uses SHA-256 by default, or SHA3-256 when WC_PUF_SHA3 is defined. The info parameter provides domain separation for multiple keys. Requires HAVE_HKDF. + For hardware PUF (WOLFSSL_HWPUF), derives key from the key code previously + generated. If the key was originally generated with key index 0, then the + derived key is sent directly to the hardware bus, and key buffer will be + zeroed. \return 0 on success \return BAD_FUNC_ARG if ctx or key is NULL, or keySz is 0 - \return PUF_DERIVE_KEY_E if PUF not ready or HKDF fails + \return PUF_DERIVE_KEY_E if PUF not ready or key derivation fails \param ctx pointer to wc_PufCtx (must be enrolled or reconstructed) - \param info optional context info for domain separation (may be NULL; - when NULL, infoSz is treated as 0) + \param info For software PUF (WOLFSSL_PUF), this is optional context info + for domain separation (may be NULL; when NULL, infoSz is treated as 0). + For hardware PUF (WOLFSSL_HWPUF), this is the key code returned when the + key was generated. \param infoSz size of info in bytes \param key output buffer for derived key \param keySz desired key size in bytes @@ -135,6 +214,7 @@ int wc_PufReconstruct(wc_PufCtx* ctx, const byte* helperData, word32 helperSz); \sa wc_PufEnroll \sa wc_PufReconstruct + \sa wc_PufGenerateKey \sa wc_PufGetIdentity */ int wc_PufDeriveKey(wc_PufCtx* ctx, const byte* info, word32 infoSz, @@ -145,6 +225,8 @@ int wc_PufDeriveKey(wc_PufCtx* ctx, const byte* info, word32 infoSz, \brief Retrieve the device identity hash (SHA-256 or SHA3-256 of stable bits). Deterministic for a given device. + This function is valid for software PUF (WOLFSSL_PUF), but invalid for + hardware PUF (WOLFSSL_HWPUF). \return 0 on success \return BAD_FUNC_ARG if ctx or id is NULL @@ -191,6 +273,8 @@ int wc_PufZeroize(wc_PufCtx* ctx); \brief Inject synthetic SRAM test data for testing without hardware. Only available when WOLFSSL_PUF_TEST is defined. + This function is valid for software PUF (WOLFSSL_PUF), but invalid for + hardware PUF (WOLFSSL_HWPUF). \return 0 on success \return BAD_FUNC_ARG if ctx or data is NULL diff --git a/wolfcrypt/src/include.am b/wolfcrypt/src/include.am index 18d7a339cd5..74241a43faf 100644 --- a/wolfcrypt/src/include.am +++ b/wolfcrypt/src/include.am @@ -73,6 +73,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..80129d48a6f --- /dev/null +++ b/wolfcrypt/src/port/nxp/hwpuf_port.c @@ -0,0 +1,294 @@ +/* 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_PUF) + +#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 struct { + byte activationCode[PUF_ACTIVATION_CODE_SIZE]; + byte ac_set; + word32 keyMask; /* unique per reset */ +} sPufData; + +static sPufData pufData; +static puf_config_t conf; + + +static int getACFromPFR(byte *ac) +{ + int ret; + flash_config_t flashInstance; + + memset(&flashInstance, 0, sizeof(flash_config_t)); + FLASH_Init(&flashInstance); + FFR_Init(&flashInstance); + + ret = FFR_KeystoreGetAC(&flashInstance, ac); + return ret != kStatus_Success; +} + +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 >= 2) + return 1; + if (*keyidx >= 16) + return 2; + if ( !HWPUF_KEY_SIZE_IS_VALID(*keysize) ) + return 3; + + return 0; +} + +int wc_PufInit(wc_PufCtx* ctx) +{ + WOLFSSL_ENTER("wc_PufInit"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + XMEMSET(ctx, 0, sizeof(wc_PufCtx)); + + PUF_GetDefaultConfig(&conf); + if (PUF_Init(PUF, &conf) != kStatus_Success) { + PUF_Deinit(PUF, &conf); + return PUF_INIT_E; + } + pufData.keyMask = RNG->RANDOM_NUMBER; + return 0; +} + +int wc_PufDeinit(wc_PufCtx* ctx) +{ + WOLFSSL_ENTER("wc_PufDeinit"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + XMEMSET(ctx, 0, sizeof(wc_PufCtx)); + + PUF_Deinit(PUF, &conf); + + return 0; +} + +/* not valid function for hw puf */ +int wc_PufReadSram(wc_PufCtx* ctx, const byte* sramAddr, word32 sramSz) +{ + WOLFSSL_ENTER("wc_PufReadSram"); + + (void)ctx; + (void)sramAddr; + (void)sramSz; + + return PUF_READ_E; +} + +int wc_PufEnroll(wc_PufCtx* ctx) +{ + int ret; + byte activationCode[PUF_ACTIVATION_CODE_SIZE]; + + WOLFSSL_ENTER("wc_PufEnroll"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + ret = PUF_Enroll(PUF, activationCode, sizeof(activationCode)); + if (ret == kStatus_EnrollNotAllowed) { + /* power cycle and try again */ + (void)PUF_PowerCycle(PUF, &conf); + ret = PUF_Enroll(PUF, activationCode, sizeof(activationCode)); + } + if (ret != kStatus_Success) { + PUF_Deinit(PUF, &conf); + return PUF_ENROLL_E; + } + + /* wipe pufData if enroll succeeded (re-enroll will render pufData moot) */ + XMEMSET(&pufData, 0, sizeof(pufData)); + /* store activation code */ + XMEMCPY(pufData.activationCode, activationCode, PUF_ACTIVATION_CODE_SIZE); + pufData.ac_set = 1; + + ctx->flags |= WC_PUF_FLAG_ENROLLED | WC_PUF_FLAG_READY; + return 0; +} + +int wc_PufReconstruct(wc_PufCtx* ctx, const byte* helperData, word32 helperSz) +{ + int ret; + + (void)helperData; + (void)helperSz; + + WOLFSSL_ENTER("wc_PufReconstruct"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + if (pufData.ac_set == 0) { + byte activationCode[PUF_ACTIVATION_CODE_SIZE]; + /* try pulling from mfg flash area (what rom code uses) */ + if (getACFromPFR(activationCode) != 0) + return PUF_RECONSTRUCT_E; + + XMEMSET(&pufData, 0, sizeof(pufData)); + XMEMCPY(pufData.activationCode, activationCode, + PUF_ACTIVATION_CODE_SIZE); + pufData.ac_set = 1; + } + + ret = PUF_Start(PUF, pufData.activationCode, PUF_ACTIVATION_CODE_SIZE); + if (ret == kStatus_StartNotAllowed) { + /* power cycle and try again */ + (void)PUF_PowerCycle(PUF, &conf); + ret = PUF_Start(PUF, pufData.activationCode, PUF_ACTIVATION_CODE_SIZE); + } + if (ret != kStatus_Success) { + PUF_Deinit(PUF, &conf); + return PUF_RECONSTRUCT_E; + } + + ctx->flags |= WC_PUF_FLAG_READY; + return 0; +} + +int wc_PufGenerateKey(wc_PufCtx* ctx, byte keyIdx, word32 keySz, + byte* kcBuf, word32 kcBufSz) +{ + int ret; + word32 keycodeSz; + + if (ctx == NULL) + return BAD_FUNC_ARG; + if (!(ctx->flags & WC_PUF_FLAG_READY)) + return PUF_GENERATE_KEY_E; + if (keyIdx > kPUF_KeyIndexMax) + return BAD_FUNC_ARG; + if ( !HWPUF_KEY_SIZE_IS_VALID(keySz) ) + return BAD_FUNC_ARG; + keycodeSz = PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySz); + if (kcBuf == NULL || kcBufSz != keycodeSz) + return BAD_FUNC_ARG; + + ret = PUF_SetIntrinsicKey(PUF, (puf_key_index_register_t)keyIdx, keySz, + kcBuf, keycodeSz); + if (ret != kStatus_Success) + return PUF_GENERATE_KEY_E; + + return 0; +} + +int wc_PufDeriveKey(wc_PufCtx* ctx, const byte* info, word32 infoSz, + byte* key, word32 keySz) +{ + int ret; + byte* keycode = (byte*)info; + word32 keytype, keyidx, keysize; + word32 keycodesize; + + WOLFSSL_ENTER("wc_PufDeriveKey"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + if (!(ctx->flags & WC_PUF_FLAG_READY)) + return PUF_DERIVE_KEY_E; + if (info == NULL || infoSz < PUF_MIN_KEY_CODE_SIZE) + return BAD_FUNC_ARG; + + ret = keyCodeCheck(keycode, &keytype, &keyidx, &keysize); + if (ret != kStatus_Success) + return BAD_FUNC_ARG; + + keycodesize = PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keysize); + if (keycodesize != infoSz) + 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, keycodesize, kPUF_KeySlot0, + pufData.keyMask); + if (ret != kStatus_Success) + return PUF_DERIVE_KEY_E; + if (key) + XMEMSET(key, 0, keySz); /* no key to return, zero out */ + } + else { + ret = PUF_GetKey(PUF, keycode, keycodesize, key, keySz); + if (ret != kStatus_Success) + return PUF_DERIVE_KEY_E; + } + return 0; +} + +/* not valid function for hw puf */ +int wc_PufGetIdentity(wc_PufCtx* ctx, byte* id, word32 idSz) +{ + WOLFSSL_ENTER("wc_PufGetIdentity"); + + (void)ctx; + (void)id; + (void)idSz; + + return PUF_IDENTITY_E; +} + +int wc_PufZeroize(wc_PufCtx* ctx) +{ + WOLFSSL_ENTER("wc_PufZeroize"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + ForceZero(ctx, sizeof(wc_PufCtx)); + + if (PUF_Zeroize(PUF) != kStatus_Success) { + PUF_Deinit(PUF, &conf); + return PUF_ZEROIZE_E; + } + return 0; +} + +#endif /* WOLFSSL_HWPUF && WOLFSSL_NXP_PUF */ diff --git a/wolfcrypt/src/puf.c b/wolfcrypt/src/puf.c index 74c59925483..7b20b0f6c20 100644 --- a/wolfcrypt/src/puf.c +++ b/wolfcrypt/src/puf.c @@ -464,6 +464,18 @@ int wc_PufInit(wc_PufCtx* ctx) return 0; } +int wc_PufDeinit(wc_PufCtx* ctx) +{ + WOLFSSL_ENTER("wc_PufDeinit"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + XMEMSET(ctx, 0, sizeof(wc_PufCtx)); + + return 0; +} + int wc_PufReadSram(wc_PufCtx* ctx, const byte* sramAddr, word32 sramSz) { WOLFSSL_ENTER("wc_PufReadSram"); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 329c88cffdf..65f339ff7f1 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -425,9 +425,12 @@ static const byte const_byte_array[] = "A+Gd\0\0\0"; #ifdef WOLFSSL_SM4 #include #endif -#ifdef WOLFSSL_PUF +#if defined(WOLFSSL_PUF) || defined(WOLFSSL_HWPUF) #include #endif +#if defined(WOLFSSL_HWPUF) && defined(WOLFSSL_NXP_PUF) + #include +#endif #ifdef HAVE_LIBZ #include #endif @@ -884,7 +887,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t camellia_test(void); #ifdef WOLFSSL_SM4 WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sm4_test(void); #endif -#ifdef WOLFSSL_PUF +#if defined(WOLFSSL_PUF) || defined(WOLFSSL_HWPUF) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t puf_test(void); #endif #ifdef WC_RSA_NO_PADDING @@ -2939,7 +2942,7 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_PASS("SM-4 test passed!\n"); #endif -#ifdef WOLFSSL_PUF +#if defined(WOLFSSL_PUF) || defined(WOLFSSL_HWPUF) if ( (ret = puf_test()) != 0) return err_sys("PUF test failed!\n", ret); else @@ -23308,6 +23311,157 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t puf_test(void) } #endif /* WOLFSSL_PUF */ +#ifdef WOLFSSL_HWPUF +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t puf_test(void) +{ + wc_test_ret_t ret = 0; + wc_PufCtx ctx; + 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("puf_test"); + + /* ---- Test 1: Init ---- */ + ret = wc_PufInit(&ctx); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* ---- Test 2: Enroll ---- */ + ret = wc_PufEnroll(&ctx); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* hw puf requires a deinit/init cycle after enroll */ + (void)wc_PufDeinit(&ctx); + (void)wc_PufInit(&ctx); + + /* ---- Test 3: Reconstruct (start) ---- */ + ret = wc_PufReconstruct(&ctx, NULL, 0); + 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_PufGenerateKey(&ctx, 1, 16, keycode16, sizeof(keycode16)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* derive key from keycode */ + ret = wc_PufDeriveKey(&ctx, 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_PufGenerateKey(&ctx, 1, 24, keycode24, sizeof(keycode24)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* derive key from keycode */ + ret = wc_PufDeriveKey(&ctx, 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_PufGenerateKey(&ctx, 1, 32, keycode32, sizeof(keycode32)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* derive key from keycode */ + ret = wc_PufDeriveKey(&ctx, 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_PufDeinit(&ctx); + (void)wc_PufInit(&ctx); + ret = wc_PufReconstruct(&ctx, NULL, 0); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* 16-byte */ + ret = wc_PufDeriveKey(&ctx, keycode16, sizeof(keycode16), key16_2, sizeof(key16_2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* 24-byte */ + ret = wc_PufDeriveKey(&ctx, keycode24, sizeof(keycode24), key24_2, sizeof(key24_2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* 32-byte */ + ret = wc_PufDeriveKey(&ctx, 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 7: generate a key and send directly to hw bus ---- */ + ret = wc_PufGenerateKey(&ctx, 0, 32, keycode32, sizeof(keycode32)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + /* derive key from keycode */ + ret = wc_PufDeriveKey(&ctx, keycode32, sizeof(keycode32), key32_2, sizeof(key32_2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + { /* key1 should be zeroed */ + int idx; + for (idx = 0; idx < sizeof(key32_2); ++idx) { + if (key32_2[idx]) + return WC_TEST_RET_ENC_NC; + } + } + + /* ---- Test 8: Bad argument checks ---- */ + /* null ctx */ + if (wc_PufInit(NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + if (wc_PufDeinit(NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + if (wc_PufEnroll(NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + if (wc_PufZeroize(NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + /* out of bounds key index */ + if (wc_PufGenerateKey(&ctx, 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_PufGenerateKey(&ctx, 1, 32, keycode32, 99) + != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + /* null key code storage */ + if (wc_PufGenerateKey(&ctx, 1, 32, NULL, sizeof(keycode32)) + != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + /* invalid key storage size */ + ret = wc_PufGenerateKey(&ctx, 7, 32, keycode32, sizeof(keycode32)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (wc_PufDeriveKey(&ctx, 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_PufDeriveKey(&ctx, keycode32, sizeof(keycode32), NULL, sizeof(key32_1)) + != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + + /* ---- Test 9: Zeroize ---- */ + ret = wc_PufZeroize(&ctx); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (wc_PufDeriveKey(&ctx, keycode24, sizeof(keycode32), key24_1, sizeof(key24_1)) + != WC_NO_ERR_TRACE(PUF_DERIVE_KEY_E)) + return WC_TEST_RET_ENC_NC; + + return 0; +} +#endif /* WOLFSSL_HWPUF */ + #ifdef HAVE_XCHACHA WOLFSSL_TEST_SUBROUTINE wc_test_ret_t XChaCha_test(void) { diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 8d49ffc18ef..04b0ac3afd4 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -328,8 +328,11 @@ 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 + PUF_GENERATE_KEY_E = -1019, /* PUF key generation failed */ + PUF_ZEROIZE_E = -1020, /* PUF zeroize failed */ + + WC_SPAN2_LAST_E = -1020, /* Update to indicate last used error code */ + WC_LAST_E = -1020, /* 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/include.am b/wolfssl/wolfcrypt/include.am index 9635e1a6cfd..cf93464d65f 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -98,6 +98,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..808e3ff56e7 --- /dev/null +++ b/wolfssl/wolfcrypt/port/nxp/hwpuf_port.h @@ -0,0 +1,33 @@ +/* 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 +#include "fsl_puf.h" + +#define HWPUF_KEY_SIZE_IS_VALID(keysz) \ + (keysz == 16 || keysz == 24 || keysz == 32) + +#define HWPUF_KEY_SIZE_TO_KEY_CODE_SIZE(keysz) \ + PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keysz) + +#endif /* _NXP_HWPUF_PORT_H_ */ diff --git a/wolfssl/wolfcrypt/puf.h b/wolfssl/wolfcrypt/puf.h index 855848574fe..a88ef474e4a 100644 --- a/wolfssl/wolfcrypt/puf.h +++ b/wolfssl/wolfcrypt/puf.h @@ -37,7 +37,7 @@ #include -#ifdef WOLFSSL_PUF +#if defined(WOLFSSL_PUF) || defined(WOLFSSL_HWPUF) /* PUF is not a FIPS-validated algorithm. Fail loudly at compile time rather * than producing undefined references at link time when WOLFSSL_PUF is @@ -81,29 +81,36 @@ #define WC_PUF_FLAG_SRAM_SET 0x04 typedef struct wc_PufCtx { +#ifndef WOLFSSL_HWPUF byte rawSram[WC_PUF_RAW_BYTES]; /* raw SRAM readout */ byte helperData[WC_PUF_HELPER_BYTES]; /* enrollment helper data */ byte stableBits[WC_PUF_STABLE_BYTES]; /* reconstructed stable bits */ byte identity[WC_PUF_ID_SZ]; /* device identity hash */ +#endif word32 flags; -#ifdef WOLFSSL_PUF_TEST +#if defined(WOLFSSL_PUF_TEST) && !defined(WOLFSSL_HWPUF) word32 testDataSet; /* flag: test data was injected */ #endif } wc_PufCtx; WOLFSSL_API int wc_PufInit(wc_PufCtx* ctx); +WOLFSSL_API int wc_PufDeinit(wc_PufCtx* ctx); WOLFSSL_API int wc_PufReadSram(wc_PufCtx* ctx, const byte* sramAddr, word32 sramSz); WOLFSSL_API int wc_PufEnroll(wc_PufCtx* ctx); WOLFSSL_API int wc_PufReconstruct(wc_PufCtx* ctx, const byte* helperData, word32 helperSz); +#ifdef WOLFSSL_HWPUF +WOLFSSL_API int wc_PufGenerateKey(wc_PufCtx* ctx, byte keyIdx, word32 keySz, + byte* keycode, word32 keycodeSz); +#endif WOLFSSL_API int wc_PufDeriveKey(wc_PufCtx* ctx, const byte* info, word32 infoSz, byte* key, word32 keySz); WOLFSSL_API int wc_PufGetIdentity(wc_PufCtx* ctx, byte* id, word32 idSz); WOLFSSL_API int wc_PufZeroize(wc_PufCtx* ctx); -#ifdef WOLFSSL_PUF_TEST +#if defined(WOLFSSL_PUF_TEST) && !defined(WOLFSSL_HWPUF) WOLFSSL_API int wc_PufSetTestData(wc_PufCtx* ctx, const byte* data, word32 sz); #endif @@ -111,6 +118,6 @@ WOLFSSL_API int wc_PufSetTestData(wc_PufCtx* ctx, const byte* data, word32 sz); } /* extern "C" */ #endif -#endif /* WOLFSSL_PUF */ +#endif /* WOLFSSL_PUF || WOLFSSL_HWPUF */ #endif /* WOLF_CRYPT_PUF_H */