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