| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972 |
- /* ext_lms.c
- *
- * Copyright (C) 2006-2023 wolfSSL Inc.
- *
- * This file is part of wolfSSL.
- *
- * wolfSSL is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * wolfSSL is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <wolfssl/wolfcrypt/settings.h>
- #include <wolfssl/wolfcrypt/error-crypt.h>
- #include <wolfssl/wolfcrypt/logging.h>
- #ifdef WOLFSSL_HAVE_LMS
- #include <wolfssl/wolfcrypt/ext_lms.h>
- #ifdef NO_INLINE
- #include <wolfssl/wolfcrypt/misc.h>
- #else
- #define WOLFSSL_MISC_INCLUDED
- #include <wolfcrypt/src/misc.c>
- #endif
- #ifndef WOLFSSL_LMS_VERIFY_ONLY
- /* If built against hss_lib_thread.a, the hash-sigs lib will spawn
- * worker threads to parallelize cpu intensive tasks. This will mainly
- * speedup key generation and signing, and to a lesser extent
- * verifying for larger levels values.
- *
- * Their default max is 16 worker threads, but can be capped with
- * hss_extra_info_set_threads(). To be safe we are capping at 4 here.
- * */
- #define EXT_LMS_MAX_THREADS (4)
- /* The hash-sigs hss_generate_private_key API requires a generate_random
- * callback that only has output and length args. The RNG struct must be global
- * to the function. Maybe there should be a wc_LmsKey_SetRngCb. */
- static THREAD_LS_T WC_RNG * LmsRng = NULL;
- static bool LmsGenerateRand(void * output, size_t length)
- {
- int ret = 0;
- if (output == NULL || LmsRng == NULL) {
- return false;
- }
- if (length == 0) {
- return true;
- }
- ret = wc_RNG_GenerateBlock(LmsRng, output, (word32) length);
- if (ret) {
- WOLFSSL_MSG("error: LmsGenerateRand failed");
- return false;
- }
- return true;
- }
- /* Write callback passed into hash-sigs hss lib.
- *
- * Returns true on success. */
- static bool LmsWritePrivKey(unsigned char *private_key,
- size_t len_private_key, void *lmsKey)
- {
- LmsKey * key = (LmsKey *) lmsKey;
- enum wc_LmsRc ret = WC_LMS_RC_NONE;
- if (private_key == NULL || key == NULL || len_private_key <= 0) {
- WOLFSSL_MSG("error: LmsWritePrivKey: invalid args");
- return false;
- }
- if (key->state != WC_LMS_STATE_PARMSET && key->state != WC_LMS_STATE_OK) {
- /* The LmsKey is not ready for writing. */
- WOLFSSL_MSG("error: LmsWritePrivKey: LMS key not in writeable state");
- return false;
- }
- if (key->write_private_key == NULL) {
- WOLFSSL_MSG("error: LmsWritePrivKey: LMS key write callback not set");
- key->state = WC_LMS_STATE_BAD;
- return false;
- }
- /* Use write callback that saves private key to non-volatile storage. */
- ret = key->write_private_key(private_key, (word32)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;
- }
- /* Read callback passed into hash-sigs hss lib.
- *
- * Returns true on success. */
- static bool LmsReadPrivKey(unsigned char *private_key,
- size_t len_private_key, void *lmsKey)
- {
- LmsKey * key = (LmsKey *) lmsKey;
- enum wc_LmsRc ret = WC_LMS_RC_NONE;
- if (private_key == NULL || key == NULL || len_private_key <= 0) {
- WOLFSSL_MSG("error: LmsReadPrivKey: invalid args");
- return false;
- }
- if (key->state != WC_LMS_STATE_PARMSET && key->state != WC_LMS_STATE_OK) {
- /* The LmsKey is not ready for reading. */
- WOLFSSL_MSG("error: LmsReadPrivKey: LMS key not in readable state");
- return false;
- }
- if (key->read_private_key == NULL) {
- WOLFSSL_MSG("error: LmsReadPrivKey: LMS key read callback not set");
- key->state = WC_LMS_STATE_BAD;
- return false;
- }
- /* Use read callback that reads private key from non-volatile storage. */
- ret = key->read_private_key(private_key, (word32)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;
- }
- #endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */
- const char * wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm)
- {
- switch (lmsParm) {
- case WC_LMS_PARM_NONE:
- return "LMS_NONE";
- case WC_LMS_PARM_L1_H15_W2:
- return "LMS/HSS L1_H15_W2";
- case WC_LMS_PARM_L1_H15_W4:
- return "LMS/HSS L1_H15_W4";
- case WC_LMS_PARM_L2_H10_W2:
- return "LMS/HSS L2_H10_W2";
- case WC_LMS_PARM_L2_H10_W4:
- return "LMS/HSS L2_H10_W4";
- case WC_LMS_PARM_L2_H10_W8:
- return "LMS/HSS L2_H10_W8";
- case WC_LMS_PARM_L3_H5_W2:
- return "LMS/HSS L3_H5_W2";
- case WC_LMS_PARM_L3_H5_W4:
- return "LMS/HSS L3_H5_W4";
- case WC_LMS_PARM_L3_H5_W8:
- return "LMS/HSS L3_H5_W8";
- case WC_LMS_PARM_L3_H10_W4:
- return "LMS/HSS L3_H10_W4";
- case WC_LMS_PARM_L4_H5_W8:
- return "LMS/HSS L4_H5_W8";
- default:
- WOLFSSL_MSG("error: invalid LMS parameter");
- break;
- }
- return "LMS_INVALID";
- }
- const char * wc_LmsKey_RcToStr(enum wc_LmsRc lmsEc)
- {
- switch (lmsEc) {
- case WC_LMS_RC_NONE:
- return "LMS_RC_NONE";
- case WC_LMS_RC_BAD_ARG:
- return "LMS_RC_BAD_ARG";
- case WC_LMS_RC_WRITE_FAIL:
- return "LMS_RC_WRITE_FAIL";
- case WC_LMS_RC_READ_FAIL:
- return "LMS_RC_READ_FAIL";
- case WC_LMS_RC_SAVED_TO_NV_MEMORY:
- return "LMS_RC_SAVED_TO_NV_MEMORY";
- case WC_LMS_RC_READ_TO_MEMORY:
- return "LMS_RC_READ_TO_MEMORY";
- default:
- WOLFSSL_MSG("error: invalid LMS error code");
- break;
- }
- return "LMS_RC_INVALID";
- }
- /* Init an LMS key.
- *
- * Call this before setting the params of an LMS key.
- *
- * Returns 0 on success.
- * */
- int wc_LmsKey_Init(LmsKey * key, void * heap, int devId)
- {
- if (key == NULL) {
- return BAD_FUNC_ARG;
- }
- (void) heap;
- (void) devId;
- ForceZero(key, sizeof(LmsKey));
- #ifndef WOLFSSL_LMS_VERIFY_ONLY
- hss_init_extra_info(&key->info);
- /* Set the max number of worker threads that hash-sigs can spawn. */
- hss_extra_info_set_threads(&key->info, EXT_LMS_MAX_THREADS);
- key->working_key = NULL;
- key->write_private_key = NULL;
- key->read_private_key = NULL;
- key->context = NULL;
- #endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */
- key->state = WC_LMS_STATE_INITED;
- return 0;
- }
- /* Set the wc_LmsParm of an LMS key.
- *
- * Use this if you wish to set a key with a predefined parameter set,
- * such as WC_LMS_PARM_L2_H10_W8.
- *
- * Key must be inited before calling this.
- *
- * Returns 0 on success.
- * */
- int wc_LmsKey_SetLmsParm(LmsKey * key, enum wc_LmsParm lmsParm)
- {
- if (key == NULL) {
- return BAD_FUNC_ARG;
- }
- /* If NONE is passed, default to the lowest predefined set. */
- switch (lmsParm) {
- case WC_LMS_PARM_NONE:
- case WC_LMS_PARM_L1_H15_W2:
- return wc_LmsKey_SetParameters(key, 1, 15, 2);
- case WC_LMS_PARM_L1_H15_W4:
- return wc_LmsKey_SetParameters(key, 1, 15, 4);
- case WC_LMS_PARM_L2_H10_W2:
- return wc_LmsKey_SetParameters(key, 2, 10, 2);
- case WC_LMS_PARM_L2_H10_W4:
- return wc_LmsKey_SetParameters(key, 2, 10, 4);
- case WC_LMS_PARM_L2_H10_W8:
- return wc_LmsKey_SetParameters(key, 2, 10, 8);
- case WC_LMS_PARM_L3_H5_W2:
- return wc_LmsKey_SetParameters(key, 3, 5, 2);
- case WC_LMS_PARM_L3_H5_W4:
- return wc_LmsKey_SetParameters(key, 3, 5, 4);
- case WC_LMS_PARM_L3_H5_W8:
- return wc_LmsKey_SetParameters(key, 3, 5, 8);
- case WC_LMS_PARM_L3_H10_W4:
- return wc_LmsKey_SetParameters(key, 3, 10, 4);
- case WC_LMS_PARM_L4_H5_W8:
- return wc_LmsKey_SetParameters(key, 4, 5, 8);
- default:
- WOLFSSL_MSG("error: invalid LMS parameter set");
- break;
- }
- return BAD_FUNC_ARG;
- }
- /* Set the parameters of an LMS key.
- *
- * Use this if you wish to set specific parameters not found in the
- * wc_LmsParm predefined sets. See comments in lms.h for allowed
- * parameters.
- *
- * Key must be inited before calling this.
- *
- * Returns 0 on success.
- * */
- int wc_LmsKey_SetParameters(LmsKey * key, int levels, int height,
- int winternitz)
- {
- int i = 0;
- param_set_t lm = LMS_SHA256_N32_H5;
- param_set_t ots = LMOTS_SHA256_N32_W1;
- if (key == NULL) {
- return BAD_FUNC_ARG;
- }
- if (key->state != WC_LMS_STATE_INITED) {
- WOLFSSL_MSG("error: LmsKey needs init");
- return -1;
- }
- /* Verify inputs make sense.
- *
- * Note: there does not seem to be a define for min or
- * max Winternitz integer in hash-sigs lib or RFC8554. */
- if (levels < MIN_HSS_LEVELS || levels > MAX_HSS_LEVELS) {
- WOLFSSL_MSG("error: invalid level parameter");
- return BAD_FUNC_ARG;
- }
- if (height < MIN_MERKLE_HEIGHT || height > MAX_MERKLE_HEIGHT) {
- WOLFSSL_MSG("error: invalid height parameter");
- return BAD_FUNC_ARG;
- }
- switch (height) {
- case 5:
- lm = LMS_SHA256_N32_H5;
- break;
- case 10:
- lm = LMS_SHA256_N32_H10;
- break;
- case 15:
- lm = LMS_SHA256_N32_H15;
- break;
- case 20:
- lm = LMS_SHA256_N32_H20;
- break;
- case 25:
- lm = LMS_SHA256_N32_H25;
- break;
- default:
- WOLFSSL_MSG("error: invalid height parameter");
- return BAD_FUNC_ARG;
- }
- switch (winternitz) {
- case 1:
- ots = LMOTS_SHA256_N32_W1;
- break;
- case 2:
- ots = LMOTS_SHA256_N32_W2;
- break;
- case 4:
- ots = LMOTS_SHA256_N32_W4;
- break;
- case 8:
- ots = LMOTS_SHA256_N32_W8;
- break;
- default:
- WOLFSSL_MSG("error: invalid winternitz parameter");
- return BAD_FUNC_ARG;
- }
- key->levels = levels;
- for (i = 0; i < levels; ++i) {
- key->lm_type[i] = lm;
- key->lm_ots_type[i] = ots;
- }
- /* Move the state to params set.
- * Key is ready for MakeKey or Reload. */
- key->state = WC_LMS_STATE_PARMSET;
- return 0;
- }
- /* Get the parameters of an LMS key.
- *
- * Key must be inited and parameters set before calling this.
- *
- * Returns 0 on success.
- * */
- int wc_LmsKey_GetParameters(const LmsKey * key, int * levels, int * height,
- int * winternitz)
- {
- if (key == NULL || levels == NULL || height == NULL || winternitz == NULL) {
- return BAD_FUNC_ARG;
- }
- /* This shouldn't happen, but check the LmsKey parameters aren't invalid. */
- if (key->levels < MIN_HSS_LEVELS || key->levels > MAX_HSS_LEVELS) {
- WOLFSSL_MSG("error: LmsKey invalid level parameter");
- return -1;
- }
- *levels = key->levels;
- switch (key->lm_type[0]) {
- case LMS_SHA256_N32_H5:
- *height = 5;
- break;
- case LMS_SHA256_N32_H10:
- *height = 10;
- break;
- case LMS_SHA256_N32_H15:
- *height = 15;
- break;
- case LMS_SHA256_N32_H20:
- *height = 20;
- break;
- case LMS_SHA256_N32_H25:
- *height = 25;
- break;
- default:
- WOLFSSL_MSG("error: LmsKey invalid height parameter");
- return -1;
- }
- switch (key->lm_ots_type[0]) {
- case LMOTS_SHA256_N32_W1:
- *winternitz = 1;
- break;
- case LMOTS_SHA256_N32_W2:
- *winternitz = 2;
- break;
- case LMOTS_SHA256_N32_W4:
- *winternitz = 4;
- break;
- case LMOTS_SHA256_N32_W8:
- *winternitz = 8;
- break;
- default:
- WOLFSSL_MSG("error: LmsKey invalid winternitz parameter");
- return -1;
- }
- return 0;
- }
- /* Frees the LMS key from memory.
- *
- * This does not affect the private key saved to non-volatile storage.
- * */
- void wc_LmsKey_Free(LmsKey* key)
- {
- if (key == NULL) {
- return;
- }
- #ifndef WOLFSSL_LMS_VERIFY_ONLY
- if (key->working_key != NULL) {
- hss_free_working_key(key->working_key);
- key->working_key = NULL;
- }
- #endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */
- ForceZero(key, sizeof(LmsKey));
- key->state = WC_LMS_STATE_FREED;
- return;
- }
- #ifndef WOLFSSL_LMS_VERIFY_ONLY
- /* Set the write private key callback to the LMS key structure.
- *
- * The callback must be able to write/update the private key to
- * non-volatile storage.
- *
- * Returns 0 on success.
- * */
- int wc_LmsKey_SetWriteCb(LmsKey * key, write_private_key_cb write_cb)
- {
- if (key == NULL || write_cb == NULL) {
- return BAD_FUNC_ARG;
- }
- /* Changing the write callback of an already working key is forbidden. */
- if (key->state == WC_LMS_STATE_OK) {
- WOLFSSL_MSG("error: wc_LmsKey_SetWriteCb: key in use");
- return -1;
- }
- key->write_private_key = write_cb;
- return 0;
- }
- /* Set the read private key callback to the LMS key structure.
- *
- * The callback must be able to read the private key from
- * non-volatile storage.
- *
- * Returns 0 on success.
- * */
- int wc_LmsKey_SetReadCb(LmsKey * key, read_private_key_cb read_cb)
- {
- if (key == NULL || read_cb == NULL) {
- return BAD_FUNC_ARG;
- }
- /* Changing the read callback of an already working key is forbidden. */
- if (key->state == WC_LMS_STATE_OK) {
- WOLFSSL_MSG("error: wc_LmsKey_SetReadCb: key in use");
- return -1;
- }
- key->read_private_key = read_cb;
- return 0;
- }
- /* Sets the context to be used by write and read callbacks.
- *
- * E.g. this could be a filename if the callbacks write/read to file.
- *
- * Returns 0 on success.
- * */
- int wc_LmsKey_SetContext(LmsKey * key, void * context)
- {
- if (key == NULL || context == NULL) {
- return BAD_FUNC_ARG;
- }
- /* Setting context of an already working key is forbidden. */
- if (key->state == WC_LMS_STATE_OK) {
- WOLFSSL_MSG("error: wc_LmsKey_SetContext: key in use");
- return -1;
- }
- key->context = context;
- return 0;
- }
- /* Make the LMS private/public key pair. The key must have its parameters
- * set before calling this.
- *
- * Write/read callbacks, and context data, must be set prior.
- * Key must have parameters set.
- *
- * Returns 0 on success.
- * */
- int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG * rng)
- {
- bool result = true;
- if (key == NULL || rng == NULL) {
- return BAD_FUNC_ARG;
- }
- if (key->state != WC_LMS_STATE_PARMSET) {
- WOLFSSL_MSG("error: LmsKey not ready for generation");
- 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 hash-sigs lib allows you to save variable length auxiliary
- * data, which can be used to speed up key reloading when signing. The
- * aux data can be 300B - 1KB in size.
- *
- * Not implemented at the moment.
- *
- * key->aux_data_len = hss_get_aux_data_len(AUX_DATA_MAX_LEN, key->levels,
- * key->lm_type,
- * key->lm_ots_type);
- *
- * key->aux_data = XMALLOC(key->aux_data_len, NULL,
- * DYNAMIC_TYPE_TMP_BUFFER);
- */
- /* First generate the private key using the parameters and callbacks.
- * If successful, private key will be saved to non-volatile storage,
- * and the public key will be in memory. */
- result = hss_generate_private_key(LmsGenerateRand, key->levels,
- key->lm_type, key->lm_ots_type,
- LmsWritePrivKey, key,
- key->pub, sizeof(key->pub),
- NULL, 0, &key->info);
- if (!result) {
- WOLFSSL_MSG("error: hss_generate_private_key failed");
- key->state = WC_LMS_STATE_BAD;
- return -1;
- }
- /* Once generated, now we must load the private key so we have
- * an hss working key for signing operations. */
- key->working_key = hss_load_private_key(LmsReadPrivKey, key,
- 0, NULL, 0, &key->info);
- if (key->working_key == NULL) {
- WOLFSSL_MSG("error: hss_load_private_key failed");
- key->state = WC_LMS_STATE_BAD;
- return -1;
- }
- /* This should not happen, but check just in case. */
- if (wc_LmsKey_SigsLeft(key) == 0) {
- WOLFSSL_MSG("error: generated LMS key signatures exhausted");
- key->state = WC_LMS_STATE_NOSIGS;
- return -1;
- }
- key->state = WC_LMS_STATE_OK;
- return 0;
- }
- /* Reload a key that has been prepared with the appropriate params and
- * data. Use this if you wish to resume signing with an existing key.
- *
- * Write/read callbacks, and context data, must be set prior.
- * Key must have parameters set.
- *
- * Returns 0 on success. */
- int wc_LmsKey_Reload(LmsKey * key)
- {
- bool result = true;
- if (key == NULL) {
- return BAD_FUNC_ARG;
- }
- if (key->state != WC_LMS_STATE_PARMSET) {
- WOLFSSL_MSG("error: LmsKey not ready for reload");
- 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);
- if (key->working_key == NULL) {
- WOLFSSL_MSG("error: hss_load_private_key failed");
- key->state = WC_LMS_STATE_BAD;
- return -1;
- }
- result = hss_get_parameter_set(&key->levels, key->lm_type,
- key->lm_ots_type, LmsReadPrivKey, key);
- if (!result) {
- WOLFSSL_MSG("error: hss_get_parameter_set failed");
- key->state = WC_LMS_STATE_BAD;
- hss_free_working_key(key->working_key);
- key->working_key = NULL;
- return -1;
- }
- /* Double check the key actually has signatures left. */
- if (wc_LmsKey_SigsLeft(key) == 0) {
- WOLFSSL_MSG("error: reloaded LMS key signatures exhausted");
- key->state = WC_LMS_STATE_NOSIGS;
- return -1;
- }
- key->state = WC_LMS_STATE_OK;
- return 0;
- }
- /* Given a levels, height, winternitz parameter set, determine
- * the private key length */
- int wc_LmsKey_GetPrivLen(const LmsKey * key, word32 * len)
- {
- if (key == NULL || len == NULL) {
- return BAD_FUNC_ARG;
- }
- *len = (word32) hss_get_private_key_len(key->levels, key->lm_type,
- key->lm_ots_type);
- return 0;
- }
- int wc_LmsKey_Sign(LmsKey* key, byte * sig, word32 * sigSz, const byte * msg,
- int msgSz)
- {
- bool result = true;
- size_t len = 0;
- if (key == NULL || sig == NULL || sigSz == NULL || msg == NULL) {
- return BAD_FUNC_ARG;
- }
- if (msgSz <= 0) {
- return BAD_FUNC_ARG;
- }
- if (key->state == WC_LMS_STATE_NOSIGS) {
- WOLFSSL_MSG("error: LMS signatures exhausted");
- return -1;
- }
- else if (key->state != WC_LMS_STATE_OK) {
- /* The key had an error the last time it was used, and we
- * can't guarantee its state. */
- WOLFSSL_MSG("error: can't sign, LMS key not in good state");
- return -1;
- }
- len = hss_get_signature_len(key->levels, key->lm_type, key->lm_ots_type);
- if (len == 0) {
- /* Key parameters are invalid. */
- WOLFSSL_MSG("error: hss_get_signature_len failed");
- key->state = WC_LMS_STATE_BAD;
- return -1;
- }
- result = hss_generate_signature(key->working_key, LmsWritePrivKey,
- key, (const void *) msg, msgSz,
- sig, len, &key->info);
- if (!result) {
- if (wc_LmsKey_SigsLeft(key) == 0) {
- WOLFSSL_MSG("error: LMS signatures exhausted");
- key->state = WC_LMS_STATE_NOSIGS;
- return -1;
- }
- WOLFSSL_MSG("error: hss_generate_signature failed");
- key->state = WC_LMS_STATE_BAD;
- return -1;
- }
- *sigSz = (word32) len;
- return 0;
- }
- /* Returns 1 if there are signatures remaining.
- * Returns 0 if available signatures are exhausted.
- *
- * Note: the number of remaining signatures is hidden behind an opaque
- * pointer in the hash-sigs lib. We could add a counter here that is
- * decremented on every signature. The number of available signatures
- * grows as
- * N = 2 ** (levels * height)
- * so it would need to be a big integer. */
- int wc_LmsKey_SigsLeft(LmsKey * key)
- {
- if (key == NULL) {
- return BAD_FUNC_ARG;
- }
- if (hss_extra_info_test_last_signature(&key->info)) {
- return 0;
- }
- return 1;
- }
- #endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY*/
- /* Given a levels, height, winternitz parameter set, determine
- * the public key length */
- int wc_LmsKey_GetPubLen(const LmsKey * key, word32 * len)
- {
- if (key == NULL || len == NULL) {
- return BAD_FUNC_ARG;
- }
- *len = (word32) hss_get_public_key_len(key->levels, key->lm_type,
- key->lm_ots_type);
- return 0;
- }
- /* Export a generated public key and parameter set from one LmsKey
- * to another. Use this to prepare a signature verification LmsKey
- * that is pub only.
- *
- * Though the public key is all that is used to verify signatures,
- * the parameter set is needed to calculate the signature length
- * before hand. */
- int wc_LmsKey_ExportPub(LmsKey * keyDst, const LmsKey * keySrc)
- {
- if (keyDst == NULL || keySrc == NULL) {
- return BAD_FUNC_ARG;
- }
- ForceZero(keyDst, sizeof(LmsKey));
- XMEMCPY(keyDst->pub, keySrc->pub, sizeof(keySrc->pub));
- XMEMCPY(keyDst->lm_type, keySrc->lm_type, sizeof(keySrc->lm_type));
- XMEMCPY(keyDst->lm_ots_type, keySrc->lm_ots_type,
- sizeof(keySrc->lm_ots_type));
- keyDst->levels = keySrc->levels;
- /* Mark this key as verify only, to prevent misuse. */
- keyDst->state = WC_LMS_STATE_VERIFYONLY;
- return 0;
- }
- /* Exports the raw LMS public key buffer from key to out buffer.
- * The out buffer should be large enough to hold the public key, and
- * outLen should indicate the size of the buffer.
- *
- * - Returns 0 on success, and sets outLen to LMS pubLen.
- * - Returns BUFFER_E if outLen < LMS pubLen.
- *
- * Call wc_LmsKey_GetPubLen beforehand to determine pubLen.
- * */
- int wc_LmsKey_ExportPubRaw(const LmsKey * key, byte * out, word32 * outLen)
- {
- int ret = 0;
- word32 pubLen = 0;
- if (key == NULL || out == NULL || outLen == NULL) {
- return BAD_FUNC_ARG;
- }
- ret = wc_LmsKey_GetPubLen(key, &pubLen);
- if (ret != 0) {
- WOLFSSL_MSG("error: wc_LmsKey_GetPubLen failed");
- return -1;
- }
- if (*outLen < pubLen) {
- return BUFFER_E;
- }
- XMEMCPY(out, key->pub, pubLen);
- *outLen = pubLen;
- return 0;
- }
- /* Imports a raw public key buffer from in array to LmsKey key.
- *
- * The LMS parameters must be set first with wc_LmsKey_SetLmsParm or
- * wc_LmsKey_SetParameters, and inLen must match the length returned
- * by wc_LmsKey_GetPubLen.
- *
- * - Returns 0 on success.
- * - Returns BUFFER_E if inlen != LMS pubLen.
- *
- * Call wc_LmsKey_GetPubLen beforehand to determine pubLen.
- * */
- int wc_LmsKey_ImportPubRaw(LmsKey * key, const byte * in, word32 inLen)
- {
- int ret = 0;
- word32 pubLen = 0;
- if (key == NULL || in == NULL) {
- return BAD_FUNC_ARG;
- }
- ret = wc_LmsKey_GetPubLen(key, &pubLen);
- if (ret != 0) {
- WOLFSSL_MSG("error: wc_LmsKey_GetPubLen failed");
- return -1;
- }
- if (inLen != pubLen) {
- /* Something inconsistent. Parameters weren't set, or input
- * pub key is wrong.*/
- return BUFFER_E;
- }
- XMEMCPY(key->pub, in, pubLen);
- return 0;
- }
- /* Given a levels, height, winternitz parameter set, determine
- * the signature length.
- *
- * Call this before wc_LmsKey_Sign so you know the length of
- * the required signature buffer. */
- int wc_LmsKey_GetSigLen(const LmsKey * key, word32 * len)
- {
- if (key == NULL || len == NULL) {
- return BAD_FUNC_ARG;
- }
- *len = (word32) hss_get_signature_len(key->levels, key->lm_type,
- key->lm_ots_type);
- return 0;
- }
- int wc_LmsKey_Verify(LmsKey * key, const byte * sig, word32 sigSz,
- const byte * msg, int msgSz)
- {
- bool result = true;
- if (key == NULL || sig == NULL || msg == NULL) {
- return BAD_FUNC_ARG;
- }
- #ifdef WOLFSSL_LMS_VERIFY_ONLY
- result = hss_validate_signature(key->pub, (const void *) msg, msgSz, sig,
- sigSz, NULL);
- #else
- result = hss_validate_signature(key->pub, (const void *) msg, msgSz, sig,
- sigSz, &key->info);
- #endif
- if (!result) {
- WOLFSSL_MSG("error: hss_validate_signature failed");
- return -1;
- }
- return 0;
- }
- #endif /* WOLFSSL_HAVE_LMS */
|