xref: /aosp_15_r20/external/mbedtls/library/lmots.c (revision 62c56f9862f102b96d72393aff6076c951fb8148)
1*62c56f98SSadaf Ebrahimi /*
2*62c56f98SSadaf Ebrahimi  * The LM-OTS one-time public-key signature scheme
3*62c56f98SSadaf Ebrahimi  *
4*62c56f98SSadaf Ebrahimi  * Copyright The Mbed TLS Contributors
5*62c56f98SSadaf Ebrahimi  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6*62c56f98SSadaf Ebrahimi  */
7*62c56f98SSadaf Ebrahimi 
8*62c56f98SSadaf Ebrahimi /*
9*62c56f98SSadaf Ebrahimi  *  The following sources were referenced in the design of this implementation
10*62c56f98SSadaf Ebrahimi  *  of the LM-OTS algorithm:
11*62c56f98SSadaf Ebrahimi  *
12*62c56f98SSadaf Ebrahimi  *  [1] IETF RFC8554
13*62c56f98SSadaf Ebrahimi  *      D. McGrew, M. Curcio, S.Fluhrer
14*62c56f98SSadaf Ebrahimi  *      https://datatracker.ietf.org/doc/html/rfc8554
15*62c56f98SSadaf Ebrahimi  *
16*62c56f98SSadaf Ebrahimi  *  [2] NIST Special Publication 800-208
17*62c56f98SSadaf Ebrahimi  *      David A. Cooper et. al.
18*62c56f98SSadaf Ebrahimi  *      https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-208.pdf
19*62c56f98SSadaf Ebrahimi  */
20*62c56f98SSadaf Ebrahimi 
21*62c56f98SSadaf Ebrahimi #include "common.h"
22*62c56f98SSadaf Ebrahimi 
23*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_LMS_C)
24*62c56f98SSadaf Ebrahimi 
25*62c56f98SSadaf Ebrahimi #include <string.h>
26*62c56f98SSadaf Ebrahimi 
27*62c56f98SSadaf Ebrahimi #include "lmots.h"
28*62c56f98SSadaf Ebrahimi 
29*62c56f98SSadaf Ebrahimi #include "mbedtls/lms.h"
30*62c56f98SSadaf Ebrahimi #include "mbedtls/platform_util.h"
31*62c56f98SSadaf Ebrahimi #include "mbedtls/error.h"
32*62c56f98SSadaf Ebrahimi #include "psa_util_internal.h"
33*62c56f98SSadaf Ebrahimi 
34*62c56f98SSadaf Ebrahimi #include "psa/crypto.h"
35*62c56f98SSadaf Ebrahimi 
36*62c56f98SSadaf Ebrahimi /* Define a local translating function to save code size by not using too many
37*62c56f98SSadaf Ebrahimi  * arguments in each translating place. */
local_err_translation(psa_status_t status)38*62c56f98SSadaf Ebrahimi static int local_err_translation(psa_status_t status)
39*62c56f98SSadaf Ebrahimi {
40*62c56f98SSadaf Ebrahimi     return psa_status_to_mbedtls(status, psa_to_lms_errors,
41*62c56f98SSadaf Ebrahimi                                  ARRAY_LENGTH(psa_to_lms_errors),
42*62c56f98SSadaf Ebrahimi                                  psa_generic_status_to_mbedtls);
43*62c56f98SSadaf Ebrahimi }
44*62c56f98SSadaf Ebrahimi #define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status)
45*62c56f98SSadaf Ebrahimi 
46*62c56f98SSadaf Ebrahimi #define PUBLIC_KEY_TYPE_OFFSET     (0)
47*62c56f98SSadaf Ebrahimi #define PUBLIC_KEY_I_KEY_ID_OFFSET (PUBLIC_KEY_TYPE_OFFSET + \
48*62c56f98SSadaf Ebrahimi                                     MBEDTLS_LMOTS_TYPE_LEN)
49*62c56f98SSadaf Ebrahimi #define PUBLIC_KEY_Q_LEAF_ID_OFFSET (PUBLIC_KEY_I_KEY_ID_OFFSET + \
50*62c56f98SSadaf Ebrahimi                                      MBEDTLS_LMOTS_I_KEY_ID_LEN)
51*62c56f98SSadaf Ebrahimi #define PUBLIC_KEY_KEY_HASH_OFFSET (PUBLIC_KEY_Q_LEAF_ID_OFFSET + \
52*62c56f98SSadaf Ebrahimi                                     MBEDTLS_LMOTS_Q_LEAF_ID_LEN)
53*62c56f98SSadaf Ebrahimi 
54*62c56f98SSadaf Ebrahimi /* We only support parameter sets that use 8-bit digits, as it does not require
55*62c56f98SSadaf Ebrahimi  * translation logic between digits and bytes */
56*62c56f98SSadaf Ebrahimi #define W_WINTERNITZ_PARAMETER (8u)
57*62c56f98SSadaf Ebrahimi #define CHECKSUM_LEN           (2)
58*62c56f98SSadaf Ebrahimi #define I_DIGIT_IDX_LEN        (2)
59*62c56f98SSadaf Ebrahimi #define J_HASH_IDX_LEN         (1)
60*62c56f98SSadaf Ebrahimi #define D_CONST_LEN            (2)
61*62c56f98SSadaf Ebrahimi 
62*62c56f98SSadaf Ebrahimi #define DIGIT_MAX_VALUE        ((1u << W_WINTERNITZ_PARAMETER) - 1u)
63*62c56f98SSadaf Ebrahimi 
64*62c56f98SSadaf Ebrahimi #define D_CONST_LEN            (2)
65*62c56f98SSadaf Ebrahimi static const unsigned char D_PUBLIC_CONSTANT_BYTES[D_CONST_LEN] = { 0x80, 0x80 };
66*62c56f98SSadaf Ebrahimi static const unsigned char D_MESSAGE_CONSTANT_BYTES[D_CONST_LEN] = { 0x81, 0x81 };
67*62c56f98SSadaf Ebrahimi 
68*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_TEST_HOOKS)
69*62c56f98SSadaf Ebrahimi int (*mbedtls_lmots_sign_private_key_invalidated_hook)(unsigned char *) = NULL;
70*62c56f98SSadaf Ebrahimi #endif /* defined(MBEDTLS_TEST_HOOKS) */
71*62c56f98SSadaf Ebrahimi 
mbedtls_lms_unsigned_int_to_network_bytes(unsigned int val,size_t len,unsigned char * bytes)72*62c56f98SSadaf Ebrahimi void mbedtls_lms_unsigned_int_to_network_bytes(unsigned int val, size_t len,
73*62c56f98SSadaf Ebrahimi                                                unsigned char *bytes)
74*62c56f98SSadaf Ebrahimi {
75*62c56f98SSadaf Ebrahimi     size_t idx;
76*62c56f98SSadaf Ebrahimi 
77*62c56f98SSadaf Ebrahimi     for (idx = 0; idx < len; idx++) {
78*62c56f98SSadaf Ebrahimi         bytes[idx] = (val >> ((len - 1 - idx) * 8)) & 0xFF;
79*62c56f98SSadaf Ebrahimi     }
80*62c56f98SSadaf Ebrahimi }
81*62c56f98SSadaf Ebrahimi 
mbedtls_lms_network_bytes_to_unsigned_int(size_t len,const unsigned char * bytes)82*62c56f98SSadaf Ebrahimi unsigned int mbedtls_lms_network_bytes_to_unsigned_int(size_t len,
83*62c56f98SSadaf Ebrahimi                                                        const unsigned char *bytes)
84*62c56f98SSadaf Ebrahimi {
85*62c56f98SSadaf Ebrahimi     size_t idx;
86*62c56f98SSadaf Ebrahimi     unsigned int val = 0;
87*62c56f98SSadaf Ebrahimi 
88*62c56f98SSadaf Ebrahimi     for (idx = 0; idx < len; idx++) {
89*62c56f98SSadaf Ebrahimi         val |= ((unsigned int) bytes[idx]) << (8 * (len - 1 - idx));
90*62c56f98SSadaf Ebrahimi     }
91*62c56f98SSadaf Ebrahimi 
92*62c56f98SSadaf Ebrahimi     return val;
93*62c56f98SSadaf Ebrahimi }
94*62c56f98SSadaf Ebrahimi 
95*62c56f98SSadaf Ebrahimi /* Calculate the checksum digits that are appended to the end of the LMOTS digit
96*62c56f98SSadaf Ebrahimi  * string. See NIST SP800-208 section 3.1 or RFC8554 Algorithm 2 for details of
97*62c56f98SSadaf Ebrahimi  * the checksum algorithm.
98*62c56f98SSadaf Ebrahimi  *
99*62c56f98SSadaf Ebrahimi  *  params              The LMOTS parameter set, I and q values which
100*62c56f98SSadaf Ebrahimi  *                      describe the key being used.
101*62c56f98SSadaf Ebrahimi  *
102*62c56f98SSadaf Ebrahimi  *  digest              The digit string to create the digest from. As
103*62c56f98SSadaf Ebrahimi  *                      this does not contain a checksum, it is the same
104*62c56f98SSadaf Ebrahimi  *                      size as a hash output.
105*62c56f98SSadaf Ebrahimi  */
lmots_checksum_calculate(const mbedtls_lmots_parameters_t * params,const unsigned char * digest)106*62c56f98SSadaf Ebrahimi static unsigned short lmots_checksum_calculate(const mbedtls_lmots_parameters_t *params,
107*62c56f98SSadaf Ebrahimi                                                const unsigned char *digest)
108*62c56f98SSadaf Ebrahimi {
109*62c56f98SSadaf Ebrahimi     size_t idx;
110*62c56f98SSadaf Ebrahimi     unsigned sum = 0;
111*62c56f98SSadaf Ebrahimi 
112*62c56f98SSadaf Ebrahimi     for (idx = 0; idx < MBEDTLS_LMOTS_N_HASH_LEN(params->type); idx++) {
113*62c56f98SSadaf Ebrahimi         sum += DIGIT_MAX_VALUE - digest[idx];
114*62c56f98SSadaf Ebrahimi     }
115*62c56f98SSadaf Ebrahimi 
116*62c56f98SSadaf Ebrahimi     return sum;
117*62c56f98SSadaf Ebrahimi }
118*62c56f98SSadaf Ebrahimi 
119*62c56f98SSadaf Ebrahimi /* Create the string of digest digits (in the base determined by the Winternitz
120*62c56f98SSadaf Ebrahimi  * parameter with the checksum appended to the end (Q || cksm(Q)). See NIST
121*62c56f98SSadaf Ebrahimi  * SP800-208 section 3.1 or RFC8554 Algorithm 3 step 5 (also used in Algorithm
122*62c56f98SSadaf Ebrahimi  * 4b step 3) for details.
123*62c56f98SSadaf Ebrahimi  *
124*62c56f98SSadaf Ebrahimi  *  params              The LMOTS parameter set, I and q values which
125*62c56f98SSadaf Ebrahimi  *                      describe the key being used.
126*62c56f98SSadaf Ebrahimi  *
127*62c56f98SSadaf Ebrahimi  *  msg                 The message that will be hashed to create the
128*62c56f98SSadaf Ebrahimi  *                      digest.
129*62c56f98SSadaf Ebrahimi  *
130*62c56f98SSadaf Ebrahimi  *  msg_size            The size of the message.
131*62c56f98SSadaf Ebrahimi  *
132*62c56f98SSadaf Ebrahimi  *  C_random_value      The random value that will be combined with the
133*62c56f98SSadaf Ebrahimi  *                      message digest. This is always the same size as a
134*62c56f98SSadaf Ebrahimi  *                      hash output for whichever hash algorithm is
135*62c56f98SSadaf Ebrahimi  *                      determined by the parameter set.
136*62c56f98SSadaf Ebrahimi  *
137*62c56f98SSadaf Ebrahimi  *  output              An output containing the digit string (+
138*62c56f98SSadaf Ebrahimi  *                      checksum) of length P digits (in the case of
139*62c56f98SSadaf Ebrahimi  *                      MBEDTLS_LMOTS_SHA256_N32_W8, this means it is of
140*62c56f98SSadaf Ebrahimi  *                      size P bytes).
141*62c56f98SSadaf Ebrahimi  */
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)142*62c56f98SSadaf Ebrahimi static int create_digit_array_with_checksum(const mbedtls_lmots_parameters_t *params,
143*62c56f98SSadaf Ebrahimi                                             const unsigned char *msg,
144*62c56f98SSadaf Ebrahimi                                             size_t msg_len,
145*62c56f98SSadaf Ebrahimi                                             const unsigned char *C_random_value,
146*62c56f98SSadaf Ebrahimi                                             unsigned char *out)
147*62c56f98SSadaf Ebrahimi {
148*62c56f98SSadaf Ebrahimi     psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
149*62c56f98SSadaf Ebrahimi     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
150*62c56f98SSadaf Ebrahimi     size_t output_hash_len;
151*62c56f98SSadaf Ebrahimi     unsigned short checksum;
152*62c56f98SSadaf Ebrahimi 
153*62c56f98SSadaf Ebrahimi     status = psa_hash_setup(&op, PSA_ALG_SHA_256);
154*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
155*62c56f98SSadaf Ebrahimi         goto exit;
156*62c56f98SSadaf Ebrahimi     }
157*62c56f98SSadaf Ebrahimi 
158*62c56f98SSadaf Ebrahimi     status = psa_hash_update(&op, params->I_key_identifier,
159*62c56f98SSadaf Ebrahimi                              MBEDTLS_LMOTS_I_KEY_ID_LEN);
160*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
161*62c56f98SSadaf Ebrahimi         goto exit;
162*62c56f98SSadaf Ebrahimi     }
163*62c56f98SSadaf Ebrahimi 
164*62c56f98SSadaf Ebrahimi     status = psa_hash_update(&op, params->q_leaf_identifier,
165*62c56f98SSadaf Ebrahimi                              MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
166*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
167*62c56f98SSadaf Ebrahimi         goto exit;
168*62c56f98SSadaf Ebrahimi     }
169*62c56f98SSadaf Ebrahimi 
170*62c56f98SSadaf Ebrahimi     status = psa_hash_update(&op, D_MESSAGE_CONSTANT_BYTES, D_CONST_LEN);
171*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
172*62c56f98SSadaf Ebrahimi         goto exit;
173*62c56f98SSadaf Ebrahimi     }
174*62c56f98SSadaf Ebrahimi 
175*62c56f98SSadaf Ebrahimi     status = psa_hash_update(&op, C_random_value,
176*62c56f98SSadaf Ebrahimi                              MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(params->type));
177*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
178*62c56f98SSadaf Ebrahimi         goto exit;
179*62c56f98SSadaf Ebrahimi     }
180*62c56f98SSadaf Ebrahimi 
181*62c56f98SSadaf Ebrahimi     status = psa_hash_update(&op, msg, msg_len);
182*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
183*62c56f98SSadaf Ebrahimi         goto exit;
184*62c56f98SSadaf Ebrahimi     }
185*62c56f98SSadaf Ebrahimi 
186*62c56f98SSadaf Ebrahimi     status = psa_hash_finish(&op, out,
187*62c56f98SSadaf Ebrahimi                              MBEDTLS_LMOTS_N_HASH_LEN(params->type),
188*62c56f98SSadaf Ebrahimi                              &output_hash_len);
189*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
190*62c56f98SSadaf Ebrahimi         goto exit;
191*62c56f98SSadaf Ebrahimi     }
192*62c56f98SSadaf Ebrahimi 
193*62c56f98SSadaf Ebrahimi     checksum = lmots_checksum_calculate(params, out);
194*62c56f98SSadaf Ebrahimi     mbedtls_lms_unsigned_int_to_network_bytes(checksum, CHECKSUM_LEN,
195*62c56f98SSadaf Ebrahimi                                               out + MBEDTLS_LMOTS_N_HASH_LEN(params->type));
196*62c56f98SSadaf Ebrahimi 
197*62c56f98SSadaf Ebrahimi exit:
198*62c56f98SSadaf Ebrahimi     psa_hash_abort(&op);
199*62c56f98SSadaf Ebrahimi 
200*62c56f98SSadaf Ebrahimi     return PSA_TO_MBEDTLS_ERR(status);
201*62c56f98SSadaf Ebrahimi }
202*62c56f98SSadaf Ebrahimi 
203*62c56f98SSadaf Ebrahimi /* Hash each element of the string of digits (+ checksum), producing a hash
204*62c56f98SSadaf Ebrahimi  * output for each element. This is used in several places (by varying the
205*62c56f98SSadaf Ebrahimi  * hash_idx_min/max_values) in order to calculate a public key from a private
206*62c56f98SSadaf Ebrahimi  * key (RFC8554 Algorithm 1 step 4), in order to sign a message (RFC8554
207*62c56f98SSadaf Ebrahimi  * Algorithm 3 step 5), and to calculate a public key candidate from a
208*62c56f98SSadaf Ebrahimi  * signature and message (RFC8554 Algorithm 4b step 3).
209*62c56f98SSadaf Ebrahimi  *
210*62c56f98SSadaf Ebrahimi  *  params              The LMOTS parameter set, I and q values which
211*62c56f98SSadaf Ebrahimi  *                      describe the key being used.
212*62c56f98SSadaf Ebrahimi  *
213*62c56f98SSadaf Ebrahimi  *  x_digit_array       The array of digits (of size P, 34 in the case of
214*62c56f98SSadaf Ebrahimi  *                      MBEDTLS_LMOTS_SHA256_N32_W8).
215*62c56f98SSadaf Ebrahimi  *
216*62c56f98SSadaf Ebrahimi  *  hash_idx_min_values An array of the starting values of the j iterator
217*62c56f98SSadaf Ebrahimi  *                      for each of the members of the digit array. If
218*62c56f98SSadaf Ebrahimi  *                      this value in NULL, then all iterators will start
219*62c56f98SSadaf Ebrahimi  *                      at 0.
220*62c56f98SSadaf Ebrahimi  *
221*62c56f98SSadaf Ebrahimi  *  hash_idx_max_values An array of the upper bound values of the j
222*62c56f98SSadaf Ebrahimi  *                      iterator for each of the members of the digit
223*62c56f98SSadaf Ebrahimi  *                      array. If this value in NULL, then iterator is
224*62c56f98SSadaf Ebrahimi  *                      bounded to be less than 2^w - 1 (255 in the case
225*62c56f98SSadaf Ebrahimi  *                      of MBEDTLS_LMOTS_SHA256_N32_W8)
226*62c56f98SSadaf Ebrahimi  *
227*62c56f98SSadaf Ebrahimi  *  output              An array containing a hash output for each member
228*62c56f98SSadaf Ebrahimi  *                      of the digit string P. In the case of
229*62c56f98SSadaf Ebrahimi  *                      MBEDTLS_LMOTS_SHA256_N32_W8, this is of size 32 *
230*62c56f98SSadaf Ebrahimi  *                      34.
231*62c56f98SSadaf Ebrahimi  */
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)232*62c56f98SSadaf Ebrahimi static int hash_digit_array(const mbedtls_lmots_parameters_t *params,
233*62c56f98SSadaf Ebrahimi                             const unsigned char *x_digit_array,
234*62c56f98SSadaf Ebrahimi                             const unsigned char *hash_idx_min_values,
235*62c56f98SSadaf Ebrahimi                             const unsigned char *hash_idx_max_values,
236*62c56f98SSadaf Ebrahimi                             unsigned char *output)
237*62c56f98SSadaf Ebrahimi {
238*62c56f98SSadaf Ebrahimi     unsigned int i_digit_idx;
239*62c56f98SSadaf Ebrahimi     unsigned char i_digit_idx_bytes[I_DIGIT_IDX_LEN];
240*62c56f98SSadaf Ebrahimi     unsigned int j_hash_idx;
241*62c56f98SSadaf Ebrahimi     unsigned char j_hash_idx_bytes[J_HASH_IDX_LEN];
242*62c56f98SSadaf Ebrahimi     unsigned int j_hash_idx_min;
243*62c56f98SSadaf Ebrahimi     unsigned int j_hash_idx_max;
244*62c56f98SSadaf Ebrahimi     psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
245*62c56f98SSadaf Ebrahimi     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
246*62c56f98SSadaf Ebrahimi     size_t output_hash_len;
247*62c56f98SSadaf Ebrahimi     unsigned char tmp_hash[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
248*62c56f98SSadaf Ebrahimi 
249*62c56f98SSadaf Ebrahimi     for (i_digit_idx = 0;
250*62c56f98SSadaf Ebrahimi          i_digit_idx < MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(params->type);
251*62c56f98SSadaf Ebrahimi          i_digit_idx++) {
252*62c56f98SSadaf Ebrahimi 
253*62c56f98SSadaf Ebrahimi         memcpy(tmp_hash,
254*62c56f98SSadaf Ebrahimi                &x_digit_array[i_digit_idx * MBEDTLS_LMOTS_N_HASH_LEN(params->type)],
255*62c56f98SSadaf Ebrahimi                MBEDTLS_LMOTS_N_HASH_LEN(params->type));
256*62c56f98SSadaf Ebrahimi 
257*62c56f98SSadaf Ebrahimi         j_hash_idx_min = hash_idx_min_values != NULL ?
258*62c56f98SSadaf Ebrahimi                          hash_idx_min_values[i_digit_idx] : 0;
259*62c56f98SSadaf Ebrahimi         j_hash_idx_max = hash_idx_max_values != NULL ?
260*62c56f98SSadaf Ebrahimi                          hash_idx_max_values[i_digit_idx] : DIGIT_MAX_VALUE;
261*62c56f98SSadaf Ebrahimi 
262*62c56f98SSadaf Ebrahimi         for (j_hash_idx = j_hash_idx_min;
263*62c56f98SSadaf Ebrahimi              j_hash_idx < j_hash_idx_max;
264*62c56f98SSadaf Ebrahimi              j_hash_idx++) {
265*62c56f98SSadaf Ebrahimi             status = psa_hash_setup(&op, PSA_ALG_SHA_256);
266*62c56f98SSadaf Ebrahimi             if (status != PSA_SUCCESS) {
267*62c56f98SSadaf Ebrahimi                 goto exit;
268*62c56f98SSadaf Ebrahimi             }
269*62c56f98SSadaf Ebrahimi 
270*62c56f98SSadaf Ebrahimi             status = psa_hash_update(&op,
271*62c56f98SSadaf Ebrahimi                                      params->I_key_identifier,
272*62c56f98SSadaf Ebrahimi                                      MBEDTLS_LMOTS_I_KEY_ID_LEN);
273*62c56f98SSadaf Ebrahimi             if (status != PSA_SUCCESS) {
274*62c56f98SSadaf Ebrahimi                 goto exit;
275*62c56f98SSadaf Ebrahimi             }
276*62c56f98SSadaf Ebrahimi 
277*62c56f98SSadaf Ebrahimi             status = psa_hash_update(&op,
278*62c56f98SSadaf Ebrahimi                                      params->q_leaf_identifier,
279*62c56f98SSadaf Ebrahimi                                      MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
280*62c56f98SSadaf Ebrahimi             if (status != PSA_SUCCESS) {
281*62c56f98SSadaf Ebrahimi                 goto exit;
282*62c56f98SSadaf Ebrahimi             }
283*62c56f98SSadaf Ebrahimi 
284*62c56f98SSadaf Ebrahimi             mbedtls_lms_unsigned_int_to_network_bytes(i_digit_idx,
285*62c56f98SSadaf Ebrahimi                                                       I_DIGIT_IDX_LEN,
286*62c56f98SSadaf Ebrahimi                                                       i_digit_idx_bytes);
287*62c56f98SSadaf Ebrahimi             status = psa_hash_update(&op, i_digit_idx_bytes, I_DIGIT_IDX_LEN);
288*62c56f98SSadaf Ebrahimi             if (status != PSA_SUCCESS) {
289*62c56f98SSadaf Ebrahimi                 goto exit;
290*62c56f98SSadaf Ebrahimi             }
291*62c56f98SSadaf Ebrahimi 
292*62c56f98SSadaf Ebrahimi             mbedtls_lms_unsigned_int_to_network_bytes(j_hash_idx,
293*62c56f98SSadaf Ebrahimi                                                       J_HASH_IDX_LEN,
294*62c56f98SSadaf Ebrahimi                                                       j_hash_idx_bytes);
295*62c56f98SSadaf Ebrahimi             status = psa_hash_update(&op, j_hash_idx_bytes, J_HASH_IDX_LEN);
296*62c56f98SSadaf Ebrahimi             if (status != PSA_SUCCESS) {
297*62c56f98SSadaf Ebrahimi                 goto exit;
298*62c56f98SSadaf Ebrahimi             }
299*62c56f98SSadaf Ebrahimi 
300*62c56f98SSadaf Ebrahimi             status = psa_hash_update(&op, tmp_hash,
301*62c56f98SSadaf Ebrahimi                                      MBEDTLS_LMOTS_N_HASH_LEN(params->type));
302*62c56f98SSadaf Ebrahimi             if (status != PSA_SUCCESS) {
303*62c56f98SSadaf Ebrahimi                 goto exit;
304*62c56f98SSadaf Ebrahimi             }
305*62c56f98SSadaf Ebrahimi 
306*62c56f98SSadaf Ebrahimi             status = psa_hash_finish(&op, tmp_hash, sizeof(tmp_hash),
307*62c56f98SSadaf Ebrahimi                                      &output_hash_len);
308*62c56f98SSadaf Ebrahimi             if (status != PSA_SUCCESS) {
309*62c56f98SSadaf Ebrahimi                 goto exit;
310*62c56f98SSadaf Ebrahimi             }
311*62c56f98SSadaf Ebrahimi 
312*62c56f98SSadaf Ebrahimi             psa_hash_abort(&op);
313*62c56f98SSadaf Ebrahimi         }
314*62c56f98SSadaf Ebrahimi 
315*62c56f98SSadaf Ebrahimi         memcpy(&output[i_digit_idx * MBEDTLS_LMOTS_N_HASH_LEN(params->type)],
316*62c56f98SSadaf Ebrahimi                tmp_hash, MBEDTLS_LMOTS_N_HASH_LEN(params->type));
317*62c56f98SSadaf Ebrahimi     }
318*62c56f98SSadaf Ebrahimi 
319*62c56f98SSadaf Ebrahimi exit:
320*62c56f98SSadaf Ebrahimi     psa_hash_abort(&op);
321*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(tmp_hash, sizeof(tmp_hash));
322*62c56f98SSadaf Ebrahimi 
323*62c56f98SSadaf Ebrahimi     return PSA_TO_MBEDTLS_ERR(status);
324*62c56f98SSadaf Ebrahimi }
325*62c56f98SSadaf Ebrahimi 
326*62c56f98SSadaf Ebrahimi /* Combine the hashes of the digit array into a public key. This is used in
327*62c56f98SSadaf Ebrahimi  * in order to calculate a public key from a private key (RFC8554 Algorithm 1
328*62c56f98SSadaf Ebrahimi  * step 4), and to calculate a public key candidate from a signature and message
329*62c56f98SSadaf Ebrahimi  * (RFC8554 Algorithm 4b step 3).
330*62c56f98SSadaf Ebrahimi  *
331*62c56f98SSadaf Ebrahimi  *  params           The LMOTS parameter set, I and q values which describe
332*62c56f98SSadaf Ebrahimi  *                   the key being used.
333*62c56f98SSadaf Ebrahimi  *  y_hashed_digits  The array of hashes, one hash for each digit of the
334*62c56f98SSadaf Ebrahimi  *                   symbol array (which is of size P, 34 in the case of
335*62c56f98SSadaf Ebrahimi  *                   MBEDTLS_LMOTS_SHA256_N32_W8)
336*62c56f98SSadaf Ebrahimi  *
337*62c56f98SSadaf Ebrahimi  *  pub_key          The output public key (or candidate public key in
338*62c56f98SSadaf Ebrahimi  *                   case this is being run as part of signature
339*62c56f98SSadaf Ebrahimi  *                   verification), in the form of a hash output.
340*62c56f98SSadaf Ebrahimi  */
public_key_from_hashed_digit_array(const mbedtls_lmots_parameters_t * params,const unsigned char * y_hashed_digits,unsigned char * pub_key)341*62c56f98SSadaf Ebrahimi static int public_key_from_hashed_digit_array(const mbedtls_lmots_parameters_t *params,
342*62c56f98SSadaf Ebrahimi                                               const unsigned char *y_hashed_digits,
343*62c56f98SSadaf Ebrahimi                                               unsigned char *pub_key)
344*62c56f98SSadaf Ebrahimi {
345*62c56f98SSadaf Ebrahimi     psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
346*62c56f98SSadaf Ebrahimi     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
347*62c56f98SSadaf Ebrahimi     size_t output_hash_len;
348*62c56f98SSadaf Ebrahimi 
349*62c56f98SSadaf Ebrahimi     status = psa_hash_setup(&op, PSA_ALG_SHA_256);
350*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
351*62c56f98SSadaf Ebrahimi         goto exit;
352*62c56f98SSadaf Ebrahimi     }
353*62c56f98SSadaf Ebrahimi 
354*62c56f98SSadaf Ebrahimi     status = psa_hash_update(&op,
355*62c56f98SSadaf Ebrahimi                              params->I_key_identifier,
356*62c56f98SSadaf Ebrahimi                              MBEDTLS_LMOTS_I_KEY_ID_LEN);
357*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
358*62c56f98SSadaf Ebrahimi         goto exit;
359*62c56f98SSadaf Ebrahimi     }
360*62c56f98SSadaf Ebrahimi 
361*62c56f98SSadaf Ebrahimi     status = psa_hash_update(&op, params->q_leaf_identifier,
362*62c56f98SSadaf Ebrahimi                              MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
363*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
364*62c56f98SSadaf Ebrahimi         goto exit;
365*62c56f98SSadaf Ebrahimi     }
366*62c56f98SSadaf Ebrahimi 
367*62c56f98SSadaf Ebrahimi     status = psa_hash_update(&op, D_PUBLIC_CONSTANT_BYTES, D_CONST_LEN);
368*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
369*62c56f98SSadaf Ebrahimi         goto exit;
370*62c56f98SSadaf Ebrahimi     }
371*62c56f98SSadaf Ebrahimi 
372*62c56f98SSadaf Ebrahimi     status = psa_hash_update(&op, y_hashed_digits,
373*62c56f98SSadaf Ebrahimi                              MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(params->type) *
374*62c56f98SSadaf Ebrahimi                              MBEDTLS_LMOTS_N_HASH_LEN(params->type));
375*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
376*62c56f98SSadaf Ebrahimi         goto exit;
377*62c56f98SSadaf Ebrahimi     }
378*62c56f98SSadaf Ebrahimi 
379*62c56f98SSadaf Ebrahimi     status = psa_hash_finish(&op, pub_key,
380*62c56f98SSadaf Ebrahimi                              MBEDTLS_LMOTS_N_HASH_LEN(params->type),
381*62c56f98SSadaf Ebrahimi                              &output_hash_len);
382*62c56f98SSadaf Ebrahimi     if (status != PSA_SUCCESS) {
383*62c56f98SSadaf Ebrahimi 
384*62c56f98SSadaf Ebrahimi exit:
385*62c56f98SSadaf Ebrahimi         psa_hash_abort(&op);
386*62c56f98SSadaf Ebrahimi     }
387*62c56f98SSadaf Ebrahimi 
388*62c56f98SSadaf Ebrahimi     return PSA_TO_MBEDTLS_ERR(status);
389*62c56f98SSadaf Ebrahimi }
390*62c56f98SSadaf Ebrahimi 
391*62c56f98SSadaf Ebrahimi #if !defined(MBEDTLS_DEPRECATED_REMOVED)
mbedtls_lms_error_from_psa(psa_status_t status)392*62c56f98SSadaf Ebrahimi int mbedtls_lms_error_from_psa(psa_status_t status)
393*62c56f98SSadaf Ebrahimi {
394*62c56f98SSadaf Ebrahimi     switch (status) {
395*62c56f98SSadaf Ebrahimi         case PSA_SUCCESS:
396*62c56f98SSadaf Ebrahimi             return 0;
397*62c56f98SSadaf Ebrahimi         case PSA_ERROR_HARDWARE_FAILURE:
398*62c56f98SSadaf Ebrahimi             return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED;
399*62c56f98SSadaf Ebrahimi         case PSA_ERROR_NOT_SUPPORTED:
400*62c56f98SSadaf Ebrahimi             return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
401*62c56f98SSadaf Ebrahimi         case PSA_ERROR_BUFFER_TOO_SMALL:
402*62c56f98SSadaf Ebrahimi             return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
403*62c56f98SSadaf Ebrahimi         case PSA_ERROR_INVALID_ARGUMENT:
404*62c56f98SSadaf Ebrahimi             return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
405*62c56f98SSadaf Ebrahimi         default:
406*62c56f98SSadaf Ebrahimi             return MBEDTLS_ERR_ERROR_GENERIC_ERROR;
407*62c56f98SSadaf Ebrahimi     }
408*62c56f98SSadaf Ebrahimi }
409*62c56f98SSadaf Ebrahimi #endif /* !MBEDTLS_DEPRECATED_REMOVED */
410*62c56f98SSadaf Ebrahimi 
mbedtls_lmots_public_init(mbedtls_lmots_public_t * ctx)411*62c56f98SSadaf Ebrahimi void mbedtls_lmots_public_init(mbedtls_lmots_public_t *ctx)
412*62c56f98SSadaf Ebrahimi {
413*62c56f98SSadaf Ebrahimi     memset(ctx, 0, sizeof(*ctx));
414*62c56f98SSadaf Ebrahimi }
415*62c56f98SSadaf Ebrahimi 
mbedtls_lmots_public_free(mbedtls_lmots_public_t * ctx)416*62c56f98SSadaf Ebrahimi void mbedtls_lmots_public_free(mbedtls_lmots_public_t *ctx)
417*62c56f98SSadaf Ebrahimi {
418*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(ctx, sizeof(*ctx));
419*62c56f98SSadaf Ebrahimi }
420*62c56f98SSadaf Ebrahimi 
mbedtls_lmots_import_public_key(mbedtls_lmots_public_t * ctx,const unsigned char * key,size_t key_len)421*62c56f98SSadaf Ebrahimi int mbedtls_lmots_import_public_key(mbedtls_lmots_public_t *ctx,
422*62c56f98SSadaf Ebrahimi                                     const unsigned char *key, size_t key_len)
423*62c56f98SSadaf Ebrahimi {
424*62c56f98SSadaf Ebrahimi     if (key_len < MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
425*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
426*62c56f98SSadaf Ebrahimi     }
427*62c56f98SSadaf Ebrahimi 
428*62c56f98SSadaf Ebrahimi     ctx->params.type =
429*62c56f98SSadaf Ebrahimi         (mbedtls_lmots_algorithm_type_t) mbedtls_lms_network_bytes_to_unsigned_int(
430*62c56f98SSadaf Ebrahimi             MBEDTLS_LMOTS_TYPE_LEN,
431*62c56f98SSadaf Ebrahimi             key +
432*62c56f98SSadaf Ebrahimi             MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
433*62c56f98SSadaf Ebrahimi 
434*62c56f98SSadaf Ebrahimi     if (key_len != MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type)) {
435*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
436*62c56f98SSadaf Ebrahimi     }
437*62c56f98SSadaf Ebrahimi 
438*62c56f98SSadaf Ebrahimi     memcpy(ctx->params.I_key_identifier,
439*62c56f98SSadaf Ebrahimi            key + PUBLIC_KEY_I_KEY_ID_OFFSET,
440*62c56f98SSadaf Ebrahimi            MBEDTLS_LMOTS_I_KEY_ID_LEN);
441*62c56f98SSadaf Ebrahimi 
442*62c56f98SSadaf Ebrahimi     memcpy(ctx->params.q_leaf_identifier,
443*62c56f98SSadaf Ebrahimi            key + PUBLIC_KEY_Q_LEAF_ID_OFFSET,
444*62c56f98SSadaf Ebrahimi            MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
445*62c56f98SSadaf Ebrahimi 
446*62c56f98SSadaf Ebrahimi     memcpy(ctx->public_key,
447*62c56f98SSadaf Ebrahimi            key + PUBLIC_KEY_KEY_HASH_OFFSET,
448*62c56f98SSadaf Ebrahimi            MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
449*62c56f98SSadaf Ebrahimi 
450*62c56f98SSadaf Ebrahimi     ctx->have_public_key = 1;
451*62c56f98SSadaf Ebrahimi 
452*62c56f98SSadaf Ebrahimi     return 0;
453*62c56f98SSadaf Ebrahimi }
454*62c56f98SSadaf Ebrahimi 
mbedtls_lmots_export_public_key(const mbedtls_lmots_public_t * ctx,unsigned char * key,size_t key_size,size_t * key_len)455*62c56f98SSadaf Ebrahimi int mbedtls_lmots_export_public_key(const mbedtls_lmots_public_t *ctx,
456*62c56f98SSadaf Ebrahimi                                     unsigned char *key, size_t key_size,
457*62c56f98SSadaf Ebrahimi                                     size_t *key_len)
458*62c56f98SSadaf Ebrahimi {
459*62c56f98SSadaf Ebrahimi     if (key_size < MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type)) {
460*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
461*62c56f98SSadaf Ebrahimi     }
462*62c56f98SSadaf Ebrahimi 
463*62c56f98SSadaf Ebrahimi     if (!ctx->have_public_key) {
464*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
465*62c56f98SSadaf Ebrahimi     }
466*62c56f98SSadaf Ebrahimi 
467*62c56f98SSadaf Ebrahimi     mbedtls_lms_unsigned_int_to_network_bytes(ctx->params.type,
468*62c56f98SSadaf Ebrahimi                                               MBEDTLS_LMOTS_TYPE_LEN,
469*62c56f98SSadaf Ebrahimi                                               key + MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
470*62c56f98SSadaf Ebrahimi 
471*62c56f98SSadaf Ebrahimi     memcpy(key + PUBLIC_KEY_I_KEY_ID_OFFSET,
472*62c56f98SSadaf Ebrahimi            ctx->params.I_key_identifier,
473*62c56f98SSadaf Ebrahimi            MBEDTLS_LMOTS_I_KEY_ID_LEN);
474*62c56f98SSadaf Ebrahimi 
475*62c56f98SSadaf Ebrahimi     memcpy(key + PUBLIC_KEY_Q_LEAF_ID_OFFSET,
476*62c56f98SSadaf Ebrahimi            ctx->params.q_leaf_identifier,
477*62c56f98SSadaf Ebrahimi            MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
478*62c56f98SSadaf Ebrahimi 
479*62c56f98SSadaf Ebrahimi     memcpy(key + PUBLIC_KEY_KEY_HASH_OFFSET, ctx->public_key,
480*62c56f98SSadaf Ebrahimi            MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
481*62c56f98SSadaf Ebrahimi 
482*62c56f98SSadaf Ebrahimi     if (key_len != NULL) {
483*62c56f98SSadaf Ebrahimi         *key_len = MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type);
484*62c56f98SSadaf Ebrahimi     }
485*62c56f98SSadaf Ebrahimi 
486*62c56f98SSadaf Ebrahimi     return 0;
487*62c56f98SSadaf Ebrahimi }
488*62c56f98SSadaf Ebrahimi 
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)489*62c56f98SSadaf Ebrahimi int mbedtls_lmots_calculate_public_key_candidate(const mbedtls_lmots_parameters_t *params,
490*62c56f98SSadaf Ebrahimi                                                  const unsigned char  *msg,
491*62c56f98SSadaf Ebrahimi                                                  size_t msg_size,
492*62c56f98SSadaf Ebrahimi                                                  const unsigned char *sig,
493*62c56f98SSadaf Ebrahimi                                                  size_t sig_size,
494*62c56f98SSadaf Ebrahimi                                                  unsigned char *out,
495*62c56f98SSadaf Ebrahimi                                                  size_t out_size,
496*62c56f98SSadaf Ebrahimi                                                  size_t *out_len)
497*62c56f98SSadaf Ebrahimi {
498*62c56f98SSadaf Ebrahimi     unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX];
499*62c56f98SSadaf Ebrahimi     unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
500*62c56f98SSadaf Ebrahimi     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
501*62c56f98SSadaf Ebrahimi 
502*62c56f98SSadaf Ebrahimi     if (msg == NULL && msg_size != 0) {
503*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
504*62c56f98SSadaf Ebrahimi     }
505*62c56f98SSadaf Ebrahimi 
506*62c56f98SSadaf Ebrahimi     if (sig_size != MBEDTLS_LMOTS_SIG_LEN(params->type) ||
507*62c56f98SSadaf Ebrahimi         out_size < MBEDTLS_LMOTS_N_HASH_LEN(params->type)) {
508*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
509*62c56f98SSadaf Ebrahimi     }
510*62c56f98SSadaf Ebrahimi 
511*62c56f98SSadaf Ebrahimi     ret = create_digit_array_with_checksum(params, msg, msg_size,
512*62c56f98SSadaf Ebrahimi                                            sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET,
513*62c56f98SSadaf Ebrahimi                                            tmp_digit_array);
514*62c56f98SSadaf Ebrahimi     if (ret) {
515*62c56f98SSadaf Ebrahimi         return ret;
516*62c56f98SSadaf Ebrahimi     }
517*62c56f98SSadaf Ebrahimi 
518*62c56f98SSadaf Ebrahimi     ret = hash_digit_array(params,
519*62c56f98SSadaf Ebrahimi                            sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(params->type),
520*62c56f98SSadaf Ebrahimi                            tmp_digit_array, NULL, (unsigned char *) y_hashed_digits);
521*62c56f98SSadaf Ebrahimi     if (ret) {
522*62c56f98SSadaf Ebrahimi         return ret;
523*62c56f98SSadaf Ebrahimi     }
524*62c56f98SSadaf Ebrahimi 
525*62c56f98SSadaf Ebrahimi     ret = public_key_from_hashed_digit_array(params,
526*62c56f98SSadaf Ebrahimi                                              (unsigned char *) y_hashed_digits,
527*62c56f98SSadaf Ebrahimi                                              out);
528*62c56f98SSadaf Ebrahimi     if (ret) {
529*62c56f98SSadaf Ebrahimi         return ret;
530*62c56f98SSadaf Ebrahimi     }
531*62c56f98SSadaf Ebrahimi 
532*62c56f98SSadaf Ebrahimi     if (out_len != NULL) {
533*62c56f98SSadaf Ebrahimi         *out_len = MBEDTLS_LMOTS_N_HASH_LEN(params->type);
534*62c56f98SSadaf Ebrahimi     }
535*62c56f98SSadaf Ebrahimi 
536*62c56f98SSadaf Ebrahimi     return 0;
537*62c56f98SSadaf Ebrahimi }
538*62c56f98SSadaf Ebrahimi 
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)539*62c56f98SSadaf Ebrahimi int mbedtls_lmots_verify(const mbedtls_lmots_public_t *ctx,
540*62c56f98SSadaf Ebrahimi                          const unsigned char *msg, size_t msg_size,
541*62c56f98SSadaf Ebrahimi                          const unsigned char *sig, size_t sig_size)
542*62c56f98SSadaf Ebrahimi {
543*62c56f98SSadaf Ebrahimi     unsigned char Kc_public_key_candidate[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
544*62c56f98SSadaf Ebrahimi     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
545*62c56f98SSadaf Ebrahimi 
546*62c56f98SSadaf Ebrahimi     if (msg == NULL && msg_size != 0) {
547*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
548*62c56f98SSadaf Ebrahimi     }
549*62c56f98SSadaf Ebrahimi 
550*62c56f98SSadaf Ebrahimi     if (!ctx->have_public_key) {
551*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
552*62c56f98SSadaf Ebrahimi     }
553*62c56f98SSadaf Ebrahimi 
554*62c56f98SSadaf Ebrahimi     if (ctx->params.type != MBEDTLS_LMOTS_SHA256_N32_W8) {
555*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
556*62c56f98SSadaf Ebrahimi     }
557*62c56f98SSadaf Ebrahimi 
558*62c56f98SSadaf Ebrahimi     if (sig_size < MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
559*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_VERIFY_FAILED;
560*62c56f98SSadaf Ebrahimi     }
561*62c56f98SSadaf Ebrahimi 
562*62c56f98SSadaf Ebrahimi     if (mbedtls_lms_network_bytes_to_unsigned_int(MBEDTLS_LMOTS_TYPE_LEN,
563*62c56f98SSadaf Ebrahimi                                                   sig + MBEDTLS_LMOTS_SIG_TYPE_OFFSET) !=
564*62c56f98SSadaf Ebrahimi         MBEDTLS_LMOTS_SHA256_N32_W8) {
565*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_VERIFY_FAILED;
566*62c56f98SSadaf Ebrahimi     }
567*62c56f98SSadaf Ebrahimi 
568*62c56f98SSadaf Ebrahimi     ret = mbedtls_lmots_calculate_public_key_candidate(&ctx->params,
569*62c56f98SSadaf Ebrahimi                                                        msg, msg_size, sig, sig_size,
570*62c56f98SSadaf Ebrahimi                                                        Kc_public_key_candidate,
571*62c56f98SSadaf Ebrahimi                                                        MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type),
572*62c56f98SSadaf Ebrahimi                                                        NULL);
573*62c56f98SSadaf Ebrahimi     if (ret) {
574*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_VERIFY_FAILED;
575*62c56f98SSadaf Ebrahimi     }
576*62c56f98SSadaf Ebrahimi 
577*62c56f98SSadaf Ebrahimi     if (memcmp(&Kc_public_key_candidate, ctx->public_key,
578*62c56f98SSadaf Ebrahimi                sizeof(ctx->public_key))) {
579*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_VERIFY_FAILED;
580*62c56f98SSadaf Ebrahimi     }
581*62c56f98SSadaf Ebrahimi 
582*62c56f98SSadaf Ebrahimi     return 0;
583*62c56f98SSadaf Ebrahimi }
584*62c56f98SSadaf Ebrahimi 
585*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_LMS_PRIVATE)
586*62c56f98SSadaf Ebrahimi 
mbedtls_lmots_private_init(mbedtls_lmots_private_t * ctx)587*62c56f98SSadaf Ebrahimi void mbedtls_lmots_private_init(mbedtls_lmots_private_t *ctx)
588*62c56f98SSadaf Ebrahimi {
589*62c56f98SSadaf Ebrahimi     memset(ctx, 0, sizeof(*ctx));
590*62c56f98SSadaf Ebrahimi }
591*62c56f98SSadaf Ebrahimi 
mbedtls_lmots_private_free(mbedtls_lmots_private_t * ctx)592*62c56f98SSadaf Ebrahimi void mbedtls_lmots_private_free(mbedtls_lmots_private_t *ctx)
593*62c56f98SSadaf Ebrahimi {
594*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(ctx,
595*62c56f98SSadaf Ebrahimi                              sizeof(*ctx));
596*62c56f98SSadaf Ebrahimi }
597*62c56f98SSadaf Ebrahimi 
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)598*62c56f98SSadaf Ebrahimi int mbedtls_lmots_generate_private_key(mbedtls_lmots_private_t *ctx,
599*62c56f98SSadaf Ebrahimi                                        mbedtls_lmots_algorithm_type_t type,
600*62c56f98SSadaf Ebrahimi                                        const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
601*62c56f98SSadaf Ebrahimi                                        uint32_t q_leaf_identifier,
602*62c56f98SSadaf Ebrahimi                                        const unsigned char *seed,
603*62c56f98SSadaf Ebrahimi                                        size_t seed_size)
604*62c56f98SSadaf Ebrahimi {
605*62c56f98SSadaf Ebrahimi     psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
606*62c56f98SSadaf Ebrahimi     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
607*62c56f98SSadaf Ebrahimi     size_t output_hash_len;
608*62c56f98SSadaf Ebrahimi     unsigned int i_digit_idx;
609*62c56f98SSadaf Ebrahimi     unsigned char i_digit_idx_bytes[2];
610*62c56f98SSadaf Ebrahimi     unsigned char const_bytes[1];
611*62c56f98SSadaf Ebrahimi 
612*62c56f98SSadaf Ebrahimi     if (ctx->have_private_key) {
613*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
614*62c56f98SSadaf Ebrahimi     }
615*62c56f98SSadaf Ebrahimi 
616*62c56f98SSadaf Ebrahimi     if (type != MBEDTLS_LMOTS_SHA256_N32_W8) {
617*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
618*62c56f98SSadaf Ebrahimi     }
619*62c56f98SSadaf Ebrahimi 
620*62c56f98SSadaf Ebrahimi     ctx->params.type = type;
621*62c56f98SSadaf Ebrahimi 
622*62c56f98SSadaf Ebrahimi     memcpy(ctx->params.I_key_identifier,
623*62c56f98SSadaf Ebrahimi            I_key_identifier,
624*62c56f98SSadaf Ebrahimi            sizeof(ctx->params.I_key_identifier));
625*62c56f98SSadaf Ebrahimi 
626*62c56f98SSadaf Ebrahimi     mbedtls_lms_unsigned_int_to_network_bytes(q_leaf_identifier,
627*62c56f98SSadaf Ebrahimi                                               MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
628*62c56f98SSadaf Ebrahimi                                               ctx->params.q_leaf_identifier);
629*62c56f98SSadaf Ebrahimi 
630*62c56f98SSadaf Ebrahimi     mbedtls_lms_unsigned_int_to_network_bytes(0xFF, sizeof(const_bytes),
631*62c56f98SSadaf Ebrahimi                                               const_bytes);
632*62c56f98SSadaf Ebrahimi 
633*62c56f98SSadaf Ebrahimi     for (i_digit_idx = 0;
634*62c56f98SSadaf Ebrahimi          i_digit_idx < MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type);
635*62c56f98SSadaf Ebrahimi          i_digit_idx++) {
636*62c56f98SSadaf Ebrahimi         status = psa_hash_setup(&op, PSA_ALG_SHA_256);
637*62c56f98SSadaf Ebrahimi         if (status != PSA_SUCCESS) {
638*62c56f98SSadaf Ebrahimi             goto exit;
639*62c56f98SSadaf Ebrahimi         }
640*62c56f98SSadaf Ebrahimi 
641*62c56f98SSadaf Ebrahimi         status = psa_hash_update(&op,
642*62c56f98SSadaf Ebrahimi                                  ctx->params.I_key_identifier,
643*62c56f98SSadaf Ebrahimi                                  sizeof(ctx->params.I_key_identifier));
644*62c56f98SSadaf Ebrahimi         if (status != PSA_SUCCESS) {
645*62c56f98SSadaf Ebrahimi             goto exit;
646*62c56f98SSadaf Ebrahimi         }
647*62c56f98SSadaf Ebrahimi 
648*62c56f98SSadaf Ebrahimi         status = psa_hash_update(&op,
649*62c56f98SSadaf Ebrahimi                                  ctx->params.q_leaf_identifier,
650*62c56f98SSadaf Ebrahimi                                  MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
651*62c56f98SSadaf Ebrahimi         if (status != PSA_SUCCESS) {
652*62c56f98SSadaf Ebrahimi             goto exit;
653*62c56f98SSadaf Ebrahimi         }
654*62c56f98SSadaf Ebrahimi 
655*62c56f98SSadaf Ebrahimi         mbedtls_lms_unsigned_int_to_network_bytes(i_digit_idx, I_DIGIT_IDX_LEN,
656*62c56f98SSadaf Ebrahimi                                                   i_digit_idx_bytes);
657*62c56f98SSadaf Ebrahimi         status = psa_hash_update(&op, i_digit_idx_bytes, I_DIGIT_IDX_LEN);
658*62c56f98SSadaf Ebrahimi         if (status != PSA_SUCCESS) {
659*62c56f98SSadaf Ebrahimi             goto exit;
660*62c56f98SSadaf Ebrahimi         }
661*62c56f98SSadaf Ebrahimi 
662*62c56f98SSadaf Ebrahimi         status = psa_hash_update(&op, const_bytes, sizeof(const_bytes));
663*62c56f98SSadaf Ebrahimi         if (status != PSA_SUCCESS) {
664*62c56f98SSadaf Ebrahimi             goto exit;
665*62c56f98SSadaf Ebrahimi         }
666*62c56f98SSadaf Ebrahimi 
667*62c56f98SSadaf Ebrahimi         status = psa_hash_update(&op, seed, seed_size);
668*62c56f98SSadaf Ebrahimi         if (status != PSA_SUCCESS) {
669*62c56f98SSadaf Ebrahimi             goto exit;
670*62c56f98SSadaf Ebrahimi         }
671*62c56f98SSadaf Ebrahimi 
672*62c56f98SSadaf Ebrahimi         status = psa_hash_finish(&op,
673*62c56f98SSadaf Ebrahimi                                  ctx->private_key[i_digit_idx],
674*62c56f98SSadaf Ebrahimi                                  MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type),
675*62c56f98SSadaf Ebrahimi                                  &output_hash_len);
676*62c56f98SSadaf Ebrahimi         if (status != PSA_SUCCESS) {
677*62c56f98SSadaf Ebrahimi             goto exit;
678*62c56f98SSadaf Ebrahimi         }
679*62c56f98SSadaf Ebrahimi 
680*62c56f98SSadaf Ebrahimi         psa_hash_abort(&op);
681*62c56f98SSadaf Ebrahimi     }
682*62c56f98SSadaf Ebrahimi 
683*62c56f98SSadaf Ebrahimi     ctx->have_private_key = 1;
684*62c56f98SSadaf Ebrahimi 
685*62c56f98SSadaf Ebrahimi exit:
686*62c56f98SSadaf Ebrahimi     psa_hash_abort(&op);
687*62c56f98SSadaf Ebrahimi 
688*62c56f98SSadaf Ebrahimi     return PSA_TO_MBEDTLS_ERR(status);
689*62c56f98SSadaf Ebrahimi }
690*62c56f98SSadaf Ebrahimi 
mbedtls_lmots_calculate_public_key(mbedtls_lmots_public_t * ctx,const mbedtls_lmots_private_t * priv_ctx)691*62c56f98SSadaf Ebrahimi int mbedtls_lmots_calculate_public_key(mbedtls_lmots_public_t *ctx,
692*62c56f98SSadaf Ebrahimi                                        const mbedtls_lmots_private_t *priv_ctx)
693*62c56f98SSadaf Ebrahimi {
694*62c56f98SSadaf Ebrahimi     unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
695*62c56f98SSadaf Ebrahimi     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
696*62c56f98SSadaf Ebrahimi 
697*62c56f98SSadaf Ebrahimi     /* Check that a private key is loaded */
698*62c56f98SSadaf Ebrahimi     if (!priv_ctx->have_private_key) {
699*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
700*62c56f98SSadaf Ebrahimi     }
701*62c56f98SSadaf Ebrahimi 
702*62c56f98SSadaf Ebrahimi     ret = hash_digit_array(&priv_ctx->params,
703*62c56f98SSadaf Ebrahimi                            (unsigned char *) priv_ctx->private_key, NULL,
704*62c56f98SSadaf Ebrahimi                            NULL, (unsigned char *) y_hashed_digits);
705*62c56f98SSadaf Ebrahimi     if (ret) {
706*62c56f98SSadaf Ebrahimi         goto exit;
707*62c56f98SSadaf Ebrahimi     }
708*62c56f98SSadaf Ebrahimi 
709*62c56f98SSadaf Ebrahimi     ret = public_key_from_hashed_digit_array(&priv_ctx->params,
710*62c56f98SSadaf Ebrahimi                                              (unsigned char *) y_hashed_digits,
711*62c56f98SSadaf Ebrahimi                                              ctx->public_key);
712*62c56f98SSadaf Ebrahimi     if (ret) {
713*62c56f98SSadaf Ebrahimi         goto exit;
714*62c56f98SSadaf Ebrahimi     }
715*62c56f98SSadaf Ebrahimi 
716*62c56f98SSadaf Ebrahimi     memcpy(&ctx->params, &priv_ctx->params,
717*62c56f98SSadaf Ebrahimi            sizeof(ctx->params));
718*62c56f98SSadaf Ebrahimi 
719*62c56f98SSadaf Ebrahimi     ctx->have_public_key = 1;
720*62c56f98SSadaf Ebrahimi 
721*62c56f98SSadaf Ebrahimi exit:
722*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(y_hashed_digits, sizeof(y_hashed_digits));
723*62c56f98SSadaf Ebrahimi 
724*62c56f98SSadaf Ebrahimi     return ret;
725*62c56f98SSadaf Ebrahimi }
726*62c56f98SSadaf Ebrahimi 
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)727*62c56f98SSadaf Ebrahimi int mbedtls_lmots_sign(mbedtls_lmots_private_t *ctx,
728*62c56f98SSadaf Ebrahimi                        int (*f_rng)(void *, unsigned char *, size_t),
729*62c56f98SSadaf Ebrahimi                        void *p_rng, const unsigned char *msg, size_t msg_size,
730*62c56f98SSadaf Ebrahimi                        unsigned char *sig, size_t sig_size, size_t *sig_len)
731*62c56f98SSadaf Ebrahimi {
732*62c56f98SSadaf Ebrahimi     unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX];
733*62c56f98SSadaf Ebrahimi     /* Create a temporary buffer to prepare the signature in. This allows us to
734*62c56f98SSadaf Ebrahimi      * finish creating a signature (ensuring the process doesn't fail), and then
735*62c56f98SSadaf Ebrahimi      * erase the private key **before** writing any data into the sig parameter
736*62c56f98SSadaf Ebrahimi      * buffer. If data were directly written into the sig buffer, it might leak
737*62c56f98SSadaf Ebrahimi      * a partial signature on failure, which effectively compromises the private
738*62c56f98SSadaf Ebrahimi      * key.
739*62c56f98SSadaf Ebrahimi      */
740*62c56f98SSadaf Ebrahimi     unsigned char tmp_sig[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
741*62c56f98SSadaf Ebrahimi     unsigned char tmp_c_random[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
742*62c56f98SSadaf Ebrahimi     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
743*62c56f98SSadaf Ebrahimi 
744*62c56f98SSadaf Ebrahimi     if (msg == NULL && msg_size != 0) {
745*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
746*62c56f98SSadaf Ebrahimi     }
747*62c56f98SSadaf Ebrahimi 
748*62c56f98SSadaf Ebrahimi     if (sig_size < MBEDTLS_LMOTS_SIG_LEN(ctx->params.type)) {
749*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
750*62c56f98SSadaf Ebrahimi     }
751*62c56f98SSadaf Ebrahimi 
752*62c56f98SSadaf Ebrahimi     /* Check that a private key is loaded */
753*62c56f98SSadaf Ebrahimi     if (!ctx->have_private_key) {
754*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
755*62c56f98SSadaf Ebrahimi     }
756*62c56f98SSadaf Ebrahimi 
757*62c56f98SSadaf Ebrahimi     ret = f_rng(p_rng, tmp_c_random,
758*62c56f98SSadaf Ebrahimi                 MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
759*62c56f98SSadaf Ebrahimi     if (ret) {
760*62c56f98SSadaf Ebrahimi         return ret;
761*62c56f98SSadaf Ebrahimi     }
762*62c56f98SSadaf Ebrahimi 
763*62c56f98SSadaf Ebrahimi     ret = create_digit_array_with_checksum(&ctx->params,
764*62c56f98SSadaf Ebrahimi                                            msg, msg_size,
765*62c56f98SSadaf Ebrahimi                                            tmp_c_random,
766*62c56f98SSadaf Ebrahimi                                            tmp_digit_array);
767*62c56f98SSadaf Ebrahimi     if (ret) {
768*62c56f98SSadaf Ebrahimi         goto exit;
769*62c56f98SSadaf Ebrahimi     }
770*62c56f98SSadaf Ebrahimi 
771*62c56f98SSadaf Ebrahimi     ret = hash_digit_array(&ctx->params, (unsigned char *) ctx->private_key,
772*62c56f98SSadaf Ebrahimi                            NULL, tmp_digit_array, (unsigned char *) tmp_sig);
773*62c56f98SSadaf Ebrahimi     if (ret) {
774*62c56f98SSadaf Ebrahimi         goto exit;
775*62c56f98SSadaf Ebrahimi     }
776*62c56f98SSadaf Ebrahimi 
777*62c56f98SSadaf Ebrahimi     mbedtls_lms_unsigned_int_to_network_bytes(ctx->params.type,
778*62c56f98SSadaf Ebrahimi                                               MBEDTLS_LMOTS_TYPE_LEN,
779*62c56f98SSadaf Ebrahimi                                               sig + MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
780*62c56f98SSadaf Ebrahimi 
781*62c56f98SSadaf Ebrahimi     /* Test hook to check if sig is being written to before we invalidate the
782*62c56f98SSadaf Ebrahimi      * private key.
783*62c56f98SSadaf Ebrahimi      */
784*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_TEST_HOOKS)
785*62c56f98SSadaf Ebrahimi     if (mbedtls_lmots_sign_private_key_invalidated_hook != NULL) {
786*62c56f98SSadaf Ebrahimi         ret = (*mbedtls_lmots_sign_private_key_invalidated_hook)(sig);
787*62c56f98SSadaf Ebrahimi         if (ret != 0) {
788*62c56f98SSadaf Ebrahimi             return ret;
789*62c56f98SSadaf Ebrahimi         }
790*62c56f98SSadaf Ebrahimi     }
791*62c56f98SSadaf Ebrahimi #endif /* defined(MBEDTLS_TEST_HOOKS) */
792*62c56f98SSadaf Ebrahimi 
793*62c56f98SSadaf Ebrahimi     /* We've got a valid signature now, so it's time to make sure the private
794*62c56f98SSadaf Ebrahimi      * key can't be reused.
795*62c56f98SSadaf Ebrahimi      */
796*62c56f98SSadaf Ebrahimi     ctx->have_private_key = 0;
797*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(ctx->private_key,
798*62c56f98SSadaf Ebrahimi                              sizeof(ctx->private_key));
799*62c56f98SSadaf Ebrahimi 
800*62c56f98SSadaf Ebrahimi     memcpy(sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET, tmp_c_random,
801*62c56f98SSadaf Ebrahimi            MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(ctx->params.type));
802*62c56f98SSadaf Ebrahimi 
803*62c56f98SSadaf Ebrahimi     memcpy(sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(ctx->params.type), tmp_sig,
804*62c56f98SSadaf Ebrahimi            MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type)
805*62c56f98SSadaf Ebrahimi            * MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
806*62c56f98SSadaf Ebrahimi 
807*62c56f98SSadaf Ebrahimi     if (sig_len != NULL) {
808*62c56f98SSadaf Ebrahimi         *sig_len = MBEDTLS_LMOTS_SIG_LEN(ctx->params.type);
809*62c56f98SSadaf Ebrahimi     }
810*62c56f98SSadaf Ebrahimi 
811*62c56f98SSadaf Ebrahimi     ret = 0;
812*62c56f98SSadaf Ebrahimi 
813*62c56f98SSadaf Ebrahimi exit:
814*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(tmp_digit_array, sizeof(tmp_digit_array));
815*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(tmp_sig, sizeof(tmp_sig));
816*62c56f98SSadaf Ebrahimi 
817*62c56f98SSadaf Ebrahimi     return ret;
818*62c56f98SSadaf Ebrahimi }
819*62c56f98SSadaf Ebrahimi 
820*62c56f98SSadaf Ebrahimi #endif /* defined(MBEDTLS_LMS_PRIVATE) */
821*62c56f98SSadaf Ebrahimi #endif /* defined(MBEDTLS_LMS_C) */
822