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