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