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