#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS)
#include <wolfssl/wolfcrypt/wc_lms.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#define LMS_U(w, hLen) \
(8 * (hLen) / (w))
#define LMS_V(w, wb) \
(2 + (8 - (wb)) / (w))
#define LMS_LS(w, wb) \
(16 - LMS_V(w, wb) * (w))
#define LMS_P(w, wb, hLen) \
(LMS_U(w, hLen) + LMS_V(w, wb))
#define LMS_PARAMS_SIG_LEN(l, h, p, hLen) \
(4 + (l) * (4 + 4 + 4 + (hLen) * (1 + (p) + (h))) + \
((l) - 1) * LMS_PUBKEY_LEN(hLen))
#ifndef WOLFSSL_WC_LMS_SMALL
#define LMS_PARAMS_CACHE(h) \
(((h) < LMS_ROOT_LEVELS) ? (h) : LMS_ROOT_LEVELS), \
(((h) < LMS_CACHE_BITS ) ? (h) : LMS_CACHE_BITS )
#else
#define LMS_PARAMS_CACHE(h)
#endif
#define LMS_PARAMS(l, h, w, wb, t, t2, hLen) \
{ l, h, w, LMS_LS(w, wb), LMS_P(w, wb, hLen), t, t2, \
LMS_PARAMS_SIG_LEN(l, h, LMS_P(w, wb, hLen), hLen), \
(hLen), LMS_PARAMS_CACHE(h) }
static int wc_lmskey_state_init(LmsState* state, const LmsParams* params)
{
int ret;
XMEMSET(state, 0, sizeof(LmsState));
state->params = params;
ret = wc_InitSha256(&state->hash);
if (ret == 0) {
ret = wc_InitSha256(&state->hash_k);
if (ret != 0) {
wc_Sha256Free(&state->hash);
}
}
return ret;
}
static void wc_lmskey_state_free(LmsState* state)
{
wc_Sha256Free(&state->hash_k);
wc_Sha256Free(&state->hash);
}
static const wc_LmsParamsMap wc_lms_map[] = {
#ifndef WOLFSSL_NO_LMS_SHA256_256
#if LMS_MAX_HEIGHT >= 15
{ WC_LMS_PARM_NONE , "LMS_NONE" ,
LMS_PARAMS(1, 15, 2, 1, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W2,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L1_H15_W2, "LMS/HSS L1_H15_W2",
LMS_PARAMS(1, 15, 2, 1, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W2,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L1_H15_W4, "LMS/HSS L1_H15_W4",
LMS_PARAMS(1, 15, 4, 2, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
#endif
#if LMS_MAX_LEVELS >= 2
#if LMS_MAX_HEIGHT >= 10
{ WC_LMS_PARM_L2_H10_W2, "LMS/HSS L2_H10_W2",
LMS_PARAMS(2, 10, 2, 1, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W2,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L2_H10_W4, "LMS/HSS L2_H10_W4",
LMS_PARAMS(2, 10, 4, 2, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L2_H10_W8, "LMS/HSS L2_H10_W8",
LMS_PARAMS(2, 10, 8, 3, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#endif
#endif
#if LMS_MAX_LEVELS >= 3
{ WC_LMS_PARM_L3_H5_W2 , "LMS/HSS L3_H5_W2" ,
LMS_PARAMS(3, 5, 2, 1, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W2,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L3_H5_W4 , "LMS/HSS L3_H5_W4" ,
LMS_PARAMS(3, 5, 4, 2, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L3_H5_W8 , "LMS/HSS L3_H5_W8" ,
LMS_PARAMS(3, 5, 8, 3, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#if LMS_MAX_HEIGHT >= 10
{ WC_LMS_PARM_L3_H10_W4, "LMS/HSS L3_H10_W4",
LMS_PARAMS(3, 10, 4, 2, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
#endif
#endif
#if LMS_MAX_LEVELS >= 4
{ WC_LMS_PARM_L4_H5_W8 , "LMS/HSS L4_H5_W8" ,
LMS_PARAMS(4, 5, 8, 3, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#endif
{ WC_LMS_PARM_L1_H5_W1 , "LMS/HSS_L1_H5_W1" ,
LMS_PARAMS(1, 5, 1, 1, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W1,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L1_H5_W2 , "LMS/HSS_L1_H5_W2" ,
LMS_PARAMS(1, 5, 2, 1, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W2,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L1_H5_W4 , "LMS/HSS_L1_H5_W4" ,
LMS_PARAMS(1, 5, 4, 2, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L1_H5_W8 , "LMS/HSS_L1_H5_W8" ,
LMS_PARAMS(1, 5, 8, 3, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#if LMS_MAX_HEIGHT >= 10
{ WC_LMS_PARM_L1_H10_W2 , "LMS/HSS_L1_H10_W2",
LMS_PARAMS(1, 10, 2, 1, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W2,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L1_H10_W4 , "LMS/HSS_L1_H10_W4",
LMS_PARAMS(1, 10, 4, 2, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L1_H10_W8 , "LMS/HSS_L1_H10_W8",
LMS_PARAMS(1, 10, 8, 3, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#endif
#if LMS_MAX_HEIGHT >= 15
{ WC_LMS_PARM_L1_H15_W8 , "LMS/HSS L1_H15_W8",
LMS_PARAMS(1, 15, 8, 3, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#endif
#if LMS_MAX_HEIGHT >= 20
{ WC_LMS_PARM_L1_H20_W2 , "LMS/HSS_L1_H20_W2",
LMS_PARAMS(1, 20, 2, 1, LMS_SHA256_M32_H20, LMOTS_SHA256_N32_W2,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L1_H20_W4 , "LMS/HSS_L1_H20_W4",
LMS_PARAMS(1, 20, 4, 2, LMS_SHA256_M32_H20, LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L1_H20_W8 , "LMS/HSS_L1_H20_W8",
LMS_PARAMS(1, 20, 8, 3, LMS_SHA256_M32_H20, LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#endif
#if LMS_MAX_LEVELS >= 2
{ WC_LMS_PARM_L2_H5_W2 , "LMS/HSS_L2_H5_W2" ,
LMS_PARAMS(2, 5, 2, 1, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W2,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L2_H5_W4 , "LMS/HSS_L2_H5_W4" ,
LMS_PARAMS(2, 5, 4, 2, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L2_H5_W8 , "LMS/HSS_L2_H5_W8" ,
LMS_PARAMS(2, 5, 8, 3, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#if LMS_MAX_HEIGHT >= 15
{ WC_LMS_PARM_L2_H15_W2 , "LMS/HSS_L2_H15_W2",
LMS_PARAMS(2, 15, 2, 1, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W2,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L2_H15_W4 , "LMS/HSS_L2_H15_W4",
LMS_PARAMS(2, 15, 4, 2, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L2_H15_W8 , "LMS/HSS_L2_H15_W8",
LMS_PARAMS(2, 15, 8, 3, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#endif
#if LMS_MAX_HEIGHT >= 20
{ WC_LMS_PARM_L2_H20_W2 , "LMS/HSS_L2_H20_W2",
LMS_PARAMS(2, 20, 2, 1, LMS_SHA256_M32_H20, LMOTS_SHA256_N32_W2,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L2_H20_W4 , "LMS/HSS_L2_H20_W4",
LMS_PARAMS(2, 20, 4, 2, LMS_SHA256_M32_H20, LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L2_H20_W8 , "LMS/HSS_L2_H20_W8",
LMS_PARAMS(2, 20, 8, 3, LMS_SHA256_M32_H20, LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#endif
#endif
#if LMS_MAX_LEVELS >= 3
#if LMS_MAX_HEIGHT >= 10
{ WC_LMS_PARM_L3_H10_W8 , "LMS/HSS L3_H10_W8",
LMS_PARAMS(3, 10, 8, 3, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#endif
#endif
#if LMS_MAX_LEVELS >= 4
{ WC_LMS_PARM_L4_H5_W2 , "LMS/HSS L4_H5_W2" ,
LMS_PARAMS(4, 5, 2, 1, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W2,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L4_H5_W4 , "LMS/HSS L4_H5_W4" ,
LMS_PARAMS(4, 5, 4, 2, LMS_SHA256_M32_H5 , LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
#if LMS_MAX_HEIGHT >= 10
{ WC_LMS_PARM_L4_H10_W4 , "LMS/HSS L4_H10_W4",
LMS_PARAMS(4, 10, 4, 2, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W4,
WC_SHA256_DIGEST_SIZE) },
{ WC_LMS_PARM_L4_H10_W8 , "LMS/HSS L4_H10_W8",
LMS_PARAMS(4, 10, 8, 3, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W8,
WC_SHA256_DIGEST_SIZE) },
#endif
#endif
#endif
#ifdef WOLFSSL_LMS_SHA256_192
#if LMS_MAX_HEIGHT >= 15
{ WC_LMS_PARM_SHA256_192_L1_H15_W2, "LMS/HSS_SHA256/192 L1_H15_W2",
LMS_PARAMS(1, 15, 2, 2, LMS_SHA256_M24_H15, LMOTS_SHA256_N24_W2,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L1_H15_W4, "LMS/HSS_SHA256/192 L1_H15_W4",
LMS_PARAMS(1, 15, 4, 3, LMS_SHA256_M24_H15, LMOTS_SHA256_N24_W4,
WC_SHA256_192_DIGEST_SIZE) },
#endif
#if LMS_MAX_LEVELS >= 2
#if LMS_MAX_HEIGHT >= 10
{ WC_LMS_PARM_SHA256_192_L2_H10_W2, "LMS/HSS SHA256/192 L2_H10_W2",
LMS_PARAMS(2, 10, 2, 2, LMS_SHA256_M24_H10, LMOTS_SHA256_N24_W2,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L2_H10_W4, "LMS/HSS SHA256/192 L2_H10_W4",
LMS_PARAMS(2, 10, 4, 3, LMS_SHA256_M24_H10, LMOTS_SHA256_N24_W4,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L2_H10_W8, "LMS/HSS SHA256/192 L2_H10_W8",
LMS_PARAMS(2, 10, 8, 4, LMS_SHA256_M24_H10, LMOTS_SHA256_N24_W8,
WC_SHA256_192_DIGEST_SIZE) },
#endif
#endif
#if LMS_MAX_LEVELS >= 3
{ WC_LMS_PARM_SHA256_192_L3_H5_W2 , "LMS/HSS_SHA256/192 L3_H5_W2" ,
LMS_PARAMS(3, 5, 2, 2, LMS_SHA256_M24_H5 , LMOTS_SHA256_N24_W2,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L3_H5_W4 , "LMS/HSS_SHA256/192 L3_H5_W4" ,
LMS_PARAMS(3, 5, 4, 3, LMS_SHA256_M24_H5 , LMOTS_SHA256_N24_W4,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L3_H5_W8 , "LMS/HSS_SHA256/192 L3_H5_W8" ,
LMS_PARAMS(3, 5, 8, 4, LMS_SHA256_M24_H5 , LMOTS_SHA256_N24_W8,
WC_SHA256_192_DIGEST_SIZE) },
#if LMS_MAX_HEIGHT >= 10
{ WC_LMS_PARM_SHA256_192_L3_H10_W4, "LMS/HSS_SHA256/192 L3_H10_W4",
LMS_PARAMS(3, 10, 4, 3, LMS_SHA256_M24_H10, LMOTS_SHA256_N24_W4,
WC_SHA256_192_DIGEST_SIZE) },
#endif
#endif
#if LMS_MAX_LEVELS >= 4
{ WC_LMS_PARM_SHA256_192_L4_H5_W8 , "LMS/HSS_SHA256/192 L4_H5_W8" ,
LMS_PARAMS(4, 5, 8, 4, LMS_SHA256_M24_H5 , LMOTS_SHA256_N24_W8,
WC_SHA256_192_DIGEST_SIZE) },
#endif
{ WC_LMS_PARM_SHA256_192_L1_H5_W1 , "LMS/HSS_SHA256/192_L1_H5_W1" ,
LMS_PARAMS(1, 5, 1, 2, LMS_SHA256_M24_H5 , LMOTS_SHA256_N24_W1,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L1_H5_W2 , "LMS/HSS_SHA256/192_L1_H5_W2" ,
LMS_PARAMS(1, 5, 2, 2, LMS_SHA256_M24_H5 , LMOTS_SHA256_N24_W2,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L1_H5_W4 , "LMS/HSS_SHA256/192_L1_H5_W4" ,
LMS_PARAMS(1, 5, 4, 3, LMS_SHA256_M24_H5 , LMOTS_SHA256_N24_W4,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L1_H5_W8 , "LMS/HSS_SHA256/192_L1_H5_W8" ,
LMS_PARAMS(1, 5, 8, 4, LMS_SHA256_M24_H5 , LMOTS_SHA256_N24_W8,
WC_SHA256_192_DIGEST_SIZE) },
#if LMS_MAX_HEIGHT >= 10
{ WC_LMS_PARM_SHA256_192_L1_H10_W2 , "LMS/HSS_SHA256/192_L1_H10_W2",
LMS_PARAMS(1, 10, 2, 2, LMS_SHA256_M24_H10, LMOTS_SHA256_N24_W2,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L1_H10_W4 , "LMS/HSS_SHA256/192_L1_H10_W4",
LMS_PARAMS(1, 10, 4, 3, LMS_SHA256_M24_H10, LMOTS_SHA256_N24_W4,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L1_H10_W8 , "LMS/HSS_SHA256/192_L1_H10_W8",
LMS_PARAMS(1, 10, 8, 4, LMS_SHA256_M24_H10, LMOTS_SHA256_N24_W8,
WC_SHA256_192_DIGEST_SIZE) },
#endif
#if LMS_MAX_HEIGHT >= 20
{ WC_LMS_PARM_SHA256_192_L1_H20_W2 , "LMS/HSS_SHA256/192_L1_H20_W2",
LMS_PARAMS(1, 20, 2, 2, LMS_SHA256_M24_H20, LMOTS_SHA256_N24_W2,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L1_H20_W4 , "LMS/HSS_SHA256/192_L1_H20_W4",
LMS_PARAMS(1, 20, 4, 3, LMS_SHA256_M24_H20, LMOTS_SHA256_N24_W4,
WC_SHA256_192_DIGEST_SIZE) },
{ WC_LMS_PARM_SHA256_192_L1_H20_W8 , "LMS/HSS_SHA256/192_L1_H20_W8",
LMS_PARAMS(1, 20, 8, 4, LMS_SHA256_M24_H20, LMOTS_SHA256_N24_W8,
WC_SHA256_192_DIGEST_SIZE) },
#endif
#endif
};
#define WC_LMS_MAP_LEN ((int)(sizeof(wc_lms_map) / sizeof(*wc_lms_map)))
int wc_LmsKey_Init(LmsKey* key, void* heap, int devId)
{
int ret = 0;
(void)heap;
(void)devId;
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
ForceZero(key, sizeof(LmsKey));
#ifndef WOLFSSL_LMS_VERIFY_ONLY
key->write_private_key = NULL;
key->read_private_key = NULL;
key->context = NULL;
key->heap = heap;
#endif
#ifdef WOLF_CRYPTO_CB
key->devId = devId;
#endif
key->state = WC_LMS_STATE_INITED;
}
return ret;
}
const char* wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm)
{
const char* str = NULL;
int i;
for (i = 0; i < WC_LMS_MAP_LEN; i++) {
if (lmsParm == wc_lms_map[i].id) {
str = wc_lms_map[i].str;
break;
}
}
return str;
}
int wc_LmsKey_SetLmsParm(LmsKey* key, enum wc_LmsParm lmsParm)
{
int ret = 0;
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->state != WC_LMS_STATE_INITED)) {
WOLFSSL_MSG("error: LmsKey needs init");
ret = BAD_STATE_E;
}
if (ret == 0) {
int i;
ret = BAD_FUNC_ARG;
for (i = 0; i < WC_LMS_MAP_LEN; i++) {
if (lmsParm == wc_lms_map[i].id) {
key->params = &wc_lms_map[i].params;
ret = 0;
break;
}
}
}
if (ret == 0) {
key->state = WC_LMS_STATE_PARMSET;
}
return ret;
}
int wc_LmsKey_SetParameters(LmsKey* key, int levels, int height,
int winternitz)
{
int ret = 0;
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->state != WC_LMS_STATE_INITED)) {
WOLFSSL_MSG("error: LmsKey needs init");
ret = BAD_STATE_E;
}
if (ret == 0) {
int i;
ret = BAD_FUNC_ARG;
for (i = 0; i < WC_LMS_MAP_LEN; i++) {
if ((levels == wc_lms_map[i].params.levels) &&
(height == wc_lms_map[i].params.height) &&
(winternitz == wc_lms_map[i].params.width)) {
key->params = &wc_lms_map[i].params;
ret = 0;
break;
}
}
}
if (ret == 0) {
key->state = WC_LMS_STATE_PARMSET;
}
return ret;
}
int wc_LmsKey_GetParameters(const LmsKey* key, int* levels, int* height,
int* winternitz)
{
int ret = 0;
if ((key == NULL) || (levels == NULL) || (height == NULL) ||
(winternitz == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->params == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
*levels = key->params->levels;
*height = key->params->height;
*winternitz = key->params->width;
}
return ret;
}
void wc_LmsKey_Free(LmsKey* key)
{
if (key != NULL) {
#ifndef WOLFSSL_LMS_VERIFY_ONLY
if (key->priv_data != NULL) {
const LmsParams* params = key->params;
int priv_data_len = LMS_PRIV_DATA_LEN(params->levels,
params->height, params->p, params->rootLevels,
params->cacheBits, params->hash_len);
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
priv_data_len += HSS_PRIVATE_KEY_LEN(key->params->hash_len);
#endif
ForceZero(key->priv_data, priv_data_len);
XFREE(key->priv_data, key->heap, DYNAMIC_TYPE_LMS);
}
#endif
ForceZero(key, sizeof(LmsKey));
key->state = WC_LMS_STATE_FREED;
}
}
#ifndef WOLFSSL_LMS_VERIFY_ONLY
int wc_LmsKey_SetWriteCb(LmsKey* key, wc_lms_write_private_key_cb write_cb)
{
int ret = 0;
if ((key == NULL) || (write_cb == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->state == WC_LMS_STATE_OK)) {
WOLFSSL_MSG("error: wc_LmsKey_SetWriteCb: key in use");
ret = BAD_STATE_E;
}
if (ret == 0) {
key->write_private_key = write_cb;
}
return ret;
}
int wc_LmsKey_SetReadCb(LmsKey* key, wc_lms_read_private_key_cb read_cb)
{
int ret = 0;
if ((key == NULL) || (read_cb == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->state == WC_LMS_STATE_OK)) {
WOLFSSL_MSG("error: wc_LmsKey_SetReadCb: key in use");
ret = BAD_STATE_E;
}
if (ret == 0) {
key->read_private_key = read_cb;
}
return ret;
}
int wc_LmsKey_SetContext(LmsKey* key, void* context)
{
int ret = 0;
if ((key == NULL) || (context == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->state == WC_LMS_STATE_OK)) {
WOLFSSL_MSG("error: wc_LmsKey_SetContext: key in use");
ret = BAD_STATE_E;
}
if (ret == 0) {
key->context = context;
}
return ret;
}
int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng)
{
int ret = 0;
int priv_data_len = 0;
if ((key == NULL) || (rng == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->state != WC_LMS_STATE_PARMSET)) {
WOLFSSL_MSG("error: LmsKey not ready for generation");
ret = BAD_STATE_E;
}
if ((ret == 0) && (key->write_private_key == NULL)) {
WOLFSSL_MSG("error: LmsKey write callback is not set");
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->context == NULL)) {
WOLFSSL_MSG("error: LmsKey context is not set");
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
const LmsParams* params = key->params;
priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height,
params->p, params->rootLevels, params->cacheBits, params->hash_len);
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
priv_data_len += HSS_PRIVATE_KEY_LEN(key->params->hash_len);
#endif
}
if ((ret == 0) && (key->priv_data == NULL)) {
key->priv_data = (byte *)XMALLOC(priv_data_len, key->heap,
DYNAMIC_TYPE_LMS);
if (key->priv_data == NULL) {
ret = MEMORY_E;
}
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
XMEMSET(key->priv_data, 0, priv_data_len);
#endif
}
if (ret == 0) {
WC_DECLARE_VAR(state, LmsState, 1, 0);
WC_ALLOC_VAR_EX(state, LmsState, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER,
ret=MEMORY_E);
if (WC_VAR_OK(state))
{
ret = wc_lmskey_state_init(state, key->params);
if (ret == 0) {
ret = wc_hss_make_key(state, rng, key->priv_raw, &key->priv,
key->priv_data, key->pub);
wc_lmskey_state_free(state);
}
ForceZero(state, sizeof(LmsState));
WC_FREE_VAR_EX(state, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
if (ret == 0) {
int rv;
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
XMEMCPY(key->priv_data + priv_data_len -
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->priv_raw,
HSS_PRIVATE_KEY_LEN(key->params->hash_len));
rv = key->write_private_key(key->priv_data, priv_data_len,
key->context);
#else
rv = key->write_private_key(key->priv_raw,
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context);
#endif
if (rv != WC_LMS_RC_SAVED_TO_NV_MEMORY) {
ret = IO_FAILED_E;
}
}
if ((ret == 0) && (wc_LmsKey_SigsLeft(key) == 0)) {
WOLFSSL_MSG("error: generated LMS key signatures exhausted");
key->state = WC_LMS_STATE_NOSIGS;
ret = BAD_STATE_E;
}
if (ret == 0) {
key->state = WC_LMS_STATE_OK;
}
return ret;
}
int wc_LmsKey_Reload(LmsKey* key)
{
int ret = 0;
int priv_data_len = 0;
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->state != WC_LMS_STATE_PARMSET)) {
WOLFSSL_MSG("error: LmsKey not ready for reload");
ret = BAD_STATE_E;
}
if ((ret == 0) && (key->read_private_key == NULL)) {
WOLFSSL_MSG("error: LmsKey read callback is not set");
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->context == NULL)) {
WOLFSSL_MSG("error: LmsKey context is not set");
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
const LmsParams* params = key->params;
priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height,
params->p, params->rootLevels, params->cacheBits, params->hash_len);
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
priv_data_len += HSS_PRIVATE_KEY_LEN(params->hash_len);
#endif
}
if ((ret == 0) && (key->priv_data == NULL)) {
key->priv_data = (byte *)XMALLOC(priv_data_len, key->heap,
DYNAMIC_TYPE_LMS);
if (key->priv_data == NULL) {
ret = MEMORY_E;
}
}
if (ret == 0) {
int rv;
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
const LmsParams* params = key->params;
rv = key->read_private_key(key->priv_data, priv_data_len, key->context);
#else
rv = key->read_private_key(key->priv_raw,
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context);
#endif
if (rv != WC_LMS_RC_READ_TO_MEMORY) {
ret = IO_FAILED_E;
}
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
if (ret == 0) {
XMEMCPY(key->priv_raw, key->priv_data + priv_data_len -
HSS_PRIVATE_KEY_LEN(params->hash_len),
HSS_PRIVATE_KEY_LEN(params->hash_len));
}
#endif
}
if ((ret == 0) && (wc_LmsKey_SigsLeft(key) == 0)) {
WOLFSSL_MSG("error: reloaded LMS key signatures exhausted");
key->state = WC_LMS_STATE_NOSIGS;
ret = BAD_STATE_E;
}
if (ret == 0) {
WC_DECLARE_VAR(state, LmsState, 1, 0);
WC_ALLOC_VAR_EX(state, LmsState, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER,
ret=MEMORY_E);
if (WC_VAR_OK(state))
{
ret = wc_lmskey_state_init(state, key->params);
if (ret == 0) {
ret = wc_hss_reload_key(state, key->priv_raw, &key->priv,
key->priv_data, NULL);
wc_lmskey_state_free(state);
}
ForceZero(state, sizeof(LmsState));
WC_FREE_VAR_EX(state, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
if (ret == 0) {
key->state = WC_LMS_STATE_OK;
}
return ret;
}
int wc_LmsKey_GetPrivLen(const LmsKey* key, word32* len)
{
int ret = 0;
if ((key == NULL) || (len == NULL) || (key->params == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
*len = HSS_PRIVATE_KEY_LEN(key->params->hash_len);
}
return ret;
}
int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg,
int msgSz)
{
int ret = 0;
if ((key == NULL) || (sig == NULL) || (sigSz == NULL) || (msg == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (msgSz <= 0)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->state == WC_LMS_STATE_NOSIGS)) {
WOLFSSL_MSG("error: LMS signatures exhausted");
ret = BAD_STATE_E;
}
if ((ret == 0) && (key->state != WC_LMS_STATE_OK)) {
WOLFSSL_MSG("error: can't sign, LMS key not in good state");
ret = BAD_STATE_E;
}
if ((ret == 0) && (*sigSz < key->params->sig_len)) {
WOLFSSL_MSG("error: LMS sig buffer too small");
ret = BUFFER_E;
}
if ((ret == 0) && (key->write_private_key == NULL)) {
WOLFSSL_MSG("error: LmsKey write/read callbacks are not set");
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->context == NULL)) {
WOLFSSL_MSG("error: LmsKey context is not set");
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
WC_DECLARE_VAR(state, LmsState, 1, 0);
WC_ALLOC_VAR_EX(state, LmsState, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER,
ret=MEMORY_E);
if (WC_VAR_OK(state))
{
ret = wc_lmskey_state_init(state, key->params);
if (ret == 0) {
ret = wc_hss_sign(state, key->priv_raw, &key->priv,
key->priv_data, msg, msgSz, sig);
wc_lmskey_state_free(state);
}
ForceZero(state, sizeof(LmsState));
WC_FREE_VAR_EX(state, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
if (ret == 0) {
*sigSz = (word32)key->params->sig_len;
}
if (ret == 0) {
int rv;
#ifdef WOLFSSL_WC_LMS_SERIALIZE_STATE
const LmsParams* params = key->params;
int priv_data_len = LMS_PRIV_DATA_LEN(params->levels, params->height,
params->p, params->rootLevels, params->cacheBits,
params->hash_len) + HSS_PRIVATE_KEY_LEN(key->params->hash_len);
XMEMCPY(key->priv_data + priv_data_len -
HSS_PRIVATE_KEY_LEN(params->hash_len), key->priv_raw,
HSS_PRIVATE_KEY_LEN(params->hash_len));
rv = key->write_private_key(key->priv_data, priv_data_len,
key->context);
#else
rv = key->write_private_key(key->priv_raw,
HSS_PRIVATE_KEY_LEN(key->params->hash_len), key->context);
#endif
if (rv != WC_LMS_RC_SAVED_TO_NV_MEMORY) {
ret = IO_FAILED_E;
}
}
return ret;
}
int wc_LmsKey_SigsLeft(LmsKey* key)
{
int ret = 0;
if (key != NULL) {
ret = wc_hss_sigsleft(key->params, key->priv_raw);
}
return ret;
}
#endif
int wc_LmsKey_GetPubLen(const LmsKey* key, word32* len)
{
int ret = 0;
if ((key == NULL) || (len == NULL) || (key->params == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
*len = HSS_PUBLIC_KEY_LEN(key->params->hash_len);
}
return ret;
}
int wc_LmsKey_ExportPub(LmsKey* keyDst, const LmsKey* keySrc)
{
int ret = 0;
if ((keyDst == NULL) || (keySrc == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
ForceZero(keyDst, sizeof(LmsKey));
keyDst->params = keySrc->params;
XMEMCPY(keyDst->pub, keySrc->pub, sizeof(keySrc->pub));
keyDst->state = WC_LMS_STATE_VERIFYONLY;
}
return ret;
}
int wc_LmsKey_ExportPubRaw(const LmsKey* key, byte* out, word32* outLen)
{
int ret = 0;
if ((key == NULL) || (out == NULL) || (outLen == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) &&
(*outLen < (word32)HSS_PUBLIC_KEY_LEN(key->params->hash_len))) {
ret = BUFFER_E;
}
if (ret == 0) {
XMEMCPY(out, key->pub, HSS_PUBLIC_KEY_LEN(key->params->hash_len));
*outLen = HSS_PUBLIC_KEY_LEN(key->params->hash_len);
}
return ret;
}
int wc_LmsKey_ImportPubRaw(LmsKey* key, const byte* in, word32 inLen)
{
int ret = 0;
if ((key == NULL) || (in == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) &&
(inLen != (word32)HSS_PUBLIC_KEY_LEN(key->params->hash_len))) {
return BUFFER_E;
}
if (ret == 0) {
XMEMCPY(key->pub, in, inLen);
if (key->state != WC_LMS_STATE_OK)
key->state = WC_LMS_STATE_VERIFYONLY;
}
return ret;
}
int wc_LmsKey_GetSigLen(const LmsKey* key, word32* len)
{
int ret = 0;
if ((key == NULL) || (len == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
*len = key->params->sig_len;
}
return ret;
}
int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz,
const byte* msg, int msgSz)
{
int ret = 0;
if ((key == NULL) || (sig == NULL) || (msg == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (key->state != WC_LMS_STATE_OK) &&
(key->state != WC_LMS_STATE_VERIFYONLY)) {
WOLFSSL_MSG("error: LMS key not ready for verification");
ret = BAD_STATE_E;
}
if ((ret == 0) && (sigSz != key->params->sig_len)) {
ret = BUFFER_E;
}
if (ret == 0) {
WC_DECLARE_VAR(state, LmsState, 1, 0);
WC_ALLOC_VAR_EX(state, LmsState, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER,
ret=MEMORY_E);
if (WC_VAR_OK(state))
{
ret = wc_lmskey_state_init(state, key->params);
if (ret == 0) {
ret = wc_hss_verify(state, key->pub, msg, msgSz, sig);
wc_lmskey_state_free(state);
}
ForceZero(state, sizeof(LmsState));
WC_FREE_VAR_EX(state, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
return ret;
}
#ifndef WOLFSSL_LMS_VERIFY_ONLY
int wc_LmsKey_GetKid(LmsKey * key, const byte ** kid, word32* kidSz)
{
word32 offset;
if ((key == NULL) || (kid == NULL) || (kidSz == NULL)) {
return BAD_FUNC_ARG;
}
offset = HSS_Q_LEN + HSS_PRIV_KEY_PARAM_SET_LEN + key->params->hash_len;
*kid = key->priv_raw + offset;
*kidSz = HSS_PRIVATE_KEY_LEN(key->params->hash_len) - offset;
return 0;
}
const byte * wc_LmsKey_GetKidFromPrivRaw(const byte * priv, word32 privSz)
{
word32 seedSz = privSz - HSS_Q_LEN - HSS_PRIV_KEY_PARAM_SET_LEN - LMS_I_LEN;
if (priv == NULL) {
return NULL;
}
if ((seedSz != WC_SHA256_192_DIGEST_SIZE) &&
(seedSz != WC_SHA256_DIGEST_SIZE)) {
return NULL;
}
return priv + privSz - LMS_I_LEN;
}
#endif
#endif