xref: /rk3399_ARM-atf/tools/cert_create/src/main.c (revision 649dbf6f3666fa4ec8bad318d01b946fb89063e0)
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 	BL30_ID,
90 	BL31_ID,
91 	BL32_ID,
92 	BL33_ID,
93 	/* Certificate file names (outputs) */
94 	BL2_CERT_ID,
95 	TRUSTED_KEY_CERT_ID,
96 	BL30_KEY_CERT_ID,
97 	BL30_CERT_ID,
98 	BL31_KEY_CERT_ID,
99 	BL31_CERT_ID,
100 	BL32_KEY_CERT_ID,
101 	BL32_CERT_ID,
102 	BL33_KEY_CERT_ID,
103 	BL33_CERT_ID,
104 	/* Key file names (input/output) */
105 	ROT_KEY_ID,
106 	TRUSTED_WORLD_KEY_ID,
107 	NON_TRUSTED_WORLD_KEY_ID,
108 	BL30_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 				/* Binary image must be specified */
221 				if (ext->data.fn == 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 in '%s'\n",
229 				      ext->ln);
230 				exit(1);
231 				break;
232 			}
233 		}
234 	}
235 }
236 
237 int main(int argc, char *argv[])
238 {
239 	STACK_OF(X509_EXTENSION) * sk = NULL;
240 	X509_EXTENSION *cert_ext = NULL;
241 	ext_t *ext = NULL;
242 	key_t *key = NULL;
243 	cert_t *cert = NULL;
244 	FILE *file = NULL;
245 	int i, j, ext_nid;
246 	int c, opt_idx = 0;
247 	const struct option *cmd_opt;
248 	const char *cur_opt;
249 	unsigned int err_code;
250 	unsigned char md[SHA256_DIGEST_LENGTH];
251 	const EVP_MD *md_info;
252 
253 	NOTICE("CoT Generation Tool: %s\n", build_msg);
254 	NOTICE("Target platform: %s\n", platform_msg);
255 
256 	/* Set default options */
257 	key_alg = KEY_ALG_RSA;
258 
259 	/* Add common command line options */
260 	cmd_opt_add("key-alg", required_argument, 'a');
261 	cmd_opt_add("help", no_argument, 'h');
262 	cmd_opt_add("save-keys", no_argument, 'k');
263 	cmd_opt_add("new-chain", no_argument, 'n');
264 	cmd_opt_add("print-cert", no_argument, 'p');
265 
266 	/* Initialize the certificates */
267 	if (cert_init() != 0) {
268 		ERROR("Cannot initialize certificates\n");
269 		exit(1);
270 	}
271 
272 	/* Initialize the keys */
273 	if (key_init() != 0) {
274 		ERROR("Cannot initialize keys\n");
275 		exit(1);
276 	}
277 
278 	/* Initialize the new types and register OIDs for the extensions */
279 	if (ext_init() != 0) {
280 		ERROR("Cannot initialize TBB extensions\n");
281 		exit(1);
282 	}
283 
284 	/* Get the command line options populated during the initialization */
285 	cmd_opt = cmd_opt_get_array();
286 
287 	while (1) {
288 		/* getopt_long stores the option index here. */
289 		c = getopt_long(argc, argv, "ahknp", cmd_opt, &opt_idx);
290 
291 		/* Detect the end of the options. */
292 		if (c == -1) {
293 			break;
294 		}
295 
296 		switch (c) {
297 		case 'a':
298 			key_alg = get_key_alg(optarg);
299 			if (key_alg < 0) {
300 				ERROR("Invalid key algorithm '%s'\n", optarg);
301 				exit(1);
302 			}
303 			break;
304 		case 'h':
305 			print_help(argv[0], cmd_opt);
306 			break;
307 		case 'k':
308 			save_keys = 1;
309 			break;
310 		case 'n':
311 			new_keys = 1;
312 			break;
313 		case 'p':
314 			print_cert = 1;
315 			break;
316 		case CMD_OPT_EXT:
317 			cur_opt = cmd_opt_get_name(opt_idx);
318 			ext = ext_get_by_opt(cur_opt);
319 			ext->data.fn = strdup(optarg);
320 			break;
321 		case CMD_OPT_KEY:
322 			cur_opt = cmd_opt_get_name(opt_idx);
323 			key = key_get_by_opt(cur_opt);
324 			key->fn = strdup(optarg);
325 			break;
326 		case CMD_OPT_CERT:
327 			cur_opt = cmd_opt_get_name(opt_idx);
328 			cert = cert_get_by_opt(cur_opt);
329 			cert->fn = strdup(optarg);
330 			break;
331 		case '?':
332 		default:
333 			printf("%s\n", optarg);
334 			exit(1);
335 		}
336 	}
337 
338 	/* Check command line arguments */
339 	check_cmd_params();
340 
341 	/* Indicate SHA256 as image hash algorithm in the certificate
342 	 * extension */
343 	md_info = EVP_sha256();
344 
345 	/* Load private keys from files (or generate new ones) */
346 	for (i = 0 ; i < num_keys ; i++) {
347 		/* First try to load the key from disk */
348 		if (key_load(&keys[i], &err_code)) {
349 			/* Key loaded successfully */
350 			continue;
351 		}
352 
353 		/* Key not loaded. Check the error code */
354 		if (err_code == KEY_ERR_MALLOC) {
355 			/* Cannot allocate memory. Abort. */
356 			ERROR("Malloc error while loading '%s'\n", keys[i].fn);
357 			exit(1);
358 		} else if (err_code == KEY_ERR_LOAD) {
359 			/* File exists, but it does not contain a valid private
360 			 * key. Abort. */
361 			ERROR("Error loading '%s'\n", keys[i].fn);
362 			exit(1);
363 		}
364 
365 		/* File does not exist, could not be opened or no filename was
366 		 * given */
367 		if (new_keys) {
368 			/* Try to create a new key */
369 			NOTICE("Creating new key for '%s'\n", keys[i].desc);
370 			if (!key_create(&keys[i], key_alg)) {
371 				ERROR("Error creating key '%s'\n", keys[i].desc);
372 				exit(1);
373 			}
374 		} else {
375 			if (err_code == KEY_ERR_OPEN) {
376 				ERROR("Error opening '%s'\n", keys[i].fn);
377 			} else {
378 				ERROR("Key '%s' not specified\n", keys[i].desc);
379 			}
380 			exit(1);
381 		}
382 	}
383 
384 	/* Create the certificates */
385 	for (i = 0 ; i < num_certs ; i++) {
386 
387 		cert = &certs[i];
388 
389 		/* Create a new stack of extensions. This stack will be used
390 		 * to create the certificate */
391 		CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
392 
393 		for (j = 0 ; j < cert->num_ext ; j++) {
394 
395 			ext = &extensions[cert->ext[j]];
396 
397 			/* Get OpenSSL internal ID for this extension */
398 			CHECK_OID(ext_nid, ext->oid);
399 
400 			/*
401 			 * Three types of extensions are currently supported:
402 			 *     - EXT_TYPE_NVCOUNTER
403 			 *     - EXT_TYPE_HASH
404 			 *     - EXT_TYPE_PKEY
405 			 */
406 			switch (ext->type) {
407 			case EXT_TYPE_NVCOUNTER:
408 				CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
409 						EXT_CRIT, ext->data.nvcounter));
410 				break;
411 			case EXT_TYPE_HASH:
412 				if (ext->data.fn == NULL) {
413 					break;
414 				}
415 				if (!sha_file(ext->data.fn, md)) {
416 					ERROR("Cannot calculate hash of %s\n",
417 						ext->data.fn);
418 					exit(1);
419 				}
420 				CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
421 						EXT_CRIT, md_info, md,
422 						SHA256_DIGEST_LENGTH));
423 				break;
424 			case EXT_TYPE_PKEY:
425 				CHECK_NULL(cert_ext, ext_new_key(ext_nid,
426 					EXT_CRIT, keys[ext->data.key].key));
427 				break;
428 			default:
429 				ERROR("Unknown extension type in %s\n",
430 						cert->cn);
431 				exit(1);
432 			}
433 
434 			/* Push the extension into the stack */
435 			sk_X509_EXTENSION_push(sk, cert_ext);
436 		}
437 
438 		/* Create certificate. Signed with ROT key */
439 		if (cert->fn && !cert_new(cert, VAL_DAYS, 0, sk)) {
440 			ERROR("Cannot create %s\n", cert->cn);
441 			exit(1);
442 		}
443 
444 		sk_X509_EXTENSION_free(sk);
445 	}
446 
447 
448 	/* Print the certificates */
449 	if (print_cert) {
450 		for (i = 0 ; i < num_certs ; i++) {
451 			if (!certs[i].x) {
452 				continue;
453 			}
454 			printf("\n\n=====================================\n\n");
455 			X509_print_fp(stdout, certs[i].x);
456 		}
457 	}
458 
459 	/* Save created certificates to files */
460 	for (i = 0 ; i < num_certs ; i++) {
461 		if (certs[i].x && certs[i].fn) {
462 			file = fopen(certs[i].fn, "w");
463 			if (file != NULL) {
464 				i2d_X509_fp(file, certs[i].x);
465 				fclose(file);
466 			} else {
467 				ERROR("Cannot create file %s\n", certs[i].fn);
468 			}
469 		}
470 	}
471 
472 	/* Save keys */
473 	if (save_keys) {
474 		for (i = 0 ; i < num_keys ; i++) {
475 			if (!key_store(&keys[i])) {
476 				ERROR("Cannot save %s\n", keys[i].desc);
477 			}
478 		}
479 	}
480 
481 #ifndef OPENSSL_NO_ENGINE
482 	ENGINE_cleanup();
483 #endif
484 	CRYPTO_cleanup_all_ex_data();
485 
486 	return 0;
487 }
488