1 /**
2 * PSA API key derivation demonstration
3 *
4 * This program calculates a key ladder: a chain of secret material, each
5 * derived from the previous one in a deterministic way based on a label.
6 * Two keys are identical if and only if they are derived from the same key
7 * using the same label.
8 *
9 * The initial key is called the master key. The master key is normally
10 * randomly generated, but it could itself be derived from another key.
11 *
12 * This program derives a series of keys called intermediate keys.
13 * The first intermediate key is derived from the master key using the
14 * first label passed on the command line. Each subsequent intermediate
15 * key is derived from the previous one using the next label passed
16 * on the command line.
17 *
18 * This program has four modes of operation:
19 *
20 * - "generate": generate a random master key.
21 * - "wrap": derive a wrapping key from the last intermediate key,
22 * and use that key to encrypt-and-authenticate some data.
23 * - "unwrap": derive a wrapping key from the last intermediate key,
24 * and use that key to decrypt-and-authenticate some
25 * ciphertext created by wrap mode.
26 * - "save": save the last intermediate key so that it can be reused as
27 * the master key in another run of the program.
28 *
29 * See the usage() output for the command line usage. See the file
30 * `key_ladder_demo.sh` for an example run.
31 */
32
33 /*
34 * Copyright The Mbed TLS Contributors
35 * SPDX-License-Identifier: Apache-2.0
36 *
37 * Licensed under the Apache License, Version 2.0 (the "License"); you may
38 * not use this file except in compliance with the License.
39 * You may obtain a copy of the License at
40 *
41 * http://www.apache.org/licenses/LICENSE-2.0
42 *
43 * Unless required by applicable law or agreed to in writing, software
44 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
45 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46 * See the License for the specific language governing permissions and
47 * limitations under the License.
48 */
49
50 /* First include Mbed TLS headers to get the Mbed TLS configuration and
51 * platform definitions that we'll use in this program. Also include
52 * standard C headers for functions we'll use here. */
53 #include "mbedtls/build_info.h"
54
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <string.h>
58
59 #include "mbedtls/platform_util.h" // for mbedtls_platform_zeroize
60
61 #include <psa/crypto.h>
62
63 /* If the build options we need are not enabled, compile a placeholder. */
64 #if !defined(MBEDTLS_SHA256_C) || !defined(MBEDTLS_MD_C) || \
65 !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_CCM_C) || \
66 !defined(MBEDTLS_PSA_CRYPTO_C) || !defined(MBEDTLS_FS_IO) || \
67 defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
main(void)68 int main( void )
69 {
70 printf( "MBEDTLS_SHA256_C and/or MBEDTLS_MD_C and/or "
71 "MBEDTLS_AES_C and/or MBEDTLS_CCM_C and/or "
72 "MBEDTLS_PSA_CRYPTO_C and/or MBEDTLS_FS_IO "
73 "not defined and/or MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER "
74 "defined.\n" );
75 return( 0 );
76 }
77 #else
78
79 /* The real program starts here. */
80
81 /* Run a system function and bail out if it fails. */
82 #define SYS_CHECK( expr ) \
83 do \
84 { \
85 if( ! ( expr ) ) \
86 { \
87 perror( #expr ); \
88 status = DEMO_ERROR; \
89 goto exit; \
90 } \
91 } \
92 while( 0 )
93
94 /* Run a PSA function and bail out if it fails. */
95 #define PSA_CHECK( expr ) \
96 do \
97 { \
98 status = ( expr ); \
99 if( status != PSA_SUCCESS ) \
100 { \
101 printf( "Error %d at line %d: %s\n", \
102 (int) status, \
103 __LINE__, \
104 #expr ); \
105 goto exit; \
106 } \
107 } \
108 while( 0 )
109
110 /* To report operational errors in this program, use an error code that is
111 * different from every PSA error code. */
112 #define DEMO_ERROR 120
113
114 /* The maximum supported key ladder depth. */
115 #define MAX_LADDER_DEPTH 10
116
117 /* Salt to use when deriving an intermediate key. */
118 #define DERIVE_KEY_SALT ( (uint8_t *) "key_ladder_demo.derive" )
119 #define DERIVE_KEY_SALT_LENGTH ( strlen( (const char*) DERIVE_KEY_SALT ) )
120
121 /* Salt to use when deriving a wrapping key. */
122 #define WRAPPING_KEY_SALT ( (uint8_t *) "key_ladder_demo.wrap" )
123 #define WRAPPING_KEY_SALT_LENGTH ( strlen( (const char*) WRAPPING_KEY_SALT ) )
124
125 /* Size of the key derivation keys (applies both to the master key and
126 * to intermediate keys). */
127 #define KEY_SIZE_BYTES 40
128
129 /* Algorithm for key derivation. */
130 #define KDF_ALG PSA_ALG_HKDF( PSA_ALG_SHA_256 )
131
132 /* Type and size of the key used to wrap data. */
133 #define WRAPPING_KEY_TYPE PSA_KEY_TYPE_AES
134 #define WRAPPING_KEY_BITS 128
135
136 /* Cipher mode used to wrap data. */
137 #define WRAPPING_ALG PSA_ALG_CCM
138
139 /* Nonce size used to wrap data. */
140 #define WRAPPING_IV_SIZE 13
141
142 /* Header used in files containing wrapped data. We'll save this header
143 * directly without worrying about data representation issues such as
144 * integer sizes and endianness, because the data is meant to be read
145 * back by the same program on the same machine. */
146 #define WRAPPED_DATA_MAGIC "key_ladder_demo" // including trailing null byte
147 #define WRAPPED_DATA_MAGIC_LENGTH ( sizeof( WRAPPED_DATA_MAGIC ) )
148 typedef struct
149 {
150 char magic[WRAPPED_DATA_MAGIC_LENGTH];
151 size_t ad_size; /* Size of the additional data, which is this header. */
152 size_t payload_size; /* Size of the encrypted data. */
153 /* Store the IV inside the additional data. It's convenient. */
154 uint8_t iv[WRAPPING_IV_SIZE];
155 } wrapped_data_header_t;
156
157 /* The modes that this program can operate in (see usage). */
158 enum program_mode
159 {
160 MODE_GENERATE,
161 MODE_SAVE,
162 MODE_UNWRAP,
163 MODE_WRAP
164 };
165
166 /* Save a key to a file. In the real world, you may want to export a derived
167 * key sometimes, to share it with another party. */
save_key(psa_key_id_t key,const char * output_file_name)168 static psa_status_t save_key( psa_key_id_t key,
169 const char *output_file_name )
170 {
171 psa_status_t status = PSA_SUCCESS;
172 uint8_t key_data[KEY_SIZE_BYTES];
173 size_t key_size;
174 FILE *key_file = NULL;
175
176 PSA_CHECK( psa_export_key( key,
177 key_data, sizeof( key_data ),
178 &key_size ) );
179 SYS_CHECK( ( key_file = fopen( output_file_name, "wb" ) ) != NULL );
180 SYS_CHECK( fwrite( key_data, 1, key_size, key_file ) == key_size );
181 SYS_CHECK( fclose( key_file ) == 0 );
182 key_file = NULL;
183
184 exit:
185 if( key_file != NULL)
186 fclose( key_file );
187 return( status );
188 }
189
190 /* Generate a master key for use in this demo.
191 *
192 * Normally a master key would be non-exportable. For the purpose of this
193 * demo, we want to save it to a file, to avoid relying on the keystore
194 * capability of the PSA crypto library. */
generate(const char * key_file_name)195 static psa_status_t generate( const char *key_file_name )
196 {
197 psa_status_t status = PSA_SUCCESS;
198 psa_key_id_t key = 0;
199 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
200
201 psa_set_key_usage_flags( &attributes,
202 PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT );
203 psa_set_key_algorithm( &attributes, KDF_ALG );
204 psa_set_key_type( &attributes, PSA_KEY_TYPE_DERIVE );
205 psa_set_key_bits( &attributes, PSA_BYTES_TO_BITS( KEY_SIZE_BYTES ) );
206
207 PSA_CHECK( psa_generate_key( &attributes, &key ) );
208
209 PSA_CHECK( save_key( key, key_file_name ) );
210
211 exit:
212 (void) psa_destroy_key( key );
213 return( status );
214 }
215
216 /* Load the master key from a file.
217 *
218 * In the real world, this master key would be stored in an internal memory
219 * and the storage would be managed by the keystore capability of the PSA
220 * crypto library. */
import_key_from_file(psa_key_usage_t usage,psa_algorithm_t alg,const char * key_file_name,psa_key_id_t * master_key)221 static psa_status_t import_key_from_file( psa_key_usage_t usage,
222 psa_algorithm_t alg,
223 const char *key_file_name,
224 psa_key_id_t *master_key )
225 {
226 psa_status_t status = PSA_SUCCESS;
227 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
228 uint8_t key_data[KEY_SIZE_BYTES];
229 size_t key_size;
230 FILE *key_file = NULL;
231 unsigned char extra_byte;
232
233 SYS_CHECK( ( key_file = fopen( key_file_name, "rb" ) ) != NULL );
234 SYS_CHECK( ( key_size = fread( key_data, 1, sizeof( key_data ),
235 key_file ) ) != 0 );
236 if( fread( &extra_byte, 1, 1, key_file ) != 0 )
237 {
238 printf( "Key file too large (max: %u).\n",
239 (unsigned) sizeof( key_data ) );
240 status = DEMO_ERROR;
241 goto exit;
242 }
243 SYS_CHECK( fclose( key_file ) == 0 );
244 key_file = NULL;
245
246 psa_set_key_usage_flags( &attributes, usage );
247 psa_set_key_algorithm( &attributes, alg );
248 psa_set_key_type( &attributes, PSA_KEY_TYPE_DERIVE );
249 PSA_CHECK( psa_import_key( &attributes, key_data, key_size, master_key ) );
250 exit:
251 if( key_file != NULL )
252 fclose( key_file );
253 mbedtls_platform_zeroize( key_data, sizeof( key_data ) );
254 if( status != PSA_SUCCESS )
255 {
256 /* If the key creation hasn't happened yet or has failed,
257 * *master_key is null. psa_destroy_key( 0 ) is
258 * guaranteed to do nothing and return PSA_SUCCESS. */
259 (void) psa_destroy_key( *master_key );
260 *master_key = 0;
261 }
262 return( status );
263 }
264
265 /* Derive the intermediate keys, using the list of labels provided on
266 * the command line. On input, *key is the master key identifier.
267 * This function destroys the master key. On successful output, *key
268 * is the identifier of the final derived key.
269 */
derive_key_ladder(const char * ladder[],size_t ladder_depth,psa_key_id_t * key)270 static psa_status_t derive_key_ladder( const char *ladder[],
271 size_t ladder_depth,
272 psa_key_id_t *key )
273 {
274 psa_status_t status = PSA_SUCCESS;
275 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
276 psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
277 size_t i;
278
279 psa_set_key_usage_flags( &attributes,
280 PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT );
281 psa_set_key_algorithm( &attributes, KDF_ALG );
282 psa_set_key_type( &attributes, PSA_KEY_TYPE_DERIVE );
283 psa_set_key_bits( &attributes, PSA_BYTES_TO_BITS( KEY_SIZE_BYTES ) );
284
285 /* For each label in turn, ... */
286 for( i = 0; i < ladder_depth; i++ )
287 {
288 /* Start deriving material from the master key (if i=0) or from
289 * the current intermediate key (if i>0). */
290 PSA_CHECK( psa_key_derivation_setup( &operation, KDF_ALG ) );
291 PSA_CHECK( psa_key_derivation_input_bytes(
292 &operation, PSA_KEY_DERIVATION_INPUT_SALT,
293 DERIVE_KEY_SALT, DERIVE_KEY_SALT_LENGTH ) );
294 PSA_CHECK( psa_key_derivation_input_key(
295 &operation, PSA_KEY_DERIVATION_INPUT_SECRET,
296 *key ) );
297 PSA_CHECK( psa_key_derivation_input_bytes(
298 &operation, PSA_KEY_DERIVATION_INPUT_INFO,
299 (uint8_t*) ladder[i], strlen( ladder[i] ) ) );
300 /* When the parent key is not the master key, destroy it,
301 * since it is no longer needed. */
302 PSA_CHECK( psa_destroy_key( *key ) );
303 *key = 0;
304 /* Derive the next intermediate key from the parent key. */
305 PSA_CHECK( psa_key_derivation_output_key( &attributes, &operation,
306 key ) );
307 PSA_CHECK( psa_key_derivation_abort( &operation ) );
308 }
309
310 exit:
311 psa_key_derivation_abort( &operation );
312 if( status != PSA_SUCCESS )
313 {
314 psa_destroy_key( *key );
315 *key = 0;
316 }
317 return( status );
318 }
319
320 /* Derive a wrapping key from the last intermediate key. */
derive_wrapping_key(psa_key_usage_t usage,psa_key_id_t derived_key,psa_key_id_t * wrapping_key)321 static psa_status_t derive_wrapping_key( psa_key_usage_t usage,
322 psa_key_id_t derived_key,
323 psa_key_id_t *wrapping_key )
324 {
325 psa_status_t status = PSA_SUCCESS;
326 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
327 psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
328
329 *wrapping_key = 0;
330
331 /* Set up a key derivation operation from the key derived from
332 * the master key. */
333 PSA_CHECK( psa_key_derivation_setup( &operation, KDF_ALG ) );
334 PSA_CHECK( psa_key_derivation_input_bytes(
335 &operation, PSA_KEY_DERIVATION_INPUT_SALT,
336 WRAPPING_KEY_SALT, WRAPPING_KEY_SALT_LENGTH ) );
337 PSA_CHECK( psa_key_derivation_input_key(
338 &operation, PSA_KEY_DERIVATION_INPUT_SECRET,
339 derived_key ) );
340 PSA_CHECK( psa_key_derivation_input_bytes(
341 &operation, PSA_KEY_DERIVATION_INPUT_INFO,
342 NULL, 0 ) );
343
344 /* Create the wrapping key. */
345 psa_set_key_usage_flags( &attributes, usage );
346 psa_set_key_algorithm( &attributes, WRAPPING_ALG );
347 psa_set_key_type( &attributes, PSA_KEY_TYPE_AES );
348 psa_set_key_bits( &attributes, WRAPPING_KEY_BITS );
349 PSA_CHECK( psa_key_derivation_output_key( &attributes, &operation,
350 wrapping_key ) );
351
352 exit:
353 psa_key_derivation_abort( &operation );
354 return( status );
355 }
356
wrap_data(const char * input_file_name,const char * output_file_name,psa_key_id_t wrapping_key)357 static psa_status_t wrap_data( const char *input_file_name,
358 const char *output_file_name,
359 psa_key_id_t wrapping_key )
360 {
361 psa_status_t status;
362 FILE *input_file = NULL;
363 FILE *output_file = NULL;
364 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
365 psa_key_type_t key_type;
366 long input_position;
367 size_t input_size;
368 size_t buffer_size = 0;
369 unsigned char *buffer = NULL;
370 size_t ciphertext_size;
371 wrapped_data_header_t header;
372
373 /* Find the size of the data to wrap. */
374 SYS_CHECK( ( input_file = fopen( input_file_name, "rb" ) ) != NULL );
375 SYS_CHECK( fseek( input_file, 0, SEEK_END ) == 0 );
376 SYS_CHECK( ( input_position = ftell( input_file ) ) != -1 );
377 #if LONG_MAX > SIZE_MAX
378 if( input_position > SIZE_MAX )
379 {
380 printf( "Input file too large.\n" );
381 status = DEMO_ERROR;
382 goto exit;
383 }
384 #endif
385 input_size = input_position;
386 PSA_CHECK( psa_get_key_attributes( wrapping_key, &attributes ) );
387 key_type = psa_get_key_type( &attributes );
388 buffer_size =
389 PSA_AEAD_ENCRYPT_OUTPUT_SIZE( key_type, WRAPPING_ALG, input_size );
390 /* Check for integer overflow. */
391 if( buffer_size < input_size )
392 {
393 printf( "Input file too large.\n" );
394 status = DEMO_ERROR;
395 goto exit;
396 }
397
398 /* Load the data to wrap. */
399 SYS_CHECK( fseek( input_file, 0, SEEK_SET ) == 0 );
400 SYS_CHECK( ( buffer = calloc( 1, buffer_size ) ) != NULL );
401 SYS_CHECK( fread( buffer, 1, input_size, input_file ) == input_size );
402 SYS_CHECK( fclose( input_file ) == 0 );
403 input_file = NULL;
404
405 /* Construct a header. */
406 memcpy( &header.magic, WRAPPED_DATA_MAGIC, WRAPPED_DATA_MAGIC_LENGTH );
407 header.ad_size = sizeof( header );
408 header.payload_size = input_size;
409
410 /* Wrap the data. */
411 PSA_CHECK( psa_generate_random( header.iv, WRAPPING_IV_SIZE ) );
412 PSA_CHECK( psa_aead_encrypt( wrapping_key, WRAPPING_ALG,
413 header.iv, WRAPPING_IV_SIZE,
414 (uint8_t *) &header, sizeof( header ),
415 buffer, input_size,
416 buffer, buffer_size,
417 &ciphertext_size ) );
418
419 /* Write the output. */
420 SYS_CHECK( ( output_file = fopen( output_file_name, "wb" ) ) != NULL );
421 SYS_CHECK( fwrite( &header, 1, sizeof( header ),
422 output_file ) == sizeof( header ) );
423 SYS_CHECK( fwrite( buffer, 1, ciphertext_size,
424 output_file ) == ciphertext_size );
425 SYS_CHECK( fclose( output_file ) == 0 );
426 output_file = NULL;
427
428 exit:
429 if( input_file != NULL )
430 fclose( input_file );
431 if( output_file != NULL )
432 fclose( output_file );
433 if( buffer != NULL )
434 mbedtls_platform_zeroize( buffer, buffer_size );
435 free( buffer );
436 return( status );
437 }
438
unwrap_data(const char * input_file_name,const char * output_file_name,psa_key_id_t wrapping_key)439 static psa_status_t unwrap_data( const char *input_file_name,
440 const char *output_file_name,
441 psa_key_id_t wrapping_key )
442 {
443 psa_status_t status;
444 FILE *input_file = NULL;
445 FILE *output_file = NULL;
446 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
447 psa_key_type_t key_type;
448 unsigned char *buffer = NULL;
449 size_t ciphertext_size = 0;
450 size_t plaintext_size;
451 wrapped_data_header_t header;
452 unsigned char extra_byte;
453
454 /* Load and validate the header. */
455 SYS_CHECK( ( input_file = fopen( input_file_name, "rb" ) ) != NULL );
456 SYS_CHECK( fread( &header, 1, sizeof( header ),
457 input_file ) == sizeof( header ) );
458 if( memcmp( &header.magic, WRAPPED_DATA_MAGIC,
459 WRAPPED_DATA_MAGIC_LENGTH ) != 0 )
460 {
461 printf( "The input does not start with a valid magic header.\n" );
462 status = DEMO_ERROR;
463 goto exit;
464 }
465 if( header.ad_size != sizeof( header ) )
466 {
467 printf( "The header size is not correct.\n" );
468 status = DEMO_ERROR;
469 goto exit;
470 }
471 PSA_CHECK( psa_get_key_attributes( wrapping_key, &attributes) );
472 key_type = psa_get_key_type( &attributes);
473 ciphertext_size =
474 PSA_AEAD_ENCRYPT_OUTPUT_SIZE( key_type, WRAPPING_ALG, header.payload_size );
475 /* Check for integer overflow. */
476 if( ciphertext_size < header.payload_size )
477 {
478 printf( "Input file too large.\n" );
479 status = DEMO_ERROR;
480 goto exit;
481 }
482
483 /* Load the payload data. */
484 SYS_CHECK( ( buffer = calloc( 1, ciphertext_size ) ) != NULL );
485 SYS_CHECK( fread( buffer, 1, ciphertext_size,
486 input_file ) == ciphertext_size );
487 if( fread( &extra_byte, 1, 1, input_file ) != 0 )
488 {
489 printf( "Extra garbage after ciphertext\n" );
490 status = DEMO_ERROR;
491 goto exit;
492 }
493 SYS_CHECK( fclose( input_file ) == 0 );
494 input_file = NULL;
495
496 /* Unwrap the data. */
497 PSA_CHECK( psa_aead_decrypt( wrapping_key, WRAPPING_ALG,
498 header.iv, WRAPPING_IV_SIZE,
499 (uint8_t *) &header, sizeof( header ),
500 buffer, ciphertext_size,
501 buffer, ciphertext_size,
502 &plaintext_size ) );
503 if( plaintext_size != header.payload_size )
504 {
505 printf( "Incorrect payload size in the header.\n" );
506 status = DEMO_ERROR;
507 goto exit;
508 }
509
510 /* Write the output. */
511 SYS_CHECK( ( output_file = fopen( output_file_name, "wb" ) ) != NULL );
512 SYS_CHECK( fwrite( buffer, 1, plaintext_size,
513 output_file ) == plaintext_size );
514 SYS_CHECK( fclose( output_file ) == 0 );
515 output_file = NULL;
516
517 exit:
518 if( input_file != NULL )
519 fclose( input_file );
520 if( output_file != NULL )
521 fclose( output_file );
522 if( buffer != NULL )
523 mbedtls_platform_zeroize( buffer, ciphertext_size );
524 free( buffer );
525 return( status );
526 }
527
run(enum program_mode mode,const char * key_file_name,const char * ladder[],size_t ladder_depth,const char * input_file_name,const char * output_file_name)528 static psa_status_t run( enum program_mode mode,
529 const char *key_file_name,
530 const char *ladder[], size_t ladder_depth,
531 const char *input_file_name,
532 const char *output_file_name )
533 {
534 psa_status_t status = PSA_SUCCESS;
535 psa_key_id_t derivation_key = 0;
536 psa_key_id_t wrapping_key = 0;
537
538 /* Initialize the PSA crypto library. */
539 PSA_CHECK( psa_crypto_init( ) );
540
541 /* Generate mode is unlike the others. Generate the master key and exit. */
542 if( mode == MODE_GENERATE )
543 return( generate( key_file_name ) );
544
545 /* Read the master key. */
546 PSA_CHECK( import_key_from_file( PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT,
547 KDF_ALG,
548 key_file_name,
549 &derivation_key ) );
550
551 /* Calculate the derived key for this session. */
552 PSA_CHECK( derive_key_ladder( ladder, ladder_depth,
553 &derivation_key ) );
554
555 switch( mode )
556 {
557 case MODE_SAVE:
558 PSA_CHECK( save_key( derivation_key, output_file_name ) );
559 break;
560 case MODE_UNWRAP:
561 PSA_CHECK( derive_wrapping_key( PSA_KEY_USAGE_DECRYPT,
562 derivation_key,
563 &wrapping_key ) );
564 PSA_CHECK( unwrap_data( input_file_name, output_file_name,
565 wrapping_key ) );
566 break;
567 case MODE_WRAP:
568 PSA_CHECK( derive_wrapping_key( PSA_KEY_USAGE_ENCRYPT,
569 derivation_key,
570 &wrapping_key ) );
571 PSA_CHECK( wrap_data( input_file_name, output_file_name,
572 wrapping_key ) );
573 break;
574 default:
575 /* Unreachable but some compilers don't realize it. */
576 break;
577 }
578
579 exit:
580 /* Destroy any remaining key. Deinitializing the crypto library would do
581 * this anyway since they are volatile keys, but explicitly destroying
582 * keys makes the code easier to reuse. */
583 (void) psa_destroy_key( derivation_key );
584 (void) psa_destroy_key( wrapping_key );
585 /* Deinitialize the PSA crypto library. */
586 mbedtls_psa_crypto_free( );
587 return( status );
588 }
589
usage(void)590 static void usage( void )
591 {
592 printf( "Usage: key_ladder_demo MODE [OPTION=VALUE]...\n" );
593 printf( "Demonstrate the usage of a key derivation ladder.\n" );
594 printf( "\n" );
595 printf( "Modes:\n" );
596 printf( " generate Generate the master key\n" );
597 printf( " save Save the derived key\n" );
598 printf( " unwrap Unwrap (decrypt) input with the derived key\n" );
599 printf( " wrap Wrap (encrypt) input with the derived key\n" );
600 printf( "\n" );
601 printf( "Options:\n" );
602 printf( " input=FILENAME Input file (required for wrap/unwrap)\n" );
603 printf( " master=FILENAME File containing the master key (default: master.key)\n" );
604 printf( " output=FILENAME Output file (required for save/wrap/unwrap)\n" );
605 printf( " label=TEXT Label for the key derivation.\n" );
606 printf( " This may be repeated multiple times.\n" );
607 printf( " To get the same key, you must use the same master key\n" );
608 printf( " and the same sequence of labels.\n" );
609 }
610
main(int argc,char * argv[])611 int main( int argc, char *argv[] )
612 {
613 const char *key_file_name = "master.key";
614 const char *input_file_name = NULL;
615 const char *output_file_name = NULL;
616 const char *ladder[MAX_LADDER_DEPTH];
617 size_t ladder_depth = 0;
618 int i;
619 enum program_mode mode;
620 psa_status_t status;
621
622 if( argc <= 1 ||
623 strcmp( argv[1], "help" ) == 0 ||
624 strcmp( argv[1], "-help" ) == 0 ||
625 strcmp( argv[1], "--help" ) == 0 )
626 {
627 usage( );
628 return( EXIT_SUCCESS );
629 }
630
631 for( i = 2; i < argc; i++ )
632 {
633 char *q = strchr( argv[i], '=' );
634 if( q == NULL )
635 {
636 printf( "Missing argument to option %s\n", argv[i] );
637 goto usage_failure;
638 }
639 *q = 0;
640 ++q;
641 if( strcmp( argv[i], "input" ) == 0 )
642 input_file_name = q;
643 else if( strcmp( argv[i], "label" ) == 0 )
644 {
645 if( ladder_depth == MAX_LADDER_DEPTH )
646 {
647 printf( "Maximum ladder depth %u exceeded.\n",
648 (unsigned) MAX_LADDER_DEPTH );
649 return( EXIT_FAILURE );
650 }
651 ladder[ladder_depth] = q;
652 ++ladder_depth;
653 }
654 else if( strcmp( argv[i], "master" ) == 0 )
655 key_file_name = q;
656 else if( strcmp( argv[i], "output" ) == 0 )
657 output_file_name = q;
658 else
659 {
660 printf( "Unknown option: %s\n", argv[i] );
661 goto usage_failure;
662 }
663 }
664
665 if( strcmp( argv[1], "generate" ) == 0 )
666 mode = MODE_GENERATE;
667 else if( strcmp( argv[1], "save" ) == 0 )
668 mode = MODE_SAVE;
669 else if( strcmp( argv[1], "unwrap" ) == 0 )
670 mode = MODE_UNWRAP;
671 else if( strcmp( argv[1], "wrap" ) == 0 )
672 mode = MODE_WRAP;
673 else
674 {
675 printf( "Unknown action: %s\n", argv[1] );
676 goto usage_failure;
677 }
678
679 if( input_file_name == NULL &&
680 ( mode == MODE_WRAP || mode == MODE_UNWRAP ) )
681 {
682 printf( "Required argument missing: input\n" );
683 return( DEMO_ERROR );
684 }
685 if( output_file_name == NULL &&
686 ( mode == MODE_SAVE || mode == MODE_WRAP || mode == MODE_UNWRAP ) )
687 {
688 printf( "Required argument missing: output\n" );
689 return( DEMO_ERROR );
690 }
691
692 status = run( mode, key_file_name,
693 ladder, ladder_depth,
694 input_file_name, output_file_name );
695 return( status == PSA_SUCCESS ?
696 EXIT_SUCCESS :
697 EXIT_FAILURE );
698
699 usage_failure:
700 usage( );
701 return( EXIT_FAILURE );
702 }
703 #endif /* MBEDTLS_SHA256_C && MBEDTLS_MD_C && MBEDTLS_AES_C && MBEDTLS_CCM_C && MBEDTLS_PSA_CRYPTO_C && MBEDTLS_FS_IO */
704