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