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