1 /*
2 * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <ctype.h>
9 #include <getopt.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <stdbool.h>
14
15 #include <openssl/conf.h>
16 #include <openssl/engine.h>
17 #include <openssl/err.h>
18 #include <openssl/pem.h>
19 #include <openssl/sha.h>
20 #include <openssl/x509v3.h>
21
22 #include "cert.h"
23 #include "cmd_opt.h"
24 #include "debug.h"
25 #include "ext.h"
26 #include "key.h"
27 #include "sha.h"
28
29 /*
30 * Helper macros to simplify the code. This macro assigns the return value of
31 * the 'fn' function to 'v' and exits if the value is NULL.
32 */
33 #define CHECK_NULL(v, fn) \
34 do { \
35 v = fn; \
36 if (v == NULL) { \
37 ERROR("NULL object at %s:%d\n", __FILE__, __LINE__); \
38 exit(1); \
39 } \
40 } while (0)
41
42 /*
43 * This macro assigns the NID corresponding to 'oid' to 'v' and exits if the
44 * NID is undefined.
45 */
46 #define CHECK_OID(v, oid) \
47 do { \
48 v = OBJ_txt2nid(oid); \
49 if (v == NID_undef) { \
50 ERROR("Cannot find extension %s\n", oid); \
51 exit(1); \
52 } \
53 } while (0)
54
55 #define MAX_FILENAME_LEN 1024
56 #define VAL_DAYS 7300
57 #define ID_TO_BIT_MASK(id) (1 << id)
58 #define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0])))
59 #define HELP_OPT_MAX_LEN 128
60
61 /* Global options */
62 static int key_alg;
63 static int hash_alg;
64 static int key_size;
65 static int new_keys;
66 static int save_keys;
67 static int print_cert;
68
69 /* Info messages created in the Makefile */
70 extern const char build_msg[];
71 extern const char platform_msg[];
72
73
strdup(const char * str)74 static char *strdup(const char *str)
75 {
76 int n = strlen(str) + 1;
77 char *dup = malloc(n);
78 if (dup) {
79 strcpy(dup, str);
80 }
81 return dup;
82 }
83
84 static const char *key_algs_str[] = {
85 [KEY_ALG_RSA] = "rsa",
86 #ifndef OPENSSL_NO_EC
87 [KEY_ALG_ECDSA] = "ecdsa"
88 #endif /* OPENSSL_NO_EC */
89 };
90
91 static const char *hash_algs_str[] = {
92 [HASH_ALG_SHA256] = "sha256",
93 [HASH_ALG_SHA384] = "sha384",
94 [HASH_ALG_SHA512] = "sha512",
95 };
96
print_help(const char * cmd,const struct option * long_opt)97 static void print_help(const char *cmd, const struct option *long_opt)
98 {
99 int rem, i = 0;
100 const struct option *opt;
101 char line[HELP_OPT_MAX_LEN];
102 char *p;
103
104 assert(cmd != NULL);
105 assert(long_opt != NULL);
106
107 printf("\n\n");
108 printf("The certificate generation tool loads the binary images and\n"
109 "optionally the RSA keys, and outputs the key and content\n"
110 "certificates properly signed to implement the chain of trust.\n"
111 "If keys are provided, they must be in PEM format.\n"
112 "Certificates are generated in DER format.\n");
113 printf("\n");
114 printf("Usage:\n");
115 printf("\t%s [OPTIONS]\n\n", cmd);
116
117 printf("Available options:\n");
118 opt = long_opt;
119 while (opt->name) {
120 p = line;
121 rem = HELP_OPT_MAX_LEN;
122 if (isalpha(opt->val)) {
123 /* Short format */
124 sprintf(p, "-%c,", (char)opt->val);
125 p += 3;
126 rem -= 3;
127 }
128 snprintf(p, rem, "--%s %s", opt->name,
129 (opt->has_arg == required_argument) ? "<arg>" : "");
130 printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i));
131 opt++;
132 i++;
133 }
134 printf("\n");
135 }
136
get_key_alg(const char * key_alg_str)137 static int get_key_alg(const char *key_alg_str)
138 {
139 int i;
140
141 for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
142 if (0 == strcmp(key_alg_str, key_algs_str[i])) {
143 return i;
144 }
145 }
146
147 return -1;
148 }
149
get_key_size(const char * key_size_str)150 static int get_key_size(const char *key_size_str)
151 {
152 char *end;
153 long key_size;
154
155 key_size = strtol(key_size_str, &end, 10);
156 if (*end != '\0')
157 return -1;
158
159 return key_size;
160 }
161
get_hash_alg(const char * hash_alg_str)162 static int get_hash_alg(const char *hash_alg_str)
163 {
164 int i;
165
166 for (i = 0 ; i < NUM_ELEM(hash_algs_str) ; i++) {
167 if (0 == strcmp(hash_alg_str, hash_algs_str[i])) {
168 return i;
169 }
170 }
171
172 return -1;
173 }
174
check_cmd_params(void)175 static void check_cmd_params(void)
176 {
177 cert_t *cert;
178 ext_t *ext;
179 key_t *key;
180 int i, j;
181 bool valid_size;
182
183 /* Only save new keys */
184 if (save_keys && !new_keys) {
185 ERROR("Only new keys can be saved to disk\n");
186 exit(1);
187 }
188
189 /* Validate key-size */
190 valid_size = false;
191 for (i = 0; i < KEY_SIZE_MAX_NUM; i++) {
192 if (key_size == KEY_SIZES[key_alg][i]) {
193 valid_size = true;
194 break;
195 }
196 }
197 if (!valid_size) {
198 ERROR("'%d' is not a valid key size for '%s'\n",
199 key_size, key_algs_str[key_alg]);
200 NOTICE("Valid sizes are: ");
201 for (i = 0; i < KEY_SIZE_MAX_NUM &&
202 KEY_SIZES[key_alg][i] != 0; i++) {
203 printf("%d ", KEY_SIZES[key_alg][i]);
204 }
205 printf("\n");
206 exit(1);
207 }
208
209 /* Check that all required options have been specified in the
210 * command line */
211 for (i = 0; i < num_certs; i++) {
212 cert = &certs[i];
213 if (cert->fn == NULL) {
214 /* Certificate not requested. Skip to the next one */
215 continue;
216 }
217
218 /* Check that all parameters required to create this certificate
219 * have been specified in the command line */
220 for (j = 0; j < cert->num_ext; j++) {
221 ext = &extensions[cert->ext[j]];
222 switch (ext->type) {
223 case EXT_TYPE_NVCOUNTER:
224 /* Counter value must be specified */
225 if ((!ext->optional) && (ext->arg == NULL)) {
226 ERROR("Value for '%s' not specified\n",
227 ext->ln);
228 exit(1);
229 }
230 break;
231 case EXT_TYPE_PKEY:
232 /* Key filename must be specified */
233 key = &keys[ext->attr.key];
234 if (!new_keys && key->fn == NULL) {
235 ERROR("Key '%s' required by '%s' not "
236 "specified\n", key->desc,
237 cert->cn);
238 exit(1);
239 }
240 break;
241 case EXT_TYPE_HASH:
242 /*
243 * Binary image must be specified
244 * unless it is explicitly made optional.
245 */
246 if ((!ext->optional) && (ext->arg == NULL)) {
247 ERROR("Image for '%s' not specified\n",
248 ext->ln);
249 exit(1);
250 }
251 break;
252 default:
253 ERROR("Unknown extension type '%d' in '%s'\n",
254 ext->type, ext->ln);
255 exit(1);
256 break;
257 }
258 }
259 }
260 }
261
262 /* Common command line options */
263 static const cmd_opt_t common_cmd_opt[] = {
264 {
265 { "help", no_argument, NULL, 'h' },
266 "Print this message and exit"
267 },
268 {
269 { "key-alg", required_argument, NULL, 'a' },
270 "Key algorithm: 'rsa' (default)- RSAPSS scheme as per PKCS#1 v2.1, 'ecdsa'"
271 },
272 {
273 { "key-size", required_argument, NULL, 'b' },
274 "Key size (for supported algorithms)."
275 },
276 {
277 { "hash-alg", required_argument, NULL, 's' },
278 "Hash algorithm : 'sha256' (default), 'sha384', 'sha512'"
279 },
280 {
281 { "save-keys", no_argument, NULL, 'k' },
282 "Save key pairs into files. Filenames must be provided"
283 },
284 {
285 { "new-keys", no_argument, NULL, 'n' },
286 "Generate new key pairs if no key files are provided"
287 },
288 {
289 { "print-cert", no_argument, NULL, 'p' },
290 "Print the certificates in the standard output"
291 }
292 };
293
main(int argc,char * argv[])294 int main(int argc, char *argv[])
295 {
296 STACK_OF(X509_EXTENSION) * sk;
297 X509_EXTENSION *cert_ext = NULL;
298 ext_t *ext;
299 key_t *key;
300 cert_t *cert;
301 FILE *file;
302 int i, j, ext_nid, nvctr;
303 int c, opt_idx = 0;
304 const struct option *cmd_opt;
305 const char *cur_opt;
306 unsigned int err_code;
307 unsigned char md[SHA512_DIGEST_LENGTH];
308 unsigned int md_len;
309 const EVP_MD *md_info;
310
311 NOTICE("CoT Generation Tool: %s\n", build_msg);
312 NOTICE("Target platform: %s\n", platform_msg);
313
314 /* Set default options */
315 key_alg = KEY_ALG_RSA;
316 hash_alg = HASH_ALG_SHA256;
317 key_size = -1;
318
319 /* Add common command line options */
320 for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
321 cmd_opt_add(&common_cmd_opt[i]);
322 }
323
324 /* Initialize the certificates */
325 if (cert_init() != 0) {
326 ERROR("Cannot initialize certificates\n");
327 exit(1);
328 }
329
330 /* Initialize the keys */
331 if (key_init() != 0) {
332 ERROR("Cannot initialize keys\n");
333 exit(1);
334 }
335
336 /* Initialize the new types and register OIDs for the extensions */
337 if (ext_init() != 0) {
338 ERROR("Cannot initialize extensions\n");
339 exit(1);
340 }
341
342 /* Get the command line options populated during the initialization */
343 cmd_opt = cmd_opt_get_array();
344
345 while (1) {
346 /* getopt_long stores the option index here. */
347 c = getopt_long(argc, argv, "a:b:hknps:", cmd_opt, &opt_idx);
348
349 /* Detect the end of the options. */
350 if (c == -1) {
351 break;
352 }
353
354 switch (c) {
355 case 'a':
356 key_alg = get_key_alg(optarg);
357 if (key_alg < 0) {
358 ERROR("Invalid key algorithm '%s'\n", optarg);
359 exit(1);
360 }
361 break;
362 case 'b':
363 key_size = get_key_size(optarg);
364 if (key_size <= 0) {
365 ERROR("Invalid key size '%s'\n", optarg);
366 exit(1);
367 }
368 break;
369 case 'h':
370 print_help(argv[0], cmd_opt);
371 exit(0);
372 case 'k':
373 save_keys = 1;
374 break;
375 case 'n':
376 new_keys = 1;
377 break;
378 case 'p':
379 print_cert = 1;
380 break;
381 case 's':
382 hash_alg = get_hash_alg(optarg);
383 if (hash_alg < 0) {
384 ERROR("Invalid hash algorithm '%s'\n", optarg);
385 exit(1);
386 }
387 break;
388 case CMD_OPT_EXT:
389 cur_opt = cmd_opt_get_name(opt_idx);
390 ext = ext_get_by_opt(cur_opt);
391 ext->arg = strdup(optarg);
392 break;
393 case CMD_OPT_KEY:
394 cur_opt = cmd_opt_get_name(opt_idx);
395 key = key_get_by_opt(cur_opt);
396 key->fn = strdup(optarg);
397 break;
398 case CMD_OPT_CERT:
399 cur_opt = cmd_opt_get_name(opt_idx);
400 cert = cert_get_by_opt(cur_opt);
401 cert->fn = strdup(optarg);
402 break;
403 case '?':
404 default:
405 print_help(argv[0], cmd_opt);
406 exit(1);
407 }
408 }
409
410 /* Select a reasonable default key-size */
411 if (key_size == -1) {
412 key_size = KEY_SIZES[key_alg][0];
413 }
414
415 /* Check command line arguments */
416 check_cmd_params();
417
418 /* Indicate SHA as image hash algorithm in the certificate
419 * extension */
420 if (hash_alg == HASH_ALG_SHA384) {
421 md_info = EVP_sha384();
422 md_len = SHA384_DIGEST_LENGTH;
423 } else if (hash_alg == HASH_ALG_SHA512) {
424 md_info = EVP_sha512();
425 md_len = SHA512_DIGEST_LENGTH;
426 } else {
427 md_info = EVP_sha256();
428 md_len = SHA256_DIGEST_LENGTH;
429 }
430
431 /* Load private keys from files (or generate new ones) */
432 for (i = 0 ; i < num_keys ; i++) {
433 if (!key_new(&keys[i])) {
434 ERROR("Failed to allocate key container\n");
435 exit(1);
436 }
437
438 /* First try to load the key from disk */
439 if (key_load(&keys[i], &err_code)) {
440 /* Key loaded successfully */
441 continue;
442 }
443
444 /* Key not loaded. Check the error code */
445 if (err_code == KEY_ERR_LOAD) {
446 /* File exists, but it does not contain a valid private
447 * key. Abort. */
448 ERROR("Error loading '%s'\n", keys[i].fn);
449 exit(1);
450 }
451
452 /* File does not exist, could not be opened or no filename was
453 * given */
454 if (new_keys) {
455 /* Try to create a new key */
456 NOTICE("Creating new key for '%s'\n", keys[i].desc);
457 if (!key_create(&keys[i], key_alg, key_size)) {
458 ERROR("Error creating key '%s'\n", keys[i].desc);
459 exit(1);
460 }
461 } else {
462 if (err_code == KEY_ERR_OPEN) {
463 ERROR("Error opening '%s'\n", keys[i].fn);
464 } else {
465 ERROR("Key '%s' not specified\n", keys[i].desc);
466 }
467 exit(1);
468 }
469 }
470
471 /* Create the certificates */
472 for (i = 0 ; i < num_certs ; i++) {
473
474 cert = &certs[i];
475
476 if (cert->fn == NULL) {
477 /* Certificate not requested. Skip to the next one */
478 continue;
479 }
480
481 /* Create a new stack of extensions. This stack will be used
482 * to create the certificate */
483 CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
484
485 for (j = 0 ; j < cert->num_ext ; j++) {
486
487 ext = &extensions[cert->ext[j]];
488
489 /* Get OpenSSL internal ID for this extension */
490 CHECK_OID(ext_nid, ext->oid);
491
492 /*
493 * Three types of extensions are currently supported:
494 * - EXT_TYPE_NVCOUNTER
495 * - EXT_TYPE_HASH
496 * - EXT_TYPE_PKEY
497 */
498 switch (ext->type) {
499 case EXT_TYPE_NVCOUNTER:
500 if (ext->optional && ext->arg == NULL) {
501 /* Skip this NVCounter */
502 continue;
503 } else {
504 /* Checked by `check_cmd_params` */
505 assert(ext->arg != NULL);
506 nvctr = atoi(ext->arg);
507 CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
508 EXT_CRIT, nvctr));
509 }
510 break;
511 case EXT_TYPE_HASH:
512 if (ext->arg == NULL) {
513 if (ext->optional) {
514 /* Include a hash filled with zeros */
515 memset(md, 0x0, SHA512_DIGEST_LENGTH);
516 } else {
517 /* Do not include this hash in the certificate */
518 continue;
519 }
520 } else {
521 /* Calculate the hash of the file */
522 if (!sha_file(hash_alg, ext->arg, md)) {
523 ERROR("Cannot calculate hash of %s\n",
524 ext->arg);
525 exit(1);
526 }
527 }
528 CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
529 EXT_CRIT, md_info, md,
530 md_len));
531 break;
532 case EXT_TYPE_PKEY:
533 CHECK_NULL(cert_ext, ext_new_key(ext_nid,
534 EXT_CRIT, keys[ext->attr.key].key));
535 break;
536 default:
537 ERROR("Unknown extension type '%d' in %s\n",
538 ext->type, cert->cn);
539 exit(1);
540 }
541
542 /* Push the extension into the stack */
543 sk_X509_EXTENSION_push(sk, cert_ext);
544 }
545
546 /* Create certificate. Signed with corresponding key */
547 if (!cert_new(hash_alg, cert, VAL_DAYS, 0, sk)) {
548 ERROR("Cannot create %s\n", cert->cn);
549 exit(1);
550 }
551
552 for (cert_ext = sk_X509_EXTENSION_pop(sk); cert_ext != NULL;
553 cert_ext = sk_X509_EXTENSION_pop(sk)) {
554 X509_EXTENSION_free(cert_ext);
555 }
556
557 sk_X509_EXTENSION_free(sk);
558 }
559
560
561 /* Print the certificates */
562 if (print_cert) {
563 for (i = 0 ; i < num_certs ; i++) {
564 if (!certs[i].x) {
565 continue;
566 }
567 printf("\n\n=====================================\n\n");
568 X509_print_fp(stdout, certs[i].x);
569 }
570 }
571
572 /* Save created certificates to files */
573 for (i = 0 ; i < num_certs ; i++) {
574 if (certs[i].x && certs[i].fn) {
575 file = fopen(certs[i].fn, "w");
576 if (file != NULL) {
577 i2d_X509_fp(file, certs[i].x);
578 fclose(file);
579 } else {
580 ERROR("Cannot create file %s\n", certs[i].fn);
581 }
582 }
583 }
584
585 /* Save keys */
586 if (save_keys) {
587 for (i = 0 ; i < num_keys ; i++) {
588 if (!key_store(&keys[i])) {
589 ERROR("Cannot save %s\n", keys[i].desc);
590 }
591 }
592 }
593
594 /* If we got here, then we must have filled the key array completely.
595 * We can then safely call free on all of the keys in the array
596 */
597 for (i = 0; i < num_keys; i++) {
598 EVP_PKEY_free(keys[i].key);
599 }
600
601 #ifndef OPENSSL_NO_ENGINE
602 ENGINE_cleanup();
603 #endif
604 CRYPTO_cleanup_all_ex_data();
605
606
607 /* We allocated strings through strdup, so now we have to free them */
608 for (i = 0; i < num_keys; i++) {
609 if (keys[i].fn != NULL) {
610 void *ptr = keys[i].fn;
611
612 keys[i].fn = NULL;
613 free(ptr);
614 }
615 }
616 for (i = 0; i < num_extensions; i++) {
617 if (extensions[i].arg != NULL) {
618 void *ptr = (void *)extensions[i].arg;
619
620 extensions[i].arg = NULL;
621 free(ptr);
622 }
623 }
624 for (i = 0; i < num_certs; i++) {
625 if (certs[i].fn != NULL) {
626 void *ptr = (void *)certs[i].fn;
627
628 certs[i].fn = NULL;
629 free(ptr);
630 }
631 }
632
633 return 0;
634 }
635