|
32 | 32 |
|
33 | 33 | #ifdef WOLFBOOT_GZIP |
34 | 34 | #include "gzip.h" |
35 | | -#ifdef WOLFBOOT_HASH_SHA256 |
36 | | -#include <wolfssl/wolfcrypt/sha256.h> |
37 | 35 | #endif |
38 | | -#ifdef WOLFBOOT_HASH_SHA384 |
39 | | -#include <wolfssl/wolfcrypt/sha512.h> |
40 | | -#endif |
41 | | -#endif /* WOLFBOOT_GZIP */ |
42 | 36 |
|
43 | 37 | /* Default upper bound on a single FIT subimage's decompressed size. |
44 | 38 | * The outer wolfBoot signature already authenticates the FIT, but a |
@@ -902,142 +896,68 @@ int fdt_fixup_initrd(void* fdt, uint64_t start, uint64_t size) |
902 | 896 | return 0; |
903 | 897 | } |
904 | 898 |
|
905 | | -#ifdef WOLFBOOT_GZIP |
906 | | -/* Verify FIT per-subimage hash-1 subnode against the loaded/decompressed |
907 | | - * image bytes. This is defense-in-depth: the outer wolfBoot signature |
908 | | - * already authenticates the entire FIT blob, but recomputing the per-image |
909 | | - * hash catches inflater bugs and corrupt streams that still parse. |
910 | | - * |
911 | | - * Returns 0 on success or when no usable hash node is present. |
912 | | - * Returns negative on hash mismatch. |
913 | | - * |
914 | | - * If hash-1.algo names an algorithm that is not compiled into this build, |
915 | | - * a warning is printed and 0 is returned (best-effort verification). */ |
916 | | -static int fit_verify_hash(const void *fdt, int img_off, |
917 | | - const uint8_t *data, uint32_t data_len) |
918 | | -{ |
919 | | - int ret = 0; |
920 | | - int done = 0; |
921 | | - int hash_off, len = 0; |
922 | | - const char *algo = NULL; |
923 | | - const uint8_t *value = NULL; |
924 | | -#if defined(WOLFBOOT_HASH_SHA256) || defined(WOLFBOOT_HASH_SHA384) |
925 | | - int did_init = 0; |
926 | | -#endif |
927 | | -#ifdef WOLFBOOT_HASH_SHA256 |
928 | | - wc_Sha256 sha256_ctx; |
929 | | - uint8_t sha256_digest[WC_SHA256_DIGEST_SIZE]; |
930 | | -#endif |
931 | | -#ifdef WOLFBOOT_HASH_SHA384 |
932 | | - wc_Sha384 sha384_ctx; |
933 | | - uint8_t sha384_digest[WC_SHA384_DIGEST_SIZE]; |
| 899 | +#ifdef WOLFBOOT_FIT_RAMDISK |
| 900 | +/* Defensive fallback: targets without a fixed relocation address |
| 901 | + * leave WOLFBOOT_LOAD_RAMDISK_ADDRESS at 0, in which case the |
| 902 | + * ramdisk is used in place. */ |
| 903 | +#ifndef WOLFBOOT_LOAD_RAMDISK_ADDRESS |
| 904 | +#define WOLFBOOT_LOAD_RAMDISK_ADDRESS 0 |
934 | 905 | #endif |
935 | 906 |
|
936 | | - hash_off = fdt_subnode_offset_namelen(fdt, img_off, "hash-1", 6); |
937 | | - if (hash_off < 0) { |
938 | | - done = 1; /* no hash-1 subnode; nothing to verify */ |
939 | | - } |
| 907 | +/* Load a FIT ramdisk subimage and patch the DTB's /chosen |
| 908 | + * linux,initrd-{start,end} to point at it. If |
| 909 | + * WOLFBOOT_LOAD_RAMDISK_ADDRESS is nonzero, the ramdisk is relocated |
| 910 | + * to that fixed address (overrides the FIT's `load` property); |
| 911 | + * otherwise the address fit_load_image returned (FIT-specified or |
| 912 | + * in-FIT pointer) is used as-is. Caller passes the DTB pointer for |
| 913 | + * the initrd fixup, or NULL to skip the fixup. |
| 914 | + * |
| 915 | + * Returns 0 on success, -1 if the ramdisk node was found but the |
| 916 | + * load failed. The current callers ignore the return value |
| 917 | + * (log-and-continue), so a missing/failed ramdisk does not abort |
| 918 | + * the boot. */ |
| 919 | +int fit_load_ramdisk(void* fit, const char* ramdisk_node, void* dts_addr) |
| 920 | +{ |
| 921 | + int rd_size = 0; |
| 922 | + uint8_t *rd_ptr; |
| 923 | + uint8_t *rd_dst; |
940 | 924 |
|
941 | | - if (!done) { |
942 | | - algo = (const char*)fdt_getprop(fdt, hash_off, "algo", &len); |
943 | | - if (algo == NULL || len <= 0) { |
944 | | - wolfBoot_printf("FIT hash-1: missing algo\n"); |
945 | | - done = 1; |
946 | | - } |
| 925 | + if (fit == NULL || ramdisk_node == NULL) { |
| 926 | + return -1; |
947 | 927 | } |
948 | 928 |
|
949 | | - if (!done) { |
950 | | - value = (const uint8_t*)fdt_getprop(fdt, hash_off, "value", &len); |
951 | | - if (value == NULL) { |
952 | | - /* mkimage emits the hash node but populates 'value' only after |
953 | | - * signing; an empty 'value' on an unsigned tree is benign. */ |
954 | | - done = 1; |
955 | | - } |
| 929 | + rd_ptr = (uint8_t*)fit_load_image(fit, ramdisk_node, &rd_size); |
| 930 | + if (rd_ptr == NULL || rd_size <= 0) { |
| 931 | + wolfBoot_printf("FIT: ramdisk node present but load failed\n"); |
| 932 | + return -1; |
956 | 933 | } |
957 | 934 |
|
958 | | -#ifdef WOLFBOOT_HASH_SHA256 |
959 | | - if (!done && strcmp(algo, "sha256") == 0) { |
960 | | - if (len != WC_SHA256_DIGEST_SIZE) { |
961 | | - wolfBoot_printf("FIT hash-1: bad sha256 value len %d\n", len); |
962 | | - ret = -1; |
963 | | - } |
964 | | - if (ret == 0) { |
965 | | - ret = wc_InitSha256(&sha256_ctx); |
966 | | - if (ret == 0) { |
967 | | - did_init = 1; |
968 | | - } |
969 | | - } |
970 | | - if (ret == 0) { |
971 | | - ret = wc_Sha256Update(&sha256_ctx, data, (word32)data_len); |
972 | | - } |
973 | | - if (ret == 0) { |
974 | | - ret = wc_Sha256Final(&sha256_ctx, sha256_digest); |
975 | | - } |
976 | | - if (did_init) { |
977 | | - wc_Sha256Free(&sha256_ctx); |
978 | | - did_init = 0; |
979 | | - } |
980 | | - if (ret != 0) { |
981 | | - wolfBoot_printf("FIT hash-1 (sha256): wc_Sha256 failed rc=%d\n", |
982 | | - ret); |
983 | | - ret = -1; |
984 | | - } |
985 | | - else if (memcmp(sha256_digest, value, WC_SHA256_DIGEST_SIZE) != 0) { |
986 | | - wolfBoot_printf("FIT hash-1 (sha256): MISMATCH\n"); |
987 | | - ret = -1; |
| 935 | + if (WOLFBOOT_LOAD_RAMDISK_ADDRESS != 0) { |
| 936 | + rd_dst = (uint8_t*)WOLFBOOT_LOAD_RAMDISK_ADDRESS; |
| 937 | + if (rd_ptr != rd_dst) { |
| 938 | + wolfBoot_printf("Loading ramdisk: %p -> %p (%d bytes)\n", |
| 939 | + rd_ptr, rd_dst, rd_size); |
| 940 | + memcpy(rd_dst, rd_ptr, rd_size); |
988 | 941 | } |
989 | 942 | else { |
990 | | - wolfBoot_printf("FIT hash-1 (sha256): OK\n"); |
| 943 | + wolfBoot_printf("Loaded ramdisk: %p (%d bytes)\n", |
| 944 | + rd_dst, rd_size); |
991 | 945 | } |
992 | | - done = 1; |
993 | 946 | } |
994 | | -#endif |
995 | | - |
996 | | -#ifdef WOLFBOOT_HASH_SHA384 |
997 | | - if (!done && strcmp(algo, "sha384") == 0) { |
998 | | - if (len != WC_SHA384_DIGEST_SIZE) { |
999 | | - wolfBoot_printf("FIT hash-1: bad sha384 value len %d\n", len); |
1000 | | - ret = -1; |
1001 | | - } |
1002 | | - if (ret == 0) { |
1003 | | - ret = wc_InitSha384(&sha384_ctx); |
1004 | | - if (ret == 0) { |
1005 | | - did_init = 1; |
1006 | | - } |
1007 | | - } |
1008 | | - if (ret == 0) { |
1009 | | - ret = wc_Sha384Update(&sha384_ctx, data, (word32)data_len); |
1010 | | - } |
1011 | | - if (ret == 0) { |
1012 | | - ret = wc_Sha384Final(&sha384_ctx, sha384_digest); |
1013 | | - } |
1014 | | - if (did_init) { |
1015 | | - wc_Sha384Free(&sha384_ctx); |
1016 | | - did_init = 0; |
1017 | | - } |
1018 | | - if (ret != 0) { |
1019 | | - wolfBoot_printf("FIT hash-1 (sha384): wc_Sha384 failed rc=%d\n", |
1020 | | - ret); |
1021 | | - ret = -1; |
1022 | | - } |
1023 | | - else if (memcmp(sha384_digest, value, WC_SHA384_DIGEST_SIZE) != 0) { |
1024 | | - wolfBoot_printf("FIT hash-1 (sha384): MISMATCH\n"); |
1025 | | - ret = -1; |
1026 | | - } |
1027 | | - else { |
1028 | | - wolfBoot_printf("FIT hash-1 (sha384): OK\n"); |
1029 | | - } |
1030 | | - done = 1; |
| 947 | + else { |
| 948 | + rd_dst = rd_ptr; |
| 949 | + wolfBoot_printf("Loaded ramdisk: %p (%d bytes)\n", |
| 950 | + rd_dst, rd_size); |
1031 | 951 | } |
1032 | | -#endif |
1033 | 952 |
|
1034 | | - if ((ret == 0) && !done) { |
1035 | | - wolfBoot_printf("FIT hash-1: algo '%s' not built in, skipping\n", |
1036 | | - algo); |
| 953 | + if (dts_addr != NULL) { |
| 954 | + (void)fdt_fixup_initrd(dts_addr, |
| 955 | + (uint64_t)(uintptr_t)rd_dst, (uint64_t)rd_size); |
1037 | 956 | } |
1038 | | - return ret; |
| 957 | + |
| 958 | + return 0; |
1039 | 959 | } |
1040 | | -#endif /* WOLFBOOT_GZIP */ |
| 960 | +#endif /* WOLFBOOT_FIT_RAMDISK */ |
1041 | 961 |
|
1042 | 962 | void* fit_load_image_ex(void* fdt, const char* image, int* lenp, |
1043 | 963 | uint32_t out_max) |
@@ -1112,16 +1032,18 @@ void* fit_load_image_ex(void* fdt, const char* image, int* lenp, |
1112 | 1032 | memcpy(load, data, len); |
1113 | 1033 | } |
1114 | 1034 |
|
1115 | | -#ifdef WOLFBOOT_GZIP |
1116 | | - /* Defense-in-depth: verify FIT hash-1 against loaded |
1117 | | - * bytes */ |
1118 | | - if (fit_verify_hash(fdt, off, (const uint8_t*)load, |
1119 | | - (uint32_t)len) != 0) { |
1120 | | - wolfBoot_printf("FIT hash verification failed for " |
1121 | | - "%s\n", image); |
1122 | | - return NULL; |
1123 | | - } |
1124 | | -#endif |
| 1035 | + /* No per-image hash-1 re-verification here. Per the |
| 1036 | + * FIT spec (and U-Boot's reference implementation), a |
| 1037 | + * hash-N subnode's value is computed over the image |
| 1038 | + * node's `data` property bytes verbatim - which means |
| 1039 | + * the compressed bytes when compression="gzip". The |
| 1040 | + * outer wolfBoot signature |
| 1041 | + * (wolfBoot_verify_authenticity) already authenticates |
| 1042 | + * the entire FIT, including those data bytes, so a |
| 1043 | + * runtime per-image hash check would be redundant. |
| 1044 | + * Inflater bugs on the decompressed payload are |
| 1045 | + * caught by gzip's own CRC32 + ISIZE trailer inside |
| 1046 | + * wolfBoot_gunzip. */ |
1125 | 1047 |
|
1126 | 1048 | /* load should always have entry, but if not use load |
1127 | 1049 | * address */ |
|
0 commit comments