132b31808SJens Wiklander /* 232b31808SJens Wiklander * The LM-OTS one-time public-key signature scheme 332b31808SJens Wiklander * 432b31808SJens Wiklander * Copyright The Mbed TLS Contributors 5*b0563631STom Van Eyck * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 632b31808SJens Wiklander */ 732b31808SJens Wiklander 832b31808SJens Wiklander /* 932b31808SJens Wiklander * The following sources were referenced in the design of this implementation 1032b31808SJens Wiklander * of the LM-OTS algorithm: 1132b31808SJens Wiklander * 1232b31808SJens Wiklander * [1] IETF RFC8554 1332b31808SJens Wiklander * D. McGrew, M. Curcio, S.Fluhrer 1432b31808SJens Wiklander * https://datatracker.ietf.org/doc/html/rfc8554 1532b31808SJens Wiklander * 1632b31808SJens Wiklander * [2] NIST Special Publication 800-208 1732b31808SJens Wiklander * David A. Cooper et. al. 1832b31808SJens Wiklander * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-208.pdf 1932b31808SJens Wiklander */ 2032b31808SJens Wiklander 2132b31808SJens Wiklander #include "common.h" 2232b31808SJens Wiklander 2332b31808SJens Wiklander #if defined(MBEDTLS_LMS_C) 2432b31808SJens Wiklander 2532b31808SJens Wiklander #include <string.h> 2632b31808SJens Wiklander 2732b31808SJens Wiklander #include "lmots.h" 2832b31808SJens Wiklander 2932b31808SJens Wiklander #include "mbedtls/lms.h" 3032b31808SJens Wiklander #include "mbedtls/platform_util.h" 3132b31808SJens Wiklander #include "mbedtls/error.h" 32*b0563631STom Van Eyck #include "psa_util_internal.h" 3332b31808SJens Wiklander 3432b31808SJens Wiklander #include "psa/crypto.h" 3532b31808SJens Wiklander 36*b0563631STom Van Eyck /* Define a local translating function to save code size by not using too many 37*b0563631STom Van Eyck * arguments in each translating place. */ 38*b0563631STom Van Eyck static int local_err_translation(psa_status_t status) 39*b0563631STom Van Eyck { 40*b0563631STom Van Eyck return psa_status_to_mbedtls(status, psa_to_lms_errors, 41*b0563631STom Van Eyck ARRAY_LENGTH(psa_to_lms_errors), 42*b0563631STom Van Eyck psa_generic_status_to_mbedtls); 43*b0563631STom Van Eyck } 44*b0563631STom Van Eyck #define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status) 4532b31808SJens Wiklander 4632b31808SJens Wiklander #define PUBLIC_KEY_TYPE_OFFSET (0) 4732b31808SJens Wiklander #define PUBLIC_KEY_I_KEY_ID_OFFSET (PUBLIC_KEY_TYPE_OFFSET + \ 4832b31808SJens Wiklander MBEDTLS_LMOTS_TYPE_LEN) 4932b31808SJens Wiklander #define PUBLIC_KEY_Q_LEAF_ID_OFFSET (PUBLIC_KEY_I_KEY_ID_OFFSET + \ 5032b31808SJens Wiklander MBEDTLS_LMOTS_I_KEY_ID_LEN) 5132b31808SJens Wiklander #define PUBLIC_KEY_KEY_HASH_OFFSET (PUBLIC_KEY_Q_LEAF_ID_OFFSET + \ 5232b31808SJens Wiklander MBEDTLS_LMOTS_Q_LEAF_ID_LEN) 5332b31808SJens Wiklander 5432b31808SJens Wiklander /* We only support parameter sets that use 8-bit digits, as it does not require 5532b31808SJens Wiklander * translation logic between digits and bytes */ 5632b31808SJens Wiklander #define W_WINTERNITZ_PARAMETER (8u) 5732b31808SJens Wiklander #define CHECKSUM_LEN (2) 5832b31808SJens Wiklander #define I_DIGIT_IDX_LEN (2) 5932b31808SJens Wiklander #define J_HASH_IDX_LEN (1) 6032b31808SJens Wiklander #define D_CONST_LEN (2) 6132b31808SJens Wiklander 6232b31808SJens Wiklander #define DIGIT_MAX_VALUE ((1u << W_WINTERNITZ_PARAMETER) - 1u) 6332b31808SJens Wiklander 6432b31808SJens Wiklander #define D_CONST_LEN (2) 6532b31808SJens Wiklander static const unsigned char D_PUBLIC_CONSTANT_BYTES[D_CONST_LEN] = { 0x80, 0x80 }; 6632b31808SJens Wiklander static const unsigned char D_MESSAGE_CONSTANT_BYTES[D_CONST_LEN] = { 0x81, 0x81 }; 6732b31808SJens Wiklander 6832b31808SJens Wiklander #if defined(MBEDTLS_TEST_HOOKS) 6932b31808SJens Wiklander int (*mbedtls_lmots_sign_private_key_invalidated_hook)(unsigned char *) = NULL; 7032b31808SJens Wiklander #endif /* defined(MBEDTLS_TEST_HOOKS) */ 7132b31808SJens Wiklander 7232b31808SJens Wiklander /* Calculate the checksum digits that are appended to the end of the LMOTS digit 7332b31808SJens Wiklander * string. See NIST SP800-208 section 3.1 or RFC8554 Algorithm 2 for details of 7432b31808SJens Wiklander * the checksum algorithm. 7532b31808SJens Wiklander * 7632b31808SJens Wiklander * params The LMOTS parameter set, I and q values which 7732b31808SJens Wiklander * describe the key being used. 7832b31808SJens Wiklander * 7932b31808SJens Wiklander * digest The digit string to create the digest from. As 8032b31808SJens Wiklander * this does not contain a checksum, it is the same 8132b31808SJens Wiklander * size as a hash output. 8232b31808SJens Wiklander */ 8332b31808SJens Wiklander static unsigned short lmots_checksum_calculate(const mbedtls_lmots_parameters_t *params, 8432b31808SJens Wiklander const unsigned char *digest) 8532b31808SJens Wiklander { 8632b31808SJens Wiklander size_t idx; 8732b31808SJens Wiklander unsigned sum = 0; 8832b31808SJens Wiklander 8932b31808SJens Wiklander for (idx = 0; idx < MBEDTLS_LMOTS_N_HASH_LEN(params->type); idx++) { 9032b31808SJens Wiklander sum += DIGIT_MAX_VALUE - digest[idx]; 9132b31808SJens Wiklander } 9232b31808SJens Wiklander 9332b31808SJens Wiklander return sum; 9432b31808SJens Wiklander } 9532b31808SJens Wiklander 9632b31808SJens Wiklander /* Create the string of digest digits (in the base determined by the Winternitz 9732b31808SJens Wiklander * parameter with the checksum appended to the end (Q || cksm(Q)). See NIST 9832b31808SJens Wiklander * SP800-208 section 3.1 or RFC8554 Algorithm 3 step 5 (also used in Algorithm 9932b31808SJens Wiklander * 4b step 3) for details. 10032b31808SJens Wiklander * 10132b31808SJens Wiklander * params The LMOTS parameter set, I and q values which 10232b31808SJens Wiklander * describe the key being used. 10332b31808SJens Wiklander * 10432b31808SJens Wiklander * msg The message that will be hashed to create the 10532b31808SJens Wiklander * digest. 10632b31808SJens Wiklander * 10732b31808SJens Wiklander * msg_size The size of the message. 10832b31808SJens Wiklander * 10932b31808SJens Wiklander * C_random_value The random value that will be combined with the 11032b31808SJens Wiklander * message digest. This is always the same size as a 11132b31808SJens Wiklander * hash output for whichever hash algorithm is 11232b31808SJens Wiklander * determined by the parameter set. 11332b31808SJens Wiklander * 11432b31808SJens Wiklander * output An output containing the digit string (+ 11532b31808SJens Wiklander * checksum) of length P digits (in the case of 11632b31808SJens Wiklander * MBEDTLS_LMOTS_SHA256_N32_W8, this means it is of 11732b31808SJens Wiklander * size P bytes). 11832b31808SJens Wiklander */ 11932b31808SJens Wiklander static int create_digit_array_with_checksum(const mbedtls_lmots_parameters_t *params, 12032b31808SJens Wiklander const unsigned char *msg, 12132b31808SJens Wiklander size_t msg_len, 12232b31808SJens Wiklander const unsigned char *C_random_value, 12332b31808SJens Wiklander unsigned char *out) 12432b31808SJens Wiklander { 12532b31808SJens Wiklander psa_hash_operation_t op = PSA_HASH_OPERATION_INIT; 12632b31808SJens Wiklander psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 12732b31808SJens Wiklander size_t output_hash_len; 12832b31808SJens Wiklander unsigned short checksum; 12932b31808SJens Wiklander 13032b31808SJens Wiklander status = psa_hash_setup(&op, PSA_ALG_SHA_256); 13132b31808SJens Wiklander if (status != PSA_SUCCESS) { 13232b31808SJens Wiklander goto exit; 13332b31808SJens Wiklander } 13432b31808SJens Wiklander 13532b31808SJens Wiklander status = psa_hash_update(&op, params->I_key_identifier, 13632b31808SJens Wiklander MBEDTLS_LMOTS_I_KEY_ID_LEN); 13732b31808SJens Wiklander if (status != PSA_SUCCESS) { 13832b31808SJens Wiklander goto exit; 13932b31808SJens Wiklander } 14032b31808SJens Wiklander 14132b31808SJens Wiklander status = psa_hash_update(&op, params->q_leaf_identifier, 14232b31808SJens Wiklander MBEDTLS_LMOTS_Q_LEAF_ID_LEN); 14332b31808SJens Wiklander if (status != PSA_SUCCESS) { 14432b31808SJens Wiklander goto exit; 14532b31808SJens Wiklander } 14632b31808SJens Wiklander 14732b31808SJens Wiklander status = psa_hash_update(&op, D_MESSAGE_CONSTANT_BYTES, D_CONST_LEN); 14832b31808SJens Wiklander if (status != PSA_SUCCESS) { 14932b31808SJens Wiklander goto exit; 15032b31808SJens Wiklander } 15132b31808SJens Wiklander 15232b31808SJens Wiklander status = psa_hash_update(&op, C_random_value, 15332b31808SJens Wiklander MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(params->type)); 15432b31808SJens Wiklander if (status != PSA_SUCCESS) { 15532b31808SJens Wiklander goto exit; 15632b31808SJens Wiklander } 15732b31808SJens Wiklander 15832b31808SJens Wiklander status = psa_hash_update(&op, msg, msg_len); 15932b31808SJens Wiklander if (status != PSA_SUCCESS) { 16032b31808SJens Wiklander goto exit; 16132b31808SJens Wiklander } 16232b31808SJens Wiklander 16332b31808SJens Wiklander status = psa_hash_finish(&op, out, 16432b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(params->type), 16532b31808SJens Wiklander &output_hash_len); 16632b31808SJens Wiklander if (status != PSA_SUCCESS) { 16732b31808SJens Wiklander goto exit; 16832b31808SJens Wiklander } 16932b31808SJens Wiklander 17032b31808SJens Wiklander checksum = lmots_checksum_calculate(params, out); 171*b0563631STom Van Eyck MBEDTLS_PUT_UINT16_BE(checksum, out, MBEDTLS_LMOTS_N_HASH_LEN(params->type)); 17232b31808SJens Wiklander 17332b31808SJens Wiklander exit: 17432b31808SJens Wiklander psa_hash_abort(&op); 17532b31808SJens Wiklander 17632b31808SJens Wiklander return PSA_TO_MBEDTLS_ERR(status); 17732b31808SJens Wiklander } 17832b31808SJens Wiklander 17932b31808SJens Wiklander /* Hash each element of the string of digits (+ checksum), producing a hash 18032b31808SJens Wiklander * output for each element. This is used in several places (by varying the 18132b31808SJens Wiklander * hash_idx_min/max_values) in order to calculate a public key from a private 18232b31808SJens Wiklander * key (RFC8554 Algorithm 1 step 4), in order to sign a message (RFC8554 18332b31808SJens Wiklander * Algorithm 3 step 5), and to calculate a public key candidate from a 18432b31808SJens Wiklander * signature and message (RFC8554 Algorithm 4b step 3). 18532b31808SJens Wiklander * 18632b31808SJens Wiklander * params The LMOTS parameter set, I and q values which 18732b31808SJens Wiklander * describe the key being used. 18832b31808SJens Wiklander * 18932b31808SJens Wiklander * x_digit_array The array of digits (of size P, 34 in the case of 19032b31808SJens Wiklander * MBEDTLS_LMOTS_SHA256_N32_W8). 19132b31808SJens Wiklander * 19232b31808SJens Wiklander * hash_idx_min_values An array of the starting values of the j iterator 19332b31808SJens Wiklander * for each of the members of the digit array. If 19432b31808SJens Wiklander * this value in NULL, then all iterators will start 19532b31808SJens Wiklander * at 0. 19632b31808SJens Wiklander * 19732b31808SJens Wiklander * hash_idx_max_values An array of the upper bound values of the j 19832b31808SJens Wiklander * iterator for each of the members of the digit 19932b31808SJens Wiklander * array. If this value in NULL, then iterator is 20032b31808SJens Wiklander * bounded to be less than 2^w - 1 (255 in the case 20132b31808SJens Wiklander * of MBEDTLS_LMOTS_SHA256_N32_W8) 20232b31808SJens Wiklander * 20332b31808SJens Wiklander * output An array containing a hash output for each member 20432b31808SJens Wiklander * of the digit string P. In the case of 20532b31808SJens Wiklander * MBEDTLS_LMOTS_SHA256_N32_W8, this is of size 32 * 20632b31808SJens Wiklander * 34. 20732b31808SJens Wiklander */ 20832b31808SJens Wiklander static int hash_digit_array(const mbedtls_lmots_parameters_t *params, 20932b31808SJens Wiklander const unsigned char *x_digit_array, 21032b31808SJens Wiklander const unsigned char *hash_idx_min_values, 21132b31808SJens Wiklander const unsigned char *hash_idx_max_values, 21232b31808SJens Wiklander unsigned char *output) 21332b31808SJens Wiklander { 21432b31808SJens Wiklander unsigned int i_digit_idx; 21532b31808SJens Wiklander unsigned char i_digit_idx_bytes[I_DIGIT_IDX_LEN]; 21632b31808SJens Wiklander unsigned int j_hash_idx; 21732b31808SJens Wiklander unsigned char j_hash_idx_bytes[J_HASH_IDX_LEN]; 21832b31808SJens Wiklander unsigned int j_hash_idx_min; 21932b31808SJens Wiklander unsigned int j_hash_idx_max; 22032b31808SJens Wiklander psa_hash_operation_t op = PSA_HASH_OPERATION_INIT; 22132b31808SJens Wiklander psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 22232b31808SJens Wiklander size_t output_hash_len; 22332b31808SJens Wiklander unsigned char tmp_hash[MBEDTLS_LMOTS_N_HASH_LEN_MAX]; 22432b31808SJens Wiklander 22532b31808SJens Wiklander for (i_digit_idx = 0; 22632b31808SJens Wiklander i_digit_idx < MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(params->type); 22732b31808SJens Wiklander i_digit_idx++) { 22832b31808SJens Wiklander 22932b31808SJens Wiklander memcpy(tmp_hash, 23032b31808SJens Wiklander &x_digit_array[i_digit_idx * MBEDTLS_LMOTS_N_HASH_LEN(params->type)], 23132b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(params->type)); 23232b31808SJens Wiklander 23332b31808SJens Wiklander j_hash_idx_min = hash_idx_min_values != NULL ? 23432b31808SJens Wiklander hash_idx_min_values[i_digit_idx] : 0; 23532b31808SJens Wiklander j_hash_idx_max = hash_idx_max_values != NULL ? 23632b31808SJens Wiklander hash_idx_max_values[i_digit_idx] : DIGIT_MAX_VALUE; 23732b31808SJens Wiklander 23832b31808SJens Wiklander for (j_hash_idx = j_hash_idx_min; 23932b31808SJens Wiklander j_hash_idx < j_hash_idx_max; 24032b31808SJens Wiklander j_hash_idx++) { 24132b31808SJens Wiklander status = psa_hash_setup(&op, PSA_ALG_SHA_256); 24232b31808SJens Wiklander if (status != PSA_SUCCESS) { 24332b31808SJens Wiklander goto exit; 24432b31808SJens Wiklander } 24532b31808SJens Wiklander 24632b31808SJens Wiklander status = psa_hash_update(&op, 24732b31808SJens Wiklander params->I_key_identifier, 24832b31808SJens Wiklander MBEDTLS_LMOTS_I_KEY_ID_LEN); 24932b31808SJens Wiklander if (status != PSA_SUCCESS) { 25032b31808SJens Wiklander goto exit; 25132b31808SJens Wiklander } 25232b31808SJens Wiklander 25332b31808SJens Wiklander status = psa_hash_update(&op, 25432b31808SJens Wiklander params->q_leaf_identifier, 25532b31808SJens Wiklander MBEDTLS_LMOTS_Q_LEAF_ID_LEN); 25632b31808SJens Wiklander if (status != PSA_SUCCESS) { 25732b31808SJens Wiklander goto exit; 25832b31808SJens Wiklander } 25932b31808SJens Wiklander 260*b0563631STom Van Eyck MBEDTLS_PUT_UINT16_BE(i_digit_idx, i_digit_idx_bytes, 0); 26132b31808SJens Wiklander status = psa_hash_update(&op, i_digit_idx_bytes, I_DIGIT_IDX_LEN); 26232b31808SJens Wiklander if (status != PSA_SUCCESS) { 26332b31808SJens Wiklander goto exit; 26432b31808SJens Wiklander } 26532b31808SJens Wiklander 266*b0563631STom Van Eyck j_hash_idx_bytes[0] = (uint8_t) j_hash_idx; 26732b31808SJens Wiklander status = psa_hash_update(&op, j_hash_idx_bytes, J_HASH_IDX_LEN); 26832b31808SJens Wiklander if (status != PSA_SUCCESS) { 26932b31808SJens Wiklander goto exit; 27032b31808SJens Wiklander } 27132b31808SJens Wiklander 27232b31808SJens Wiklander status = psa_hash_update(&op, tmp_hash, 27332b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(params->type)); 27432b31808SJens Wiklander if (status != PSA_SUCCESS) { 27532b31808SJens Wiklander goto exit; 27632b31808SJens Wiklander } 27732b31808SJens Wiklander 27832b31808SJens Wiklander status = psa_hash_finish(&op, tmp_hash, sizeof(tmp_hash), 27932b31808SJens Wiklander &output_hash_len); 28032b31808SJens Wiklander if (status != PSA_SUCCESS) { 28132b31808SJens Wiklander goto exit; 28232b31808SJens Wiklander } 28332b31808SJens Wiklander 28432b31808SJens Wiklander psa_hash_abort(&op); 28532b31808SJens Wiklander } 28632b31808SJens Wiklander 28732b31808SJens Wiklander memcpy(&output[i_digit_idx * MBEDTLS_LMOTS_N_HASH_LEN(params->type)], 28832b31808SJens Wiklander tmp_hash, MBEDTLS_LMOTS_N_HASH_LEN(params->type)); 28932b31808SJens Wiklander } 29032b31808SJens Wiklander 29132b31808SJens Wiklander exit: 29232b31808SJens Wiklander psa_hash_abort(&op); 29332b31808SJens Wiklander mbedtls_platform_zeroize(tmp_hash, sizeof(tmp_hash)); 29432b31808SJens Wiklander 29532b31808SJens Wiklander return PSA_TO_MBEDTLS_ERR(status); 29632b31808SJens Wiklander } 29732b31808SJens Wiklander 29832b31808SJens Wiklander /* Combine the hashes of the digit array into a public key. This is used in 29932b31808SJens Wiklander * in order to calculate a public key from a private key (RFC8554 Algorithm 1 30032b31808SJens Wiklander * step 4), and to calculate a public key candidate from a signature and message 30132b31808SJens Wiklander * (RFC8554 Algorithm 4b step 3). 30232b31808SJens Wiklander * 30332b31808SJens Wiklander * params The LMOTS parameter set, I and q values which describe 30432b31808SJens Wiklander * the key being used. 30532b31808SJens Wiklander * y_hashed_digits The array of hashes, one hash for each digit of the 30632b31808SJens Wiklander * symbol array (which is of size P, 34 in the case of 30732b31808SJens Wiklander * MBEDTLS_LMOTS_SHA256_N32_W8) 30832b31808SJens Wiklander * 30932b31808SJens Wiklander * pub_key The output public key (or candidate public key in 31032b31808SJens Wiklander * case this is being run as part of signature 31132b31808SJens Wiklander * verification), in the form of a hash output. 31232b31808SJens Wiklander */ 31332b31808SJens Wiklander static int public_key_from_hashed_digit_array(const mbedtls_lmots_parameters_t *params, 31432b31808SJens Wiklander const unsigned char *y_hashed_digits, 31532b31808SJens Wiklander unsigned char *pub_key) 31632b31808SJens Wiklander { 31732b31808SJens Wiklander psa_hash_operation_t op = PSA_HASH_OPERATION_INIT; 31832b31808SJens Wiklander psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 31932b31808SJens Wiklander size_t output_hash_len; 32032b31808SJens Wiklander 32132b31808SJens Wiklander status = psa_hash_setup(&op, PSA_ALG_SHA_256); 32232b31808SJens Wiklander if (status != PSA_SUCCESS) { 32332b31808SJens Wiklander goto exit; 32432b31808SJens Wiklander } 32532b31808SJens Wiklander 32632b31808SJens Wiklander status = psa_hash_update(&op, 32732b31808SJens Wiklander params->I_key_identifier, 32832b31808SJens Wiklander MBEDTLS_LMOTS_I_KEY_ID_LEN); 32932b31808SJens Wiklander if (status != PSA_SUCCESS) { 33032b31808SJens Wiklander goto exit; 33132b31808SJens Wiklander } 33232b31808SJens Wiklander 33332b31808SJens Wiklander status = psa_hash_update(&op, params->q_leaf_identifier, 33432b31808SJens Wiklander MBEDTLS_LMOTS_Q_LEAF_ID_LEN); 33532b31808SJens Wiklander if (status != PSA_SUCCESS) { 33632b31808SJens Wiklander goto exit; 33732b31808SJens Wiklander } 33832b31808SJens Wiklander 33932b31808SJens Wiklander status = psa_hash_update(&op, D_PUBLIC_CONSTANT_BYTES, D_CONST_LEN); 34032b31808SJens Wiklander if (status != PSA_SUCCESS) { 34132b31808SJens Wiklander goto exit; 34232b31808SJens Wiklander } 34332b31808SJens Wiklander 34432b31808SJens Wiklander status = psa_hash_update(&op, y_hashed_digits, 34532b31808SJens Wiklander MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(params->type) * 34632b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(params->type)); 34732b31808SJens Wiklander if (status != PSA_SUCCESS) { 34832b31808SJens Wiklander goto exit; 34932b31808SJens Wiklander } 35032b31808SJens Wiklander 35132b31808SJens Wiklander status = psa_hash_finish(&op, pub_key, 35232b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(params->type), 35332b31808SJens Wiklander &output_hash_len); 35432b31808SJens Wiklander if (status != PSA_SUCCESS) { 35532b31808SJens Wiklander 35632b31808SJens Wiklander exit: 35732b31808SJens Wiklander psa_hash_abort(&op); 35832b31808SJens Wiklander } 35932b31808SJens Wiklander 36032b31808SJens Wiklander return PSA_TO_MBEDTLS_ERR(status); 36132b31808SJens Wiklander } 36232b31808SJens Wiklander 36332b31808SJens Wiklander #if !defined(MBEDTLS_DEPRECATED_REMOVED) 36432b31808SJens Wiklander int mbedtls_lms_error_from_psa(psa_status_t status) 36532b31808SJens Wiklander { 36632b31808SJens Wiklander switch (status) { 36732b31808SJens Wiklander case PSA_SUCCESS: 36832b31808SJens Wiklander return 0; 36932b31808SJens Wiklander case PSA_ERROR_HARDWARE_FAILURE: 37032b31808SJens Wiklander return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED; 37132b31808SJens Wiklander case PSA_ERROR_NOT_SUPPORTED: 37232b31808SJens Wiklander return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; 37332b31808SJens Wiklander case PSA_ERROR_BUFFER_TOO_SMALL: 37432b31808SJens Wiklander return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL; 37532b31808SJens Wiklander case PSA_ERROR_INVALID_ARGUMENT: 37632b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 37732b31808SJens Wiklander default: 37832b31808SJens Wiklander return MBEDTLS_ERR_ERROR_GENERIC_ERROR; 37932b31808SJens Wiklander } 38032b31808SJens Wiklander } 38132b31808SJens Wiklander #endif /* !MBEDTLS_DEPRECATED_REMOVED */ 38232b31808SJens Wiklander 38332b31808SJens Wiklander void mbedtls_lmots_public_init(mbedtls_lmots_public_t *ctx) 38432b31808SJens Wiklander { 38532b31808SJens Wiklander memset(ctx, 0, sizeof(*ctx)); 38632b31808SJens Wiklander } 38732b31808SJens Wiklander 38832b31808SJens Wiklander void mbedtls_lmots_public_free(mbedtls_lmots_public_t *ctx) 38932b31808SJens Wiklander { 39032b31808SJens Wiklander mbedtls_platform_zeroize(ctx, sizeof(*ctx)); 39132b31808SJens Wiklander } 39232b31808SJens Wiklander 39332b31808SJens Wiklander int mbedtls_lmots_import_public_key(mbedtls_lmots_public_t *ctx, 39432b31808SJens Wiklander const unsigned char *key, size_t key_len) 39532b31808SJens Wiklander { 39632b31808SJens Wiklander if (key_len < MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) { 39732b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 39832b31808SJens Wiklander } 39932b31808SJens Wiklander 400*b0563631STom Van Eyck ctx->params.type = (mbedtls_lmots_algorithm_type_t) 401*b0563631STom Van Eyck MBEDTLS_GET_UINT32_BE(key, MBEDTLS_LMOTS_SIG_TYPE_OFFSET); 40232b31808SJens Wiklander 40332b31808SJens Wiklander if (key_len != MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type)) { 40432b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 40532b31808SJens Wiklander } 40632b31808SJens Wiklander 40732b31808SJens Wiklander memcpy(ctx->params.I_key_identifier, 40832b31808SJens Wiklander key + PUBLIC_KEY_I_KEY_ID_OFFSET, 40932b31808SJens Wiklander MBEDTLS_LMOTS_I_KEY_ID_LEN); 41032b31808SJens Wiklander 41132b31808SJens Wiklander memcpy(ctx->params.q_leaf_identifier, 41232b31808SJens Wiklander key + PUBLIC_KEY_Q_LEAF_ID_OFFSET, 41332b31808SJens Wiklander MBEDTLS_LMOTS_Q_LEAF_ID_LEN); 41432b31808SJens Wiklander 41532b31808SJens Wiklander memcpy(ctx->public_key, 41632b31808SJens Wiklander key + PUBLIC_KEY_KEY_HASH_OFFSET, 41732b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type)); 41832b31808SJens Wiklander 41932b31808SJens Wiklander ctx->have_public_key = 1; 42032b31808SJens Wiklander 42132b31808SJens Wiklander return 0; 42232b31808SJens Wiklander } 42332b31808SJens Wiklander 42432b31808SJens Wiklander int mbedtls_lmots_export_public_key(const mbedtls_lmots_public_t *ctx, 42532b31808SJens Wiklander unsigned char *key, size_t key_size, 42632b31808SJens Wiklander size_t *key_len) 42732b31808SJens Wiklander { 42832b31808SJens Wiklander if (key_size < MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type)) { 42932b31808SJens Wiklander return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL; 43032b31808SJens Wiklander } 43132b31808SJens Wiklander 43232b31808SJens Wiklander if (!ctx->have_public_key) { 43332b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 43432b31808SJens Wiklander } 43532b31808SJens Wiklander 436*b0563631STom Van Eyck MBEDTLS_PUT_UINT32_BE(ctx->params.type, key, MBEDTLS_LMOTS_SIG_TYPE_OFFSET); 43732b31808SJens Wiklander 43832b31808SJens Wiklander memcpy(key + PUBLIC_KEY_I_KEY_ID_OFFSET, 43932b31808SJens Wiklander ctx->params.I_key_identifier, 44032b31808SJens Wiklander MBEDTLS_LMOTS_I_KEY_ID_LEN); 44132b31808SJens Wiklander 44232b31808SJens Wiklander memcpy(key + PUBLIC_KEY_Q_LEAF_ID_OFFSET, 44332b31808SJens Wiklander ctx->params.q_leaf_identifier, 44432b31808SJens Wiklander MBEDTLS_LMOTS_Q_LEAF_ID_LEN); 44532b31808SJens Wiklander 44632b31808SJens Wiklander memcpy(key + PUBLIC_KEY_KEY_HASH_OFFSET, ctx->public_key, 44732b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type)); 44832b31808SJens Wiklander 44932b31808SJens Wiklander if (key_len != NULL) { 45032b31808SJens Wiklander *key_len = MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type); 45132b31808SJens Wiklander } 45232b31808SJens Wiklander 45332b31808SJens Wiklander return 0; 45432b31808SJens Wiklander } 45532b31808SJens Wiklander 45632b31808SJens Wiklander int mbedtls_lmots_calculate_public_key_candidate(const mbedtls_lmots_parameters_t *params, 45732b31808SJens Wiklander const unsigned char *msg, 45832b31808SJens Wiklander size_t msg_size, 45932b31808SJens Wiklander const unsigned char *sig, 46032b31808SJens Wiklander size_t sig_size, 46132b31808SJens Wiklander unsigned char *out, 46232b31808SJens Wiklander size_t out_size, 46332b31808SJens Wiklander size_t *out_len) 46432b31808SJens Wiklander { 46532b31808SJens Wiklander unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX]; 46632b31808SJens Wiklander unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX]; 46732b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 46832b31808SJens Wiklander 46932b31808SJens Wiklander if (msg == NULL && msg_size != 0) { 47032b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 47132b31808SJens Wiklander } 47232b31808SJens Wiklander 47332b31808SJens Wiklander if (sig_size != MBEDTLS_LMOTS_SIG_LEN(params->type) || 47432b31808SJens Wiklander out_size < MBEDTLS_LMOTS_N_HASH_LEN(params->type)) { 47532b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 47632b31808SJens Wiklander } 47732b31808SJens Wiklander 47832b31808SJens Wiklander ret = create_digit_array_with_checksum(params, msg, msg_size, 47932b31808SJens Wiklander sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET, 48032b31808SJens Wiklander tmp_digit_array); 48132b31808SJens Wiklander if (ret) { 48232b31808SJens Wiklander return ret; 48332b31808SJens Wiklander } 48432b31808SJens Wiklander 48532b31808SJens Wiklander ret = hash_digit_array(params, 48632b31808SJens Wiklander sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(params->type), 48732b31808SJens Wiklander tmp_digit_array, NULL, (unsigned char *) y_hashed_digits); 48832b31808SJens Wiklander if (ret) { 48932b31808SJens Wiklander return ret; 49032b31808SJens Wiklander } 49132b31808SJens Wiklander 49232b31808SJens Wiklander ret = public_key_from_hashed_digit_array(params, 49332b31808SJens Wiklander (unsigned char *) y_hashed_digits, 49432b31808SJens Wiklander out); 49532b31808SJens Wiklander if (ret) { 49632b31808SJens Wiklander return ret; 49732b31808SJens Wiklander } 49832b31808SJens Wiklander 49932b31808SJens Wiklander if (out_len != NULL) { 50032b31808SJens Wiklander *out_len = MBEDTLS_LMOTS_N_HASH_LEN(params->type); 50132b31808SJens Wiklander } 50232b31808SJens Wiklander 50332b31808SJens Wiklander return 0; 50432b31808SJens Wiklander } 50532b31808SJens Wiklander 50632b31808SJens Wiklander int mbedtls_lmots_verify(const mbedtls_lmots_public_t *ctx, 50732b31808SJens Wiklander const unsigned char *msg, size_t msg_size, 50832b31808SJens Wiklander const unsigned char *sig, size_t sig_size) 50932b31808SJens Wiklander { 51032b31808SJens Wiklander unsigned char Kc_public_key_candidate[MBEDTLS_LMOTS_N_HASH_LEN_MAX]; 51132b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 51232b31808SJens Wiklander 51332b31808SJens Wiklander if (msg == NULL && msg_size != 0) { 51432b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 51532b31808SJens Wiklander } 51632b31808SJens Wiklander 51732b31808SJens Wiklander if (!ctx->have_public_key) { 51832b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 51932b31808SJens Wiklander } 52032b31808SJens Wiklander 52132b31808SJens Wiklander if (ctx->params.type != MBEDTLS_LMOTS_SHA256_N32_W8) { 52232b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 52332b31808SJens Wiklander } 52432b31808SJens Wiklander 52532b31808SJens Wiklander if (sig_size < MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) { 52632b31808SJens Wiklander return MBEDTLS_ERR_LMS_VERIFY_FAILED; 52732b31808SJens Wiklander } 52832b31808SJens Wiklander 529*b0563631STom Van Eyck if (MBEDTLS_GET_UINT32_BE(sig, MBEDTLS_LMOTS_SIG_TYPE_OFFSET) != MBEDTLS_LMOTS_SHA256_N32_W8) { 53032b31808SJens Wiklander return MBEDTLS_ERR_LMS_VERIFY_FAILED; 53132b31808SJens Wiklander } 53232b31808SJens Wiklander 53332b31808SJens Wiklander ret = mbedtls_lmots_calculate_public_key_candidate(&ctx->params, 53432b31808SJens Wiklander msg, msg_size, sig, sig_size, 53532b31808SJens Wiklander Kc_public_key_candidate, 53632b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type), 53732b31808SJens Wiklander NULL); 53832b31808SJens Wiklander if (ret) { 53932b31808SJens Wiklander return MBEDTLS_ERR_LMS_VERIFY_FAILED; 54032b31808SJens Wiklander } 54132b31808SJens Wiklander 54232b31808SJens Wiklander if (memcmp(&Kc_public_key_candidate, ctx->public_key, 54332b31808SJens Wiklander sizeof(ctx->public_key))) { 54432b31808SJens Wiklander return MBEDTLS_ERR_LMS_VERIFY_FAILED; 54532b31808SJens Wiklander } 54632b31808SJens Wiklander 54732b31808SJens Wiklander return 0; 54832b31808SJens Wiklander } 54932b31808SJens Wiklander 55032b31808SJens Wiklander #if defined(MBEDTLS_LMS_PRIVATE) 55132b31808SJens Wiklander 55232b31808SJens Wiklander void mbedtls_lmots_private_init(mbedtls_lmots_private_t *ctx) 55332b31808SJens Wiklander { 55432b31808SJens Wiklander memset(ctx, 0, sizeof(*ctx)); 55532b31808SJens Wiklander } 55632b31808SJens Wiklander 55732b31808SJens Wiklander void mbedtls_lmots_private_free(mbedtls_lmots_private_t *ctx) 55832b31808SJens Wiklander { 55932b31808SJens Wiklander mbedtls_platform_zeroize(ctx, 56032b31808SJens Wiklander sizeof(*ctx)); 56132b31808SJens Wiklander } 56232b31808SJens Wiklander 56332b31808SJens Wiklander int mbedtls_lmots_generate_private_key(mbedtls_lmots_private_t *ctx, 56432b31808SJens Wiklander mbedtls_lmots_algorithm_type_t type, 56532b31808SJens Wiklander const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN], 56632b31808SJens Wiklander uint32_t q_leaf_identifier, 56732b31808SJens Wiklander const unsigned char *seed, 56832b31808SJens Wiklander size_t seed_size) 56932b31808SJens Wiklander { 57032b31808SJens Wiklander psa_hash_operation_t op = PSA_HASH_OPERATION_INIT; 57132b31808SJens Wiklander psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 57232b31808SJens Wiklander size_t output_hash_len; 57332b31808SJens Wiklander unsigned int i_digit_idx; 57432b31808SJens Wiklander unsigned char i_digit_idx_bytes[2]; 575*b0563631STom Van Eyck unsigned char const_bytes[1] = { 0xFF }; 57632b31808SJens Wiklander 57732b31808SJens Wiklander if (ctx->have_private_key) { 57832b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 57932b31808SJens Wiklander } 58032b31808SJens Wiklander 58132b31808SJens Wiklander if (type != MBEDTLS_LMOTS_SHA256_N32_W8) { 58232b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 58332b31808SJens Wiklander } 58432b31808SJens Wiklander 58532b31808SJens Wiklander ctx->params.type = type; 58632b31808SJens Wiklander 58732b31808SJens Wiklander memcpy(ctx->params.I_key_identifier, 58832b31808SJens Wiklander I_key_identifier, 58932b31808SJens Wiklander sizeof(ctx->params.I_key_identifier)); 59032b31808SJens Wiklander 591*b0563631STom Van Eyck MBEDTLS_PUT_UINT32_BE(q_leaf_identifier, ctx->params.q_leaf_identifier, 0); 59232b31808SJens Wiklander 59332b31808SJens Wiklander for (i_digit_idx = 0; 59432b31808SJens Wiklander i_digit_idx < MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type); 59532b31808SJens Wiklander i_digit_idx++) { 59632b31808SJens Wiklander status = psa_hash_setup(&op, PSA_ALG_SHA_256); 59732b31808SJens Wiklander if (status != PSA_SUCCESS) { 59832b31808SJens Wiklander goto exit; 59932b31808SJens Wiklander } 60032b31808SJens Wiklander 60132b31808SJens Wiklander status = psa_hash_update(&op, 60232b31808SJens Wiklander ctx->params.I_key_identifier, 60332b31808SJens Wiklander sizeof(ctx->params.I_key_identifier)); 60432b31808SJens Wiklander if (status != PSA_SUCCESS) { 60532b31808SJens Wiklander goto exit; 60632b31808SJens Wiklander } 60732b31808SJens Wiklander 60832b31808SJens Wiklander status = psa_hash_update(&op, 60932b31808SJens Wiklander ctx->params.q_leaf_identifier, 61032b31808SJens Wiklander MBEDTLS_LMOTS_Q_LEAF_ID_LEN); 61132b31808SJens Wiklander if (status != PSA_SUCCESS) { 61232b31808SJens Wiklander goto exit; 61332b31808SJens Wiklander } 61432b31808SJens Wiklander 615*b0563631STom Van Eyck MBEDTLS_PUT_UINT16_BE(i_digit_idx, i_digit_idx_bytes, 0); 61632b31808SJens Wiklander status = psa_hash_update(&op, i_digit_idx_bytes, I_DIGIT_IDX_LEN); 61732b31808SJens Wiklander if (status != PSA_SUCCESS) { 61832b31808SJens Wiklander goto exit; 61932b31808SJens Wiklander } 62032b31808SJens Wiklander 62132b31808SJens Wiklander status = psa_hash_update(&op, const_bytes, sizeof(const_bytes)); 62232b31808SJens Wiklander if (status != PSA_SUCCESS) { 62332b31808SJens Wiklander goto exit; 62432b31808SJens Wiklander } 62532b31808SJens Wiklander 62632b31808SJens Wiklander status = psa_hash_update(&op, seed, seed_size); 62732b31808SJens Wiklander if (status != PSA_SUCCESS) { 62832b31808SJens Wiklander goto exit; 62932b31808SJens Wiklander } 63032b31808SJens Wiklander 63132b31808SJens Wiklander status = psa_hash_finish(&op, 63232b31808SJens Wiklander ctx->private_key[i_digit_idx], 63332b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type), 63432b31808SJens Wiklander &output_hash_len); 63532b31808SJens Wiklander if (status != PSA_SUCCESS) { 63632b31808SJens Wiklander goto exit; 63732b31808SJens Wiklander } 63832b31808SJens Wiklander 63932b31808SJens Wiklander psa_hash_abort(&op); 64032b31808SJens Wiklander } 64132b31808SJens Wiklander 64232b31808SJens Wiklander ctx->have_private_key = 1; 64332b31808SJens Wiklander 64432b31808SJens Wiklander exit: 64532b31808SJens Wiklander psa_hash_abort(&op); 64632b31808SJens Wiklander 64732b31808SJens Wiklander return PSA_TO_MBEDTLS_ERR(status); 64832b31808SJens Wiklander } 64932b31808SJens Wiklander 65032b31808SJens Wiklander int mbedtls_lmots_calculate_public_key(mbedtls_lmots_public_t *ctx, 65132b31808SJens Wiklander const mbedtls_lmots_private_t *priv_ctx) 65232b31808SJens Wiklander { 65332b31808SJens Wiklander unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX]; 65432b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 65532b31808SJens Wiklander 65632b31808SJens Wiklander /* Check that a private key is loaded */ 65732b31808SJens Wiklander if (!priv_ctx->have_private_key) { 65832b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 65932b31808SJens Wiklander } 66032b31808SJens Wiklander 66132b31808SJens Wiklander ret = hash_digit_array(&priv_ctx->params, 66232b31808SJens Wiklander (unsigned char *) priv_ctx->private_key, NULL, 66332b31808SJens Wiklander NULL, (unsigned char *) y_hashed_digits); 66432b31808SJens Wiklander if (ret) { 66532b31808SJens Wiklander goto exit; 66632b31808SJens Wiklander } 66732b31808SJens Wiklander 66832b31808SJens Wiklander ret = public_key_from_hashed_digit_array(&priv_ctx->params, 66932b31808SJens Wiklander (unsigned char *) y_hashed_digits, 67032b31808SJens Wiklander ctx->public_key); 67132b31808SJens Wiklander if (ret) { 67232b31808SJens Wiklander goto exit; 67332b31808SJens Wiklander } 67432b31808SJens Wiklander 67532b31808SJens Wiklander memcpy(&ctx->params, &priv_ctx->params, 67632b31808SJens Wiklander sizeof(ctx->params)); 67732b31808SJens Wiklander 67832b31808SJens Wiklander ctx->have_public_key = 1; 67932b31808SJens Wiklander 68032b31808SJens Wiklander exit: 68132b31808SJens Wiklander mbedtls_platform_zeroize(y_hashed_digits, sizeof(y_hashed_digits)); 68232b31808SJens Wiklander 68332b31808SJens Wiklander return ret; 68432b31808SJens Wiklander } 68532b31808SJens Wiklander 68632b31808SJens Wiklander int mbedtls_lmots_sign(mbedtls_lmots_private_t *ctx, 68732b31808SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 68832b31808SJens Wiklander void *p_rng, const unsigned char *msg, size_t msg_size, 68932b31808SJens Wiklander unsigned char *sig, size_t sig_size, size_t *sig_len) 69032b31808SJens Wiklander { 69132b31808SJens Wiklander unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX]; 69232b31808SJens Wiklander /* Create a temporary buffer to prepare the signature in. This allows us to 69332b31808SJens Wiklander * finish creating a signature (ensuring the process doesn't fail), and then 69432b31808SJens Wiklander * erase the private key **before** writing any data into the sig parameter 69532b31808SJens Wiklander * buffer. If data were directly written into the sig buffer, it might leak 69632b31808SJens Wiklander * a partial signature on failure, which effectively compromises the private 69732b31808SJens Wiklander * key. 69832b31808SJens Wiklander */ 69932b31808SJens Wiklander unsigned char tmp_sig[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX]; 70032b31808SJens Wiklander unsigned char tmp_c_random[MBEDTLS_LMOTS_N_HASH_LEN_MAX]; 70132b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 70232b31808SJens Wiklander 70332b31808SJens Wiklander if (msg == NULL && msg_size != 0) { 70432b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 70532b31808SJens Wiklander } 70632b31808SJens Wiklander 70732b31808SJens Wiklander if (sig_size < MBEDTLS_LMOTS_SIG_LEN(ctx->params.type)) { 70832b31808SJens Wiklander return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL; 70932b31808SJens Wiklander } 71032b31808SJens Wiklander 71132b31808SJens Wiklander /* Check that a private key is loaded */ 71232b31808SJens Wiklander if (!ctx->have_private_key) { 71332b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; 71432b31808SJens Wiklander } 71532b31808SJens Wiklander 71632b31808SJens Wiklander ret = f_rng(p_rng, tmp_c_random, 71732b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type)); 71832b31808SJens Wiklander if (ret) { 71932b31808SJens Wiklander return ret; 72032b31808SJens Wiklander } 72132b31808SJens Wiklander 72232b31808SJens Wiklander ret = create_digit_array_with_checksum(&ctx->params, 72332b31808SJens Wiklander msg, msg_size, 72432b31808SJens Wiklander tmp_c_random, 72532b31808SJens Wiklander tmp_digit_array); 72632b31808SJens Wiklander if (ret) { 72732b31808SJens Wiklander goto exit; 72832b31808SJens Wiklander } 72932b31808SJens Wiklander 73032b31808SJens Wiklander ret = hash_digit_array(&ctx->params, (unsigned char *) ctx->private_key, 73132b31808SJens Wiklander NULL, tmp_digit_array, (unsigned char *) tmp_sig); 73232b31808SJens Wiklander if (ret) { 73332b31808SJens Wiklander goto exit; 73432b31808SJens Wiklander } 73532b31808SJens Wiklander 736*b0563631STom Van Eyck MBEDTLS_PUT_UINT32_BE(ctx->params.type, sig, MBEDTLS_LMOTS_SIG_TYPE_OFFSET); 73732b31808SJens Wiklander 73832b31808SJens Wiklander /* Test hook to check if sig is being written to before we invalidate the 73932b31808SJens Wiklander * private key. 74032b31808SJens Wiklander */ 74132b31808SJens Wiklander #if defined(MBEDTLS_TEST_HOOKS) 74232b31808SJens Wiklander if (mbedtls_lmots_sign_private_key_invalidated_hook != NULL) { 74332b31808SJens Wiklander ret = (*mbedtls_lmots_sign_private_key_invalidated_hook)(sig); 74432b31808SJens Wiklander if (ret != 0) { 74532b31808SJens Wiklander return ret; 74632b31808SJens Wiklander } 74732b31808SJens Wiklander } 74832b31808SJens Wiklander #endif /* defined(MBEDTLS_TEST_HOOKS) */ 74932b31808SJens Wiklander 75032b31808SJens Wiklander /* We've got a valid signature now, so it's time to make sure the private 75132b31808SJens Wiklander * key can't be reused. 75232b31808SJens Wiklander */ 75332b31808SJens Wiklander ctx->have_private_key = 0; 75432b31808SJens Wiklander mbedtls_platform_zeroize(ctx->private_key, 75532b31808SJens Wiklander sizeof(ctx->private_key)); 75632b31808SJens Wiklander 75732b31808SJens Wiklander memcpy(sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET, tmp_c_random, 75832b31808SJens Wiklander MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(ctx->params.type)); 75932b31808SJens Wiklander 76032b31808SJens Wiklander memcpy(sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(ctx->params.type), tmp_sig, 76132b31808SJens Wiklander MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type) 76232b31808SJens Wiklander * MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type)); 76332b31808SJens Wiklander 76432b31808SJens Wiklander if (sig_len != NULL) { 76532b31808SJens Wiklander *sig_len = MBEDTLS_LMOTS_SIG_LEN(ctx->params.type); 76632b31808SJens Wiklander } 76732b31808SJens Wiklander 76832b31808SJens Wiklander ret = 0; 76932b31808SJens Wiklander 77032b31808SJens Wiklander exit: 77132b31808SJens Wiklander mbedtls_platform_zeroize(tmp_digit_array, sizeof(tmp_digit_array)); 77232b31808SJens Wiklander mbedtls_platform_zeroize(tmp_sig, sizeof(tmp_sig)); 77332b31808SJens Wiklander 77432b31808SJens Wiklander return ret; 77532b31808SJens Wiklander } 77632b31808SJens Wiklander 77732b31808SJens Wiklander #endif /* defined(MBEDTLS_LMS_PRIVATE) */ 77832b31808SJens Wiklander #endif /* defined(MBEDTLS_LMS_C) */ 779