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