xref: /rk3399_ARM-atf/tools/cert_create/src/main.c (revision 51faada71a219a8b94cd8d8e423f0f22e9da4d8f)
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 	opt = long_opt;
138 	while (opt->name) {
139 		p = line;
140 		rem = HELP_OPT_MAX_LEN;
141 		if (isalpha(opt->val)) {
142 			/* Short format */
143 			sprintf(p, "-%c,", (char)opt->val);
144 			p += 3;
145 			rem -= 3;
146 		}
147 		snprintf(p, rem, "--%s %s", opt->name,
148 			 (opt->has_arg == required_argument) ? "<arg>" : "");
149 		printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i));
150 		opt++;
151 		i++;
152 	}
153 	printf("\n");
154 
155 	exit(0);
156 }
157 
158 static int get_key_alg(const char *key_alg_str)
159 {
160 	int i;
161 
162 	for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
163 		if (0 == strcmp(key_alg_str, key_algs_str[i])) {
164 			return i;
165 		}
166 	}
167 
168 	return -1;
169 }
170 
171 static void check_cmd_params(void)
172 {
173 	cert_t *cert;
174 	ext_t *ext;
175 	key_t *key;
176 	int i, j;
177 
178 	/* Only save new keys */
179 	if (save_keys && !new_keys) {
180 		ERROR("Only new keys can be saved to disk\n");
181 		exit(1);
182 	}
183 
184 	/* Check that all required options have been specified in the
185 	 * command line */
186 	for (i = 0; i < num_certs; i++) {
187 		cert = &certs[i];
188 		if (cert->fn == NULL) {
189 			/* Certificate not requested. Skip to the next one */
190 			continue;
191 		}
192 
193 		/* Check that all parameters required to create this certificate
194 		 * have been specified in the command line */
195 		for (j = 0; j < cert->num_ext; j++) {
196 			ext = &extensions[cert->ext[j]];
197 			switch (ext->type) {
198 			case EXT_TYPE_NVCOUNTER:
199 				/* Counter value must be specified */
200 				if ((!ext->optional) && (ext->arg == NULL)) {
201 					ERROR("Value for '%s' not specified\n",
202 					      ext->ln);
203 					exit(1);
204 				}
205 				break;
206 			case EXT_TYPE_PKEY:
207 				/* Key filename must be specified */
208 				key = &keys[ext->attr.key];
209 				if (!new_keys && key->fn == NULL) {
210 					ERROR("Key '%s' required by '%s' not "
211 					      "specified\n", key->desc,
212 					      cert->cn);
213 					exit(1);
214 				}
215 				break;
216 			case EXT_TYPE_HASH:
217 				/*
218 				 * Binary image must be specified
219 				 * unless it is explicitly made optional.
220 				 */
221 				if ((!ext->optional) && (ext->arg == NULL)) {
222 					ERROR("Image for '%s' not specified\n",
223 					      ext->ln);
224 					exit(1);
225 				}
226 				break;
227 			default:
228 				ERROR("Unknown extension type '%d' in '%s'\n",
229 				      ext->type, ext->ln);
230 				exit(1);
231 				break;
232 			}
233 		}
234 	}
235 }
236 
237 /* Common command line options */
238 static const cmd_opt_t common_cmd_opt[] = {
239 	{
240 		{ "help", no_argument, NULL, 'h' },
241 		"Print this message and exit"
242 	},
243 	{
244 		{ "key-alg", required_argument, NULL, 'a' },
245 		"Key algorithm: 'rsa' (default), 'ecdsa'"
246 	},
247 	{
248 		{ "save-keys", no_argument, NULL, 'k' },
249 		"Save key pairs into files. Filenames must be provided"
250 	},
251 	{
252 		{ "new-keys", no_argument, NULL, 'n' },
253 		"Generate new key pairs if no key files are provided"
254 	},
255 	{
256 		{ "print-cert", no_argument, NULL, 'p' },
257 		"Print the certificates in the standard output"
258 	}
259 };
260 
261 int main(int argc, char *argv[])
262 {
263 	STACK_OF(X509_EXTENSION) * sk;
264 	X509_EXTENSION *cert_ext;
265 	ext_t *ext;
266 	key_t *key;
267 	cert_t *cert;
268 	FILE *file;
269 	int i, j, ext_nid, nvctr;
270 	int c, opt_idx = 0;
271 	const struct option *cmd_opt;
272 	const char *cur_opt;
273 	unsigned int err_code;
274 	unsigned char md[SHA256_DIGEST_LENGTH];
275 	const EVP_MD *md_info;
276 
277 	NOTICE("CoT Generation Tool: %s\n", build_msg);
278 	NOTICE("Target platform: %s\n", platform_msg);
279 
280 	/* Set default options */
281 	key_alg = KEY_ALG_RSA;
282 
283 	/* Add common command line options */
284 	for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
285 		cmd_opt_add(&common_cmd_opt[i]);
286 	}
287 
288 	/* Initialize the certificates */
289 	if (cert_init() != 0) {
290 		ERROR("Cannot initialize certificates\n");
291 		exit(1);
292 	}
293 
294 	/* Initialize the keys */
295 	if (key_init() != 0) {
296 		ERROR("Cannot initialize keys\n");
297 		exit(1);
298 	}
299 
300 	/* Initialize the new types and register OIDs for the extensions */
301 	if (ext_init() != 0) {
302 		ERROR("Cannot initialize TBB extensions\n");
303 		exit(1);
304 	}
305 
306 	/* Get the command line options populated during the initialization */
307 	cmd_opt = cmd_opt_get_array();
308 
309 	while (1) {
310 		/* getopt_long stores the option index here. */
311 		c = getopt_long(argc, argv, "a:hknp", cmd_opt, &opt_idx);
312 
313 		/* Detect the end of the options. */
314 		if (c == -1) {
315 			break;
316 		}
317 
318 		switch (c) {
319 		case 'a':
320 			key_alg = get_key_alg(optarg);
321 			if (key_alg < 0) {
322 				ERROR("Invalid key algorithm '%s'\n", optarg);
323 				exit(1);
324 			}
325 			break;
326 		case 'h':
327 			print_help(argv[0], cmd_opt);
328 			break;
329 		case 'k':
330 			save_keys = 1;
331 			break;
332 		case 'n':
333 			new_keys = 1;
334 			break;
335 		case 'p':
336 			print_cert = 1;
337 			break;
338 		case CMD_OPT_EXT:
339 			cur_opt = cmd_opt_get_name(opt_idx);
340 			ext = ext_get_by_opt(cur_opt);
341 			ext->arg = strdup(optarg);
342 			break;
343 		case CMD_OPT_KEY:
344 			cur_opt = cmd_opt_get_name(opt_idx);
345 			key = key_get_by_opt(cur_opt);
346 			key->fn = strdup(optarg);
347 			break;
348 		case CMD_OPT_CERT:
349 			cur_opt = cmd_opt_get_name(opt_idx);
350 			cert = cert_get_by_opt(cur_opt);
351 			cert->fn = strdup(optarg);
352 			break;
353 		case '?':
354 		default:
355 			print_help(argv[0], cmd_opt);
356 			exit(1);
357 		}
358 	}
359 
360 	/* Check command line arguments */
361 	check_cmd_params();
362 
363 	/* Indicate SHA256 as image hash algorithm in the certificate
364 	 * extension */
365 	md_info = EVP_sha256();
366 
367 	/* Load private keys from files (or generate new ones) */
368 	for (i = 0 ; i < num_keys ; i++) {
369 		if (!key_new(&keys[i])) {
370 			ERROR("Failed to allocate key container\n");
371 			exit(1);
372 		}
373 
374 		/* First try to load the key from disk */
375 		if (key_load(&keys[i], &err_code)) {
376 			/* Key loaded successfully */
377 			continue;
378 		}
379 
380 		/* Key not loaded. Check the error code */
381 		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 				if (ext->arg) {
432 					nvctr = atoi(ext->arg);
433 					CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
434 						EXT_CRIT, nvctr));
435 				}
436 				break;
437 			case EXT_TYPE_HASH:
438 				if (ext->arg == NULL) {
439 					if (ext->optional) {
440 						/* Include a hash filled with zeros */
441 						memset(md, 0x0, SHA256_DIGEST_LENGTH);
442 					} else {
443 						/* Do not include this hash in the certificate */
444 						break;
445 					}
446 				} else {
447 					/* Calculate the hash of the file */
448 					if (!sha_file(ext->arg, md)) {
449 						ERROR("Cannot calculate hash of %s\n",
450 							ext->arg);
451 						exit(1);
452 					}
453 				}
454 				CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
455 						EXT_CRIT, md_info, md,
456 						SHA256_DIGEST_LENGTH));
457 				break;
458 			case EXT_TYPE_PKEY:
459 				CHECK_NULL(cert_ext, ext_new_key(ext_nid,
460 					EXT_CRIT, keys[ext->attr.key].key));
461 				break;
462 			default:
463 				ERROR("Unknown extension type '%d' in %s\n",
464 						ext->type, cert->cn);
465 				exit(1);
466 			}
467 
468 			/* Push the extension into the stack */
469 			sk_X509_EXTENSION_push(sk, cert_ext);
470 		}
471 
472 		/* Create certificate. Signed with ROT key */
473 		if (cert->fn && !cert_new(cert, VAL_DAYS, 0, sk)) {
474 			ERROR("Cannot create %s\n", cert->cn);
475 			exit(1);
476 		}
477 
478 		sk_X509_EXTENSION_free(sk);
479 	}
480 
481 
482 	/* Print the certificates */
483 	if (print_cert) {
484 		for (i = 0 ; i < num_certs ; i++) {
485 			if (!certs[i].x) {
486 				continue;
487 			}
488 			printf("\n\n=====================================\n\n");
489 			X509_print_fp(stdout, certs[i].x);
490 		}
491 	}
492 
493 	/* Save created certificates to files */
494 	for (i = 0 ; i < num_certs ; i++) {
495 		if (certs[i].x && certs[i].fn) {
496 			file = fopen(certs[i].fn, "w");
497 			if (file != NULL) {
498 				i2d_X509_fp(file, certs[i].x);
499 				fclose(file);
500 			} else {
501 				ERROR("Cannot create file %s\n", certs[i].fn);
502 			}
503 		}
504 	}
505 
506 	/* Save keys */
507 	if (save_keys) {
508 		for (i = 0 ; i < num_keys ; i++) {
509 			if (!key_store(&keys[i])) {
510 				ERROR("Cannot save %s\n", keys[i].desc);
511 			}
512 		}
513 	}
514 
515 #ifndef OPENSSL_NO_ENGINE
516 	ENGINE_cleanup();
517 #endif
518 	CRYPTO_cleanup_all_ex_data();
519 
520 	return 0;
521 }
522