132b31808SJens Wiklander /*
232b31808SJens Wiklander * The LM-OTS one-time public-key signature scheme
332b31808SJens Wiklander *
432b31808SJens Wiklander * Copyright The Mbed TLS Contributors
5b0563631STom 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"
32b0563631STom Van Eyck #include "psa_util_internal.h"
3332b31808SJens Wiklander
3432b31808SJens Wiklander #include "psa/crypto.h"
3532b31808SJens Wiklander
36b0563631STom Van Eyck /* Define a local translating function to save code size by not using too many
37b0563631STom Van Eyck * arguments in each translating place. */
local_err_translation(psa_status_t status)38b0563631STom Van Eyck static int local_err_translation(psa_status_t status)
39b0563631STom Van Eyck {
40b0563631STom Van Eyck return psa_status_to_mbedtls(status, psa_to_lms_errors,
41b0563631STom Van Eyck ARRAY_LENGTH(psa_to_lms_errors),
42b0563631STom Van Eyck psa_generic_status_to_mbedtls);
43b0563631STom Van Eyck }
44b0563631STom 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 */
lmots_checksum_calculate(const mbedtls_lmots_parameters_t * params,const unsigned char * digest)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 */
create_digit_array_with_checksum(const mbedtls_lmots_parameters_t * params,const unsigned char * msg,size_t msg_len,const unsigned char * C_random_value,unsigned char * out)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);
171b0563631STom 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 */
hash_digit_array(const mbedtls_lmots_parameters_t * params,const unsigned char * x_digit_array,const unsigned char * hash_idx_min_values,const unsigned char * hash_idx_max_values,unsigned char * output)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
260b0563631STom 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
266b0563631STom 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 */
public_key_from_hashed_digit_array(const mbedtls_lmots_parameters_t * params,const unsigned char * y_hashed_digits,unsigned char * pub_key)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)
mbedtls_lms_error_from_psa(psa_status_t status)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
mbedtls_lmots_public_init(mbedtls_lmots_public_t * ctx)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
mbedtls_lmots_public_free(mbedtls_lmots_public_t * ctx)38832b31808SJens Wiklander void mbedtls_lmots_public_free(mbedtls_lmots_public_t *ctx)
38932b31808SJens Wiklander {
390cb034002SJerome Forissier if (ctx == NULL) {
391cb034002SJerome Forissier return;
392cb034002SJerome Forissier }
393cb034002SJerome Forissier
39432b31808SJens Wiklander mbedtls_platform_zeroize(ctx, sizeof(*ctx));
39532b31808SJens Wiklander }
39632b31808SJens Wiklander
mbedtls_lmots_import_public_key(mbedtls_lmots_public_t * ctx,const unsigned char * key,size_t key_len)39732b31808SJens Wiklander int mbedtls_lmots_import_public_key(mbedtls_lmots_public_t *ctx,
39832b31808SJens Wiklander const unsigned char *key, size_t key_len)
39932b31808SJens Wiklander {
40032b31808SJens Wiklander if (key_len < MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
40132b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
40232b31808SJens Wiklander }
40332b31808SJens Wiklander
404*273a583eSThomas Bourgoin uint32_t type = MBEDTLS_GET_UINT32_BE(key, MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
405*273a583eSThomas Bourgoin if (type != (uint32_t) MBEDTLS_LMOTS_SHA256_N32_W8) {
406*273a583eSThomas Bourgoin return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
407*273a583eSThomas Bourgoin }
408*273a583eSThomas Bourgoin ctx->params.type = (mbedtls_lmots_algorithm_type_t) type;
40932b31808SJens Wiklander
41032b31808SJens Wiklander if (key_len != MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type)) {
41132b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
41232b31808SJens Wiklander }
41332b31808SJens Wiklander
41432b31808SJens Wiklander memcpy(ctx->params.I_key_identifier,
41532b31808SJens Wiklander key + PUBLIC_KEY_I_KEY_ID_OFFSET,
41632b31808SJens Wiklander MBEDTLS_LMOTS_I_KEY_ID_LEN);
41732b31808SJens Wiklander
41832b31808SJens Wiklander memcpy(ctx->params.q_leaf_identifier,
41932b31808SJens Wiklander key + PUBLIC_KEY_Q_LEAF_ID_OFFSET,
42032b31808SJens Wiklander MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
42132b31808SJens Wiklander
42232b31808SJens Wiklander memcpy(ctx->public_key,
42332b31808SJens Wiklander key + PUBLIC_KEY_KEY_HASH_OFFSET,
42432b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
42532b31808SJens Wiklander
42632b31808SJens Wiklander ctx->have_public_key = 1;
42732b31808SJens Wiklander
42832b31808SJens Wiklander return 0;
42932b31808SJens Wiklander }
43032b31808SJens Wiklander
mbedtls_lmots_export_public_key(const mbedtls_lmots_public_t * ctx,unsigned char * key,size_t key_size,size_t * key_len)43132b31808SJens Wiklander int mbedtls_lmots_export_public_key(const mbedtls_lmots_public_t *ctx,
43232b31808SJens Wiklander unsigned char *key, size_t key_size,
43332b31808SJens Wiklander size_t *key_len)
43432b31808SJens Wiklander {
43532b31808SJens Wiklander if (key_size < MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type)) {
43632b31808SJens Wiklander return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
43732b31808SJens Wiklander }
43832b31808SJens Wiklander
43932b31808SJens Wiklander if (!ctx->have_public_key) {
44032b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
44132b31808SJens Wiklander }
44232b31808SJens Wiklander
443b0563631STom Van Eyck MBEDTLS_PUT_UINT32_BE(ctx->params.type, key, MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
44432b31808SJens Wiklander
44532b31808SJens Wiklander memcpy(key + PUBLIC_KEY_I_KEY_ID_OFFSET,
44632b31808SJens Wiklander ctx->params.I_key_identifier,
44732b31808SJens Wiklander MBEDTLS_LMOTS_I_KEY_ID_LEN);
44832b31808SJens Wiklander
44932b31808SJens Wiklander memcpy(key + PUBLIC_KEY_Q_LEAF_ID_OFFSET,
45032b31808SJens Wiklander ctx->params.q_leaf_identifier,
45132b31808SJens Wiklander MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
45232b31808SJens Wiklander
45332b31808SJens Wiklander memcpy(key + PUBLIC_KEY_KEY_HASH_OFFSET, ctx->public_key,
45432b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
45532b31808SJens Wiklander
45632b31808SJens Wiklander if (key_len != NULL) {
45732b31808SJens Wiklander *key_len = MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type);
45832b31808SJens Wiklander }
45932b31808SJens Wiklander
46032b31808SJens Wiklander return 0;
46132b31808SJens Wiklander }
46232b31808SJens Wiklander
mbedtls_lmots_calculate_public_key_candidate(const mbedtls_lmots_parameters_t * params,const unsigned char * msg,size_t msg_size,const unsigned char * sig,size_t sig_size,unsigned char * out,size_t out_size,size_t * out_len)46332b31808SJens Wiklander int mbedtls_lmots_calculate_public_key_candidate(const mbedtls_lmots_parameters_t *params,
46432b31808SJens Wiklander const unsigned char *msg,
46532b31808SJens Wiklander size_t msg_size,
46632b31808SJens Wiklander const unsigned char *sig,
46732b31808SJens Wiklander size_t sig_size,
46832b31808SJens Wiklander unsigned char *out,
46932b31808SJens Wiklander size_t out_size,
47032b31808SJens Wiklander size_t *out_len)
47132b31808SJens Wiklander {
47232b31808SJens Wiklander unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX];
47332b31808SJens Wiklander unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
47432b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
47532b31808SJens Wiklander
47632b31808SJens Wiklander if (msg == NULL && msg_size != 0) {
47732b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
47832b31808SJens Wiklander }
47932b31808SJens Wiklander
48032b31808SJens Wiklander if (sig_size != MBEDTLS_LMOTS_SIG_LEN(params->type) ||
48132b31808SJens Wiklander out_size < MBEDTLS_LMOTS_N_HASH_LEN(params->type)) {
48232b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
48332b31808SJens Wiklander }
48432b31808SJens Wiklander
48532b31808SJens Wiklander ret = create_digit_array_with_checksum(params, msg, msg_size,
48632b31808SJens Wiklander sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET,
48732b31808SJens Wiklander tmp_digit_array);
48832b31808SJens Wiklander if (ret) {
48932b31808SJens Wiklander return ret;
49032b31808SJens Wiklander }
49132b31808SJens Wiklander
49232b31808SJens Wiklander ret = hash_digit_array(params,
49332b31808SJens Wiklander sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(params->type),
49432b31808SJens Wiklander tmp_digit_array, NULL, (unsigned char *) y_hashed_digits);
49532b31808SJens Wiklander if (ret) {
49632b31808SJens Wiklander return ret;
49732b31808SJens Wiklander }
49832b31808SJens Wiklander
49932b31808SJens Wiklander ret = public_key_from_hashed_digit_array(params,
50032b31808SJens Wiklander (unsigned char *) y_hashed_digits,
50132b31808SJens Wiklander out);
50232b31808SJens Wiklander if (ret) {
50332b31808SJens Wiklander return ret;
50432b31808SJens Wiklander }
50532b31808SJens Wiklander
50632b31808SJens Wiklander if (out_len != NULL) {
50732b31808SJens Wiklander *out_len = MBEDTLS_LMOTS_N_HASH_LEN(params->type);
50832b31808SJens Wiklander }
50932b31808SJens Wiklander
51032b31808SJens Wiklander return 0;
51132b31808SJens Wiklander }
51232b31808SJens Wiklander
mbedtls_lmots_verify(const mbedtls_lmots_public_t * ctx,const unsigned char * msg,size_t msg_size,const unsigned char * sig,size_t sig_size)51332b31808SJens Wiklander int mbedtls_lmots_verify(const mbedtls_lmots_public_t *ctx,
51432b31808SJens Wiklander const unsigned char *msg, size_t msg_size,
51532b31808SJens Wiklander const unsigned char *sig, size_t sig_size)
51632b31808SJens Wiklander {
51732b31808SJens Wiklander unsigned char Kc_public_key_candidate[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
51832b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
51932b31808SJens Wiklander
52032b31808SJens Wiklander if (msg == NULL && msg_size != 0) {
52132b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
52232b31808SJens Wiklander }
52332b31808SJens Wiklander
52432b31808SJens Wiklander if (!ctx->have_public_key) {
52532b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
52632b31808SJens Wiklander }
52732b31808SJens Wiklander
52832b31808SJens Wiklander if (ctx->params.type != MBEDTLS_LMOTS_SHA256_N32_W8) {
52932b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
53032b31808SJens Wiklander }
53132b31808SJens Wiklander
53232b31808SJens Wiklander if (sig_size < MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
53332b31808SJens Wiklander return MBEDTLS_ERR_LMS_VERIFY_FAILED;
53432b31808SJens Wiklander }
53532b31808SJens Wiklander
536b0563631STom Van Eyck if (MBEDTLS_GET_UINT32_BE(sig, MBEDTLS_LMOTS_SIG_TYPE_OFFSET) != MBEDTLS_LMOTS_SHA256_N32_W8) {
53732b31808SJens Wiklander return MBEDTLS_ERR_LMS_VERIFY_FAILED;
53832b31808SJens Wiklander }
53932b31808SJens Wiklander
54032b31808SJens Wiklander ret = mbedtls_lmots_calculate_public_key_candidate(&ctx->params,
54132b31808SJens Wiklander msg, msg_size, sig, sig_size,
54232b31808SJens Wiklander Kc_public_key_candidate,
54332b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type),
54432b31808SJens Wiklander NULL);
54532b31808SJens Wiklander if (ret) {
54632b31808SJens Wiklander return MBEDTLS_ERR_LMS_VERIFY_FAILED;
54732b31808SJens Wiklander }
54832b31808SJens Wiklander
54932b31808SJens Wiklander if (memcmp(&Kc_public_key_candidate, ctx->public_key,
55032b31808SJens Wiklander sizeof(ctx->public_key))) {
55132b31808SJens Wiklander return MBEDTLS_ERR_LMS_VERIFY_FAILED;
55232b31808SJens Wiklander }
55332b31808SJens Wiklander
55432b31808SJens Wiklander return 0;
55532b31808SJens Wiklander }
55632b31808SJens Wiklander
55732b31808SJens Wiklander #if defined(MBEDTLS_LMS_PRIVATE)
55832b31808SJens Wiklander
mbedtls_lmots_private_init(mbedtls_lmots_private_t * ctx)55932b31808SJens Wiklander void mbedtls_lmots_private_init(mbedtls_lmots_private_t *ctx)
56032b31808SJens Wiklander {
56132b31808SJens Wiklander memset(ctx, 0, sizeof(*ctx));
56232b31808SJens Wiklander }
56332b31808SJens Wiklander
mbedtls_lmots_private_free(mbedtls_lmots_private_t * ctx)56432b31808SJens Wiklander void mbedtls_lmots_private_free(mbedtls_lmots_private_t *ctx)
56532b31808SJens Wiklander {
566cb034002SJerome Forissier if (ctx == NULL) {
567cb034002SJerome Forissier return;
568cb034002SJerome Forissier }
569cb034002SJerome Forissier
57032b31808SJens Wiklander mbedtls_platform_zeroize(ctx,
57132b31808SJens Wiklander sizeof(*ctx));
57232b31808SJens Wiklander }
57332b31808SJens Wiklander
mbedtls_lmots_generate_private_key(mbedtls_lmots_private_t * ctx,mbedtls_lmots_algorithm_type_t type,const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],uint32_t q_leaf_identifier,const unsigned char * seed,size_t seed_size)57432b31808SJens Wiklander int mbedtls_lmots_generate_private_key(mbedtls_lmots_private_t *ctx,
57532b31808SJens Wiklander mbedtls_lmots_algorithm_type_t type,
57632b31808SJens Wiklander const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
57732b31808SJens Wiklander uint32_t q_leaf_identifier,
57832b31808SJens Wiklander const unsigned char *seed,
57932b31808SJens Wiklander size_t seed_size)
58032b31808SJens Wiklander {
58132b31808SJens Wiklander psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
58232b31808SJens Wiklander psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
58332b31808SJens Wiklander size_t output_hash_len;
58432b31808SJens Wiklander unsigned int i_digit_idx;
58532b31808SJens Wiklander unsigned char i_digit_idx_bytes[2];
586b0563631STom Van Eyck unsigned char const_bytes[1] = { 0xFF };
58732b31808SJens Wiklander
58832b31808SJens Wiklander if (ctx->have_private_key) {
58932b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
59032b31808SJens Wiklander }
59132b31808SJens Wiklander
59232b31808SJens Wiklander if (type != MBEDTLS_LMOTS_SHA256_N32_W8) {
59332b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
59432b31808SJens Wiklander }
59532b31808SJens Wiklander
59632b31808SJens Wiklander ctx->params.type = type;
59732b31808SJens Wiklander
59832b31808SJens Wiklander memcpy(ctx->params.I_key_identifier,
59932b31808SJens Wiklander I_key_identifier,
60032b31808SJens Wiklander sizeof(ctx->params.I_key_identifier));
60132b31808SJens Wiklander
602b0563631STom Van Eyck MBEDTLS_PUT_UINT32_BE(q_leaf_identifier, ctx->params.q_leaf_identifier, 0);
60332b31808SJens Wiklander
60432b31808SJens Wiklander for (i_digit_idx = 0;
60532b31808SJens Wiklander i_digit_idx < MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type);
60632b31808SJens Wiklander i_digit_idx++) {
60732b31808SJens Wiklander status = psa_hash_setup(&op, PSA_ALG_SHA_256);
60832b31808SJens Wiklander if (status != PSA_SUCCESS) {
60932b31808SJens Wiklander goto exit;
61032b31808SJens Wiklander }
61132b31808SJens Wiklander
61232b31808SJens Wiklander status = psa_hash_update(&op,
61332b31808SJens Wiklander ctx->params.I_key_identifier,
61432b31808SJens Wiklander sizeof(ctx->params.I_key_identifier));
61532b31808SJens Wiklander if (status != PSA_SUCCESS) {
61632b31808SJens Wiklander goto exit;
61732b31808SJens Wiklander }
61832b31808SJens Wiklander
61932b31808SJens Wiklander status = psa_hash_update(&op,
62032b31808SJens Wiklander ctx->params.q_leaf_identifier,
62132b31808SJens Wiklander MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
62232b31808SJens Wiklander if (status != PSA_SUCCESS) {
62332b31808SJens Wiklander goto exit;
62432b31808SJens Wiklander }
62532b31808SJens Wiklander
626b0563631STom Van Eyck MBEDTLS_PUT_UINT16_BE(i_digit_idx, i_digit_idx_bytes, 0);
62732b31808SJens Wiklander status = psa_hash_update(&op, i_digit_idx_bytes, I_DIGIT_IDX_LEN);
62832b31808SJens Wiklander if (status != PSA_SUCCESS) {
62932b31808SJens Wiklander goto exit;
63032b31808SJens Wiklander }
63132b31808SJens Wiklander
63232b31808SJens Wiklander status = psa_hash_update(&op, const_bytes, sizeof(const_bytes));
63332b31808SJens Wiklander if (status != PSA_SUCCESS) {
63432b31808SJens Wiklander goto exit;
63532b31808SJens Wiklander }
63632b31808SJens Wiklander
63732b31808SJens Wiklander status = psa_hash_update(&op, seed, seed_size);
63832b31808SJens Wiklander if (status != PSA_SUCCESS) {
63932b31808SJens Wiklander goto exit;
64032b31808SJens Wiklander }
64132b31808SJens Wiklander
64232b31808SJens Wiklander status = psa_hash_finish(&op,
64332b31808SJens Wiklander ctx->private_key[i_digit_idx],
64432b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type),
64532b31808SJens Wiklander &output_hash_len);
64632b31808SJens Wiklander if (status != PSA_SUCCESS) {
64732b31808SJens Wiklander goto exit;
64832b31808SJens Wiklander }
64932b31808SJens Wiklander
65032b31808SJens Wiklander psa_hash_abort(&op);
65132b31808SJens Wiklander }
65232b31808SJens Wiklander
65332b31808SJens Wiklander ctx->have_private_key = 1;
65432b31808SJens Wiklander
65532b31808SJens Wiklander exit:
65632b31808SJens Wiklander psa_hash_abort(&op);
65732b31808SJens Wiklander
65832b31808SJens Wiklander return PSA_TO_MBEDTLS_ERR(status);
65932b31808SJens Wiklander }
66032b31808SJens Wiklander
mbedtls_lmots_calculate_public_key(mbedtls_lmots_public_t * ctx,const mbedtls_lmots_private_t * priv_ctx)66132b31808SJens Wiklander int mbedtls_lmots_calculate_public_key(mbedtls_lmots_public_t *ctx,
66232b31808SJens Wiklander const mbedtls_lmots_private_t *priv_ctx)
66332b31808SJens Wiklander {
66432b31808SJens Wiklander unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
66532b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
66632b31808SJens Wiklander
66732b31808SJens Wiklander /* Check that a private key is loaded */
66832b31808SJens Wiklander if (!priv_ctx->have_private_key) {
66932b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
67032b31808SJens Wiklander }
67132b31808SJens Wiklander
67232b31808SJens Wiklander ret = hash_digit_array(&priv_ctx->params,
67332b31808SJens Wiklander (unsigned char *) priv_ctx->private_key, NULL,
67432b31808SJens Wiklander NULL, (unsigned char *) y_hashed_digits);
67532b31808SJens Wiklander if (ret) {
67632b31808SJens Wiklander goto exit;
67732b31808SJens Wiklander }
67832b31808SJens Wiklander
67932b31808SJens Wiklander ret = public_key_from_hashed_digit_array(&priv_ctx->params,
68032b31808SJens Wiklander (unsigned char *) y_hashed_digits,
68132b31808SJens Wiklander ctx->public_key);
68232b31808SJens Wiklander if (ret) {
68332b31808SJens Wiklander goto exit;
68432b31808SJens Wiklander }
68532b31808SJens Wiklander
68632b31808SJens Wiklander memcpy(&ctx->params, &priv_ctx->params,
68732b31808SJens Wiklander sizeof(ctx->params));
68832b31808SJens Wiklander
68932b31808SJens Wiklander ctx->have_public_key = 1;
69032b31808SJens Wiklander
69132b31808SJens Wiklander exit:
69232b31808SJens Wiklander mbedtls_platform_zeroize(y_hashed_digits, sizeof(y_hashed_digits));
69332b31808SJens Wiklander
69432b31808SJens Wiklander return ret;
69532b31808SJens Wiklander }
69632b31808SJens Wiklander
mbedtls_lmots_sign(mbedtls_lmots_private_t * ctx,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng,const unsigned char * msg,size_t msg_size,unsigned char * sig,size_t sig_size,size_t * sig_len)69732b31808SJens Wiklander int mbedtls_lmots_sign(mbedtls_lmots_private_t *ctx,
69832b31808SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t),
69932b31808SJens Wiklander void *p_rng, const unsigned char *msg, size_t msg_size,
70032b31808SJens Wiklander unsigned char *sig, size_t sig_size, size_t *sig_len)
70132b31808SJens Wiklander {
70232b31808SJens Wiklander unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX];
70332b31808SJens Wiklander /* Create a temporary buffer to prepare the signature in. This allows us to
70432b31808SJens Wiklander * finish creating a signature (ensuring the process doesn't fail), and then
70532b31808SJens Wiklander * erase the private key **before** writing any data into the sig parameter
70632b31808SJens Wiklander * buffer. If data were directly written into the sig buffer, it might leak
70732b31808SJens Wiklander * a partial signature on failure, which effectively compromises the private
70832b31808SJens Wiklander * key.
70932b31808SJens Wiklander */
71032b31808SJens Wiklander unsigned char tmp_sig[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
71132b31808SJens Wiklander unsigned char tmp_c_random[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
71232b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
71332b31808SJens Wiklander
71432b31808SJens Wiklander if (msg == NULL && msg_size != 0) {
71532b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
71632b31808SJens Wiklander }
71732b31808SJens Wiklander
71832b31808SJens Wiklander if (sig_size < MBEDTLS_LMOTS_SIG_LEN(ctx->params.type)) {
71932b31808SJens Wiklander return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
72032b31808SJens Wiklander }
72132b31808SJens Wiklander
72232b31808SJens Wiklander /* Check that a private key is loaded */
72332b31808SJens Wiklander if (!ctx->have_private_key) {
72432b31808SJens Wiklander return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
72532b31808SJens Wiklander }
72632b31808SJens Wiklander
72732b31808SJens Wiklander ret = f_rng(p_rng, tmp_c_random,
72832b31808SJens Wiklander MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
72932b31808SJens Wiklander if (ret) {
73032b31808SJens Wiklander return ret;
73132b31808SJens Wiklander }
73232b31808SJens Wiklander
73332b31808SJens Wiklander ret = create_digit_array_with_checksum(&ctx->params,
73432b31808SJens Wiklander msg, msg_size,
73532b31808SJens Wiklander tmp_c_random,
73632b31808SJens Wiklander tmp_digit_array);
73732b31808SJens Wiklander if (ret) {
73832b31808SJens Wiklander goto exit;
73932b31808SJens Wiklander }
74032b31808SJens Wiklander
74132b31808SJens Wiklander ret = hash_digit_array(&ctx->params, (unsigned char *) ctx->private_key,
74232b31808SJens Wiklander NULL, tmp_digit_array, (unsigned char *) tmp_sig);
74332b31808SJens Wiklander if (ret) {
74432b31808SJens Wiklander goto exit;
74532b31808SJens Wiklander }
74632b31808SJens Wiklander
747b0563631STom Van Eyck MBEDTLS_PUT_UINT32_BE(ctx->params.type, sig, MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
74832b31808SJens Wiklander
74932b31808SJens Wiklander /* Test hook to check if sig is being written to before we invalidate the
75032b31808SJens Wiklander * private key.
75132b31808SJens Wiklander */
75232b31808SJens Wiklander #if defined(MBEDTLS_TEST_HOOKS)
75332b31808SJens Wiklander if (mbedtls_lmots_sign_private_key_invalidated_hook != NULL) {
75432b31808SJens Wiklander ret = (*mbedtls_lmots_sign_private_key_invalidated_hook)(sig);
75532b31808SJens Wiklander if (ret != 0) {
75632b31808SJens Wiklander return ret;
75732b31808SJens Wiklander }
75832b31808SJens Wiklander }
75932b31808SJens Wiklander #endif /* defined(MBEDTLS_TEST_HOOKS) */
76032b31808SJens Wiklander
76132b31808SJens Wiklander /* We've got a valid signature now, so it's time to make sure the private
76232b31808SJens Wiklander * key can't be reused.
76332b31808SJens Wiklander */
76432b31808SJens Wiklander ctx->have_private_key = 0;
76532b31808SJens Wiklander mbedtls_platform_zeroize(ctx->private_key,
76632b31808SJens Wiklander sizeof(ctx->private_key));
76732b31808SJens Wiklander
76832b31808SJens Wiklander memcpy(sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET, tmp_c_random,
76932b31808SJens Wiklander MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(ctx->params.type));
77032b31808SJens Wiklander
77132b31808SJens Wiklander memcpy(sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(ctx->params.type), tmp_sig,
77232b31808SJens Wiklander MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type)
77332b31808SJens Wiklander * MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
77432b31808SJens Wiklander
77532b31808SJens Wiklander if (sig_len != NULL) {
77632b31808SJens Wiklander *sig_len = MBEDTLS_LMOTS_SIG_LEN(ctx->params.type);
77732b31808SJens Wiklander }
77832b31808SJens Wiklander
77932b31808SJens Wiklander ret = 0;
78032b31808SJens Wiklander
78132b31808SJens Wiklander exit:
78232b31808SJens Wiklander mbedtls_platform_zeroize(tmp_digit_array, sizeof(tmp_digit_array));
78332b31808SJens Wiklander mbedtls_platform_zeroize(tmp_sig, sizeof(tmp_sig));
78432b31808SJens Wiklander
78532b31808SJens Wiklander return ret;
78632b31808SJens Wiklander }
78732b31808SJens Wiklander
78832b31808SJens Wiklander #endif /* defined(MBEDTLS_LMS_PRIVATE) */
78932b31808SJens Wiklander #endif /* defined(MBEDTLS_LMS_C) */
790