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