LMS/HSS: cleanup, and safer write/read callbacks

This commit is contained in:
jordan
2023-07-07 15:30:50 -05:00
parent 67bef21185
commit 55bbd5865c
6 changed files with 127 additions and 69 deletions

View File

@ -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:

View File

@ -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;

View File

@ -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);

View File

@ -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); }

View File

@ -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. */

View File

@ -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 */