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

Report no signatures left for an LMS/XMSS key held by a device

When the device declines a SigsLeft query, wc_LmsKey_SigsLeft and
wc_XmssKey_SigsLeft fall back to software. That is right for a key whose
state software holds, such as one made or reloaded through a devId that
only routes other algorithms. But a key whose state lives on the device,
named by id or reloaded without a read callback, has none in software.
XMSS then called the unset read_private_key and crashed. LMS counted
from the all-zero priv_raw and reported a signature left.

Fall back to software only when it holds the private key: privSet for
LMS, which only a software MakeKey or Reload sets, and sk plus the read
callback for XMSS. Otherwise report no signatures left, as before
d56831c90d. The doc comments list this as a reason for returning 0.

wc_LmsKey_Sign and wc_XmssKey_Sign had the same fallback. When the
device declined to sign with such a key, software signed with the unset
priv_data or sk and crashed. A key generated on the device has no sk
either, so XMSS crashed there even with read and write callbacks set.
Return BAD_STATE_E when the LMS privSet or the XMSS sk is not set.

wc_LmsKey_MakeKey and wc_LmsKey_Reload left priv_raw and priv_data in
place when generating or reading the key, or a later step such as
writing out a new key, failed, so a key that was never saved or loaded
still counted from priv_raw. On any failure after the state and callback
checks, wipe priv_data, priv_raw and the expanded key state and clear
privSet, which is now set as soon as priv_raw holds the key. The
priv_data buffer is kept rather than freed, so a caller that supplied
its own, as WOLFSSL_NO_MALLOC builds must, can retry. A call refused by
those checks leaves a loaded key alone.

test_wc_LmsKey_id_sigsleft and test_wc_XmssKey_id_sigsleft query a key
from InitId on a device that declines, and the LMS test also signs with
it. test_wc_XmssKey_keygen_sign_declined signs with a key generated on
a device that then declines. test_wc_LmsKey_reload_fail_sigsleft and
test_wc_LmsKey_makekey_fail_sigsleft query a key whose Reload failed to
read or whose MakeKey failed to write, and check that a priv_data buffer
the caller supplied is still in place. The reload_devid tests now also
check that a software-held key on a declining devId still reports
signatures left.
This commit is contained in:
Tobias Frauenschläger
2026-10-21 14:27:57 +02:00
committed by Paul Adelsbach
parent 2a37b112b5
commit 31ecbbbbf7
4 changed files with 308 additions and 26 deletions

View File

@@ -470,6 +470,7 @@ int test_wc_LmsKey_reload_devid(void)
ExpectIntEQ(wc_LmsKey_Reload(&key), 0);
/* The reload must have expanded the private key, not been skipped. */
ExpectNotNull(key.priv_data);
ExpectIntEQ(wc_LmsKey_SigsLeft(&key), 1);
ExpectIntEQ(wc_LmsKey_GetKid(&key, &kid, &kidSz), 0);
ExpectIntEQ(kidSz, WC_LMS_I_LEN);
@@ -617,10 +618,72 @@ int test_wc_LmsKey_reload_devid_verify(void)
return EXPECT_RESULT();
}
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) && \
defined(WOLF_CRYPTO_CB) && defined(WOLF_PRIVATE_KEY_ID) && \
!defined(WOLF_CRYPTO_CB_ONLY_LMS)
static int test_lms_write_key_ok(const byte* priv, word32 privSz,
void* context)
{
(void)priv;
(void)privSz;
(void)context;
return WC_LMS_RC_SAVED_TO_NV_MEMORY;
}
#endif
/*
* Test that an LMS key named by id reports no signatures left, and is not
* signed with in software, when the device declines.
*/
int test_wc_LmsKey_id_sigsleft(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) && \
defined(WOLF_CRYPTO_CB) && defined(WOLF_PRIVATE_KEY_ID)
LmsKey key;
const byte id[] = { 0x01, 0x02, 0x03, 0x04 };
#ifndef WOLF_CRYPTO_CB_ONLY_LMS
byte msg[] = "test message for LMS signing";
byte* sig = NULL;
word32 sigSz = 0;
#endif
XMEMSET(&key, 0, sizeof(key));
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);
#ifndef WOLF_CRYPTO_CB_ONLY_LMS
ExpectIntEQ(wc_LmsKey_SetWriteCb(&key, test_lms_write_key_ok), 0);
#endif
ExpectIntEQ(wc_LmsKey_Reload(&key), 0);
ExpectIntEQ(wc_LmsKey_SigsLeft(&key), 0);
#ifndef WOLF_CRYPTO_CB_ONLY_LMS
ExpectIntEQ(wc_LmsKey_GetSigLen(&key, &sigSz), 0);
ExpectNotNull(sig = (byte*)XMALLOC(sigSz, NULL, DYNAMIC_TYPE_TMP_BUFFER));
if (sig != NULL) {
ExpectIntEQ(wc_LmsKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)),
WC_NO_ERR_TRACE(BAD_STATE_E));
}
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
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)) || \
(defined(WOLF_CRYPTO_CB_ONLY_XMSS) && !defined(WOLFSSL_SWDEV) && \
!defined(WOLFSSL_XMSS_VERIFY_ONLY) && \
defined(TEST_XMSS_H10_AVAILABLE)) || \
(defined(WOLFSSL_HAVE_XMSS) && !defined(WOLF_CRYPTO_CB_ONLY_XMSS) && \
!defined(WOLFSSL_XMSS_VERIFY_ONLY) && defined(TEST_XMSS_H10_AVAILABLE)))
/* An accelerator that generates keys and declines everything else. */
static int test_lms_xmss_keygen_cryptocb(int devIdArg, wc_CryptoInfo* info,
@@ -673,6 +736,86 @@ int test_wc_LmsKey_keygen_no_sigsleft(void)
return EXPECT_RESULT();
}
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) && \
!defined(WOLF_CRYPTO_CB_ONLY_LMS)
static int test_lms_read_key_fail(byte* priv, word32 privSz, void* context)
{
(void)priv;
(void)privSz;
(void)context;
return WC_LMS_RC_READ_FAIL;
}
static int test_lms_write_key_fail(const byte* priv, word32 privSz,
void* context)
{
(void)priv;
(void)privSz;
(void)context;
return WC_LMS_RC_WRITE_FAIL;
}
/* Upper bound on priv_data for the parameters test_lms_set_params uses. */
#define TEST_LMS_PRIV_DATA_LEN \
(LMS_PRIV_DATA_LEN(1, 10, 8, LMS_ROOT_LEVELS, LMS_CACHE_BITS, \
LMS_MAX_NODE_LEN) + HSS_MAX_PRIVATE_KEY_LEN)
#endif
/* An LMS key whose MakeKey failed to save has no private key to count from. */
int test_wc_LmsKey_makekey_fail_sigsleft(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) && \
!defined(WOLF_CRYPTO_CB_ONLY_LMS)
LmsKey key;
WC_RNG rng;
static byte privData[TEST_LMS_PRIV_DATA_LEN];
XMEMSET(&key, 0, sizeof(key));
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0);
key.priv_data = privData;
ExpectIntEQ(test_lms_set_params(&key), 0);
ExpectIntEQ(wc_LmsKey_SetWriteCb(&key, test_lms_write_key_fail), 0);
ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), WC_NO_ERR_TRACE(IO_FAILED_E));
ExpectIntEQ(wc_LmsKey_SigsLeft(&key), 0);
/* A caller-supplied buffer stays with the key for a retry. */
ExpectPtrEq(key.priv_data, privData);
key.priv_data = NULL;
wc_LmsKey_Free(&key);
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}
/* An LMS key whose Reload failed has no private key to count from. */
int test_wc_LmsKey_reload_fail_sigsleft(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) && \
!defined(WOLF_CRYPTO_CB_ONLY_LMS)
LmsKey key;
static byte privData[TEST_LMS_PRIV_DATA_LEN];
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0);
key.priv_data = privData;
ExpectIntEQ(test_lms_set_params(&key), 0);
ExpectIntEQ(wc_LmsKey_SetReadCb(&key, test_lms_read_key_fail), 0);
ExpectIntNE(wc_LmsKey_Reload(&key), 0);
ExpectIntEQ(wc_LmsKey_SigsLeft(&key), 0);
ExpectPtrEq(key.priv_data, privData);
key.priv_data = NULL;
wc_LmsKey_Free(&key);
#endif
return EXPECT_RESULT();
}
#if defined(WOLF_CRYPTO_CB_ONLY_LMS) && !defined(WOLFSSL_SWDEV) && \
!defined(WOLFSSL_LMS_VERIFY_ONLY)
static int test_lms_read_fail(byte* priv, word32 privSz, void* context)
@@ -859,6 +1002,7 @@ int test_wc_XmssKey_reload_devid(void)
ExpectIntEQ(wc_XmssKey_Reload(&key), 0);
/* The reload must have allocated the secret key, not been skipped. */
ExpectNotNull(key.sk);
ExpectIntEQ(wc_XmssKey_SigsLeft(&key), 1);
/* Sign with the reloaded key and verify with a software-only key. */
sigSz = sizeof(sig);
@@ -987,6 +1131,100 @@ int test_wc_XmssKey_reload_devid_verify(void)
return EXPECT_RESULT();
}
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) && \
defined(WOLF_CRYPTO_CB) && defined(TEST_XMSS_H10_AVAILABLE) && \
!defined(WOLF_CRYPTO_CB_ONLY_XMSS)
static enum wc_XmssRc test_xmss_write_key_ok(const byte* priv, word32 privSz,
void* context)
{
(void)priv;
(void)privSz;
(void)context;
return WC_XMSS_RC_SAVED_TO_NV_MEMORY;
}
static enum wc_XmssRc test_xmss_read_key_ok(byte* priv, word32 privSz,
void* context)
{
(void)priv;
(void)privSz;
(void)context;
return WC_XMSS_RC_READ_TO_MEMORY;
}
#endif
/*
* Test that an XMSS key generated on a device is not signed with in software
* when the device declines.
*/
int test_wc_XmssKey_keygen_sign_declined(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) && \
defined(WOLF_CRYPTO_CB) && defined(TEST_XMSS_H10_AVAILABLE) && \
!defined(WOLF_CRYPTO_CB_ONLY_XMSS)
XmssKey key;
WC_RNG rng;
byte msg[] = "test message for XMSS signing";
byte* sig = NULL;
word32 sigSz = 0;
XMEMSET(&key, 0, sizeof(key));
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_LMS_XMSS_CRYPTOCB_DEVID,
test_lms_xmss_keygen_cryptocb, NULL), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_XmssKey_Init(&key, NULL, TEST_LMS_XMSS_CRYPTOCB_DEVID), 0);
ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0);
ExpectIntEQ(wc_XmssKey_SetWriteCb(&key, test_xmss_write_key_ok), 0);
ExpectIntEQ(wc_XmssKey_SetReadCb(&key, test_xmss_read_key_ok), 0);
ExpectIntEQ(wc_XmssKey_MakeKey(&key, &rng), 0);
ExpectNull(key.sk);
ExpectIntEQ(wc_XmssKey_GetSigLen(&key, &sigSz), 0);
ExpectNotNull(sig = (byte*)XMALLOC(sigSz, NULL, DYNAMIC_TYPE_TMP_BUFFER));
if (sig != NULL) {
ExpectIntEQ(wc_XmssKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)),
WC_NO_ERR_TRACE(BAD_STATE_E));
}
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wc_XmssKey_Free(&key);
wc_FreeRng(&rng);
wc_CryptoCb_UnRegisterDevice(TEST_LMS_XMSS_CRYPTOCB_DEVID);
#endif
return EXPECT_RESULT();
}
/*
* Same scenario as test_wc_LmsKey_id_sigsleft, for XMSS.
*/
int test_wc_XmssKey_id_sigsleft(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) && \
defined(WOLF_CRYPTO_CB) && defined(TEST_XMSS_H10_AVAILABLE) && \
defined(WOLF_PRIVATE_KEY_ID)
XmssKey key;
const byte id[] = { 0x01, 0x02, 0x03, 0x04 };
XMEMSET(&key, 0, sizeof(key));
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_Reload(&key), 0);
ExpectIntEQ(wc_XmssKey_SigsLeft(&key), 0);
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

@@ -30,11 +30,16 @@ int test_wc_LmsKey_reload_cache(void);
int test_wc_LmsKey_reload_devid(void);
int test_wc_LmsKey_reload_no_pub(void);
int test_wc_LmsKey_reload_devid_verify(void);
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_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_cb_only_no_device(void);
int test_rfc9802_lms_x509_verify(void);
int test_rfc9802_xmss_x509_verify(void);
@@ -53,11 +58,16 @@ int test_wc_XmssFeatureCoverage(void);
TEST_DECL_GROUP("lms", test_wc_LmsKey_reload_devid), \
TEST_DECL_GROUP("lms", test_wc_LmsKey_reload_no_pub), \
TEST_DECL_GROUP("lms", test_wc_LmsKey_reload_devid_verify), \
TEST_DECL_GROUP("lms", test_wc_LmsKey_reload_fail_sigsleft), \
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_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_cb_only_no_device), \
TEST_DECL_GROUP("lms", test_rfc9802_lms_x509_verify), \
TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_verify), \

View File

@@ -1007,6 +1007,30 @@ int wc_LmsKey_GetParameters_ex(const LmsKey* key, int* levels, int* height,
return ret;
}
#ifndef WOLFSSL_LMS_VERIFY_ONLY
/* Wipe the private key held in software, keeping the priv_data buffer.
*
* @param [in, out] key LMS key.
*/
static void wc_lmskey_wipe_priv(LmsKey* key)
{
if (key->priv_data != NULL) {
const LmsParams* params = key->params;
word32 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
priv_data_len += HSS_PRIVATE_KEY_LEN(params->hash_len);
#endif
ForceZero(key->priv_data, priv_data_len);
}
ForceZero(key->priv_raw, sizeof(key->priv_raw));
ForceZero(&key->priv, sizeof(HssPrivKey));
key->privSet = 0;
}
#endif
/* Frees the LMS key from memory.
*
* This does not affect the private key saved to non-volatile storage.
@@ -1028,23 +1052,9 @@ void wc_LmsKey_Free(LmsKey* key)
}
#endif
#ifndef WOLFSSL_LMS_VERIFY_ONLY
if (key->priv_data != NULL) {
const LmsParams* params = key->params;
word32 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
priv_data_len += HSS_PRIVATE_KEY_LEN(key->params->hash_len);
#endif
ForceZero(key->priv_data, priv_data_len);
XFREE(key->priv_data, key->heap, DYNAMIC_TYPE_LMS);
key->priv_data = NULL;
}
ForceZero(key->priv_raw, HSS_MAX_PRIVATE_KEY_LEN);
key->privSet = 0;
ForceZero(&key->priv, sizeof(HssPrivKey));
wc_lmskey_wipe_priv(key);
XFREE(key->priv_data, key->heap, DYNAMIC_TYPE_LMS);
key->priv_data = NULL;
key->write_private_key = NULL;
key->read_private_key = NULL;
@@ -1304,6 +1314,9 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
if (rv != WC_LMS_RC_SAVED_TO_NV_MEMORY) {
ret = IO_FAILED_E;
}
else {
key->privSet = 1;
}
}
/* This should not happen, but check whether signatures can be created. */
@@ -1313,11 +1326,14 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
ret = BAD_STATE_E;
}
if ((ret != 0) && (priv_data_len > 0)) {
wc_lmskey_wipe_priv(key);
}
if (ret == 0) {
/* Update state. */
key->state = WC_LMS_STATE_OK;
key->pubSet = 1;
key->privSet = 1;
}
#endif /* WOLF_CRYPTO_CB_ONLY_LMS */
@@ -1431,6 +1447,9 @@ int wc_LmsKey_Reload(LmsKey* key)
HSS_PRIVATE_KEY_LEN(params->hash_len));
}
#endif
if (ret == 0) {
key->privSet = 1;
}
}
/* Double check the key actually has signatures left. */
@@ -1461,10 +1480,13 @@ int wc_LmsKey_Reload(LmsKey* key)
}
}
if ((ret != 0) && (priv_data_len > 0)) {
wc_lmskey_wipe_priv(key);
}
if (ret == 0) {
/* Update state. */
key->state = WC_LMS_STATE_OK;
key->privSet = 1;
}
#endif /* WOLF_CRYPTO_CB_ONLY_LMS */
@@ -1595,6 +1617,10 @@ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg,
WOLFSSL_MSG("error: LmsKey write/read callbacks are not set");
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (!key->privSet)) {
WOLFSSL_MSG("error: LMS private key not held in software");
ret = BAD_STATE_E;
}
if (ret == 0) {
WC_DECLARE_VAR(state, LmsState, 1, 0);
@@ -1671,6 +1697,7 @@ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg,
* @return 1 if there are signatures remaining.
* @return 0 if available signatures are exhausted, or the key is NULL, has
* no parameters set or is verify-only.
* @return 0 when the device declines and software holds no private key.
*/
int wc_LmsKey_SigsLeft(LmsKey* key)
{
@@ -1697,14 +1724,14 @@ int wc_LmsKey_SigsLeft(LmsKey* key)
WOLFSSL_MSG("PqcStatefulSigSigsLeft returned an error");
return 0;
}
/* Cryptocb declined. priv_raw reflects software state from the
* CRYPTOCB_UNAVAILABLE fall-through in MakeKey/Reload, so the
* software check below is valid. */
WOLFSSL_MSG("LMS SigsLeft not supported by device, using software");
}
#endif
#ifndef WOLF_CRYPTO_CB_ONLY_LMS
ret = wc_hss_sigsleft(key->params, key->priv_raw);
/* Only a software MakeKey or Reload fills priv_raw. */
if (key->privSet) {
ret = wc_hss_sigsleft(key->params, key->priv_raw);
}
#endif
}

View File

@@ -1593,6 +1593,10 @@ int wc_XmssKey_Sign(XmssKey* key, byte* sig, word32* sigLen, const byte* msg,
WOLFSSL_MSG("error: XmssKey write/read callbacks are not set");
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->sk == NULL)) {
WOLFSSL_MSG("error: XMSS secret key not held in software");
ret = BAD_STATE_E;
}
if (ret == 0) {
*sigLen = key->params->sig_len;
@@ -1609,6 +1613,7 @@ int wc_XmssKey_Sign(XmssKey* key, byte* sig, word32* sigLen, const byte* msg,
* @param [in] key XMSS key to check.
* @return 1 when signatures possible.
* @return 0 when key exhausted.
* @return 0 when the device declines and software holds no private key.
*/
int wc_XmssKey_SigsLeft(XmssKey* key)
{
@@ -1635,9 +1640,6 @@ int wc_XmssKey_SigsLeft(XmssKey* key)
WOLFSSL_MSG("PqcStatefulSigSigsLeft returned an error");
return 0;
}
/* Cryptocb declined. Fall through to the software path: state
* reflects the CRYPTOCB_UNAVAILABLE fall-through in MakeKey/Reload,
* and read_private_key can repopulate sk from NV storage. */
WOLFSSL_MSG("XMSS SigsLeft not supported by device, using software");
}
#endif
@@ -1652,6 +1654,11 @@ int wc_XmssKey_SigsLeft(XmssKey* key)
WOLFSSL_MSG("error: can't sign, XMSS key not in good state");
ret = 0;
}
/* A key held by a device has no secret key in software. */
else if ((key->sk == NULL) || (key->read_private_key == NULL)) {
WOLFSSL_MSG("error: XMSS secret key not held in software");
ret = 0;
}
/* Read the current secret key from NV storage.*/
else if (key->read_private_key(key->sk, key->sk_len, key->context) !=
WC_XMSS_RC_READ_TO_MEMORY) {