blob: 99236370cd6711bb93c4a7eb60cb7709776556d2 [file] [log] [blame]
Juan Castillo6f971622014-10-21 11:30:42 +01001/*
Masahiro Yamadabb41eb72017-05-22 12:11:24 +09002 * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
Juan Castillo6f971622014-10-21 11:30:42 +01003 *
dp-arm82cb2c12017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Juan Castillo6f971622014-10-21 11:30:42 +01005 */
6
Juan Castillo159807e2015-12-15 16:37:57 +00007#include <assert.h>
8#include <ctype.h>
Juan Castillo6f971622014-10-21 11:30:42 +01009#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
Masahiro Yamadabb41eb72017-05-22 12:11:24 +090021#if USE_TBBR_DEFS
22#include <tbbr_oid.h>
23#else
24#include <platform_oid.h>
25#endif
26
Juan Castillo6f971622014-10-21 11:30:42 +010027#include "cert.h"
Juan Castilload2c1a92015-07-03 16:23:16 +010028#include "cmd_opt.h"
Juan Castillo6f971622014-10-21 11:30:42 +010029#include "debug.h"
30#include "ext.h"
31#include "key.h"
Juan Castillo6f971622014-10-21 11:30:42 +010032#include "sha.h"
Juan Castillo55e291a2015-06-12 11:27:59 +010033#include "tbbr/tbb_ext.h"
34#include "tbbr/tbb_cert.h"
35#include "tbbr/tbb_key.h"
Juan Castillo6f971622014-10-21 11:30:42 +010036
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)
Juan Castilloccbf8902015-06-01 16:34:23 +010066#define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0])))
Juan Castillo159807e2015-12-15 16:37:57 +000067#define HELP_OPT_MAX_LEN 128
Juan Castillo6f971622014-10-21 11:30:42 +010068
69/* Global options */
Juan Castilloccbf8902015-06-01 16:34:23 +010070static int key_alg;
Juan Castillo6f971622014-10-21 11:30:42 +010071static int new_keys;
72static int save_keys;
73static int print_cert;
Juan Castillo6f971622014-10-21 11:30:42 +010074
Juan Castillo6f971622014-10-21 11:30:42 +010075/* Info messages created in the Makefile */
76extern const char build_msg[];
77extern const char platform_msg[];
78
79
80static 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
Juan Castilloccbf8902015-06-01 16:34:23 +010090static const char *key_algs_str[] = {
91 [KEY_ALG_RSA] = "rsa",
Juan Castilloed2a76e2015-06-30 13:36:57 +010092#ifndef OPENSSL_NO_EC
Juan Castilloccbf8902015-06-01 16:34:23 +010093 [KEY_ALG_ECDSA] = "ecdsa"
Juan Castilloed2a76e2015-06-30 13:36:57 +010094#endif /* OPENSSL_NO_EC */
Juan Castilloccbf8902015-06-01 16:34:23 +010095};
96
Juan Castilload2c1a92015-07-03 16:23:16 +010097static void print_help(const char *cmd, const struct option *long_opt)
Juan Castillo6f971622014-10-21 11:30:42 +010098{
Juan Castillo159807e2015-12-15 16:37:57 +000099 int rem, i = 0;
100 const struct option *opt;
101 char line[HELP_OPT_MAX_LEN];
102 char *p;
103
104 assert(cmd != NULL);
105 assert(long_opt != NULL);
106
Juan Castillo6f971622014-10-21 11:30:42 +0100107 printf("\n\n");
108 printf("The certificate generation tool loads the binary images and\n"
109 "optionally the RSA keys, and outputs the key and content\n"
110 "certificates properly signed to implement the chain of trust.\n"
111 "If keys are provided, they must be in PEM format.\n"
112 "Certificates are generated in DER format.\n");
113 printf("\n");
Juan Castillo159807e2015-12-15 16:37:57 +0000114 printf("Usage:\n");
115 printf("\t%s [OPTIONS]\n\n", cmd);
116
117 printf("Available options:\n");
Juan Castillo159807e2015-12-15 16:37:57 +0000118 opt = long_opt;
119 while (opt->name) {
120 p = line;
121 rem = HELP_OPT_MAX_LEN;
122 if (isalpha(opt->val)) {
123 /* Short format */
124 sprintf(p, "-%c,", (char)opt->val);
125 p += 3;
126 rem -= 3;
127 }
128 snprintf(p, rem, "--%s %s", opt->name,
129 (opt->has_arg == required_argument) ? "<arg>" : "");
130 printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i));
131 opt++;
132 i++;
Juan Castillo6f971622014-10-21 11:30:42 +0100133 }
134 printf("\n");
Juan Castillo6f971622014-10-21 11:30:42 +0100135
136 exit(0);
137}
138
Juan Castilloccbf8902015-06-01 16:34:23 +0100139static int get_key_alg(const char *key_alg_str)
140{
141 int i;
142
143 for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
144 if (0 == strcmp(key_alg_str, key_algs_str[i])) {
145 return i;
146 }
147 }
148
149 return -1;
150}
151
Juan Castillo6f971622014-10-21 11:30:42 +0100152static void check_cmd_params(void)
153{
Juan Castillodfc90e22015-07-08 12:11:38 +0100154 cert_t *cert;
155 ext_t *ext;
156 key_t *key;
157 int i, j;
158
Juan Castilloccbf8902015-06-01 16:34:23 +0100159 /* Only save new keys */
160 if (save_keys && !new_keys) {
161 ERROR("Only new keys can be saved to disk\n");
162 exit(1);
163 }
164
Juan Castillodfc90e22015-07-08 12:11:38 +0100165 /* Check that all required options have been specified in the
166 * command line */
167 for (i = 0; i < num_certs; i++) {
168 cert = &certs[i];
169 if (cert->fn == NULL) {
170 /* Certificate not requested. Skip to the next one */
171 continue;
Juan Castillo6f971622014-10-21 11:30:42 +0100172 }
173
Juan Castillodfc90e22015-07-08 12:11:38 +0100174 /* Check that all parameters required to create this certificate
175 * have been specified in the command line */
176 for (j = 0; j < cert->num_ext; j++) {
177 ext = &extensions[cert->ext[j]];
178 switch (ext->type) {
Juan Castillo96103d52016-01-22 11:05:24 +0000179 case EXT_TYPE_NVCOUNTER:
180 /* Counter value must be specified */
181 if ((!ext->optional) && (ext->arg == NULL)) {
182 ERROR("Value for '%s' not specified\n",
183 ext->ln);
184 exit(1);
185 }
186 break;
Juan Castillodfc90e22015-07-08 12:11:38 +0100187 case EXT_TYPE_PKEY:
188 /* Key filename must be specified */
Juan Castillo96103d52016-01-22 11:05:24 +0000189 key = &keys[ext->attr.key];
Juan Castillodfc90e22015-07-08 12:11:38 +0100190 if (!new_keys && key->fn == NULL) {
191 ERROR("Key '%s' required by '%s' not "
192 "specified\n", key->desc,
193 cert->cn);
194 exit(1);
195 }
196 break;
197 case EXT_TYPE_HASH:
Yatharth Kocharcebe1f22015-08-21 15:30:55 +0100198 /*
199 * Binary image must be specified
200 * unless it is explicitly made optional.
201 */
Juan Castillo96103d52016-01-22 11:05:24 +0000202 if ((!ext->optional) && (ext->arg == NULL)) {
Juan Castillodfc90e22015-07-08 12:11:38 +0100203 ERROR("Image for '%s' not specified\n",
204 ext->ln);
205 exit(1);
206 }
207 break;
208 default:
Juan Castillo96103d52016-01-22 11:05:24 +0000209 ERROR("Unknown extension type '%d' in '%s'\n",
210 ext->type, ext->ln);
Juan Castillodfc90e22015-07-08 12:11:38 +0100211 exit(1);
212 break;
213 }
Juan Castillo6f971622014-10-21 11:30:42 +0100214 }
215 }
216}
217
Juan Castillo159807e2015-12-15 16:37:57 +0000218/* Common command line options */
219static const cmd_opt_t common_cmd_opt[] = {
220 {
221 { "help", no_argument, NULL, 'h' },
222 "Print this message and exit"
223 },
224 {
225 { "key-alg", required_argument, NULL, 'a' },
226 "Key algorithm: 'rsa' (default), 'ecdsa'"
227 },
228 {
229 { "save-keys", no_argument, NULL, 'k' },
230 "Save key pairs into files. Filenames must be provided"
231 },
232 {
233 { "new-keys", no_argument, NULL, 'n' },
234 "Generate new key pairs if no key files are provided"
235 },
236 {
237 { "print-cert", no_argument, NULL, 'p' },
238 "Print the certificates in the standard output"
239 }
240};
241
Juan Castillo6f971622014-10-21 11:30:42 +0100242int main(int argc, char *argv[])
243{
Masahiro Yamadac893c732017-02-06 19:47:44 +0900244 STACK_OF(X509_EXTENSION) * sk;
245 X509_EXTENSION *cert_ext;
246 ext_t *ext;
247 key_t *key;
248 cert_t *cert;
249 FILE *file;
Juan Castillo96103d52016-01-22 11:05:24 +0000250 int i, j, ext_nid, nvctr;
Juan Castillo6f971622014-10-21 11:30:42 +0100251 int c, opt_idx = 0;
Juan Castilload2c1a92015-07-03 16:23:16 +0100252 const struct option *cmd_opt;
253 const char *cur_opt;
Juan Castilloccbf8902015-06-01 16:34:23 +0100254 unsigned int err_code;
Juan Castillo6f971622014-10-21 11:30:42 +0100255 unsigned char md[SHA256_DIGEST_LENGTH];
Juan Castilloc3da66b2015-03-05 14:30:00 +0000256 const EVP_MD *md_info;
Juan Castillo6f971622014-10-21 11:30:42 +0100257
258 NOTICE("CoT Generation Tool: %s\n", build_msg);
259 NOTICE("Target platform: %s\n", platform_msg);
260
Juan Castilloccbf8902015-06-01 16:34:23 +0100261 /* Set default options */
262 key_alg = KEY_ALG_RSA;
263
Juan Castilload2c1a92015-07-03 16:23:16 +0100264 /* Add common command line options */
Juan Castillo159807e2015-12-15 16:37:57 +0000265 for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
266 cmd_opt_add(&common_cmd_opt[i]);
267 }
Juan Castilload2c1a92015-07-03 16:23:16 +0100268
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
Juan Castillo6f971622014-10-21 11:30:42 +0100290 while (1) {
291 /* getopt_long stores the option index here. */
Juan Castillo159807e2015-12-15 16:37:57 +0000292 c = getopt_long(argc, argv, "a:hknp", cmd_opt, &opt_idx);
Juan Castillo6f971622014-10-21 11:30:42 +0100293
294 /* Detect the end of the options. */
295 if (c == -1) {
296 break;
297 }
298
299 switch (c) {
Juan Castilloccbf8902015-06-01 16:34:23 +0100300 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;
Juan Castillo6f971622014-10-21 11:30:42 +0100307 case 'h':
Juan Castilload2c1a92015-07-03 16:23:16 +0100308 print_help(argv[0], cmd_opt);
Juan Castillo6f971622014-10-21 11:30:42 +0100309 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;
Juan Castilload2c1a92015-07-03 16:23:16 +0100319 case CMD_OPT_EXT:
320 cur_opt = cmd_opt_get_name(opt_idx);
321 ext = ext_get_by_opt(cur_opt);
Juan Castillo96103d52016-01-22 11:05:24 +0000322 ext->arg = strdup(optarg);
Juan Castillo6f971622014-10-21 11:30:42 +0100323 break;
Juan Castilload2c1a92015-07-03 16:23:16 +0100324 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);
Juan Castillo6f971622014-10-21 11:30:42 +0100328 break;
Juan Castilload2c1a92015-07-03 16:23:16 +0100329 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);
Juan Castillo6f971622014-10-21 11:30:42 +0100333 break;
334 case '?':
335 default:
Juan Castillo159807e2015-12-15 16:37:57 +0000336 print_help(argv[0], cmd_opt);
Juan Castillo6f971622014-10-21 11:30:42 +0100337 exit(1);
338 }
339 }
340
Juan Castillo6f971622014-10-21 11:30:42 +0100341 /* Check command line arguments */
342 check_cmd_params();
343
Juan Castilloc3da66b2015-03-05 14:30:00 +0000344 /* Indicate SHA256 as image hash algorithm in the certificate
345 * extension */
346 md_info = EVP_sha256();
347
Juan Castillo6f971622014-10-21 11:30:42 +0100348 /* Load private keys from files (or generate new ones) */
Juan Castillo55e291a2015-06-12 11:27:59 +0100349 for (i = 0 ; i < num_keys ; i++) {
Masahiro Yamada762f1eb2017-02-06 21:15:01 +0900350 if (!key_new(&keys[i])) {
351 ERROR("Failed to allocate key container\n");
352 exit(1);
353 }
354
Juan Castilloccbf8902015-06-01 16:34:23 +0100355 /* First try to load the key from disk */
356 if (key_load(&keys[i], &err_code)) {
357 /* Key loaded successfully */
358 continue;
Juan Castillo6f971622014-10-21 11:30:42 +0100359 }
Juan Castilloccbf8902015-06-01 16:34:23 +0100360
361 /* Key not loaded. Check the error code */
Masahiro Yamada762f1eb2017-02-06 21:15:01 +0900362 if (err_code == KEY_ERR_LOAD) {
Juan Castilloccbf8902015-06-01 16:34:23 +0100363 /* File exists, but it does not contain a valid private
364 * key. Abort. */
365 ERROR("Error loading '%s'\n", keys[i].fn);
366 exit(1);
367 }
368
369 /* File does not exist, could not be opened or no filename was
370 * given */
371 if (new_keys) {
372 /* Try to create a new key */
373 NOTICE("Creating new key for '%s'\n", keys[i].desc);
374 if (!key_create(&keys[i], key_alg)) {
375 ERROR("Error creating key '%s'\n", keys[i].desc);
Juan Castillo6f971622014-10-21 11:30:42 +0100376 exit(1);
377 }
Juan Castilloccbf8902015-06-01 16:34:23 +0100378 } else {
379 if (err_code == KEY_ERR_OPEN) {
380 ERROR("Error opening '%s'\n", keys[i].fn);
381 } else {
382 ERROR("Key '%s' not specified\n", keys[i].desc);
383 }
384 exit(1);
Juan Castillo6f971622014-10-21 11:30:42 +0100385 }
386 }
387
Juan Castillo55e291a2015-06-12 11:27:59 +0100388 /* Create the certificates */
389 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo6f971622014-10-21 11:30:42 +0100390
Juan Castillo55e291a2015-06-12 11:27:59 +0100391 cert = &certs[i];
Juan Castillo6f971622014-10-21 11:30:42 +0100392
Juan Castillo55e291a2015-06-12 11:27:59 +0100393 /* Create a new stack of extensions. This stack will be used
394 * to create the certificate */
Juan Castillo6f971622014-10-21 11:30:42 +0100395 CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
Juan Castillo55e291a2015-06-12 11:27:59 +0100396
397 for (j = 0 ; j < cert->num_ext ; j++) {
398
399 ext = &extensions[cert->ext[j]];
400
401 /* Get OpenSSL internal ID for this extension */
402 CHECK_OID(ext_nid, ext->oid);
403
404 /*
405 * Three types of extensions are currently supported:
406 * - EXT_TYPE_NVCOUNTER
407 * - EXT_TYPE_HASH
408 * - EXT_TYPE_PKEY
409 */
410 switch (ext->type) {
411 case EXT_TYPE_NVCOUNTER:
Yatharth Kocharf16db562016-06-22 14:49:27 +0100412 if (ext->arg) {
413 nvctr = atoi(ext->arg);
414 CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
Juan Castillo96103d52016-01-22 11:05:24 +0000415 EXT_CRIT, nvctr));
Yatharth Kocharf16db562016-06-22 14:49:27 +0100416 }
Juan Castillo55e291a2015-06-12 11:27:59 +0100417 break;
418 case EXT_TYPE_HASH:
Juan Castillo96103d52016-01-22 11:05:24 +0000419 if (ext->arg == NULL) {
Yatharth Kocharcebe1f22015-08-21 15:30:55 +0100420 if (ext->optional) {
421 /* Include a hash filled with zeros */
422 memset(md, 0x0, SHA256_DIGEST_LENGTH);
423 } else {
424 /* Do not include this hash in the certificate */
425 break;
426 }
427 } else {
428 /* Calculate the hash of the file */
Juan Castillo96103d52016-01-22 11:05:24 +0000429 if (!sha_file(ext->arg, md)) {
Yatharth Kocharcebe1f22015-08-21 15:30:55 +0100430 ERROR("Cannot calculate hash of %s\n",
Juan Castillo96103d52016-01-22 11:05:24 +0000431 ext->arg);
Yatharth Kocharcebe1f22015-08-21 15:30:55 +0100432 exit(1);
433 }
Juan Castillo55e291a2015-06-12 11:27:59 +0100434 }
435 CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
436 EXT_CRIT, md_info, md,
437 SHA256_DIGEST_LENGTH));
438 break;
439 case EXT_TYPE_PKEY:
440 CHECK_NULL(cert_ext, ext_new_key(ext_nid,
Juan Castillo96103d52016-01-22 11:05:24 +0000441 EXT_CRIT, keys[ext->attr.key].key));
Juan Castillo55e291a2015-06-12 11:27:59 +0100442 break;
443 default:
Juan Castillo96103d52016-01-22 11:05:24 +0000444 ERROR("Unknown extension type '%d' in %s\n",
445 ext->type, cert->cn);
Juan Castillo55e291a2015-06-12 11:27:59 +0100446 exit(1);
447 }
448
449 /* Push the extension into the stack */
450 sk_X509_EXTENSION_push(sk, cert_ext);
Juan Castillo6f971622014-10-21 11:30:42 +0100451 }
Juan Castillo6f971622014-10-21 11:30:42 +0100452
Juan Castillo55e291a2015-06-12 11:27:59 +0100453 /* Create certificate. Signed with ROT key */
Juan Castillodfc90e22015-07-08 12:11:38 +0100454 if (cert->fn && !cert_new(cert, VAL_DAYS, 0, sk)) {
Juan Castillo55e291a2015-06-12 11:27:59 +0100455 ERROR("Cannot create %s\n", cert->cn);
Juan Castillo6f971622014-10-21 11:30:42 +0100456 exit(1);
457 }
458
459 sk_X509_EXTENSION_free(sk);
460 }
461
Juan Castillo6f971622014-10-21 11:30:42 +0100462
463 /* Print the certificates */
464 if (print_cert) {
Juan Castillo55e291a2015-06-12 11:27:59 +0100465 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo6f971622014-10-21 11:30:42 +0100466 if (!certs[i].x) {
467 continue;
468 }
469 printf("\n\n=====================================\n\n");
470 X509_print_fp(stdout, certs[i].x);
471 }
472 }
473
474 /* Save created certificates to files */
Juan Castillo55e291a2015-06-12 11:27:59 +0100475 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo6f971622014-10-21 11:30:42 +0100476 if (certs[i].x && certs[i].fn) {
477 file = fopen(certs[i].fn, "w");
478 if (file != NULL) {
479 i2d_X509_fp(file, certs[i].x);
480 fclose(file);
481 } else {
482 ERROR("Cannot create file %s\n", certs[i].fn);
483 }
484 }
485 }
486
487 /* Save keys */
488 if (save_keys) {
Juan Castillo55e291a2015-06-12 11:27:59 +0100489 for (i = 0 ; i < num_keys ; i++) {
Juan Castillo6f971622014-10-21 11:30:42 +0100490 if (!key_store(&keys[i])) {
491 ERROR("Cannot save %s\n", keys[i].desc);
492 }
493 }
494 }
495
Juan Castillo6f971622014-10-21 11:30:42 +0100496#ifndef OPENSSL_NO_ENGINE
497 ENGINE_cleanup();
498#endif
499 CRYPTO_cleanup_all_ex_data();
500
501 return 0;
502}