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