xref: /rk3399_ARM-atf/tools/cert_create/src/main.c (revision 4df2246943af8568564b4732de02794b2fd8bd39)
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_ext.h"
34 #include "tbbr/tbb_cert.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 new_keys;
72 static int save_keys;
73 static int print_cert;
74 
75 /* Info messages created in the Makefile */
76 extern const char build_msg[];
77 extern const char platform_msg[];
78 
79 
80 static char *strdup(const char *str)
81 {
82 	int n = strlen(str) + 1;
83 	char *dup = malloc(n);
84 	if (dup) {
85 		strcpy(dup, str);
86 	}
87 	return dup;
88 }
89 
90 static const char *key_algs_str[] = {
91 	[KEY_ALG_RSA] = "rsa",
92 #ifndef OPENSSL_NO_EC
93 	[KEY_ALG_ECDSA] = "ecdsa"
94 #endif /* OPENSSL_NO_EC */
95 };
96 
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 	exit(0);
137 }
138 
139 static int get_key_alg(const char *key_alg_str)
140 {
141 	int i;
142 
143 	for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
144 		if (0 == strcmp(key_alg_str, key_algs_str[i])) {
145 			return i;
146 		}
147 	}
148 
149 	return -1;
150 }
151 
152 static void check_cmd_params(void)
153 {
154 	cert_t *cert;
155 	ext_t *ext;
156 	key_t *key;
157 	int i, j;
158 
159 	/* Only save new keys */
160 	if (save_keys && !new_keys) {
161 		ERROR("Only new keys can be saved to disk\n");
162 		exit(1);
163 	}
164 
165 	/* Check that all required options have been specified in the
166 	 * command line */
167 	for (i = 0; i < num_certs; i++) {
168 		cert = &certs[i];
169 		if (cert->fn == NULL) {
170 			/* Certificate not requested. Skip to the next one */
171 			continue;
172 		}
173 
174 		/* Check that all parameters required to create this certificate
175 		 * have been specified in the command line */
176 		for (j = 0; j < cert->num_ext; j++) {
177 			ext = &extensions[cert->ext[j]];
178 			switch (ext->type) {
179 			case EXT_TYPE_NVCOUNTER:
180 				/* Counter value must be specified */
181 				if ((!ext->optional) && (ext->arg == NULL)) {
182 					ERROR("Value for '%s' not specified\n",
183 					      ext->ln);
184 					exit(1);
185 				}
186 				break;
187 			case EXT_TYPE_PKEY:
188 				/* Key filename must be specified */
189 				key = &keys[ext->attr.key];
190 				if (!new_keys && key->fn == NULL) {
191 					ERROR("Key '%s' required by '%s' not "
192 					      "specified\n", key->desc,
193 					      cert->cn);
194 					exit(1);
195 				}
196 				break;
197 			case EXT_TYPE_HASH:
198 				/*
199 				 * Binary image must be specified
200 				 * unless it is explicitly made optional.
201 				 */
202 				if ((!ext->optional) && (ext->arg == NULL)) {
203 					ERROR("Image for '%s' not specified\n",
204 					      ext->ln);
205 					exit(1);
206 				}
207 				break;
208 			default:
209 				ERROR("Unknown extension type '%d' in '%s'\n",
210 				      ext->type, ext->ln);
211 				exit(1);
212 				break;
213 			}
214 		}
215 	}
216 }
217 
218 /* Common command line options */
219 static const cmd_opt_t common_cmd_opt[] = {
220 	{
221 		{ "help", no_argument, NULL, 'h' },
222 		"Print this message and exit"
223 	},
224 	{
225 		{ "key-alg", required_argument, NULL, 'a' },
226 		"Key algorithm: 'rsa' (default), 'ecdsa'"
227 	},
228 	{
229 		{ "save-keys", no_argument, NULL, 'k' },
230 		"Save key pairs into files. Filenames must be provided"
231 	},
232 	{
233 		{ "new-keys", no_argument, NULL, 'n' },
234 		"Generate new key pairs if no key files are provided"
235 	},
236 	{
237 		{ "print-cert", no_argument, NULL, 'p' },
238 		"Print the certificates in the standard output"
239 	}
240 };
241 
242 int main(int argc, char *argv[])
243 {
244 	STACK_OF(X509_EXTENSION) * sk;
245 	X509_EXTENSION *cert_ext;
246 	ext_t *ext;
247 	key_t *key;
248 	cert_t *cert;
249 	FILE *file;
250 	int i, j, ext_nid, nvctr;
251 	int c, opt_idx = 0;
252 	const struct option *cmd_opt;
253 	const char *cur_opt;
254 	unsigned int err_code;
255 	unsigned char md[SHA256_DIGEST_LENGTH];
256 	const EVP_MD *md_info;
257 
258 	NOTICE("CoT Generation Tool: %s\n", build_msg);
259 	NOTICE("Target platform: %s\n", platform_msg);
260 
261 	/* Set default options */
262 	key_alg = KEY_ALG_RSA;
263 
264 	/* Add common command line options */
265 	for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
266 		cmd_opt_add(&common_cmd_opt[i]);
267 	}
268 
269 	/* Initialize the certificates */
270 	if (cert_init() != 0) {
271 		ERROR("Cannot initialize certificates\n");
272 		exit(1);
273 	}
274 
275 	/* Initialize the keys */
276 	if (key_init() != 0) {
277 		ERROR("Cannot initialize keys\n");
278 		exit(1);
279 	}
280 
281 	/* Initialize the new types and register OIDs for the extensions */
282 	if (ext_init() != 0) {
283 		ERROR("Cannot initialize TBB extensions\n");
284 		exit(1);
285 	}
286 
287 	/* Get the command line options populated during the initialization */
288 	cmd_opt = cmd_opt_get_array();
289 
290 	while (1) {
291 		/* getopt_long stores the option index here. */
292 		c = getopt_long(argc, argv, "a:hknp", cmd_opt, &opt_idx);
293 
294 		/* Detect the end of the options. */
295 		if (c == -1) {
296 			break;
297 		}
298 
299 		switch (c) {
300 		case 'a':
301 			key_alg = get_key_alg(optarg);
302 			if (key_alg < 0) {
303 				ERROR("Invalid key algorithm '%s'\n", optarg);
304 				exit(1);
305 			}
306 			break;
307 		case 'h':
308 			print_help(argv[0], cmd_opt);
309 			break;
310 		case 'k':
311 			save_keys = 1;
312 			break;
313 		case 'n':
314 			new_keys = 1;
315 			break;
316 		case 'p':
317 			print_cert = 1;
318 			break;
319 		case CMD_OPT_EXT:
320 			cur_opt = cmd_opt_get_name(opt_idx);
321 			ext = ext_get_by_opt(cur_opt);
322 			ext->arg = strdup(optarg);
323 			break;
324 		case CMD_OPT_KEY:
325 			cur_opt = cmd_opt_get_name(opt_idx);
326 			key = key_get_by_opt(cur_opt);
327 			key->fn = strdup(optarg);
328 			break;
329 		case CMD_OPT_CERT:
330 			cur_opt = cmd_opt_get_name(opt_idx);
331 			cert = cert_get_by_opt(cur_opt);
332 			cert->fn = strdup(optarg);
333 			break;
334 		case '?':
335 		default:
336 			print_help(argv[0], cmd_opt);
337 			exit(1);
338 		}
339 	}
340 
341 	/* Check command line arguments */
342 	check_cmd_params();
343 
344 	/* Indicate SHA256 as image hash algorithm in the certificate
345 	 * extension */
346 	md_info = EVP_sha256();
347 
348 	/* Load private keys from files (or generate new ones) */
349 	for (i = 0 ; i < num_keys ; i++) {
350 		if (!key_new(&keys[i])) {
351 			ERROR("Failed to allocate key container\n");
352 			exit(1);
353 		}
354 
355 		/* First try to load the key from disk */
356 		if (key_load(&keys[i], &err_code)) {
357 			/* Key loaded successfully */
358 			continue;
359 		}
360 
361 		/* Key not loaded. Check the error code */
362 		if (err_code == KEY_ERR_LOAD) {
363 			/* File exists, but it does not contain a valid private
364 			 * key. Abort. */
365 			ERROR("Error loading '%s'\n", keys[i].fn);
366 			exit(1);
367 		}
368 
369 		/* File does not exist, could not be opened or no filename was
370 		 * given */
371 		if (new_keys) {
372 			/* Try to create a new key */
373 			NOTICE("Creating new key for '%s'\n", keys[i].desc);
374 			if (!key_create(&keys[i], key_alg)) {
375 				ERROR("Error creating key '%s'\n", keys[i].desc);
376 				exit(1);
377 			}
378 		} else {
379 			if (err_code == KEY_ERR_OPEN) {
380 				ERROR("Error opening '%s'\n", keys[i].fn);
381 			} else {
382 				ERROR("Key '%s' not specified\n", keys[i].desc);
383 			}
384 			exit(1);
385 		}
386 	}
387 
388 	/* Create the certificates */
389 	for (i = 0 ; i < num_certs ; i++) {
390 
391 		cert = &certs[i];
392 
393 		/* Create a new stack of extensions. This stack will be used
394 		 * to create the certificate */
395 		CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
396 
397 		for (j = 0 ; j < cert->num_ext ; j++) {
398 
399 			ext = &extensions[cert->ext[j]];
400 
401 			/* Get OpenSSL internal ID for this extension */
402 			CHECK_OID(ext_nid, ext->oid);
403 
404 			/*
405 			 * Three types of extensions are currently supported:
406 			 *     - EXT_TYPE_NVCOUNTER
407 			 *     - EXT_TYPE_HASH
408 			 *     - EXT_TYPE_PKEY
409 			 */
410 			switch (ext->type) {
411 			case EXT_TYPE_NVCOUNTER:
412 				if (ext->arg) {
413 					nvctr = atoi(ext->arg);
414 					CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
415 						EXT_CRIT, nvctr));
416 				}
417 				break;
418 			case EXT_TYPE_HASH:
419 				if (ext->arg == NULL) {
420 					if (ext->optional) {
421 						/* Include a hash filled with zeros */
422 						memset(md, 0x0, SHA256_DIGEST_LENGTH);
423 					} else {
424 						/* Do not include this hash in the certificate */
425 						break;
426 					}
427 				} else {
428 					/* Calculate the hash of the file */
429 					if (!sha_file(ext->arg, md)) {
430 						ERROR("Cannot calculate hash of %s\n",
431 							ext->arg);
432 						exit(1);
433 					}
434 				}
435 				CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
436 						EXT_CRIT, md_info, md,
437 						SHA256_DIGEST_LENGTH));
438 				break;
439 			case EXT_TYPE_PKEY:
440 				CHECK_NULL(cert_ext, ext_new_key(ext_nid,
441 					EXT_CRIT, keys[ext->attr.key].key));
442 				break;
443 			default:
444 				ERROR("Unknown extension type '%d' in %s\n",
445 						ext->type, cert->cn);
446 				exit(1);
447 			}
448 
449 			/* Push the extension into the stack */
450 			sk_X509_EXTENSION_push(sk, cert_ext);
451 		}
452 
453 		/* Create certificate. Signed with ROT key */
454 		if (cert->fn && !cert_new(cert, VAL_DAYS, 0, sk)) {
455 			ERROR("Cannot create %s\n", cert->cn);
456 			exit(1);
457 		}
458 
459 		sk_X509_EXTENSION_free(sk);
460 	}
461 
462 
463 	/* Print the certificates */
464 	if (print_cert) {
465 		for (i = 0 ; i < num_certs ; i++) {
466 			if (!certs[i].x) {
467 				continue;
468 			}
469 			printf("\n\n=====================================\n\n");
470 			X509_print_fp(stdout, certs[i].x);
471 		}
472 	}
473 
474 	/* Save created certificates to files */
475 	for (i = 0 ; i < num_certs ; i++) {
476 		if (certs[i].x && certs[i].fn) {
477 			file = fopen(certs[i].fn, "w");
478 			if (file != NULL) {
479 				i2d_X509_fp(file, certs[i].x);
480 				fclose(file);
481 			} else {
482 				ERROR("Cannot create file %s\n", certs[i].fn);
483 			}
484 		}
485 	}
486 
487 	/* Save keys */
488 	if (save_keys) {
489 		for (i = 0 ; i < num_keys ; i++) {
490 			if (!key_store(&keys[i])) {
491 				ERROR("Cannot save %s\n", keys[i].desc);
492 			}
493 		}
494 	}
495 
496 #ifndef OPENSSL_NO_ENGINE
497 	ENGINE_cleanup();
498 #endif
499 	CRYPTO_cleanup_all_ex_data();
500 
501 	return 0;
502 }
503