blob: b7ad33fe36804697112ce501b1e4906057c2ae63 [file] [log] [blame]
Juan Castillo11abdcd2014-10-21 11:30:42 +01001/*
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"
Juan Castillo1218dd52015-07-03 16:23:16 +010044#include "cmd_opt.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010045#include "debug.h"
46#include "ext.h"
47#include "key.h"
48#include "platform_oid.h"
49#include "sha.h"
Juan Castilloe6d30e92015-06-12 11:27:59 +010050#include "tbbr/tbb_ext.h"
51#include "tbbr/tbb_cert.h"
52#include "tbbr/tbb_key.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010053
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)
Juan Castillof9f39c32015-06-01 16:34:23 +010083#define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0])))
Juan Castillo11abdcd2014-10-21 11:30:42 +010084
85/* Files */
86enum {
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 */
Juan Castillof9f39c32015-06-01 16:34:23 +0100116static int key_alg;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100117static int new_keys;
118static int save_keys;
119static int print_cert;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100120
Juan Castillo11abdcd2014-10-21 11:30:42 +0100121/* Info messages created in the Makefile */
122extern const char build_msg[];
123extern const char platform_msg[];
124
125
126static 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
Juan Castillof9f39c32015-06-01 16:34:23 +0100136static const char *key_algs_str[] = {
137 [KEY_ALG_RSA] = "rsa",
Juan Castilloa2224ab2015-06-30 13:36:57 +0100138#ifndef OPENSSL_NO_EC
Juan Castillof9f39c32015-06-01 16:34:23 +0100139 [KEY_ALG_ECDSA] = "ecdsa"
Juan Castilloa2224ab2015-06-30 13:36:57 +0100140#endif /* OPENSSL_NO_EC */
Juan Castillof9f39c32015-06-01 16:34:23 +0100141};
142
Juan Castillo1218dd52015-07-03 16:23:16 +0100143static void print_help(const char *cmd, const struct option *long_opt)
Juan Castillo11abdcd2014-10-21 11:30:42 +0100144{
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");
Juan Castillof9f39c32015-06-01 16:34:23 +0100159 printf("-a Key algorithm: rsa (default), ecdsa\n");
Juan Castillo11abdcd2014-10-21 11:30:42 +0100160 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
Juan Castillof9f39c32015-06-01 16:34:23 +0100169static 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
Juan Castillo11abdcd2014-10-21 11:30:42 +0100182static void check_cmd_params(void)
183{
Juan Castillo86958fd2015-07-08 12:11:38 +0100184 cert_t *cert;
185 ext_t *ext;
186 key_t *key;
187 int i, j;
188
Juan Castillof9f39c32015-06-01 16:34:23 +0100189 /* 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
Juan Castillo86958fd2015-07-08 12:11:38 +0100195 /* 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;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100202 }
203
Juan Castillo86958fd2015-07-08 12:11:38 +0100204 /* 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 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100233 }
234 }
235}
236
237int main(int argc, char *argv[])
238{
239 STACK_OF(X509_EXTENSION) * sk = NULL;
Juan Castilloe6d30e92015-06-12 11:27:59 +0100240 X509_EXTENSION *cert_ext = NULL;
241 ext_t *ext = NULL;
Juan Castillo1218dd52015-07-03 16:23:16 +0100242 key_t *key = NULL;
243 cert_t *cert = NULL;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100244 FILE *file = NULL;
Juan Castilloe6d30e92015-06-12 11:27:59 +0100245 int i, j, ext_nid;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100246 int c, opt_idx = 0;
Juan Castillo1218dd52015-07-03 16:23:16 +0100247 const struct option *cmd_opt;
248 const char *cur_opt;
Juan Castillof9f39c32015-06-01 16:34:23 +0100249 unsigned int err_code;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100250 unsigned char md[SHA256_DIGEST_LENGTH];
Juan Castilloac402932015-03-05 14:30:00 +0000251 const EVP_MD *md_info;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100252
253 NOTICE("CoT Generation Tool: %s\n", build_msg);
254 NOTICE("Target platform: %s\n", platform_msg);
255
Juan Castillof9f39c32015-06-01 16:34:23 +0100256 /* Set default options */
257 key_alg = KEY_ALG_RSA;
258
Juan Castillo1218dd52015-07-03 16:23:16 +0100259 /* 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
Juan Castillo11abdcd2014-10-21 11:30:42 +0100287 while (1) {
288 /* getopt_long stores the option index here. */
Juan Castillo1218dd52015-07-03 16:23:16 +0100289 c = getopt_long(argc, argv, "ahknp", cmd_opt, &opt_idx);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100290
291 /* Detect the end of the options. */
292 if (c == -1) {
293 break;
294 }
295
296 switch (c) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100297 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;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100304 case 'h':
Juan Castillo1218dd52015-07-03 16:23:16 +0100305 print_help(argv[0], cmd_opt);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100306 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;
Juan Castillo1218dd52015-07-03 16:23:16 +0100316 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);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100320 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100321 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);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100325 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100326 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);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100330 break;
331 case '?':
332 default:
333 printf("%s\n", optarg);
334 exit(1);
335 }
336 }
337
Juan Castillo11abdcd2014-10-21 11:30:42 +0100338 /* Check command line arguments */
339 check_cmd_params();
340
Juan Castilloac402932015-03-05 14:30:00 +0000341 /* Indicate SHA256 as image hash algorithm in the certificate
342 * extension */
343 md_info = EVP_sha256();
344
Juan Castillo11abdcd2014-10-21 11:30:42 +0100345 /* Load private keys from files (or generate new ones) */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100346 for (i = 0 ; i < num_keys ; i++) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100347 /* 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);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100363 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100364
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);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100372 exit(1);
373 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100374 } 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);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100381 }
382 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100383
Juan Castilloe6d30e92015-06-12 11:27:59 +0100384 /* Create the certificates */
385 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100386
Juan Castilloe6d30e92015-06-12 11:27:59 +0100387 cert = &certs[i];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100388
Juan Castilloe6d30e92015-06-12 11:27:59 +0100389 /* Create a new stack of extensions. This stack will be used
390 * to create the certificate */
Juan Castillo11abdcd2014-10-21 11:30:42 +0100391 CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
Juan Castillo11abdcd2014-10-21 11:30:42 +0100392
Juan Castilloe6d30e92015-06-12 11:27:59 +0100393 for (j = 0 ; j < cert->num_ext ; j++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100394
Juan Castilloe6d30e92015-06-12 11:27:59 +0100395 ext = &extensions[cert->ext[j]];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100396
Juan Castilloe6d30e92015-06-12 11:27:59 +0100397 /* Get OpenSSL internal ID for this extension */
398 CHECK_OID(ext_nid, ext->oid);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100399
Juan Castilloe6d30e92015-06-12 11:27:59 +0100400 /*
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 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100433
Juan Castilloe6d30e92015-06-12 11:27:59 +0100434 /* Push the extension into the stack */
435 sk_X509_EXTENSION_push(sk, cert_ext);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100436 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100437
Juan Castilloe6d30e92015-06-12 11:27:59 +0100438 /* Create certificate. Signed with ROT key */
Juan Castillo86958fd2015-07-08 12:11:38 +0100439 if (cert->fn && !cert_new(cert, VAL_DAYS, 0, sk)) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100440 ERROR("Cannot create %s\n", cert->cn);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100441 exit(1);
442 }
443
444 sk_X509_EXTENSION_free(sk);
445 }
446
Juan Castillo11abdcd2014-10-21 11:30:42 +0100447
448 /* Print the certificates */
449 if (print_cert) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100450 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100451 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 */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100460 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100461 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) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100474 for (i = 0 ; i < num_keys ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100475 if (!key_store(&keys[i])) {
476 ERROR("Cannot save %s\n", keys[i].desc);
477 }
478 }
479 }
480
Juan Castillo11abdcd2014-10-21 11:30:42 +0100481#ifndef OPENSSL_NO_ENGINE
482 ENGINE_cleanup();
483#endif
484 CRYPTO_cleanup_all_ex_data();
485
486 return 0;
487}