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