diff --git a/tests/api.c b/tests/api.c index 78ec5a4c16..4b0a657f6d 100644 --- a/tests/api.c +++ b/tests/api.c @@ -37899,7 +37899,11 @@ static int test_lms_init_key(LmsKey* key, WC_RNG* rng) ret = wc_LmsKey_Init(key, NULL, INVALID_DEVID); if (ret != 0) return ret; +#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10) ret = wc_LmsKey_SetParameters(key, 1, 10, 8); +#else + ret = wc_LmsKey_SetParameters(key, 1, 5, 8); +#endif if (ret != 0) return ret; ret = wc_LmsKey_SetWriteCb(key, test_lms_write_key); @@ -37973,7 +37977,8 @@ int test_wc_LmsKey_sign_verify(void) int test_wc_LmsKey_reload_cache(void) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) && \ + (!defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10)) LmsKey key; LmsKey vkey; WC_RNG rng; @@ -38012,7 +38017,11 @@ int test_wc_LmsKey_reload_cache(void) ExpectIntEQ(wc_LmsKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)), 0); ExpectIntEQ(wc_LmsKey_Init(&vkey, NULL, INVALID_DEVID), 0); +#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10) ExpectIntEQ(wc_LmsKey_SetParameters(&vkey, 1, 10, 8), 0); +#else + ExpectIntEQ(wc_LmsKey_SetParameters(&vkey, 1, 5, 8), 0); +#endif ExpectIntEQ(wc_LmsKey_ImportPubRaw(&vkey, pub, pubSz), 0); ExpectIntEQ(wc_LmsKey_Verify(&vkey, sig, sigSz, msg, sizeof(msg)), 0); @@ -38688,9 +38697,15 @@ int test_rfc9802_lms_x509_verify(void) * or SHAKE-only builds skip this block. */ static const char* const lmsFiles[] = { "./certs/lms/bc_lms_sha256_h5_w4_root.der", +#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10) "./certs/lms/bc_lms_sha256_h10_w8_root.der", +#endif +#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 2) "./certs/lms/bc_hss_L2_H5_W8_root.der", +#endif +#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 3) "./certs/lms/bc_hss_L3_H5_W4_root.der", +#endif "./certs/lms/bc_lms_native_bc_root.der", }; size_t i; diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index fc8879c295..fb351a4571 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -11700,7 +11700,6 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub) XMEMCPY(key.pub, lms_pub_L4_H5_W8, HSS_MAX_PUBLIC_KEY_LEN); break; - case WC_LMS_PARM_NONE: case WC_LMS_PARM_L1_H15_W2: case WC_LMS_PARM_L1_H15_W4: case WC_LMS_PARM_L2_H10_W8: diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c index d97979f133..2f8a70068f 100644 --- a/wolfcrypt/src/wc_lms.c +++ b/wolfcrypt/src/wc_lms.c @@ -98,10 +98,10 @@ * @param [in] t LMS type. * @param [in] t2 LM-OTS type. */ -#define LMS_PARAMS(l, h, w, wb, t, t2, hLen) \ - { l, h, w, LMS_LS(w, wb), LMS_P(w, wb, hLen), t, t2, \ - LMS_PARAMS_SIG_LEN(l, h, LMS_P(w, wb, hLen), hLen), \ - (hLen), LMS_PARAMS_CACHE(h) } +#define LMS_PARAMS(l, h, w, wb, t, t2, hLen) \ + { l, h, w, LMS_LS(w, wb), LMS_P(w, wb, hLen), t, t2, \ + (hLen), LMS_PARAMS_SIG_LEN(l, h, LMS_P(w, wb, hLen), hLen), \ + LMS_PARAMS_CACHE(h) } /* Initialize the working state for LMS operations. @@ -165,9 +165,6 @@ static void wc_lmskey_state_free(LmsState* state) static const wc_LmsParamsMap wc_lms_map[] = { #ifndef WOLFSSL_NO_LMS_SHA256_256 #if LMS_MAX_HEIGHT >= 15 - { WC_LMS_PARM_NONE , "LMS_NONE" , - LMS_PARAMS(1, 15, 2, 1, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W2, - WC_SHA256_DIGEST_SIZE) }, { WC_LMS_PARM_L1_H15_W2, "LMS/HSS L1_H15_W2", LMS_PARAMS(1, 15, 2, 1, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W2, WC_SHA256_DIGEST_SIZE) }, @@ -607,6 +604,7 @@ static const wc_LmsParamsMap wc_lms_map[] = { /* Initialize LMS key. * * Call this before setting the params of an LMS key. + * Must call wc_LmsKey_Free before calling this function again. * * @param [out] key LMS key to initialize. * @param [in] heap Heap hint. @@ -627,14 +625,11 @@ int wc_LmsKey_Init(LmsKey* key, void* heap, int devId) ret = BAD_FUNC_ARG; } if (ret == 0) { - /* Zeroize the key data. */ - ForceZero(key, sizeof(LmsKey)); + /* Clear the key data. */ + XMEMSET(key, 0, sizeof(LmsKey)); #ifndef WOLFSSL_LMS_VERIFY_ONLY /* Initialize other fields. */ - key->write_private_key = NULL; - key->read_private_key = NULL; - key->context = NULL; key->heap = heap; #endif #ifdef WOLF_CRYPTO_CB @@ -657,7 +652,7 @@ int wc_LmsKey_Init(LmsKey* key, void* heap, int devId) * @param [in] devId Device identifier. * * @return 0 on success. - * @return BAD_FUNC_ARG when key is NULL. + * @return BAD_FUNC_ARG when key is NULL, or id is NULL and len is not 0. * @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, @@ -665,13 +660,16 @@ int wc_LmsKey_InitId(LmsKey* key, const unsigned char* id, int len, void* heap, { int ret = 0; - if (key == NULL) + if ((key == NULL) || ((id == NULL) && (len != 0))) { ret = BAD_FUNC_ARG; - if (ret == 0 && (len < 0 || len > LMS_MAX_ID_LEN)) + } + if ((ret == 0) && ((len < 0) || (len > LMS_MAX_ID_LEN))) { ret = BUFFER_E; - if (ret == 0) + } + if (ret == 0) { ret = wc_LmsKey_Init(key, heap, devId); - if (ret == 0 && id != NULL && len != 0) { + } + if ((ret == 0) && (id != NULL) && (len != 0)) { XMEMCPY(key->id, id, (size_t)len); key->idLen = len; } @@ -693,20 +691,23 @@ int wc_LmsKey_InitId(LmsKey* key, const unsigned char* id, int len, void* heap, int wc_LmsKey_InitLabel(LmsKey* key, const char* label, void* heap, int devId) { int ret = 0; - int labelLen = 0; + size_t labelLen = 0; - if (key == NULL || label == NULL) + 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; + labelLen = 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, labelLen); + key->labelLen = (int)labelLen; } return ret; @@ -790,10 +791,6 @@ int wc_LmsKey_SetLmsParm(LmsKey* key, enum wc_LmsParm lmsParm) } /* Set the parameters of an LMS key. - * - * Use this if you wish to set specific parameters not found in the - * wc_LmsParm predefined sets. See comments in wc_lms.h for allowed - * parameters. * * Key must be inited before calling this. * @@ -804,6 +801,7 @@ int wc_LmsKey_SetLmsParm(LmsKey* key, enum wc_LmsParm lmsParm) * @return 0 on success. * @return BAD_FUNC_ARG when key is NULL. * @return BAD_FUNC_ARG when parameters not supported. + * @return BAD_STATE_E when key state is not initialized. * */ int wc_LmsKey_SetParameters(LmsKey* key, int levels, int height, int winternitz) @@ -847,6 +845,67 @@ int wc_LmsKey_SetParameters(LmsKey* key, int levels, int height, return ret; } +/* Set the parameters of an LMS key including hash length. + * + * Key must be inited before calling this. + * + * @param [in, out] key LMS key to set parameters on. + * @param [in] levels Number of tree levels. + * @param [in] height Height of each tree. + * @param [in] winternitz Width or Winternitz coefficient. + * @param [in] hash Hash algorithm to use. Valid values: + * - LMS_SHA256 + * - LMS_SHA256_192 + * - LMS_SHAKE256 + * - LMS_SHAKE256_192 + * @return 0 on success. + * @return BAD_FUNC_ARG when key is NULL. + * @return BAD_FUNC_ARG when parameters not supported. + * @return BAD_STATE_E when key state is not initialized. + * */ +int wc_LmsKey_SetParameters_ex(LmsKey* key, int levels, int height, + int winternitz, int hash) +{ + int ret = 0; + + /* Validate parameters. */ + if (key == NULL) { + ret = BAD_FUNC_ARG; + } + + /* Check state is valid. */ + if ((ret == 0) && (key->state != WC_LMS_STATE_INITED)) { + WOLFSSL_MSG("error: LmsKey needs init"); + ret = BAD_STATE_E; + } + + if (ret == 0) { + int i; + + ret = BAD_FUNC_ARG; + /* Search through table for matching levels, height and width. */ + for (i = 0; i < WC_LMS_MAP_LEN; i++) { + if ((levels == wc_lms_map[i].params.levels) && + (height == wc_lms_map[i].params.height) && + (winternitz == wc_lms_map[i].params.width) && + (hash == (wc_lms_map[i].params.lmsType & LMS_HASH_MASK))) { + /* Set the parameters into the key. */ + key->params = &wc_lms_map[i].params; + ret = 0; + break; + } + } + } + + if (ret == 0) { + /* Move the state to params set. + * Key is ready for MakeKey or Reload. */ + key->state = WC_LMS_STATE_PARMSET; + } + + return ret; +} + /* Get the parameters of an LMS key. * * Key must be inited and parameters set before calling this. @@ -855,8 +914,10 @@ int wc_LmsKey_SetParameters(LmsKey* key, int levels, int height, * @param [out] levels Number of levels of trees. * @param [out] height Height of the trees. * @param [out] winternitz Winternitz width. - * Returns 0 on success. - * */ + * @return 0 on success. + * @return BAD_FUNC_ARG when key, key->params, levels, height or winternitz is + * NULL. + */ int wc_LmsKey_GetParameters(const LmsKey* key, int* levels, int* height, int* winternitz) { @@ -883,6 +944,46 @@ int wc_LmsKey_GetParameters(const LmsKey* key, int* levels, int* height, return ret; } +/* Get the parameters of an LMS key. + * + * Key must be inited and parameters set before calling this. + * + * @param [in] key LMS key. + * @param [out] levels Number of levels of trees. + * @param [out] height Height of the trees. + * @param [out] winternitz Winternitz width. + * @param [out] hash Hash algorithm. + * @return 0 on success. + * @return BAD_FUNC_ARG when key, key->params, levels, height, winternitz or + * hash is NULL. + */ +int wc_LmsKey_GetParameters_ex(const LmsKey* key, int* levels, int* height, + int* winternitz, int* hash) +{ + int ret = 0; + + /* Validate parameters. */ + if ((key == NULL) || (levels == NULL) || (height == NULL) || + (winternitz == NULL) || (hash == NULL)) { + ret = BAD_FUNC_ARG; + } + + /* Validate the parameters are available. */ + if ((ret == 0) && (key->params == NULL)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + /* Set the levels, height and Winternitz width from parameters. */ + *levels = key->params->levels; + *height = key->params->height; + *winternitz = key->params->width; + *hash = key->params->lmsType & LMS_HASH_MASK; + } + + return ret; +} + /* Frees the LMS key from memory. * * This does not affect the private key saved to non-volatile storage. @@ -899,15 +1000,34 @@ void wc_LmsKey_Free(LmsKey* key) params->height, params->p, params->rootLevels, params->cacheBits, params->hash_len); -#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE + #ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE priv_data_len += HSS_PRIVATE_KEY_LEN(key->params->hash_len); -#endif + #endif ForceZero(key->priv_data, priv_data_len); XFREE(key->priv_data, key->heap, DYNAMIC_TYPE_LMS); + key->priv_data = NULL; } - #endif - ForceZero(key, sizeof(LmsKey)); + ForceZero(key->priv_raw, HSS_MAX_PRIVATE_KEY_LEN); + ForceZero(&key->priv, sizeof(HssPrivKey)); + + key->write_private_key = NULL; + key->read_private_key = NULL; + key->context = NULL; + key->heap = NULL; + #endif + XMEMSET(key->pub, 0, sizeof(key->pub)); + key->params = NULL; + #ifdef WOLF_CRYPTO_CB + key->devId = INVALID_DEVID; + key->devCtx = NULL; + #endif + #ifdef WOLF_PRIVATE_KEY_ID + XMEMSET(key->id, 0, sizeof(key->id)); + key->idLen = 0; + XMEMSET(key->label, 0, sizeof(key->label)); + key->labelLen = 0; + #endif key->state = WC_LMS_STATE_FREED; } @@ -1051,6 +1171,13 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng) ret = wc_CryptoCb_PqcStatefulSigKeyGen(WC_PQC_STATEFUL_SIG_TYPE_LMS, key, rng); if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + /* This should not happen, but check whether signatures can be + * created. */ + if ((ret == 0) && (wc_LmsKey_SigsLeft(key) == 0)) { + WOLFSSL_MSG("error: generated LMS key signatures exhausted"); + key->state = WC_LMS_STATE_NOSIGS; + ret = BAD_STATE_E; + } /* On success, mirror the software path's terminal state so * subsequent Sign/Verify calls don't fail with BAD_STATE_E. */ if (ret == 0) { @@ -1072,9 +1199,9 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng) priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height, params->p, params->rootLevels, params->cacheBits, params->hash_len); -#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE + #ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE priv_data_len += HSS_PRIVATE_KEY_LEN(key->params->hash_len); -#endif + #endif } if ((ret == 0) && (key->priv_data == NULL)) { /* Allocate memory for the private key data. */ @@ -1084,9 +1211,11 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng) if (key->priv_data == NULL) { ret = MEMORY_E; } -#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE - XMEMSET(key->priv_data, 0, priv_data_len); -#endif + #ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE + else { + XMEMSET(key->priv_data, 0, priv_data_len); + } + #endif } if (ret == 0) { WC_DECLARE_VAR(state, LmsState, 1, 0); @@ -1111,16 +1240,16 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng) if (ret == 0) { int rv; /* Write private key to storage. */ -#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE + #ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE XMEMCPY(key->priv_data + priv_data_len - HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->priv_raw, HSS_PRIVATE_KEY_LEN(key->params->hash_len)); rv = key->write_private_key(key->priv_data, priv_data_len, key->context); -#else + #else rv = key->write_private_key(key->priv_raw, HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context); -#endif + #endif if (rv != WC_LMS_RC_SAVED_TO_NV_MEMORY) { ret = IO_FAILED_E; } @@ -1141,8 +1270,10 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng) return ret; } -/* Reload a key that has been prepared with the appropriate params and - * data. Use this if you wish to resume signing with an existing key. +/* Reload a key that has been prepared with the appropriate params and data. + * + * Use this if you wish to resume signing with an existing key. + * Call this function after initializing and setting parameters. * * Write/read callbacks, and context data, must be set prior. * Key must have parameters set. @@ -1185,9 +1316,9 @@ int wc_LmsKey_Reload(LmsKey* key) priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height, params->p, params->rootLevels, params->cacheBits, params->hash_len); -#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE + #ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE priv_data_len += HSS_PRIVATE_KEY_LEN(params->hash_len); -#endif + #endif } if ((ret == 0) && (key->priv_data == NULL)) { /* Allocate memory for the private key data. */ @@ -1202,24 +1333,24 @@ int wc_LmsKey_Reload(LmsKey* key) int rv; /* Load private key. */ -#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE + #ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE const LmsParams* params = key->params; rv = key->read_private_key(key->priv_data, priv_data_len, key->context); -#else + #else rv = key->read_private_key(key->priv_raw, HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context); -#endif + #endif if (rv != WC_LMS_RC_READ_TO_MEMORY) { ret = IO_FAILED_E; } -#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE + #ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE if (ret == 0) { XMEMCPY(key->priv_raw, key->priv_data + priv_data_len - HSS_PRIVATE_KEY_LEN(params->hash_len), HSS_PRIVATE_KEY_LEN(params->hash_len)); } -#endif + #endif } /* Double check the key actually has signatures left. */ @@ -1258,7 +1389,7 @@ int wc_LmsKey_Reload(LmsKey* key) return ret; } -/* Get the private key length based on parameter set of key. +/* Get the raw private key length based on parameter set of key. * * @param [in] key LMS key. * @param [out] len Length of private key. @@ -1292,7 +1423,7 @@ int wc_LmsKey_GetPrivLen(const LmsKey* key, word32* len) * @param [in] msgSz Length of message in bytes. * @return 0 on success. * @return BAD_FUNC_ARG when key, sig, sigSz or msg is NULL. - * @return BAD_FUNC_ARG when msgSz is not greater than 0. + * @return BAD_FUNC_ARG when msgSz is less than 0. * @return BAD_FUNC_ARG when a write private key is not set. * @return BAD_FUNC_ARG when a read/write private key context is not set. * @return BUFFER_E when sigSz is too small. @@ -1305,21 +1436,22 @@ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg, int ret = 0; /* Validate parameters. */ - if ((key == NULL) || (sig == NULL) || (sigSz == NULL) || (msg == NULL)) { + if ((key == NULL) || (key->params == NULL) || (sig == NULL) || + (sigSz == NULL) || (msg == NULL)) { ret = BAD_FUNC_ARG; } - if ((ret == 0) && (msgSz <= 0)) { + if ((ret == 0) && (msgSz < 0)) { ret = BAD_FUNC_ARG; } /* Check state. */ - if ((ret == 0) && (key->state == WC_LMS_STATE_NOSIGS)) { - WOLFSSL_MSG("error: LMS signatures exhausted"); - ret = BAD_STATE_E; - } if ((ret == 0) && (key->state != WC_LMS_STATE_OK)) { - /* The key had an error the last time it was used, and we - * can't guarantee its state. */ - WOLFSSL_MSG("error: can't sign, LMS key not in good state"); + if (key->state == WC_LMS_STATE_NOSIGS) { + WOLFSSL_MSG("error: LMS signatures exhausted"); + } + else { + /* The key state is not ready for signing. */ + WOLFSSL_MSG("error: can't sign, LMS key not in good state"); + } ret = BAD_STATE_E; } /* Check signature buffer size. */ @@ -1336,8 +1468,9 @@ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg, 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)) + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { return ret; + } ret = 0; /* fall through to software path */ } #endif @@ -1375,7 +1508,7 @@ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg, int rv; /* Write private key to storage. */ -#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE + #ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE const LmsParams* params = key->params; word32 priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height, params->p, params->rootLevels, params->cacheBits, @@ -1386,10 +1519,10 @@ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg, HSS_PRIVATE_KEY_LEN(params->hash_len)); rv = key->write_private_key(key->priv_data, priv_data_len, key->context); -#else + #else rv = key->write_private_key(key->priv_raw, HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context); -#endif + #endif if (rv != WC_LMS_RC_SAVED_TO_NV_MEMORY) { /* Write to NV storage failed. Erase the signature from * memory to prevent OTS key reuse if state is rolled back. */ @@ -1414,7 +1547,7 @@ int wc_LmsKey_SigsLeft(LmsKey* key) /* NULL keys have no signatures remaining. */ if (key != NULL) { -#ifdef WOLF_CRYPTO_CB + #ifdef WOLF_CRYPTO_CB if (key->devId != INVALID_DEVID) { word32 sigsLeft = 0; int cbRet = wc_CryptoCb_PqcStatefulSigSigsLeft( @@ -1432,7 +1565,7 @@ int wc_LmsKey_SigsLeft(LmsKey* key) } return 0; } -#endif + #endif ret = wc_hss_sigsleft(key->params, key->priv_raw); } @@ -1467,8 +1600,8 @@ int wc_LmsKey_GetPubLen(const LmsKey* key, word32* len) /* Export a generated public key and parameter set from one LmsKey * to another, with explicit heap and device bindings. * - * The destination is fully (re)initialized as a verify-only key; - * any prior state on keyDst is discarded. + * The destination key must be unused or have been freed. + * The destination is fully initialized as a verify-only key. * * @param [out] keyDst LMS key to copy into. * @param [in] keySrc LMS key to copy. @@ -1477,32 +1610,29 @@ int wc_LmsKey_GetPubLen(const LmsKey* key, word32* len) * Use INVALID_DEVID when not using a device. * @return 0 on success. * @return BAD_FUNC_ARG when keyDst or keySrc is NULL. + * @return BAD_STATE_E when in the wrong state for the operation. */ 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; } + if ((ret == 0) && (keySrc->state != WC_LMS_STATE_OK) && + (keySrc->state != WC_LMS_STATE_VERIFYONLY) && + (keySrc->state != WC_LMS_STATE_NOSIGS)) { + ret = BAD_STATE_E; + } if (ret == 0) { - ForceZero(keyDst, sizeof(LmsKey)); - + ret = wc_LmsKey_Init(keyDst, heap, devId); + } + if (ret == 0) { 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; } @@ -1752,7 +1882,8 @@ int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz, int ret = 0; /* Validate parameters. */ - if ((key == NULL) || (sig == NULL) || (msg == NULL)) { + if ((key == NULL) || (key->params == NULL) || (sig == NULL) || + (msg == NULL)) { ret = BAD_FUNC_ARG; } if ((ret == 0) && (msgSz < 0)) { @@ -1821,31 +1952,36 @@ int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz, * @param [out] kidSz Size of key ID. * @return 0 on success. * @return BAD_FUNC_ARG when a key, kid or kidSz is NULL. + * @return NOT_COMPILED_IN when key is on a device. */ -int wc_LmsKey_GetKid(LmsKey * key, const byte ** kid, word32* kidSz) +int wc_LmsKey_GetKid(LmsKey* key, const byte** kid, word32* kidSz) { + int ret = 0; word32 offset; - if ((key == NULL) || (kid == NULL) || (kidSz == NULL)) { - return BAD_FUNC_ARG; + if ((key == NULL) || (key->params == NULL) || (kid == NULL) || + (kidSz == NULL)) { + ret = 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) { + * the private state. Extend the CryptoCb surface if device-side KID + * retrieval becomes a requirement. + */ + if ((ret == 0) && (key->devId != INVALID_DEVID)) { WOLFSSL_MSG( - "wc_LmsKey_GetKid: priv_raw may be uninitialised for HSM keys"); + "wc_LmsKey_GetKid: priv_raw may be uninitialised for HSM keys"); } #endif + if (ret == 0) { + /* SEED length is hash length. */ + offset = HSS_Q_LEN + HSS_PRIV_KEY_PARAM_SET_LEN + key->params->hash_len; + *kid = key->priv_raw + offset; + *kidSz = HSS_PRIVATE_KEY_LEN(key->params->hash_len) - offset; + } - /* SEED length is hash length. */ - offset = HSS_Q_LEN + HSS_PRIV_KEY_PARAM_SET_LEN + key->params->hash_len; - *kid = key->priv_raw + offset; - *kidSz = HSS_PRIVATE_KEY_LEN(key->params->hash_len) - offset; - - return 0; + return ret; } @@ -1859,18 +1995,27 @@ int wc_LmsKey_GetKid(LmsKey * key, const byte ** kid, word32* kidSz) * @param Pointer to 16 byte Key ID in the private key. * @return NULL on failure. */ -const byte * wc_LmsKey_GetKidFromPrivRaw(const byte * priv, word32 privSz) +const byte* wc_LmsKey_GetKidFromPrivRaw(const byte* priv, word32 privSz) { - word32 seedSz = privSz - HSS_Q_LEN - HSS_PRIV_KEY_PARAM_SET_LEN - LMS_I_LEN; + const byte* ret; - if (priv == NULL) { - return NULL; + if ((priv == NULL) || + (privSz < HSS_Q_LEN + HSS_PRIV_KEY_PARAM_SET_LEN + LMS_I_LEN)) { + ret = NULL; } - if ((seedSz != WC_SHA256_192_DIGEST_SIZE) && - (seedSz != WC_SHA256_DIGEST_SIZE)) { - return NULL; + else { + word32 seedSz = privSz - HSS_Q_LEN - HSS_PRIV_KEY_PARAM_SET_LEN - + LMS_I_LEN; + if ((seedSz != WC_SHA256_192_DIGEST_SIZE) && + (seedSz != WC_SHA256_DIGEST_SIZE)) { + ret = NULL; + } + else { + ret = priv + privSz - LMS_I_LEN; + } } - return priv + privSz - LMS_I_LEN; + + return ret; } #endif diff --git a/wolfcrypt/src/wc_lms_impl.c b/wolfcrypt/src/wc_lms_impl.c index b9a4a20f73..25e89901a9 100644 --- a/wolfcrypt/src/wc_lms_impl.c +++ b/wolfcrypt/src/wc_lms_impl.c @@ -926,7 +926,7 @@ static int wc_lmots_msg_hash(LmsState* state, const byte* msg, word32 msgSz, } else #endif - { + if (ret == 0) { ret = NOT_COMPILED_IN; } } @@ -2103,7 +2103,7 @@ static int wc_lms_treehash(LmsState* state, const byte* id, const byte* seed, ret = wc_lms_interior_hash(state, sp, r, temp); /* Copy out node to authentication path if on path. */ - if ((ret == 0) && (auth_path != NULL) && ((q >> h) ^ 0x1) == j) { + if ((ret == 0) && (auth_path != NULL) && (((q >> h) ^ 0x1) == j)) { XMEMCPY(auth_path + h * params->hash_len, temp, params->hash_len); } @@ -2256,7 +2256,7 @@ static int wc_lms_treehash_init(LmsState* state, LmsPrivState* privState, } /* Copy out node to authentication path if on path. */ - if ((ret == 0) && (auth_path != NULL) && ((q >> h) ^ 0x1) == j) { + if ((ret == 0) && (auth_path != NULL) && (((q >> h) ^ 0x1) == j)) { XMEMCPY(auth_path + h * params->hash_len, temp, params->hash_len); } @@ -2350,15 +2350,21 @@ static int wc_lms_treehash_update(LmsState* state, LmsPrivState* privState, params->hash_len; /* Copy cached node into working buffer. */ XMEMCPY(temp, leaf->cache + off, params->hash_len); - /* I || u32str(i) || ... */ - c32toa(i, rp); } else { /* Calculate leaf node hash. */ ret = wc_lms_leaf_hash(state, seed, i, r, temp); - /* Check if this is at the end of the cache and not beyond q plus - * the number of leaf nodes. */ + /* Slide the leaf cache forward by one slot when i is exactly the + * leaf immediately past the cached window and still within the + * window we will need to cover q. Callers (wc_hss_init_auth_path / + * wc_hss_update_auth_path) advance i contiguously, so i never + * jumps past leaf->idx + max_cb in normal use; if that invariant + * is broken, the cache stays put and i is silently uncached + * (correct, but defeats the cache). */ + if (i > leaf->idx + max_cb) { + WOLFSSL_MSG("Bad value for index"); + } if ((i == leaf->idx + max_cb) && (i < (q + max_cb))) { /* Copy working node into cache over old first node. */ XMEMCPY(leaf->cache + leaf->offset * params->hash_len, temp, @@ -2834,12 +2840,14 @@ static int wc_lms_verify(LmsState* state, const byte* pub, const byte* msg, * (low 12 bits, LMS_H_W_MASK). The wire format strips the * private flags (see encoder lines 2483, 2510, 1559), so the * comparison is against the RFC type code only. This is safe so - * long as the low-12-bit codes remain globally distinct across - * hash families (they are today: 0x05-0x09 SHA-256/M32, - * 0x0a-0x0e SHA-256/M24, 0x0f-0x13 SHAKE/M32, etc.). Any future - * parameter set that introduces a collision in the low 12 bits - * would require this check to compare the full lmsType, not the - * masked form. */ + * long as the (lmsType, lmOtsType) pair, masked to the low 12 bits, + * is unique across the static map -- i.e., no two entries from + * different hash families happen to have the same RFC code pair. + * All current entries have matching hash families, so the pair is + * trivially unique. A future entry mixing families would need this + * checked explicitly. Any future parameter set that introduces a + * collision in the low 12 bits would require this check to compare + * the full lmsType, not the masked form. */ const byte* sig_lms_type = sig + LMS_Q_LEN + LMS_TYPE_LEN + params->hash_len + params->p * params->hash_len; word32 sigType; @@ -3118,12 +3126,13 @@ static int wc_lms_next_subtree_init(LmsState* state, LmsPrivState* privState, byte* priv_i; word32 pq; + /* Get next key pointer. */ priv_q = priv; - priv += LMS_Q_LEN; + /* Get pointers of current private. */ priv_seed = curr + LMS_Q_LEN; - priv += params->hash_len; priv_i = curr + LMS_Q_LEN + params->hash_len; - priv += LMS_I_LEN; + /* Move next private key to next leaf for updating.*/ + priv += LMS_Q_LEN + params->hash_len + LMS_I_LEN; ato32(curr, &pq); pq = (pq + 1U) & ((((word32)1U) << params->height) - (word32)1U); @@ -3182,7 +3191,7 @@ static int wc_hss_next_subtree_inc(LmsState* state, HssPrivKey* priv_key, cp64_hi = w64ShiftRight(p64, (params->levels - i - 1) * params->height); cq64_hi = w64ShiftRight(q64, (params->levels - i - 1) * params->height); /* Get the q for the child. */ - ato32(curr + LMS_PRIV_LEN(params->hash_len), (unsigned int*)&qc); + ato32(curr + LMS_PRIV_LEN(params->hash_len), &qc); /* Compare index of parent node with previous value. */ if (w64LT(p64_hi, q64_hi)) { @@ -3426,7 +3435,7 @@ static int wc_hss_presign(LmsState* state, HssPrivKey* priv_key) const LmsParams* params = state->params; byte* buffer = state->buffer; byte pub[LMS_PUBKEY_LEN(LMS_MAX_NODE_LEN)]; - byte* root = pub + LMS_PUBKEY_LEN(LMS_MAX_NODE_LEN) - params->hash_len; + byte* root = pub + LMS_PUBKEY_LEN(params->hash_len) - params->hash_len; byte* priv = priv_key->priv; int i; @@ -3514,8 +3523,6 @@ static void wc_hss_priv_data_store(const LmsParams* params, HssPrivKey* key, { int l; - (void)key; - /* Expanded private keys. */ priv_data += LMS_PRIV_KEY_LEN(params->levels, params->hash_len); @@ -4022,15 +4029,23 @@ int wc_hss_sign(LmsState* state, byte* priv_raw, HssPrivKey* priv_key, */ int wc_hss_sigsleft(const LmsParams* params, const byte* priv_raw) { + int ret; w64wrapper q; w64wrapper cnt; - /* Get current q - next leaf index to sign with. */ - ato64(priv_raw, &q); - /* 1 << total_height = total leaf nodes. */ - cnt = w64ShiftLeft(w64From32(0, 1), params->levels * params->height); - /* Check q is less than total leaf node count. */ - return w64LT(q, cnt); + if (params->levels * params->height >= 64) { + ret = 1; + } + else { + /* Get current q - next leaf index to sign with. */ + ato64(priv_raw, &q); + /* 1 << total_height = total leaf nodes. */ + cnt = w64ShiftLeft(w64From32(0, 1), params->levels * params->height); + /* Check q is less than total leaf node count. */ + ret = w64LT(q, cnt); + } + + return ret; } #endif /* !WOLFSSL_LMS_VERIFY_ONLY */ @@ -4086,8 +4101,12 @@ int wc_hss_verify(LmsState* state, const byte* pub, const byte* msg, sig += LMS_L_LEN; sigRem = sigSz - LMS_L_LEN; + /* Validate that the count of levels matches the parameters. */ + if (levels != state->params->levels) { + ret = SIG_VERIFY_E; + } /* Line 2: Verify that pub and signature match in levels. */ - if (nspk + 1 != levels) { + if ((ret == 0) && (nspk + 1 != levels)) { /* Line 3: Return invalid signature. */ ret = SIG_VERIFY_E; } diff --git a/wolfssl/wolfcrypt/wc_lms.h b/wolfssl/wolfcrypt/wc_lms.h index 15a9e8befa..a8d898c6c6 100644 --- a/wolfssl/wolfcrypt/wc_lms.h +++ b/wolfssl/wolfcrypt/wc_lms.h @@ -112,8 +112,10 @@ #define WC_LMS_I_LEN 16 /* Private key write and read callbacks. */ -typedef int (*wc_lms_write_private_key_cb)(const byte * priv, word32 privSz, void *context); -typedef int (*wc_lms_read_private_key_cb)(byte * priv, word32 privSz, void *context); +typedef int (*wc_lms_write_private_key_cb)(const byte* priv, word32 privSz, + void* context); +typedef int (*wc_lms_read_private_key_cb)(byte* priv, word32 privSz, + void* context); /* Return codes returned by private key callbacks. */ enum wc_LmsRc { @@ -157,7 +159,6 @@ enum wc_LmsRc { * will be large. */ enum wc_LmsParm { #ifndef WOLFSSL_NO_LMS_SHA256_256 - WC_LMS_PARM_NONE = 0, WC_LMS_PARM_L1_H5_W1 = 1, WC_LMS_PARM_L1_H5_W2 = 2, WC_LMS_PARM_L1_H5_W4 = 3, @@ -617,10 +618,10 @@ typedef struct LmsParams { word16 lmsType; /* LMOTS type. */ word16 lmOtsType; - /* Length of LM-OTS signature. */ - word16 sig_len; /* Length of seed. */ word16 hash_len; + /* Length of LM-OTS signature. */ + word32 sig_len; #ifndef WOLFSSL_WC_LMS_SMALL /* Number of root levels of interior nodes to store. */ word8 rootLevels; @@ -793,50 +794,55 @@ typedef struct LmsKey { extern "C" { #endif -WOLFSSL_API int wc_LmsKey_Init(LmsKey * key, void * heap, int devId); +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); +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, +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); -WOLFSSL_API int wc_LmsKey_GetParameters(const LmsKey * key, int * levels, - int * height, int * winternitz); +WOLFSSL_API int wc_LmsKey_SetParameters_ex(LmsKey* key, int levels, + int height, int winternitz, int hash); +WOLFSSL_API int wc_LmsKey_GetParameters(const LmsKey* key, int* levels, + int* height, int* winternitz); +WOLFSSL_API int wc_LmsKey_GetParameters_ex(const LmsKey* key, int* levels, + int* height, int* winternitz, int* hash); #ifndef WOLFSSL_LMS_VERIFY_ONLY -WOLFSSL_API int wc_LmsKey_SetWriteCb(LmsKey * key, +WOLFSSL_API int wc_LmsKey_SetWriteCb(LmsKey* key, wc_lms_write_private_key_cb write_cb); -WOLFSSL_API int wc_LmsKey_SetReadCb(LmsKey * key, +WOLFSSL_API int wc_LmsKey_SetReadCb(LmsKey* key, wc_lms_read_private_key_cb read_cb); -WOLFSSL_API int wc_LmsKey_SetContext(LmsKey * key, void * context); -WOLFSSL_API int wc_LmsKey_MakeKey(LmsKey * key, WC_RNG * rng); -WOLFSSL_API int wc_LmsKey_Reload(LmsKey * key); -WOLFSSL_API int wc_LmsKey_GetPrivLen(const LmsKey * key, word32 * len); -WOLFSSL_API int wc_LmsKey_Sign(LmsKey * key, byte * sig, word32 * sigSz, - const byte * msg, int msgSz); -WOLFSSL_API int wc_LmsKey_SigsLeft(LmsKey * key); +WOLFSSL_API int wc_LmsKey_SetContext(LmsKey* key, void* context); +WOLFSSL_API int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng); +WOLFSSL_API int wc_LmsKey_Reload(LmsKey* key); +WOLFSSL_API int wc_LmsKey_GetPrivLen(const LmsKey* key, word32* len); +WOLFSSL_API int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, + const byte* msg, int msgSz); +WOLFSSL_API int wc_LmsKey_SigsLeft(LmsKey* key); #endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */ -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, +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, word32 inLen); -WOLFSSL_API int wc_LmsKey_Verify(LmsKey * key, const byte * sig, word32 sigSz, - const byte * msg, int msgSz); -WOLFSSL_API const char * wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm); -WOLFSSL_API const char * wc_LmsKey_RcToStr(enum wc_LmsRc lmsRc); +WOLFSSL_API int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz, + const byte* msg, int msgSz); +WOLFSSL_API const char* wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm); -WOLFSSL_API int wc_LmsKey_GetKid(LmsKey * key, const byte ** kid, +#ifndef WOLFSSL_LMS_VERIFY_ONLY +WOLFSSL_API int wc_LmsKey_GetKid(LmsKey* key, const byte** kid, word32* kidSz); -WOLFSSL_API const byte * wc_LmsKey_GetKidFromPrivRaw(const byte * priv, +WOLFSSL_API const byte* wc_LmsKey_GetKidFromPrivRaw(const byte* priv, word32 privSz); +#endif int wc_hss_make_key(LmsState* state, WC_RNG* rng, byte* priv_raw, HssPrivKey* priv_key, byte* priv_data, byte* pub); diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/lms.rs b/wrapper/rust/wolfssl-wolfcrypt/src/lms.rs index d3be50dc87..90d4f1127f 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/lms.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/lms.rs @@ -108,7 +108,6 @@ pub struct Lms { #[cfg(lms_sha256_256)] impl Lms { - pub const PARM_NONE: u32 = sys::wc_LmsParm_WC_LMS_PARM_NONE; pub const PARM_L1_H5_W1: u32 = sys::wc_LmsParm_WC_LMS_PARM_L1_H5_W1; pub const PARM_L1_H5_W2: u32 = sys::wc_LmsParm_WC_LMS_PARM_L1_H5_W2; pub const PARM_L1_H5_W4: u32 = sys::wc_LmsParm_WC_LMS_PARM_L1_H5_W4;