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