From 55bbd5865c314d2afda39ff5821a630bda579579 Mon Sep 17 00:00:00 2001 From: jordan Date: Fri, 7 Jul 2023 15:30:50 -0500 Subject: [PATCH] LMS/HSS: cleanup, and safer write/read callbacks --- INSTALL | 2 +- wolfcrypt/benchmark/benchmark.c | 54 ++++++++++++++---- wolfcrypt/src/ext_lms.c | 98 +++++++++++++++++---------------- wolfcrypt/test/test.c | 33 ++++++++++- wolfssl/wolfcrypt/ext_lms.h | 1 - wolfssl/wolfcrypt/lms.h | 8 +-- 6 files changed, 127 insertions(+), 69 deletions(-) diff --git a/INSTALL b/INSTALL index afa36410b..13611c26b 100644 --- a/INSTALL +++ b/INSTALL @@ -276,7 +276,7 @@ We also have vcpkg ports for wolftpm, wolfmqtt and curl. $ git clone https://github.com/cisco/hash-sigs.git src $ cd src - In sha256.h, set USE_OPENSSl to 0: + In sha256.h, set USE_OPENSSL to 0: #define USE_OPENSSL 0 Now build: diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 4ad8b45b7..63e83f710 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -7818,6 +7818,23 @@ static const byte lms_pub_L4_H5_W8[60] = 0x74,0x24,0x12,0xC8 }; +static int lms_write_key_mem(const byte * priv, word32 privSz, void *context) +{ + /* WARNING: THIS IS AN INSECURE WRITE CALLBACK THAT SHOULD ONLY + * BE USED FOR TESTING PURPOSES! Production applications should + * write only to non-volatile storage. */ + XMEMCPY(context, priv, privSz); + return WC_LMS_RC_SAVED_TO_NV_MEMORY; +} + +static int lms_read_key_mem(byte * priv, word32 privSz, void *context) +{ + /* WARNING: THIS IS AN INSECURE READ CALLBACK THAT SHOULD ONLY + * BE USED FOR TESTING PURPOSES! */ + XMEMCPY(priv, context, privSz); + return WC_LMS_RC_READ_TO_MEMORY; +} + static void bench_lms_sign_verify(enum wc_LmsParm parm) { LmsKey key; @@ -7831,6 +7848,7 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm) int times = 0; int count = 0; double start = 0.0F; + byte priv[HSS_MAX_PRIVATE_KEY_LEN]; const char * str = wc_LmsKey_ParmToStr(parm); ret = wc_LmsKey_Init(&key, parm); @@ -7841,32 +7859,32 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm) switch (parm) { case WC_LMS_PARM_L2_H10_W2: - XMEMCPY(key.priv, lms_priv_L2_H10_W2, sizeof(lms_priv_L2_H10_W2)); + XMEMCPY(priv, lms_priv_L2_H10_W2, sizeof(lms_priv_L2_H10_W2)); XMEMCPY(key.pub, lms_pub_L2_H10_W2, sizeof(lms_pub_L2_H10_W2)); break; case WC_LMS_PARM_L2_H10_W4: - XMEMCPY(key.priv, lms_priv_L2_H10_W4, sizeof(lms_priv_L2_H10_W4)); + XMEMCPY(priv, lms_priv_L2_H10_W4, sizeof(lms_priv_L2_H10_W4)); XMEMCPY(key.pub, lms_pub_L2_H10_W4, sizeof(lms_pub_L2_H10_W4)); break; case WC_LMS_PARM_L3_H5_W4: - XMEMCPY(key.priv, lms_priv_L3_H5_W4, sizeof(lms_priv_L3_H5_W4)); + XMEMCPY(priv, lms_priv_L3_H5_W4, sizeof(lms_priv_L3_H5_W4)); XMEMCPY(key.pub, lms_pub_L3_H5_W4, sizeof(lms_pub_L3_H5_W4)); break; case WC_LMS_PARM_L3_H5_W8: - XMEMCPY(key.priv, lms_priv_L3_H5_W8, sizeof(lms_priv_L3_H5_W8)); + XMEMCPY(priv, lms_priv_L3_H5_W8, sizeof(lms_priv_L3_H5_W8)); XMEMCPY(key.pub, lms_pub_L3_H5_W8, sizeof(lms_pub_L3_H5_W8)); break; case WC_LMS_PARM_L3_H10_W4: - XMEMCPY(key.priv, lms_priv_L3_H10_W4, sizeof(lms_priv_L3_H10_W4)); + XMEMCPY(priv, lms_priv_L3_H10_W4, sizeof(lms_priv_L3_H10_W4)); XMEMCPY(key.pub, lms_pub_L3_H10_W4, sizeof(lms_pub_L3_H10_W4)); break; case WC_LMS_PARM_L4_H5_W8: - XMEMCPY(key.priv, lms_priv_L4_H5_W8, sizeof(lms_priv_L4_H5_W8)); + XMEMCPY(priv, lms_priv_L4_H5_W8, sizeof(lms_priv_L4_H5_W8)); XMEMCPY(key.pub, lms_pub_L4_H5_W8, sizeof(lms_pub_L4_H5_W8)); break; @@ -7880,6 +7898,24 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm) goto exit_lms_sign_verify; } + ret = wc_LmsKey_SetWriteCb(&key, lms_write_key_mem); + if (ret) { + fprintf(stderr, "error: wc_LmsKey_SetWriteCb failed: %d\n", ret); + goto exit_lms_sign_verify; + } + + ret = wc_LmsKey_SetReadCb(&key, lms_read_key_mem); + if (ret) { + fprintf(stderr, "error: wc_LmsKey_SetReadCb failed: %d\n", ret); + goto exit_lms_sign_verify; + } + + ret = wc_LmsKey_SetContext(&key, (void *) priv); + if (ret) { + fprintf(stderr, "error: wc_LmsKey_SetContext failed: %d\n", ret); + goto exit_lms_sign_verify; + } + /* Even with saved priv/pub keys, we must still reload the private * key before using it. Reloading the private key is the bottleneck * for larger heights. Only print load time in debug builds. */ @@ -7933,12 +7969,6 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm) printf("wc_LmsKey_Sign failed: %d\n", ret); goto exit_lms_sign_verify; } - - /*ret = wc_LmsKey_Verify(&key, sig, sigSz, (byte *) msg, msgSz); - if (ret) { - printf("wc_LmsKey_Verify failed: %d\n", ret); - goto exit_lms_sign_verify; - }*/ } count += times; diff --git a/wolfcrypt/src/ext_lms.c b/wolfcrypt/src/ext_lms.c index 0927d7b11..a7d1007d7 100644 --- a/wolfcrypt/src/ext_lms.c +++ b/wolfcrypt/src/ext_lms.c @@ -83,27 +83,20 @@ static bool LmsWritePrivKey(unsigned char *private_key, return false; } - if (key->write_private_key != NULL) { - /* Use write callback. */ - ret = key->write_private_key(private_key, len_private_key, key->context); - - if (ret != WC_LMS_RC_SAVED_TO_NV_MEMORY) { - WOLFSSL_MSG("error: LmsKey write_private_key failed"); - WOLFSSL_MSG(wc_LmsKey_RcToStr(ret)); - key->state = WC_LMS_STATE_BAD; - return false; - } + if (key->write_private_key == NULL) { + WOLFSSL_MSG("error: LmsWritePrivKey: LMS key write callback not set"); + key->state = WC_LMS_STATE_NOT_INITED; + return false; } - else { - /* Save to memory. */ - if (len_private_key > sizeof(key->priv)) { - WOLFSSL_MSG("error: LmsWritePrivKey: private key too large"); - key->state = WC_LMS_STATE_BAD; - return false; - } - XMEMSET(key->priv, 0, sizeof(key->priv)); - XMEMCPY(key->priv, private_key, len_private_key); + /* Use write callback. */ + ret = key->write_private_key(private_key, len_private_key, key->context); + + if (ret != WC_LMS_RC_SAVED_TO_NV_MEMORY) { + WOLFSSL_MSG("error: LmsKey write_private_key failed"); + WOLFSSL_MSG(wc_LmsKey_RcToStr(ret)); + key->state = WC_LMS_STATE_BAD; + return false; } return true; @@ -128,26 +121,20 @@ static bool LmsReadPrivKey(unsigned char *private_key, return false; } - if (key->read_private_key != NULL) { - /* Use read callback. */ - ret = key->read_private_key(private_key, len_private_key, key->context); - - if (ret != WC_LMS_RC_READ_TO_MEMORY) { - WOLFSSL_MSG("error: LmsKey read_private_key failed"); - WOLFSSL_MSG(wc_LmsKey_RcToStr(ret)); - key->state = WC_LMS_STATE_BAD; - return false; - } + if (key->read_private_key == NULL) { + WOLFSSL_MSG("error: LmsReadPrivKey: LMS key read callback not set"); + key->state = WC_LMS_STATE_NOT_INITED; + return false; } - else { - /* Read from memory. */ - if (len_private_key > sizeof(key->priv)) { - WOLFSSL_MSG("error: LmsReadPrivKey: private key too large"); - key->state = WC_LMS_STATE_BAD; - return false; - } - XMEMCPY(private_key, key->priv, len_private_key); + /* Use read callback. */ + ret = key->read_private_key(private_key, len_private_key, key->context); + + if (ret != WC_LMS_RC_READ_TO_MEMORY) { + WOLFSSL_MSG("error: LmsKey read_private_key failed"); + WOLFSSL_MSG(wc_LmsKey_RcToStr(ret)); + key->state = WC_LMS_STATE_BAD; + return false; } return true; @@ -362,11 +349,6 @@ int wc_LmsKey_Init_ex(LmsKey * key, int levels, int height, hss_init_extra_info(&key->info); - /* The hash-sigs lib API will accept either: - * 1. private key callbacks with context pointer, or - * 2. context that points at private key. - * Do the 2nd by default, unless user sets the callbacks through API. */ - key->working_key = NULL; key->write_private_key = NULL; key->read_private_key = NULL; @@ -407,6 +389,16 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG * rng) return -1; } + if (key->write_private_key == NULL || key->read_private_key == NULL) { + WOLFSSL_MSG("error: LmsKey write/read callbacks are not set"); + return -1; + } + + if (key->context == NULL) { + WOLFSSL_MSG("error: LmsKey context is not set"); + return -1; + } + LmsRng = rng; /* todo: The has-sigs lib allows you to save variable length auxiliary @@ -449,24 +441,24 @@ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG * rng) return 0; } -int wc_LmsKey_SetWriteCb(LmsKey * key, write_private_key_cb wf) +int wc_LmsKey_SetWriteCb(LmsKey * key, write_private_key_cb write_cb) { - if (key == NULL || wf == NULL) { + if (key == NULL || write_cb == NULL) { return BAD_FUNC_ARG; } - key->write_private_key = wf; + key->write_private_key = write_cb; return 0; } -int wc_LmsKey_SetReadCb(LmsKey * key, read_private_key_cb rf) +int wc_LmsKey_SetReadCb(LmsKey * key, read_private_key_cb read_cb) { - if (key == NULL || rf == NULL) { + if (key == NULL || read_cb == NULL) { return BAD_FUNC_ARG; } - key->read_private_key = rf; + key->read_private_key = read_cb; return 0; } @@ -499,6 +491,16 @@ int wc_LmsKey_Reload(LmsKey * key) return -1; } + if (key->write_private_key == NULL || key->read_private_key == NULL) { + WOLFSSL_MSG("error: LmsKey write/read callbacks are not set"); + return -1; + } + + if (key->context == NULL) { + WOLFSSL_MSG("error: LmsKey context is not set"); + return -1; + } + key->working_key = hss_load_private_key(LmsReadPrivKey, key, 0, NULL, 0, &key->info); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 028bf858b..8caf0d135 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -34823,6 +34823,23 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t kyber_test(void) #ifdef WOLFSSL_HAVE_LMS +static int lms_write_key_mem(const byte * priv, word32 privSz, void *context) +{ + /* WARNING: THIS IS AN INSECURE WRITE CALLBACK THAT SHOULD ONLY + * BE USED FOR TESTING PURPOSES! Production applications should + * write only to non-volatile storage. */ + XMEMCPY(context, priv, privSz); + return WC_LMS_RC_SAVED_TO_NV_MEMORY; +} + +static int lms_read_key_mem(byte * priv, word32 privSz, void *context) +{ + /* WARNING: THIS IS AN INSECURE READ CALLBACK THAT SHOULD ONLY + * BE USED FOR TESTING PURPOSES! */ + XMEMCPY(priv, context, privSz); + return WC_LMS_RC_READ_TO_MEMORY; +} + WOLFSSL_TEST_SUBROUTINE int lms_test(void) { int ret; @@ -34834,6 +34851,7 @@ WOLFSSL_TEST_SUBROUTINE int lms_test(void) word32 sigSz = 0; const char * msg = "LMS HSS post quantum signature test"; word32 msgSz = (word32) XSTRLEN(msg); + unsigned char priv[HSS_MAX_PRIVATE_KEY_LEN]; unsigned char old_priv[HSS_MAX_PRIVATE_KEY_LEN]; XMEMSET(old_priv, 0, sizeof(old_priv)); @@ -34856,10 +34874,19 @@ WOLFSSL_TEST_SUBROUTINE int lms_test(void) ret = wc_LmsKey_Init_ex(&signingKey, 1, 5, 1, NULL, INVALID_DEVID); if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); } + ret = wc_LmsKey_SetWriteCb(&signingKey, lms_write_key_mem); + if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); } + + ret = wc_LmsKey_SetReadCb(&signingKey, lms_read_key_mem); + if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); } + + ret = wc_LmsKey_SetContext(&signingKey, (void *) priv); + if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); } + ret = wc_LmsKey_MakeKey(&signingKey, &rng); if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); } - XMEMCPY(old_priv, signingKey.priv, sizeof(signingKey.priv)); + XMEMCPY(old_priv, priv, sizeof(priv)); ret = wc_LmsKey_ExportPub(&verifyKey, &signingKey); if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); } @@ -34885,12 +34912,12 @@ WOLFSSL_TEST_SUBROUTINE int lms_test(void) if (ret != 0) { return WC_TEST_RET_ENC_I(i); } /* The updated private key should not match the old one. */ - if (XMEMCMP(old_priv, signingKey.priv, sizeof(signingKey.priv)) == 0) { + if (XMEMCMP(old_priv, priv, sizeof(priv)) == 0) { printf("error: current priv key should not match old: %zu\n", i); return WC_TEST_RET_ENC_I(i); } - XMEMCPY(old_priv, signingKey.priv, sizeof(signingKey.priv)); + XMEMCPY(old_priv, priv, sizeof(priv)); ret = wc_LmsKey_Verify(&verifyKey, sig, sigSz, (byte *) msg, msgSz); if (ret != 0) { return WC_TEST_RET_ENC_I(i); } diff --git a/wolfssl/wolfcrypt/ext_lms.h b/wolfssl/wolfcrypt/ext_lms.h index 86cfc79ce..faf833ad1 100644 --- a/wolfssl/wolfcrypt/ext_lms.h +++ b/wolfssl/wolfcrypt/ext_lms.h @@ -50,7 +50,6 @@ struct LmsKey { unsigned levels; /* Number of tree levels. */ param_set_t lm_type[MAX_HSS_LEVELS]; /* Height parm per level. */ param_set_t lm_ots_type[MAX_HSS_LEVELS]; /* Winternitz parm per level. */ - unsigned char priv[HSS_MAX_PRIVATE_KEY_LEN]; unsigned char pub[HSS_MAX_PUBLIC_KEY_LEN]; hss_working_key * working_key; write_private_key_cb write_private_key; /* Callback to write/update key. */ diff --git a/wolfssl/wolfcrypt/lms.h b/wolfssl/wolfcrypt/lms.h index 4085efcce..9bd917248 100644 --- a/wolfssl/wolfcrypt/lms.h +++ b/wolfssl/wolfcrypt/lms.h @@ -104,8 +104,10 @@ enum wc_LmsState { WOLFSSL_API int wc_LmsKey_Init(LmsKey * key, enum wc_LmsParm lmsParm); WOLFSSL_API int wc_LmsKey_Init_ex(LmsKey * key, int levels, int height, int winternitz, void* heap, int devId); -WOLFSSL_API int wc_LmsKey_SetWriteCb(LmsKey * key, write_private_key_cb wf); -WOLFSSL_API int wc_LmsKey_SetReadCb(LmsKey * key, read_private_key_cb rf); +WOLFSSL_API int wc_LmsKey_SetWriteCb(LmsKey * key, + write_private_key_cb write_cb); +WOLFSSL_API int wc_LmsKey_SetReadCb(LmsKey * key, + read_private_key_cb read_cb); WOLFSSL_API int wc_LmsKey_SetContext(LmsKey * key, void * context); WOLFSSL_API void wc_LmsKey_Free(LmsKey * key); WOLFSSL_API int wc_LmsKey_MakeKey(LmsKey * key, WC_RNG * rng); @@ -126,6 +128,4 @@ WOLFSSL_API const char * wc_LmsKey_RcToStr(enum wc_LmsRc lmsRc); #endif #endif /* WOLFSSL_HAVE_LMS */ - #endif /* WOLF_CRYPT_LMS_H */ -