1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 #include <assert.h>
20 #include <stddef.h>
21 #include <inttypes.h>
22 #include <ctype.h>
23 #include <stdio.h>
24 #include <errno.h>
25 
26 #include "sysflash/sysflash.h"
27 
28 #include "bootutil/bootutil_log.h"
29 
30 #ifdef __ZEPHYR__
31 #include <zephyr/sys/reboot.h>
32 #include <zephyr/sys/byteorder.h>
33 #include <zephyr/sys/__assert.h>
34 #include <zephyr/drivers/flash.h>
35 #include <zephyr/kernel.h>
36 #include <zephyr/sys/crc.h>
37 #include <zephyr/sys/base64.h>
38 #include <hal/hal_flash.h>
39 #elif __ESPRESSIF__
40 #include <bootloader_utility.h>
41 #include <esp_rom_sys.h>
42 #include <esp_crc.h>
43 #include <endian.h>
44 #include <mbedtls/base64.h>
45 #else
46 #include <bsp/bsp.h>
47 #include <hal/hal_system.h>
48 #include <hal/hal_flash.h>
49 #include <os/endian.h>
50 #include <os/os_cputime.h>
51 #include <crc/crc16.h>
52 #include <base64/base64.h>
53 #endif /* __ZEPHYR__ */
54 
55 #include <zcbor_decode.h>
56 #include <zcbor_encode.h>
57 #include "zcbor_bulk.h"
58 
59 #include <flash_map_backend/flash_map_backend.h>
60 #include <os/os.h>
61 #include <os/os_malloc.h>
62 
63 #include <bootutil/image.h>
64 #include <bootutil/bootutil.h>
65 
66 #include "boot_serial/boot_serial.h"
67 #include "boot_serial_priv.h"
68 #include "mcuboot_config/mcuboot_config.h"
69 
70 #ifdef MCUBOOT_ERASE_PROGRESSIVELY
71 #include "bootutil_priv.h"
72 #endif
73 
74 #ifdef MCUBOOT_ENC_IMAGES
75 #include "single_loader.h"
76 #endif
77 
78 #include "bootutil/boot_hooks.h"
79 
80 BOOT_LOG_MODULE_DECLARE(mcuboot);
81 
82 #ifndef ARRAY_SIZE
83 #define ARRAY_SIZE ZCBOR_ARRAY_SIZE
84 #endif
85 
86 #ifndef MCUBOOT_SERIAL_MAX_RECEIVE_SIZE
87 #define MCUBOOT_SERIAL_MAX_RECEIVE_SIZE 512
88 #endif
89 
90 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
91 #define BOOT_SERIAL_IMAGE_STATE_SIZE_MAX 48
92 #else
93 #define BOOT_SERIAL_IMAGE_STATE_SIZE_MAX 0
94 #endif
95 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
96 #define BOOT_SERIAL_HASH_SIZE_MAX 36
97 #else
98 #define BOOT_SERIAL_HASH_SIZE_MAX 0
99 #endif
100 
101 #define BOOT_SERIAL_OUT_MAX     ((128 + BOOT_SERIAL_IMAGE_STATE_SIZE_MAX + \
102                                   BOOT_SERIAL_HASH_SIZE_MAX) * BOOT_IMAGE_NUMBER)
103 
104 #define BOOT_SERIAL_FRAME_MTU   124 /* 127 - pkt start (2 bytes) and stop (1 byte) */
105 
106 #ifdef __ZEPHYR__
107 /* base64 lib encodes data to null-terminated string */
108 #define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
109 
110 #define CRC16_INITIAL_CRC       0       /* what to seed crc16 with */
111 #define CRC_CITT_POLYMINAL 0x1021
112 
113 #define ntohs(x) sys_be16_to_cpu(x)
114 #define htons(x) sys_cpu_to_be16(x)
115 #elif __ESPRESSIF__
116 #define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
117 #define CRC16_INITIAL_CRC       0       /* what to seed crc16 with */
118 
119 #define ntohs(x) be16toh(x)
120 #define htons(x) htobe16(x)
121 
122 #define base64_decode mbedtls_base64_decode
123 #define base64_encode mbedtls_base64_encode
124 #endif
125 
126 #if (BOOT_IMAGE_NUMBER > 1)
127 #define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
128 #else
129 #define IMAGES_ITER(x)
130 #endif
131 
132 static char in_buf[MCUBOOT_SERIAL_MAX_RECEIVE_SIZE + 1];
133 static char dec_buf[MCUBOOT_SERIAL_MAX_RECEIVE_SIZE + 1];
134 const struct boot_uart_funcs *boot_uf;
135 static struct nmgr_hdr *bs_hdr;
136 static bool bs_entry;
137 
138 static char bs_obuf[BOOT_SERIAL_OUT_MAX];
139 
140 static void boot_serial_output(void);
141 
142 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
143 static int boot_serial_get_hash(const struct image_header *hdr,
144                                 const struct flash_area *fap, uint8_t *hash);
145 #endif
146 
147 static zcbor_state_t cbor_state[2];
148 
reset_cbor_state(void)149 void reset_cbor_state(void)
150 {
151     zcbor_new_encode_state(cbor_state, 2, (uint8_t *)bs_obuf,
152         sizeof(bs_obuf), 0);
153 }
154 
155 /**
156  * Function that processes MGMT_GROUP_ID_PERUSER mcumgr group and may be
157  * used to process any groups that have not been processed by generic boot
158  * serial implementation.
159  *
160  * @param[in] hdr -- the decoded header of mcumgr message;
161  * @param[in] buffer -- buffer with first mcumgr message;
162  * @param[in] len -- length of of data in buffer;
163  * @param[out] *cs -- object with encoded response.
164  *
165  * @return 0 on success; non-0 error code otherwise.
166  */
167 extern int bs_peruser_system_specific(const struct nmgr_hdr *hdr,
168                                       const char *buffer,
169                                       int len, zcbor_state_t *cs);
170 
171 #define zcbor_tstr_put_lit_cast(state, string) \
172 	zcbor_tstr_encode_ptr(state, (char *)string, sizeof(string) - 1)
173 
174 #ifndef MCUBOOT_USE_SNPRINTF
175 /*
176  * Convert version into string without use of snprintf().
177  */
178 static int
u32toa(char * tgt,uint32_t val)179 u32toa(char *tgt, uint32_t val)
180 {
181     char *dst;
182     uint32_t d = 1;
183     uint32_t dgt;
184     int n = 0;
185 
186     dst = tgt;
187     while (val / d >= 10) {
188         d *= 10;
189     }
190     while (d) {
191         dgt = val / d;
192         val %= d;
193         d /= 10;
194         if (n || dgt > 0 || d == 0) {
195             *dst++ = dgt + '0';
196             ++n;
197         }
198     }
199     *dst = '\0';
200 
201     return dst - tgt;
202 }
203 
204 /*
205  * dst has to be able to fit "255.255.65535.4294967295" (25 characters).
206  */
207 static void
bs_list_img_ver(char * dst,int maxlen,struct image_version * ver)208 bs_list_img_ver(char *dst, int maxlen, struct image_version *ver)
209 {
210     int off;
211 
212     off = u32toa(dst, ver->iv_major);
213     dst[off++] = '.';
214     off += u32toa(dst + off, ver->iv_minor);
215     dst[off++] = '.';
216     off += u32toa(dst + off, ver->iv_revision);
217 
218     if (ver->iv_build_num != 0) {
219         dst[off++] = '.';
220         off += u32toa(dst + off, ver->iv_build_num);
221     }
222 }
223 #else
224 /*
225  * dst has to be able to fit "255.255.65535.4294967295" (25 characters).
226  */
227 static void
bs_list_img_ver(char * dst,int maxlen,struct image_version * ver)228 bs_list_img_ver(char *dst, int maxlen, struct image_version *ver)
229 {
230    int len;
231 
232    len = snprintf(dst, maxlen, "%hu.%hu.%hu", (uint16_t)ver->iv_major,
233                   (uint16_t)ver->iv_minor, ver->iv_revision);
234 
235    if (ver->iv_build_num != 0 && len > 0 && len < maxlen) {
236       snprintf(&dst[len], (maxlen - len), "%u", ver->iv_build_num);
237    }
238 }
239 #endif /* !MCUBOOT_USE_SNPRINTF */
240 
241 /*
242  * List images.
243  */
244 static void
bs_list(char * buf,int len)245 bs_list(char *buf, int len)
246 {
247     struct image_header hdr;
248     uint32_t slot, area_id;
249     const struct flash_area *fap;
250     uint8_t image_index;
251 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
252     uint8_t hash[32];
253 #endif
254 
255     zcbor_map_start_encode(cbor_state, 1);
256     zcbor_tstr_put_lit_cast(cbor_state, "images");
257     zcbor_list_start_encode(cbor_state, 5);
258     image_index = 0;
259     IMAGES_ITER(image_index) {
260 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
261         int swap_status = boot_swap_type_multi(image_index);
262 #endif
263 
264         for (slot = 0; slot < 2; slot++) {
265             uint8_t tmpbuf[64];
266 
267 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
268             bool active = false;
269             bool confirmed = false;
270             bool pending = false;
271             bool permanent = false;
272 #endif
273 
274             area_id = flash_area_id_from_multi_image_slot(image_index, slot);
275             if (flash_area_open(area_id, &fap)) {
276                 continue;
277             }
278 
279             int rc = BOOT_HOOK_CALL(boot_read_image_header_hook,
280                                     BOOT_HOOK_REGULAR, image_index, slot, &hdr);
281             if (rc == BOOT_HOOK_REGULAR)
282             {
283                 flash_area_read(fap, 0, &hdr, sizeof(hdr));
284             }
285 
286             if (hdr.ih_magic == IMAGE_MAGIC)
287             {
288                 FIH_DECLARE(fih_rc, FIH_FAILURE);
289 
290                 BOOT_HOOK_CALL_FIH(boot_image_check_hook,
291                                    FIH_BOOT_HOOK_REGULAR,
292                                    fih_rc, image_index, slot);
293                 if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR))
294                 {
295 #ifdef MCUBOOT_ENC_IMAGES
296                     if (slot == 0 && IS_ENCRYPTED(&hdr)) {
297                         /* Clear the encrypted flag we didn't supply a key
298                         * This flag could be set if there was a decryption in place
299                         * performed before. We will try to validate the image without
300                         * decryption by clearing the flag in the heder. If
301                         * still encrypted the validation will fail.
302                         */
303                         hdr.ih_flags &= ~(ENCRYPTIONFLAGS);
304                     }
305 #endif
306                     FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, &hdr, fap, tmpbuf, sizeof(tmpbuf),
307                                     NULL, 0, NULL);
308                 }
309 
310                 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
311                     continue;
312                 }
313             }
314 
315 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
316             /* Retrieve SHA256 hash of image for identification */
317             rc = boot_serial_get_hash(&hdr, fap, hash);
318 #endif
319 
320             flash_area_close(fap);
321             zcbor_map_start_encode(cbor_state, 20);
322 
323 #if (BOOT_IMAGE_NUMBER > 1)
324             zcbor_tstr_put_lit_cast(cbor_state, "image");
325             zcbor_uint32_put(cbor_state, image_index);
326 #endif
327 
328 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
329             if (swap_status == BOOT_SWAP_TYPE_NONE) {
330                 if (slot == BOOT_PRIMARY_SLOT) {
331                     confirmed = true;
332                     active = true;
333                 }
334             } else if (swap_status == BOOT_SWAP_TYPE_TEST) {
335                 if (slot == BOOT_PRIMARY_SLOT) {
336                     confirmed = true;
337                 } else {
338                     pending = true;
339                 }
340             } else if (swap_status == BOOT_SWAP_TYPE_PERM) {
341                 if (slot == BOOT_PRIMARY_SLOT) {
342                     confirmed = true;
343                 } else {
344                     pending = true;
345                     permanent = true;
346                 }
347             } else if (swap_status == BOOT_SWAP_TYPE_REVERT) {
348                 if (slot == BOOT_PRIMARY_SLOT) {
349                     active = true;
350                 } else {
351                     confirmed = true;
352                 }
353             }
354 
355             if (!(hdr.ih_flags & IMAGE_F_NON_BOOTABLE)) {
356                 zcbor_tstr_put_lit_cast(cbor_state, "bootable");
357                 zcbor_bool_put(cbor_state, 1);
358             }
359 
360             if (confirmed) {
361                 zcbor_tstr_put_lit_cast(cbor_state, "confirmed");
362                 zcbor_bool_put(cbor_state, true);
363             }
364 
365             if (active) {
366                 zcbor_tstr_put_lit_cast(cbor_state, "active");
367                 zcbor_bool_put(cbor_state, true);
368             }
369 
370             if (pending) {
371                 zcbor_tstr_put_lit_cast(cbor_state, "pending");
372                 zcbor_bool_put(cbor_state, true);
373             }
374 
375             if (permanent) {
376                 zcbor_tstr_put_lit_cast(cbor_state, "permanent");
377                 zcbor_bool_put(cbor_state, true);
378             }
379 #endif
380 
381             zcbor_tstr_put_lit_cast(cbor_state, "slot");
382             zcbor_uint32_put(cbor_state, slot);
383 
384 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
385             if (rc == 0) {
386                 zcbor_tstr_put_lit_cast(cbor_state, "hash");
387                 zcbor_bstr_encode_ptr(cbor_state, hash, sizeof(hash));
388             }
389 #endif
390 
391             zcbor_tstr_put_lit_cast(cbor_state, "version");
392 
393             bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
394 
395             zcbor_tstr_encode_ptr(cbor_state, (char *)tmpbuf, strlen((char *)tmpbuf));
396             zcbor_map_end_encode(cbor_state, 20);
397         }
398     }
399     zcbor_list_end_encode(cbor_state, 5);
400     zcbor_map_end_encode(cbor_state, 1);
401     boot_serial_output();
402 }
403 
404 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
405 /*
406  * Set image state.
407  */
408 static void
bs_set(char * buf,int len)409 bs_set(char *buf, int len)
410 {
411     /*
412      * Expected data format.
413      * {
414      *   "confirm":<true for confirm, false for test>
415      *   "hash":<hash of image (OPTIONAL for single image only)>
416      * }
417      */
418     uint8_t image_index = 0;
419     size_t decoded = 0;
420     uint8_t hash[32];
421     bool confirm;
422     struct zcbor_string img_hash;
423     bool ok;
424     int rc;
425 
426 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
427     bool found = false;
428 #endif
429 
430     zcbor_state_t zsd[4];
431     zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1);
432 
433     struct zcbor_map_decode_key_val image_set_state_decode[] = {
434         ZCBOR_MAP_DECODE_KEY_DECODER("confirm", zcbor_uint32_decode, &confirm),
435 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
436         ZCBOR_MAP_DECODE_KEY_DECODER("hash", zcbor_bstr_decode, &img_hash),
437 #endif
438     };
439 
440     ok = zcbor_map_decode_bulk(zsd, image_set_state_decode, ARRAY_SIZE(image_set_state_decode),
441                                &decoded) == 0;
442 
443     if (!ok || len != decoded) {
444         rc = MGMT_ERR_EINVAL;
445         goto out;
446     }
447 
448 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
449     if ((img_hash.len != sizeof(hash) && img_hash.len != 0) ||
450         (img_hash.len == 0 && BOOT_IMAGE_NUMBER > 1)) {
451         /* Hash is required and was not provided or is invalid size */
452         rc = MGMT_ERR_EINVAL;
453         goto out;
454     }
455 
456     if (img_hash.len != 0) {
457         for (image_index = 0; image_index < BOOT_IMAGE_NUMBER; ++image_index) {
458             struct image_header hdr;
459             uint32_t area_id;
460             const struct flash_area *fap;
461             uint8_t tmpbuf[64];
462 
463             area_id = flash_area_id_from_multi_image_slot(image_index, 1);
464             if (flash_area_open(area_id, &fap)) {
465                 BOOT_LOG_ERR("Failed to open flash area ID %d", area_id);
466                 continue;
467             }
468 
469             rc = BOOT_HOOK_CALL(boot_read_image_header_hook,
470                                 BOOT_HOOK_REGULAR, image_index, 1, &hdr);
471             if (rc == BOOT_HOOK_REGULAR)
472             {
473                 flash_area_read(fap, 0, &hdr, sizeof(hdr));
474             }
475 
476             if (hdr.ih_magic == IMAGE_MAGIC)
477             {
478                 FIH_DECLARE(fih_rc, FIH_FAILURE);
479 
480                 BOOT_HOOK_CALL_FIH(boot_image_check_hook,
481                                    FIH_BOOT_HOOK_REGULAR,
482                                    fih_rc, image_index, 1);
483                 if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR))
484                 {
485                     FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, &hdr, fap,
486                              tmpbuf, sizeof(tmpbuf), NULL, 0, NULL);
487                 }
488 
489                 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
490                     continue;
491                 }
492             }
493 
494             /* Retrieve SHA256 hash of image for identification */
495             rc = boot_serial_get_hash(&hdr, fap, hash);
496             flash_area_close(fap);
497 
498             if (rc == 0 && memcmp(hash, img_hash.value, sizeof(hash)) == 0) {
499                 /* Hash matches, set this slot for test or confirmation */
500                 found = true;
501                 break;
502             }
503         }
504 
505         if (!found) {
506             /* Image was not found with specified hash */
507             BOOT_LOG_ERR("Did not find image with specified hash");
508             rc = MGMT_ERR_ENOENT;
509             goto out;
510         }
511     }
512 #endif
513 
514     rc = boot_set_pending_multi(image_index, confirm);
515 
516 out:
517     if (rc == 0) {
518         /* Success - return updated list of images */
519         bs_list(buf, len);
520     } else {
521         /* Error code, only return the error */
522         zcbor_map_start_encode(cbor_state, 10);
523         zcbor_tstr_put_lit_cast(cbor_state, "rc");
524         zcbor_int32_put(cbor_state, rc);
525         zcbor_map_end_encode(cbor_state, 10);
526 
527         boot_serial_output();
528     }
529 }
530 #endif
531 
532 /*
533  * Send rc code only.
534  */
535 static void
bs_rc_rsp(int rc_code)536 bs_rc_rsp(int rc_code)
537 {
538     zcbor_map_start_encode(cbor_state, 10);
539     zcbor_tstr_put_lit_cast(cbor_state, "rc");
540     zcbor_int32_put(cbor_state, rc_code);
541     zcbor_map_end_encode(cbor_state, 10);
542     boot_serial_output();
543 }
544 
545 static void
bs_list_set(uint8_t op,char * buf,int len)546 bs_list_set(uint8_t op, char *buf, int len)
547 {
548     if (op == NMGR_OP_READ) {
549         bs_list(buf, len);
550     } else {
551 #ifdef MCUBOOT_SERIAL_IMG_GRP_IMAGE_STATE
552         bs_set(buf, len);
553 #else
554         bs_rc_rsp(MGMT_ERR_ENOTSUP);
555 #endif
556     }
557 }
558 
559 #ifdef MCUBOOT_ERASE_PROGRESSIVELY
560 /** Erases range of flash, aligned to sector size
561  *
562  * Function will erase all sectors withing [start, end] range; it does not check
563  * the @p start for alignment, and it will use @p end to find boundaries of las
564  * sector to erase. Function returns offset of the first byte past the last
565  * erased sector, so basically offset of next sector to be erased if needed.
566  * The function is intended to be called iteratively with previously returned
567  * offset as @p start.
568  *
569  * @param   start starting offset, aligned to sector offset;
570  * @param   end ending offset, maybe anywhere within sector;
571  *
572  * @retval On success: offset of the first byte past last erased sector;
573  *         On failure: -EINVAL.
574  */
erase_range(const struct flash_area * fap,off_t start,off_t end)575 static off_t erase_range(const struct flash_area *fap, off_t start, off_t end)
576 {
577     struct flash_sector sect;
578     size_t size;
579     int rc;
580 
581     if (end >= flash_area_get_size(fap)) {
582         return -EINVAL;
583     }
584 
585     if (end < start) {
586         return start;
587     }
588 
589     if (flash_area_get_sector(fap, end, &sect)) {
590         return -EINVAL;
591     }
592 
593     size = flash_sector_get_off(&sect) + flash_sector_get_size(&sect) - start;
594     BOOT_LOG_INF("Erasing range 0x%jx:0x%jx", (intmax_t)start,
595 		 (intmax_t)(start + size - 1));
596 
597     rc = flash_area_erase(fap, start, size);
598     if (rc != 0) {
599         BOOT_LOG_ERR("Error %d while erasing range", rc);
600         return -EINVAL;
601     }
602 
603     return start + size;
604 }
605 #endif
606 
607 /*
608  * Image upload request.
609  */
610 static void
bs_upload(char * buf,int len)611 bs_upload(char *buf, int len)
612 {
613     static size_t img_size;             /* Total image size, held for duration of upload */
614     static uint32_t curr_off;           /* Expected current offset */
615     const uint8_t *img_chunk = NULL;    /* Pointer to buffer with received image chunk */
616     size_t img_chunk_len = 0;           /* Length of received image chunk */
617     size_t img_chunk_off = SIZE_MAX;    /* Offset of image chunk within image  */
618     uint8_t rem_bytes;                  /* Reminder bytes after aligning chunk write to
619                                          * to flash alignment */
620     uint32_t img_num;
621     size_t img_size_tmp = SIZE_MAX;     /* Temp variable for image size */
622     const struct flash_area *fap = NULL;
623     int rc;
624     struct zcbor_string img_chunk_data;
625     size_t decoded = 0;
626     bool ok;
627 #ifdef MCUBOOT_ERASE_PROGRESSIVELY
628     static off_t not_yet_erased = 0;    /* Offset of next byte to erase; writes to flash
629                                          * are done in consecutive manner and erases are done
630                                          * to allow currently received chunk to be written;
631                                          * this state variable holds information where last
632                                          * erase has stopped to let us know whether erase
633                                          * is needed to be able to write current chunk.
634                                          */
635     static struct flash_sector status_sector;
636 #endif
637 
638     zcbor_state_t zsd[4];
639     zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1);
640 
641     struct zcbor_map_decode_key_val image_upload_decode[] = {
642         ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &img_num),
643         ZCBOR_MAP_DECODE_KEY_DECODER("data", zcbor_bstr_decode, &img_chunk_data),
644         ZCBOR_MAP_DECODE_KEY_DECODER("len", zcbor_size_decode, &img_size_tmp),
645         ZCBOR_MAP_DECODE_KEY_DECODER("off", zcbor_size_decode, &img_chunk_off),
646     };
647 
648     ok = zcbor_map_decode_bulk(zsd, image_upload_decode, ARRAY_SIZE(image_upload_decode),
649                                &decoded) == 0;
650 
651     if (!ok) {
652         goto out_invalid_data;
653     }
654 
655     img_chunk = img_chunk_data.value;
656     img_chunk_len = img_chunk_data.len;
657 
658     /*
659      * Expected data format.
660      * {
661      *   "image":<image number in a multi-image set (OPTIONAL)>
662      *   "data":<image data>
663      *   "len":<image len>
664      *   "off":<current offset of image data>
665      * }
666      */
667 
668     if (img_chunk_off == SIZE_MAX || img_chunk == NULL) {
669         /*
670          * Offset must be set in every block.
671          */
672         goto out_invalid_data;
673     }
674 
675 #if !defined(MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD)
676     rc = flash_area_open(flash_area_id_from_multi_image_slot(img_num, 0), &fap);
677 #else
678     rc = flash_area_open(flash_area_id_from_direct_image(img_num), &fap);
679 #endif
680     if (rc) {
681         rc = MGMT_ERR_EINVAL;
682         goto out;
683     }
684 
685     if (img_chunk_off == 0) {
686         /* Receiving chunk with 0 offset resets the upload state; this basically
687          * means that upload has started from beginning.
688          */
689         const size_t area_size = flash_area_get_size(fap);
690 
691         curr_off = 0;
692 #ifdef MCUBOOT_ERASE_PROGRESSIVELY
693         /* Get trailer sector information; this is done early because inability to get
694          * that sector information means that upload will not work anyway.
695          * TODO: This is single occurrence issue, it should get detected during tests
696          * and fixed otherwise you are deploying broken mcuboot.
697          */
698         if (flash_area_get_sector(fap, boot_status_off(fap), &status_sector)) {
699             rc = MGMT_ERR_EUNKNOWN;
700             BOOT_LOG_ERR("Unable to determine flash sector of the image trailer");
701             goto out;
702          }
703 #endif
704 
705 #if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
706         /* We are using swap state at end of flash area to store validation
707          * result. Make sure the user cannot write it from an image to skip validation.
708          */
709         if (img_size_tmp > (area_size - BOOT_MAGIC_SZ)) {
710             goto out_invalid_data;
711         }
712 #else
713         if (img_size_tmp > area_size) {
714             goto out_invalid_data;
715         }
716 
717 #endif
718 
719 #ifndef MCUBOOT_ERASE_PROGRESSIVELY
720         /* Non-progressive erase erases entire image slot when first chunk of
721          * an image is received.
722          */
723         rc = flash_area_erase(fap, 0, area_size);
724         if (rc) {
725             goto out_invalid_data;
726         }
727 #else
728         not_yet_erased = 0;
729 #endif
730 
731         img_size = img_size_tmp;
732     } else if (img_chunk_off != curr_off) {
733         /* If received chunk offset does not match expected one jump, pretend
734          * success and jump to out; out will respond to client with success
735          * and request the expected offset, held by curr_off.
736          */
737         rc = 0;
738         goto out;
739     } else if (curr_off + img_chunk_len > img_size) {
740         rc = MGMT_ERR_EINVAL;
741         goto out;
742     }
743 
744 #ifdef MCUBOOT_ERASE_PROGRESSIVELY
745     /* Progressive erase will erase enough flash, aligned to sector size,
746      * as needed for the current chunk to be written.
747      */
748     not_yet_erased = erase_range(fap, not_yet_erased,
749                                  curr_off + img_chunk_len - 1);
750 
751     if (not_yet_erased < 0) {
752         rc = MGMT_ERR_EINVAL;
753         goto out;
754     }
755 #endif
756 
757     /* Writes are aligned to flash write alignment, so may drop a few bytes
758      * from the end of the buffer; we will request these bytes again with
759      * new buffer by responding with request for offset after the last aligned
760      * write.
761      */
762     rem_bytes = img_chunk_len % flash_area_align(fap);
763     img_chunk_len -= rem_bytes;
764 
765     if (curr_off + img_chunk_len + rem_bytes < img_size) {
766         rem_bytes = 0;
767     }
768 
769     BOOT_LOG_INF("Writing at 0x%x until 0x%x", curr_off, curr_off + img_chunk_len);
770     /* Write flash aligned chunk, note that img_chunk_len now holds aligned length */
771 #if defined(MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE) && MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE > 0
772     if (flash_area_align(fap) > 1 &&
773         (((size_t)img_chunk) & (flash_area_align(fap) - 1)) != 0) {
774         /* Buffer address incompatible with write address, use buffer to write */
775         uint8_t write_size = MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE;
776         uint8_t wbs_aligned[MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE];
777 
778         while (img_chunk_len >= flash_area_align(fap)) {
779             if (write_size > img_chunk_len) {
780                 write_size = img_chunk_len;
781             }
782 
783             memset(wbs_aligned, flash_area_erased_val(fap), sizeof(wbs_aligned));
784             memcpy(wbs_aligned, img_chunk, write_size);
785 
786             rc = flash_area_write(fap, curr_off, wbs_aligned, write_size);
787 
788             if (rc != 0) {
789                 goto out;
790             }
791 
792             curr_off += write_size;
793             img_chunk += write_size;
794             img_chunk_len -= write_size;
795         }
796     } else {
797         rc = flash_area_write(fap, curr_off, img_chunk, img_chunk_len);
798     }
799 #else
800     rc = flash_area_write(fap, curr_off, img_chunk, img_chunk_len);
801 #endif
802 
803     if (rc == 0 && rem_bytes) {
804         /* Non-zero rem_bytes means that last chunk needs alignment; the aligned
805          * part, in the img_chunk_len - rem_bytes count bytes, has already been
806          * written by the above write, so we are left with the rem_bytes.
807          */
808         uint8_t wbs_aligned[BOOT_MAX_ALIGN];
809 
810         memset(wbs_aligned, flash_area_erased_val(fap), sizeof(wbs_aligned));
811         memcpy(wbs_aligned, img_chunk + img_chunk_len, rem_bytes);
812 
813         rc = flash_area_write(fap, curr_off + img_chunk_len, wbs_aligned,
814                               flash_area_align(fap));
815     }
816 
817     if (rc == 0) {
818         curr_off += img_chunk_len + rem_bytes;
819         if (curr_off == img_size) {
820 #ifdef MCUBOOT_ERASE_PROGRESSIVELY
821             /* Assure that sector for image trailer was erased. */
822             /* Check whether it was erased during previous upload. */
823             off_t start = flash_sector_get_off(&status_sector);
824 
825             if (erase_range(fap, start, start) < 0) {
826                 rc = MGMT_ERR_EUNKNOWN;
827                 goto out;
828             }
829 #endif
830             rc = BOOT_HOOK_CALL(boot_serial_uploaded_hook, 0, img_num, fap,
831                                 img_size);
832             if (rc) {
833                 BOOT_LOG_ERR("Error %d post upload hook", rc);
834                 goto out;
835             }
836         }
837     } else {
838     out_invalid_data:
839         rc = MGMT_ERR_EINVAL;
840     }
841 
842 out:
843     BOOT_LOG_INF("RX: 0x%x", rc);
844     zcbor_map_start_encode(cbor_state, 10);
845     zcbor_tstr_put_lit_cast(cbor_state, "rc");
846     zcbor_int32_put(cbor_state, rc);
847     if (rc == 0) {
848         zcbor_tstr_put_lit_cast(cbor_state, "off");
849         zcbor_uint32_put(cbor_state, curr_off);
850     }
851     zcbor_map_end_encode(cbor_state, 10);
852 
853     boot_serial_output();
854     flash_area_close(fap);
855 
856 #ifdef MCUBOOT_ENC_IMAGES
857     if (curr_off == img_size) {
858         /* Last sector received, now start a decryption on the image if it is encrypted*/
859         rc = boot_handle_enc_fw();
860     }
861 #endif //#ifdef MCUBOOT_ENC_IMAGES
862 }
863 
864 #ifdef MCUBOOT_BOOT_MGMT_ECHO
865 static void
bs_echo(char * buf,int len)866 bs_echo(char *buf, int len)
867 {
868     struct zcbor_string value = { 0 };
869     struct zcbor_string key;
870     bool ok;
871     uint32_t rc = MGMT_ERR_EINVAL;
872 
873     zcbor_state_t zsd[4];
874     zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1);
875 
876     if (!zcbor_map_start_decode(zsd)) {
877         goto out;
878     }
879 
880     do {
881         ok = zcbor_tstr_decode(zsd, &key);
882 
883         if (ok) {
884             if (key.len == 1 && *key.value == 'd') {
885                 ok = zcbor_tstr_decode(zsd, &value);
886                 break;
887             }
888 
889             ok = zcbor_any_skip(zsd, NULL);
890         }
891     } while (ok);
892 
893     if (!ok || !zcbor_map_end_decode(zsd)) {
894         goto out;
895     }
896 
897     zcbor_map_start_encode(cbor_state, 10);
898     zcbor_tstr_put_term(cbor_state, "r");
899     if (zcbor_tstr_encode(cbor_state, &value) && zcbor_map_end_encode(cbor_state, 10)) {
900         boot_serial_output();
901         return;
902     } else {
903         rc = MGMT_ERR_ENOMEM;
904     }
905 
906 out:
907     reset_cbor_state();
908     bs_rc_rsp(rc);
909 }
910 #endif
911 
912 /*
913  * Reset, and (presumably) boot to newly uploaded image. Flush console
914  * before restarting.
915  */
916 static void
bs_reset(char * buf,int len)917 bs_reset(char *buf, int len)
918 {
919     int rc = BOOT_HOOK_CALL(boot_reset_request_hook, 0, false);
920     if (rc == BOOT_RESET_REQUEST_HOOK_BUSY) {
921 	rc = MGMT_ERR_EBUSY;
922     } else {
923         /* Currently whatever else is returned it is just converted
924          * to 0/no error. Boot serial starts accepting "force" parameter
925          * in command this needs to change.
926          */
927          rc = 0;
928     }
929     bs_rc_rsp(rc);
930 
931     if (rc == 0) {
932 #ifdef __ZEPHYR__
933 #ifdef CONFIG_MULTITHREADING
934         k_sleep(K_MSEC(250));
935 #else
936         k_busy_wait(250000);
937 #endif
938         sys_reboot(SYS_REBOOT_COLD);
939 #elif __ESPRESSIF__
940         esp_rom_delay_us(250000);
941         bootloader_reset();
942 #else
943         os_cputime_delay_usecs(250000);
944         hal_system_reset();
945 #endif
946     }
947 }
948 
949 /*
950  * Parse incoming line of input from console.
951  * Expect newtmgr protocol with serial transport.
952  */
953 void
boot_serial_input(char * buf,int len)954 boot_serial_input(char *buf, int len)
955 {
956     struct nmgr_hdr *hdr;
957 
958     hdr = (struct nmgr_hdr *)buf;
959     if (len < sizeof(*hdr) ||
960       (hdr->nh_op != NMGR_OP_READ && hdr->nh_op != NMGR_OP_WRITE) ||
961       (ntohs(hdr->nh_len) < len - sizeof(*hdr))) {
962         return;
963     }
964     bs_hdr = hdr;
965     hdr->nh_group = ntohs(hdr->nh_group);
966 
967     buf += sizeof(*hdr);
968     len -= sizeof(*hdr);
969 
970     reset_cbor_state();
971 
972     /*
973      * Limited support for commands.
974      */
975     if (hdr->nh_group == MGMT_GROUP_ID_IMAGE) {
976         switch (hdr->nh_id) {
977         case IMGMGR_NMGR_ID_STATE:
978             bs_list_set(hdr->nh_op, buf, len);
979             break;
980         case IMGMGR_NMGR_ID_UPLOAD:
981             bs_upload(buf, len);
982             break;
983         default:
984             bs_rc_rsp(MGMT_ERR_ENOTSUP);
985             break;
986         }
987     } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) {
988         switch (hdr->nh_id) {
989         case NMGR_ID_ECHO:
990 #ifdef MCUBOOT_BOOT_MGMT_ECHO
991             bs_echo(buf, len);
992 #endif
993             break;
994         case NMGR_ID_CONS_ECHO_CTRL:
995             bs_rc_rsp(0);
996             break;
997         case NMGR_ID_RESET:
998             bs_reset(buf, len);
999             break;
1000         default:
1001             bs_rc_rsp(MGMT_ERR_ENOTSUP);
1002             break;
1003         }
1004     } else if (MCUBOOT_PERUSER_MGMT_GROUP_ENABLED == 1) {
1005         if (bs_peruser_system_specific(hdr, buf, len, cbor_state) == 0) {
1006             boot_serial_output();
1007         }
1008     } else {
1009         bs_rc_rsp(MGMT_ERR_ENOTSUP);
1010     }
1011 #ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
1012     bs_entry = true;
1013 #endif
1014 }
1015 
1016 static void
boot_serial_output(void)1017 boot_serial_output(void)
1018 {
1019     char *data;
1020     int len, out;
1021     uint16_t crc;
1022     uint16_t totlen;
1023     char pkt_cont[2] = { SHELL_NLIP_DATA_START1, SHELL_NLIP_DATA_START2 };
1024     char pkt_start[2] = { SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 };
1025     char buf[BOOT_SERIAL_OUT_MAX + sizeof(*bs_hdr) + sizeof(crc) + sizeof(totlen)];
1026     char encoded_buf[BASE64_ENCODE_SIZE(sizeof(buf))];
1027 
1028     data = bs_obuf;
1029     len = (uint32_t)cbor_state->payload_mut - (uint32_t)bs_obuf;
1030 
1031     bs_hdr->nh_op++;
1032     bs_hdr->nh_flags = 0;
1033     bs_hdr->nh_len = htons(len);
1034     bs_hdr->nh_group = htons(bs_hdr->nh_group);
1035 
1036 #ifdef __ZEPHYR__
1037     crc =  crc16_itu_t(CRC16_INITIAL_CRC, (uint8_t *)bs_hdr, sizeof(*bs_hdr));
1038     crc =  crc16_itu_t(crc, data, len);
1039 #elif __ESPRESSIF__
1040     /* For ESP32 it was used the CRC API in rom/crc.h */
1041     crc =  ~esp_crc16_be(~CRC16_INITIAL_CRC, (uint8_t *)bs_hdr, sizeof(*bs_hdr));
1042     crc =  ~esp_crc16_be(~crc, (uint8_t *)data, len);
1043 #else
1044     crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
1045     crc = crc16_ccitt(crc, data, len);
1046 #endif
1047     crc = htons(crc);
1048 
1049     totlen = len + sizeof(*bs_hdr) + sizeof(crc);
1050     totlen = htons(totlen);
1051 
1052     memcpy(buf, &totlen, sizeof(totlen));
1053     totlen = sizeof(totlen);
1054     memcpy(&buf[totlen], bs_hdr, sizeof(*bs_hdr));
1055     totlen += sizeof(*bs_hdr);
1056     memcpy(&buf[totlen], data, len);
1057     totlen += len;
1058     memcpy(&buf[totlen], &crc, sizeof(crc));
1059     totlen += sizeof(crc);
1060 #ifdef __ZEPHYR__
1061     size_t enc_len;
1062     base64_encode(encoded_buf, sizeof(encoded_buf), &enc_len, buf, totlen);
1063     totlen = enc_len;
1064 #elif __ESPRESSIF__
1065     size_t enc_len;
1066     base64_encode((unsigned char *)encoded_buf, sizeof(encoded_buf), &enc_len, (unsigned char *)buf, totlen);
1067     totlen = enc_len;
1068 #else
1069     totlen = base64_encode(buf, totlen, encoded_buf, 1);
1070 #endif
1071 
1072     out = 0;
1073     while (out < totlen) {
1074         if (out == 0) {
1075             boot_uf->write(pkt_start, sizeof(pkt_start));
1076         } else {
1077             boot_uf->write(pkt_cont, sizeof(pkt_cont));
1078         }
1079 
1080         len = MIN(BOOT_SERIAL_FRAME_MTU, totlen - out);
1081         boot_uf->write(&encoded_buf[out], len);
1082 
1083         out += len;
1084 
1085         boot_uf->write("\n", 1);
1086     }
1087 
1088     BOOT_LOG_INF("TX");
1089 }
1090 
1091 /*
1092  * Returns 1 if full packet has been received.
1093  */
1094 static int
boot_serial_in_dec(char * in,int inlen,char * out,int * out_off,int maxout)1095 boot_serial_in_dec(char *in, int inlen, char *out, int *out_off, int maxout)
1096 {
1097     int rc;
1098     uint16_t crc;
1099     uint16_t len;
1100 
1101 #ifdef __ZEPHYR__
1102     int err;
1103     err = base64_decode( &out[*out_off], maxout - *out_off, &rc, in, inlen - 2);
1104     if (err) {
1105         return -1;
1106     }
1107 #elif __ESPRESSIF__
1108     int err;
1109     err = base64_decode((unsigned char *)&out[*out_off], maxout - *out_off, (size_t *)&rc, (unsigned char *)in, inlen);
1110     if (err) {
1111         return -1;
1112     }
1113 #else
1114     if (*out_off + base64_decode_len(in) >= maxout) {
1115         return -1;
1116     }
1117     rc = base64_decode(in, &out[*out_off]);
1118     if (rc < 0) {
1119         return -1;
1120     }
1121 #endif
1122 
1123     *out_off += rc;
1124     if (*out_off <= sizeof(uint16_t)) {
1125         return 0;
1126     }
1127 
1128     len = ntohs(*(uint16_t *)out);
1129     if (len != *out_off - sizeof(uint16_t)) {
1130         return 0;
1131     }
1132 
1133     if (len > *out_off - sizeof(uint16_t)) {
1134         len = *out_off - sizeof(uint16_t);
1135     }
1136 
1137     out += sizeof(uint16_t);
1138 #ifdef __ZEPHYR__
1139     crc = crc16_itu_t(CRC16_INITIAL_CRC, out, len);
1140 #elif __ESPRESSIF__
1141     crc = ~esp_crc16_be(~CRC16_INITIAL_CRC, (uint8_t *)out, len);
1142 #else
1143     crc = crc16_ccitt(CRC16_INITIAL_CRC, out, len);
1144 #endif
1145     if (crc || len <= sizeof(crc)) {
1146         return 0;
1147     }
1148     *out_off -= sizeof(crc);
1149     out[*out_off] = '\0';
1150 
1151     return 1;
1152 }
1153 
1154 /*
1155  * Task which waits reading console, expecting to get image over
1156  * serial port.
1157  */
1158 static void
boot_serial_read_console(const struct boot_uart_funcs * f,int timeout_in_ms)1159 boot_serial_read_console(const struct boot_uart_funcs *f,int timeout_in_ms)
1160 {
1161     int rc;
1162     int off;
1163     int dec_off = 0;
1164     int full_line;
1165     int max_input;
1166     int elapsed_in_ms = 0;
1167 
1168     boot_uf = f;
1169     max_input = sizeof(in_buf);
1170 
1171     off = 0;
1172     while (timeout_in_ms > 0 || bs_entry) {
1173         /*
1174          * Don't enter CPU idle state here if timeout based serial recovery is
1175          * used as otherwise the boot process hangs forever, waiting for input
1176          * from serial console (if single-thread mode is used).
1177          */
1178 #ifndef MCUBOOT_SERIAL_WAIT_FOR_DFU
1179         MCUBOOT_CPU_IDLE();
1180 #endif
1181         MCUBOOT_WATCHDOG_FEED();
1182 #ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
1183         uint32_t start = k_uptime_get_32();
1184 #endif
1185         rc = f->read(in_buf + off, sizeof(in_buf) - off, &full_line);
1186         if (rc <= 0 && !full_line) {
1187             goto check_timeout;
1188         }
1189         off += rc;
1190         if (!full_line) {
1191             if (off == max_input) {
1192                 /*
1193                  * Full line, no newline yet. Reset the input buffer.
1194                  */
1195                 off = 0;
1196             }
1197             goto check_timeout;
1198         }
1199         if (in_buf[0] == SHELL_NLIP_PKT_START1 &&
1200           in_buf[1] == SHELL_NLIP_PKT_START2) {
1201             dec_off = 0;
1202             rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
1203         } else if (in_buf[0] == SHELL_NLIP_DATA_START1 &&
1204           in_buf[1] == SHELL_NLIP_DATA_START2) {
1205             rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
1206         }
1207 
1208         /* serve errors: out of decode memory, or bad encoding */
1209         if (rc == 1) {
1210             boot_serial_input(&dec_buf[2], dec_off - 2);
1211         }
1212         off = 0;
1213 check_timeout:
1214         /* Subtract elapsed time */
1215 #ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
1216         elapsed_in_ms = (k_uptime_get_32() - start);
1217 #endif
1218         timeout_in_ms -= elapsed_in_ms;
1219     }
1220 }
1221 
1222 /*
1223  * Task which waits reading console, expecting to get image over
1224  * serial port.
1225  */
1226 void
boot_serial_start(const struct boot_uart_funcs * f)1227 boot_serial_start(const struct boot_uart_funcs *f)
1228 {
1229     bs_entry = true;
1230     boot_serial_read_console(f,0);
1231 }
1232 
1233 #ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
1234 /*
1235  * Task which waits reading console for a certain amount of timeout.
1236  * If within this timeout no mcumgr command is received, the function is
1237  * returning, else the serial boot is never exited
1238  */
1239 void
boot_serial_check_start(const struct boot_uart_funcs * f,int timeout_in_ms)1240 boot_serial_check_start(const struct boot_uart_funcs *f, int timeout_in_ms)
1241 {
1242     bs_entry = false;
1243     boot_serial_read_console(f,timeout_in_ms);
1244 }
1245 #endif
1246 
1247 #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH
1248 /* Function to find the hash of an image, returns 0 on success. */
boot_serial_get_hash(const struct image_header * hdr,const struct flash_area * fap,uint8_t * hash)1249 static int boot_serial_get_hash(const struct image_header *hdr,
1250                                 const struct flash_area *fap, uint8_t *hash)
1251 {
1252     struct image_tlv_iter it;
1253     uint32_t offset;
1254     uint16_t len;
1255     uint16_t type;
1256     int rc;
1257 
1258     /* Manifest data is concatenated to the end of the image.
1259      * It is encoded in TLV format.
1260      */
1261     rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
1262     if (rc) {
1263         return -1;
1264     }
1265 
1266     /* Traverse through the TLV area to find the image hash TLV. */
1267     while (true) {
1268         rc = bootutil_tlv_iter_next(&it, &offset, &len, &type);
1269         if (rc < 0) {
1270             return -1;
1271         } else if (rc > 0) {
1272             break;
1273         }
1274 
1275         if (type == IMAGE_TLV_SHA256) {
1276             /* Get the image's hash value from the manifest section. */
1277             if (len != 32) {
1278                 return -1;
1279             }
1280 
1281             rc = flash_area_read(fap, offset, hash, len);
1282             if (rc) {
1283                 return -1;
1284             }
1285 
1286             return 0;
1287         }
1288     }
1289 
1290     return -1;
1291 }
1292 #endif
1293