xref: /rk3399_ARM-atf/tools/cert_create/src/main.c (revision f59821d51255f14e0ac00eef7bc98ef75c686876)
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 <getopt.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include <openssl/conf.h>
37 #include <openssl/engine.h>
38 #include <openssl/err.h>
39 #include <openssl/pem.h>
40 #include <openssl/sha.h>
41 #include <openssl/x509v3.h>
42 
43 #include "cert.h"
44 #include "cmd_opt.h"
45 #include "debug.h"
46 #include "ext.h"
47 #include "key.h"
48 #include "platform_oid.h"
49 #include "sha.h"
50 #include "tbbr/tbb_ext.h"
51 #include "tbbr/tbb_cert.h"
52 #include "tbbr/tbb_key.h"
53 
54 /*
55  * Helper macros to simplify the code. This macro assigns the return value of
56  * the 'fn' function to 'v' and exits if the value is NULL.
57  */
58 #define CHECK_NULL(v, fn) \
59 	do { \
60 		v = fn; \
61 		if (v == NULL) { \
62 			ERROR("NULL object at %s:%d\n", __FILE__, __LINE__); \
63 			exit(1); \
64 		} \
65 	} while (0)
66 
67 /*
68  * This macro assigns the NID corresponding to 'oid' to 'v' and exits if the
69  * NID is undefined.
70  */
71 #define CHECK_OID(v, oid) \
72 	do { \
73 		v = OBJ_txt2nid(oid); \
74 		if (v == NID_undef) { \
75 			ERROR("Cannot find TBB extension %s\n", oid); \
76 			exit(1); \
77 		} \
78 	} while (0)
79 
80 #define MAX_FILENAME_LEN		1024
81 #define VAL_DAYS			7300
82 #define ID_TO_BIT_MASK(id)		(1 << id)
83 #define NUM_ELEM(x)			((sizeof(x)) / (sizeof(x[0])))
84 
85 /* Files */
86 enum {
87 	/* Image file names (inputs) */
88 	BL2_ID = 0,
89 	SCP_BL2_ID,
90 	BL31_ID,
91 	BL32_ID,
92 	BL33_ID,
93 	/* Certificate file names (outputs) */
94 	TRUSTED_BOOT_FW_CERT_ID,
95 	TRUSTED_KEY_CERT_ID,
96 	SCP_FW_KEY_CERT_ID,
97 	SCP_FW_CONTENT_CERT_ID,
98 	SOC_FW_KEY_CERT_ID,
99 	SOC_FW_CONTENT_CERT_ID,
100 	TRUSTED_OS_FW_KEY_CERT_ID,
101 	TRUSTED_OS_FW_CONTENT_CERT_ID,
102 	NON_TRUSTED_FW_KEY_CERT_ID,
103 	NON_TRUSTED_FW_CONTENT_CERT_ID,
104 	/* Key file names (input/output) */
105 	ROT_KEY_ID,
106 	TRUSTED_WORLD_KEY_ID,
107 	NON_TRUSTED_WORLD_KEY_ID,
108 	SCP_BL2_KEY_ID,
109 	BL31_KEY_ID,
110 	BL32_KEY_ID,
111 	BL33_KEY_ID,
112 	NUM_OPTS
113 };
114 
115 /* Global options */
116 static int key_alg;
117 static int new_keys;
118 static int save_keys;
119 static int print_cert;
120 
121 /* Info messages created in the Makefile */
122 extern const char build_msg[];
123 extern const char platform_msg[];
124 
125 
126 static char *strdup(const char *str)
127 {
128 	int n = strlen(str) + 1;
129 	char *dup = malloc(n);
130 	if (dup) {
131 		strcpy(dup, str);
132 	}
133 	return dup;
134 }
135 
136 static const char *key_algs_str[] = {
137 	[KEY_ALG_RSA] = "rsa",
138 #ifndef OPENSSL_NO_EC
139 	[KEY_ALG_ECDSA] = "ecdsa"
140 #endif /* OPENSSL_NO_EC */
141 };
142 
143 static void print_help(const char *cmd, const struct option *long_opt)
144 {
145 	int i = 0;
146 	printf("\n\n");
147 	printf("The certificate generation tool loads the binary images and\n"
148 	       "optionally the RSA keys, and outputs the key and content\n"
149 	       "certificates properly signed to implement the chain of trust.\n"
150 	       "If keys are provided, they must be in PEM format.\n"
151 	       "Certificates are generated in DER format.\n");
152 	printf("\n");
153 	printf("Usage:\n\n");
154 	printf("    %s [-hknp] \\\n", cmd);
155 	for (i = 0; i < NUM_OPTS; i++) {
156 		printf("        --%s <file>  \\\n", long_opt[i].name);
157 	}
158 	printf("\n");
159 	printf("-a    Key algorithm: rsa (default), ecdsa\n");
160 	printf("-h    Print help and exit\n");
161 	printf("-k    Save key pairs into files. Filenames must be provided\n");
162 	printf("-n    Generate new key pairs if no key files are provided\n");
163 	printf("-p    Print the certificates in the standard output\n");
164 	printf("\n");
165 
166 	exit(0);
167 }
168 
169 static int get_key_alg(const char *key_alg_str)
170 {
171 	int i;
172 
173 	for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
174 		if (0 == strcmp(key_alg_str, key_algs_str[i])) {
175 			return i;
176 		}
177 	}
178 
179 	return -1;
180 }
181 
182 static void check_cmd_params(void)
183 {
184 	cert_t *cert;
185 	ext_t *ext;
186 	key_t *key;
187 	int i, j;
188 
189 	/* Only save new keys */
190 	if (save_keys && !new_keys) {
191 		ERROR("Only new keys can be saved to disk\n");
192 		exit(1);
193 	}
194 
195 	/* Check that all required options have been specified in the
196 	 * command line */
197 	for (i = 0; i < num_certs; i++) {
198 		cert = &certs[i];
199 		if (cert->fn == NULL) {
200 			/* Certificate not requested. Skip to the next one */
201 			continue;
202 		}
203 
204 		/* Check that all parameters required to create this certificate
205 		 * have been specified in the command line */
206 		for (j = 0; j < cert->num_ext; j++) {
207 			ext = &extensions[cert->ext[j]];
208 			switch (ext->type) {
209 			case EXT_TYPE_PKEY:
210 				/* Key filename must be specified */
211 				key = &keys[ext->data.key];
212 				if (!new_keys && key->fn == NULL) {
213 					ERROR("Key '%s' required by '%s' not "
214 					      "specified\n", key->desc,
215 					      cert->cn);
216 					exit(1);
217 				}
218 				break;
219 			case EXT_TYPE_HASH:
220 				/*
221 				 * Binary image must be specified
222 				 * unless it is explicitly made optional.
223 				 */
224 				if ((!ext->optional) && (ext->data.fn == NULL)) {
225 					ERROR("Image for '%s' not specified\n",
226 					      ext->ln);
227 					exit(1);
228 				}
229 				break;
230 			default:
231 				ERROR("Unknown extension type in '%s'\n",
232 				      ext->ln);
233 				exit(1);
234 				break;
235 			}
236 		}
237 	}
238 }
239 
240 int main(int argc, char *argv[])
241 {
242 	STACK_OF(X509_EXTENSION) * sk = NULL;
243 	X509_EXTENSION *cert_ext = NULL;
244 	ext_t *ext = NULL;
245 	key_t *key = NULL;
246 	cert_t *cert = NULL;
247 	FILE *file = NULL;
248 	int i, j, ext_nid;
249 	int c, opt_idx = 0;
250 	const struct option *cmd_opt;
251 	const char *cur_opt;
252 	unsigned int err_code;
253 	unsigned char md[SHA256_DIGEST_LENGTH];
254 	const EVP_MD *md_info;
255 
256 	NOTICE("CoT Generation Tool: %s\n", build_msg);
257 	NOTICE("Target platform: %s\n", platform_msg);
258 
259 	/* Set default options */
260 	key_alg = KEY_ALG_RSA;
261 
262 	/* Add common command line options */
263 	cmd_opt_add("key-alg", required_argument, 'a');
264 	cmd_opt_add("help", no_argument, 'h');
265 	cmd_opt_add("save-keys", no_argument, 'k');
266 	cmd_opt_add("new-chain", no_argument, 'n');
267 	cmd_opt_add("print-cert", no_argument, 'p');
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, "ahknp", 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->data.fn = 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 			printf("%s\n", optarg);
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 		/* First try to load the key from disk */
351 		if (key_load(&keys[i], &err_code)) {
352 			/* Key loaded successfully */
353 			continue;
354 		}
355 
356 		/* Key not loaded. Check the error code */
357 		if (err_code == KEY_ERR_MALLOC) {
358 			/* Cannot allocate memory. Abort. */
359 			ERROR("Malloc error while loading '%s'\n", keys[i].fn);
360 			exit(1);
361 		} else if (err_code == KEY_ERR_LOAD) {
362 			/* File exists, but it does not contain a valid private
363 			 * key. Abort. */
364 			ERROR("Error loading '%s'\n", keys[i].fn);
365 			exit(1);
366 		}
367 
368 		/* File does not exist, could not be opened or no filename was
369 		 * given */
370 		if (new_keys) {
371 			/* Try to create a new key */
372 			NOTICE("Creating new key for '%s'\n", keys[i].desc);
373 			if (!key_create(&keys[i], key_alg)) {
374 				ERROR("Error creating key '%s'\n", keys[i].desc);
375 				exit(1);
376 			}
377 		} else {
378 			if (err_code == KEY_ERR_OPEN) {
379 				ERROR("Error opening '%s'\n", keys[i].fn);
380 			} else {
381 				ERROR("Key '%s' not specified\n", keys[i].desc);
382 			}
383 			exit(1);
384 		}
385 	}
386 
387 	/* Create the certificates */
388 	for (i = 0 ; i < num_certs ; i++) {
389 
390 		cert = &certs[i];
391 
392 		/* Create a new stack of extensions. This stack will be used
393 		 * to create the certificate */
394 		CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
395 
396 		for (j = 0 ; j < cert->num_ext ; j++) {
397 
398 			ext = &extensions[cert->ext[j]];
399 
400 			/* Get OpenSSL internal ID for this extension */
401 			CHECK_OID(ext_nid, ext->oid);
402 
403 			/*
404 			 * Three types of extensions are currently supported:
405 			 *     - EXT_TYPE_NVCOUNTER
406 			 *     - EXT_TYPE_HASH
407 			 *     - EXT_TYPE_PKEY
408 			 */
409 			switch (ext->type) {
410 			case EXT_TYPE_NVCOUNTER:
411 				CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
412 						EXT_CRIT, ext->data.nvcounter));
413 				break;
414 			case EXT_TYPE_HASH:
415 				if (ext->data.fn == NULL) {
416 					if (ext->optional) {
417 						/* Include a hash filled with zeros */
418 						memset(md, 0x0, SHA256_DIGEST_LENGTH);
419 					} else {
420 						/* Do not include this hash in the certificate */
421 						break;
422 					}
423 				} else {
424 					/* Calculate the hash of the file */
425 					if (!sha_file(ext->data.fn, md)) {
426 						ERROR("Cannot calculate hash of %s\n",
427 							ext->data.fn);
428 						exit(1);
429 					}
430 				}
431 				CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
432 						EXT_CRIT, md_info, md,
433 						SHA256_DIGEST_LENGTH));
434 				break;
435 			case EXT_TYPE_PKEY:
436 				CHECK_NULL(cert_ext, ext_new_key(ext_nid,
437 					EXT_CRIT, keys[ext->data.key].key));
438 				break;
439 			default:
440 				ERROR("Unknown extension type in %s\n",
441 						cert->cn);
442 				exit(1);
443 			}
444 
445 			/* Push the extension into the stack */
446 			sk_X509_EXTENSION_push(sk, cert_ext);
447 		}
448 
449 		/* Create certificate. Signed with ROT key */
450 		if (cert->fn && !cert_new(cert, VAL_DAYS, 0, sk)) {
451 			ERROR("Cannot create %s\n", cert->cn);
452 			exit(1);
453 		}
454 
455 		sk_X509_EXTENSION_free(sk);
456 	}
457 
458 
459 	/* Print the certificates */
460 	if (print_cert) {
461 		for (i = 0 ; i < num_certs ; i++) {
462 			if (!certs[i].x) {
463 				continue;
464 			}
465 			printf("\n\n=====================================\n\n");
466 			X509_print_fp(stdout, certs[i].x);
467 		}
468 	}
469 
470 	/* Save created certificates to files */
471 	for (i = 0 ; i < num_certs ; i++) {
472 		if (certs[i].x && certs[i].fn) {
473 			file = fopen(certs[i].fn, "w");
474 			if (file != NULL) {
475 				i2d_X509_fp(file, certs[i].x);
476 				fclose(file);
477 			} else {
478 				ERROR("Cannot create file %s\n", certs[i].fn);
479 			}
480 		}
481 	}
482 
483 	/* Save keys */
484 	if (save_keys) {
485 		for (i = 0 ; i < num_keys ; i++) {
486 			if (!key_store(&keys[i])) {
487 				ERROR("Cannot save %s\n", keys[i].desc);
488 			}
489 		}
490 	}
491 
492 #ifndef OPENSSL_NO_ENGINE
493 	ENGINE_cleanup();
494 #endif
495 	CRYPTO_cleanup_all_ex_data();
496 
497 	return 0;
498 }
499