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