blob: 915291c272212bc67b14d546b62ac51ff3b5a498 [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 Colesc8f96042022-08-25 13:49:54 +010041#include "mbedtls/lms.h"
Raef Coles8ff6df52021-07-21 12:42:15 +010042#include "mbedtls/platform_util.h"
43#include "mbedtls/error.h"
44
Raef Colesc8f96042022-08-25 13:49:54 +010045#include "psa/crypto.h"
46
Raef Coles8ff6df52021-07-21 12:42:15 +010047#define W_SYMBOL_BIT_LEN (8)
48#define CHECKSUM_LEN (2)
49#define I_SYMBOL_IDX_LEN (2)
50#define J_HASH_IDX_LEN (1)
51#define D_CONST_LEN (2)
52
53#define SYMBOL_MAX_VAL ((1 << W_SYMBOL_BIT_LEN) - 1)
54
55#define D_PBLC_CONSTANT (0x8080)
56#define D_MESG_CONSTANT (0x8181)
57
58static void val_to_network_bytes(unsigned int val, size_t len, unsigned char *bytes)
59{
60 size_t idx;
61
62 for (idx = 0; idx < len; idx++) {
63 bytes[idx] = (val >> ((len - 1 - idx) * 8)) & 0xFF;
64 }
65}
66
67static unsigned int network_bytes_to_val(size_t len, const unsigned char *bytes)
68{
69 size_t idx;
70 unsigned int val = 0;
71
72 for (idx = 0; idx < len; idx++) {
73 val |= ((unsigned int)bytes[idx]) << (8 * (len - 1 - idx));
74 }
75
76 return val;
77}
78
79static unsigned short lmots_checksum_generate( const unsigned char* digest )
80{
81 size_t idx;
82 unsigned short sum = 0;
83
84 for ( idx = 0; idx < MBEDTLS_LMOTS_N_HASH_LEN; idx++ )
85 {
86 sum += ( 1 << W_SYMBOL_BIT_LEN ) - 1 - digest[idx];
87 }
88
89 return sum;
90}
91
92static int create_symbol_array( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
93 const unsigned char q_leaf_identifier[MBEDTLS_LMOTS_Q_LEAF_ID_LEN],
94 const unsigned char *msg,
95 size_t msg_len,
96 const unsigned char C_random_value[MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN],
97 unsigned char out[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN] )
98{
Raef Colesc8f96042022-08-25 13:49:54 +010099 psa_hash_operation_t op;
100 psa_status_t status;
101 size_t output_hash_len;
Raef Coles8ff6df52021-07-21 12:42:15 +0100102 unsigned char D_MESG_BYTES[D_CONST_LEN];
103 unsigned short checksum;
104 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
105
Raef Colesc8f96042022-08-25 13:49:54 +0100106 op = psa_hash_operation_init();
107 status = psa_hash_setup( &op, PSA_ALG_SHA_256 );
108 ret = mbedtls_lms_error_from_psa( status );
109 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100110 {
111 goto out;
112 }
113
Raef Colesc8f96042022-08-25 13:49:54 +0100114 status = psa_hash_update( &op, I_key_identifier, MBEDTLS_LMOTS_I_KEY_ID_LEN );
115 ret = mbedtls_lms_error_from_psa( status );
116 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100117 {
118 goto out;
119 }
120
Raef Colesc8f96042022-08-25 13:49:54 +0100121 status = psa_hash_update( &op, q_leaf_identifier, MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
122 ret = mbedtls_lms_error_from_psa( status );
123 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100124 {
125 goto out;
126 }
127
128 val_to_network_bytes( D_MESG_CONSTANT, D_CONST_LEN, D_MESG_BYTES );
Raef Colesc8f96042022-08-25 13:49:54 +0100129 status = psa_hash_update( &op, D_MESG_BYTES, sizeof( D_MESG_BYTES ) );
130 ret = mbedtls_lms_error_from_psa( status );
131 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100132 {
133 goto out;
134 }
135
Raef Colesc8f96042022-08-25 13:49:54 +0100136 status = psa_hash_update( &op, C_random_value, MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN );
137 ret = mbedtls_lms_error_from_psa( status );
138 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100139 {
140 goto out;
141 }
142
Raef Colesc8f96042022-08-25 13:49:54 +0100143 status = psa_hash_update( &op, msg, msg_len );
144 ret = mbedtls_lms_error_from_psa( status );
145 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100146 {
147 goto out;
148 }
149
Raef Colesc8f96042022-08-25 13:49:54 +0100150 status = psa_hash_finish( &op, out, MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN,
151 &output_hash_len );
152 ret = mbedtls_lms_error_from_psa( status );
153 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100154 {
155 goto out;
156 }
157
158 checksum = lmots_checksum_generate( out );
159 val_to_network_bytes( checksum, CHECKSUM_LEN, out + MBEDTLS_LMOTS_N_HASH_LEN );
160
161out:
Raef Colesc8f96042022-08-25 13:49:54 +0100162 psa_hash_abort( &op );
Raef Coles8ff6df52021-07-21 12:42:15 +0100163
164 return( ret );
165}
166
167static int hash_symbol_array( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
168 const unsigned char q_leaf_identifier[MBEDTLS_LMOTS_Q_LEAF_ID_LEN],
169 const unsigned char x_symbol_array[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32],
170 const unsigned char hash_idx_min_values[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN],
171 const unsigned char hash_idx_max_values[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN],
172 unsigned char output[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32] )
173{
174 unsigned char i_symbol_idx;
175 unsigned char j_hash_idx;
176 unsigned char i_symbol_idx_bytes[I_SYMBOL_IDX_LEN];
177 unsigned char j_hash_idx_bytes[1];
178 unsigned short j_hash_idx_min;
179 unsigned short j_hash_idx_max;
Raef Colesc8f96042022-08-25 13:49:54 +0100180 psa_hash_operation_t op;
181 psa_status_t status;
182 size_t output_hash_len;
Raef Coles8ff6df52021-07-21 12:42:15 +0100183 unsigned char tmp_hash[32];
184 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
185
186 for ( i_symbol_idx = 0; i_symbol_idx < MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN; i_symbol_idx++ )
187 {
188
189 memcpy( tmp_hash, &x_symbol_array[i_symbol_idx], MBEDTLS_LMOTS_N_HASH_LEN );
190
191 j_hash_idx_min = hash_idx_min_values != NULL ? hash_idx_min_values[i_symbol_idx] : 0;
192 j_hash_idx_max = hash_idx_max_values != NULL ? hash_idx_max_values[i_symbol_idx] : SYMBOL_MAX_VAL;
193
194 for ( j_hash_idx = (unsigned char)j_hash_idx_min; j_hash_idx < j_hash_idx_max; j_hash_idx++ )
195 {
Raef Colesc8f96042022-08-25 13:49:54 +0100196 op = psa_hash_operation_init();
197 status = psa_hash_setup( &op, PSA_ALG_SHA_256 );
198 ret = mbedtls_lms_error_from_psa( status );
199 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100200 {
201 goto out;
202 }
203
Raef Colesc8f96042022-08-25 13:49:54 +0100204 status = psa_hash_update( &op, I_key_identifier, MBEDTLS_LMOTS_I_KEY_ID_LEN );
205 ret = mbedtls_lms_error_from_psa( status );
206 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100207 {
208 goto out;
209 }
210
Raef Colesc8f96042022-08-25 13:49:54 +0100211 status = psa_hash_update( &op, q_leaf_identifier, MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
212 ret = mbedtls_lms_error_from_psa( status );
213 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100214 {
215 goto out;
216 }
217
218 val_to_network_bytes( i_symbol_idx, I_SYMBOL_IDX_LEN, i_symbol_idx_bytes );
Raef Colesc8f96042022-08-25 13:49:54 +0100219 status = psa_hash_update( &op, i_symbol_idx_bytes, I_SYMBOL_IDX_LEN );
220 ret = mbedtls_lms_error_from_psa( status );
221 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100222 {
223 goto out;
224 }
225
226 val_to_network_bytes( j_hash_idx, J_HASH_IDX_LEN, j_hash_idx_bytes );
Raef Colesc8f96042022-08-25 13:49:54 +0100227 status = psa_hash_update( &op, j_hash_idx_bytes, J_HASH_IDX_LEN );
228 ret = mbedtls_lms_error_from_psa( status );
229 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100230 {
231 goto out;
232 }
233
Raef Colesc8f96042022-08-25 13:49:54 +0100234 status = psa_hash_update( &op, tmp_hash, MBEDTLS_LMOTS_N_HASH_LEN );
235 ret = mbedtls_lms_error_from_psa( status );
236 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100237 {
238 goto out;
239 }
240
Raef Colesc8f96042022-08-25 13:49:54 +0100241 status = psa_hash_finish( &op, tmp_hash, sizeof( tmp_hash ), &output_hash_len );
242 ret = mbedtls_lms_error_from_psa( status );
243 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100244 {
245 goto out;
246 }
247
Raef Colesc8f96042022-08-25 13:49:54 +0100248 psa_hash_abort( &op );
Raef Coles8ff6df52021-07-21 12:42:15 +0100249 }
250
251 memcpy( &output[i_symbol_idx], tmp_hash, MBEDTLS_LMOTS_N_HASH_LEN );
252 }
253
254out:
255 if( ret )
256 {
Raef Colesc8f96042022-08-25 13:49:54 +0100257 psa_hash_abort( &op );
Raef Coles8ff6df52021-07-21 12:42:15 +0100258 return( ret );
259 }
260
261 return ret;
262}
263
264static int public_key_from_hashed_symbol_array( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
265 const unsigned char q_leaf_identifier[MBEDTLS_LMOTS_Q_LEAF_ID_LEN],
266 const unsigned char y_hashed_symbols[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32],
267 unsigned char *pub_key )
268{
269 unsigned char D_PBLC_bytes[D_CONST_LEN];
Raef Colesc8f96042022-08-25 13:49:54 +0100270 psa_hash_operation_t op;
271 psa_status_t status;
272 size_t output_hash_len;
Raef Coles8ff6df52021-07-21 12:42:15 +0100273 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
274
Raef Colesc8f96042022-08-25 13:49:54 +0100275 op = psa_hash_operation_init( );
276 status = psa_hash_setup( &op, PSA_ALG_SHA_256 );
277 ret = mbedtls_lms_error_from_psa( status );
278 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100279 {
280 goto out;
281 }
282
Raef Colesc8f96042022-08-25 13:49:54 +0100283 status = psa_hash_update( &op, I_key_identifier, MBEDTLS_LMOTS_I_KEY_ID_LEN );
284 ret = mbedtls_lms_error_from_psa( status );
285 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100286 {
287 goto out;
288 }
289
Raef Colesc8f96042022-08-25 13:49:54 +0100290 status = psa_hash_update( &op, q_leaf_identifier, MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
291 ret = mbedtls_lms_error_from_psa( status );
292 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100293 {
294 goto out;
295 }
296
297 val_to_network_bytes( D_PBLC_CONSTANT, D_CONST_LEN, D_PBLC_bytes );
Raef Colesc8f96042022-08-25 13:49:54 +0100298 status = psa_hash_update( &op, D_PBLC_bytes, D_CONST_LEN );
299 ret = mbedtls_lms_error_from_psa( status );
300 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100301 {
302 goto out;
303 }
304
Raef Colesc8f96042022-08-25 13:49:54 +0100305 status = psa_hash_update( &op, ( unsigned char * )y_hashed_symbols,
306 MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN * MBEDTLS_LMOTS_N_HASH_LEN );
307 ret = mbedtls_lms_error_from_psa( status );
308 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100309 {
310 goto out;
311 }
312
Raef Colesc8f96042022-08-25 13:49:54 +0100313 status = psa_hash_finish( &op, pub_key, 32, &output_hash_len );
314 ret = mbedtls_lms_error_from_psa( status );
Raef Coles8ff6df52021-07-21 12:42:15 +0100315
316out:
Raef Colesc8f96042022-08-25 13:49:54 +0100317 psa_hash_abort( &op );
Raef Coles8ff6df52021-07-21 12:42:15 +0100318 return( ret );
319}
320
Raef Colesc8f96042022-08-25 13:49:54 +0100321int mbedtls_lms_error_from_psa(psa_status_t status)
322{
323 switch( status ) {
324 case PSA_SUCCESS:
325 return( 0 );
326 case PSA_ERROR_HARDWARE_FAILURE:
327 return( MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED );
328 case PSA_ERROR_NOT_SUPPORTED:
329 return( MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED );
330 case PSA_ERROR_BUFFER_TOO_SMALL:
331 return( MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL );
332 case PSA_ERROR_INVALID_ARGUMENT:
333 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
334 default:
335 return( MBEDTLS_ERR_ERROR_GENERIC_ERROR );
336 }
337}
338
Raef Coles8ff6df52021-07-21 12:42:15 +0100339void mbedtls_lmots_init( mbedtls_lmots_context *ctx )
340{
341 if( ctx == NULL ) {
342 return;
343 }
344
345 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lmots_context ) ) ;
346}
347
348void mbedtls_lmots_free( mbedtls_lmots_context *ctx )
349{
350 if( ctx == NULL )
351 {
352 return;
353 }
354
355 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lmots_context ) ) ;
356}
357
358int mbedtls_lmots_set_algorithm_type( mbedtls_lmots_context *ctx,
359 mbedtls_lmots_algorithm_type_t type )
360{
361 if( ctx == NULL )
362 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100363 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100364 }
365
366 ctx->MBEDTLS_PRIVATE(type) = type;
367
368 return( 0 );
369}
370
371int mbedtls_lmots_generate_pub_key_candidate( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
372 const unsigned char q_leaf_identifier[MBEDTLS_LMOTS_Q_LEAF_ID_LEN],
373 const unsigned char *msg,
374 size_t msg_len,
375 const unsigned char *sig,
376 unsigned char *out )
377{
378 unsigned char tmp_symbol_array[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN];
379 unsigned char y_hashed_symbols[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32];
380 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
381
382 if (I_key_identifier == NULL || msg == NULL || sig == NULL || out == NULL)
383 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100384 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100385 }
386
387 ret = create_symbol_array( I_key_identifier, q_leaf_identifier, msg, msg_len,
388 sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET, tmp_symbol_array );
389 if ( ret )
390 {
391 return ( ret );
392 }
393
394 ret = hash_symbol_array( I_key_identifier, q_leaf_identifier,
395 ( const unsigned char( *)[32] )(sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET),
396 tmp_symbol_array, NULL, y_hashed_symbols );
397 if ( ret )
398 {
399 return ( ret );
400 }
401
402 ret = public_key_from_hashed_symbol_array( I_key_identifier, q_leaf_identifier,
403 ( const unsigned char( *)[32] )y_hashed_symbols,
404 out );
405 if ( ret )
406 {
407 return ( ret );
408 }
409
410 return( 0 );
411}
412
413int mbedtls_lmots_sign( mbedtls_lmots_context *ctx,
414 int (*f_rng)(void *, unsigned char *, size_t),
415 void *p_rng, const unsigned char *msg, size_t msg_len,
416 unsigned char *sig )
417{
418 unsigned char tmp_symbol_array[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN];
419 unsigned char tmp_sig[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][MBEDTLS_LMOTS_N_HASH_LEN];
420 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
421
422 if( ctx == NULL || f_rng == NULL || p_rng == NULL || msg == NULL || sig == NULL)
423 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100424 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100425 }
426
427 /* Check that a private key is loaded */
428 if ( !ctx->MBEDTLS_PRIVATE(have_privkey) )
429 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100430 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100431 }
432
433 ret = f_rng( p_rng, sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET, MBEDTLS_LMOTS_N_HASH_LEN );
434 if ( ret )
435 {
436 return( ret );
437 }
438
439 ret = create_symbol_array( ctx->MBEDTLS_PRIVATE(I_key_identifier),
440 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
441 msg, msg_len, sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET,
442 tmp_symbol_array );
443 if ( ret )
444 {
445 return( ret );
446 }
447
448 ret = hash_symbol_array( ctx->MBEDTLS_PRIVATE(I_key_identifier),
449 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
450 ( const unsigned char( *)[32] )(ctx->MBEDTLS_PRIVATE(priv_key)),
451 NULL, tmp_symbol_array, tmp_sig );
452 if ( ret )
453 {
454 return( ret );
455 }
456
457 val_to_network_bytes( ctx->MBEDTLS_PRIVATE(type), MBEDTLS_LMOTS_TYPE_LEN,
458 sig + MBEDTLS_LMOTS_SIG_TYPE_OFFSET );
459
460 /* We've got a valid signature now, so it's time to make sure the private
461 * key can't be reused.
462 */
463 ctx->MBEDTLS_PRIVATE(have_privkey) = 0;
464 mbedtls_platform_zeroize(ctx->MBEDTLS_PRIVATE(priv_key),
465 sizeof(ctx->MBEDTLS_PRIVATE(priv_key)));
466
467 memcpy(sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET, tmp_sig,
468 MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN * MBEDTLS_LMOTS_N_HASH_LEN);
469
470 return( 0 );
471}
472
473int mbedtls_lmots_verify( mbedtls_lmots_context *ctx, const unsigned char *msg,
474 size_t msg_len, const unsigned char *sig )
475{
476 unsigned char Kc_public_key_candidate[32];
477 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
478
479 if( ctx == NULL || msg == NULL || sig == NULL)
480 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100481 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100482 }
483
484 if ( !ctx->MBEDTLS_PRIVATE(have_pubkey) )
485 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100486 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100487 }
488
489 if( ctx->MBEDTLS_PRIVATE(type ) != MBEDTLS_LMOTS_SHA256_N32_W8 )
490 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100491 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100492 }
493
494 if ( network_bytes_to_val( MBEDTLS_LMOTS_TYPE_LEN,
495 sig + MBEDTLS_LMOTS_SIG_TYPE_OFFSET ) != MBEDTLS_LMOTS_SHA256_N32_W8 )
496 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100497 return( MBEDTLS_ERR_LMS_VERIFY_FAILED );
Raef Coles8ff6df52021-07-21 12:42:15 +0100498 }
499
500 ret = mbedtls_lmots_generate_pub_key_candidate( ctx->MBEDTLS_PRIVATE(I_key_identifier),
501 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
502 msg, msg_len, sig,
503 Kc_public_key_candidate );
504 if ( ret )
505 {
506 return( ret );
507 }
508
509 if ( memcmp( &Kc_public_key_candidate, ctx->MBEDTLS_PRIVATE(pub_key),
510 sizeof( ctx->MBEDTLS_PRIVATE(pub_key) ) ) )
511 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100512 return( MBEDTLS_ERR_LMS_VERIFY_FAILED );
Raef Coles8ff6df52021-07-21 12:42:15 +0100513 }
514
515 return( 0 );
516}
517
518int mbedtls_lmots_import_pubkey( mbedtls_lmots_context *ctx,
519 const unsigned char *key )
520{
521 if ( ctx == NULL || key == NULL)
522 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100523 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100524 }
525
526 ctx->MBEDTLS_PRIVATE(type) = network_bytes_to_val( MBEDTLS_LMOTS_TYPE_LEN,
527 key + MBEDTLS_LMOTS_SIG_TYPE_OFFSET );
528
529 memcpy( ctx->MBEDTLS_PRIVATE(I_key_identifier), key + MBEDTLS_LMOTS_PUBKEY_I_KEY_ID_OFFSET,
530 MBEDTLS_LMOTS_I_KEY_ID_LEN );
531
532 memcpy( ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes), key + MBEDTLS_LMOTS_PUBKEY_Q_LEAF_ID_OFFSET,
533 MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
534 ctx->MBEDTLS_PRIVATE(q_leaf_identifier) = network_bytes_to_val( MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
535 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes) );
536
537 memcpy( ctx->MBEDTLS_PRIVATE(pub_key), key + MBEDTLS_LMOTS_PUBKEY_KEY_HASH_OFFSET, MBEDTLS_LMOTS_N_HASH_LEN );
538
539 ctx->MBEDTLS_PRIVATE(have_pubkey) = 1;
540
541 return( 0 );
542}
543
544int mbedtls_lmots_export_pubkey( mbedtls_lmots_context *ctx,
545 unsigned char *key )
546{
547 if ( ctx == NULL || key == NULL)
548 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100549 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100550 }
551
552 if ( ! ctx->MBEDTLS_PRIVATE(have_pubkey) )
553 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100554 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100555 }
556
557 val_to_network_bytes( ctx->MBEDTLS_PRIVATE(type), MBEDTLS_LMOTS_TYPE_LEN,
558 key + MBEDTLS_LMOTS_SIG_TYPE_OFFSET );
559
560 memcpy( key + MBEDTLS_LMOTS_PUBKEY_I_KEY_ID_OFFSET, ctx->MBEDTLS_PRIVATE(I_key_identifier),
561 MBEDTLS_LMOTS_I_KEY_ID_LEN );
562
563 memcpy( key + MBEDTLS_LMOTS_PUBKEY_Q_LEAF_ID_OFFSET, ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
564 MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
565
566 memcpy( key + MBEDTLS_LMOTS_PUBKEY_KEY_HASH_OFFSET, ctx->MBEDTLS_PRIVATE(pub_key),
567 MBEDTLS_LMOTS_N_HASH_LEN );
568
569 return( 0 );
570}
571
572
573int mbedtls_lmots_gen_pubkey( mbedtls_lmots_context *ctx )
574{
575 unsigned char y_hashed_symbols[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32];
576 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
577
578 if( ctx == NULL )
579 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100580 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100581 }
582
583 /* Check that a private key is loaded */
584 if ( !ctx->MBEDTLS_PRIVATE(have_privkey) )
585 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100586 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100587 }
588
589 ret = hash_symbol_array( ctx->MBEDTLS_PRIVATE(I_key_identifier),
590 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
591 ( const unsigned char( *)[32] )(ctx->MBEDTLS_PRIVATE(priv_key)),
592 NULL, NULL, y_hashed_symbols );
593 if ( ret )
594 {
595 return( ret );
596 }
597
598 ret = public_key_from_hashed_symbol_array( ctx->MBEDTLS_PRIVATE(I_key_identifier),
599 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
600 ( const unsigned char( *)[32] )y_hashed_symbols,
601 ctx->MBEDTLS_PRIVATE(pub_key) );
602 if ( ret )
603 {
604 return( ret );
605 }
606
607 ctx->MBEDTLS_PRIVATE(have_pubkey = 1);
608
609 return( ret );
610}
611
612int mbedtls_lmots_gen_privkey( mbedtls_lmots_context *ctx,
613 const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
614 unsigned int q_leaf_identifier,
615 const unsigned char *seed,
616 size_t seed_len )
617{
Raef Colesc8f96042022-08-25 13:49:54 +0100618 psa_hash_operation_t op;
619 psa_status_t status;
620 size_t output_hash_len;
Raef Coles8ff6df52021-07-21 12:42:15 +0100621 unsigned int i_symbol_idx;
622 unsigned char i_symbol_idx_bytes[2];
623 unsigned char const_bytes[1];
624 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
625
626 if( ctx == NULL || I_key_identifier == NULL || seed == NULL)
627 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100628 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100629 }
630
631 if ( ctx->MBEDTLS_PRIVATE(have_privkey) )
632 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100633 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100634 }
635
636 if ( ctx->MBEDTLS_PRIVATE(type) != MBEDTLS_LMOTS_SHA256_N32_W8 ) {
Raef Coles7dce69a2022-08-24 14:07:06 +0100637 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100638 }
639
640 memcpy( ctx->MBEDTLS_PRIVATE(I_key_identifier), I_key_identifier,
641 sizeof( ctx->MBEDTLS_PRIVATE(I_key_identifier) ) );
642
643 ctx->MBEDTLS_PRIVATE(q_leaf_identifier) = q_leaf_identifier;
644
645 val_to_network_bytes( ctx->MBEDTLS_PRIVATE(q_leaf_identifier), MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
646 ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes) );
647
648 val_to_network_bytes( 0xFF, sizeof( const_bytes ), const_bytes );
649
650 for ( i_symbol_idx = 0; i_symbol_idx < MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN; i_symbol_idx++ )
651 {
Raef Colesc8f96042022-08-25 13:49:54 +0100652 op = psa_hash_operation_init( );
653 status = psa_hash_setup( &op, PSA_ALG_SHA_256 );
654 ret = mbedtls_lms_error_from_psa( status );
655 if ( ret != 0 )
Raef Coles8ff6df52021-07-21 12:42:15 +0100656 {
657 goto out;
658 }
659
Raef Colesc8f96042022-08-25 13:49:54 +0100660 ret = psa_hash_update( &op, ctx->MBEDTLS_PRIVATE(I_key_identifier),
661 sizeof( ctx->MBEDTLS_PRIVATE(I_key_identifier) ) );
662 ret = mbedtls_lms_error_from_psa( status );
Raef Coles8ff6df52021-07-21 12:42:15 +0100663 if ( ret ) {
664 goto out;
665 }
666
Raef Colesc8f96042022-08-25 13:49:54 +0100667 status = psa_hash_update( &op, ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes),
668 sizeof( ctx->MBEDTLS_PRIVATE(q_leaf_identifier_bytes) ) );
669 ret = mbedtls_lms_error_from_psa( status );
Raef Coles8ff6df52021-07-21 12:42:15 +0100670 if ( ret )
671 {
672 goto out;
673 }
674
675 val_to_network_bytes( i_symbol_idx, I_SYMBOL_IDX_LEN, i_symbol_idx_bytes );
Raef Colesc8f96042022-08-25 13:49:54 +0100676 status = psa_hash_update( &op, i_symbol_idx_bytes, I_SYMBOL_IDX_LEN );
677 ret = mbedtls_lms_error_from_psa( status );
Raef Coles8ff6df52021-07-21 12:42:15 +0100678 if ( ret )
679 {
680 goto out;
681 }
682
Raef Colesc8f96042022-08-25 13:49:54 +0100683 status = psa_hash_update( &op, const_bytes, sizeof( const_bytes) );
684 ret = mbedtls_lms_error_from_psa( status );
Raef Coles8ff6df52021-07-21 12:42:15 +0100685 if ( ret )
686 {
687 goto out;
688 }
689
Raef Colesc8f96042022-08-25 13:49:54 +0100690 status = psa_hash_update( &op, seed, seed_len );
691 ret = mbedtls_lms_error_from_psa( status );
Raef Coles8ff6df52021-07-21 12:42:15 +0100692 if ( ret )
693 {
694 goto out;
695 }
696
Raef Colesc8f96042022-08-25 13:49:54 +0100697 status = psa_hash_finish( &op, ctx->MBEDTLS_PRIVATE(priv_key)[i_symbol_idx],
698 32, &output_hash_len );
699 ret = mbedtls_lms_error_from_psa( status );
Raef Coles8ff6df52021-07-21 12:42:15 +0100700 if ( ret )
701 {
702 goto out;
703 }
704
Raef Colesc8f96042022-08-25 13:49:54 +0100705 psa_hash_abort( &op );
Raef Coles8ff6df52021-07-21 12:42:15 +0100706 }
707
708 ctx->MBEDTLS_PRIVATE(have_privkey) = 1;
709
710out:
711 if( ret )
712 {
Raef Colesc8f96042022-08-25 13:49:54 +0100713 psa_hash_abort( &op );
Raef Coles8ff6df52021-07-21 12:42:15 +0100714 return( ret );
715 }
716
717 return ret;
718}
719
Raef Coles7dce69a2022-08-24 14:07:06 +0100720#endif /* MBEDTLS_LMS_C */