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 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 #ifndef OPENSSL_NO_EC 93 [KEY_ALG_ECDSA] = "ecdsa" 94 #endif /* OPENSSL_NO_EC */ 95 }; 96 97 static void print_help(const char *cmd, const struct option *long_opt) 98 { 99 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 107 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"); 114 printf("Usage:\n"); 115 printf("\t%s [OPTIONS]\n\n", cmd); 116 117 printf("Available options:\n"); 118 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++; 133 } 134 printf("\n"); 135 136 exit(0); 137 } 138 139 static 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 152 static void check_cmd_params(void) 153 { 154 cert_t *cert; 155 ext_t *ext; 156 key_t *key; 157 int i, j; 158 159 /* 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 165 /* 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; 172 } 173 174 /* 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) { 179 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; 187 case EXT_TYPE_PKEY: 188 /* Key filename must be specified */ 189 key = &keys[ext->attr.key]; 190 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: 198 /* 199 * Binary image must be specified 200 * unless it is explicitly made optional. 201 */ 202 if ((!ext->optional) && (ext->arg == NULL)) { 203 ERROR("Image for '%s' not specified\n", 204 ext->ln); 205 exit(1); 206 } 207 break; 208 default: 209 ERROR("Unknown extension type '%d' in '%s'\n", 210 ext->type, ext->ln); 211 exit(1); 212 break; 213 } 214 } 215 } 216 } 217 218 /* Common command line options */ 219 static 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 242 int main(int argc, char *argv[]) 243 { 244 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; 250 int i, j, ext_nid, nvctr; 251 int c, opt_idx = 0; 252 const struct option *cmd_opt; 253 const char *cur_opt; 254 unsigned int err_code; 255 unsigned char md[SHA256_DIGEST_LENGTH]; 256 const EVP_MD *md_info; 257 258 NOTICE("CoT Generation Tool: %s\n", build_msg); 259 NOTICE("Target platform: %s\n", platform_msg); 260 261 /* Set default options */ 262 key_alg = KEY_ALG_RSA; 263 264 /* Add common command line options */ 265 for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) { 266 cmd_opt_add(&common_cmd_opt[i]); 267 } 268 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 290 while (1) { 291 /* getopt_long stores the option index here. */ 292 c = getopt_long(argc, argv, "a:hknp", cmd_opt, &opt_idx); 293 294 /* Detect the end of the options. */ 295 if (c == -1) { 296 break; 297 } 298 299 switch (c) { 300 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; 307 case 'h': 308 print_help(argv[0], cmd_opt); 309 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; 319 case CMD_OPT_EXT: 320 cur_opt = cmd_opt_get_name(opt_idx); 321 ext = ext_get_by_opt(cur_opt); 322 ext->arg = strdup(optarg); 323 break; 324 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); 328 break; 329 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); 333 break; 334 case '?': 335 default: 336 print_help(argv[0], cmd_opt); 337 exit(1); 338 } 339 } 340 341 /* Check command line arguments */ 342 check_cmd_params(); 343 344 /* Indicate SHA256 as image hash algorithm in the certificate 345 * extension */ 346 md_info = EVP_sha256(); 347 348 /* Load private keys from files (or generate new ones) */ 349 for (i = 0 ; i < num_keys ; i++) { 350 if (!key_new(&keys[i])) { 351 ERROR("Failed to allocate key container\n"); 352 exit(1); 353 } 354 355 /* First try to load the key from disk */ 356 if (key_load(&keys[i], &err_code)) { 357 /* Key loaded successfully */ 358 continue; 359 } 360 361 /* Key not loaded. Check the error code */ 362 if (err_code == KEY_ERR_LOAD) { 363 /* 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); 376 exit(1); 377 } 378 } 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); 385 } 386 } 387 388 /* Create the certificates */ 389 for (i = 0 ; i < num_certs ; i++) { 390 391 cert = &certs[i]; 392 393 /* Create a new stack of extensions. This stack will be used 394 * to create the certificate */ 395 CHECK_NULL(sk, sk_X509_EXTENSION_new_null()); 396 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: 412 if (ext->arg) { 413 nvctr = atoi(ext->arg); 414 CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid, 415 EXT_CRIT, nvctr)); 416 } 417 break; 418 case EXT_TYPE_HASH: 419 if (ext->arg == NULL) { 420 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 */ 429 if (!sha_file(ext->arg, md)) { 430 ERROR("Cannot calculate hash of %s\n", 431 ext->arg); 432 exit(1); 433 } 434 } 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, 441 EXT_CRIT, keys[ext->attr.key].key)); 442 break; 443 default: 444 ERROR("Unknown extension type '%d' in %s\n", 445 ext->type, cert->cn); 446 exit(1); 447 } 448 449 /* Push the extension into the stack */ 450 sk_X509_EXTENSION_push(sk, cert_ext); 451 } 452 453 /* Create certificate. Signed with ROT key */ 454 if (cert->fn && !cert_new(cert, VAL_DAYS, 0, sk)) { 455 ERROR("Cannot create %s\n", cert->cn); 456 exit(1); 457 } 458 459 sk_X509_EXTENSION_free(sk); 460 } 461 462 463 /* Print the certificates */ 464 if (print_cert) { 465 for (i = 0 ; i < num_certs ; i++) { 466 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 */ 475 for (i = 0 ; i < num_certs ; i++) { 476 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) { 489 for (i = 0 ; i < num_keys ; i++) { 490 if (!key_store(&keys[i])) { 491 ERROR("Cannot save %s\n", keys[i].desc); 492 } 493 } 494 } 495 496 #ifndef OPENSSL_NO_ENGINE 497 ENGINE_cleanup(); 498 #endif 499 CRYPTO_cleanup_all_ex_data(); 500 501 return 0; 502 } 503