1 /*
2 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Copyright (c) 2020-2023 Nordic Semiconductor ASA
5 * Copyright (c) 2020 Arm Limited
6 */
7
8 #include <assert.h>
9 #include "bootutil/image.h"
10 #include <../src/bootutil_priv.h>
11 #include "bootutil/bootutil_log.h"
12 #include "bootutil/bootutil_public.h"
13 #include "bootutil/fault_injection_hardening.h"
14 #include "bootutil/enc_key.h"
15
16 #include "mcuboot_config/mcuboot_config.h"
17
18 #ifdef MCUBOOT_ENC_IMAGES
19
20 BOOT_LOG_MODULE_DECLARE(serial_encryption);
21
22 fih_ret
boot_image_validate_encrypted(const struct flash_area * fa_p,struct image_header * hdr,uint8_t * buf,uint16_t buf_size)23 boot_image_validate_encrypted(const struct flash_area *fa_p,
24 struct image_header *hdr, uint8_t *buf,
25 uint16_t buf_size)
26 {
27 FIH_DECLARE(fih_rc, FIH_FAILURE);
28
29 struct boot_loader_state boot_data;
30 struct boot_loader_state *state = &boot_data;
31 struct boot_status _bs;
32 struct boot_status *bs = &_bs;
33 uint8_t image_index;
34 int rc;
35
36 memset(&boot_data, 0, sizeof(struct boot_loader_state));
37 image_index = BOOT_CURR_IMG(state);
38 if(IS_ENCRYPTED(hdr)) {
39 rc = boot_enc_load(BOOT_CURR_ENC(state), 1, hdr, fa_p, bs);
40 if (rc < 0) {
41 FIH_RET(fih_rc);
42 }
43 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs);
44 if (rc < 0) {
45 FIH_RET(fih_rc);
46 }
47 }
48 FIH_CALL(bootutil_img_validate, fih_rc, BOOT_CURR_ENC(state), image_index,
49 hdr, fa_p, buf, buf_size, NULL, 0, NULL);
50
51 FIH_RET(fih_rc);
52 }
53
54 /*
55 * Compute the total size of the given image. Includes the size of
56 * the TLVs.
57 */
58 static int
read_image_size(const struct flash_area * fa_p,struct image_header * hdr,uint32_t * size)59 read_image_size(const struct flash_area *fa_p,
60 struct image_header *hdr,
61 uint32_t *size)
62 {
63 struct image_tlv_info info;
64 uint32_t off;
65 uint32_t protect_tlv_size;
66 int rc;
67
68 off = BOOT_TLV_OFF(hdr);
69
70 if (flash_area_read(fa_p, off, &info, sizeof(info))) {
71 rc = BOOT_EFLASH;
72 goto done;
73 }
74
75 protect_tlv_size = hdr->ih_protect_tlv_size;
76 if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
77 if (protect_tlv_size != info.it_tlv_tot) {
78 rc = BOOT_EBADIMAGE;
79 goto done;
80 }
81
82 if (flash_area_read(fa_p, off + info.it_tlv_tot, &info, sizeof(info))) {
83 rc = BOOT_EFLASH;
84 goto done;
85 }
86 } else if (protect_tlv_size != 0) {
87 rc = BOOT_EBADIMAGE;
88 goto done;
89 }
90
91 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
92 rc = BOOT_EBADIMAGE;
93 goto done;
94 }
95
96 *size = off + protect_tlv_size + info.it_tlv_tot;
97 rc = 0;
98
99 done:
100 return rc;
101 }
102
103 /**
104 * reads, decrypts in RAM & write back the decrypted image in the same region
105 * This function is NOT power failsafe since the image is decrypted in the RAM
106 * buffer.
107 *
108 * @param flash_area The ID of the source flash area.
109 * @param off_src The offset within the flash area to
110 * copy from.
111 * @param sz The number of bytes to copy. should match erase sector
112 *
113 * @return 0 on success; nonzero on failure.
114 */
115 static int
decrypt_region_inplace(struct boot_loader_state * state,const struct flash_area * fap,struct image_header * hdr,uint32_t off,uint32_t sz)116 decrypt_region_inplace(struct boot_loader_state *state,
117 const struct flash_area *fap,
118 struct image_header *hdr,
119 uint32_t off, uint32_t sz)
120 {
121 uint32_t bytes_copied;
122 int chunk_sz;
123 int rc;
124 uint32_t tlv_off;
125 size_t blk_off;
126 uint16_t idx;
127 uint32_t blk_sz;
128 int slot = flash_area_id_to_multi_image_slot(BOOT_CURR_IMG(state),
129 flash_area_get_id(fap));
130 uint8_t buf[sz] __attribute__((aligned));
131 assert(sz <= sizeof buf);
132 assert(slot >= 0);
133
134 bytes_copied = 0;
135 while (bytes_copied < sz) {
136 if (sz - bytes_copied > sizeof buf) {
137 chunk_sz = sizeof buf;
138 } else {
139 chunk_sz = sz - bytes_copied;
140 }
141
142 rc = flash_area_read(fap, off + bytes_copied, buf, chunk_sz);
143 if (rc != 0) {
144 return BOOT_EFLASH;
145 }
146
147 if (IS_ENCRYPTED(hdr)) {
148 blk_sz = chunk_sz;
149 idx = 0;
150 if (off + bytes_copied < hdr->ih_hdr_size) {
151 /* do not decrypt header */
152 if (hdr->ih_hdr_size > (off + bytes_copied + chunk_sz)) {
153 /* all bytes in header, skip decryption */
154 blk_sz = 0;
155 }
156 else {
157 blk_sz = off + bytes_copied + chunk_sz - hdr->ih_hdr_size;
158 }
159
160 blk_off = 0;
161 idx = hdr->ih_hdr_size;
162 } else {
163 blk_off = ((off + bytes_copied) - hdr->ih_hdr_size) & 0xf;
164 }
165 tlv_off = BOOT_TLV_OFF(hdr);
166 if (off + bytes_copied + chunk_sz > tlv_off) {
167 /* do not decrypt TLVs */
168 if (off + bytes_copied >= tlv_off) {
169 blk_sz = 0;
170 } else {
171 blk_sz = tlv_off - (off + bytes_copied);
172 }
173 }
174 boot_enc_decrypt(BOOT_CURR_ENC(state), slot,
175 (off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
176 blk_off, &buf[idx]);
177 }
178 rc = flash_area_erase(fap, off + bytes_copied, chunk_sz);
179 if (rc != 0) {
180 return BOOT_EFLASH;
181 }
182 rc = flash_area_write(fap, off + bytes_copied, buf, chunk_sz);
183 if (rc != 0) {
184 return BOOT_EFLASH;
185 }
186
187 bytes_copied += chunk_sz;
188
189 MCUBOOT_WATCHDOG_FEED();
190 }
191
192 return 0;
193 }
194
195 /**
196 * Check if a image was encrypted into the first slot, and decrypt it
197 * in place. this operation is not power failsafe.
198 *
199 * The operation is done by checking the last flash sector, and using it as a
200 * temporarely scratch partition. The
201 *
202 * @param[in] fa_p flash area pointer
203 * @param[in] hdr boot image header pointer
204 *
205 * @return FIH_SUCCESS on success, error code otherwise
206 */
207 inline static fih_ret
decrypt_image_inplace(const struct flash_area * fa_p,struct image_header * hdr)208 decrypt_image_inplace(const struct flash_area *fa_p,
209 struct image_header *hdr)
210 {
211 FIH_DECLARE(fih_rc, FIH_FAILURE);
212 int rc;
213 struct boot_loader_state boot_data;
214 struct boot_loader_state *state = &boot_data;
215 struct boot_status _bs;
216 struct boot_status *bs = &_bs;
217 size_t size;
218 size_t sect_size;
219 size_t sect_count;
220 size_t sect;
221 struct flash_sector sector;
222
223 memset(&boot_data, 0, sizeof(struct boot_loader_state));
224 memset(&_bs, 0, sizeof(struct boot_status));
225
226 /* Get size from last sector to know page/sector erase size */
227 rc = flash_area_get_sector(fa_p, boot_status_off(fa_p), §or);
228
229
230 if(IS_ENCRYPTED(hdr)) {
231 #if 0 //Skip this step?, the image will just not boot if it's not decrypted properly
232 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
233 /* First check if the encrypted image is a good image before decrypting */
234 FIH_CALL(boot_image_validate_encrypted,fih_rc,fa_p,&_hdr,tmpbuf,BOOT_TMPBUF_SZ);
235 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
236 FIH_RET(fih_rc);
237 }
238 #endif
239 memset(&boot_data, 0, sizeof(struct boot_loader_state));
240 /* Load the encryption keys into cache */
241 rc = boot_enc_load(BOOT_CURR_ENC(state), 0, hdr, fa_p, bs);
242 if (rc < 0) {
243 FIH_RET(fih_rc);
244 }
245 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 0, bs)) {
246 FIH_RET(fih_rc);
247 }
248 }
249 else
250 {
251 /* Expected encrypted image! */
252 FIH_RET(fih_rc);
253 }
254
255 uint32_t src_size = 0;
256 rc = read_image_size(fa_p,hdr, &src_size);
257 if (rc != 0) {
258 FIH_RET(fih_rc);
259 }
260
261 /* TODO: This assumes every sector has an equal size, should instead use
262 * flash_area_get_sectors() to get the size of each sector and iterate
263 * over it.
264 */
265 sect_size = sector.fs_size;
266 sect_count = fa_p->fa_size / sect_size;
267 for (sect = 0, size = 0; size < src_size && sect < sect_count; sect++) {
268 rc = decrypt_region_inplace(state, fa_p,hdr, size, sect_size);
269 if (rc != 0) {
270 FIH_RET(fih_rc);
271 }
272 size += sect_size;
273 }
274
275 fih_rc = FIH_SUCCESS;
276 FIH_RET(fih_rc);
277 }
278
279 int
boot_handle_enc_fw(const struct flash_area * flash_area)280 boot_handle_enc_fw(const struct flash_area *flash_area)
281 {
282 int rc = -1;
283 struct image_header _hdr = { 0 };
284 FIH_DECLARE(fih_rc, FIH_FAILURE);
285
286 rc = boot_image_load_header(flash_area, &_hdr);
287 if (rc != 0) {
288 goto out;
289 }
290
291 if (IS_ENCRYPTED(&_hdr)) {
292 //encrypted, we need to decrypt in place
293 FIH_CALL(decrypt_image_inplace,fih_rc,flash_area,&_hdr);
294 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
295 rc = -1;
296 goto out;
297 }
298 }
299 else
300 {
301 rc = 0;
302 }
303
304 out:
305 return rc;
306 }
307
308 #endif
309