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