1 /* 2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <getopt.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include <openssl/conf.h> 37 #include <openssl/engine.h> 38 #include <openssl/err.h> 39 #include <openssl/pem.h> 40 #include <openssl/sha.h> 41 #include <openssl/x509v3.h> 42 43 #include "cert.h" 44 #include "cmd_opt.h" 45 #include "debug.h" 46 #include "ext.h" 47 #include "key.h" 48 #include "platform_oid.h" 49 #include "sha.h" 50 #include "tbbr/tbb_ext.h" 51 #include "tbbr/tbb_cert.h" 52 #include "tbbr/tbb_key.h" 53 54 /* 55 * Helper macros to simplify the code. This macro assigns the return value of 56 * the 'fn' function to 'v' and exits if the value is NULL. 57 */ 58 #define CHECK_NULL(v, fn) \ 59 do { \ 60 v = fn; \ 61 if (v == NULL) { \ 62 ERROR("NULL object at %s:%d\n", __FILE__, __LINE__); \ 63 exit(1); \ 64 } \ 65 } while (0) 66 67 /* 68 * This macro assigns the NID corresponding to 'oid' to 'v' and exits if the 69 * NID is undefined. 70 */ 71 #define CHECK_OID(v, oid) \ 72 do { \ 73 v = OBJ_txt2nid(oid); \ 74 if (v == NID_undef) { \ 75 ERROR("Cannot find TBB extension %s\n", oid); \ 76 exit(1); \ 77 } \ 78 } while (0) 79 80 #define MAX_FILENAME_LEN 1024 81 #define VAL_DAYS 7300 82 #define ID_TO_BIT_MASK(id) (1 << id) 83 #define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0]))) 84 85 /* Files */ 86 enum { 87 /* Image file names (inputs) */ 88 BL2_ID = 0, 89 SCP_BL2_ID, 90 BL31_ID, 91 BL32_ID, 92 BL33_ID, 93 /* Certificate file names (outputs) */ 94 TRUSTED_BOOT_FW_CERT_ID, 95 TRUSTED_KEY_CERT_ID, 96 SCP_FW_KEY_CERT_ID, 97 SCP_FW_CONTENT_CERT_ID, 98 SOC_FW_KEY_CERT_ID, 99 SOC_FW_CONTENT_CERT_ID, 100 TRUSTED_OS_FW_KEY_CERT_ID, 101 TRUSTED_OS_FW_CONTENT_CERT_ID, 102 NON_TRUSTED_FW_KEY_CERT_ID, 103 NON_TRUSTED_FW_CONTENT_CERT_ID, 104 /* Key file names (input/output) */ 105 ROT_KEY_ID, 106 TRUSTED_WORLD_KEY_ID, 107 NON_TRUSTED_WORLD_KEY_ID, 108 SCP_BL2_KEY_ID, 109 BL31_KEY_ID, 110 BL32_KEY_ID, 111 BL33_KEY_ID, 112 NUM_OPTS 113 }; 114 115 /* Global options */ 116 static int key_alg; 117 static int new_keys; 118 static int save_keys; 119 static int print_cert; 120 121 /* Info messages created in the Makefile */ 122 extern const char build_msg[]; 123 extern const char platform_msg[]; 124 125 126 static char *strdup(const char *str) 127 { 128 int n = strlen(str) + 1; 129 char *dup = malloc(n); 130 if (dup) { 131 strcpy(dup, str); 132 } 133 return dup; 134 } 135 136 static const char *key_algs_str[] = { 137 [KEY_ALG_RSA] = "rsa", 138 #ifndef OPENSSL_NO_EC 139 [KEY_ALG_ECDSA] = "ecdsa" 140 #endif /* OPENSSL_NO_EC */ 141 }; 142 143 static void print_help(const char *cmd, const struct option *long_opt) 144 { 145 int i = 0; 146 printf("\n\n"); 147 printf("The certificate generation tool loads the binary images and\n" 148 "optionally the RSA keys, and outputs the key and content\n" 149 "certificates properly signed to implement the chain of trust.\n" 150 "If keys are provided, they must be in PEM format.\n" 151 "Certificates are generated in DER format.\n"); 152 printf("\n"); 153 printf("Usage:\n\n"); 154 printf(" %s [-hknp] \\\n", cmd); 155 for (i = 0; i < NUM_OPTS; i++) { 156 printf(" --%s <file> \\\n", long_opt[i].name); 157 } 158 printf("\n"); 159 printf("-a Key algorithm: rsa (default), ecdsa\n"); 160 printf("-h Print help and exit\n"); 161 printf("-k Save key pairs into files. Filenames must be provided\n"); 162 printf("-n Generate new key pairs if no key files are provided\n"); 163 printf("-p Print the certificates in the standard output\n"); 164 printf("\n"); 165 166 exit(0); 167 } 168 169 static int get_key_alg(const char *key_alg_str) 170 { 171 int i; 172 173 for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) { 174 if (0 == strcmp(key_alg_str, key_algs_str[i])) { 175 return i; 176 } 177 } 178 179 return -1; 180 } 181 182 static void check_cmd_params(void) 183 { 184 cert_t *cert; 185 ext_t *ext; 186 key_t *key; 187 int i, j; 188 189 /* Only save new keys */ 190 if (save_keys && !new_keys) { 191 ERROR("Only new keys can be saved to disk\n"); 192 exit(1); 193 } 194 195 /* Check that all required options have been specified in the 196 * command line */ 197 for (i = 0; i < num_certs; i++) { 198 cert = &certs[i]; 199 if (cert->fn == NULL) { 200 /* Certificate not requested. Skip to the next one */ 201 continue; 202 } 203 204 /* Check that all parameters required to create this certificate 205 * have been specified in the command line */ 206 for (j = 0; j < cert->num_ext; j++) { 207 ext = &extensions[cert->ext[j]]; 208 switch (ext->type) { 209 case EXT_TYPE_PKEY: 210 /* Key filename must be specified */ 211 key = &keys[ext->data.key]; 212 if (!new_keys && key->fn == NULL) { 213 ERROR("Key '%s' required by '%s' not " 214 "specified\n", key->desc, 215 cert->cn); 216 exit(1); 217 } 218 break; 219 case EXT_TYPE_HASH: 220 /* 221 * Binary image must be specified 222 * unless it is explicitly made optional. 223 */ 224 if ((!ext->optional) && (ext->data.fn == NULL)) { 225 ERROR("Image for '%s' not specified\n", 226 ext->ln); 227 exit(1); 228 } 229 break; 230 default: 231 ERROR("Unknown extension type in '%s'\n", 232 ext->ln); 233 exit(1); 234 break; 235 } 236 } 237 } 238 } 239 240 int main(int argc, char *argv[]) 241 { 242 STACK_OF(X509_EXTENSION) * sk = NULL; 243 X509_EXTENSION *cert_ext = NULL; 244 ext_t *ext = NULL; 245 key_t *key = NULL; 246 cert_t *cert = NULL; 247 FILE *file = NULL; 248 int i, j, ext_nid; 249 int c, opt_idx = 0; 250 const struct option *cmd_opt; 251 const char *cur_opt; 252 unsigned int err_code; 253 unsigned char md[SHA256_DIGEST_LENGTH]; 254 const EVP_MD *md_info; 255 256 NOTICE("CoT Generation Tool: %s\n", build_msg); 257 NOTICE("Target platform: %s\n", platform_msg); 258 259 /* Set default options */ 260 key_alg = KEY_ALG_RSA; 261 262 /* Add common command line options */ 263 cmd_opt_add("key-alg", required_argument, 'a'); 264 cmd_opt_add("help", no_argument, 'h'); 265 cmd_opt_add("save-keys", no_argument, 'k'); 266 cmd_opt_add("new-chain", no_argument, 'n'); 267 cmd_opt_add("print-cert", no_argument, 'p'); 268 269 /* Initialize the certificates */ 270 if (cert_init() != 0) { 271 ERROR("Cannot initialize certificates\n"); 272 exit(1); 273 } 274 275 /* Initialize the keys */ 276 if (key_init() != 0) { 277 ERROR("Cannot initialize keys\n"); 278 exit(1); 279 } 280 281 /* Initialize the new types and register OIDs for the extensions */ 282 if (ext_init() != 0) { 283 ERROR("Cannot initialize TBB extensions\n"); 284 exit(1); 285 } 286 287 /* Get the command line options populated during the initialization */ 288 cmd_opt = cmd_opt_get_array(); 289 290 while (1) { 291 /* getopt_long stores the option index here. */ 292 c = getopt_long(argc, argv, "ahknp", cmd_opt, &opt_idx); 293 294 /* Detect the end of the options. */ 295 if (c == -1) { 296 break; 297 } 298 299 switch (c) { 300 case 'a': 301 key_alg = get_key_alg(optarg); 302 if (key_alg < 0) { 303 ERROR("Invalid key algorithm '%s'\n", optarg); 304 exit(1); 305 } 306 break; 307 case 'h': 308 print_help(argv[0], cmd_opt); 309 break; 310 case 'k': 311 save_keys = 1; 312 break; 313 case 'n': 314 new_keys = 1; 315 break; 316 case 'p': 317 print_cert = 1; 318 break; 319 case CMD_OPT_EXT: 320 cur_opt = cmd_opt_get_name(opt_idx); 321 ext = ext_get_by_opt(cur_opt); 322 ext->data.fn = strdup(optarg); 323 break; 324 case CMD_OPT_KEY: 325 cur_opt = cmd_opt_get_name(opt_idx); 326 key = key_get_by_opt(cur_opt); 327 key->fn = strdup(optarg); 328 break; 329 case CMD_OPT_CERT: 330 cur_opt = cmd_opt_get_name(opt_idx); 331 cert = cert_get_by_opt(cur_opt); 332 cert->fn = strdup(optarg); 333 break; 334 case '?': 335 default: 336 printf("%s\n", optarg); 337 exit(1); 338 } 339 } 340 341 /* Check command line arguments */ 342 check_cmd_params(); 343 344 /* Indicate SHA256 as image hash algorithm in the certificate 345 * extension */ 346 md_info = EVP_sha256(); 347 348 /* Load private keys from files (or generate new ones) */ 349 for (i = 0 ; i < num_keys ; i++) { 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_MALLOC) { 358 /* Cannot allocate memory. Abort. */ 359 ERROR("Malloc error while loading '%s'\n", keys[i].fn); 360 exit(1); 361 } else if (err_code == KEY_ERR_LOAD) { 362 /* File exists, but it does not contain a valid private 363 * key. Abort. */ 364 ERROR("Error loading '%s'\n", keys[i].fn); 365 exit(1); 366 } 367 368 /* File does not exist, could not be opened or no filename was 369 * given */ 370 if (new_keys) { 371 /* Try to create a new key */ 372 NOTICE("Creating new key for '%s'\n", keys[i].desc); 373 if (!key_create(&keys[i], key_alg)) { 374 ERROR("Error creating key '%s'\n", keys[i].desc); 375 exit(1); 376 } 377 } else { 378 if (err_code == KEY_ERR_OPEN) { 379 ERROR("Error opening '%s'\n", keys[i].fn); 380 } else { 381 ERROR("Key '%s' not specified\n", keys[i].desc); 382 } 383 exit(1); 384 } 385 } 386 387 /* Create the certificates */ 388 for (i = 0 ; i < num_certs ; i++) { 389 390 cert = &certs[i]; 391 392 /* Create a new stack of extensions. This stack will be used 393 * to create the certificate */ 394 CHECK_NULL(sk, sk_X509_EXTENSION_new_null()); 395 396 for (j = 0 ; j < cert->num_ext ; j++) { 397 398 ext = &extensions[cert->ext[j]]; 399 400 /* Get OpenSSL internal ID for this extension */ 401 CHECK_OID(ext_nid, ext->oid); 402 403 /* 404 * Three types of extensions are currently supported: 405 * - EXT_TYPE_NVCOUNTER 406 * - EXT_TYPE_HASH 407 * - EXT_TYPE_PKEY 408 */ 409 switch (ext->type) { 410 case EXT_TYPE_NVCOUNTER: 411 CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid, 412 EXT_CRIT, ext->data.nvcounter)); 413 break; 414 case EXT_TYPE_HASH: 415 if (ext->data.fn == NULL) { 416 if (ext->optional) { 417 /* Include a hash filled with zeros */ 418 memset(md, 0x0, SHA256_DIGEST_LENGTH); 419 } else { 420 /* Do not include this hash in the certificate */ 421 break; 422 } 423 } else { 424 /* Calculate the hash of the file */ 425 if (!sha_file(ext->data.fn, md)) { 426 ERROR("Cannot calculate hash of %s\n", 427 ext->data.fn); 428 exit(1); 429 } 430 } 431 CHECK_NULL(cert_ext, ext_new_hash(ext_nid, 432 EXT_CRIT, md_info, md, 433 SHA256_DIGEST_LENGTH)); 434 break; 435 case EXT_TYPE_PKEY: 436 CHECK_NULL(cert_ext, ext_new_key(ext_nid, 437 EXT_CRIT, keys[ext->data.key].key)); 438 break; 439 default: 440 ERROR("Unknown extension type in %s\n", 441 cert->cn); 442 exit(1); 443 } 444 445 /* Push the extension into the stack */ 446 sk_X509_EXTENSION_push(sk, cert_ext); 447 } 448 449 /* Create certificate. Signed with ROT key */ 450 if (cert->fn && !cert_new(cert, VAL_DAYS, 0, sk)) { 451 ERROR("Cannot create %s\n", cert->cn); 452 exit(1); 453 } 454 455 sk_X509_EXTENSION_free(sk); 456 } 457 458 459 /* Print the certificates */ 460 if (print_cert) { 461 for (i = 0 ; i < num_certs ; i++) { 462 if (!certs[i].x) { 463 continue; 464 } 465 printf("\n\n=====================================\n\n"); 466 X509_print_fp(stdout, certs[i].x); 467 } 468 } 469 470 /* Save created certificates to files */ 471 for (i = 0 ; i < num_certs ; i++) { 472 if (certs[i].x && certs[i].fn) { 473 file = fopen(certs[i].fn, "w"); 474 if (file != NULL) { 475 i2d_X509_fp(file, certs[i].x); 476 fclose(file); 477 } else { 478 ERROR("Cannot create file %s\n", certs[i].fn); 479 } 480 } 481 } 482 483 /* Save keys */ 484 if (save_keys) { 485 for (i = 0 ; i < num_keys ; i++) { 486 if (!key_store(&keys[i])) { 487 ERROR("Cannot save %s\n", keys[i].desc); 488 } 489 } 490 } 491 492 #ifndef OPENSSL_NO_ENGINE 493 ENGINE_cleanup(); 494 #endif 495 CRYPTO_cleanup_all_ex_data(); 496 497 return 0; 498 } 499