|
42 | 42 |
|
43 | 43 | #include "mcuboot_config/mcuboot_config.h"
|
44 | 44 |
|
| 45 | +#if defined(MCUBOOT_DECOMPRESS_IMAGES) |
| 46 | +#include <nrf_compress/implementation.h> |
| 47 | +#include <compression/decompression.h> |
| 48 | +#endif |
| 49 | + |
| 50 | +#include "bootutil/bootutil_log.h" |
| 51 | + |
| 52 | +BOOT_LOG_MODULE_DECLARE(mcuboot); |
| 53 | + |
45 | 54 | #ifdef MCUBOOT_ENC_IMAGES
|
46 | 55 | #include "bootutil/enc_key.h"
|
47 | 56 | #endif
|
@@ -484,7 +493,7 @@ bootutil_img_validate(struct boot_loader_state *state,
|
484 | 493 | #endif
|
485 | 494 | )
|
486 | 495 | {
|
487 |
| -#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT) |
| 496 | +#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT) || defined(MCUBOOT_DECOMPRESS_IMAGES) |
488 | 497 | int image_index = (state == NULL ? 0 : BOOT_CURR_IMG(state));
|
489 | 498 | #endif
|
490 | 499 | uint32_t off;
|
@@ -527,6 +536,68 @@ bootutil_img_validate(struct boot_loader_state *state,
|
527 | 536 | }
|
528 | 537 | #endif
|
529 | 538 |
|
| 539 | +#ifdef MCUBOOT_DECOMPRESS_IMAGES |
| 540 | + /* If the image is compressed, the integrity of the image must also be validated */ |
| 541 | + if (MUST_DECOMPRESS(fap, image_index, hdr)) { |
| 542 | + bool found_decompressed_size = false; |
| 543 | + bool found_decompressed_sha = false; |
| 544 | + bool found_decompressed_signature = false; |
| 545 | + |
| 546 | + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true); |
| 547 | + if (rc) { |
| 548 | + goto out; |
| 549 | + } |
| 550 | + |
| 551 | + if (it.tlv_end > bootutil_max_image_size(state, fap)) { |
| 552 | + rc = -1; |
| 553 | + goto out; |
| 554 | + } |
| 555 | + |
| 556 | + while (true) { |
| 557 | + uint16_t expected_size = 0; |
| 558 | + bool *found_flag = NULL; |
| 559 | + |
| 560 | + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); |
| 561 | + if (rc < 0) { |
| 562 | + goto out; |
| 563 | + } else if (rc > 0) { |
| 564 | + break; |
| 565 | + } |
| 566 | + |
| 567 | + switch (type) { |
| 568 | + case IMAGE_TLV_DECOMP_SIZE: |
| 569 | + expected_size = sizeof(size_t); |
| 570 | + found_flag = &found_decompressed_size; |
| 571 | + break; |
| 572 | + case IMAGE_TLV_DECOMP_SHA: |
| 573 | + expected_size = IMAGE_HASH_SIZE; |
| 574 | + found_flag = &found_decompressed_sha; |
| 575 | + break; |
| 576 | + case IMAGE_TLV_DECOMP_SIGNATURE: |
| 577 | + found_flag = &found_decompressed_signature; |
| 578 | + break; |
| 579 | + default: |
| 580 | + continue; |
| 581 | + }; |
| 582 | + |
| 583 | + if (type == IMAGE_TLV_DECOMP_SIGNATURE && !EXPECTED_SIG_LEN(len)) { |
| 584 | + rc = -1; |
| 585 | + goto out; |
| 586 | + } else if (type != IMAGE_TLV_DECOMP_SIGNATURE && len != expected_size) { |
| 587 | + rc = -1; |
| 588 | + goto out; |
| 589 | + } |
| 590 | + |
| 591 | + *found_flag = true; |
| 592 | + } |
| 593 | + |
| 594 | + rc = (!found_decompressed_size || !found_decompressed_sha || !found_decompressed_signature); |
| 595 | + if (rc) { |
| 596 | + goto out; |
| 597 | + } |
| 598 | + } |
| 599 | +#endif |
| 600 | + |
530 | 601 | #if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
|
531 | 602 | #if defined(MCUBOOT_SWAP_USING_OFFSET) && defined(MCUBOOT_SERIAL_RECOVERY)
|
532 | 603 | rc = bootutil_img_hash(state, hdr, fap, tmp_buf, tmp_buf_sz, hash, seed, seed_len,
|
@@ -760,6 +831,161 @@ bootutil_img_validate(struct boot_loader_state *state,
|
760 | 831 | skip_security_counter_check:
|
761 | 832 | #endif
|
762 | 833 |
|
| 834 | +#ifdef MCUBOOT_DECOMPRESS_IMAGES |
| 835 | + /* Only after all previous verifications have passed, perform a dry-run of the decompression |
| 836 | + * and ensure the image is valid |
| 837 | + */ |
| 838 | + if (!rc && MUST_DECOMPRESS(fap, image_index, hdr)) { |
| 839 | + image_hash_valid = 0; |
| 840 | + FIH_SET(valid_signature, FIH_FAILURE); |
| 841 | + |
| 842 | + rc = bootutil_img_hash_decompress(state, hdr, fap, tmp_buf, tmp_buf_sz, |
| 843 | + hash, seed, seed_len); |
| 844 | + if (rc) { |
| 845 | + goto out; |
| 846 | + } |
| 847 | + |
| 848 | + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SHA, true); |
| 849 | + if (rc) { |
| 850 | + goto out; |
| 851 | + } |
| 852 | + |
| 853 | + if (it.tlv_end > bootutil_max_image_size(state, fap)) { |
| 854 | + rc = -1; |
| 855 | + goto out; |
| 856 | + } |
| 857 | + |
| 858 | + while (true) { |
| 859 | + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); |
| 860 | + if (rc < 0) { |
| 861 | + goto out; |
| 862 | + } else if (rc > 0) { |
| 863 | + break; |
| 864 | + } |
| 865 | + |
| 866 | + if (type == IMAGE_TLV_DECOMP_SHA) { |
| 867 | + /* Verify the image hash. This must always be present. */ |
| 868 | + if (len != sizeof(hash)) { |
| 869 | + rc = -1; |
| 870 | + goto out; |
| 871 | + } |
| 872 | + rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash)); |
| 873 | + if (rc) { |
| 874 | + goto out; |
| 875 | + } |
| 876 | + |
| 877 | + FIH_CALL(boot_fih_memequal, fih_rc, hash, buf, sizeof(hash)); |
| 878 | + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { |
| 879 | + FIH_SET(fih_rc, FIH_FAILURE); |
| 880 | + goto out; |
| 881 | + } |
| 882 | + |
| 883 | + image_hash_valid = 1; |
| 884 | + } |
| 885 | + } |
| 886 | + |
| 887 | + rc = !image_hash_valid; |
| 888 | + if (rc) { |
| 889 | + goto out; |
| 890 | + } |
| 891 | + |
| 892 | +#ifdef EXPECTED_SIG_TLV |
| 893 | +#ifdef EXPECTED_KEY_TLV |
| 894 | + rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_KEY_TLV, false); |
| 895 | + if (rc) { |
| 896 | + goto out; |
| 897 | + } |
| 898 | + |
| 899 | + if (it.tlv_end > bootutil_max_image_size(state, fap)) { |
| 900 | + rc = -1; |
| 901 | + goto out; |
| 902 | + } |
| 903 | + |
| 904 | + while (true) { |
| 905 | + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); |
| 906 | + if (rc < 0) { |
| 907 | + goto out; |
| 908 | + } else if (rc > 0) { |
| 909 | + break; |
| 910 | + } |
| 911 | + |
| 912 | + if (type == EXPECTED_KEY_TLV) { |
| 913 | + /* |
| 914 | + * Determine which key we should be checking. |
| 915 | + */ |
| 916 | + if (len > KEY_BUF_SIZE) { |
| 917 | + rc = -1; |
| 918 | + goto out; |
| 919 | + } |
| 920 | +#ifndef MCUBOOT_HW_KEY |
| 921 | + rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len); |
| 922 | + if (rc) { |
| 923 | + goto out; |
| 924 | + } |
| 925 | + key_id = bootutil_find_key(buf, len); |
| 926 | +#else |
| 927 | + rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len); |
| 928 | + if (rc) { |
| 929 | + goto out; |
| 930 | + } |
| 931 | + key_id = bootutil_find_key(image_index, key_buf, len); |
| 932 | +#endif /* !MCUBOOT_HW_KEY */ |
| 933 | + /* |
| 934 | + * The key may not be found, which is acceptable. There |
| 935 | + * can be multiple signatures, each preceded by a key. |
| 936 | + */ |
| 937 | + } |
| 938 | + } |
| 939 | +#endif /* EXPECTED_KEY_TLV */ |
| 940 | + |
| 941 | + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIGNATURE, true); |
| 942 | + if (rc) { |
| 943 | + goto out; |
| 944 | + } |
| 945 | + |
| 946 | + if (it.tlv_end > bootutil_max_image_size(state, fap)) { |
| 947 | + rc = -1; |
| 948 | + goto out; |
| 949 | + } |
| 950 | + |
| 951 | + while (true) { |
| 952 | + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); |
| 953 | + if (rc < 0) { |
| 954 | + goto out; |
| 955 | + } else if (rc > 0) { |
| 956 | + rc = 0; |
| 957 | + break; |
| 958 | + } |
| 959 | + |
| 960 | + if (type == IMAGE_TLV_DECOMP_SIGNATURE) { |
| 961 | + /* Ignore this signature if it is out of bounds. */ |
| 962 | + if (key_id < 0 || key_id >= bootutil_key_cnt) { |
| 963 | + key_id = -1; |
| 964 | + continue; |
| 965 | + } |
| 966 | + |
| 967 | + if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { |
| 968 | + rc = -1; |
| 969 | + goto out; |
| 970 | + } |
| 971 | + rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len); |
| 972 | + if (rc) { |
| 973 | + goto out; |
| 974 | + } |
| 975 | + |
| 976 | + FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash), |
| 977 | + buf, len, key_id); |
| 978 | + key_id = -1; |
| 979 | + } |
| 980 | + } |
| 981 | +#endif /* EXPECTED_SIG_TLV */ |
| 982 | + } |
| 983 | +#endif |
| 984 | + |
| 985 | +#ifdef EXPECTED_SIG_TLV |
| 986 | + FIH_SET(fih_rc, valid_signature); |
| 987 | +#endif |
| 988 | + |
763 | 989 | out:
|
764 | 990 | if (rc) {
|
765 | 991 | FIH_SET(fih_rc, FIH_FAILURE);
|
|
0 commit comments