/* wc_lms.c * * Copyright (C) 2006-2026 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 3 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 */ #include #if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS) #include #ifdef NO_INLINE #include #else #define WOLFSSL_MISC_INCLUDED #include #endif /* Calculate u. Appendix B. Works for w of 1, 2, 4, or 8. * * @param [in] w Winternitz width. */ #define LMS_U(w, hLen) \ (8 * (hLen) / (w)) /* Calculate u. Appendix B. Works for w of 1, 2, 4, or 8. * * @param [in] w Winternitz width. * @param [in] wb Winternitz width length in bits. */ #define LMS_V(w, wb) \ (2 + (8 - (wb)) / (w)) /* Calculate ls. Appendix B. Works for w of 1, 2, 4, or 8. * * @param [in] w Winternitz width. * @param [in] wb Winternitz width length in bits. */ #define LMS_LS(w, wb) \ (16 - LMS_V(w, wb) * (w)) /* Calculate p. Appendix B. Works for w of 1, 2, 4, or 8. * * @param [in] w Winternitz width. * @param [in] wb Winternitz width length in bits. */ #define LMS_P(w, wb, hLen) \ (LMS_U(w, hLen) + LMS_V(w, wb)) /* Calculate signature length. * * @param [in] l Number of levels. * @param [in] h Height of the trees. * @param [in] p Number of n-byte string elements in signature for a tree. */ #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 /* Root levels and leaf cache bits. */ #define LMS_PARAMS_CACHE(h) \ (((h) < LMS_ROOT_LEVELS) ? (h) : LMS_ROOT_LEVELS), \ (((h) < LMS_CACHE_BITS ) ? (h) : LMS_CACHE_BITS ) #else /* Root levels and leaf cache bits aren't in structure. */ #define LMS_PARAMS_CACHE(h) /* null expansion */ #endif /* Define parameters entry for LMS. * * @param [in] l Number of levels. * @param [in] h Height of the trees. * @param [in] w Winternitz width. * @param [in] wb Winternitz width length in bits. * @param [in] t LMS type. * @param [in] t2 LM-OTS type. */ #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) } /* Initialize the working state for LMS operations. * * @param [in, out] state LMS state. * @param [in] params LMS parameters. */ static int wc_lmskey_state_init(LmsState* state, const LmsParams* params) { int ret; /* Zero out every field. */ XMEMSET(state, 0, sizeof(LmsState)); /* Keep a reference to the parameters for use in operations. */ state->params = params; /* Initialize the two hash algorithms. */ ret = wc_InitSha256(&state->hash); if (ret == 0) { ret = wc_InitSha256(&state->hash_k); if (ret != 0) { wc_Sha256Free(&state->hash); } } return ret; } /* Free the working state for LMS operations. * * @param [in] state LMS state. */ static void wc_lmskey_state_free(LmsState* state) { wc_Sha256Free(&state->hash_k); wc_Sha256Free(&state->hash); } /* Supported LMS parameters. */ 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 /* For when user sets L, H, W explicitly. */ { 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 /* !WOLFSSL_NO_LMS_SHA256_256 */ #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 /* WOLFSSL_LMS_SHA256_192 */ }; /* Number of parameter sets supported. */ #define WC_LMS_MAP_LEN ((int)(sizeof(wc_lms_map) / sizeof(*wc_lms_map))) /* Initialize LMS key. * * Call this before setting the params of an LMS key. * * @param [out] key LMS key to initialize. * @param [in] heap Heap hint. * @param [in] devId Device identifier. * Use INVALID_DEVID when not using a device. * @return 0 on success. * @return BAD_FUNC_ARG when key is NULL. */ int wc_LmsKey_Init(LmsKey* key, void* heap, int devId) { int ret = 0; (void)heap; (void)devId; /* Validate parameters. */ if (key == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0) { /* Zeroize the key data. */ ForceZero(key, sizeof(LmsKey)); #ifndef WOLFSSL_LMS_VERIFY_ONLY /* Initialize other fields. */ 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 /* Start in initialized state. */ key->state = WC_LMS_STATE_INITED; } return ret; } /* Get the string representation of the LMS parameter set. * * @param [in] lmsParm LMS parameter set identifier. * @return String representing LMS parameter set on success. * @return NULL when parameter set not supported. */ const char* wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm) { const char* str = NULL; int i; /* Search through table for matching numeric identifier. */ for (i = 0; i < WC_LMS_MAP_LEN; i++) { if (lmsParm == wc_lms_map[i].id) { /* Get string corresponding to numeric identifier. */ str = wc_lms_map[i].str; break; } } /* Return the string or NULL. */ return str; } /* 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. * * @param [in, out] key LMS key to set parameters on. * @param [in] lmsParm Identifier of parameters. * @return 0 on success. * @return BAD_FUNC_ARG when key is NULL. * @return BAD_FUNC_ARG when parameters not supported. */ int wc_LmsKey_SetLmsParm(LmsKey* key, enum wc_LmsParm lmsParm) { int ret = 0; /* Validate parameters. */ if (key == NULL) { ret = BAD_FUNC_ARG; } /* Check state is valid. */ 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; /* Search through table for matching numeric identifier. */ for (i = 0; i < WC_LMS_MAP_LEN; i++) { if (lmsParm == wc_lms_map[i].id) { /* Set the parameters into the key. */ key->params = &wc_lms_map[i].params; ret = 0; break; } } } if (ret == 0) { /* Move the state to params set. * Key is ready for MakeKey or Reload. */ key->state = WC_LMS_STATE_PARMSET; } return ret; } /* 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. * * @param [in, out] key LMS key to set parameters on. * @param [in] levels Number of tree levels. * @param [in] height Height of each tree. * @param [in] winternitz Width or Winternitz coefficient. * @return 0 on success. * @return BAD_FUNC_ARG when key is NULL. * @return BAD_FUNC_ARG when parameters not supported. * */ int wc_LmsKey_SetParameters(LmsKey* key, int levels, int height, int winternitz) { int ret = 0; /* Validate parameters. */ if (key == NULL) { ret = BAD_FUNC_ARG; } /* Check state is valid. */ 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; /* Search through table for matching levels, height and width. */ 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)) { /* Set the parameters into the key. */ key->params = &wc_lms_map[i].params; ret = 0; break; } } } if (ret == 0) { /* Move the state to params set. * Key is ready for MakeKey or Reload. */ key->state = WC_LMS_STATE_PARMSET; } return ret; } /* Get the parameters of an LMS key. * * Key must be inited and parameters set before calling this. * * @param [in] key LMS key. * @param [out] levels Number of levels of trees. * @param [out] height Height of the trees. * @param [out] winternitz Winternitz width. * Returns 0 on success. * */ int wc_LmsKey_GetParameters(const LmsKey* key, int* levels, int* height, int* winternitz) { int ret = 0; /* Validate parameters. */ if ((key == NULL) || (levels == NULL) || (height == NULL) || (winternitz == NULL)) { ret = BAD_FUNC_ARG; } /* Validate the parameters are available. */ if ((ret == 0) && (key->params == NULL)) { ret = BAD_FUNC_ARG; } if (ret == 0) { /* Set the levels, height and Winternitz width from parameters. */ *levels = key->params->levels; *height = key->params->height; *winternitz = key->params->width; } return ret; } /* Frees the LMS key from memory. * * This does not affect the private key saved to non-volatile storage. * * @param [in, out] key LMS key to free. */ 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 /* 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. * * @param [in, out] key LMS key. * @param [in] write_cb Callback function that stores private key. * @return 0 on success. * @return BAD_FUNC_ARG when key or write_cb is NULL. * @return BAD_STATE_E when key state is invalid. */ int wc_LmsKey_SetWriteCb(LmsKey* key, wc_lms_write_private_key_cb write_cb) { int ret = 0; /* Validate parameters. */ if ((key == NULL) || (write_cb == NULL)) { ret = BAD_FUNC_ARG; } /* Changing the write callback of an already working key is forbidden. */ 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) { /* Set the callback into the key. */ key->write_private_key = write_cb; } return ret; } /* 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. * * @param [in, out] key LMS key. * @param [in] read_cb Callback function that loads private key. * @return 0 on success. * @return BAD_FUNC_ARG when key or read_cb is NULL. * @return BAD_STATE_E when key state is invalid. * */ int wc_LmsKey_SetReadCb(LmsKey* key, wc_lms_read_private_key_cb read_cb) { int ret = 0; /* Validate parameters. */ if ((key == NULL) || (read_cb == NULL)) { ret = BAD_FUNC_ARG; } /* Changing the read callback of an already working key is forbidden. */ 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) { /* Set the callback into the key. */ key->read_private_key = read_cb; } return ret; } /* 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. * * @param [in, out] key LMS key. * @param [in] context Pointer to data for read/write callbacks. * @return 0 on success. * @return BAD_FUNC_ARG when key or context is NULL. * @return BAD_STATE_E when key state is invalid. * */ int wc_LmsKey_SetContext(LmsKey* key, void* context) { int ret = 0; /* Validate parameters. */ if ((key == NULL) || (context == NULL)) { ret = BAD_FUNC_ARG; } /* Setting context of an already working key is forbidden. */ 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) { /* Set the callback context into the key. */ key->context = context; } return ret; } /* 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. * * @param [in, out] key LMS key. * @param [in] rng Random number generator. * @return 0 on success. * @return BAD_FUNC_ARG when key or rng is NULL. * @return BAD_STATE_E when key is in an invalid state. * @return BAD_FUNC_ARG when write callback or callback context not set. * @return BAD_STATE_E when no more signatures can be created. */ int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng) { int ret = 0; int priv_data_len = 0; /* Validate parameters. */ if ((key == NULL) || (rng == NULL)) { ret = BAD_FUNC_ARG; } /* Check state. */ if ((ret == 0) && (key->state != WC_LMS_STATE_PARMSET)) { WOLFSSL_MSG("error: LmsKey not ready for generation"); ret = BAD_STATE_E; } /* Check write callback set. */ if ((ret == 0) && (key->write_private_key == NULL)) { WOLFSSL_MSG("error: LmsKey write callback is not set"); ret = BAD_FUNC_ARG; } /* Check callback context set. */ 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)) { /* Allocate memory for the private key data. */ key->priv_data = (byte *)XMALLOC(priv_data_len, key->heap, DYNAMIC_TYPE_LMS); /* Check pointer is valid. */ 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); /* Allocate memory for working state. */ WC_ALLOC_VAR_EX(state, LmsState, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER, ret=MEMORY_E); if (WC_VAR_OK(state)) { /* Initialize working state for use. */ ret = wc_lmskey_state_init(state, key->params); if (ret == 0) { /* Make the HSS key. */ 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; /* Write private key to storage. */ #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; } } /* This should not happen, but check whether signatures can be created. */ 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) { /* Update state. */ key->state = WC_LMS_STATE_OK; } return ret; } /* 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. * * @param [in, out] key LMS key. * * Returns 0 on success. */ int wc_LmsKey_Reload(LmsKey* key) { int ret = 0; int priv_data_len = 0; /* Validate parameter. */ if (key == NULL) { ret = BAD_FUNC_ARG; } /* Check state. */ if ((ret == 0) && (key->state != WC_LMS_STATE_PARMSET)) { WOLFSSL_MSG("error: LmsKey not ready for reload"); ret = BAD_STATE_E; } /* Check read callback present. */ if ((ret == 0) && (key->read_private_key == NULL)) { WOLFSSL_MSG("error: LmsKey read callback is not set"); ret = BAD_FUNC_ARG; } /* Check context for callback set */ 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)) { /* Allocate memory for the private key data. */ key->priv_data = (byte *)XMALLOC(priv_data_len, key->heap, DYNAMIC_TYPE_LMS); /* Check pointer is valid. */ if (key->priv_data == NULL) { ret = MEMORY_E; } } if (ret == 0) { int rv; /* Load private key. */ #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 } /* Double check the key actually has signatures left. */ 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); /* Allocate memory for working state. */ WC_ALLOC_VAR_EX(state, LmsState, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER, ret=MEMORY_E); if (WC_VAR_OK(state)) { /* Initialize working state for use. */ ret = wc_lmskey_state_init(state, key->params); if (ret == 0) { /* Reload the key ready for signing. */ 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) { /* Update state. */ key->state = WC_LMS_STATE_OK; } return ret; } /* Get the private key length based on parameter set of key. * * @param [in] key LMS key. * @param [out] len Length of private key. * @return 0 on success. * @return BAD_FUNC_ARG when key or len is NULL or parameters not set. */ int wc_LmsKey_GetPrivLen(const LmsKey* key, word32* len) { int ret = 0; /* Validate parameters. */ if ((key == NULL) || (len == NULL) || (key->params == NULL)) { ret = BAD_FUNC_ARG; } if (ret == 0) { /* Return private key length from parameter set. */ *len = HSS_PRIVATE_KEY_LEN(key->params->hash_len); } return ret; } /* Sign a message. * * @param [in, out] key LMS key to sign with. * @param [out] sig Signature data. Buffer must be big enough to hold * signature data. * @param [out] sigSz Length of signature data. * @param [in] msg Message to sign. * @param [in] msgSz Length of message in bytes. * @return 0 on success. * @return BAD_FUNC_ARG when key, sig, sigSz or msg is NULL. * @return BAD_FUNC_ARG when msgSz is not greater than 0. */ int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg, int msgSz) { int ret = 0; /* Validate parameters. */ if ((key == NULL) || (sig == NULL) || (sigSz == NULL) || (msg == NULL)) { ret = BAD_FUNC_ARG; } if ((ret == 0) && (msgSz <= 0)) { ret = BAD_FUNC_ARG; } /* Check state. */ 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)) { /* 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"); ret = BAD_STATE_E; } if (ret == 0) { WC_DECLARE_VAR(state, LmsState, 1, 0); /* Allocate memory for working state. */ WC_ALLOC_VAR_EX(state, LmsState, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER, ret=MEMORY_E); if (WC_VAR_OK(state)) { /* Initialize working state for use. */ ret = wc_lmskey_state_init(state, key->params); if (ret == 0) { /* Sign message. */ 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; /* Write private key to storage. */ #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; } /* Returns whether signatures can be created with key. * * @param [in] key LMS key. * * @return 1 if there are signatures remaining. * @return 0 if available signatures are exhausted. */ int wc_LmsKey_SigsLeft(LmsKey* key) { int ret = 0; /* NULL keys have no signatures remaining. */ if (key != NULL) { ret = wc_hss_sigsleft(key->params, key->priv_raw); } return ret; } #endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY*/ /* Get the public key length based on parameter set of key. * * @param [in] key LMS key. * @param [out] len Length of public key. * @return 0 on success. * @return BAD_FUNC_ARG when key or len is NULL or parameters not set. */ int wc_LmsKey_GetPubLen(const LmsKey* key, word32* len) { int ret = 0; /* Validate parameters */ 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; } /* 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. * * @param [out] keyDst LMS key to copy into. * @param [in] keySrc LMS key to copy. * @return 0 on success. * @return BAD_FUNC_ARG when keyDst or keySrc is NULL. */ 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)); /* Mark this key as verify only, to prevent misuse. */ keyDst->state = WC_LMS_STATE_VERIFYONLY; } return ret; } /* 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. * * Call wc_LmsKey_GetPubLen beforehand to determine pubLen. * * @param [in] key LMS key. * @param [out] out Buffer to hold encoded public key. * @param [in, out] outLen On in, length of out in bytes. * On out, the length of the public key in bytes. * @return 0 on success. * @return BAD_FUNC_ARG when key, out or outLen is NULL. * @return BUFFER_E when outLen is too small to hold encoded public key. */ int wc_LmsKey_ExportPubRaw(const LmsKey* key, byte* out, word32* outLen) { int ret = 0; /* Validate parameters. */ if ((key == NULL) || (out == NULL) || (outLen == NULL)) { ret = BAD_FUNC_ARG; } /* Check size of out is sufficient. */ if ((ret == 0) && (*outLen < (word32)HSS_PUBLIC_KEY_LEN(key->params->hash_len))) { ret = BUFFER_E; } if (ret == 0) { /* Return encoded public key. */ XMEMCPY(out, key->pub, HSS_PUBLIC_KEY_LEN(key->params->hash_len)); *outLen = HSS_PUBLIC_KEY_LEN(key->params->hash_len); } return ret; } /* 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. * * Call wc_LmsKey_GetPubLen beforehand to determine pubLen. * * @param [in, out] key LMS key to put public key in. * @param [in] in Buffer holding encoded public key. * @param [in] inLen Length of encoded public key in bytes. * @return 0 on success. * @return BAD_FUNC_ARG when key or in is NULL. * @return BUFFER_E when inLen does not match public key length by parameters. */ int wc_LmsKey_ImportPubRaw(LmsKey* key, const byte* in, word32 inLen) { int ret = 0; /* Validate parameters. */ if ((key == NULL) || (in == NULL)) { ret = BAD_FUNC_ARG; } if ((ret == 0) && (inLen != (word32)HSS_PUBLIC_KEY_LEN(key->params->hash_len))) { /* Something inconsistent. Parameters weren't set, or input * pub key is wrong.*/ 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; } /* 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. * * @param [in] key LMS key. * @param [out] len Length of a signature in bytes. * @return 0 on success. * @return BAD_FUNC_ARG when key or len is NULL. */ int wc_LmsKey_GetSigLen(const LmsKey* key, word32* len) { int ret = 0; /* Validate parameters. */ if ((key == NULL) || (len == NULL)) { ret = BAD_FUNC_ARG; } if (ret == 0) { *len = key->params->sig_len; } return ret; } /* Verify the signature of the message with public key. * * @param [in] key LMS key. * @param [in] sig Signature to verify. * @param [in] sigSz Size of signature in bytes. * @param [in] msg Message to verify. * @param [in] msgSz Length of the message in bytes. * @return 0 on success. * @return BAD_FUNC_ARG when a key, sig or msg is NULL. * @return SIG_VERIFY_E when signature did not verify message. * @return BAD_STATE_E when wrong state for operation. * @return BUFFER_E when sigSz is invalid for parameters. */ int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz, const byte* msg, int msgSz) { int ret = 0; /* Validate parameters. */ if ((key == NULL) || (sig == NULL) || (msg == NULL)) { ret = BAD_FUNC_ARG; } /* Check state. */ if ((ret == 0) && (key->state != WC_LMS_STATE_OK) && (key->state != WC_LMS_STATE_VERIFYONLY)) { /* LMS key not ready for verification. Param str must be * set first, and Reload() called. */ WOLFSSL_MSG("error: LMS key not ready for verification"); ret = BAD_STATE_E; } /* Check signature length. */ if ((ret == 0) && (sigSz != key->params->sig_len)) { ret = BUFFER_E; } if (ret == 0) { WC_DECLARE_VAR(state, LmsState, 1, 0); /* Allocate memory for working state. */ WC_ALLOC_VAR_EX(state, LmsState, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER, ret=MEMORY_E); if (WC_VAR_OK(state)) { /* Initialize working state for use. */ ret = wc_lmskey_state_init(state, key->params); if (ret == 0) { /* Verify signature of message with public key. */ 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 /* Get the Key ID from the LMS key. * * PRIV = Q | PARAMS | SEED | I * where I is the Key ID. * * @param [in] key LMS key. * @param [out] kid Key ID data. * @param [out] kidSz Size of key ID. * @return 0 on success. * @return BAD_FUNC_ARG when a key, kid or kidSz is NULL. */ int wc_LmsKey_GetKid(LmsKey * key, const byte ** kid, word32* kidSz) { word32 offset; if ((key == NULL) || (kid == NULL) || (kidSz == NULL)) { return BAD_FUNC_ARG; } /* SEED length is hash length. */ 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; } /* Get the Key ID from the raw private key data. * * PRIV = Q | PARAMS | SEED | I * where I is the Key ID. * * @param [in] priv Private key data. * @param [in] privSz Size of private key data. * @param Pointer to 16 byte Key ID in the private key. * @return NULL on failure. */ 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 /* WOLFSSL_HAVE_LMS && WOLFSSL_WC_LMS */