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