xref: /rk3399_ARM-atf/tools/cert_create/src/main.c (revision 530ceda57288aa931d0c8ba7b3066340d587cc9b)
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 #ifndef OPENSSL_NO_EC
96 	[KEY_ALG_ECDSA] = "ecdsa"
97 #endif /* OPENSSL_NO_EC */
98 };
99 
100 static const char *hash_algs_str[] = {
101 	[HASH_ALG_SHA256] = "sha256",
102 	[HASH_ALG_SHA384] = "sha384",
103 	[HASH_ALG_SHA512] = "sha512",
104 };
105 
106 static void print_help(const char *cmd, const struct option *long_opt)
107 {
108 	int rem, i = 0;
109 	const struct option *opt;
110 	char line[HELP_OPT_MAX_LEN];
111 	char *p;
112 
113 	assert(cmd != NULL);
114 	assert(long_opt != NULL);
115 
116 	printf("\n\n");
117 	printf("The certificate generation tool loads the binary images and\n"
118 	       "optionally the RSA keys, and outputs the key and content\n"
119 	       "certificates properly signed to implement the chain of trust.\n"
120 	       "If keys are provided, they must be in PEM format.\n"
121 	       "Certificates are generated in DER format.\n");
122 	printf("\n");
123 	printf("Usage:\n");
124 	printf("\t%s [OPTIONS]\n\n", cmd);
125 
126 	printf("Available options:\n");
127 	opt = long_opt;
128 	while (opt->name) {
129 		p = line;
130 		rem = HELP_OPT_MAX_LEN;
131 		if (isalpha(opt->val)) {
132 			/* Short format */
133 			sprintf(p, "-%c,", (char)opt->val);
134 			p += 3;
135 			rem -= 3;
136 		}
137 		snprintf(p, rem, "--%s %s", opt->name,
138 			 (opt->has_arg == required_argument) ? "<arg>" : "");
139 		printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i));
140 		opt++;
141 		i++;
142 	}
143 	printf("\n");
144 }
145 
146 static int get_key_alg(const char *key_alg_str)
147 {
148 	int i;
149 
150 	for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
151 		if (0 == strcmp(key_alg_str, key_algs_str[i])) {
152 			return i;
153 		}
154 	}
155 
156 	return -1;
157 }
158 
159 static int get_key_size(const char *key_size_str)
160 {
161 	char *end;
162 	long key_size;
163 
164 	key_size = strtol(key_size_str, &end, 10);
165 	if (*end != '\0')
166 		return -1;
167 
168 	return key_size;
169 }
170 
171 static int get_hash_alg(const char *hash_alg_str)
172 {
173 	int i;
174 
175 	for (i = 0 ; i < NUM_ELEM(hash_algs_str) ; i++) {
176 		if (0 == strcmp(hash_alg_str, hash_algs_str[i])) {
177 			return i;
178 		}
179 	}
180 
181 	return -1;
182 }
183 
184 static void check_cmd_params(void)
185 {
186 	cert_t *cert;
187 	ext_t *ext;
188 	key_t *key;
189 	int i, j;
190 	bool valid_size;
191 
192 	/* Only save new keys */
193 	if (save_keys && !new_keys) {
194 		ERROR("Only new keys can be saved to disk\n");
195 		exit(1);
196 	}
197 
198 	/* Validate key-size */
199 	valid_size = false;
200 	for (i = 0; i < KEY_SIZE_MAX_NUM; i++) {
201 		if (key_size == KEY_SIZES[key_alg][i]) {
202 			valid_size = true;
203 			break;
204 		}
205 	}
206 	if (!valid_size) {
207 		ERROR("'%d' is not a valid key size for '%s'\n",
208 				key_size, key_algs_str[key_alg]);
209 		NOTICE("Valid sizes are: ");
210 		for (i = 0; i < KEY_SIZE_MAX_NUM &&
211 				KEY_SIZES[key_alg][i] != 0; i++) {
212 			printf("%d ", KEY_SIZES[key_alg][i]);
213 		}
214 		printf("\n");
215 		exit(1);
216 	}
217 
218 	/* Check that all required options have been specified in the
219 	 * command line */
220 	for (i = 0; i < num_certs; i++) {
221 		cert = &certs[i];
222 		if (cert->fn == NULL) {
223 			/* Certificate not requested. Skip to the next one */
224 			continue;
225 		}
226 
227 		/* Check that all parameters required to create this certificate
228 		 * have been specified in the command line */
229 		for (j = 0; j < cert->num_ext; j++) {
230 			ext = &extensions[cert->ext[j]];
231 			switch (ext->type) {
232 			case EXT_TYPE_NVCOUNTER:
233 				/* Counter value must be specified */
234 				if ((!ext->optional) && (ext->arg == NULL)) {
235 					ERROR("Value for '%s' not specified\n",
236 					      ext->ln);
237 					exit(1);
238 				}
239 				break;
240 			case EXT_TYPE_PKEY:
241 				/* Key filename must be specified */
242 				key = &keys[ext->attr.key];
243 				if (!new_keys && key->fn == NULL) {
244 					ERROR("Key '%s' required by '%s' not "
245 					      "specified\n", key->desc,
246 					      cert->cn);
247 					exit(1);
248 				}
249 				break;
250 			case EXT_TYPE_HASH:
251 				/*
252 				 * Binary image must be specified
253 				 * unless it is explicitly made optional.
254 				 */
255 				if ((!ext->optional) && (ext->arg == NULL)) {
256 					ERROR("Image for '%s' not specified\n",
257 					      ext->ln);
258 					exit(1);
259 				}
260 				break;
261 			default:
262 				ERROR("Unknown extension type '%d' in '%s'\n",
263 				      ext->type, ext->ln);
264 				exit(1);
265 				break;
266 			}
267 		}
268 	}
269 }
270 
271 /* Common command line options */
272 static const cmd_opt_t common_cmd_opt[] = {
273 	{
274 		{ "help", no_argument, NULL, 'h' },
275 		"Print this message and exit"
276 	},
277 	{
278 		{ "key-alg", required_argument, NULL, 'a' },
279 		"Key algorithm: 'rsa' (default)- RSAPSS scheme as per PKCS#1 v2.1, 'ecdsa'"
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 
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 TBB 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 (!key_new(&keys[i])) {
443 			ERROR("Failed to allocate key container\n");
444 			exit(1);
445 		}
446 
447 		/* First try to load the key from disk */
448 		if (key_load(&keys[i], &err_code)) {
449 			/* Key loaded successfully */
450 			continue;
451 		}
452 
453 		/* Key not loaded. Check the error code */
454 		if (err_code == KEY_ERR_LOAD) {
455 			/* File exists, but it does not contain a valid private
456 			 * key. Abort. */
457 			ERROR("Error loading '%s'\n", keys[i].fn);
458 			exit(1);
459 		}
460 
461 		/* File does not exist, could not be opened or no filename was
462 		 * given */
463 		if (new_keys) {
464 			/* Try to create a new key */
465 			NOTICE("Creating new key for '%s'\n", keys[i].desc);
466 			if (!key_create(&keys[i], key_alg, key_size)) {
467 				ERROR("Error creating key '%s'\n", keys[i].desc);
468 				exit(1);
469 			}
470 		} else {
471 			if (err_code == KEY_ERR_OPEN) {
472 				ERROR("Error opening '%s'\n", keys[i].fn);
473 			} else {
474 				ERROR("Key '%s' not specified\n", keys[i].desc);
475 			}
476 			exit(1);
477 		}
478 	}
479 
480 	/* Create the certificates */
481 	for (i = 0 ; i < num_certs ; i++) {
482 
483 		cert = &certs[i];
484 
485 		/* Create a new stack of extensions. This stack will be used
486 		 * to create the certificate */
487 		CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
488 
489 		for (j = 0 ; j < cert->num_ext ; j++) {
490 
491 			ext = &extensions[cert->ext[j]];
492 
493 			/* Get OpenSSL internal ID for this extension */
494 			CHECK_OID(ext_nid, ext->oid);
495 
496 			/*
497 			 * Three types of extensions are currently supported:
498 			 *     - EXT_TYPE_NVCOUNTER
499 			 *     - EXT_TYPE_HASH
500 			 *     - EXT_TYPE_PKEY
501 			 */
502 			switch (ext->type) {
503 			case EXT_TYPE_NVCOUNTER:
504 				if (ext->arg) {
505 					nvctr = atoi(ext->arg);
506 					CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
507 						EXT_CRIT, nvctr));
508 				}
509 				break;
510 			case EXT_TYPE_HASH:
511 				if (ext->arg == NULL) {
512 					if (ext->optional) {
513 						/* Include a hash filled with zeros */
514 						memset(md, 0x0, SHA512_DIGEST_LENGTH);
515 					} else {
516 						/* Do not include this hash in the certificate */
517 						break;
518 					}
519 				} else {
520 					/* Calculate the hash of the file */
521 					if (!sha_file(hash_alg, ext->arg, md)) {
522 						ERROR("Cannot calculate hash of %s\n",
523 							ext->arg);
524 						exit(1);
525 					}
526 				}
527 				CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
528 						EXT_CRIT, md_info, md,
529 						md_len));
530 				break;
531 			case EXT_TYPE_PKEY:
532 				CHECK_NULL(cert_ext, ext_new_key(ext_nid,
533 					EXT_CRIT, keys[ext->attr.key].key));
534 				break;
535 			default:
536 				ERROR("Unknown extension type '%d' in %s\n",
537 						ext->type, cert->cn);
538 				exit(1);
539 			}
540 
541 			/* Push the extension into the stack */
542 			sk_X509_EXTENSION_push(sk, cert_ext);
543 		}
544 
545 		/* Create certificate. Signed with corresponding key */
546 		if (cert->fn && !cert_new(hash_alg, cert, VAL_DAYS, 0, sk)) {
547 			ERROR("Cannot create %s\n", cert->cn);
548 			exit(1);
549 		}
550 
551 		sk_X509_EXTENSION_free(sk);
552 	}
553 
554 
555 	/* Print the certificates */
556 	if (print_cert) {
557 		for (i = 0 ; i < num_certs ; i++) {
558 			if (!certs[i].x) {
559 				continue;
560 			}
561 			printf("\n\n=====================================\n\n");
562 			X509_print_fp(stdout, certs[i].x);
563 		}
564 	}
565 
566 	/* Save created certificates to files */
567 	for (i = 0 ; i < num_certs ; i++) {
568 		if (certs[i].x && certs[i].fn) {
569 			file = fopen(certs[i].fn, "w");
570 			if (file != NULL) {
571 				i2d_X509_fp(file, certs[i].x);
572 				fclose(file);
573 			} else {
574 				ERROR("Cannot create file %s\n", certs[i].fn);
575 			}
576 		}
577 	}
578 
579 	/* Save keys */
580 	if (save_keys) {
581 		for (i = 0 ; i < num_keys ; i++) {
582 			if (!key_store(&keys[i])) {
583 				ERROR("Cannot save %s\n", keys[i].desc);
584 			}
585 		}
586 	}
587 
588 #ifndef OPENSSL_NO_ENGINE
589 	ENGINE_cleanup();
590 #endif
591 	CRYPTO_cleanup_all_ex_data();
592 
593 	return 0;
594 }
595