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