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