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