Merge pull request #10448 from SparkiDev/lms_fixes_1

LMS: fixes and improvements
This commit is contained in:
David Garske
2026-05-12 09:26:42 -07:00
committed by GitHub
6 changed files with 358 additions and 175 deletions
+16 -1
View File
@@ -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;
-1
View File
@@ -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:
+252 -107
View File
@@ -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
+46 -27
View File
@@ -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;
}
+44 -38
View File
@@ -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);
@@ -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;