Address PR comments

This commit is contained in:
Paul Adelsbach
2026-05-05 13:03:56 -07:00
parent b9eb7c1ff8
commit 7906e67c14
3 changed files with 135 additions and 364 deletions
-186
View File
@@ -1,186 +0,0 @@
# LMS / XMSS Crypto Callback support
This document describes the wolfSSL-side groundwork that lets LMS / HSS
(RFC 8554) and XMSS / XMSS^MT (RFC 8391, both profiled in NIST SP 800-208)
participate in the `WOLF_CRYPTO_CB` framework. With this layer in place, the
wolfSSL PKCS#11 provider and the wolfHSM client can host stateful
hash-based keys on a device without the wolfSSL public API changing.
No HSM-side or PKCS#11-provider code lives in this layer. It only adds the
dispatcher surface, the per-key device binding, and the helpers a backend
needs to answer the request.
## Why route stateful hash-based keys through a device
LMS and XMSS are one-time-signature trees: the private key holds a counter
that must be incremented on every signature, and signing the same index twice
breaks the security proof. Moving that counter to a hardware module is the
clean way to make the scheme operationally safe — the HSM is the natural
owner of the index, and an attacker who steals a host snapshot cannot replay
old indices.
## PKCS#11 mapping
PKCS#11 v3.1 standardised HSS and v3.2 added XMSS / XMSS^MT. The CryptoCb
surface mirrors what those mechanisms expose:
| wolfSSL API | PKCS#11 analog | CryptoCb dispatcher |
|-----------------------|------------------------------------------------|----------------------------------------------|
| `wc_LmsKey_MakeKey` | `CKM_HSS_KEY_PAIR_GEN` | `wc_CryptoCb_PqcStatefulSigKeyGen` |
| `wc_LmsKey_Sign` | `CKM_HSS` (sign) | `wc_CryptoCb_PqcStatefulSigSign` |
| `wc_LmsKey_Verify` | `CKM_HSS` (verify) | `wc_CryptoCb_PqcStatefulSigVerify` |
| `wc_LmsKey_SigsLeft` | `CKA_HSS_KEYS_REMAINING` attribute | `wc_CryptoCb_PqcStatefulSigSigsLeft` |
| `wc_XmssKey_MakeKey` | `CKM_XMSS_KEY_PAIR_GEN` / `CKM_XMSSMT_KEY_PAIR_GEN` | `wc_CryptoCb_PqcStatefulSigKeyGen` |
| `wc_XmssKey_Sign` | `CKM_XMSS` / `CKM_XMSSMT` (sign) | `wc_CryptoCb_PqcStatefulSigSign` |
| `wc_XmssKey_Verify` | `CKM_XMSS` / `CKM_XMSSMT` (verify) | `wc_CryptoCb_PqcStatefulSigVerify` |
| `wc_XmssKey_SigsLeft` | XMSS remaining-sigs attribute | `wc_CryptoCb_PqcStatefulSigSigsLeft` |
The four dispatchers are shared between LMS and XMSS, following the
`wc_CryptoCb_PqcSign*` family used for Dilithium and Falcon. A new
discriminator enum `wc_PqcStatefulSignatureType` (`WC_PQC_STATEFUL_SIG_TYPE_LMS`,
`WC_PQC_STATEFUL_SIG_TYPE_XMSS`) tells the callback which of `LmsKey*` or
`XmssKey*` the `void* key` field is. XMSS vs XMSS^MT is decided inside the
callback via the existing `XmssKey::is_xmssmt` field.
`Reload`, `GetKid`, and `ExportPub` are not routed through CryptoCb, but each
is aware of HSM-backed keys: `Reload` short-circuits because state lives in
the device, `GetKid` logs a warning since `priv_raw` may be uninitialised,
and a new `ExportPub_ex` variant lets the caller bind the verify-only copy
to a `heap` / `devId` of their choosing so it dispatches through the same
device as the signing key. The external-backend variants (`ext_lms.c` /
`ext_xmss.c`, selected by `--with-liblms` / `--with-libxmss`) are
intentionally outside the scope of this layer and execute purely in
software.
## Per-key device binding
Each key carries the device-binding fields that other key types
(`RsaKey`, `ecc_key`, `dilithium_key`) already expose:
```c
struct LmsKey {
/* ... existing fields ... */
#ifdef WOLF_CRYPTO_CB
int devId; /* device identifier */
void* devCtx; /* opaque per-device state, owned by the callback */
#endif
#ifdef WOLF_PRIVATE_KEY_ID
byte id[LMS_MAX_ID_LEN]; /* device-side key identifier */
int idLen;
char label[LMS_MAX_LABEL_LEN]; /* device-side key label */
int labelLen;
#endif
};
```
`XmssKey` carries the equivalent set under the same macro guards, with
`XMSS_MAX_ID_LEN` / `XMSS_MAX_LABEL_LEN`. The `*_MAX_ID_LEN` and
`*_MAX_LABEL_LEN` constants default to 32 and can be overridden by
predefining the macros.
`devCtx`, `id`, and `label` are storage only — wolfSSL never reads or writes
them internally. Backends populate `devCtx` from the callback (typically the
first time they touch the key) and consume `id` / `label` to resolve the
on-device handle.
## Public API additions
```c
/* Bind a key to a device-side identifier or label. */
#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_XmssKey_InitId (XmssKey* key, const unsigned char* id,
int len, void* heap, int devId);
WOLFSSL_API int wc_XmssKey_InitLabel(XmssKey* key, const char* label,
void* heap, int devId);
#endif
/* Hash a message according to the given algorithm. */
WOLFSSL_API int wc_LmsKey_HashMsg (const LmsKey * key, const byte * msg,
word32 msgSz, byte * hash,
word32 * hashSz);
WOLFSSL_API int wc_XmssKey_HashMsg(const XmssKey* key, const byte* msg,
word32 msgSz, byte* hash,
word32* hashSz);
/* Export a public key into a verify-only key with explicit heap and
* device bindings. */
WOLFSSL_API int wc_LmsKey_ExportPub_ex (LmsKey * keyDst,
const LmsKey * keySrc,
void * heap, int devId);
WOLFSSL_API int wc_XmssKey_ExportPub_ex(XmssKey* keyDst,
const XmssKey* keySrc,
void* heap, int devId);
```
The `Init*` helpers follow the `wc_InitRsaKey_Id` / `wc_InitRsaKey_Label`
shape: they validate length bounds, delegate the rest of init to
`wc_LmsKey_Init` / `wc_XmssKey_Init`, then copy id / label onto the key.
The `HashMsg` helpers honour the parameter set:
| Algorithm | Hash families covered |
|-----------|-----------------------------------------------------------------|
| LMS / HSS | SHA-256 (32 bytes), SHA-256/192 (24 bytes), SHAKE256 (32 / 24) |
| XMSS / MT | SHA-256, SHA-512, SHAKE128, SHAKE256 (per `params->hash`) |
`*hashSz` is in / out: callers pass the buffer size and receive the digest
length on success.
## Sign / verify input format
The CryptoCb dispatcher forwards the raw message to the callback. PKCS#11
v3.2 section 6.66.8 ("XMSS and XMSSMT without hashing") and the analogous
text for HSS specify that those mechanisms take a pre-computed digest
rather than the message. Backends that need that behaviour — typically
PKCS#11 providers — call `wc_LmsKey_HashMsg` or `wc_XmssKey_HashMsg` from
inside the callback to produce the algorithm-dictated digest. Backends
that take the full message (typically wolfHSM) consume `msg` / `msgSz`
directly. Picking one or the other is a callback decision; the dispatcher
is agnostic.
## Build configuration
| `./configure` flag(s) | Effect |
|--------------------------------------------------------|-------------------------------------------------------|
| `--enable-lms --enable-xmss --enable-cryptocb` | Primary target. Full dispatcher and round-trip tests. |
| `--enable-lms --enable-xmss` | New dispatcher code is fully `#ifdef`-elided. |
| `--enable-cryptocb` | LMS / XMSS-less build; nothing CryptoCb-side breaks. |
| `CPPFLAGS=-DWOLF_PRIVATE_KEY_ID …` | Adds `id` / `label` fields and the `Init*` helpers. |
## Verification
`./wolfcrypt/test/testwolfcrypt` exercises the full dispatcher round trip:
inside `cryptocb_test`, `lms_test` and `xmss_test` run with the harness's
registered `myCryptoDevCb`, which clears the key's `devId`, invokes the
software API recursively, then restores `devId`. Sign and verify both go
through the dispatcher, so the produced signatures self-verify within the
harness. With no device registered, `lms_test` and `xmss_test` remain on the
software path and produce bit-identical KAT output.
## Design notes
- **Shared dispatcher, separate type tag.** The eight LMS / XMSS operations
collapse to four shared dispatchers (`KeyGen`, `Sign`, `Verify`,
`SigsLeft`) keyed on `wc_PqcStatefulSignatureType`. The pattern matches
the `PqcSign` family used for Dilithium / Falcon and reduces the surface
area a backend has to implement.
- **Verify carries `int* res`.** Following the Ed25519 / ECC / PqcVerify
convention, the verify dispatcher reports validity through a separate
`*res` flag, so a backend can distinguish a transport error from a
forged signature. The wrapping wolfSSL function still translates
`res != 1` to `SIG_VERIFY_E` for callers that do not see `res`.
- **`SigsLeft` carries `word32* sigsLeft`.** PKCS#11 defines
`CKA_HSS_KEYS_REMAINING` as a `CK_ULONG`-sized attribute; the callback
uses `word32*` so an HSS key at its 2^32 limit can be expressed
unambiguously. The wolfSSL public API still returns `int` and clamps at
`0x7FFFFFFF`.
- **HSM-backed keys skip the software write / read callbacks.**
`wc_LmsKey_MakeKey` / `_Sign` and the XMSS equivalents dispatch through
CryptoCb *before* validating `write_private_key` / `read_private_key` /
`context`. A device-backed key does not need dummy software callbacks.
On `CRYPTOCB_UNAVAILABLE` fall-through the software validations are
re-applied as normal.
+61 -79
View File
@@ -41,73 +41,6 @@
#include <wolfssl/wolfcrypt/cryptocb.h>
#endif
/* Compute the digest of msg using the hash function dictated by the LMS
* parameter set. Crypto-callback / HSM backends that follow PKCS#11 v3.2
* CKM_HSS semantics (pre-computed digest input) can call this from within
* their callback; backends that take the raw message (e.g. wolfHSM) can
* ignore it. *hashSz is in/out: it must be at least params->hash_len on
* entry and is set to the actual digest length on success.
*
* @param [in] key LMS key (must have a parameter set bound).
* @param [in] msg Message to hash.
* @param [in] msgSz Length of msg in bytes.
* @param [out] hash Buffer receiving the digest.
* @param [in,out] hashSz On entry, size of hash buffer. On success,
* the digest length.
* @return 0 on success.
* @return BAD_FUNC_ARG when an argument is NULL or the buffer is too
* small for the digest.
* @return NOT_COMPILED_IN when the param set's hash family is disabled.
*/
int wc_LmsKey_HashMsg(const LmsKey* key, const byte* msg, word32 msgSz,
byte* hash, word32* hashSz)
{
int ret = 0;
word32 needSz;
if ((key == NULL) || (msg == NULL) || (hash == NULL) || (hashSz == NULL))
return BAD_FUNC_ARG;
if (key->params == NULL)
return BAD_FUNC_ARG;
needSz = (word32)key->params->hash_len;
if (*hashSz < needSz)
return BAD_FUNC_ARG;
switch (key->params->lmsType & 0xF000) {
case LMS_SHA256: /* 32-byte SHA-256 */
case LMS_SHA256_192: /* SHA-256 truncated to 24 bytes */ {
byte full[WC_SHA256_DIGEST_SIZE];
ret = wc_Sha256Hash(msg, msgSz, full);
if (ret == 0)
XMEMCPY(hash, full, needSz);
break;
}
#ifdef WOLFSSL_LMS_SHAKE256
case LMS_SHAKE256: /* SHAKE256 with 32-byte output */
case LMS_SHAKE256_192: /* SHAKE256 with 24-byte output */ {
wc_Shake shake;
ret = wc_InitShake256(&shake, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_Shake256_Update(&shake, msg, msgSz);
if (ret == 0)
ret = wc_Shake256_Final(&shake, hash, needSz);
wc_Shake256_Free(&shake);
}
break;
}
#endif
default:
WOLFSSL_MSG("LMS: unsupported hash family for HashMsg");
ret = NOT_COMPILED_IN;
break;
}
if (ret == 0)
*hashSz = needSz;
return ret;
}
/* Calculate u. Appendix B. Works for w of 1, 2, 4, or 8.
*
@@ -1134,10 +1067,6 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
WOLFSSL_MSG("error: LmsKey write callback is not set");
ret = BAD_FUNC_ARG;
}
/* Callback context is opaque to wolfCrypt and may legitimately be NULL
* (e.g. callbacks that read/write a static buffer or HSM-backed keys
* with stub callbacks); no check needed here. */
if (ret == 0) {
const LmsParams* params = key->params;
priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height,
@@ -1250,7 +1179,6 @@ int wc_LmsKey_Reload(LmsKey* key)
WOLFSSL_MSG("error: LmsKey read callback is not set");
ret = BAD_FUNC_ARG;
}
/* Callback context is opaque; NULL is allowed. */
if (ret == 0) {
const LmsParams* params = key->params;
@@ -1354,6 +1282,66 @@ int wc_LmsKey_GetPrivLen(const LmsKey* key, word32* len)
return ret;
}
/* Compute the digest of msg using the hash function dictated by the LMS
* parameter set. Crypto-callback / HSM backends that follow PKCS#11 v3.2
* CKM_HSS semantics (pre-computed digest input) can call this from within
* their callback; backends that take the raw message (e.g. wolfHSM) can
* ignore it. *hashSz is in/out: it must be at least params->hash_len on
* entry and is set to the actual digest length on success.
*
* @param [in] key LMS key (must have a parameter set bound).
* @param [in] msg Message to hash.
* @param [in] msgSz Length of msg in bytes.
* @param [out] hash Buffer receiving the digest.
* @param [in,out] hashSz On entry, size of hash buffer. On success,
* the digest length.
* @return 0 on success.
* @return BAD_FUNC_ARG when an argument is NULL or the buffer is too
* small for the digest.
* @return NOT_COMPILED_IN when the param set's hash family is disabled.
*/
int wc_LmsKey_HashMsg(const LmsKey* key, const byte* msg, word32 msgSz,
byte* hash, word32* hashSz)
{
int ret = 0;
word32 needSz;
if ((key == NULL) || (msg == NULL) || (hash == NULL) || (hashSz == NULL))
return BAD_FUNC_ARG;
if (key->params == NULL)
return BAD_FUNC_ARG;
needSz = (word32)key->params->hash_len;
if (*hashSz < needSz)
return BAD_FUNC_ARG;
switch (key->params->lmsType & LMS_HASH_MASK) {
case LMS_SHA256: /* 32-byte SHA-256 */
case LMS_SHA256_192: /* SHA-256 truncated to 24 bytes */ {
byte full[WC_SHA256_DIGEST_SIZE];
ret = wc_Sha256Hash(msg, msgSz, full);
if (ret == 0)
XMEMCPY(hash, full, needSz);
break;
}
#ifdef WOLFSSL_LMS_SHAKE256
case LMS_SHAKE256: /* SHAKE256 with 32-byte output */
case LMS_SHAKE256_192: /* SHAKE256 with 24-byte output */ {
ret = wc_Shake256Hash(msg, msgSz, hash, needSz);
break;
}
#endif
default:
WOLFSSL_MSG("LMS: unsupported hash family for HashMsg");
ret = NOT_COMPILED_IN;
break;
}
if (ret == 0)
*hashSz = needSz;
return ret;
}
/* Sign a message.
*
* @param [in, out] key LMS key to sign with.
@@ -1419,7 +1407,6 @@ 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;
}
/* Callback context is opaque; NULL is allowed. */
if (ret == 0) {
WC_DECLARE_VAR(state, LmsState, 1, 0);
@@ -1493,9 +1480,7 @@ int wc_LmsKey_SigsLeft(LmsKey* key)
int cbRet = wc_CryptoCb_PqcStatefulSigSigsLeft(
WC_PQC_STATEFUL_SIG_TYPE_LMS, key, &sigsLeft);
if (cbRet == 0) {
/* Clamp to int range; callers treat 0 as "exhausted". */
return (sigsLeft > (word32)0x7FFFFFFF)
? 0x7FFFFFFF : (int)sigsLeft;
return (sigsLeft != 0) ? 1 : 0;
}
/* The device owns the private state; no safe software fallback
* exists because key->priv_raw does not reflect HSM state. */
@@ -1734,9 +1719,6 @@ int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz,
if ((key == NULL) || (sig == NULL) || (msg == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (msgSz <= 0)) {
ret = BAD_FUNC_ARG;
}
/* Check state. */
if ((ret == 0) && (key->state != WC_LMS_STATE_OK) &&
(key->state != WC_LMS_STATE_VERIFYONLY)) {
+74 -99
View File
@@ -41,96 +41,6 @@
#include <wolfssl/wolfcrypt/cryptocb.h>
#endif
/* Compute the digest of msg using the hash function dictated by the XMSS
* parameter set. Crypto-callback / HSM backends that follow PKCS#11 v3.2
* CKM_XMSS / CKM_XMSSMT semantics (pre-computed digest input, see section
* 6.66.8 "XMSS and XMSSMT without hashing") can call this from within
* their callback; backends that take the raw message (e.g. wolfHSM) can
* ignore it. *hashSz is in/out: it must be at least params->n on entry
* and is set to the actual digest length on success.
*
* @param [in] key XMSS key (must have a parameter set bound).
* @param [in] msg Message to hash.
* @param [in] msgSz Length of msg in bytes.
* @param [out] hash Buffer receiving the digest.
* @param [in,out] hashSz On entry, size of hash buffer. On success,
* the digest length.
* @return 0 on success.
* @return BAD_FUNC_ARG when an argument is NULL or the buffer is too
* small for the digest.
* @return NOT_COMPILED_IN when the param set's hash family is disabled.
*/
int wc_XmssKey_HashMsg(const XmssKey* key, const byte* msg, word32 msgSz,
byte* hash, word32* hashSz)
{
int ret = 0;
word32 needSz;
if ((key == NULL) || (msg == NULL) || (hash == NULL) || (hashSz == NULL))
return BAD_FUNC_ARG;
if (key->params == NULL)
return BAD_FUNC_ARG;
needSz = (word32)key->params->n;
if (*hashSz < needSz)
return BAD_FUNC_ARG;
switch (key->params->hash) {
#ifdef WC_XMSS_SHA256
case WC_HASH_TYPE_SHA256: {
/* SHA2_*_192 variants set n=24, but wc_Hash rejects an output
* smaller than WC_SHA256_DIGEST_SIZE. Hash to a full buffer and
* copy the requested prefix, mirroring LMS_SHA256_192. */
byte full[WC_SHA256_DIGEST_SIZE];
ret = wc_Sha256Hash(msg, msgSz, full);
if (ret == 0)
XMEMCPY(hash, full, needSz);
break;
}
#endif
#ifdef WC_XMSS_SHA512
case WC_HASH_TYPE_SHA512:
ret = wc_Hash(WC_HASH_TYPE_SHA512, msg, msgSz, hash, needSz);
break;
#endif
#ifdef WC_XMSS_SHAKE128
case WC_HASH_TYPE_SHAKE128: {
wc_Shake shake;
ret = wc_InitShake128(&shake, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_Shake128_Update(&shake, msg, msgSz);
if (ret == 0)
ret = wc_Shake128_Final(&shake, hash, needSz);
wc_Shake128_Free(&shake);
}
break;
}
#endif
#ifdef WC_XMSS_SHAKE256
case WC_HASH_TYPE_SHAKE256: {
wc_Shake shake;
ret = wc_InitShake256(&shake, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_Shake256_Update(&shake, msg, msgSz);
if (ret == 0)
ret = wc_Shake256_Final(&shake, hash, needSz);
wc_Shake256_Free(&shake);
}
break;
}
#endif
default:
WOLFSSL_MSG("XMSS: unsupported hash for HashMsg");
ret = NOT_COMPILED_IN;
break;
}
if (ret == 0)
*hashSz = needSz;
return ret;
}
/***************************
* DIGEST init and free.
***************************/
@@ -1316,10 +1226,6 @@ int wc_XmssKey_MakeKey(XmssKey* key, WC_RNG* rng)
WOLFSSL_MSG("error: XmssKey write callback is not set");
ret = BAD_FUNC_ARG;
}
/* Callback context is opaque to wolfCrypt and may legitimately be NULL
* (e.g. callbacks that read/write a static buffer or HSM-backed keys
* with stub callbacks); no check needed here. */
if (ret == 0) {
/* Allocate sk array. */
ret = wc_xmsskey_alloc_sk(key);
@@ -1450,7 +1356,6 @@ int wc_XmssKey_Reload(XmssKey* key)
WOLFSSL_MSG("error: XmssKey write/read callbacks are not set");
ret = BAD_FUNC_ARG;
}
/* Callback context is opaque; NULL is allowed. */
if (ret == 0) {
/* Allocate sk array. */
@@ -1516,6 +1421,79 @@ int wc_XmssKey_GetPrivLen(const XmssKey* key, word32* len)
return ret;
}
/* Compute the digest of msg using the hash function dictated by the XMSS
* parameter set. Crypto-callback / HSM backends that follow PKCS#11 v3.2
* CKM_XMSS / CKM_XMSSMT semantics (pre-computed digest input, see section
* 6.66.8 "XMSS and XMSSMT without hashing") can call this from within
* their callback; backends that take the raw message (e.g. wolfHSM) can
* ignore it. *hashSz is in/out: it must be at least params->n on entry
* and is set to the actual digest length on success.
*
* @param [in] key XMSS key (must have a parameter set bound).
* @param [in] msg Message to hash.
* @param [in] msgSz Length of msg in bytes.
* @param [out] hash Buffer receiving the digest.
* @param [in,out] hashSz On entry, size of hash buffer. On success,
* the digest length.
* @return 0 on success.
* @return BAD_FUNC_ARG when an argument is NULL or the buffer is too
* small for the digest.
* @return NOT_COMPILED_IN when the param set's hash family is disabled.
*/
int wc_XmssKey_HashMsg(const XmssKey* key, const byte* msg, word32 msgSz,
byte* hash, word32* hashSz)
{
int ret = 0;
word32 needSz;
if ((key == NULL) || (msg == NULL) || (hash == NULL) || (hashSz == NULL))
return BAD_FUNC_ARG;
if (key->params == NULL)
return BAD_FUNC_ARG;
needSz = (word32)key->params->n;
if (*hashSz < needSz)
return BAD_FUNC_ARG;
switch (key->params->hash) {
#ifdef WC_XMSS_SHA256
case WC_HASH_TYPE_SHA256: {
/* SHA2_*_192 variants set n=24, but wc_Hash rejects an output
* smaller than WC_SHA256_DIGEST_SIZE. Hash to a full buffer and
* copy the requested prefix. */
byte full[WC_SHA256_DIGEST_SIZE];
ret = wc_Sha256Hash(msg, msgSz, full);
if (ret == 0)
XMEMCPY(hash, full, needSz);
break;
}
#endif
#ifdef WC_XMSS_SHA512
case WC_HASH_TYPE_SHA512:
ret = wc_Hash(WC_HASH_TYPE_SHA512, msg, msgSz, hash, needSz);
break;
#endif
#ifdef WC_XMSS_SHAKE128
case WC_HASH_TYPE_SHAKE128:
ret = wc_Shake128Hash(msg, msgSz, hash, needSz);
break;
#endif
#ifdef WC_XMSS_SHAKE256
case WC_HASH_TYPE_SHAKE256:
ret = wc_Shake256Hash(msg, msgSz, hash, needSz);
break;
#endif
default:
WOLFSSL_MSG("XMSS: unsupported hash for HashMsg");
ret = NOT_COMPILED_IN;
break;
}
if (ret == 0)
*hashSz = needSz;
return ret;
}
/* Sign the message using the XMSS secret key.
*
* @param [in] key XMSS key to use to sign.
@@ -1582,7 +1560,6 @@ 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;
}
/* Callback context is opaque; NULL is allowed. */
if (ret == 0) {
*sigLen = key->params->sig_len;
@@ -1613,9 +1590,7 @@ int wc_XmssKey_SigsLeft(XmssKey* key)
int cbRet = wc_CryptoCb_PqcStatefulSigSigsLeft(
WC_PQC_STATEFUL_SIG_TYPE_XMSS, key, &sigsLeft);
if (cbRet == 0) {
/* Clamp to int range; callers treat 0 as "exhausted". */
return (sigsLeft > (word32)0x7FFFFFFF)
? 0x7FFFFFFF : (int)sigsLeft;
return (sigsLeft != 0) ? 1 : 0;
}
/* The device owns the private state; no safe software fallback
* exists because key->sk does not reflect HSM state. */