Skip to content

Commit 29f534f

Browse files
authored
Merge pull request #8836 from SparkiDev/lms_serialize_state
LMS: Allow state to be saved with private key
2 parents 38892fd + d05790e commit 29f534f

5 files changed

Lines changed: 130 additions & 39 deletions

File tree

.wolfssl_known_macro_extras

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,8 @@ WOLFSSL_USE_FLASHMEM
864864
WOLFSSL_USE_OPTIONS_H
865865
WOLFSSL_USE_POPEN_HOST
866866
WOLFSSL_VALIDATE_DH_KEYGEN
867+
WOLFSSL_WC_LMS_SERIALIZE_STATE
868+
WOLFSSL_WC_MLKEM
867869
WOLFSSL_WC_XMSS_NO_SHA256
868870
WOLFSSL_WC_XMSS_NO_SHAKE256
869871
WOLFSSL_WICED_PSEUDO_UNIX_EPOCH_TIME

wolfcrypt/benchmark/benchmark.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9876,6 +9876,7 @@ void bench_mlkem(int type)
98769876
#endif
98779877

98789878
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
9879+
#ifndef WOLFSSL_WC_LMS_SERIALIZE_STATE
98799880
#ifndef WOLFSSL_NO_LMS_SHA256_256
98809881
/* WC_LMS_PARM_L2_H10_W2
98819882
* signature length: 9300 */
@@ -10033,6 +10034,7 @@ static const byte lms_pub_L4_H5_W8[60] =
1003310034
0x74,0x24,0x12,0xC8
1003410035
};
1003510036
#endif
10037+
#endif /* WOLFSSL_WC_LMS_SERIALIZE_STATE */
1003610038

1003710039
static int lms_write_key_mem(const byte* priv, word32 privSz, void* context)
1003810040
{
@@ -10050,7 +10052,11 @@ static int lms_read_key_mem(byte* priv, word32 privSz, void* context)
1005010052
XMEMCPY(priv, context, privSz);
1005110053
return WC_LMS_RC_READ_TO_MEMORY;
1005210054
}
10055+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
10056+
static byte lms_priv[64*1024 + HSS_MAX_PRIVATE_KEY_LEN];
10057+
#else
1005310058
static byte lms_priv[HSS_MAX_PRIVATE_KEY_LEN];
10059+
#endif
1005410060

1005510061
static void bench_lms_keygen(enum wc_LmsParm parm, byte* pub)
1005610062
{
@@ -10192,6 +10198,7 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub)
1019210198
goto exit_lms_sign_verify;
1019310199
}
1019410200

10201+
#ifndef WOLFSSL_WC_LMS_SERIALIZE_STATE
1019510202
switch (parm) {
1019610203
#ifndef WOLFSSL_NO_LMS_SHA256_256
1019710204
case WC_LMS_PARM_L2_H10_W2:
@@ -10283,6 +10290,9 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub)
1028310290
XMEMCPY(key.pub, pub, HSS_MAX_PUBLIC_KEY_LEN);
1028410291
break;
1028510292
}
10293+
#else
10294+
XMEMCPY(key.pub, pub, HSS_MAX_PUBLIC_KEY_LEN);
10295+
#endif
1028610296

1028710297
ret = wc_LmsKey_SetWriteCb(&key, lms_write_key_mem);
1028810298
if (ret) {

wolfcrypt/src/wc_lms.c

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -586,11 +586,14 @@ void wc_LmsKey_Free(LmsKey* key)
586586
#ifndef WOLFSSL_LMS_VERIFY_ONLY
587587
if (key->priv_data != NULL) {
588588
const LmsParams* params = key->params;
589-
590-
ForceZero(key->priv_data, LMS_PRIV_DATA_LEN(params->levels,
589+
int priv_data_len = LMS_PRIV_DATA_LEN(params->levels,
591590
params->height, params->p, params->rootLevels,
592-
params->cacheBits, params->hash_len));
591+
params->cacheBits, params->hash_len);
593592

593+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
594+
priv_data_len += HSS_PRIVATE_KEY_LEN(key->params->hash_len);
595+
#endif
596+
ForceZero(key->priv_data, priv_data_len);
594597
XFREE(key->priv_data, key->heap, DYNAMIC_TYPE_LMS);
595598
}
596599
#endif
@@ -717,6 +720,7 @@ int wc_LmsKey_SetContext(LmsKey* key, void* context)
717720
int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
718721
{
719722
int ret = 0;
723+
int priv_data_len = 0;
720724

721725
/* Validate parameters. */
722726
if ((key == NULL) || (rng == NULL)) {
@@ -738,17 +742,26 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
738742
ret = BAD_FUNC_ARG;
739743
}
740744

741-
if ((ret == 0) && (key->priv_data == NULL)) {
745+
if (ret == 0) {
742746
const LmsParams* params = key->params;
747+
priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height,
748+
params->p, params->rootLevels, params->cacheBits, params->hash_len);
743749

750+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
751+
priv_data_len += HSS_PRIVATE_KEY_LEN(key->params->hash_len);
752+
#endif
753+
}
754+
if ((ret == 0) && (key->priv_data == NULL)) {
744755
/* Allocate memory for the private key data. */
745-
key->priv_data = (byte *)XMALLOC(LMS_PRIV_DATA_LEN(params->levels,
746-
params->height, params->p, params->rootLevels, params->cacheBits,
747-
params->hash_len), key->heap, DYNAMIC_TYPE_LMS);
756+
key->priv_data = (byte *)XMALLOC(priv_data_len, key->heap,
757+
DYNAMIC_TYPE_LMS);
748758
/* Check pointer is valid. */
749759
if (key->priv_data == NULL) {
750760
ret = MEMORY_E;
751761
}
762+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
763+
XMEMSET(key->priv_data, 0, priv_data_len);
764+
#endif
752765
}
753766
if (ret == 0) {
754767
#ifdef WOLFSSL_SMALL_STACK
@@ -759,7 +772,8 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
759772

760773
#ifdef WOLFSSL_SMALL_STACK
761774
/* Allocate memory for working state. */
762-
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL, DYNAMIC_TYPE_TMP_BUFFER);
775+
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL,
776+
DYNAMIC_TYPE_TMP_BUFFER);
763777
if (state == NULL) {
764778
ret = MEMORY_E;
765779
}
@@ -781,9 +795,18 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
781795
}
782796
}
783797
if (ret == 0) {
798+
int rv;
784799
/* Write private key to storage. */
785-
int rv = key->write_private_key(key->priv_raw,
800+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
801+
XMEMCPY(key->priv_data + priv_data_len -
802+
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->priv_raw,
803+
HSS_PRIVATE_KEY_LEN(key->params->hash_len));
804+
rv = key->write_private_key(key->priv_data, priv_data_len,
805+
key->context);
806+
#else
807+
rv = key->write_private_key(key->priv_raw,
786808
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context);
809+
#endif
787810
if (rv != WC_LMS_RC_SAVED_TO_NV_MEMORY) {
788811
ret = IO_FAILED_E;
789812
}
@@ -816,6 +839,7 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
816839
int wc_LmsKey_Reload(LmsKey* key)
817840
{
818841
int ret = 0;
842+
int priv_data_len = 0;
819843

820844
/* Validate parameter. */
821845
if (key == NULL) {
@@ -837,25 +861,46 @@ int wc_LmsKey_Reload(LmsKey* key)
837861
ret = BAD_FUNC_ARG;
838862
}
839863

840-
if ((ret == 0) && (key->priv_data == NULL)) {
864+
if (ret == 0) {
841865
const LmsParams* params = key->params;
866+
priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height,
867+
params->p, params->rootLevels, params->cacheBits, params->hash_len);
842868

869+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
870+
priv_data_len += HSS_PRIVATE_KEY_LEN(params->hash_len);
871+
#endif
872+
}
873+
if ((ret == 0) && (key->priv_data == NULL)) {
843874
/* Allocate memory for the private key data. */
844-
key->priv_data = (byte *)XMALLOC(LMS_PRIV_DATA_LEN(params->levels,
845-
params->height, params->p, params->rootLevels, params->cacheBits,
846-
params->hash_len), key->heap, DYNAMIC_TYPE_LMS);
875+
key->priv_data = (byte *)XMALLOC(priv_data_len, key->heap,
876+
DYNAMIC_TYPE_LMS);
847877
/* Check pointer is valid. */
848878
if (key->priv_data == NULL) {
849879
ret = MEMORY_E;
850880
}
851881
}
852882
if (ret == 0) {
883+
int rv;
884+
853885
/* Load private key. */
854-
int rv = key->read_private_key(key->priv_raw,
886+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
887+
const LmsParams* params = key->params;
888+
889+
rv = key->read_private_key(key->priv_data, priv_data_len, key->context);
890+
#else
891+
rv = key->read_private_key(key->priv_raw,
855892
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context);
893+
#endif
856894
if (rv != WC_LMS_RC_READ_TO_MEMORY) {
857895
ret = IO_FAILED_E;
858896
}
897+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
898+
if (ret == 0) {
899+
XMEMCPY(key->priv_raw, key->priv_data + priv_data_len -
900+
HSS_PRIVATE_KEY_LEN(params->hash_len),
901+
HSS_PRIVATE_KEY_LEN(params->hash_len));
902+
}
903+
#endif
859904
}
860905

861906
/* Double check the key actually has signatures left. */
@@ -874,7 +919,8 @@ int wc_LmsKey_Reload(LmsKey* key)
874919

875920
#ifdef WOLFSSL_SMALL_STACK
876921
/* Allocate memory for working state. */
877-
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL, DYNAMIC_TYPE_TMP_BUFFER);
922+
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL,
923+
DYNAMIC_TYPE_TMP_BUFFER);
878924
if (state == NULL) {
879925
ret = MEMORY_E;
880926
}
@@ -972,7 +1018,8 @@ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg,
9721018

9731019
#ifdef WOLFSSL_SMALL_STACK
9741020
/* Allocate memory for working state. */
975-
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL, DYNAMIC_TYPE_TMP_BUFFER);
1021+
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL,
1022+
DYNAMIC_TYPE_TMP_BUFFER);
9761023
if (state == NULL) {
9771024
ret = MEMORY_E;
9781025
}
@@ -997,9 +1044,24 @@ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg,
9971044
*sigSz = (word32)key->params->sig_len;
9981045
}
9991046
if (ret == 0) {
1047+
int rv;
1048+
10001049
/* Write private key to storage. */
1001-
int rv = key->write_private_key(key->priv_raw,
1050+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
1051+
const LmsParams* params = key->params;
1052+
int priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height,
1053+
params->p, params->rootLevels, params->cacheBits,
1054+
params->hash_len) + HSS_PRIVATE_KEY_LEN(key->params->hash_len);
1055+
1056+
XMEMCPY(key->priv_data + priv_data_len -
1057+
HSS_PRIVATE_KEY_LEN(params->hash_len), key->priv_raw,
1058+
HSS_PRIVATE_KEY_LEN(params->hash_len));
1059+
rv = key->write_private_key(key->priv_data, priv_data_len,
1060+
key->context);
1061+
#else
1062+
rv = key->write_private_key(key->priv_raw,
10021063
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context);
1064+
#endif
10031065
if (rv != WC_LMS_RC_SAVED_TO_NV_MEMORY) {
10041066
ret = IO_FAILED_E;
10051067
}
@@ -1234,7 +1296,8 @@ int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz,
12341296

12351297
#ifdef WOLFSSL_SMALL_STACK
12361298
/* Allocate memory for working state. */
1237-
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL, DYNAMIC_TYPE_TMP_BUFFER);
1299+
state = (LmsState*)XMALLOC(sizeof(LmsState), NULL,
1300+
DYNAMIC_TYPE_TMP_BUFFER);
12381301
if (state == NULL) {
12391302
ret = MEMORY_E;
12401303
}

wolfcrypt/src/wc_lms_impl.c

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3208,7 +3208,7 @@ static void wc_hss_priv_data_store(const LmsParams* params, HssPrivKey* key,
32083208
int wc_hss_reload_key(LmsState* state, const byte* priv_raw,
32093209
HssPrivKey* priv_key, byte* priv_data, byte* pub_root)
32103210
{
3211-
int ret;
3211+
int ret = 0;
32123212

32133213
(void)pub_root;
32143214

@@ -3217,27 +3217,34 @@ int wc_hss_reload_key(LmsState* state, const byte* priv_raw,
32173217
priv_key->inited = 0;
32183218
#endif
32193219

3220-
/* Expand the raw private key into the private key data. */
3221-
ret = wc_hss_expand_private_key(state, priv_key->priv, priv_raw, 0);
3222-
#ifndef WOLFSSL_WC_LMS_SMALL
3223-
if ((ret == 0) && (!priv_key->inited)) {
3224-
/* Initialize the authentication paths and caches for all trees. */
3225-
ret = wc_hss_init_auth_path(state, priv_key, pub_root);
3226-
#ifndef WOLFSSL_LMS_NO_SIGN_SMOOTHING
3227-
if (ret == 0) {
3228-
ret = wc_hss_next_subtrees_init(state, priv_key);
3229-
}
3230-
#endif
3231-
#if !defined(WOLFSSL_LMS_NO_SIG_CACHE) && (LMS_MAX_LEVELS > 1)
3232-
if (ret == 0) {
3233-
/* Calculate signatures for trees not at bottom. */
3234-
ret = wc_hss_presign(state, priv_key);
3220+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
3221+
if (pub_root != NULL)
3222+
#endif
3223+
{
3224+
/* Expand the raw private key into the private key data. */
3225+
ret = wc_hss_expand_private_key(state, priv_key->priv, priv_raw, 0);
3226+
#ifndef WOLFSSL_WC_LMS_SMALL
3227+
if ((ret == 0) && (!priv_key->inited)) {
3228+
/* Initialize the authentication paths and caches for all trees. */
3229+
ret = wc_hss_init_auth_path(state, priv_key, pub_root);
3230+
#ifndef WOLFSSL_LMS_NO_SIGN_SMOOTHING
3231+
if (ret == 0) {
3232+
ret = wc_hss_next_subtrees_init(state, priv_key);
3233+
}
3234+
#endif
3235+
#if !defined(WOLFSSL_LMS_NO_SIG_CACHE) && (LMS_MAX_LEVELS > 1)
3236+
if (ret == 0) {
3237+
/* Calculate signatures for trees not at bottom. */
3238+
ret = wc_hss_presign(state, priv_key);
3239+
}
3240+
#endif /* !WOLFSSL_LMS_NO_SIG_CACHE */
32353241
}
3236-
#endif /* !WOLFSSL_LMS_NO_SIG_CACHE */
3237-
/* Set initialized flag. */
3238-
priv_key->inited = (ret == 0);
3242+
#endif /* WOLFSSL_WC_LMS_SMALL */
32393243
}
3240-
#endif /* WOLFSSL_WC_LMS_SMALL */
3244+
#ifndef WOLFSSL_WC_LMS_SMALL
3245+
/* Set initialized flag. */
3246+
priv_key->inited = (ret == 0);
3247+
#endif
32413248

32423249
return ret;
32433250
}
@@ -3301,6 +3308,10 @@ int wc_hss_make_key(LmsState* state, WC_RNG* rng, byte* priv_raw,
33013308
wc_lmots_public_key_encode(params, priv_key->priv, pub);
33023309
}
33033310

3311+
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
3312+
wc_hss_priv_data_store(state->params, priv_key, priv_data);
3313+
#endif
3314+
33043315
return ret;
33053316
}
33063317

@@ -3581,7 +3592,7 @@ static int wc_hss_sign_build_sig(LmsState* state, byte* priv_raw,
35813592
*
35823593
* @param [in, out] state LMS state.
35833594
* @param [in, out] priv_raw Raw private key bytes.
3584-
* @param [in, out] priv_key Private key data.
3595+
* @param [in, out] priv_key Private key.
35853596
* @param [in, out] priv_data Private key data.
35863597
* @param [in] msg Message to sign.
35873598
* @param [in] msgSz Length of message in bytes.

wolfcrypt/test/test.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47911,8 +47911,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
4791147911
word32 sigSz = 0;
4791247912
const char * msg = "LMS HSS post quantum signature test";
4791347913
word32 msgSz = (word32) XSTRLEN(msg);
47914+
#ifndef WOLFSSL_WC_LMS_SERIALIZE_STATE
4791447915
unsigned char priv[HSS_MAX_PRIVATE_KEY_LEN];
4791547916
unsigned char old_priv[HSS_MAX_PRIVATE_KEY_LEN];
47917+
#else
47918+
static unsigned char priv[64 * 1024 + HSS_MAX_PRIVATE_KEY_LEN];
47919+
static unsigned char old_priv[64 * 1024 + HSS_MAX_PRIVATE_KEY_LEN];
47920+
#endif
4791647921
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
4791747922
byte * sig = (byte*)XMALLOC(WC_TEST_LMS_SIG_LEN, HEAP_HINT,
4791847923
DYNAMIC_TYPE_TMP_BUFFER);

0 commit comments

Comments
 (0)