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