blob: df59961b0ac18b07c386355e853f031199fd3a56 [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_cert.h"
Isla Mitchell2a4b4b712017-07-11 14:54:08 +010034#include "tbbr/tbb_ext.h"
Juan Castillo55e291a2015-06-12 11:27:59 +010035#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",
Soby Mathewa8eb2862017-08-31 11:50:29 +010092 [KEY_ALG_RSA_1_5] = "rsa_1_5",
Juan Castilloed2a76e2015-06-30 13:36:57 +010093#ifndef OPENSSL_NO_EC
Juan Castilloccbf8902015-06-01 16:34:23 +010094 [KEY_ALG_ECDSA] = "ecdsa"
Juan Castilloed2a76e2015-06-30 13:36:57 +010095#endif /* OPENSSL_NO_EC */
Juan Castilloccbf8902015-06-01 16:34:23 +010096};
97
Juan Castilload2c1a92015-07-03 16:23:16 +010098static void print_help(const char *cmd, const struct option *long_opt)
Juan Castillo6f971622014-10-21 11:30:42 +010099{
Juan Castillo159807e2015-12-15 16:37:57 +0000100 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
Juan Castillo6f971622014-10-21 11:30:42 +0100108 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");
Juan Castillo159807e2015-12-15 16:37:57 +0000115 printf("Usage:\n");
116 printf("\t%s [OPTIONS]\n\n", cmd);
117
118 printf("Available options:\n");
Juan Castillo159807e2015-12-15 16:37:57 +0000119 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++;
Juan Castillo6f971622014-10-21 11:30:42 +0100134 }
135 printf("\n");
Juan Castillo6f971622014-10-21 11:30:42 +0100136
137 exit(0);
138}
139
Juan Castilloccbf8902015-06-01 16:34:23 +0100140static 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
Juan Castillo6f971622014-10-21 11:30:42 +0100153static void check_cmd_params(void)
154{
Juan Castillodfc90e22015-07-08 12:11:38 +0100155 cert_t *cert;
156 ext_t *ext;
157 key_t *key;
158 int i, j;
159
Juan Castilloccbf8902015-06-01 16:34:23 +0100160 /* 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
Juan Castillodfc90e22015-07-08 12:11:38 +0100166 /* 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;
Juan Castillo6f971622014-10-21 11:30:42 +0100173 }
174
Juan Castillodfc90e22015-07-08 12:11:38 +0100175 /* 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) {
Juan Castillo96103d52016-01-22 11:05:24 +0000180 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;
Juan Castillodfc90e22015-07-08 12:11:38 +0100188 case EXT_TYPE_PKEY:
189 /* Key filename must be specified */
Juan Castillo96103d52016-01-22 11:05:24 +0000190 key = &keys[ext->attr.key];
Juan Castillodfc90e22015-07-08 12:11:38 +0100191 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:
Yatharth Kocharcebe1f22015-08-21 15:30:55 +0100199 /*
200 * Binary image must be specified
201 * unless it is explicitly made optional.
202 */
Juan Castillo96103d52016-01-22 11:05:24 +0000203 if ((!ext->optional) && (ext->arg == NULL)) {
Juan Castillodfc90e22015-07-08 12:11:38 +0100204 ERROR("Image for '%s' not specified\n",
205 ext->ln);
206 exit(1);
207 }
208 break;
209 default:
Juan Castillo96103d52016-01-22 11:05:24 +0000210 ERROR("Unknown extension type '%d' in '%s'\n",
211 ext->type, ext->ln);
Juan Castillodfc90e22015-07-08 12:11:38 +0100212 exit(1);
213 break;
214 }
Juan Castillo6f971622014-10-21 11:30:42 +0100215 }
216 }
217}
218
Juan Castillo159807e2015-12-15 16:37:57 +0000219/* Common command line options */
220static 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' },
Soby Mathewa8eb2862017-08-31 11:50:29 +0100227 "Key algorithm: 'rsa' (default) - RSAPSS scheme as per \
228PKCS#1 v2.1, 'rsa_1_5' - RSA PKCS#1 v1.5, 'ecdsa'"
Juan Castillo159807e2015-12-15 16:37:57 +0000229 },
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
Juan Castillo6f971622014-10-21 11:30:42 +0100244int main(int argc, char *argv[])
245{
Masahiro Yamadac893c732017-02-06 19:47:44 +0900246 STACK_OF(X509_EXTENSION) * sk;
247 X509_EXTENSION *cert_ext;
248 ext_t *ext;
249 key_t *key;
250 cert_t *cert;
251 FILE *file;
Juan Castillo96103d52016-01-22 11:05:24 +0000252 int i, j, ext_nid, nvctr;
Juan Castillo6f971622014-10-21 11:30:42 +0100253 int c, opt_idx = 0;
Juan Castilload2c1a92015-07-03 16:23:16 +0100254 const struct option *cmd_opt;
255 const char *cur_opt;
Juan Castilloccbf8902015-06-01 16:34:23 +0100256 unsigned int err_code;
Juan Castillo6f971622014-10-21 11:30:42 +0100257 unsigned char md[SHA256_DIGEST_LENGTH];
Juan Castilloc3da66b2015-03-05 14:30:00 +0000258 const EVP_MD *md_info;
Juan Castillo6f971622014-10-21 11:30:42 +0100259
260 NOTICE("CoT Generation Tool: %s\n", build_msg);
261 NOTICE("Target platform: %s\n", platform_msg);
262
Juan Castilloccbf8902015-06-01 16:34:23 +0100263 /* Set default options */
264 key_alg = KEY_ALG_RSA;
265
Juan Castilload2c1a92015-07-03 16:23:16 +0100266 /* Add common command line options */
Juan Castillo159807e2015-12-15 16:37:57 +0000267 for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
268 cmd_opt_add(&common_cmd_opt[i]);
269 }
Juan Castilload2c1a92015-07-03 16:23:16 +0100270
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
Juan Castillo6f971622014-10-21 11:30:42 +0100292 while (1) {
293 /* getopt_long stores the option index here. */
Juan Castillo159807e2015-12-15 16:37:57 +0000294 c = getopt_long(argc, argv, "a:hknp", cmd_opt, &opt_idx);
Juan Castillo6f971622014-10-21 11:30:42 +0100295
296 /* Detect the end of the options. */
297 if (c == -1) {
298 break;
299 }
300
301 switch (c) {
Juan Castilloccbf8902015-06-01 16:34:23 +0100302 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;
Juan Castillo6f971622014-10-21 11:30:42 +0100309 case 'h':
Juan Castilload2c1a92015-07-03 16:23:16 +0100310 print_help(argv[0], cmd_opt);
Juan Castillo6f971622014-10-21 11:30:42 +0100311 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;
Juan Castilload2c1a92015-07-03 16:23:16 +0100321 case CMD_OPT_EXT:
322 cur_opt = cmd_opt_get_name(opt_idx);
323 ext = ext_get_by_opt(cur_opt);
Juan Castillo96103d52016-01-22 11:05:24 +0000324 ext->arg = strdup(optarg);
Juan Castillo6f971622014-10-21 11:30:42 +0100325 break;
Juan Castilload2c1a92015-07-03 16:23:16 +0100326 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);
Juan Castillo6f971622014-10-21 11:30:42 +0100330 break;
Juan Castilload2c1a92015-07-03 16:23:16 +0100331 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);
Juan Castillo6f971622014-10-21 11:30:42 +0100335 break;
336 case '?':
337 default:
Juan Castillo159807e2015-12-15 16:37:57 +0000338 print_help(argv[0], cmd_opt);
Juan Castillo6f971622014-10-21 11:30:42 +0100339 exit(1);
340 }
341 }
342
Juan Castillo6f971622014-10-21 11:30:42 +0100343 /* Check command line arguments */
344 check_cmd_params();
345
Juan Castilloc3da66b2015-03-05 14:30:00 +0000346 /* Indicate SHA256 as image hash algorithm in the certificate
347 * extension */
348 md_info = EVP_sha256();
349
Juan Castillo6f971622014-10-21 11:30:42 +0100350 /* Load private keys from files (or generate new ones) */
Juan Castillo55e291a2015-06-12 11:27:59 +0100351 for (i = 0 ; i < num_keys ; i++) {
Masahiro Yamada762f1eb2017-02-06 21:15:01 +0900352 if (!key_new(&keys[i])) {
353 ERROR("Failed to allocate key container\n");
354 exit(1);
355 }
356
Juan Castilloccbf8902015-06-01 16:34:23 +0100357 /* First try to load the key from disk */
358 if (key_load(&keys[i], &err_code)) {
359 /* Key loaded successfully */
360 continue;
Juan Castillo6f971622014-10-21 11:30:42 +0100361 }
Juan Castilloccbf8902015-06-01 16:34:23 +0100362
363 /* Key not loaded. Check the error code */
Masahiro Yamada762f1eb2017-02-06 21:15:01 +0900364 if (err_code == KEY_ERR_LOAD) {
Juan Castilloccbf8902015-06-01 16:34:23 +0100365 /* 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);
Juan Castillo6f971622014-10-21 11:30:42 +0100378 exit(1);
379 }
Juan Castilloccbf8902015-06-01 16:34:23 +0100380 } 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);
Juan Castillo6f971622014-10-21 11:30:42 +0100387 }
388 }
389
Juan Castillo55e291a2015-06-12 11:27:59 +0100390 /* Create the certificates */
391 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo6f971622014-10-21 11:30:42 +0100392
Juan Castillo55e291a2015-06-12 11:27:59 +0100393 cert = &certs[i];
Juan Castillo6f971622014-10-21 11:30:42 +0100394
Juan Castillo55e291a2015-06-12 11:27:59 +0100395 /* Create a new stack of extensions. This stack will be used
396 * to create the certificate */
Juan Castillo6f971622014-10-21 11:30:42 +0100397 CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
Juan Castillo55e291a2015-06-12 11:27:59 +0100398
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:
Yatharth Kocharf16db562016-06-22 14:49:27 +0100414 if (ext->arg) {
415 nvctr = atoi(ext->arg);
416 CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
Juan Castillo96103d52016-01-22 11:05:24 +0000417 EXT_CRIT, nvctr));
Yatharth Kocharf16db562016-06-22 14:49:27 +0100418 }
Juan Castillo55e291a2015-06-12 11:27:59 +0100419 break;
420 case EXT_TYPE_HASH:
Juan Castillo96103d52016-01-22 11:05:24 +0000421 if (ext->arg == NULL) {
Yatharth Kocharcebe1f22015-08-21 15:30:55 +0100422 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 */
Juan Castillo96103d52016-01-22 11:05:24 +0000431 if (!sha_file(ext->arg, md)) {
Yatharth Kocharcebe1f22015-08-21 15:30:55 +0100432 ERROR("Cannot calculate hash of %s\n",
Juan Castillo96103d52016-01-22 11:05:24 +0000433 ext->arg);
Yatharth Kocharcebe1f22015-08-21 15:30:55 +0100434 exit(1);
435 }
Juan Castillo55e291a2015-06-12 11:27:59 +0100436 }
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,
Juan Castillo96103d52016-01-22 11:05:24 +0000443 EXT_CRIT, keys[ext->attr.key].key));
Juan Castillo55e291a2015-06-12 11:27:59 +0100444 break;
445 default:
Juan Castillo96103d52016-01-22 11:05:24 +0000446 ERROR("Unknown extension type '%d' in %s\n",
447 ext->type, cert->cn);
Juan Castillo55e291a2015-06-12 11:27:59 +0100448 exit(1);
449 }
450
451 /* Push the extension into the stack */
452 sk_X509_EXTENSION_push(sk, cert_ext);
Juan Castillo6f971622014-10-21 11:30:42 +0100453 }
Juan Castillo6f971622014-10-21 11:30:42 +0100454
Soby Mathewa8eb2862017-08-31 11:50:29 +0100455 /* Create certificate. Signed with corresponding key */
456 if (cert->fn && !cert_new(key_alg, cert, VAL_DAYS, 0, sk)) {
Juan Castillo55e291a2015-06-12 11:27:59 +0100457 ERROR("Cannot create %s\n", cert->cn);
Juan Castillo6f971622014-10-21 11:30:42 +0100458 exit(1);
459 }
460
461 sk_X509_EXTENSION_free(sk);
462 }
463
Juan Castillo6f971622014-10-21 11:30:42 +0100464
465 /* Print the certificates */
466 if (print_cert) {
Juan Castillo55e291a2015-06-12 11:27:59 +0100467 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo6f971622014-10-21 11:30:42 +0100468 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 */
Juan Castillo55e291a2015-06-12 11:27:59 +0100477 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo6f971622014-10-21 11:30:42 +0100478 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) {
Juan Castillo55e291a2015-06-12 11:27:59 +0100491 for (i = 0 ; i < num_keys ; i++) {
Juan Castillo6f971622014-10-21 11:30:42 +0100492 if (!key_store(&keys[i])) {
493 ERROR("Cannot save %s\n", keys[i].desc);
494 }
495 }
496 }
497
Juan Castillo6f971622014-10-21 11:30:42 +0100498#ifndef OPENSSL_NO_ENGINE
499 ENGINE_cleanup();
500#endif
501 CRYPTO_cleanup_all_ex_data();
502
503 return 0;
504}