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