1 /* 2 * Copyright (c) 2015-2019, 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 #include <stdbool.h> 14 15 #include <openssl/conf.h> 16 #include <openssl/engine.h> 17 #include <openssl/err.h> 18 #include <openssl/pem.h> 19 #include <openssl/sha.h> 20 #include <openssl/x509v3.h> 21 22 #if USE_TBBR_DEFS 23 #include <tbbr_oid.h> 24 #else 25 #include <platform_oid.h> 26 #endif 27 28 #include "cert.h" 29 #include "cmd_opt.h" 30 #include "debug.h" 31 #include "ext.h" 32 #include "key.h" 33 #include "sha.h" 34 #include "tbbr/tbb_cert.h" 35 #include "tbbr/tbb_ext.h" 36 #include "tbbr/tbb_key.h" 37 38 /* 39 * Helper macros to simplify the code. This macro assigns the return value of 40 * the 'fn' function to 'v' and exits if the value is NULL. 41 */ 42 #define CHECK_NULL(v, fn) \ 43 do { \ 44 v = fn; \ 45 if (v == NULL) { \ 46 ERROR("NULL object at %s:%d\n", __FILE__, __LINE__); \ 47 exit(1); \ 48 } \ 49 } while (0) 50 51 /* 52 * This macro assigns the NID corresponding to 'oid' to 'v' and exits if the 53 * NID is undefined. 54 */ 55 #define CHECK_OID(v, oid) \ 56 do { \ 57 v = OBJ_txt2nid(oid); \ 58 if (v == NID_undef) { \ 59 ERROR("Cannot find TBB extension %s\n", oid); \ 60 exit(1); \ 61 } \ 62 } while (0) 63 64 #define MAX_FILENAME_LEN 1024 65 #define VAL_DAYS 7300 66 #define ID_TO_BIT_MASK(id) (1 << id) 67 #define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0]))) 68 #define HELP_OPT_MAX_LEN 128 69 70 /* Global options */ 71 static int key_alg; 72 static int hash_alg; 73 static int key_size; 74 static int new_keys; 75 static int save_keys; 76 static int print_cert; 77 78 /* Info messages created in the Makefile */ 79 extern const char build_msg[]; 80 extern const char platform_msg[]; 81 82 83 static char *strdup(const char *str) 84 { 85 int n = strlen(str) + 1; 86 char *dup = malloc(n); 87 if (dup) { 88 strcpy(dup, str); 89 } 90 return dup; 91 } 92 93 static const char *key_algs_str[] = { 94 [KEY_ALG_RSA] = "rsa", 95 #ifndef OPENSSL_NO_EC 96 [KEY_ALG_ECDSA] = "ecdsa" 97 #endif /* OPENSSL_NO_EC */ 98 }; 99 100 static const char *hash_algs_str[] = { 101 [HASH_ALG_SHA256] = "sha256", 102 [HASH_ALG_SHA384] = "sha384", 103 [HASH_ALG_SHA512] = "sha512", 104 }; 105 106 static void print_help(const char *cmd, const struct option *long_opt) 107 { 108 int rem, i = 0; 109 const struct option *opt; 110 char line[HELP_OPT_MAX_LEN]; 111 char *p; 112 113 assert(cmd != NULL); 114 assert(long_opt != NULL); 115 116 printf("\n\n"); 117 printf("The certificate generation tool loads the binary images and\n" 118 "optionally the RSA keys, and outputs the key and content\n" 119 "certificates properly signed to implement the chain of trust.\n" 120 "If keys are provided, they must be in PEM format.\n" 121 "Certificates are generated in DER format.\n"); 122 printf("\n"); 123 printf("Usage:\n"); 124 printf("\t%s [OPTIONS]\n\n", cmd); 125 126 printf("Available options:\n"); 127 opt = long_opt; 128 while (opt->name) { 129 p = line; 130 rem = HELP_OPT_MAX_LEN; 131 if (isalpha(opt->val)) { 132 /* Short format */ 133 sprintf(p, "-%c,", (char)opt->val); 134 p += 3; 135 rem -= 3; 136 } 137 snprintf(p, rem, "--%s %s", opt->name, 138 (opt->has_arg == required_argument) ? "<arg>" : ""); 139 printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i)); 140 opt++; 141 i++; 142 } 143 printf("\n"); 144 } 145 146 static int get_key_alg(const char *key_alg_str) 147 { 148 int i; 149 150 for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) { 151 if (0 == strcmp(key_alg_str, key_algs_str[i])) { 152 return i; 153 } 154 } 155 156 return -1; 157 } 158 159 static int get_key_size(const char *key_size_str) 160 { 161 char *end; 162 long key_size; 163 164 key_size = strtol(key_size_str, &end, 10); 165 if (*end != '\0') 166 return -1; 167 168 return key_size; 169 } 170 171 static int get_hash_alg(const char *hash_alg_str) 172 { 173 int i; 174 175 for (i = 0 ; i < NUM_ELEM(hash_algs_str) ; i++) { 176 if (0 == strcmp(hash_alg_str, hash_algs_str[i])) { 177 return i; 178 } 179 } 180 181 return -1; 182 } 183 184 static void check_cmd_params(void) 185 { 186 cert_t *cert; 187 ext_t *ext; 188 key_t *key; 189 int i, j; 190 bool valid_size; 191 192 /* Only save new keys */ 193 if (save_keys && !new_keys) { 194 ERROR("Only new keys can be saved to disk\n"); 195 exit(1); 196 } 197 198 /* Validate key-size */ 199 valid_size = false; 200 for (i = 0; i < KEY_SIZE_MAX_NUM; i++) { 201 if (key_size == KEY_SIZES[key_alg][i]) { 202 valid_size = true; 203 break; 204 } 205 } 206 if (!valid_size) { 207 ERROR("'%d' is not a valid key size for '%s'\n", 208 key_size, key_algs_str[key_alg]); 209 NOTICE("Valid sizes are: "); 210 for (i = 0; i < KEY_SIZE_MAX_NUM && 211 KEY_SIZES[key_alg][i] != 0; i++) { 212 printf("%d ", KEY_SIZES[key_alg][i]); 213 } 214 printf("\n"); 215 exit(1); 216 } 217 218 /* Check that all required options have been specified in the 219 * command line */ 220 for (i = 0; i < num_certs; i++) { 221 cert = &certs[i]; 222 if (cert->fn == NULL) { 223 /* Certificate not requested. Skip to the next one */ 224 continue; 225 } 226 227 /* Check that all parameters required to create this certificate 228 * have been specified in the command line */ 229 for (j = 0; j < cert->num_ext; j++) { 230 ext = &extensions[cert->ext[j]]; 231 switch (ext->type) { 232 case EXT_TYPE_NVCOUNTER: 233 /* Counter value must be specified */ 234 if ((!ext->optional) && (ext->arg == NULL)) { 235 ERROR("Value for '%s' not specified\n", 236 ext->ln); 237 exit(1); 238 } 239 break; 240 case EXT_TYPE_PKEY: 241 /* Key filename must be specified */ 242 key = &keys[ext->attr.key]; 243 if (!new_keys && key->fn == NULL) { 244 ERROR("Key '%s' required by '%s' not " 245 "specified\n", key->desc, 246 cert->cn); 247 exit(1); 248 } 249 break; 250 case EXT_TYPE_HASH: 251 /* 252 * Binary image must be specified 253 * unless it is explicitly made optional. 254 */ 255 if ((!ext->optional) && (ext->arg == NULL)) { 256 ERROR("Image for '%s' not specified\n", 257 ext->ln); 258 exit(1); 259 } 260 break; 261 default: 262 ERROR("Unknown extension type '%d' in '%s'\n", 263 ext->type, ext->ln); 264 exit(1); 265 break; 266 } 267 } 268 } 269 } 270 271 /* Common command line options */ 272 static const cmd_opt_t common_cmd_opt[] = { 273 { 274 { "help", no_argument, NULL, 'h' }, 275 "Print this message and exit" 276 }, 277 { 278 { "key-alg", required_argument, NULL, 'a' }, 279 "Key algorithm: 'rsa' (default)- RSAPSS scheme as per PKCS#1 v2.1, 'ecdsa'" 280 }, 281 { 282 { "key-size", required_argument, NULL, 'b' }, 283 "Key size (for supported algorithms)." 284 }, 285 { 286 { "hash-alg", required_argument, NULL, 's' }, 287 "Hash algorithm : 'sha256' (default), 'sha384', 'sha512'" 288 }, 289 { 290 { "save-keys", no_argument, NULL, 'k' }, 291 "Save key pairs into files. Filenames must be provided" 292 }, 293 { 294 { "new-keys", no_argument, NULL, 'n' }, 295 "Generate new key pairs if no key files are provided" 296 }, 297 { 298 { "print-cert", no_argument, NULL, 'p' }, 299 "Print the certificates in the standard output" 300 } 301 }; 302 303 int main(int argc, char *argv[]) 304 { 305 STACK_OF(X509_EXTENSION) * sk; 306 X509_EXTENSION *cert_ext = NULL; 307 ext_t *ext; 308 key_t *key; 309 cert_t *cert; 310 FILE *file; 311 int i, j, ext_nid, nvctr; 312 int c, opt_idx = 0; 313 const struct option *cmd_opt; 314 const char *cur_opt; 315 unsigned int err_code; 316 unsigned char md[SHA512_DIGEST_LENGTH]; 317 unsigned int md_len; 318 const EVP_MD *md_info; 319 320 NOTICE("CoT Generation Tool: %s\n", build_msg); 321 NOTICE("Target platform: %s\n", platform_msg); 322 323 /* Set default options */ 324 key_alg = KEY_ALG_RSA; 325 hash_alg = HASH_ALG_SHA256; 326 key_size = -1; 327 328 /* Add common command line options */ 329 for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) { 330 cmd_opt_add(&common_cmd_opt[i]); 331 } 332 333 /* Initialize the certificates */ 334 if (cert_init() != 0) { 335 ERROR("Cannot initialize certificates\n"); 336 exit(1); 337 } 338 339 /* Initialize the keys */ 340 if (key_init() != 0) { 341 ERROR("Cannot initialize keys\n"); 342 exit(1); 343 } 344 345 /* Initialize the new types and register OIDs for the extensions */ 346 if (ext_init() != 0) { 347 ERROR("Cannot initialize TBB extensions\n"); 348 exit(1); 349 } 350 351 /* Get the command line options populated during the initialization */ 352 cmd_opt = cmd_opt_get_array(); 353 354 while (1) { 355 /* getopt_long stores the option index here. */ 356 c = getopt_long(argc, argv, "a:b:hknps:", cmd_opt, &opt_idx); 357 358 /* Detect the end of the options. */ 359 if (c == -1) { 360 break; 361 } 362 363 switch (c) { 364 case 'a': 365 key_alg = get_key_alg(optarg); 366 if (key_alg < 0) { 367 ERROR("Invalid key algorithm '%s'\n", optarg); 368 exit(1); 369 } 370 break; 371 case 'b': 372 key_size = get_key_size(optarg); 373 if (key_size <= 0) { 374 ERROR("Invalid key size '%s'\n", optarg); 375 exit(1); 376 } 377 break; 378 case 'h': 379 print_help(argv[0], cmd_opt); 380 exit(0); 381 case 'k': 382 save_keys = 1; 383 break; 384 case 'n': 385 new_keys = 1; 386 break; 387 case 'p': 388 print_cert = 1; 389 break; 390 case 's': 391 hash_alg = get_hash_alg(optarg); 392 if (hash_alg < 0) { 393 ERROR("Invalid hash algorithm '%s'\n", optarg); 394 exit(1); 395 } 396 break; 397 case CMD_OPT_EXT: 398 cur_opt = cmd_opt_get_name(opt_idx); 399 ext = ext_get_by_opt(cur_opt); 400 ext->arg = strdup(optarg); 401 break; 402 case CMD_OPT_KEY: 403 cur_opt = cmd_opt_get_name(opt_idx); 404 key = key_get_by_opt(cur_opt); 405 key->fn = strdup(optarg); 406 break; 407 case CMD_OPT_CERT: 408 cur_opt = cmd_opt_get_name(opt_idx); 409 cert = cert_get_by_opt(cur_opt); 410 cert->fn = strdup(optarg); 411 break; 412 case '?': 413 default: 414 print_help(argv[0], cmd_opt); 415 exit(1); 416 } 417 } 418 419 /* Select a reasonable default key-size */ 420 if (key_size == -1) { 421 key_size = KEY_SIZES[key_alg][0]; 422 } 423 424 /* Check command line arguments */ 425 check_cmd_params(); 426 427 /* Indicate SHA as image hash algorithm in the certificate 428 * extension */ 429 if (hash_alg == HASH_ALG_SHA384) { 430 md_info = EVP_sha384(); 431 md_len = SHA384_DIGEST_LENGTH; 432 } else if (hash_alg == HASH_ALG_SHA512) { 433 md_info = EVP_sha512(); 434 md_len = SHA512_DIGEST_LENGTH; 435 } else { 436 md_info = EVP_sha256(); 437 md_len = SHA256_DIGEST_LENGTH; 438 } 439 440 /* Load private keys from files (or generate new ones) */ 441 for (i = 0 ; i < num_keys ; i++) { 442 if (!key_new(&keys[i])) { 443 ERROR("Failed to allocate key container\n"); 444 exit(1); 445 } 446 447 /* First try to load the key from disk */ 448 if (key_load(&keys[i], &err_code)) { 449 /* Key loaded successfully */ 450 continue; 451 } 452 453 /* Key not loaded. Check the error code */ 454 if (err_code == KEY_ERR_LOAD) { 455 /* File exists, but it does not contain a valid private 456 * key. Abort. */ 457 ERROR("Error loading '%s'\n", keys[i].fn); 458 exit(1); 459 } 460 461 /* File does not exist, could not be opened or no filename was 462 * given */ 463 if (new_keys) { 464 /* Try to create a new key */ 465 NOTICE("Creating new key for '%s'\n", keys[i].desc); 466 if (!key_create(&keys[i], key_alg, key_size)) { 467 ERROR("Error creating key '%s'\n", keys[i].desc); 468 exit(1); 469 } 470 } else { 471 if (err_code == KEY_ERR_OPEN) { 472 ERROR("Error opening '%s'\n", keys[i].fn); 473 } else { 474 ERROR("Key '%s' not specified\n", keys[i].desc); 475 } 476 exit(1); 477 } 478 } 479 480 /* Create the certificates */ 481 for (i = 0 ; i < num_certs ; i++) { 482 483 cert = &certs[i]; 484 485 /* Create a new stack of extensions. This stack will be used 486 * to create the certificate */ 487 CHECK_NULL(sk, sk_X509_EXTENSION_new_null()); 488 489 for (j = 0 ; j < cert->num_ext ; j++) { 490 491 ext = &extensions[cert->ext[j]]; 492 493 /* Get OpenSSL internal ID for this extension */ 494 CHECK_OID(ext_nid, ext->oid); 495 496 /* 497 * Three types of extensions are currently supported: 498 * - EXT_TYPE_NVCOUNTER 499 * - EXT_TYPE_HASH 500 * - EXT_TYPE_PKEY 501 */ 502 switch (ext->type) { 503 case EXT_TYPE_NVCOUNTER: 504 if (ext->arg) { 505 nvctr = atoi(ext->arg); 506 CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid, 507 EXT_CRIT, nvctr)); 508 } 509 break; 510 case EXT_TYPE_HASH: 511 if (ext->arg == NULL) { 512 if (ext->optional) { 513 /* Include a hash filled with zeros */ 514 memset(md, 0x0, SHA512_DIGEST_LENGTH); 515 } else { 516 /* Do not include this hash in the certificate */ 517 break; 518 } 519 } else { 520 /* Calculate the hash of the file */ 521 if (!sha_file(hash_alg, ext->arg, md)) { 522 ERROR("Cannot calculate hash of %s\n", 523 ext->arg); 524 exit(1); 525 } 526 } 527 CHECK_NULL(cert_ext, ext_new_hash(ext_nid, 528 EXT_CRIT, md_info, md, 529 md_len)); 530 break; 531 case EXT_TYPE_PKEY: 532 CHECK_NULL(cert_ext, ext_new_key(ext_nid, 533 EXT_CRIT, keys[ext->attr.key].key)); 534 break; 535 default: 536 ERROR("Unknown extension type '%d' in %s\n", 537 ext->type, cert->cn); 538 exit(1); 539 } 540 541 /* Push the extension into the stack */ 542 sk_X509_EXTENSION_push(sk, cert_ext); 543 } 544 545 /* Create certificate. Signed with corresponding key */ 546 if (cert->fn && !cert_new(hash_alg, cert, VAL_DAYS, 0, sk)) { 547 ERROR("Cannot create %s\n", cert->cn); 548 exit(1); 549 } 550 551 sk_X509_EXTENSION_free(sk); 552 } 553 554 555 /* Print the certificates */ 556 if (print_cert) { 557 for (i = 0 ; i < num_certs ; i++) { 558 if (!certs[i].x) { 559 continue; 560 } 561 printf("\n\n=====================================\n\n"); 562 X509_print_fp(stdout, certs[i].x); 563 } 564 } 565 566 /* Save created certificates to files */ 567 for (i = 0 ; i < num_certs ; i++) { 568 if (certs[i].x && certs[i].fn) { 569 file = fopen(certs[i].fn, "w"); 570 if (file != NULL) { 571 i2d_X509_fp(file, certs[i].x); 572 fclose(file); 573 } else { 574 ERROR("Cannot create file %s\n", certs[i].fn); 575 } 576 } 577 } 578 579 /* Save keys */ 580 if (save_keys) { 581 for (i = 0 ; i < num_keys ; i++) { 582 if (!key_store(&keys[i])) { 583 ERROR("Cannot save %s\n", keys[i].desc); 584 } 585 } 586 } 587 588 #ifndef OPENSSL_NO_ENGINE 589 ENGINE_cleanup(); 590 #endif 591 CRYPTO_cleanup_all_ex_data(); 592 593 return 0; 594 } 595