blob: 7319d29be793e4ec0aa41df3cffed514bca2bdbc [file] [log] [blame]
Raef Coles8ff6df52021-07-21 12:42:15 +01001/*
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#ifdef MBEDTLS_LMOTS_C
36
37#include <string.h>
38
39#include "mbedtls/lmots.h"
40#include "mbedtls/md.h"
41#include "mbedtls/platform_util.h"
42#include "mbedtls/error.h"
43
44#define W_SYMBOL_BIT_LEN (8)
45#define CHECKSUM_LEN (2)
46#define I_SYMBOL_IDX_LEN (2)
47#define J_HASH_IDX_LEN (1)
48#define D_CONST_LEN (2)
49
50#define SYMBOL_MAX_VAL ((1 << W_SYMBOL_BIT_LEN) - 1)
51
52#define D_PBLC_CONSTANT (0x8080)
53#define D_MESG_CONSTANT (0x8181)
54
55static void val_to_network_bytes(unsigned int val, size_t len, unsigned char *bytes)
56{
57 size_t idx;
58
59 for (idx = 0; idx < len; idx++) {
60 bytes[idx] = (val >> ((len - 1 - idx) * 8)) & 0xFF;
61 }
62}
63
64static unsigned int network_bytes_to_val(size_t len, const unsigned char *bytes)
65{
66 size_t idx;
67 unsigned int val = 0;
68
69 for (idx = 0; idx < len; idx++) {
70 val |= ((unsigned int)bytes[idx]) << (8 * (len - 1 - idx));
71 }
72
73 return val;
74}
75
76static unsigned short lmots_checksum_generate( const unsigned char* digest )
77{
78 size_t idx;
79 unsigned short sum = 0;
80
81 for ( idx = 0; idx < MBEDTLS_LMOTS_N_HASH_LEN; idx++ )
82 {
83 sum += ( 1 << W_SYMBOL_BIT_LEN ) - 1 - digest[idx];
84 }
85
86 return sum;
87}
88
89static int create_symbol_array( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
90 const unsigned char q_leaf_identifier[MBEDTLS_LMOTS_Q_LEAF_ID_LEN],
91 const unsigned char *msg,
92 size_t msg_len,
93 const unsigned char C_random_value[MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN],
94 unsigned char out[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN] )
95{
96 mbedtls_md_context_t hash_ctx;
97 unsigned char D_MESG_BYTES[D_CONST_LEN];
98 unsigned short checksum;
99 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
100
101 mbedtls_md_init( &hash_ctx );
102 ret = mbedtls_md_setup( &hash_ctx, mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ), 0 );
103 if( ret )
104 {
105 goto out;
106 }
107 ret = mbedtls_md_starts( &hash_ctx );
108 if ( ret )
109 {
110 goto out;
111 }
112
113 ret = mbedtls_md_update( &hash_ctx, I_key_identifier, MBEDTLS_LMOTS_I_KEY_ID_LEN );
114 if ( ret )
115 {
116 goto out;
117 }
118
119 ret = mbedtls_md_update( &hash_ctx, q_leaf_identifier, MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
120 if ( ret )
121 {
122 goto out;
123 }
124
125 val_to_network_bytes( D_MESG_CONSTANT, D_CONST_LEN, D_MESG_BYTES );
126 ret = mbedtls_md_update( &hash_ctx, D_MESG_BYTES, sizeof( D_MESG_BYTES ) );
127 if ( ret )
128 {
129 goto out;
130 }
131
132 ret = mbedtls_md_update( &hash_ctx, C_random_value, MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN );
133 if ( ret )
134 {
135 goto out;
136 }
137
138 ret = mbedtls_md_update( &hash_ctx, msg, msg_len );
139 if ( ret )
140 {
141 goto out;
142 }
143
144 ret = mbedtls_md_finish( &hash_ctx, out );
145 if ( ret )
146 {
147 goto out;
148 }
149
150 checksum = lmots_checksum_generate( out );
151 val_to_network_bytes( checksum, CHECKSUM_LEN, out + MBEDTLS_LMOTS_N_HASH_LEN );
152
153out:
154 mbedtls_md_free( &hash_ctx );
155
156 return( ret );
157}
158
159static int hash_symbol_array( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
160 const unsigned char q_leaf_identifier[MBEDTLS_LMOTS_Q_LEAF_ID_LEN],
161 const unsigned char x_symbol_array[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32],
162 const unsigned char hash_idx_min_values[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN],
163 const unsigned char hash_idx_max_values[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN],
164 unsigned char output[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32] )
165{
166 unsigned char i_symbol_idx;
167 unsigned char j_hash_idx;
168 unsigned char i_symbol_idx_bytes[I_SYMBOL_IDX_LEN];
169 unsigned char j_hash_idx_bytes[1];
170 unsigned short j_hash_idx_min;
171 unsigned short j_hash_idx_max;
172 mbedtls_md_context_t hash_ctx;
173 unsigned char tmp_hash[32];
174 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
175
176 for ( i_symbol_idx = 0; i_symbol_idx < MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN; i_symbol_idx++ )
177 {
178
179 memcpy( tmp_hash, &x_symbol_array[i_symbol_idx], MBEDTLS_LMOTS_N_HASH_LEN );
180
181 j_hash_idx_min = hash_idx_min_values != NULL ? hash_idx_min_values[i_symbol_idx] : 0;
182 j_hash_idx_max = hash_idx_max_values != NULL ? hash_idx_max_values[i_symbol_idx] : SYMBOL_MAX_VAL;
183
184 for ( j_hash_idx = (unsigned char)j_hash_idx_min; j_hash_idx < j_hash_idx_max; j_hash_idx++ )
185 {
186 mbedtls_md_init( &hash_ctx );
187 ret = mbedtls_md_setup( &hash_ctx, mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ), 0 );
188 if( ret )
189 {
190 goto out;
191 }
192 ret = mbedtls_md_starts( &hash_ctx );
193 if ( ret )
194 {
195 goto out;
196 }
197
198 ret = mbedtls_md_update( &hash_ctx, I_key_identifier, MBEDTLS_LMOTS_I_KEY_ID_LEN );
199 if ( ret )
200 {
201 goto out;
202 }
203
204 ret = mbedtls_md_update( &hash_ctx, q_leaf_identifier, MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
205 if ( ret )
206 {
207 goto out;
208 }
209
210 val_to_network_bytes( i_symbol_idx, I_SYMBOL_IDX_LEN, i_symbol_idx_bytes );
211 ret = mbedtls_md_update( &hash_ctx, i_symbol_idx_bytes, I_SYMBOL_IDX_LEN );
212 if ( ret )
213 {
214 goto out;
215 }
216
217 val_to_network_bytes( j_hash_idx, J_HASH_IDX_LEN, j_hash_idx_bytes );
218 ret = mbedtls_md_update( &hash_ctx, j_hash_idx_bytes, J_HASH_IDX_LEN );
219 if ( ret )
220 {
221 goto out;
222 }
223
224 ret = mbedtls_md_update( &hash_ctx, tmp_hash, MBEDTLS_LMOTS_N_HASH_LEN );
225 if ( ret )
226 {
227 goto out;
228 }
229
230 ret = mbedtls_md_finish( &hash_ctx, tmp_hash );
231 if ( ret )
232 {
233 goto out;
234 }
235
236 mbedtls_md_free( &hash_ctx );
237 }
238
239 memcpy( &output[i_symbol_idx], tmp_hash, MBEDTLS_LMOTS_N_HASH_LEN );
240 }
241
242out:
243 if( ret )
244 {
245 mbedtls_md_free( &hash_ctx );
246 return( ret );
247 }
248
249 return ret;
250}
251
252static int public_key_from_hashed_symbol_array( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
253 const unsigned char q_leaf_identifier[MBEDTLS_LMOTS_Q_LEAF_ID_LEN],
254 const unsigned char y_hashed_symbols[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32],
255 unsigned char *pub_key )
256{
257 unsigned char D_PBLC_bytes[D_CONST_LEN];
258 mbedtls_md_context_t hash_ctx;
259 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
260
261 mbedtls_md_init( &hash_ctx );
262 ret = mbedtls_md_setup( &hash_ctx, mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ), 0 );
263 if( ret )
264 {
265 goto out;
266 }
267 ret = mbedtls_md_starts( &hash_ctx );
268 if ( ret )
269 {
270 goto out;
271 }
272
273 ret = mbedtls_md_update( &hash_ctx, I_key_identifier,
274 MBEDTLS_LMOTS_I_KEY_ID_LEN );
275 if ( ret )
276 {
277 goto out;
278 }
279
280 ret = mbedtls_md_update( &hash_ctx, q_leaf_identifier,
281 MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
282 if ( ret )
283 {
284 goto out;
285 }
286
287 val_to_network_bytes( D_PBLC_CONSTANT, D_CONST_LEN, D_PBLC_bytes );
288 ret = mbedtls_md_update( &hash_ctx, D_PBLC_bytes, D_CONST_LEN );
289 if ( ret )
290 {
291 goto out;
292 }
293
294 ret = mbedtls_md_update( &hash_ctx, ( unsigned char * )y_hashed_symbols,
295 MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN * MBEDTLS_LMOTS_N_HASH_LEN );
296 if ( ret )
297 {
298 goto out;
299 }
300
301 ret = mbedtls_md_finish( &hash_ctx, pub_key );
302
303out:
304 mbedtls_md_free( &hash_ctx );
305 return( ret );
306}
307
308void mbedtls_lmots_init( mbedtls_lmots_context *ctx )
309{
310 if( ctx == NULL ) {
311 return;
312 }
313
314 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lmots_context ) ) ;
315}
316
317void mbedtls_lmots_free( mbedtls_lmots_context *ctx )
318{
319 if( ctx == NULL )
320 {
321 return;
322 }
323
324 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lmots_context ) ) ;
325}
326
327int mbedtls_lmots_set_algorithm_type( mbedtls_lmots_context *ctx,
328 mbedtls_lmots_algorithm_type_t type )
329{
330 if( ctx == NULL )
331 {
332 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
333 }
334
335 ctx->MBEDTLS_PRIVATE(type) = type;
336
337 return( 0 );
338}
339
340int mbedtls_lmots_generate_pub_key_candidate( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
341 const unsigned char q_leaf_identifier[MBEDTLS_LMOTS_Q_LEAF_ID_LEN],
342 const unsigned char *msg,
343 size_t msg_len,
344 const unsigned char *sig,
345 unsigned char *out )
346{
347 unsigned char tmp_symbol_array[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN];
348 unsigned char y_hashed_symbols[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32];
349 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
350
351 if (I_key_identifier == NULL || msg == NULL || sig == NULL || out == NULL)
352 {
353 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
354 }
355
356 ret = create_symbol_array( I_key_identifier, q_leaf_identifier, msg, msg_len,
357 sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET, tmp_symbol_array );
358 if ( ret )
359 {
360 return ( ret );
361 }
362
363 ret = hash_symbol_array( I_key_identifier, q_leaf_identifier,
364 ( const unsigned char( *)[32] )(sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET),
365 tmp_symbol_array, NULL, y_hashed_symbols );
366 if ( ret )
367 {
368 return ( ret );
369 }
370
371 ret = public_key_from_hashed_symbol_array( I_key_identifier, q_leaf_identifier,
372 ( const unsigned char( *)[32] )y_hashed_symbols,
373 out );
374 if ( ret )
375 {
376 return ( ret );
377 }
378
379 return( 0 );
380}
381
382int mbedtls_lmots_sign( mbedtls_lmots_context *ctx,
383 int (*f_rng)(void *, unsigned char *, size_t),
384 void *p_rng, const unsigned char *msg, size_t msg_len,
385 unsigned char *sig )
386{
387 unsigned char tmp_symbol_array[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN];
388 unsigned char tmp_sig[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][MBEDTLS_LMOTS_N_HASH_LEN];
389 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
390
391 if( ctx == NULL || f_rng == NULL || p_rng == NULL || msg == NULL || sig == NULL)
392 {
393 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
394 }
395
396 /* Check that a private key is loaded */
397 if ( !ctx->MBEDTLS_PRIVATE(have_privkey) )
398 {
399 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
400 }
401
402 ret = f_rng( p_rng, sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET, MBEDTLS_LMOTS_N_HASH_LEN );
403 if ( ret )
404 {
405 return( ret );
406 }
407
408 ret = create_symbol_array( ctx->MBEDTLS_PRIVATE(I_key_identifier),
409 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
410 msg, msg_len, sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET,
411 tmp_symbol_array );
412 if ( ret )
413 {
414 return( ret );
415 }
416
417 ret = hash_symbol_array( ctx->MBEDTLS_PRIVATE(I_key_identifier),
418 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
419 ( const unsigned char( *)[32] )(ctx->MBEDTLS_PRIVATE(priv_key)),
420 NULL, tmp_symbol_array, tmp_sig );
421 if ( ret )
422 {
423 return( ret );
424 }
425
426 val_to_network_bytes( ctx->MBEDTLS_PRIVATE(type), MBEDTLS_LMOTS_TYPE_LEN,
427 sig + MBEDTLS_LMOTS_SIG_TYPE_OFFSET );
428
429 /* We've got a valid signature now, so it's time to make sure the private
430 * key can't be reused.
431 */
432 ctx->MBEDTLS_PRIVATE(have_privkey) = 0;
433 mbedtls_platform_zeroize(ctx->MBEDTLS_PRIVATE(priv_key),
434 sizeof(ctx->MBEDTLS_PRIVATE(priv_key)));
435
436 memcpy(sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET, tmp_sig,
437 MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN * MBEDTLS_LMOTS_N_HASH_LEN);
438
439 return( 0 );
440}
441
442int mbedtls_lmots_verify( mbedtls_lmots_context *ctx, const unsigned char *msg,
443 size_t msg_len, const unsigned char *sig )
444{
445 unsigned char Kc_public_key_candidate[32];
446 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
447
448 if( ctx == NULL || msg == NULL || sig == NULL)
449 {
450 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
451 }
452
453 if ( !ctx->MBEDTLS_PRIVATE(have_pubkey) )
454 {
455 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
456 }
457
458 if( ctx->MBEDTLS_PRIVATE(type ) != MBEDTLS_LMOTS_SHA256_N32_W8 )
459 {
460 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
461 }
462
463 if ( network_bytes_to_val( MBEDTLS_LMOTS_TYPE_LEN,
464 sig + MBEDTLS_LMOTS_SIG_TYPE_OFFSET ) != MBEDTLS_LMOTS_SHA256_N32_W8 )
465 {
466 return( MBEDTLS_ERR_LMOTS_VERIFY_FAILED );
467 }
468
469 ret = mbedtls_lmots_generate_pub_key_candidate( ctx->MBEDTLS_PRIVATE(I_key_identifier),
470 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
471 msg, msg_len, sig,
472 Kc_public_key_candidate );
473 if ( ret )
474 {
475 return( ret );
476 }
477
478 if ( memcmp( &Kc_public_key_candidate, ctx->MBEDTLS_PRIVATE(pub_key),
479 sizeof( ctx->MBEDTLS_PRIVATE(pub_key) ) ) )
480 {
481 return( MBEDTLS_ERR_LMOTS_VERIFY_FAILED );
482 }
483
484 return( 0 );
485}
486
487int mbedtls_lmots_import_pubkey( mbedtls_lmots_context *ctx,
488 const unsigned char *key )
489{
490 if ( ctx == NULL || key == NULL)
491 {
492 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
493 }
494
495 ctx->MBEDTLS_PRIVATE(type) = network_bytes_to_val( MBEDTLS_LMOTS_TYPE_LEN,
496 key + MBEDTLS_LMOTS_SIG_TYPE_OFFSET );
497
498 memcpy( ctx->MBEDTLS_PRIVATE(I_key_identifier), key + MBEDTLS_LMOTS_PUBKEY_I_KEY_ID_OFFSET,
499 MBEDTLS_LMOTS_I_KEY_ID_LEN );
500
501 memcpy( ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes), key + MBEDTLS_LMOTS_PUBKEY_Q_LEAF_ID_OFFSET,
502 MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
503 ctx->MBEDTLS_PRIVATE(q_leaf_identifier) = network_bytes_to_val( MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
504 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes) );
505
506 memcpy( ctx->MBEDTLS_PRIVATE(pub_key), key + MBEDTLS_LMOTS_PUBKEY_KEY_HASH_OFFSET, MBEDTLS_LMOTS_N_HASH_LEN );
507
508 ctx->MBEDTLS_PRIVATE(have_pubkey) = 1;
509
510 return( 0 );
511}
512
513int mbedtls_lmots_export_pubkey( mbedtls_lmots_context *ctx,
514 unsigned char *key )
515{
516 if ( ctx == NULL || key == NULL)
517 {
518 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
519 }
520
521 if ( ! ctx->MBEDTLS_PRIVATE(have_pubkey) )
522 {
523 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
524 }
525
526 val_to_network_bytes( ctx->MBEDTLS_PRIVATE(type), MBEDTLS_LMOTS_TYPE_LEN,
527 key + MBEDTLS_LMOTS_SIG_TYPE_OFFSET );
528
529 memcpy( key + MBEDTLS_LMOTS_PUBKEY_I_KEY_ID_OFFSET, ctx->MBEDTLS_PRIVATE(I_key_identifier),
530 MBEDTLS_LMOTS_I_KEY_ID_LEN );
531
532 memcpy( key + MBEDTLS_LMOTS_PUBKEY_Q_LEAF_ID_OFFSET, ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
533 MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
534
535 memcpy( key + MBEDTLS_LMOTS_PUBKEY_KEY_HASH_OFFSET, ctx->MBEDTLS_PRIVATE(pub_key),
536 MBEDTLS_LMOTS_N_HASH_LEN );
537
538 return( 0 );
539}
540
541
542int mbedtls_lmots_gen_pubkey( mbedtls_lmots_context *ctx )
543{
544 unsigned char y_hashed_symbols[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32];
545 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
546
547 if( ctx == NULL )
548 {
549 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
550 }
551
552 /* Check that a private key is loaded */
553 if ( !ctx->MBEDTLS_PRIVATE(have_privkey) )
554 {
555 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
556 }
557
558 ret = hash_symbol_array( ctx->MBEDTLS_PRIVATE(I_key_identifier),
559 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
560 ( const unsigned char( *)[32] )(ctx->MBEDTLS_PRIVATE(priv_key)),
561 NULL, NULL, y_hashed_symbols );
562 if ( ret )
563 {
564 return( ret );
565 }
566
567 ret = public_key_from_hashed_symbol_array( ctx->MBEDTLS_PRIVATE(I_key_identifier),
568 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
569 ( const unsigned char( *)[32] )y_hashed_symbols,
570 ctx->MBEDTLS_PRIVATE(pub_key) );
571 if ( ret )
572 {
573 return( ret );
574 }
575
576 ctx->MBEDTLS_PRIVATE(have_pubkey = 1);
577
578 return( ret );
579}
580
581int mbedtls_lmots_gen_privkey( mbedtls_lmots_context *ctx,
582 const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
583 unsigned int q_leaf_identifier,
584 const unsigned char *seed,
585 size_t seed_len )
586{
587 mbedtls_md_context_t hash_ctx;
588 unsigned int i_symbol_idx;
589 unsigned char i_symbol_idx_bytes[2];
590 unsigned char const_bytes[1];
591 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
592
593 if( ctx == NULL || I_key_identifier == NULL || seed == NULL)
594 {
595 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
596 }
597
598 if ( ctx->MBEDTLS_PRIVATE(have_privkey) )
599 {
600 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
601 }
602
603 if ( ctx->MBEDTLS_PRIVATE(type) != MBEDTLS_LMOTS_SHA256_N32_W8 ) {
604 return( MBEDTLS_ERR_LMOTS_BAD_INPUT_DATA );
605 }
606
607 memcpy( ctx->MBEDTLS_PRIVATE(I_key_identifier), I_key_identifier,
608 sizeof( ctx->MBEDTLS_PRIVATE(I_key_identifier) ) );
609
610 ctx->MBEDTLS_PRIVATE(q_leaf_identifier) = q_leaf_identifier;
611
612 val_to_network_bytes( ctx->MBEDTLS_PRIVATE(q_leaf_identifier), MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
613 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes) );
614
615 val_to_network_bytes( 0xFF, sizeof( const_bytes ), const_bytes );
616
617 for ( i_symbol_idx = 0; i_symbol_idx < MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN; i_symbol_idx++ )
618 {
619 mbedtls_md_init( &hash_ctx );
620 ret = mbedtls_md_setup( &hash_ctx, mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ), 0 );
621 if( ret )
622 {
623 goto out;
624 }
625 ret = mbedtls_md_starts( &hash_ctx );
626 if ( ret )
627 {
628 goto out;
629 }
630
631 ret = mbedtls_md_update( &hash_ctx, ctx->MBEDTLS_PRIVATE(I_key_identifier),
632 sizeof( ctx->MBEDTLS_PRIVATE(I_key_identifier) ) );
633 if ( ret ) {
634 goto out;
635 }
636
637 ret = mbedtls_md_update( &hash_ctx, ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
638 sizeof( ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes) ) );
639 if ( ret )
640 {
641 goto out;
642 }
643
644 val_to_network_bytes( i_symbol_idx, I_SYMBOL_IDX_LEN, i_symbol_idx_bytes );
645 ret = mbedtls_md_update( &hash_ctx, i_symbol_idx_bytes, I_SYMBOL_IDX_LEN );
646 if ( ret )
647 {
648 goto out;
649 }
650
651 ret = mbedtls_md_update( &hash_ctx, const_bytes, sizeof( const_bytes) );
652 if ( ret )
653 {
654 goto out;
655 }
656
657 ret = mbedtls_md_update( &hash_ctx, seed, seed_len );
658 if ( ret )
659 {
660 goto out;
661 }
662
663 ret = mbedtls_md_finish( &hash_ctx, ctx->MBEDTLS_PRIVATE(priv_key)[i_symbol_idx] );
664 if ( ret )
665 {
666 goto out;
667 }
668
669 mbedtls_md_free( &hash_ctx);
670 }
671
672 ctx->MBEDTLS_PRIVATE(have_privkey) = 1;
673
674out:
675 if( ret )
676 {
677 mbedtls_md_free( &hash_ctx );
678 return( ret );
679 }
680
681 return ret;
682}
683
684#endif /* MBEDTLS_LMOTS_C */