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