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), &sector);
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