1 /* 2 * Copyright (c) 2013, Google Inc. 3 * 4 * (C) Copyright 2008 Semihalf 5 * 6 * (C) Copyright 2000-2006 7 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include "mkimage.h" 13 #include <image.h> 14 #include <version.h> 15 16 /** 17 * fit_set_hash_value - set hash value in requested has node 18 * @fit: pointer to the FIT format image header 19 * @noffset: hash node offset 20 * @value: hash value to be set 21 * @value_len: hash value length 22 * 23 * fit_set_hash_value() attempts to set hash value in a node at offset 24 * given and returns operation status to the caller. 25 * 26 * returns 27 * 0, on success 28 * -1, on failure 29 */ 30 static int fit_set_hash_value(void *fit, int noffset, uint8_t *value, 31 int value_len) 32 { 33 int ret; 34 35 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 36 if (ret) { 37 printf("Can't set hash '%s' property for '%s' node(%s)\n", 38 FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL), 39 fdt_strerror(ret)); 40 return -1; 41 } 42 43 return 0; 44 } 45 46 /** 47 * fit_image_process_hash - Process a single subnode of the images/ node 48 * 49 * Check each subnode and process accordingly. For hash nodes we generate 50 * a hash of the supplised data and store it in the node. 51 * 52 * @fit: pointer to the FIT format image header 53 * @image_name: name of image being processes (used to display errors) 54 * @noffset: subnode offset 55 * @data: data to process 56 * @size: size of data in bytes 57 * @return 0 if ok, -1 on error 58 */ 59 static int fit_image_process_hash(void *fit, const char *image_name, 60 int noffset, const void *data, size_t size) 61 { 62 uint8_t value[FIT_MAX_HASH_LEN]; 63 const char *node_name; 64 int value_len; 65 char *algo; 66 67 node_name = fit_get_name(fit, noffset, NULL); 68 69 if (fit_image_hash_get_algo(fit, noffset, &algo)) { 70 printf("Can't get hash algo property for '%s' hash node in '%s' image node\n", 71 node_name, image_name); 72 return -1; 73 } 74 75 if (calculate_hash(data, size, algo, value, &value_len)) { 76 printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n", 77 algo, node_name, image_name); 78 return -1; 79 } 80 81 if (fit_set_hash_value(fit, noffset, value, value_len)) { 82 printf("Can't set hash value for '%s' hash node in '%s' image node\n", 83 node_name, image_name); 84 return -1; 85 } 86 87 return 0; 88 } 89 90 /** 91 * fit_image_write_sig() - write the signature to a FIT 92 * 93 * This writes the signature and signer data to the FIT. 94 * 95 * @fit: pointer to the FIT format image header 96 * @noffset: hash node offset 97 * @value: signature value to be set 98 * @value_len: signature value length 99 * @comment: Text comment to write (NULL for none) 100 * 101 * returns 102 * 0, on success 103 * -FDT_ERR_..., on failure 104 */ 105 static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, 106 int value_len, const char *comment, const char *region_prop, 107 int region_proplen) 108 { 109 int string_size; 110 int ret; 111 112 /* 113 * Get the current string size, before we update the FIT and add 114 * more 115 */ 116 string_size = fdt_size_dt_strings(fit); 117 118 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 119 if (!ret) { 120 ret = fdt_setprop_string(fit, noffset, "signer-name", 121 "mkimage"); 122 } 123 if (!ret) { 124 ret = fdt_setprop_string(fit, noffset, "signer-version", 125 PLAIN_VERSION); 126 } 127 if (comment && !ret) 128 ret = fdt_setprop_string(fit, noffset, "comment", comment); 129 if (!ret) 130 ret = fit_set_timestamp(fit, noffset, time(NULL)); 131 if (region_prop && !ret) { 132 uint32_t strdata[2]; 133 134 ret = fdt_setprop(fit, noffset, "hashed-nodes", 135 region_prop, region_proplen); 136 strdata[0] = 0; 137 strdata[1] = cpu_to_fdt32(string_size); 138 if (!ret) { 139 ret = fdt_setprop(fit, noffset, "hashed-strings", 140 strdata, sizeof(strdata)); 141 } 142 } 143 144 return ret; 145 } 146 147 static int fit_image_setup_sig(struct image_sign_info *info, 148 const char *keydir, void *fit, const char *image_name, 149 int noffset, const char *require_keys) 150 { 151 const char *node_name; 152 char *algo_name; 153 154 node_name = fit_get_name(fit, noffset, NULL); 155 if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { 156 printf("Can't get algo property for '%s' signature node in '%s' image node\n", 157 node_name, image_name); 158 return -1; 159 } 160 161 memset(info, '\0', sizeof(*info)); 162 info->keydir = keydir; 163 info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 164 info->fit = fit; 165 info->node_offset = noffset; 166 info->algo = image_get_sig_algo(algo_name); 167 info->require_keys = require_keys; 168 if (!info->algo) { 169 printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n", 170 algo_name, node_name, image_name); 171 return -1; 172 } 173 174 return 0; 175 } 176 177 /** 178 * fit_image_process_sig- Process a single subnode of the images/ node 179 * 180 * Check each subnode and process accordingly. For signature nodes we 181 * generate a signed hash of the supplised data and store it in the node. 182 * 183 * @keydir: Directory containing keys to use for signing 184 * @keydest: Destination FDT blob to write public keys into 185 * @fit: pointer to the FIT format image header 186 * @image_name: name of image being processes (used to display errors) 187 * @noffset: subnode offset 188 * @data: data to process 189 * @size: size of data in bytes 190 * @comment: Comment to add to signature nodes 191 * @require_keys: Mark all keys as 'required' 192 * @return 0 if ok, -1 on error 193 */ 194 static int fit_image_process_sig(const char *keydir, void *keydest, 195 void *fit, const char *image_name, 196 int noffset, const void *data, size_t size, 197 const char *comment, int require_keys) 198 { 199 struct image_sign_info info; 200 struct image_region region; 201 const char *node_name; 202 uint8_t *value; 203 uint value_len; 204 int ret; 205 206 if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset, 207 require_keys ? "image" : NULL)) 208 return -1; 209 210 node_name = fit_get_name(fit, noffset, NULL); 211 region.data = data; 212 region.size = size; 213 ret = info.algo->sign(&info, ®ion, 1, &value, &value_len); 214 if (ret) { 215 printf("Failed to sign '%s' signature node in '%s' image node: %d\n", 216 node_name, image_name, ret); 217 218 /* We allow keys to be missing */ 219 if (ret == -ENOENT) 220 return 0; 221 return -1; 222 } 223 224 ret = fit_image_write_sig(fit, noffset, value, value_len, comment, 225 NULL, 0); 226 if (ret) { 227 printf("Can't write signature for '%s' signature node in '%s' image node: %s\n", 228 node_name, image_name, fdt_strerror(ret)); 229 return -1; 230 } 231 free(value); 232 233 /* Get keyname again, as FDT has changed and invalidated our pointer */ 234 info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 235 236 /* Write the public key into the supplied FDT file */ 237 if (keydest && info.algo->add_verify_data(&info, keydest)) { 238 printf("Failed to add verification data for '%s' signature node in '%s' image node\n", 239 node_name, image_name); 240 return -1; 241 } 242 243 return 0; 244 } 245 246 /** 247 * fit_image_add_verification_data() - calculate/set verig. data for image node 248 * 249 * This adds hash and signature values for an component image node. 250 * 251 * All existing hash subnodes are checked, if algorithm property is set to 252 * one of the supported hash algorithms, hash value is computed and 253 * corresponding hash node property is set, for example: 254 * 255 * Input component image node structure: 256 * 257 * o image@1 (at image_noffset) 258 * | - data = [binary data] 259 * o hash@1 260 * |- algo = "sha1" 261 * 262 * Output component image node structure: 263 * 264 * o image@1 (at image_noffset) 265 * | - data = [binary data] 266 * o hash@1 267 * |- algo = "sha1" 268 * |- value = sha1(data) 269 * 270 * For signature details, please see doc/uImage.FIT/signature.txt 271 * 272 * @keydir Directory containing *.key and *.crt files (or NULL) 273 * @keydest FDT Blob to write public keys into (NULL if none) 274 * @fit: Pointer to the FIT format image header 275 * @image_noffset: Requested component image node 276 * @comment: Comment to add to signature nodes 277 * @require_keys: Mark all keys as 'required' 278 * @return: 0 on success, <0 on failure 279 */ 280 int fit_image_add_verification_data(const char *keydir, void *keydest, 281 void *fit, int image_noffset, const char *comment, 282 int require_keys) 283 { 284 const char *image_name; 285 const void *data; 286 size_t size; 287 int noffset; 288 289 /* Get image data and data length */ 290 if (fit_image_get_data(fit, image_noffset, &data, &size)) { 291 printf("Can't get image data/size\n"); 292 return -1; 293 } 294 295 image_name = fit_get_name(fit, image_noffset, NULL); 296 297 /* Process all hash subnodes of the component image node */ 298 for (noffset = fdt_first_subnode(fit, image_noffset); 299 noffset >= 0; 300 noffset = fdt_next_subnode(fit, noffset)) { 301 const char *node_name; 302 int ret = 0; 303 304 /* 305 * Check subnode name, must be equal to "hash" or "signature". 306 * Multiple hash nodes require unique unit node 307 * names, e.g. hash@1, hash@2, signature@1, etc. 308 */ 309 node_name = fit_get_name(fit, noffset, NULL); 310 if (!strncmp(node_name, FIT_HASH_NODENAME, 311 strlen(FIT_HASH_NODENAME))) { 312 ret = fit_image_process_hash(fit, image_name, noffset, 313 data, size); 314 } else if (IMAGE_ENABLE_SIGN && keydir && 315 !strncmp(node_name, FIT_SIG_NODENAME, 316 strlen(FIT_SIG_NODENAME))) { 317 ret = fit_image_process_sig(keydir, keydest, 318 fit, image_name, noffset, data, size, 319 comment, require_keys); 320 } 321 if (ret) 322 return -1; 323 } 324 325 return 0; 326 } 327 328 struct strlist { 329 int count; 330 char **strings; 331 }; 332 333 static void strlist_init(struct strlist *list) 334 { 335 memset(list, '\0', sizeof(*list)); 336 } 337 338 static void strlist_free(struct strlist *list) 339 { 340 int i; 341 342 for (i = 0; i < list->count; i++) 343 free(list->strings[i]); 344 free(list->strings); 345 } 346 347 static int strlist_add(struct strlist *list, const char *str) 348 { 349 char *dup; 350 351 dup = strdup(str); 352 list->strings = realloc(list->strings, 353 (list->count + 1) * sizeof(char *)); 354 if (!list || !str) 355 return -1; 356 list->strings[list->count++] = dup; 357 358 return 0; 359 } 360 361 static const char *fit_config_get_image_list(void *fit, int noffset, 362 int *lenp, int *allow_missingp) 363 { 364 static const char default_list[] = FIT_KERNEL_PROP "\0" 365 FIT_FDT_PROP; 366 const char *prop; 367 368 /* If there is an "image" property, use that */ 369 prop = fdt_getprop(fit, noffset, "sign-images", lenp); 370 if (prop) { 371 *allow_missingp = 0; 372 return *lenp ? prop : NULL; 373 } 374 375 /* Default image list */ 376 *allow_missingp = 1; 377 *lenp = sizeof(default_list); 378 379 return default_list; 380 } 381 382 static int fit_config_get_hash_list(void *fit, int conf_noffset, 383 int sig_offset, struct strlist *node_inc) 384 { 385 int allow_missing; 386 const char *prop, *iname, *end; 387 const char *conf_name, *sig_name; 388 char name[200], path[200]; 389 int image_count; 390 int ret, len; 391 392 conf_name = fit_get_name(fit, conf_noffset, NULL); 393 sig_name = fit_get_name(fit, sig_offset, NULL); 394 395 /* 396 * Build a list of nodes we need to hash. We always need the root 397 * node and the configuration. 398 */ 399 strlist_init(node_inc); 400 snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name); 401 if (strlist_add(node_inc, "/") || 402 strlist_add(node_inc, name)) 403 goto err_mem; 404 405 /* Get a list of images that we intend to sign */ 406 prop = fit_config_get_image_list(fit, sig_offset, &len, 407 &allow_missing); 408 if (!prop) 409 return 0; 410 411 /* Locate the images */ 412 end = prop + len; 413 image_count = 0; 414 for (iname = prop; iname < end; iname += strlen(iname) + 1) { 415 int noffset; 416 int image_noffset; 417 int hash_count; 418 419 image_noffset = fit_conf_get_prop_node(fit, conf_noffset, 420 iname); 421 if (image_noffset < 0) { 422 printf("Failed to find image '%s' in configuration '%s/%s'\n", 423 iname, conf_name, sig_name); 424 if (allow_missing) 425 continue; 426 427 return -ENOENT; 428 } 429 430 ret = fdt_get_path(fit, image_noffset, path, sizeof(path)); 431 if (ret < 0) 432 goto err_path; 433 if (strlist_add(node_inc, path)) 434 goto err_mem; 435 436 snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, 437 conf_name); 438 439 /* Add all this image's hashes */ 440 hash_count = 0; 441 for (noffset = fdt_first_subnode(fit, image_noffset); 442 noffset >= 0; 443 noffset = fdt_next_subnode(fit, noffset)) { 444 const char *name = fit_get_name(fit, noffset, NULL); 445 446 if (strncmp(name, FIT_HASH_NODENAME, 447 strlen(FIT_HASH_NODENAME))) 448 continue; 449 ret = fdt_get_path(fit, noffset, path, sizeof(path)); 450 if (ret < 0) 451 goto err_path; 452 if (strlist_add(node_inc, path)) 453 goto err_mem; 454 hash_count++; 455 } 456 457 if (!hash_count) { 458 printf("Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n", 459 conf_name, sig_name, iname); 460 return -ENOMSG; 461 } 462 463 image_count++; 464 } 465 466 if (!image_count) { 467 printf("Failed to find any images for configuration '%s/%s'\n", 468 conf_name, sig_name); 469 return -ENOMSG; 470 } 471 472 return 0; 473 474 err_mem: 475 printf("Out of memory processing configuration '%s/%s'\n", conf_name, 476 sig_name); 477 return -ENOMEM; 478 479 err_path: 480 printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n", 481 iname, conf_name, sig_name, fdt_strerror(ret)); 482 return -ENOENT; 483 } 484 485 static int fit_config_get_data(void *fit, int conf_noffset, int noffset, 486 struct image_region **regionp, int *region_countp, 487 char **region_propp, int *region_proplen) 488 { 489 char * const exc_prop[] = {"data"}; 490 struct strlist node_inc; 491 struct image_region *region; 492 struct fdt_region fdt_regions[100]; 493 const char *conf_name, *sig_name; 494 char path[200]; 495 int count, i; 496 char *region_prop; 497 int ret, len; 498 499 conf_name = fit_get_name(fit, conf_noffset, NULL); 500 sig_name = fit_get_name(fit, conf_noffset, NULL); 501 debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name); 502 503 /* Get a list of nodes we want to hash */ 504 ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc); 505 if (ret) 506 return ret; 507 508 /* Get a list of regions to hash */ 509 count = fdt_find_regions(fit, node_inc.strings, node_inc.count, 510 exc_prop, ARRAY_SIZE(exc_prop), 511 fdt_regions, ARRAY_SIZE(fdt_regions), 512 path, sizeof(path), 1); 513 if (count < 0) { 514 printf("Failed to hash configuration '%s/%s': %s\n", conf_name, 515 sig_name, fdt_strerror(ret)); 516 return -EIO; 517 } 518 if (count == 0) { 519 printf("No data to hash for configuration '%s/%s': %s\n", 520 conf_name, sig_name, fdt_strerror(ret)); 521 return -EINVAL; 522 } 523 524 /* Build our list of data blocks */ 525 region = fit_region_make_list(fit, fdt_regions, count, NULL); 526 if (!region) { 527 printf("Out of memory hashing configuration '%s/%s'\n", 528 conf_name, sig_name); 529 return -ENOMEM; 530 } 531 532 /* Create a list of all hashed properties */ 533 debug("Hash nodes:\n"); 534 for (i = len = 0; i < node_inc.count; i++) { 535 debug(" %s\n", node_inc.strings[i]); 536 len += strlen(node_inc.strings[i]) + 1; 537 } 538 region_prop = malloc(len); 539 if (!region_prop) { 540 printf("Out of memory setting up regions for configuration '%s/%s'\n", 541 conf_name, sig_name); 542 return -ENOMEM; 543 } 544 for (i = len = 0; i < node_inc.count; 545 len += strlen(node_inc.strings[i]) + 1, i++) 546 strcpy(region_prop + len, node_inc.strings[i]); 547 strlist_free(&node_inc); 548 549 *region_countp = count; 550 *regionp = region; 551 *region_propp = region_prop; 552 *region_proplen = len; 553 554 return 0; 555 } 556 557 static int fit_config_process_sig(const char *keydir, void *keydest, 558 void *fit, const char *conf_name, int conf_noffset, 559 int noffset, const char *comment, int require_keys) 560 { 561 struct image_sign_info info; 562 const char *node_name; 563 struct image_region *region; 564 char *region_prop; 565 int region_proplen; 566 int region_count; 567 uint8_t *value; 568 uint value_len; 569 int ret; 570 571 node_name = fit_get_name(fit, noffset, NULL); 572 if (fit_config_get_data(fit, conf_noffset, noffset, ®ion, 573 ®ion_count, ®ion_prop, ®ion_proplen)) 574 return -1; 575 576 if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset, 577 require_keys ? "conf" : NULL)) 578 return -1; 579 580 ret = info.algo->sign(&info, region, region_count, &value, &value_len); 581 free(region); 582 if (ret) { 583 printf("Failed to sign '%s' signature node in '%s' conf node\n", 584 node_name, conf_name); 585 586 /* We allow keys to be missing */ 587 if (ret == -ENOENT) 588 return 0; 589 return -1; 590 } 591 592 if (fit_image_write_sig(fit, noffset, value, value_len, comment, 593 region_prop, region_proplen)) { 594 printf("Can't write signature for '%s' signature node in '%s' conf node\n", 595 node_name, conf_name); 596 return -1; 597 } 598 free(value); 599 free(region_prop); 600 601 /* Get keyname again, as FDT has changed and invalidated our pointer */ 602 info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 603 604 /* Write the public key into the supplied FDT file */ 605 if (keydest && info.algo->add_verify_data(&info, keydest)) { 606 printf("Failed to add verification data for '%s' signature node in '%s' image node\n", 607 node_name, conf_name); 608 return -1; 609 } 610 611 return 0; 612 } 613 614 static int fit_config_add_verification_data(const char *keydir, void *keydest, 615 void *fit, int conf_noffset, const char *comment, 616 int require_keys) 617 { 618 const char *conf_name; 619 int noffset; 620 621 conf_name = fit_get_name(fit, conf_noffset, NULL); 622 623 /* Process all hash subnodes of the configuration node */ 624 for (noffset = fdt_first_subnode(fit, conf_noffset); 625 noffset >= 0; 626 noffset = fdt_next_subnode(fit, noffset)) { 627 const char *node_name; 628 int ret = 0; 629 630 node_name = fit_get_name(fit, noffset, NULL); 631 if (!strncmp(node_name, FIT_SIG_NODENAME, 632 strlen(FIT_SIG_NODENAME))) { 633 ret = fit_config_process_sig(keydir, keydest, 634 fit, conf_name, conf_noffset, noffset, comment, 635 require_keys); 636 } 637 if (ret) 638 return ret; 639 } 640 641 return 0; 642 } 643 644 int fit_add_verification_data(const char *keydir, void *keydest, void *fit, 645 const char *comment, int require_keys) 646 { 647 int images_noffset, confs_noffset; 648 int noffset; 649 int ret; 650 651 /* Find images parent node offset */ 652 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 653 if (images_noffset < 0) { 654 printf("Can't find images parent node '%s' (%s)\n", 655 FIT_IMAGES_PATH, fdt_strerror(images_noffset)); 656 return images_noffset; 657 } 658 659 /* Process its subnodes, print out component images details */ 660 for (noffset = fdt_first_subnode(fit, images_noffset); 661 noffset >= 0; 662 noffset = fdt_next_subnode(fit, noffset)) { 663 /* 664 * Direct child node of the images parent node, 665 * i.e. component image node. 666 */ 667 ret = fit_image_add_verification_data(keydir, keydest, 668 fit, noffset, comment, require_keys); 669 if (ret) 670 return ret; 671 } 672 673 /* If there are no keys, we can't sign configurations */ 674 if (!IMAGE_ENABLE_SIGN || !keydir) 675 return 0; 676 677 /* Find configurations parent node offset */ 678 confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); 679 if (confs_noffset < 0) { 680 printf("Can't find images parent node '%s' (%s)\n", 681 FIT_IMAGES_PATH, fdt_strerror(confs_noffset)); 682 return -ENOENT; 683 } 684 685 /* Process its subnodes, print out component images details */ 686 for (noffset = fdt_first_subnode(fit, confs_noffset); 687 noffset >= 0; 688 noffset = fdt_next_subnode(fit, noffset)) { 689 ret = fit_config_add_verification_data(keydir, keydest, 690 fit, noffset, comment, 691 require_keys); 692 if (ret) 693 return ret; 694 } 695 696 return 0; 697 } 698 699 #ifdef CONFIG_FIT_SIGNATURE 700 int fit_check_sign(const void *working_fdt, const void *key) 701 { 702 int cfg_noffset; 703 int ret; 704 705 cfg_noffset = fit_conf_get_node(working_fdt, NULL); 706 if (!cfg_noffset) 707 return -1; 708 709 ret = fit_config_verify(working_fdt, cfg_noffset); 710 return ret; 711 } 712 #endif 713