1
0
mirror of https://github.com/wolfSSL/wolfssl.git synced 2026-10-24 04:09:07 +03:00

Let an LMS/XMSS key named by id verify on a device without Reload

wc_LmsKey_Verify and wc_XmssKey_Verify accepted only a key in the OK or
VERIFYONLY state before calling the device. A key from InitId or
InitLabel with its parameters set is in PARMSET, and only Reload moves
it on. A verify-only build compiles Reload out, so such a key could
never verify, on any device.

Accept PARMSET before the device call for a key named by id, label or
device context. wolfHSM names a key cached on the HSM only by devCtx,
with no id. Any other key in PARMSET has no public key anywhere and
still gets BAD_STATE_E without reaching the device. Software still
refuses an id key after the device declines, because a key in PARMSET
never has a public key and the existing pubSet check returns
BAD_STATE_E.

test_wc_LmsKey_id_verify and test_wc_XmssKey_id_verify verify with such
a key through a device, by id and by device context. They check that a
key with neither gets BAD_STATE_E without the device being called, and
that the id key fails without a device: BAD_STATE_E, or NO_VALID_DEVID
in a callback-only build with no software verify. Both run in
verify-only builds, so the guard of the verify callback they share now
covers those builds.
This commit is contained in:
Tobias Frauenschläger
2026-10-21 14:46:50 +02:00
committed by Paul Adelsbach
parent 007ee17cdf
commit 8ebafb02bd
4 changed files with 189 additions and 13 deletions

View File

@@ -60,7 +60,8 @@
/* LMS tests */
/*----------------------------------------------------------------------------*/
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
#if defined(WOLFSSL_HAVE_LMS) && (!defined(WOLFSSL_LMS_VERIFY_ONLY) || \
(defined(WOLF_CRYPTO_CB) && defined(WOLF_PRIVATE_KEY_ID)))
#include <wolfssl/wolfcrypt/wc_lms.h>
@@ -73,6 +74,9 @@ static int test_lms_set_params(LmsKey* key)
return wc_LmsKey_SetParameters(key, 1, 5, 8);
#endif
}
#endif
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
#ifdef TEST_LMS_SW_AVAILABLE
/* Per-process temp file: parallel unit.test runs (e.g. CI shards sharing a
@@ -393,11 +397,12 @@ static int test_lms_xmss_cryptocb(int devIdArg, wc_CryptoInfo* info, void* ctx)
}
#endif
/* Must be the exact union of the two verify test guards below. */
/* Must be the exact union of the guards of the tests that register it. */
#if defined(WOLF_CRYPTO_CB) && \
((defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)) || \
(defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) && \
defined(TEST_XMSS_H10_AVAILABLE)))
((defined(WOLFSSL_HAVE_LMS) && \
(!defined(WOLFSSL_LMS_VERIFY_ONLY) || defined(WOLF_PRIVATE_KEY_ID))) || \
(defined(WOLFSSL_HAVE_XMSS) && defined(TEST_XMSS_H10_AVAILABLE) && \
(!defined(WOLFSSL_XMSS_VERIFY_ONLY) || defined(WOLF_PRIVATE_KEY_ID))))
/* Number of stateful signature verifications the accelerator below answered. */
static int test_lms_xmss_verify_calls;
@@ -677,6 +682,80 @@ int test_wc_LmsKey_id_sigsleft(void)
return EXPECT_RESULT();
}
/*
* Test that an LMS key named by id verifies on its device with only its
* parameters set, as a verify-only build has no Reload to call.
*/
int test_wc_LmsKey_id_verify(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_LMS) && defined(WOLF_CRYPTO_CB) && \
defined(WOLF_PRIVATE_KEY_ID)
LmsKey key;
const byte id[] = { 0x01, 0x02, 0x03, 0x04 };
byte msg[] = "test message for LMS signing";
byte* sig = NULL;
word32 sigSz = 0;
XMEMSET(&key, 0, sizeof(key));
test_lms_xmss_verify_calls = 0;
ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_LMS_XMSS_CRYPTOCB_DEVID,
test_lms_xmss_verify_cryptocb, NULL), 0);
ExpectIntEQ(wc_LmsKey_InitId(&key, id, (int)sizeof(id), NULL,
TEST_LMS_XMSS_CRYPTOCB_DEVID), 0);
ExpectIntEQ(test_lms_set_params(&key), 0);
ExpectIntEQ(wc_LmsKey_GetSigLen(&key, &sigSz), 0);
ExpectNotNull(sig = (byte*)XMALLOC(sigSz, NULL, DYNAMIC_TYPE_TMP_BUFFER));
if (sig != NULL) {
XMEMSET(sig, 0, sigSz);
ExpectIntEQ(wc_LmsKey_Verify(&key, sig, sigSz, msg, sizeof(msg)), 0);
ExpectIntEQ(test_lms_xmss_verify_calls, 1);
}
wc_LmsKey_Free(&key);
/* A key with no id, label or device context needs a public key. */
ExpectIntEQ(wc_LmsKey_Init(&key, NULL, TEST_LMS_XMSS_CRYPTOCB_DEVID), 0);
ExpectIntEQ(test_lms_set_params(&key), 0);
if (sig != NULL) {
ExpectIntEQ(wc_LmsKey_Verify(&key, sig, sigSz, msg, sizeof(msg)),
WC_NO_ERR_TRACE(BAD_STATE_E));
ExpectIntEQ(test_lms_xmss_verify_calls, 1);
}
wc_LmsKey_Free(&key);
/* A device context names the key as an id does. */
ExpectIntEQ(wc_LmsKey_Init(&key, NULL, TEST_LMS_XMSS_CRYPTOCB_DEVID), 0);
ExpectIntEQ(test_lms_set_params(&key), 0);
key.devCtx = msg;
if (sig != NULL) {
ExpectIntEQ(wc_LmsKey_Verify(&key, sig, sigSz, msg, sizeof(msg)), 0);
ExpectIntEQ(test_lms_xmss_verify_calls, 2);
}
key.devCtx = NULL;
wc_LmsKey_Free(&key);
/* Without a device the same key has no public key to verify with. */
ExpectIntEQ(wc_LmsKey_InitId(&key, id, (int)sizeof(id), NULL,
INVALID_DEVID), 0);
ExpectIntEQ(test_lms_set_params(&key), 0);
if (sig != NULL) {
#if defined(WOLF_CRYPTO_CB_ONLY_LMS) && !defined(WOLFSSL_SWDEV)
ExpectIntEQ(wc_LmsKey_Verify(&key, sig, sigSz, msg, sizeof(msg)),
WC_NO_ERR_TRACE(NO_VALID_DEVID));
#else
ExpectIntEQ(wc_LmsKey_Verify(&key, sig, sigSz, msg, sizeof(msg)),
WC_NO_ERR_TRACE(BAD_STATE_E));
#endif
}
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wc_LmsKey_Free(&key);
wc_CryptoCb_UnRegisterDevice(TEST_LMS_XMSS_CRYPTOCB_DEVID);
#endif
return EXPECT_RESULT();
}
/* Must be the exact union of the guards of the tests that register it. */
#if defined(WOLF_CRYPTO_CB) && \
((defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)) || \
@@ -1225,6 +1304,79 @@ int test_wc_XmssKey_id_sigsleft(void)
return EXPECT_RESULT();
}
/*
* Same scenario as test_wc_LmsKey_id_verify, for XMSS.
*/
int test_wc_XmssKey_id_verify(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_XMSS) && defined(WOLF_CRYPTO_CB) && \
defined(TEST_XMSS_H10_AVAILABLE) && defined(WOLF_PRIVATE_KEY_ID)
XmssKey key;
const byte id[] = { 0x01, 0x02, 0x03, 0x04 };
byte msg[] = "test message for XMSS signing";
byte* sig = NULL;
word32 sigSz = 0;
XMEMSET(&key, 0, sizeof(key));
test_lms_xmss_verify_calls = 0;
ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_LMS_XMSS_CRYPTOCB_DEVID,
test_lms_xmss_verify_cryptocb, NULL), 0);
ExpectIntEQ(wc_XmssKey_InitId(&key, id, (int)sizeof(id), NULL,
TEST_LMS_XMSS_CRYPTOCB_DEVID), 0);
ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0);
ExpectIntEQ(wc_XmssKey_GetSigLen(&key, &sigSz), 0);
ExpectNotNull(sig = (byte*)XMALLOC(sigSz, NULL, DYNAMIC_TYPE_TMP_BUFFER));
if (sig != NULL) {
XMEMSET(sig, 0, sigSz);
ExpectIntEQ(wc_XmssKey_Verify(&key, sig, sigSz, msg, sizeof(msg)), 0);
ExpectIntEQ(test_lms_xmss_verify_calls, 1);
}
wc_XmssKey_Free(&key);
/* A key with no id, label or device context needs a public key. */
ExpectIntEQ(wc_XmssKey_Init(&key, NULL, TEST_LMS_XMSS_CRYPTOCB_DEVID), 0);
ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0);
if (sig != NULL) {
ExpectIntEQ(wc_XmssKey_Verify(&key, sig, sigSz, msg, sizeof(msg)),
WC_NO_ERR_TRACE(BAD_STATE_E));
ExpectIntEQ(test_lms_xmss_verify_calls, 1);
}
wc_XmssKey_Free(&key);
/* A device context names the key as an id does. */
ExpectIntEQ(wc_XmssKey_Init(&key, NULL, TEST_LMS_XMSS_CRYPTOCB_DEVID), 0);
ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0);
key.devCtx = msg;
if (sig != NULL) {
ExpectIntEQ(wc_XmssKey_Verify(&key, sig, sigSz, msg, sizeof(msg)), 0);
ExpectIntEQ(test_lms_xmss_verify_calls, 2);
}
key.devCtx = NULL;
wc_XmssKey_Free(&key);
/* Without a device the same key has no public key to verify with. */
ExpectIntEQ(wc_XmssKey_InitId(&key, id, (int)sizeof(id), NULL,
INVALID_DEVID), 0);
ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0);
if (sig != NULL) {
#if defined(WOLF_CRYPTO_CB_ONLY_XMSS) && !defined(WOLFSSL_SWDEV)
ExpectIntEQ(wc_XmssKey_Verify(&key, sig, sigSz, msg, sizeof(msg)),
WC_NO_ERR_TRACE(NO_VALID_DEVID));
#else
ExpectIntEQ(wc_XmssKey_Verify(&key, sig, sigSz, msg, sizeof(msg)),
WC_NO_ERR_TRACE(BAD_STATE_E));
#endif
}
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wc_XmssKey_Free(&key);
wc_CryptoCb_UnRegisterDevice(TEST_LMS_XMSS_CRYPTOCB_DEVID);
#endif
return EXPECT_RESULT();
}
#if defined(WOLF_CRYPTO_CB_ONLY_XMSS) && !defined(WOLFSSL_SWDEV) && \
!defined(WOLFSSL_XMSS_VERIFY_ONLY) && defined(TEST_XMSS_H10_AVAILABLE)
static enum wc_XmssRc test_xmss_read_fail(byte* priv, word32 privSz,

View File

@@ -34,12 +34,14 @@ int test_wc_LmsKey_reload_fail_sigsleft(void);
int test_wc_LmsKey_makekey_fail_sigsleft(void);
int test_wc_LmsKey_keygen_no_sigsleft(void);
int test_wc_LmsKey_id_sigsleft(void);
int test_wc_LmsKey_id_verify(void);
int test_wc_LmsKey_cb_only_no_device(void);
int test_wc_XmssKey_reload_devid(void);
int test_wc_XmssKey_reload_no_pub(void);
int test_wc_XmssKey_reload_devid_verify(void);
int test_wc_XmssKey_keygen_sign_declined(void);
int test_wc_XmssKey_id_sigsleft(void);
int test_wc_XmssKey_id_verify(void);
int test_wc_XmssKey_cb_only_no_device(void);
int test_rfc9802_lms_x509_verify(void);
int test_rfc9802_xmss_x509_verify(void);
@@ -62,12 +64,14 @@ int test_wc_XmssFeatureCoverage(void);
TEST_DECL_GROUP("lms", test_wc_LmsKey_makekey_fail_sigsleft), \
TEST_DECL_GROUP("lms", test_wc_LmsKey_keygen_no_sigsleft), \
TEST_DECL_GROUP("lms", test_wc_LmsKey_id_sigsleft), \
TEST_DECL_GROUP("lms", test_wc_LmsKey_id_verify), \
TEST_DECL_GROUP("lms", test_wc_LmsKey_cb_only_no_device), \
TEST_DECL_GROUP("xmss", test_wc_XmssKey_reload_devid), \
TEST_DECL_GROUP("xmss", test_wc_XmssKey_reload_no_pub), \
TEST_DECL_GROUP("xmss", test_wc_XmssKey_reload_devid_verify), \
TEST_DECL_GROUP("xmss", test_wc_XmssKey_keygen_sign_declined), \
TEST_DECL_GROUP("xmss", test_wc_XmssKey_id_sigsleft), \
TEST_DECL_GROUP("xmss", test_wc_XmssKey_id_verify), \
TEST_DECL_GROUP("xmss", test_wc_XmssKey_cb_only_no_device), \
TEST_DECL_GROUP("lms", test_rfc9802_lms_x509_verify), \
TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_verify), \

View File

@@ -57,6 +57,16 @@
#include <wolfssl/wolfcrypt/cryptocb.h>
#endif
/* A key named by id, label or device context is held by a device. */
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_PRIVATE_KEY_ID)
#define LMS_KEY_ON_DEVICE(key) (((key)->devCtx != NULL) || \
((key)->idLen > 0) || ((key)->labelLen > 0))
#elif defined(WOLF_CRYPTO_CB)
#define LMS_KEY_ON_DEVICE(key) ((key)->devCtx != NULL)
#else
#define LMS_KEY_ON_DEVICE(key) 0
#endif
/* Calculate u. Appendix B. Works for w of 1, 2, 4, or 8.
*
@@ -2077,11 +2087,11 @@ int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz,
static const byte lms_empty_msg[] = {0};
msg = lms_empty_msg;
}
/* Check state. */
/* Check state. A key named by id may have only its parameters set. */
if ((ret == 0) && (key->state != WC_LMS_STATE_OK) &&
(key->state != WC_LMS_STATE_VERIFYONLY)) {
/* LMS key not ready for verification. Param str must be
* set first, and Reload() called. */
(key->state != WC_LMS_STATE_VERIFYONLY) &&
((key->state != WC_LMS_STATE_PARMSET) ||
!LMS_KEY_ON_DEVICE(key))) {
WOLFSSL_MSG("error: LMS key not ready for verification");
ret = BAD_STATE_E;
}

View File

@@ -56,6 +56,16 @@
#include <wolfssl/wolfcrypt/cryptocb.h>
#endif
/* A key named by id, label or device context is held by a device. */
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_PRIVATE_KEY_ID)
#define XMSS_KEY_ON_DEVICE(key) (((key)->devCtx != NULL) || \
((key)->idLen > 0) || ((key)->labelLen > 0))
#elif defined(WOLF_CRYPTO_CB)
#define XMSS_KEY_ON_DEVICE(key) ((key)->devCtx != NULL)
#else
#define XMSS_KEY_ON_DEVICE(key) 0
#endif
#ifndef WOLF_CRYPTO_CB_ONLY_XMSS
/***************************
* DIGEST init and free.
@@ -2105,11 +2115,11 @@ int wc_XmssKey_Verify(XmssKey* key, const byte* sig, word32 sigLen,
static const byte xmss_empty_msg[] = {0};
m = xmss_empty_msg;
}
/* Validate state. */
/* Validate state. A key named by id may have only its parameters set. */
if ((ret == 0) && (key->state != WC_XMSS_STATE_OK) &&
(key->state != WC_XMSS_STATE_VERIFYONLY)) {
/* XMSS key not ready for verification. Param str must be
* set first, and Reload() called. */
(key->state != WC_XMSS_STATE_VERIFYONLY) &&
((key->state != WC_XMSS_STATE_PARMSET) ||
!XMSS_KEY_ON_DEVICE(key))) {
WOLFSSL_MSG("error: XMSS key not ready for verification");
ret = BAD_STATE_E;
}