diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index dcdb5bf7b0..0036556ba9 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -1017,6 +1017,154 @@ int wc_CryptoCb_Ed25519Verify(const byte* sig, word32 sigLen, } #endif /* HAVE_ED25519 */ +#if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) +int wc_CryptoCb_PqcStatefulSigGetDevId(int type, void* key) +{ + int devId = INVALID_DEVID; + + if (key == NULL) + return devId; + +#if defined(WOLFSSL_HAVE_LMS) + if (type == WC_PQC_STATEFUL_SIG_TYPE_LMS) { + devId = ((LmsKey*)key)->devId; + } +#endif +#if defined(WOLFSSL_HAVE_XMSS) + if (type == WC_PQC_STATEFUL_SIG_TYPE_XMSS) { + devId = ((XmssKey*)key)->devId; + } +#endif + + return devId; +} + +int wc_CryptoCb_PqcStatefulSigKeyGen(int type, void* key, WC_RNG* rng) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + int devId = INVALID_DEVID; + CryptoCb* dev; + + if (key == NULL) + return ret; + + devId = wc_CryptoCb_PqcStatefulSigGetDevId(type, key); + if (devId == INVALID_DEVID) + return ret; + + dev = wc_CryptoCb_FindDevice(devId, WC_ALGO_TYPE_PK); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_PK; + cryptoInfo.pk.type = WC_PK_TYPE_PQC_STATEFUL_SIG_KEYGEN; + cryptoInfo.pk.pqc_stateful_sig_kg.rng = rng; + cryptoInfo.pk.pqc_stateful_sig_kg.key = key; + cryptoInfo.pk.pqc_stateful_sig_kg.type = type; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_PqcStatefulSigSign(const byte* msg, word32 msgSz, byte* out, + word32* outSz, int type, void* key) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + int devId = INVALID_DEVID; + CryptoCb* dev; + + if (key == NULL) + return ret; + + devId = wc_CryptoCb_PqcStatefulSigGetDevId(type, key); + if (devId == INVALID_DEVID) + return ret; + + dev = wc_CryptoCb_FindDevice(devId, WC_ALGO_TYPE_PK); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_PK; + cryptoInfo.pk.type = WC_PK_TYPE_PQC_STATEFUL_SIG_SIGN; + cryptoInfo.pk.pqc_stateful_sig_sign.msg = msg; + cryptoInfo.pk.pqc_stateful_sig_sign.msgSz = msgSz; + cryptoInfo.pk.pqc_stateful_sig_sign.out = out; + cryptoInfo.pk.pqc_stateful_sig_sign.outSz = outSz; + cryptoInfo.pk.pqc_stateful_sig_sign.key = key; + cryptoInfo.pk.pqc_stateful_sig_sign.type = type; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_PqcStatefulSigVerify(const byte* sig, word32 sigSz, + const byte* msg, word32 msgSz, int* res, int type, void* key) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + int devId = INVALID_DEVID; + CryptoCb* dev; + + if (key == NULL) + return ret; + + devId = wc_CryptoCb_PqcStatefulSigGetDevId(type, key); + if (devId == INVALID_DEVID) + return ret; + + dev = wc_CryptoCb_FindDevice(devId, WC_ALGO_TYPE_PK); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_PK; + cryptoInfo.pk.type = WC_PK_TYPE_PQC_STATEFUL_SIG_VERIFY; + cryptoInfo.pk.pqc_stateful_sig_verify.sig = sig; + cryptoInfo.pk.pqc_stateful_sig_verify.sigSz = sigSz; + cryptoInfo.pk.pqc_stateful_sig_verify.msg = msg; + cryptoInfo.pk.pqc_stateful_sig_verify.msgSz = msgSz; + cryptoInfo.pk.pqc_stateful_sig_verify.res = res; + cryptoInfo.pk.pqc_stateful_sig_verify.key = key; + cryptoInfo.pk.pqc_stateful_sig_verify.type = type; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_PqcStatefulSigSigsLeft(int type, void* key, word32* sigsLeft) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + int devId = INVALID_DEVID; + CryptoCb* dev; + + if (key == NULL) + return ret; + + devId = wc_CryptoCb_PqcStatefulSigGetDevId(type, key); + if (devId == INVALID_DEVID) + return ret; + + dev = wc_CryptoCb_FindDevice(devId, WC_ALGO_TYPE_PK); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_PK; + cryptoInfo.pk.type = WC_PK_TYPE_PQC_STATEFUL_SIG_SIGS_LEFT; + cryptoInfo.pk.pqc_stateful_sig_sigs_left.key = key; + cryptoInfo.pk.pqc_stateful_sig_sigs_left.sigsLeft = sigsLeft; + cryptoInfo.pk.pqc_stateful_sig_sigs_left.type = type; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} +#endif /* WOLFSSL_HAVE_LMS || WOLFSSL_HAVE_XMSS */ + #if defined(WOLFSSL_HAVE_MLKEM) int wc_CryptoCb_PqcKemGetDevId(int type, void* key) { diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c index 99a3e19e81..109a53dcf1 100644 --- a/wolfcrypt/src/wc_lms.c +++ b/wolfcrypt/src/wc_lms.c @@ -28,6 +28,7 @@ #define FIPS_NO_WRAPPERS #endif #include +#include #ifdef NO_INLINE #include @@ -36,6 +37,10 @@ #include #endif +#ifdef WOLF_CRYPTO_CB + #include +#endif + /* Calculate u. Appendix B. Works for w of 1, 2, 4, or 8. * @@ -642,6 +647,72 @@ int wc_LmsKey_Init(LmsKey* key, void* heap, int devId) return ret; } +#ifdef WOLF_PRIVATE_KEY_ID +/* Initialize an LmsKey and bind it to a device-side key identifier. + * + * @param [in,out] key LmsKey to initialize. + * @param [in] id Identifier bytes (may be NULL when len is 0). + * @param [in] len Length of id; must be in [0, LMS_MAX_ID_LEN]. + * @param [in] heap Heap hint forwarded to wc_LmsKey_Init. + * @param [in] devId Device identifier. + * + * @return 0 on success. + * @return BAD_FUNC_ARG when key is NULL. + * @return BUFFER_E when len is negative or exceeds LMS_MAX_ID_LEN. + */ +int wc_LmsKey_InitId(LmsKey* key, const unsigned char* id, int len, void* heap, + int devId) +{ + int ret = 0; + + if (key == NULL) + ret = BAD_FUNC_ARG; + if (ret == 0 && (len < 0 || len > LMS_MAX_ID_LEN)) + ret = BUFFER_E; + if (ret == 0) + ret = wc_LmsKey_Init(key, heap, devId); + if (ret == 0 && id != NULL && len != 0) { + XMEMCPY(key->id, id, (size_t)len); + key->idLen = len; + } + + return ret; +} + +/* Initialize an LmsKey and bind it to a device-side key label. + * + * @param [in,out] key LmsKey to initialize. + * @param [in] label NUL-terminated label string (must be non-empty). + * @param [in] heap Heap hint forwarded to wc_LmsKey_Init. + * @param [in] devId Device identifier. + * + * @return 0 on success. + * @return BAD_FUNC_ARG when key or label is NULL. + * @return BUFFER_E when label is empty or longer than LMS_MAX_LABEL_LEN. + */ +int wc_LmsKey_InitLabel(LmsKey* key, const char* label, void* heap, int devId) +{ + int ret = 0; + int labelLen = 0; + + if (key == NULL || label == NULL) + ret = BAD_FUNC_ARG; + if (ret == 0) { + labelLen = (int)XSTRLEN(label); + if (labelLen == 0 || labelLen > LMS_MAX_LABEL_LEN) + ret = BUFFER_E; + } + if (ret == 0) + ret = wc_LmsKey_Init(key, heap, devId); + if (ret == 0) { + XMEMCPY(key->label, label, (size_t)labelLen); + key->labelLen = labelLen; + } + + return ret; +} +#endif /* WOLF_PRIVATE_KEY_ID */ + /* Get the string representation of the LMS parameter set. * * @param [in] lmsParm LMS parameter set identifier. @@ -923,8 +994,10 @@ int wc_LmsKey_SetContext(LmsKey* key, void* context) { int ret = 0; - /* Validate parameters. */ - if ((key == NULL) || (context == NULL)) { + /* Validate parameters. NULL context is allowed: callers with stub + * read/write callbacks (e.g. HSM-backed keys whose private state lives + * in the device) have no meaningful context to pass. */ + if (key == NULL) { ret = BAD_FUNC_ARG; } /* Setting context of an already working key is forbidden. */ @@ -969,17 +1042,31 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng) WOLFSSL_MSG("error: LmsKey not ready for generation"); ret = BAD_STATE_E; } + +#ifdef WOLF_CRYPTO_CB + /* HSM-backed keys skip the software write/context callbacks because the + * device owns the private state. On CRYPTOCB_UNAVAILABLE fall-through the + * software checks below still run. */ + if ((ret == 0) && (key->devId != INVALID_DEVID)) { + ret = wc_CryptoCb_PqcStatefulSigKeyGen(WC_PQC_STATEFUL_SIG_TYPE_LMS, + key, rng); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + /* On success, mirror the software path's terminal state so + * subsequent Sign/Verify calls don't fail with BAD_STATE_E. */ + if (ret == 0) { + key->state = WC_LMS_STATE_OK; + } + return ret; + } + ret = 0; /* fall through to software path */ + } +#endif + /* Check write callback set. */ if ((ret == 0) && (key->write_private_key == NULL)) { WOLFSSL_MSG("error: LmsKey write callback is not set"); ret = BAD_FUNC_ARG; } - /* Check callback context set. */ - if ((ret == 0) && (key->context == NULL)) { - WOLFSSL_MSG("error: LmsKey context is not set"); - ret = BAD_FUNC_ARG; - } - if (ret == 0) { const LmsParams* params = key->params; priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height, @@ -1077,16 +1164,21 @@ int wc_LmsKey_Reload(LmsKey* key) WOLFSSL_MSG("error: LmsKey not ready for reload"); ret = BAD_STATE_E; } + +#ifdef WOLF_CRYPTO_CB + /* State for HSM-backed keys lives in the device; no software reload. */ + if ((ret == 0) && (key->devId != INVALID_DEVID)) { + WOLFSSL_MSG("wc_LmsKey_Reload is a no-op for HSM-backed keys"); + key->state = WC_LMS_STATE_OK; + return 0; + } +#endif + /* Check read callback present. */ if ((ret == 0) && (key->read_private_key == NULL)) { WOLFSSL_MSG("error: LmsKey read callback is not set"); ret = BAD_FUNC_ARG; } - /* Check context for callback set */ - if ((ret == 0) && (key->context == NULL)) { - WOLFSSL_MSG("error: LmsKey context is not set"); - ret = BAD_FUNC_ARG; - } if (ret == 0) { const LmsParams* params = key->params; @@ -1236,16 +1328,25 @@ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg, WOLFSSL_MSG("error: LMS sig buffer too small"); ret = BUFFER_E; } + +#ifdef WOLF_CRYPTO_CB + /* HSM-backed keys skip the software write/context callbacks because the + * device owns the private state. On CRYPTOCB_UNAVAILABLE fall-through the + * software checks below still run. */ + if ((ret == 0) && (key->devId != INVALID_DEVID)) { + ret = wc_CryptoCb_PqcStatefulSigSign(msg, (word32)msgSz, sig, sigSz, + WC_PQC_STATEFUL_SIG_TYPE_LMS, key); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + ret = 0; /* fall through to software path */ + } +#endif + /* Check read and write callbacks available. */ if ((ret == 0) && (key->write_private_key == NULL)) { WOLFSSL_MSG("error: LmsKey write/read callbacks are not set"); ret = BAD_FUNC_ARG; } - /* Check read/write callback context available. */ - if ((ret == 0) && (key->context == NULL)) { - WOLFSSL_MSG("error: LmsKey context is not set"); - ret = BAD_FUNC_ARG; - } if (ret == 0) { WC_DECLARE_VAR(state, LmsState, 1, 0); @@ -1313,6 +1414,25 @@ int wc_LmsKey_SigsLeft(LmsKey* key) /* NULL keys have no signatures remaining. */ if (key != NULL) { +#ifdef WOLF_CRYPTO_CB + if (key->devId != INVALID_DEVID) { + word32 sigsLeft = 0; + int cbRet = wc_CryptoCb_PqcStatefulSigSigsLeft( + WC_PQC_STATEFUL_SIG_TYPE_LMS, key, &sigsLeft); + if (cbRet == 0) { + return (sigsLeft != 0) ? 1 : 0; + } + /* The device owns the private state; no safe software fallback + * exists because key->priv_raw does not reflect HSM state. */ + if (cbRet != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + WOLFSSL_MSG("PqcStatefulSigSigsLeft returned an error"); + } + else { + WOLFSSL_MSG("LMS SigsLeft not supported by device"); + } + return 0; + } +#endif ret = wc_hss_sigsleft(key->params, key->priv_raw); } @@ -1345,22 +1465,27 @@ int wc_LmsKey_GetPubLen(const LmsKey* key, word32* len) } /* Export a generated public key and parameter set from one LmsKey - * to another. Use this to prepare a signature verification LmsKey - * that is pub only. + * to another, with explicit heap and device bindings. * - * Though the public key is all that is used to verify signatures, - * the parameter set is needed to calculate the signature length - * before hand. + * The destination is fully (re)initialized as a verify-only key; + * any prior state on keyDst is discarded. * * @param [out] keyDst LMS key to copy into. * @param [in] keySrc LMS key to copy. + * @param [in] heap Heap hint for keyDst. + * @param [in] devId Device identifier for keyDst. + * Use INVALID_DEVID when not using a device. * @return 0 on success. * @return BAD_FUNC_ARG when keyDst or keySrc is NULL. */ -int wc_LmsKey_ExportPub(LmsKey* keyDst, const LmsKey* keySrc) +int wc_LmsKey_ExportPub_ex(LmsKey* keyDst, const LmsKey* keySrc, + void* heap, int devId) { int ret = 0; + (void)heap; + (void)devId; + if ((keyDst == NULL) || (keySrc == NULL)) { ret = BAD_FUNC_ARG; } @@ -1371,6 +1496,13 @@ int wc_LmsKey_ExportPub(LmsKey* keyDst, const LmsKey* keySrc) keyDst->params = keySrc->params; XMEMCPY(keyDst->pub, keySrc->pub, sizeof(keySrc->pub)); + #ifndef WOLFSSL_LMS_VERIFY_ONLY + keyDst->heap = heap; + #endif + #ifdef WOLF_CRYPTO_CB + keyDst->devId = devId; + #endif + /* Mark this key as verify only, to prevent misuse. */ keyDst->state = WC_LMS_STATE_VERIFYONLY; } @@ -1378,6 +1510,34 @@ int wc_LmsKey_ExportPub(LmsKey* keyDst, const LmsKey* keySrc) return ret; } +/* Export a generated public key and parameter set from one LmsKey + * to another. Use this to prepare a signature verification LmsKey + * that is pub only. + * + * Though the public key is all that is used to verify signatures, + * the parameter set is needed to calculate the signature length + * before hand. + * + * The destination key is left with no heap hint and no device + * binding. Callers that need either should use + * wc_LmsKey_ExportPub_ex. + * + * @param [out] keyDst LMS key to copy into. + * @param [in] keySrc LMS key to copy. + * @return 0 on success. + * @return BAD_FUNC_ARG when keyDst or keySrc is NULL. + */ +int wc_LmsKey_ExportPub(LmsKey* keyDst, const LmsKey* keySrc) +{ + return wc_LmsKey_ExportPub_ex(keyDst, keySrc, + #ifndef WOLFSSL_LMS_VERIFY_ONLY + (keySrc != NULL) ? keySrc->heap : NULL, + #else + NULL, + #endif + INVALID_DEVID); +} + /* Exports the raw LMS public key buffer from key to out buffer. * The out buffer should be large enough to hold the public key, and * outLen should indicate the size of the buffer. @@ -1518,6 +1678,20 @@ int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz, ret = BUFFER_E; } +#ifdef WOLF_CRYPTO_CB + if ((ret == 0) && (key->devId != INVALID_DEVID)) { + int res = 0; + ret = wc_CryptoCb_PqcStatefulSigVerify(sig, sigSz, msg, (word32)msgSz, + &res, WC_PQC_STATEFUL_SIG_TYPE_LMS, key); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + if (ret == 0 && res != 1) + ret = SIG_VERIFY_E; + return ret; + } + ret = 0; /* fall through to software path */ + } +#endif + if (ret == 0) { WC_DECLARE_VAR(state, LmsState, 1, 0); @@ -1562,6 +1736,16 @@ int wc_LmsKey_GetKid(LmsKey * key, const byte ** kid, word32* kidSz) return BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + /* priv_raw is not populated for HSM-backed keys where the device owns + * the private state; the returned KID will be zero bytes. Extend the + * CryptoCb surface if device-side KID retrieval becomes a requirement. */ + if (key->devId != INVALID_DEVID) { + WOLFSSL_MSG( + "wc_LmsKey_GetKid: priv_raw may be uninitialised for HSM keys"); + } +#endif + /* SEED length is hash length. */ offset = HSS_Q_LEN + HSS_PRIV_KEY_PARAM_SET_LEN + key->params->hash_len; *kid = key->priv_raw + offset; diff --git a/wolfcrypt/src/wc_xmss.c b/wolfcrypt/src/wc_xmss.c index f48922897f..b236e6ad89 100644 --- a/wolfcrypt/src/wc_xmss.c +++ b/wolfcrypt/src/wc_xmss.c @@ -28,6 +28,7 @@ #define FIPS_NO_WRAPPERS #endif #include +#include #ifdef NO_INLINE #include @@ -36,6 +37,9 @@ #include #endif +#ifdef WOLF_CRYPTO_CB + #include +#endif /*************************** * DIGEST init and free. @@ -812,7 +816,7 @@ static WC_INLINE int wc_xmsskey_signupdate(XmssKey* key, byte* sig, * * @param [in] key The XMSS key to init. * @param [in] heap Dynamic memory hint used by subsequent allocations. - * @param [in] devId Unused. + * @param [in] devId Device identifier (used with WOLF_CRYPTO_CB). * * @return 0 on success. * @return BAD_FUNC_ARG when a parameter is NULL. @@ -821,7 +825,9 @@ int wc_XmssKey_Init(XmssKey* key, void* heap, int devId) { int ret = 0; +#ifndef WOLF_CRYPTO_CB (void) devId; +#endif /* Validate parameters. */ if (key == NULL) { @@ -832,12 +838,82 @@ int wc_XmssKey_Init(XmssKey* key, void* heap, int devId) /* Zeroize key and set state to initialized. */ ForceZero(key, sizeof(XmssKey)); key->heap = heap; + #ifdef WOLF_CRYPTO_CB + key->devId = devId; + #endif key->state = WC_XMSS_STATE_INITED; } return ret; } +#ifdef WOLF_PRIVATE_KEY_ID +/* Initialize an XmssKey and bind it to a device-side key identifier. + * + * @param [in,out] key XmssKey to initialize. + * @param [in] id Identifier bytes (may be NULL when len is 0). + * @param [in] len Length of id; must be in [0, XMSS_MAX_ID_LEN]. + * @param [in] heap Heap hint forwarded to wc_XmssKey_Init. + * @param [in] devId Device identifier. + * + * @return 0 on success. + * @return BAD_FUNC_ARG when key is NULL. + * @return BUFFER_E when len is negative or exceeds XMSS_MAX_ID_LEN. + */ +int wc_XmssKey_InitId(XmssKey* key, const unsigned char* id, int len, + void* heap, int devId) +{ + int ret = 0; + + if (key == NULL) + ret = BAD_FUNC_ARG; + if (ret == 0 && (len < 0 || len > XMSS_MAX_ID_LEN)) + ret = BUFFER_E; + if (ret == 0) + ret = wc_XmssKey_Init(key, heap, devId); + if (ret == 0 && id != NULL && len != 0) { + XMEMCPY(key->id, id, (size_t)len); + key->idLen = len; + } + + return ret; +} + +/* Initialize an XmssKey and bind it to a device-side key label. + * + * @param [in,out] key XmssKey to initialize. + * @param [in] label NUL-terminated label string (must be non-empty). + * @param [in] heap Heap hint forwarded to wc_XmssKey_Init. + * @param [in] devId Device identifier. + * + * @return 0 on success. + * @return BAD_FUNC_ARG when key or label is NULL. + * @return BUFFER_E when label is empty or longer than XMSS_MAX_LABEL_LEN. + */ +int wc_XmssKey_InitLabel(XmssKey* key, const char* label, void* heap, + int devId) +{ + int ret = 0; + int labelLen = 0; + + if (key == NULL || label == NULL) + ret = BAD_FUNC_ARG; + if (ret == 0) { + labelLen = (int)XSTRLEN(label); + if (labelLen == 0 || labelLen > XMSS_MAX_LABEL_LEN) + ret = BUFFER_E; + } + if (ret == 0) + ret = wc_XmssKey_Init(key, heap, devId); + if (ret == 0) { + XMEMCPY(key->label, label, (size_t)labelLen); + key->labelLen = labelLen; + } + + return ret; +} +#endif /* WOLF_PRIVATE_KEY_ID */ + /* Set the XMSS key parameter string. * * The input string must be one of the supported parm set names in @@ -897,6 +973,62 @@ int wc_XmssKey_SetParamStr(XmssKey* key, const char* str) return ret; } +/* Get the XMSS key parameter string for a key whose params have been set. + * + * Performs a reverse lookup from key->oid (and key->is_xmssmt) into the + * supported algorithm tables and returns a pointer to the static parameter + * string (e.g. "XMSS-SHA2_10_256" or "XMSSMT-SHA2_20/4_256"). The returned + * pointer remains valid for the lifetime of the program. + * + * @param [in] key XMSS key with params set via wc_XmssKey_SetParamStr. + * @param [out] str On success, set to the algorithm name. + * + * @return 0 on success. + * @return BAD_FUNC_ARG when a parameter is NULL. + * @return BAD_STATE_E when params have not been set. + * @return NOT_COMPILED_IN when the OID is not in the supported tables. + */ +int wc_XmssKey_GetParamStr(const XmssKey* key, const char** str) +{ + int ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); + unsigned int i; + + if ((key == NULL) || (str == NULL)) { + return BAD_FUNC_ARG; + } + if (key->state != WC_XMSS_STATE_PARMSET && + key->state != WC_XMSS_STATE_OK && + key->state != WC_XMSS_STATE_VERIFYONLY && + key->state != WC_XMSS_STATE_NOSIGS) { + return BAD_STATE_E; + } + + if (key->is_xmssmt) { +#if WOLFSSL_XMSS_MAX_HEIGHT >= 20 + for (i = 0; i < WC_XMSSMT_ALG_LEN; i++) { + if (wc_xmssmt_alg[i].oid == key->oid) { + *str = wc_xmssmt_alg[i].str; + ret = 0; + break; + } + } +#endif + } + else { +#if WOLFSSL_XMSS_MIN_HEIGHT <= 20 + for (i = 0; i < WC_XMSS_ALG_LEN; i++) { + if (wc_xmss_alg[i].oid == key->oid) { + *str = wc_xmss_alg[i].str; + ret = 0; + break; + } + } +#endif + } + + return ret; +} + /* Force zeros and frees the XMSS key from memory. * * This does not touch the private key saved to non-volatile storage. @@ -1009,8 +1141,10 @@ int wc_XmssKey_SetContext(XmssKey* key, void* context) { int ret = 0; - /* Validate parameters. */ - if ((key == NULL) || (context == NULL)) { + /* Validate parameters. NULL context is allowed: callers with stub + * read/write callbacks (e.g. HSM-backed keys whose private state lives + * in the device) have no meaningful context to pass. */ + if (key == NULL) { ret = BAD_FUNC_ARG; } /* Setting context of an already working key is forbidden. */ @@ -1068,17 +1202,30 @@ int wc_XmssKey_MakeKey(XmssKey* key, WC_RNG* rng) WOLFSSL_MSG("error: XmssKey not ready for generation"); ret = BAD_STATE_E; } +#ifdef WOLF_CRYPTO_CB + /* HSM-backed keys skip the software write/context callbacks because the + * device owns the private state. On CRYPTOCB_UNAVAILABLE fall-through the + * software checks below still run. */ + if ((ret == 0) && (key->devId != INVALID_DEVID)) { + ret = wc_CryptoCb_PqcStatefulSigKeyGen(WC_PQC_STATEFUL_SIG_TYPE_XMSS, + key, rng); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + /* On success, mirror the software path's terminal state so + * subsequent Sign/Verify calls don't fail with BAD_STATE_E. */ + if (ret == 0) { + key->state = WC_XMSS_STATE_OK; + } + return ret; + } + ret = 0; /* fall through to software path */ + } +#endif + /* Ensure write callback available. */ if ((ret == 0) && (key->write_private_key == NULL)) { WOLFSSL_MSG("error: XmssKey write callback is not set"); ret = BAD_FUNC_ARG; } - /* Ensure read/write callback context available. */ - if ((ret == 0) && (key->context == NULL)) { - WOLFSSL_MSG("error: XmssKey context is not set"); - ret = BAD_FUNC_ARG; - } - if (ret == 0) { /* Allocate sk array. */ ret = wc_xmsskey_alloc_sk(key); @@ -1193,17 +1340,22 @@ int wc_XmssKey_Reload(XmssKey* key) WOLFSSL_MSG("error: XmssKey not ready for reload"); ret = BAD_STATE_E; } + +#ifdef WOLF_CRYPTO_CB + /* State for HSM-backed keys lives in the device; no software reload. */ + if ((ret == 0) && (key->devId != INVALID_DEVID)) { + WOLFSSL_MSG("wc_XmssKey_Reload is a no-op for HSM-backed keys"); + key->state = WC_XMSS_STATE_OK; + return 0; + } +#endif + /* Ensure read and write callbacks are available. */ if ((ret == 0) && ((key->write_private_key == NULL) || (key->read_private_key == NULL))) { WOLFSSL_MSG("error: XmssKey write/read callbacks are not set"); ret = BAD_FUNC_ARG; } - /* Ensure read and write callback context is available. */ - if ((ret == 0) && (key->context == NULL)) { - WOLFSSL_MSG("error: XmssKey context is not set"); - ret = BAD_FUNC_ARG; - } if (ret == 0) { /* Allocate sk array. */ @@ -1315,17 +1467,26 @@ int wc_XmssKey_Sign(XmssKey* key, byte* sig, word32* sigLen, const byte* msg, WOLFSSL_MSG("error: XMSS sig buffer too small"); ret = BUFFER_E; } + +#ifdef WOLF_CRYPTO_CB + /* HSM-backed keys skip the software write/context callbacks because the + * device owns the private state. On CRYPTOCB_UNAVAILABLE fall-through the + * software checks below still run. */ + if ((ret == 0) && (key->devId != INVALID_DEVID)) { + ret = wc_CryptoCb_PqcStatefulSigSign(msg, (word32)msgLen, sig, sigLen, + WC_PQC_STATEFUL_SIG_TYPE_XMSS, key); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + ret = 0; /* fall through to software path */ + } +#endif + /* Check read and write callbacks available. */ if ((ret == 0) && ((key->write_private_key == NULL) || (key->read_private_key == NULL))) { WOLFSSL_MSG("error: XmssKey write/read callbacks are not set"); ret = BAD_FUNC_ARG; } - /* Check read/write callback context available. */ - if ((ret == 0) && (key->context == NULL)) { - WOLFSSL_MSG("error: XmssKey context is not set"); - ret = BAD_FUNC_ARG; - } if (ret == 0) { *sigLen = key->params->sig_len; @@ -1344,14 +1505,34 @@ int wc_XmssKey_Sign(XmssKey* key, byte* sig, word32* sigLen, const byte* msg, */ int wc_XmssKey_SigsLeft(XmssKey* key) { - int ret; + int ret = 0; /* Validate parameter. */ - if (key == NULL) { - ret = 0; + if (key == NULL) + return 0; + +#ifdef WOLF_CRYPTO_CB + if (key->devId != INVALID_DEVID) { + word32 sigsLeft = 0; + int cbRet = wc_CryptoCb_PqcStatefulSigSigsLeft( + WC_PQC_STATEFUL_SIG_TYPE_XMSS, key, &sigsLeft); + if (cbRet == 0) { + return (sigsLeft != 0) ? 1 : 0; + } + /* The device owns the private state; no safe software fallback + * exists because key->sk does not reflect HSM state. */ + if (cbRet != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + WOLFSSL_MSG("PqcStatefulSigSigsLeft returned an error"); + } + else { + WOLFSSL_MSG("XMSS SigsLeft not supported by device"); + } + return 0; } +#endif + /* Validate state. */ - else if (key->state == WC_XMSS_STATE_NOSIGS) { + if (key->state == WC_XMSS_STATE_NOSIGS) { WOLFSSL_MSG("error: XMSS signatures exhausted"); ret = 0; } @@ -1412,10 +1593,15 @@ int wc_XmssKey_GetPubLen(const XmssKey* key, word32* len) * @return BAD_FUNC_ARG when a key is NULL. * @return Other negative when digest algorithm initialization failed. */ -int wc_XmssKey_ExportPub(XmssKey* keyDst, const XmssKey* keySrc) +int wc_XmssKey_ExportPub_ex(XmssKey* keyDst, const XmssKey* keySrc, + void* heap, int devId) { int ret = 0; +#ifndef WOLF_CRYPTO_CB + (void)devId; +#endif + /* Validate parameters. */ if ((keyDst == NULL) || (keySrc == NULL)) { ret = BAD_FUNC_ARG; @@ -1432,14 +1618,23 @@ int wc_XmssKey_ExportPub(XmssKey* keyDst, const XmssKey* keySrc) keyDst->oid = keySrc->oid; keyDst->is_xmssmt = keySrc->is_xmssmt; keyDst->params = keySrc->params; - keyDst->heap = keySrc->heap; - } - if (ret == 0) { + keyDst->heap = heap; + + #ifdef WOLF_CRYPTO_CB + keyDst->devId = devId; + #endif + /* Mark keyDst as verify only, to prevent misuse. */ keyDst->state = WC_XMSS_STATE_VERIFYONLY; } - return 0; + return ret; +} + +int wc_XmssKey_ExportPub(XmssKey* keyDst, const XmssKey* keySrc) +{ + return wc_XmssKey_ExportPub_ex(keyDst, keySrc, + (keySrc != NULL) ? keySrc->heap : NULL, INVALID_DEVID); } /* Exports the raw XMSS public key buffer from key to out buffer. @@ -1603,7 +1798,7 @@ int wc_XmssKey_GetSigLen(const XmssKey* key, word32* len) int wc_XmssKey_Verify(XmssKey* key, const byte* sig, word32 sigLen, const byte* m, int mLen) { - int ret = 0; + int ret = 0; /* Validate parameters. */ if ((key == NULL) || (sig == NULL) || (m == NULL)) { @@ -1623,6 +1818,20 @@ int wc_XmssKey_Verify(XmssKey* key, const byte* sig, word32 sigLen, ret = BUFFER_E; } +#ifdef WOLF_CRYPTO_CB + if ((ret == 0) && (key->devId != INVALID_DEVID)) { + int res = 0; + ret = wc_CryptoCb_PqcStatefulSigVerify(sig, sigLen, m, (word32)mLen, + &res, WC_PQC_STATEFUL_SIG_TYPE_XMSS, key); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + if (ret == 0 && res != 1) + ret = SIG_VERIFY_E; + return ret; + } + ret = 0; /* fall through to software path */ + } +#endif + if (ret == 0) { WC_DECLARE_VAR(state, XmssState, 1, 0); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 64f1afb0a2..d9a536ada1 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -52993,7 +52993,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void) if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } /* Export the pub to a verify key. */ - ret = wc_XmssKey_ExportPub(&verifyKey, &signingKey); + ret = wc_XmssKey_ExportPub_ex(&verifyKey, &signingKey, NULL, devId); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } /* Repeat a few times to check that: @@ -53666,7 +53666,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void) ERROR_OUT(WC_TEST_RET_ENC_I(kidSz), out); } - ret = wc_LmsKey_ExportPub(&verifyKey, &signingKey); + ret = wc_LmsKey_ExportPub_ex(&verifyKey, &signingKey, NULL, devId); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } ret = wc_LmsKey_GetSigLen(&verifyKey, &sigSz); @@ -53681,7 +53681,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void) { word32 smallSz = 1; wc_lms_write_private_key_cb saved_write_cb; - void* saved_ctx; /* Undersized sig buffer should return BUFFER_E. */ ret = wc_LmsKey_Sign(&signingKey, sig, &smallSz, (byte *) msg, msgSz); @@ -53698,15 +53697,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } - /* NULL context should return BAD_FUNC_ARG. */ - saved_ctx = signingKey.context; - signingKey.context = NULL; - ret = wc_LmsKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz); - signingKey.context = saved_ctx; - if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { - ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); - } - ret = 0; } @@ -68583,6 +68573,117 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) } #endif #endif /* HAVE_ED25519 */ + #if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) + if (info->pk.type == WC_PK_TYPE_PQC_STATEFUL_SIG_KEYGEN) { + int pqcType = info->pk.pqc_stateful_sig_kg.type; + (void)pqcType; + #if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + if (pqcType == WC_PQC_STATEFUL_SIG_TYPE_LMS) { + LmsKey* lk = (LmsKey*)info->pk.pqc_stateful_sig_kg.key; + lk->devId = INVALID_DEVID; + ret = wc_LmsKey_MakeKey(lk, info->pk.pqc_stateful_sig_kg.rng); + lk->devId = devIdArg; + } + #endif + #if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + if (pqcType == WC_PQC_STATEFUL_SIG_TYPE_XMSS) { + XmssKey* xk = (XmssKey*)info->pk.pqc_stateful_sig_kg.key; + xk->devId = INVALID_DEVID; + ret = wc_XmssKey_MakeKey(xk, info->pk.pqc_stateful_sig_kg.rng); + xk->devId = devIdArg; + } + #endif + } + else if (info->pk.type == WC_PK_TYPE_PQC_STATEFUL_SIG_SIGN) { + int pqcType = info->pk.pqc_stateful_sig_sign.type; + word32 sigSz = *info->pk.pqc_stateful_sig_sign.outSz; + (void)pqcType; + #if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + if (pqcType == WC_PQC_STATEFUL_SIG_TYPE_LMS) { + LmsKey* lk = (LmsKey*)info->pk.pqc_stateful_sig_sign.key; + lk->devId = INVALID_DEVID; + ret = wc_LmsKey_Sign(lk, + info->pk.pqc_stateful_sig_sign.out, &sigSz, + info->pk.pqc_stateful_sig_sign.msg, + (int)info->pk.pqc_stateful_sig_sign.msgSz); + lk->devId = devIdArg; + } + #endif + #if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + if (pqcType == WC_PQC_STATEFUL_SIG_TYPE_XMSS) { + XmssKey* xk = (XmssKey*)info->pk.pqc_stateful_sig_sign.key; + xk->devId = INVALID_DEVID; + ret = wc_XmssKey_Sign(xk, + info->pk.pqc_stateful_sig_sign.out, &sigSz, + info->pk.pqc_stateful_sig_sign.msg, + (int)info->pk.pqc_stateful_sig_sign.msgSz); + xk->devId = devIdArg; + } + #endif + *info->pk.pqc_stateful_sig_sign.outSz = sigSz; + } + else if (info->pk.type == WC_PK_TYPE_PQC_STATEFUL_SIG_VERIFY) { + int pqcType = info->pk.pqc_stateful_sig_verify.type; + int verifyRet = WC_NO_ERR_TRACE(NOT_COMPILED_IN); + #if defined(WOLFSSL_HAVE_LMS) + if (pqcType == WC_PQC_STATEFUL_SIG_TYPE_LMS) { + LmsKey* lk = (LmsKey*)info->pk.pqc_stateful_sig_verify.key; + lk->devId = INVALID_DEVID; + verifyRet = wc_LmsKey_Verify(lk, + info->pk.pqc_stateful_sig_verify.sig, + info->pk.pqc_stateful_sig_verify.sigSz, + info->pk.pqc_stateful_sig_verify.msg, + (int)info->pk.pqc_stateful_sig_verify.msgSz); + lk->devId = devIdArg; + } + #endif + #if defined(WOLFSSL_HAVE_XMSS) + if (pqcType == WC_PQC_STATEFUL_SIG_TYPE_XMSS) { + XmssKey* xk = (XmssKey*)info->pk.pqc_stateful_sig_verify.key; + xk->devId = INVALID_DEVID; + verifyRet = wc_XmssKey_Verify(xk, + info->pk.pqc_stateful_sig_verify.sig, + info->pk.pqc_stateful_sig_verify.sigSz, + info->pk.pqc_stateful_sig_verify.msg, + (int)info->pk.pqc_stateful_sig_verify.msgSz); + xk->devId = devIdArg; + } + #endif + if (info->pk.pqc_stateful_sig_verify.res != NULL) { + *info->pk.pqc_stateful_sig_verify.res = + (verifyRet == 0) ? 1 : 0; + } + /* SIG_VERIFY_E is a validity signal, not a crypto error, so + * translate it back to success for the dispatcher. */ + if (verifyRet == WC_NO_ERR_TRACE(SIG_VERIFY_E)) + verifyRet = 0; + ret = verifyRet; + } + else if (info->pk.type == WC_PK_TYPE_PQC_STATEFUL_SIG_SIGS_LEFT) { + int pqcType = info->pk.pqc_stateful_sig_sigs_left.type; + int count = 0; + (void)pqcType; + #if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + if (pqcType == WC_PQC_STATEFUL_SIG_TYPE_LMS) { + LmsKey* lk = (LmsKey*)info->pk.pqc_stateful_sig_sigs_left.key; + lk->devId = INVALID_DEVID; + count = wc_LmsKey_SigsLeft(lk); + lk->devId = devIdArg; + } + #endif + #if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + if (pqcType == WC_PQC_STATEFUL_SIG_TYPE_XMSS) { + XmssKey* xk = (XmssKey*)info->pk.pqc_stateful_sig_sigs_left.key; + xk->devId = INVALID_DEVID; + count = wc_XmssKey_SigsLeft(xk); + xk->devId = devIdArg; + } + #endif + if (info->pk.pqc_stateful_sig_sigs_left.sigsLeft != NULL) + *info->pk.pqc_stateful_sig_sigs_left.sigsLeft = (word32)count; + ret = 0; + } + #endif /* WOLFSSL_HAVE_LMS || WOLFSSL_HAVE_XMSS */ #ifdef WOLFSSL_HAVE_MLKEM if (info->pk.type == WC_PK_TYPE_PQC_KEM_KEYGEN) { if ((info->pk.pqc_kem_kg.type == WC_PQC_KEM_TYPE_KYBER) && @@ -70016,6 +70117,14 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) if (ret == 0) ret = dilithium_test(); #endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + if (ret == 0) + ret = xmss_test(); +#endif +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + if (ret == 0) + ret = lms_test(); +#endif #ifdef HAVE_ED25519 PRIVATE_KEY_UNLOCK(); if (ret == 0) diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index a9fb827e59..eee9e23182 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -86,6 +86,12 @@ #if defined(HAVE_FALCON) #include #endif +#if defined(WOLFSSL_HAVE_LMS) + #include +#endif +#if defined(WOLFSSL_HAVE_XMSS) + #include +#endif #ifdef WOLF_CRYPTO_CB_CMD @@ -344,6 +350,35 @@ typedef struct wc_CryptoInfo { int type; /* enum wc_PqcSignatureType */ } pqc_sig_check; #endif + #if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) + struct { + WC_RNG* rng; + void* key; + int type; /* enum wc_PqcStatefulSignatureType */ + } pqc_stateful_sig_kg; + struct { + const byte* msg; + word32 msgSz; + byte* out; + word32* outSz; + void* key; + int type; /* enum wc_PqcStatefulSignatureType */ + } pqc_stateful_sig_sign; + struct { + const byte* sig; + word32 sigSz; + const byte* msg; + word32 msgSz; + int* res; + void* key; + int type; /* enum wc_PqcStatefulSignatureType */ + } pqc_stateful_sig_verify; + struct { + void* key; + word32* sigsLeft; + int type; /* enum wc_PqcStatefulSignatureType */ + } pqc_stateful_sig_sigs_left; + #endif #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES }; #endif @@ -711,6 +746,20 @@ WOLFSSL_LOCAL int wc_CryptoCb_Ed25519Verify(const byte* sig, word32 sigLen, const byte* context, byte contextLen); #endif /* HAVE_ED25519 */ +#if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) +WOLFSSL_LOCAL int wc_CryptoCb_PqcStatefulSigGetDevId(int type, void* key); + +WOLFSSL_LOCAL int wc_CryptoCb_PqcStatefulSigKeyGen(int type, void* key, + WC_RNG* rng); +WOLFSSL_LOCAL int wc_CryptoCb_PqcStatefulSigSign(const byte* msg, + word32 msgSz, byte* out, word32* outSz, int type, void* key); +WOLFSSL_LOCAL int wc_CryptoCb_PqcStatefulSigVerify(const byte* sig, + word32 sigSz, const byte* msg, word32 msgSz, int* res, int type, + void* key); +WOLFSSL_LOCAL int wc_CryptoCb_PqcStatefulSigSigsLeft(int type, void* key, + word32* sigsLeft); +#endif /* WOLFSSL_HAVE_LMS || WOLFSSL_HAVE_XMSS */ + #if defined(WOLFSSL_HAVE_MLKEM) WOLFSSL_LOCAL int wc_CryptoCb_PqcKemGetDevId(int type, void* key); diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 01e71a3ebb..894ce4607b 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1573,6 +1573,14 @@ enum wc_PkType { WC_PK_TYPE_EC_GET_SIG_SIZE = 29, #undef _WC_PK_TYPE_MAX #define _WC_PK_TYPE_MAX WC_PK_TYPE_EC_GET_SIG_SIZE +#if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) + WC_PK_TYPE_PQC_STATEFUL_SIG_KEYGEN = 30, + WC_PK_TYPE_PQC_STATEFUL_SIG_SIGN = 31, + WC_PK_TYPE_PQC_STATEFUL_SIG_VERIFY = 32, + WC_PK_TYPE_PQC_STATEFUL_SIG_SIGS_LEFT = 33, + #undef _WC_PK_TYPE_MAX + #define _WC_PK_TYPE_MAX WC_PK_TYPE_PQC_STATEFUL_SIG_SIGS_LEFT +#endif WC_PK_TYPE_MAX = _WC_PK_TYPE_MAX }; @@ -1607,6 +1615,25 @@ enum wc_PkType { }; #endif +#if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) + /* Post quantum stateful hash-based signature algorithms. */ + enum wc_PqcStatefulSignatureType { + WC_PQC_STATEFUL_SIG_TYPE_NONE = 0, + #define _WC_PQC_STATEFUL_SIG_TYPE_MAX WC_PQC_STATEFUL_SIG_TYPE_NONE + #if defined(WOLFSSL_HAVE_LMS) + WC_PQC_STATEFUL_SIG_TYPE_LMS = 1, + #undef _WC_PQC_STATEFUL_SIG_TYPE_MAX + #define _WC_PQC_STATEFUL_SIG_TYPE_MAX WC_PQC_STATEFUL_SIG_TYPE_LMS + #endif + #if defined(WOLFSSL_HAVE_XMSS) + WC_PQC_STATEFUL_SIG_TYPE_XMSS = 2, + #undef _WC_PQC_STATEFUL_SIG_TYPE_MAX + #define _WC_PQC_STATEFUL_SIG_TYPE_MAX WC_PQC_STATEFUL_SIG_TYPE_XMSS + #endif + WC_PQC_STATEFUL_SIG_TYPE_MAX = _WC_PQC_STATEFUL_SIG_TYPE_MAX + }; +#endif + /* settings detection for compile vs runtime math incompatibilities */ enum { diff --git a/wolfssl/wolfcrypt/wc_lms.h b/wolfssl/wolfcrypt/wc_lms.h index e12d99431e..cc58dea204 100644 --- a/wolfssl/wolfcrypt/wc_lms.h +++ b/wolfssl/wolfcrypt/wc_lms.h @@ -736,6 +736,13 @@ typedef struct HssPrivKey { #endif } HssPrivKey; +#ifndef LMS_MAX_ID_LEN +#define LMS_MAX_ID_LEN 32 +#endif +#ifndef LMS_MAX_LABEL_LEN +#define LMS_MAX_LABEL_LEN 32 +#endif + typedef struct LmsKey { /* Public key. */ ALIGN16 byte pub[HSS_PUBLIC_KEY_LEN(LMS_MAX_NODE_LEN)]; @@ -764,6 +771,16 @@ typedef struct LmsKey { #ifdef WOLF_CRYPTO_CB /* Device Identifier. */ int devId; + /* Per-device opaque context, populated by the callback. */ + void* devCtx; +#endif +#ifdef WOLF_PRIVATE_KEY_ID + /* Optional device-side key identifier. */ + byte id[LMS_MAX_ID_LEN]; + int idLen; + /* Optional device-side key label. */ + char label[LMS_MAX_LABEL_LEN]; + int labelLen; #endif } LmsKey; @@ -772,6 +789,12 @@ typedef struct LmsKey { #endif WOLFSSL_API int wc_LmsKey_Init(LmsKey * key, void * heap, int devId); +#ifdef WOLF_PRIVATE_KEY_ID +WOLFSSL_API int wc_LmsKey_InitId(LmsKey * key, const unsigned char * id, + int len, void * heap, int devId); +WOLFSSL_API int wc_LmsKey_InitLabel(LmsKey * key, const char * label, + void * heap, int devId); +#endif WOLFSSL_API int wc_LmsKey_SetLmsParm(LmsKey * key, enum wc_LmsParm lmsParm); WOLFSSL_API int wc_LmsKey_SetParameters(LmsKey * key, int levels, int height, int winternitz); @@ -794,6 +817,8 @@ WOLFSSL_API void wc_LmsKey_Free(LmsKey * key); WOLFSSL_API int wc_LmsKey_GetSigLen(const LmsKey * key, word32 * len); WOLFSSL_API int wc_LmsKey_GetPubLen(const LmsKey * key, word32 * len); WOLFSSL_API int wc_LmsKey_ExportPub(LmsKey * keyDst, const LmsKey * keySrc); +WOLFSSL_API int wc_LmsKey_ExportPub_ex(LmsKey * keyDst, const LmsKey * keySrc, + void * heap, int devId); WOLFSSL_API int wc_LmsKey_ExportPubRaw(const LmsKey * key, byte * out, word32 * outLen); WOLFSSL_API int wc_LmsKey_ImportPubRaw(LmsKey * key, const byte * in, diff --git a/wolfssl/wolfcrypt/wc_xmss.h b/wolfssl/wolfcrypt/wc_xmss.h index 5d0bba1da0..ae48161be8 100644 --- a/wolfssl/wolfcrypt/wc_xmss.h +++ b/wolfssl/wolfcrypt/wc_xmss.h @@ -337,6 +337,13 @@ typedef struct XmssParams { word8 bds_k; } XmssParams; +#ifndef XMSS_MAX_ID_LEN +#define XMSS_MAX_ID_LEN 32 +#endif +#ifndef XMSS_MAX_LABEL_LEN +#define XMSS_MAX_LABEL_LEN 32 +#endif + typedef struct XmssKey { /* Public key. */ unsigned char pk[2 * WC_XMSS_MAX_N]; @@ -362,6 +369,20 @@ typedef struct XmssKey { void* heap; /* State of key. */ enum wc_XmssState state; +#ifdef WOLF_CRYPTO_CB + /* Device Identifier. */ + int devId; + /* Per-device opaque context, populated by the callback. */ + void* devCtx; +#endif +#ifdef WOLF_PRIVATE_KEY_ID + /* Optional device-side key identifier. */ + byte id[XMSS_MAX_ID_LEN]; + int idLen; + /* Optional device-side key label. */ + char label[XMSS_MAX_LABEL_LEN]; + int labelLen; +#endif } XmssKey; typedef struct XmssState { @@ -403,7 +424,14 @@ typedef struct XmssState { #endif WOLFSSL_API int wc_XmssKey_Init(XmssKey* key, void* heap, int devId); +#ifdef WOLF_PRIVATE_KEY_ID +WOLFSSL_API int wc_XmssKey_InitId(XmssKey* key, const unsigned char* id, + int len, void* heap, int devId); +WOLFSSL_API int wc_XmssKey_InitLabel(XmssKey* key, const char* label, + void* heap, int devId); +#endif WOLFSSL_API int wc_XmssKey_SetParamStr(XmssKey* key, const char* str); +WOLFSSL_API int wc_XmssKey_GetParamStr(const XmssKey* key, const char** str); #ifndef WOLFSSL_XMSS_VERIFY_ONLY WOLFSSL_API int wc_XmssKey_SetWriteCb(XmssKey* key, wc_xmss_write_private_key_cb write_cb); @@ -421,6 +449,8 @@ WOLFSSL_API void wc_XmssKey_Free(XmssKey* key); WOLFSSL_API int wc_XmssKey_GetSigLen(const XmssKey* key, word32* len); WOLFSSL_API int wc_XmssKey_GetPubLen(const XmssKey* key, word32* len); WOLFSSL_API int wc_XmssKey_ExportPub(XmssKey* keyDst, const XmssKey* keySrc); +WOLFSSL_API int wc_XmssKey_ExportPub_ex(XmssKey* keyDst, const XmssKey* keySrc, + void* heap, int devId); WOLFSSL_API int wc_XmssKey_ExportPubRaw(const XmssKey* key, byte* out, word32* outLen); WOLFSSL_API int wc_XmssKey_ImportPubRaw(XmssKey* key, const byte* in,