diff options
-rw-r--r-- | utils/atj2137/atjboottool/fwu.c | 66 |
1 files changed, 60 insertions, 6 deletions
diff --git a/utils/atj2137/atjboottool/fwu.c b/utils/atj2137/atjboottool/fwu.c index 44281af4f4..82ef28632a 100644 --- a/utils/atj2137/atjboottool/fwu.c +++ b/utils/atj2137/atjboottool/fwu.c | |||
@@ -29,6 +29,11 @@ | |||
29 | { cprintf(RED, str_bad); return 1; } \ | 29 | { cprintf(RED, str_bad); return 1; } \ |
30 | else { cprintf(RED, str_ok); } | 30 | else { cprintf(RED, str_ok); } |
31 | 31 | ||
32 | #define check_field_soft(v_exp, v_have, str_ok, str_bad) \ | ||
33 | if((v_exp) != (v_have)) \ | ||
34 | { cprintf(RED, str_bad); } \ | ||
35 | else { cprintf(RED, str_ok); } | ||
36 | |||
32 | #define FWU_SIG_SIZE 16 | 37 | #define FWU_SIG_SIZE 16 |
33 | #define FWU_BLOCK_SIZE 512 | 38 | #define FWU_BLOCK_SIZE 512 |
34 | 39 | ||
@@ -47,6 +52,19 @@ const uint8_t g_fwu_signature[FWU_SIG_SIZE] = | |||
47 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x75 | 52 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x75 |
48 | }; | 53 | }; |
49 | 54 | ||
55 | struct fwu_tail_t | ||
56 | { | ||
57 | uint8_t length; /* in blocks? it's always 1 */ | ||
58 | uint8_t type; /* always 7 */ | ||
59 | uint8_t reserved[14]; | ||
60 | uint32_t fwu_checksum; | ||
61 | uint32_t flags; /* always 0x55aa55aa */ | ||
62 | uint8_t desc[8]; /* always 'FwuTail' */ | ||
63 | uint8_t fwu_crc_checksum[32]; /* always 0 */ | ||
64 | uint8_t reserved2[444]; | ||
65 | uint32_t fwutail_checksum; | ||
66 | } __attribute__((packed)); | ||
67 | |||
50 | struct version_desc_t | 68 | struct version_desc_t |
51 | { | 69 | { |
52 | uint8_t version; | 70 | uint8_t version; |
@@ -727,6 +745,7 @@ static int get_key_fwu_v3(size_t size, uint8_t *buf, uint8_t *blockA, uint8_t *b | |||
727 | uint8_t ba = buf[0x1ee] & 0xf; | 745 | uint8_t ba = buf[0x1ee] & 0xf; |
728 | uint8_t bb = buf[0x1fe] & 0xf; | 746 | uint8_t bb = buf[0x1fe] & 0xf; |
729 | 747 | ||
748 | cprintf(BLUE, "Crypto\n"); | ||
730 | cprintf_field(" Block A: ", "%d\n", ba + 2); | 749 | cprintf_field(" Block A: ", "%d\n", ba + 2); |
731 | cprintf_field(" Block B: ", "%d\n", ba + bb + 5); | 750 | cprintf_field(" Block B: ", "%d\n", ba + bb + 5); |
732 | 751 | ||
@@ -882,6 +901,7 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f | |||
882 | uint8_t blockA; | 901 | uint8_t blockA; |
883 | uint8_t blockB; | 902 | uint8_t blockB; |
884 | uint8_t keybuf[32]; | 903 | uint8_t keybuf[32]; |
904 | struct fwu_hdr_t *hdr = (void *)buf; | ||
885 | memset(keybuf, 0, sizeof(keybuf)); | 905 | memset(keybuf, 0, sizeof(keybuf)); |
886 | int ret = get_key_fwu_v3(*size, buf, &blockA, &blockB, keybuf, block); | 906 | int ret = get_key_fwu_v3(*size, buf, &blockA, &blockB, keybuf, block); |
887 | if(ret != 0) | 907 | if(ret != 0) |
@@ -890,6 +910,7 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f | |||
890 | size_t file_size = *size; | 910 | size_t file_size = *size; |
891 | /* the input buffer is reorganized based on two offsets (blockA and blockB), | 911 | /* the input buffer is reorganized based on two offsets (blockA and blockB), |
892 | * skip 2048 bytes of data used for crypto init */ | 912 | * skip 2048 bytes of data used for crypto init */ |
913 | *size = hdr->fw_size; /* use firmware size, not file size */ | ||
893 | *size -= 2048; | 914 | *size -= 2048; |
894 | uint8_t *tmpbuf = malloc(*size); | 915 | uint8_t *tmpbuf = malloc(*size); |
895 | memset(tmpbuf, 0, *size); | 916 | memset(tmpbuf, 0, *size); |
@@ -919,12 +940,7 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f | |||
919 | rounds_to_perform = 1; | 940 | rounds_to_perform = 1; |
920 | /* the ATJ213x and ATJ2127 do not use the same encryption at this point, and I | 941 | /* the ATJ213x and ATJ2127 do not use the same encryption at this point, and I |
921 | * don't see any obvious way to tell which encryption is used (since they | 942 | * don't see any obvious way to tell which encryption is used (since they |
922 | * use the same version above). The only difference is that ATJ2127 images | 943 | * use the same version above). */ |
923 | * I have seen have an extra 512 bytes at the end file (ie the actual file | ||
924 | * is 512 bytes larger than indicated by the header) but I don't know if this | ||
925 | * is the case for all files. Thus, unless the user force encryption mode, | ||
926 | * try both and see if one looks like an AFI file. To guess which one to use, | ||
927 | * decrypt the first sector and see if it looks like an AFI file */ | ||
928 | bool is_atj2127 = false; | 944 | bool is_atj2127 = false; |
929 | if(mode == FWU_AUTO) | 945 | if(mode == FWU_AUTO) |
930 | { | 946 | { |
@@ -951,6 +967,17 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f | |||
951 | return 0; | 967 | return 0; |
952 | } | 968 | } |
953 | 969 | ||
970 | uint32_t fwu_checksum(void *buf, size_t size) | ||
971 | { | ||
972 | if(size % 4) | ||
973 | cprintf(GREY, "WARNING: checksum of buffer whose length is not a multiple of 4"); | ||
974 | uint32_t *p = buf; | ||
975 | uint32_t sum = 0; | ||
976 | for(size_t i = 0; i < size / 4; i++) | ||
977 | sum += *p++; | ||
978 | return sum; | ||
979 | } | ||
980 | |||
954 | int fwu_decrypt(uint8_t *buf, size_t *size, enum fwu_mode_t mode) | 981 | int fwu_decrypt(uint8_t *buf, size_t *size, enum fwu_mode_t mode) |
955 | { | 982 | { |
956 | struct fwu_hdr_t *hdr = (void *)buf; | 983 | struct fwu_hdr_t *hdr = (void *)buf; |
@@ -1010,6 +1037,33 @@ int fwu_decrypt(uint8_t *buf, size_t *size, enum fwu_mode_t mode) | |||
1010 | return 2; | 1037 | return 2; |
1011 | } | 1038 | } |
1012 | 1039 | ||
1040 | /* check whether the firmware has a FwuTail (as far as I know, there is no flag anywhere that | ||
1041 | * indicates its presence or not) */ | ||
1042 | struct fwu_tail_t *tail = (void *)(buf + hdr->fw_size - sizeof(struct fwu_tail_t)); | ||
1043 | if(tail->flags == 0x55aa55aa && strcmp((char *)tail->desc, "FwuTail") == 0) | ||
1044 | { | ||
1045 | cprintf(BLUE, "Tail\n"); | ||
1046 | cprintf_field(" Length: ", "%d ", tail->length); | ||
1047 | check_field_soft(tail->length, 1, "Ok\n", "Fail\n"); | ||
1048 | cprintf_field(" Type: ", "%d ", tail->type); | ||
1049 | check_field_soft(tail->type, 7, "Ok\n", "Fail\n"); | ||
1050 | cprintf_field(" FW checksum: ", "%x ", tail->fwu_checksum); | ||
1051 | check_field_soft(fwu_checksum(buf, hdr->fw_size - sizeof(struct fwu_tail_t)), | ||
1052 | tail->fwu_checksum, "Ok\n", "Mismatch\n"); | ||
1053 | cprintf(GREEN, " FW CRC Checksum: "); | ||
1054 | for(unsigned i = 0; i < sizeof(tail->fwu_crc_checksum); i++) | ||
1055 | cprintf(YELLOW, "%02x", tail->fwu_crc_checksum[i]); | ||
1056 | cprintf(RED, " Ignored (should be 0)\n"); | ||
1057 | cprintf_field(" Tail checksum: ", "%x ", tail->fwutail_checksum); | ||
1058 | check_field_soft(fwu_checksum(tail, sizeof(struct fwu_tail_t) - 4), | ||
1059 | tail->fwutail_checksum, "Ok\n", "Mismatch\n"); | ||
1060 | /* if it has a tail, the firmware size includes it, so we need to decrease it to avoid | ||
1061 | * "decrypting" the tail and output garbage */ | ||
1062 | hdr->fw_size -= sizeof(struct fwu_tail_t); | ||
1063 | } | ||
1064 | else | ||
1065 | cprintf(BLUE, "Firmware does not seem to have a tail\n"); | ||
1066 | |||
1013 | if(g_version[ver].version == 3) | 1067 | if(g_version[ver].version == 3) |
1014 | { | 1068 | { |
1015 | uint8_t block[512]; | 1069 | uint8_t block[512]; |