diff --git a/.gitmodules b/.gitmodules index dcd3a70b..bf510c93 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,9 +19,6 @@ [submodule "boot/cypress/libs/cy-mbedtls-acceleration"] path = boot/cypress/libs/cy-mbedtls-acceleration url = https://github.com/cypresssemiconductorco/cy-mbedtls-acceleration.git -[submodule "ext/cddl-gen"] - path = ext/cddl-gen - url = https://github.com/NordicSemiconductor/cddl-gen.git [submodule "boot/espressif/hal/esp-idf"] path = boot/espressif/hal/esp-idf url = https://github.com/espressif/esp-idf.git diff --git a/.mbedignore b/.mbedignore index 06a173ec..5dd4ea2c 100644 --- a/.mbedignore +++ b/.mbedignore @@ -11,7 +11,6 @@ samples/* scripts/* sim/* testplan/* -ext/cddl_gen/* ext/fiat/* ext/mbedtls/* ext/mbedtls-asn1/* diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c index a11284fe..4a4a63de 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -25,7 +25,7 @@ #include "sysflash/sysflash.h" #include "bootutil/bootutil_log.h" -#include "cbor_encode.h" +#include "zcbor_encode.h" #ifdef __ZEPHYR__ #include @@ -99,17 +99,12 @@ static char bs_obuf[BOOT_SERIAL_OUT_MAX]; static void boot_serial_output(void); -static cbor_state_backups_t dummy_backups; -static cbor_state_t cbor_state = { - .backups = &dummy_backups -}; +static zcbor_state_t cbor_state[2]; void reset_cbor_state(void) { - cbor_state.payload_mut = (uint8_t *)bs_obuf; - cbor_state.payload_end = (const uint8_t *)bs_obuf - + sizeof(bs_obuf); - cbor_state.elem_count = 0; + zcbor_new_encode_state(cbor_state, 2, (uint8_t *)bs_obuf, + (size_t)bs_obuf + sizeof(bs_obuf), 0); } /** @@ -126,7 +121,7 @@ void reset_cbor_state(void) */ extern int bs_peruser_system_specific(const struct nmgr_hdr *hdr, const char *buffer, - int len, cbor_state_t *cs); + int len, zcbor_state_t *cs); /* * Convert version into string without use of snprintf(). @@ -157,6 +152,9 @@ u32toa(char *tgt, uint32_t val) return dst - tgt; } +#define zcbor_tstr_put_lit_cast(state, string) \ + zcbor_tstr_encode_ptr(state, (uint8_t *)string, sizeof(string) - 1) + /* * dst has to be able to fit "255.255.65535.4294967295" (25 characters). */ @@ -186,9 +184,9 @@ bs_list(char *buf, int len) const struct flash_area *fap; uint8_t image_index; - map_start_encode(&cbor_state, 1); - tstrx_put(&cbor_state, "images"); - list_start_encode(&cbor_state, 5); + zcbor_map_start_encode(cbor_state, 1); + zcbor_tstr_put_lit_cast(cbor_state, "images"); + zcbor_list_start_encode(cbor_state, 5); image_index = 0; IMAGES_ITER(image_index) { for (slot = 0; slot < 2; slot++) { @@ -235,24 +233,24 @@ bs_list(char *buf, int len) continue; } - map_start_encode(&cbor_state, 20); + zcbor_map_start_encode(cbor_state, 20); #if (BOOT_IMAGE_NUMBER > 1) - tstrx_put(&cbor_state, "image"); - uintx32_put(&cbor_state, image_index); + zcbor_tstr_put_lit_cast(cbor_state, "image"); + zcbor_uint32_put(cbor_state, image_index); #endif - tstrx_put(&cbor_state, "slot"); - uintx32_put(&cbor_state, slot); - tstrx_put(&cbor_state, "version"); + zcbor_tstr_put_lit_cast(cbor_state, "slot"); + zcbor_uint32_put(cbor_state, slot); + zcbor_tstr_put_lit_cast(cbor_state, "version"); bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver); - tstrx_put_term(&cbor_state, (char *)tmpbuf); - map_end_encode(&cbor_state, 20); + zcbor_tstr_encode_ptr(cbor_state, tmpbuf, strlen((char *)tmpbuf)); + zcbor_map_end_encode(cbor_state, 20); } } - list_end_encode(&cbor_state, 5); - map_end_encode(&cbor_state, 1); + zcbor_list_end_encode(cbor_state, 5); + zcbor_map_end_encode(cbor_state, 1); boot_serial_output(); } @@ -289,15 +287,15 @@ bs_upload(char *buf, int len) */ struct Upload upload; - uint32_t decoded_len; - bool result = cbor_decode_Upload((const uint8_t *)buf, len, &upload, &decoded_len); + size_t decoded_len; + uint_fast8_t result = cbor_decode_Upload((const uint8_t *)buf, len, &upload, &decoded_len); - if (!result || (len != decoded_len)) { + if ((result != ZCBOR_SUCCESS) || (len != decoded_len)) { goto out_invalid_data; } for (int i = 0; i < upload._Upload_members_count; i++) { - struct Member_ *member = &upload._Upload_members[i]; + struct Member_ *member = &upload._Upload_members[i]._Upload_members; switch(member->_Member_choice) { case _Member_image: img_num = member->_Member_image; @@ -458,14 +456,14 @@ bs_upload(char *buf, int len) out: BOOT_LOG_INF("RX: 0x%x", rc); - map_start_encode(&cbor_state, 10); - tstrx_put(&cbor_state, "rc"); - uintx32_put(&cbor_state, rc); + zcbor_map_start_encode(cbor_state, 10); + zcbor_tstr_put_lit_cast(cbor_state, "rc"); + zcbor_uint32_put(cbor_state, rc); if (rc == 0) { - tstrx_put(&cbor_state, "off"); - uintx32_put(&cbor_state, curr_off); + zcbor_tstr_put_lit_cast(cbor_state, "off"); + zcbor_uint32_put(cbor_state, curr_off); } - map_end_encode(&cbor_state, 10); + zcbor_map_end_encode(cbor_state, 10); boot_serial_output(); flash_area_close(fap); @@ -484,10 +482,10 @@ out: static void bs_rc_rsp(int rc_code) { - map_start_encode(&cbor_state, 10); - tstrx_put(&cbor_state, "rc"); - uintx32_put(&cbor_state, rc_code); - map_end_encode(&cbor_state, 10); + zcbor_map_start_encode(cbor_state, 10); + zcbor_tstr_put_lit_cast(cbor_state, "rc"); + zcbor_uint32_put(cbor_state, rc_code); + zcbor_map_end_encode(cbor_state, 10); boot_serial_output(); } @@ -605,7 +603,7 @@ boot_serial_input(char *buf, int len) break; } } else if (MCUBOOT_PERUSER_MGMT_GROUP_ENABLED == 1) { - if (bs_peruser_system_specific(hdr, buf, len, &cbor_state) == 0) { + if (bs_peruser_system_specific(hdr, buf, len, cbor_state) == 0) { boot_serial_output(); } } else { @@ -628,7 +626,7 @@ boot_serial_output(void) char encoded_buf[BASE64_ENCODE_SIZE(sizeof(buf))]; data = bs_obuf; - len = (uint32_t)cbor_state.payload_mut - (uint32_t)bs_obuf; + len = (uint32_t)cbor_state->payload_mut - (uint32_t)bs_obuf; bs_hdr->nh_op++; bs_hdr->nh_flags = 0; diff --git a/boot/boot_serial/src/cbor_common.c b/boot/boot_serial/src/cbor_common.c deleted file mode 100644 index 8a4cd9c7..00000000 --- a/boot/boot_serial/src/cbor_common.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * This file has been copied from the cddl-gen submodule. - * Commit 9f77837f9950da1633d22abf6181a830521a6688 - */ - -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include "cbor_common.h" - -_Static_assert((sizeof(size_t) == sizeof(void *)), - "This code needs size_t to be the same length as pointers."); - -bool new_backup(cbor_state_t *state, uint32_t new_elem_count) -{ - if ((state->backups->current_backup + 1) - >= state->backups->num_backups) { - FAIL(); - } - - uint32_t i = ++(state->backups->current_backup); - memcpy(&state->backups->backup_list[i], state, - sizeof(cbor_state_t)); - - state->elem_count = new_elem_count; - - return true; -} - - -bool restore_backup(cbor_state_t *state, uint32_t flags, - uint32_t max_elem_count) -{ - const uint8_t *payload = state->payload; - const uint32_t elem_count = state->elem_count; - - if (state->backups->current_backup == 0) { - FAIL(); - } - - if (flags & FLAG_RESTORE) { - uint32_t i = state->backups->current_backup; - - memcpy(state, &state->backups->backup_list[i], - sizeof(cbor_state_t)); - } - - if (flags & FLAG_DISCARD) { - state->backups->current_backup--; - } - - if (elem_count > max_elem_count) { - cbor_print("elem_count: %d (expected max %d)\r\n", - elem_count, max_elem_count); - FAIL(); - } - - if (flags & FLAG_TRANSFER_PAYLOAD) { - state->payload = payload; - } - - return true; -} - - -bool union_start_code(cbor_state_t *state) -{ - if (!new_backup(state, state->elem_count)) { - FAIL(); - } - return true; -} - - -bool union_elem_code(cbor_state_t *state) -{ - if (!restore_backup(state, FLAG_RESTORE, state->elem_count)) { - FAIL(); - } - return true; -} - -bool union_end_code(cbor_state_t *state) -{ - if (!restore_backup(state, FLAG_DISCARD, state->elem_count)) { - FAIL(); - } - return true; -} - -bool entry_function(const uint8_t *payload, uint32_t payload_len, - const void *struct_ptr, uint32_t *payload_len_out, - cbor_encoder_t func, uint32_t elem_count, uint32_t num_backups) -{ - cbor_state_t state = { - .payload = payload, - .payload_end = payload + payload_len, - .elem_count = elem_count, - }; - - cbor_state_t state_backups[num_backups + 1]; - - cbor_state_backups_t backups = { - .backup_list = state_backups, - .current_backup = 0, - .num_backups = num_backups + 1, - }; - - state.backups = &backups; - - bool result = func(&state, struct_ptr); - - if (result && (payload_len_out != NULL)) { - *payload_len_out = MIN(payload_len, - (size_t)state.payload - (size_t)payload); - } - return result; -} diff --git a/boot/boot_serial/src/cbor_common.h b/boot/boot_serial/src/cbor_common.h deleted file mode 100644 index e6529083..00000000 --- a/boot/boot_serial/src/cbor_common.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * This file has been copied from the cddl-gen submodule. - * Commit 9f77837f9950da1633d22abf6181a830521a6688 - */ - -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef CBOR_COMMON_H__ -#define CBOR_COMMON_H__ -#include -#include -#include - - -/** Convenience type that allows pointing to strings directly inside the payload - * without the need to copy out. - */ -typedef struct -{ - const uint8_t *value; - uint32_t len; -} cbor_string_type_t; - -#ifdef CDDL_CBOR_VERBOSE -#include -#define cbor_trace() (printk("bytes left: %d, byte: 0x%x, elem_count: 0x%zx, %s:%d\n",\ - (uint32_t)state->payload_end - (uint32_t)state->payload, *state->payload, state->elem_count,\ - __FILE__, __LINE__)) -#define cbor_assert(expr, ...) \ -do { \ - if (!(expr)) { \ - printk("ASSERTION \n \"" #expr \ - "\"\nfailed at %s:%d with message:\n ", \ - __FILE__, __LINE__); \ - printk(__VA_ARGS__);\ - return false; \ - } \ -} while(0) -#define cbor_print(...) printk(__VA_ARGS__) -#else -#define cbor_trace() ((void)state) -#define cbor_assert(...) -#define cbor_print(...) -#endif - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif - - -struct cbor_state_backups_s; - -typedef struct cbor_state_backups_s cbor_state_backups_t; - -typedef struct{ -union { - uint8_t *payload_mut; - uint8_t const *payload; /**< The current place in the payload. Will be - updated when an element is correctly - processed. */ -}; - uint8_t const *payload_bak; /**< Temporary backup of payload. */ - uint32_t elem_count; /**< The current element is part of a LIST or a MAP, - and this keeps count of how many elements are - expected. This will be checked before processing - and decremented if the element is correctly - processed. */ - uint8_t const *payload_end; /**< The end of the payload. This will be - checked against payload before - processing each element. */ - cbor_state_backups_t *backups; -} cbor_state_t; - -struct cbor_state_backups_s{ - cbor_state_t *backup_list; - uint32_t current_backup; - uint32_t num_backups; -}; - -/** Function pointer type used with multi_decode. - * - * This type is compatible with all decoding functions here and in the generated - * code, except for multi_decode. - */ -typedef bool(cbor_encoder_t)(cbor_state_t *, const void *); -typedef bool(cbor_decoder_t)(cbor_state_t *, void *); - -/** Enumeration representing the major types available in CBOR. - * - * The major type is represented in the 3 first bits of the header byte. - */ -typedef enum -{ - CBOR_MAJOR_TYPE_PINT = 0, ///! Positive Integer - CBOR_MAJOR_TYPE_NINT = 1, ///! Negative Integer - CBOR_MAJOR_TYPE_BSTR = 2, ///! Byte String - CBOR_MAJOR_TYPE_TSTR = 3, ///! Text String - CBOR_MAJOR_TYPE_LIST = 4, ///! List - CBOR_MAJOR_TYPE_MAP = 5, ///! Map - CBOR_MAJOR_TYPE_TAG = 6, ///! Semantic Tag - CBOR_MAJOR_TYPE_PRIM = 7, ///! Primitive Type -} cbor_major_type_t; - -/** Shorthand macro to check if a result is within min/max constraints. - */ -#define PTR_VALUE_IN_RANGE(type, res, min, max) \ - (((min == NULL) || (*(type *)res >= *(type *)min)) \ - && ((max == NULL) || (*(type *)res <= *(type *)max))) - -#define FAIL() \ -do {\ - cbor_trace(); \ - return false; \ -} while(0) - - -#define VALUE_IN_HEADER 23 /**! For values below this, the value is encoded - directly in the header. */ - -#define BOOL_TO_PRIM 20 ///! In CBOR, false/true have the values 20/21 - -#define FLAG_RESTORE 1UL -#define FLAG_DISCARD 2UL -#define FLAG_TRANSFER_PAYLOAD 4UL - -bool new_backup(cbor_state_t *state, uint32_t new_elem_count); - -bool restore_backup(cbor_state_t *state, uint32_t flags, - uint32_t max_elem_count); - -bool union_start_code(cbor_state_t *state); - -bool union_elem_code(cbor_state_t *state); - -bool union_end_code(cbor_state_t *state); - -bool entry_function(const uint8_t *payload, uint32_t payload_len, - const void *struct_ptr, uint32_t *payload_len_out, - cbor_encoder_t func, uint32_t elem_count, uint32_t num_backups); - -#endif /* CBOR_COMMON_H__ */ diff --git a/boot/boot_serial/src/cbor_decode.c b/boot/boot_serial/src/cbor_decode.c deleted file mode 100644 index 97077294..00000000 --- a/boot/boot_serial/src/cbor_decode.c +++ /dev/null @@ -1,629 +0,0 @@ -/* - * This file has been copied from the cddl-gen submodule. - * Commit 9f77837f9950da1633d22abf6181a830521a6688 - */ - -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include "cbor_decode.h" -#include "cbor_common.h" - - -/** Return value length from additional value. - */ -static uint32_t additional_len(uint8_t additional) -{ - if (24 <= additional && additional <= 27) { - /* 24 => 1 - * 25 => 2 - * 26 => 4 - * 27 => 8 - */ - return 1 << (additional - 24); - } - return 0; -} - -/** Extract the major type, i.e. the first 3 bits of the header byte. */ -#define MAJOR_TYPE(header_byte) (((header_byte) >> 5) & 0x7) - -/** Extract the additional info, i.e. the last 5 bits of the header byte. */ -#define ADDITIONAL(header_byte) ((header_byte) & 0x1F) - - -#define FAIL_AND_DECR_IF(expr) \ -do {\ - if (expr) { \ - (state->payload)--; \ - FAIL(); \ - } \ -} while(0) - -#define FAIL_IF(expr) \ -do {\ - if (expr) { \ - FAIL(); \ - } \ -} while(0) - - -#define FAIL_RESTORE() \ - state->payload = state->payload_bak; \ - state->elem_count++; \ - FAIL() - -/** Get a single value. - * - * @details @p ppayload must point to the header byte. This function will - * retrieve the value (either from within the additional info, or from - * the subsequent bytes) and return it in the result. The result can - * have arbitrary length. - * - * The function will also validate - * - Min/max constraints on the value. - * - That @p payload doesn't overrun past @p payload_end. - * - That @p elem_count has not been exhausted. - * - * @p ppayload and @p elem_count are updated if the function - * succeeds. If not, they are left unchanged. - * - * CBOR values are always big-endian, so this function converts from - * big to little-endian if necessary (@ref CONFIG_BIG_ENDIAN). - */ -static bool value_extract(cbor_state_t *state, - void *const result, uint32_t result_len) -{ - cbor_trace(); - cbor_assert(result_len != 0, "0-length result not supported.\n"); - cbor_assert(result != NULL, NULL); - - FAIL_IF((state->elem_count == 0) \ - || (state->payload >= state->payload_end)); - - uint8_t *u8_result = (uint8_t *)result; - uint8_t additional = ADDITIONAL(*state->payload); - - state->payload_bak = state->payload; - (state->payload)++; - - memset(result, 0, result_len); - if (additional <= VALUE_IN_HEADER) { -#ifdef CONFIG_BIG_ENDIAN - u8_result[result_len - 1] = additional; -#else - u8_result[0] = additional; -#endif /* CONFIG_BIG_ENDIAN */ - } else { - uint32_t len = additional_len(additional); - - FAIL_AND_DECR_IF(len > result_len); - FAIL_AND_DECR_IF((state->payload + len) - > state->payload_end); - -#ifdef CONFIG_BIG_ENDIAN - memcpy(&u8_result[result_len - len], state->payload, len); -#else - for (uint32_t i = 0; i < len; i++) { - u8_result[i] = (state->payload)[len - i - 1]; - } -#endif /* CONFIG_BIG_ENDIAN */ - - (state->payload) += len; - } - - (state->elem_count)--; - return true; -} - - -static bool int32_decode(cbor_state_t *state, int32_t *result) -{ - FAIL_IF(state->payload >= state->payload_end); - uint8_t major_type = MAJOR_TYPE(*state->payload); - uint32_t uint_result; - int32_t int_result; - - if (!value_extract(state, &uint_result, 4)) { - FAIL(); - } - - cbor_print("uintval: %u\r\n", uint_result); - if (uint_result >= (1 << (8*sizeof(uint_result)-1))) { - /* Value is too large to fit in a signed integer. */ - FAIL_RESTORE(); - } - - if (major_type == CBOR_MAJOR_TYPE_NINT) { - /* Convert from CBOR's representation. */ - int_result = -1 - uint_result; - } else { - int_result = uint_result; - } - - cbor_print("val: %d\r\n", int_result); - *result = int_result; - return true; -} - - -bool intx32_decode(cbor_state_t *state, int32_t *result) -{ - FAIL_IF(state->payload >= state->payload_end); - uint8_t major_type = MAJOR_TYPE(*state->payload); - - if (major_type != CBOR_MAJOR_TYPE_PINT - && major_type != CBOR_MAJOR_TYPE_NINT) { - /* Value to be read doesn't have the right type. */ - FAIL(); - } - - if (!int32_decode(state, result)) { - FAIL(); - } - return true; -} - -bool intx32_expect(cbor_state_t *state, int32_t result) -{ - int32_t value; - - if (!intx32_decode(state, &value)) { - FAIL(); - } - - if (value != result) { - cbor_print("%d != %d\r\n", value, result); - FAIL_RESTORE(); - } - return true; -} - - -static bool uint32_decode(cbor_state_t *state, uint32_t *result) -{ - if (!value_extract(state, result, 4)) { - FAIL(); - } - - return true; -} - - -bool uintx32_decode(cbor_state_t *state, uint32_t *result) -{ - FAIL_IF(state->payload >= state->payload_end); - uint8_t major_type = MAJOR_TYPE(*state->payload); - - if (major_type != CBOR_MAJOR_TYPE_PINT) { - /* Value to be read doesn't have the right type. */ - FAIL(); - } - if (!uint32_decode(state, result)) { - FAIL(); - } - return true; -} - -bool uintx32_expect(cbor_state_t *state, uint32_t result) -{ - uint32_t value; - - if (!uintx32_decode(state, &value)) { - FAIL(); - } - if (value != result) { - cbor_print("%u != %u\r\n", value, result); - FAIL_RESTORE(); - } - return true; -} - -bool uintx32_expect_union(cbor_state_t *state, uint32_t result) -{ - union_elem_code(state); - return uintx32_expect(state, result); -} - - -static bool strx_start_decode(cbor_state_t *state, - cbor_string_type_t *result, cbor_major_type_t exp_major_type) -{ - FAIL_IF(state->payload >= state->payload_end); - uint8_t major_type = MAJOR_TYPE(*state->payload); - - if (major_type != exp_major_type) { - FAIL(); - } - - if (!uint32_decode(state, &result->len)) { - FAIL(); - } - - if (result->len > (state->payload_end - state->payload)) { - cbor_print("error: 0x%x > 0x%x\r\n", - (uint32_t)result->len, - (uint32_t)(state->payload_end - state->payload)); - FAIL_RESTORE(); - } - - result->value = state->payload; - return true; -} - -bool bstrx_cbor_start_decode(cbor_state_t *state, cbor_string_type_t *result) -{ - if(!strx_start_decode(state, result, CBOR_MAJOR_TYPE_BSTR)) { - FAIL(); - } - - if (!new_backup(state, 0xFFFFFFFF)) { - FAIL_RESTORE(); - } - - /* Overflow is checked in strx_start_decode() */ - state->payload_end = result->value + result->len; - return true; -} - -bool bstrx_cbor_end_decode(cbor_state_t *state) -{ - if (state->payload != state->payload_end) { - FAIL(); - } - if (!restore_backup(state, - FLAG_RESTORE | FLAG_DISCARD | FLAG_TRANSFER_PAYLOAD, - 0xFFFFFFFF)) { - FAIL(); - } - - return true; -} - - -bool strx_decode(cbor_state_t *state, cbor_string_type_t *result, - cbor_major_type_t exp_major_type) -{ - if (!strx_start_decode(state, result, exp_major_type)) { - FAIL(); - } - - /* Overflow is checked in strx_start_decode() */ - (state->payload) += result->len; - return true; -} - - -bool strx_expect(cbor_state_t *state, cbor_string_type_t *result, - cbor_major_type_t exp_major_type) -{ - cbor_string_type_t tmp_result; - - if (!strx_decode(state, &tmp_result, exp_major_type)) { - FAIL(); - } - if ((tmp_result.len != result->len) - || memcmp(result->value, tmp_result.value, tmp_result.len)) { - FAIL_RESTORE(); - } - return true; -} - - -bool bstrx_decode(cbor_state_t *state, cbor_string_type_t *result) -{ - return strx_decode(state, result, CBOR_MAJOR_TYPE_BSTR); -} - - -bool bstrx_expect(cbor_state_t *state, cbor_string_type_t *result) -{ - return strx_expect(state, result, CBOR_MAJOR_TYPE_BSTR); -} - - -bool tstrx_decode(cbor_state_t *state, cbor_string_type_t *result) -{ - return strx_decode(state, result, CBOR_MAJOR_TYPE_TSTR); -} - - -bool tstrx_expect(cbor_state_t *state, cbor_string_type_t *result) -{ - return strx_expect(state, result, CBOR_MAJOR_TYPE_TSTR); -} - - -static bool list_map_start_decode(cbor_state_t *state, - cbor_major_type_t exp_major_type) -{ - FAIL_IF(state->payload >= state->payload_end); - uint8_t major_type = MAJOR_TYPE(*state->payload); - uint32_t new_elem_count; - - if (major_type != exp_major_type) { - FAIL(); - } - - if (!uint32_decode(state, &new_elem_count)) { - FAIL(); - } - - if (!new_backup(state, new_elem_count)) { - FAIL_RESTORE(); - } - - return true; -} - - -bool list_start_decode(cbor_state_t *state) -{ - return list_map_start_decode(state, CBOR_MAJOR_TYPE_LIST); -} - - -bool map_start_decode(cbor_state_t *state) -{ - bool ret = list_map_start_decode(state, CBOR_MAJOR_TYPE_MAP); - - if (ret) { - state->elem_count *= 2; - } - return ret; -} - - -bool list_map_end_decode(cbor_state_t *state) -{ - if (!restore_backup(state, - FLAG_RESTORE | FLAG_DISCARD | FLAG_TRANSFER_PAYLOAD, - 0)) { - FAIL(); - } - - return true; -} - - -bool list_end_decode(cbor_state_t *state) -{ - return list_map_end_decode(state); -} - - -bool map_end_decode(cbor_state_t *state) -{ - return list_map_end_decode(state); -} - - -static bool primx_decode(cbor_state_t *state, uint32_t *result) -{ - FAIL_IF(state->payload >= state->payload_end); - uint8_t major_type = MAJOR_TYPE(*state->payload); - - if (major_type != CBOR_MAJOR_TYPE_PRIM) { - /* Value to be read doesn't have the right type. */ - FAIL(); - } - if (!uint32_decode(state, result)) { - FAIL(); - } - if (*result > 0xFF) { - FAIL_RESTORE(); - } - return true; -} - -static bool primx_expect(cbor_state_t *state, uint32_t result) -{ - uint32_t value; - - if (!primx_decode(state, &value)) { - FAIL(); - } - if (value != result) { - FAIL_RESTORE(); - } - return true; -} - - -bool nilx_expect(cbor_state_t *state, void *result) -{ - if (!primx_expect(state, 22)) { - FAIL(); - } - return true; -} - - -bool boolx_decode(cbor_state_t *state, bool *result) -{ - uint32_t tmp_result; - - if (!primx_decode(state, &tmp_result)) { - FAIL(); - } - (*result) = tmp_result - BOOL_TO_PRIM; - - cbor_print("boolval: %u\r\n", *result); - return true; -} - - -bool boolx_expect(cbor_state_t *state, bool result) -{ - bool value; - - if (!boolx_decode(state, &value)) { - FAIL(); - } - if (value != result) { - FAIL_RESTORE(); - } - return true; -} - - -bool double_decode(cbor_state_t *state, double *result) -{ - FAIL_IF(state->payload >= state->payload_end); - uint8_t major_type = MAJOR_TYPE(*state->payload); - - if (major_type != CBOR_MAJOR_TYPE_PRIM) { - /* Value to be read doesn't have the right type. */ - FAIL(); - } - if (!value_extract(state, result, - sizeof(*result))) { - FAIL(); - } - return true; -} - - -bool double_expect(cbor_state_t *state, double *result) -{ - double value; - - if (!double_decode(state, &value)) { - FAIL(); - } - if (value != *result) { - FAIL_RESTORE(); - } - return true; -} - - -bool any_decode(cbor_state_t *state, void *result) -{ - cbor_assert(result == NULL, - "'any' type cannot be returned, only skipped.\n"); - - FAIL_IF(state->payload >= state->payload_end); - uint8_t major_type = MAJOR_TYPE(*state->payload); - uint32_t value; - uint32_t num_decode; - void *null_result = NULL; - uint32_t temp_elem_count; - uint8_t const *payload_bak; - - if (!value_extract(state, &value, sizeof(value))) { - /* Can happen because of elem_count (or payload_end) */ - FAIL(); - } - - switch (major_type) { - case CBOR_MAJOR_TYPE_BSTR: - case CBOR_MAJOR_TYPE_TSTR: - (state->payload) += value; - break; - case CBOR_MAJOR_TYPE_MAP: - value *= 2; /* Because all members have a key. */ - /* Fallthrough */ - case CBOR_MAJOR_TYPE_LIST: - temp_elem_count = state->elem_count; - payload_bak = state->payload; - state->elem_count = value; - if (!multi_decode(value, value, &num_decode, - (void *)any_decode, state, - &null_result, 0)) { - state->elem_count = temp_elem_count; - state->payload = payload_bak; - FAIL(); - } - state->elem_count = temp_elem_count; - break; - default: - /* Do nothing */ - break; - } - - return true; -} - - -bool tag_decode(cbor_state_t *state, uint32_t *result) -{ - FAIL_IF(state->payload >= state->payload_end); - uint8_t major_type = MAJOR_TYPE(*state->payload); - - if (major_type != CBOR_MAJOR_TYPE_TAG) { - /* Value to be read doesn't have the right type. */ - FAIL(); - } - if (!uint32_decode(state, result)) { - FAIL(); - } - state->elem_count++; - return true; -} - - -bool tag_expect(cbor_state_t *state, uint32_t result) -{ - uint32_t tag_val; - - if (!tag_decode(state, &tag_val)) { - FAIL(); - } - if (tag_val != result) { - FAIL_RESTORE(); - } - return true; -} - - -bool multi_decode(uint32_t min_decode, - uint32_t max_decode, - uint32_t *num_decode, - cbor_decoder_t decoder, - cbor_state_t *state, - void *result, - uint32_t result_len) -{ - for (uint32_t i = 0; i < max_decode; i++) { - uint8_t const *payload_bak = state->payload; - uint32_t elem_count_bak = state->elem_count; - - if (!decoder(state, - (uint8_t *)result + i*result_len)) { - *num_decode = i; - state->payload = payload_bak; - state->elem_count = elem_count_bak; - if (i < min_decode) { - FAIL(); - } else { - cbor_print("Found %zu elements.\n", i); - } - return true; - } - } - cbor_print("Found %zu elements.\n", max_decode); - *num_decode = max_decode; - return true; -} - - -bool present_decode(uint32_t *present, - cbor_decoder_t decoder, - cbor_state_t *state, - void *result) -{ - uint32_t num_decode; - bool retval = multi_decode(0, 1, &num_decode, decoder, state, result, 0); - if (retval) { - *present = num_decode; - } - return retval; -} diff --git a/boot/boot_serial/src/cbor_decode.h b/boot/boot_serial/src/cbor_decode.h deleted file mode 100644 index 5bdc8001..00000000 --- a/boot/boot_serial/src/cbor_decode.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * This file has been copied from the cddl-gen submodule. - * Commit 9f77837f9950da1633d22abf6181a830521a6688 - */ - -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef CBOR_DECODE_H__ -#define CBOR_DECODE_H__ -#include -#include -#include -#include "cbor_common.h" - -/** The cbor_decode library provides functions for decoding CBOR data elements. - * - * This library is primarily meant to be called from code generated by - * $CDDL_GEN_BASE/cddl_gen/cddl_gen.py script, or its equivalent cddl_gen - * command line executable. - * - * Some details to notice about this library: - * - Integers are all 32 bits (uint32_t). This means that CBOR's 64 bit values - * are not supported, even when the code is running on a 64 bit architecture. - * This applies to integer types, as well as lengths for other types. - * - Strings are kept in the container type cbor_string_type_t, which is a - * pointer and a length. - * - When a function returns false, it only means that decoding that particular - * value failed. If a value is allowed to take multiple different values, - * another decoding function can be called if the first fails. - * - There is some type casting going on under the hood to make the code - * generator friendly. See especially the processor_t type which is compatible - * with all functions except multi_decode, but the compiler doesn't "know" - * this because they are defined with different pointer types. It also means - * any usage of multi_decode must be made with care for function types. - * - * - * CBOR's format is described well on Wikipedia - * - https://en.wikipedia.org/wiki/CBOR - * but here's a synopsis: - * - * Encoded CBOR data elements look like this. - * - * | Header | Value | Payload | - * | 1 byte | 0, 1, 2, 4, or 8 bytes | 0 - 2^64-1 bytes/elements | - * | 3 bits | 5 bits | - * | Major | Additional| - * | Type | info | - * - * The available major types can be seen in @ref cbor_major_type_t. - * - * For all types, Values 0-23 are encoded directly in the "Additional info", - * meaning that the "Value" field is 0 bytes long. If "Additional info" is 24, - * 25, 26, or 27, the "Value" field is 1, 2, 4, or 8 bytes long, respectively. - * - * Major types PINT, NINT, TAG, and PRIM elements have no payload, only Value. - * PINT: Interpret the Value as a positive integer. - * NINT: Interpret the Value as a positive integer, then multiply by -1 and - * subtract 1. - * TAG: The Value says something about the next non-tag element. - * See https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml - * PRIM: Different Values mean different things: - * 20: "false" - * 21: "true" - * 22: "null" - * 23: "undefined" - * >=0x10000: Interpret as IEEE 754 float with given precision - * - * For BSTR, TSTR, LIST, and MAP, the Value describes the length of the payload. - * For BSTR and TSTR, the length is in bytes, for LIST, the length is in number - * of elements, and for MAP, the length is in number of key/value element pairs. - * - * For LIST and MAP, sub elements are regular CBOR elements with their own - * Header, Value and Payload. LISTs and MAPs can be recursively encoded. - * - * The additional info means slightly different things for different major - * types. - */ - -/** Decode a PINT/NINT into a int32_t. - * - * @param[inout] state The current state of the decoding. - * @param[out] result Where to place the decoded value. - * - * @retval true If the value was decoded correctly. - * @retval false If the value has the wrong type, the payload overflowed, the - * element count was exhausted, or the value was larger than can - * fit in the result variable. - */ -bool intx32_decode(cbor_state_t *state, int32_t *result); - -/** Expect a PINT/NINT with a certain value. Uses intx32_decode internally. - * - * @param[inout] state The current state of the decoding. - * @param[in] result The expected value - * - * @retval true If the result was decoded correctly and has the expected value. - * @retval false If intx32_decode failed or the result doesn't have the - * expected value. - */ -bool intx32_expect(cbor_state_t *state, int32_t result); - -/** Decode a PINT. */ -bool uintx32_decode(cbor_state_t *state, uint32_t *result); -bool uintx32_expect(cbor_state_t *state, uint32_t result); -bool uintx32_expect_union(cbor_state_t *state, uint32_t result); - -/** Decode and consume a BSTR header. - * - * The rest of the string can be decoded as CBOR. - * A state backup is created to keep track of the element count. - * - * @retval true Header decoded correctly - * @retval false Header decoded incorrectly, or backup failed. - */ -bool bstrx_cbor_start_decode(cbor_state_t *state, cbor_string_type_t *result); - -/** Finalize decoding a CBOR-encoded bstr. - * - * Restore element count from backup. - */ -bool bstrx_cbor_end_decode(cbor_state_t *state); - -/** Decode and consume a BSTR */ -bool bstrx_decode(cbor_state_t *state, cbor_string_type_t *result); -bool bstrx_expect(cbor_state_t *state, cbor_string_type_t *result); - -/** Decode and consume a TSTR */ -bool tstrx_decode(cbor_state_t *state, cbor_string_type_t *result); -bool tstrx_expect(cbor_state_t *state, cbor_string_type_t *result); - -/** Decode and consume a LIST header. - * - * The contents of the list can be decoded via subsequent function calls. - * A state backup is created to keep track of the element count. - * - * @retval true Header decoded correctly - * @retval false Header decoded incorrectly, or backup failed. - */ -bool list_start_decode(cbor_state_t *state); - -/** Decode and consume a MAP header. */ -bool map_start_decode(cbor_state_t *state); - -/** Finalize decoding a LIST - * - * Check that the list had the correct number of elements, and restore previous - * element count from backup. - * - * @retval true Everything ok. - * @retval false Element count not correct. - */ -bool list_end_decode(cbor_state_t *state); - -/** Finalize decoding a MAP */ -bool map_end_decode(cbor_state_t *state); - -/** Decode a "nil" primitive value. */ -bool nilx_expect(cbor_state_t *state, void *result); - -/** Decode a boolean primitive value. */ -bool boolx_decode(cbor_state_t *state, bool *result); -bool boolx_expect(cbor_state_t *state, bool result); - -/** Decode a float */ -bool float_decode(cbor_state_t *state, double *result); -bool float_expect(cbor_state_t *state, double *result); - -/** Skip a single element, regardless of type and value. */ -bool any_decode(cbor_state_t *state, void *result); - -/** Decode a tag. */ -bool tag_decode(cbor_state_t *state, uint32_t *result); -bool tag_expect(cbor_state_t *state, uint32_t result); - -/** Decode 0 or more elements with the same type and constraints. - * - * @details This must not necessarily decode all elements in a list. E.g. if - * the list contains 3 INTS between 0 and 100 followed by 0 to 2 BSTRs - * with length 8, that could be done with: - * - * @code{c} - * uint32_t int_min = 0; - * uint32_t int_max = 100; - * uint32_t bstr_size = 8; - * uint32_t ints[3]; - * cbor_string_type_t bstrs[2]; - * bool res; - * - * res = list_start_encode(state, 3, 5); - * // check res - * res = multi_encode(3, 3, &num_encode, uintx32_encode, state, - * ints, &int_min, &int_max, 4); - * // check res - * res = multi_encode(0, 2, &num_encode, strx_encode, state, - * bstrs, &bstr_size, &bstr_size, - * sizeof(cbor_string_type_t)); - * // check res - * res = list_end_encode(state, 3, 5); - * // check res - * @endcode - * - * @param[in] min_decode The minimum acceptable number of elements. - * @param[in] max_decode The maximum acceptable number of elements. - * @param[out] num_decode The actual number of elements. - * @param[in] decoder The decoder function to call under the hood. This - * function will be called with the provided arguments - * repeatedly until the function fails (returns false) - * or until it has been called @p max_decode times. - * result is moved @p result_len bytes for each call - * to @p decoder, i.e. @p result refers to an array - * of result variables. - * @param[out] result Where to place the decoded values. Must be an array - * of length at least @p max_decode. - * @param[in] result_len The length of the result variables. Must be the - * length matching the elements of @p result. - * - * @retval true If at least @p min_decode variables were correctly decoded. - * @retval false If @p decoder failed before having decoded @p min_decode - * values. - */ -bool multi_decode(uint32_t min_decode, uint32_t max_decode, uint32_t *num_decode, - cbor_decoder_t decoder, cbor_state_t *state, void *result, - uint32_t result_len); - -bool present_decode(uint32_t *present, - cbor_decoder_t decoder, - cbor_state_t *state, - void *result); - -#endif /* CBOR_DECODE_H__ */ diff --git a/boot/boot_serial/src/cbor_encode.c b/boot/boot_serial/src/cbor_encode.c deleted file mode 100644 index d12dc945..00000000 --- a/boot/boot_serial/src/cbor_encode.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * This file has been copied from the cddl-gen submodule. - * Commit 9f77837f9950da1633d22abf6181a830521a6688 - */ - -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include "cbor_encode.h" -#include "cbor_common.h" - -_Static_assert((sizeof(size_t) == sizeof(void *)), - "This code needs size_t to be the same length as pointers."); - -uint8_t get_additional(uint32_t len, uint8_t value0) -{ - switch(len) { - case 0: return value0; - case 1: return 24; - case 2: return 25; - case 3: return 25; - case 4: return 26; - case 5: return 26; - case 6: return 26; - case 7: return 26; - case 8: return 27; - } - - cbor_assert(false, NULL); - return 0; -} - -static bool encode_header_byte(cbor_state_t *state, - cbor_major_type_t major_type, uint8_t additional) -{ - if ((state->payload + 1) > state->payload_end) { - FAIL(); - } - - cbor_assert(additional < 32, NULL); - - *(state->payload_mut++) = (major_type << 5) | (additional & 0x1F); - return true; -} - -/** Encode a single value. - */ -static bool value_encode_len(cbor_state_t *state, cbor_major_type_t major_type, - const void *const input, uint32_t result_len) -{ - uint8_t *u8_result = (uint8_t *)input; - - if ((state->payload + 1 + result_len) > state->payload_end) { - FAIL(); - } - - if (!encode_header_byte(state, major_type, - get_additional(result_len, u8_result[0]))) { - FAIL(); - } - state->payload_mut--; - cbor_trace(); - state->payload_mut++; - -#ifdef CONFIG_BIG_ENDIAN - memcpy(state->payload_mut, u8_result, result_len); - state->payload_mut += result_len; -#else - for (; result_len > 0; result_len--) { - *(state->payload_mut++) = u8_result[result_len - 1]; - } -#endif - - state->elem_count++; - return true; -} - - -static uint32_t get_result_len(const void *const input, uint32_t max_result_len) -{ - uint8_t *u8_result = (uint8_t *)input; - size_t i; - - for (i = 0; i < max_result_len; i++) { -#ifdef CONFIG_BIG_ENDIAN - size_t idx = i; -#else - size_t idx = max_result_len - 1 - i; -#endif - if (u8_result[idx] != 0) { - break; - } - } - max_result_len -= i; - - /* According to specification result length can be encoded on 1, 2, 4 - * or 8 bytes. - */ - cbor_assert(max_result_len <= 8, "Up to 8 bytes can be used to encode length.\n"); - size_t encode_byte_cnt = 1; - - for (size_t i = 0; i <= 3; i++) { - if (max_result_len <= encode_byte_cnt) { - max_result_len = encode_byte_cnt; - break; - } - - encode_byte_cnt *= 2; - } - - if ((max_result_len == 1) && (u8_result[0] <= VALUE_IN_HEADER)) { - max_result_len = 0; - } - - return max_result_len; -} - - -static bool value_encode(cbor_state_t *state, cbor_major_type_t major_type, - const void *const input, uint32_t max_result_len) -{ - cbor_assert(max_result_len != 0, "0-length result not supported.\n"); - return value_encode_len(state, major_type, input, - get_result_len(input, max_result_len)); -} - - -bool intx32_put(cbor_state_t *state, int32_t input) -{ - cbor_major_type_t major_type; - - if (input < 0) { - major_type = CBOR_MAJOR_TYPE_NINT; - /* Convert from CBOR's representation. */ - input = -1 - input; - } else { - major_type = CBOR_MAJOR_TYPE_PINT; - input = input; - } - - if (!value_encode(state, major_type, &input, 4)) { - FAIL(); - } - - return true; -} - -bool intx32_encode(cbor_state_t *state, const int32_t *input) -{ - return intx32_put(state, *input); -} - - -static bool uint32_encode(cbor_state_t *state, const uint32_t *input, - cbor_major_type_t major_type) -{ - if (!value_encode(state, major_type, input, 4)) { - FAIL(); - } - return true; -} - - -bool uintx32_encode(cbor_state_t *state, const uint32_t *input) -{ - if (!uint32_encode(state, input, CBOR_MAJOR_TYPE_PINT)) { - FAIL(); - } - return true; -} - - -bool uintx32_put(cbor_state_t *state, uint32_t input) -{ - if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PINT)) { - FAIL(); - } - return true; -} - - -static bool strx_start_encode(cbor_state_t *state, - const cbor_string_type_t *input, cbor_major_type_t major_type) -{ - if (input->value && ((get_result_len(&input->len, sizeof(input->len)) - + 1 + input->len + (size_t)state->payload) - > (size_t)state->payload_end)) { - FAIL(); - } - if (!uint32_encode(state, &input->len, major_type)) { - FAIL(); - } - - return true; -} - - -static bool primx_encode(cbor_state_t *state, uint32_t input) -{ - if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PRIM)) { - FAIL(); - } - return true; -} - - -static uint32_t remaining_str_len(cbor_state_t *state) -{ - uint32_t max_len = (size_t)state->payload_end - (size_t)state->payload; - uint32_t result_len = get_result_len(&max_len, sizeof(uint32_t)); - return max_len - result_len - 1; -} - - -bool bstrx_cbor_start_encode(cbor_state_t *state, const cbor_string_type_t *result) -{ - if (!new_backup(state, 0)) { - FAIL(); - } - - uint32_t max_len = remaining_str_len(state); - - /* Encode a dummy header */ - if (!uint32_encode(state, &max_len, - CBOR_MAJOR_TYPE_BSTR)) { - FAIL(); - } - return true; -} - - -bool bstrx_cbor_end_encode(cbor_state_t *state) -{ - const uint8_t *payload = state->payload; - - if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) { - FAIL(); - } - cbor_string_type_t value; - - value.value = state->payload_end - remaining_str_len(state); - value.len = (size_t)payload - (size_t)value.value; - - /* Reencode header of list now that we know the number of elements. */ - if (!bstrx_encode(state, &value)) { - FAIL(); - } - return true; -} - - -static bool strx_encode(cbor_state_t *state, - const cbor_string_type_t *input, cbor_major_type_t major_type) -{ - if (!strx_start_encode(state, input, major_type)) { - FAIL(); - } - if (input->len > (state->payload_end - state->payload)) { - FAIL(); - } - if (state->payload_mut != input->value) { - memmove(state->payload_mut, input->value, input->len); - } - state->payload += input->len; - return true; -} - - -bool bstrx_encode(cbor_state_t *state, const cbor_string_type_t *input) -{ - return strx_encode(state, input, CBOR_MAJOR_TYPE_BSTR); -} - - -bool tstrx_encode(cbor_state_t *state, const cbor_string_type_t *input) -{ - return strx_encode(state, input, CBOR_MAJOR_TYPE_TSTR); -} - - -static bool list_map_start_encode(cbor_state_t *state, uint32_t max_num, - cbor_major_type_t major_type) -{ -#ifdef CDDL_CBOR_CANONICAL - if (!new_backup(state, 0)) { - FAIL(); - } - - /* Encode dummy header with max number of elements. */ - if (!uint32_encode(state, &max_num, major_type)) { - FAIL(); - } - state->elem_count--; /* Because of dummy header. */ -#else - if (!encode_header_byte(state, major_type, 31)) { - FAIL(); - } -#endif - return true; -} - - -bool list_start_encode(cbor_state_t *state, uint32_t max_num) -{ - return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_LIST); -} - - -bool map_start_encode(cbor_state_t *state, uint32_t max_num) -{ - return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_MAP); -} - - -bool list_map_end_encode(cbor_state_t *state, uint32_t max_num, - cbor_major_type_t major_type) -{ -#ifdef CDDL_CBOR_CANONICAL - uint32_t list_count = ((major_type == CBOR_MAJOR_TYPE_LIST) ? - state->elem_count - : (state->elem_count / 2)); - - const uint8_t *payload = state->payload; - uint32_t max_header_len = get_result_len(&max_num, 4); - uint32_t header_len = get_result_len(&list_count, 4); - - if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) { - FAIL(); - } - - cbor_print("list_count: %d\r\n", list_count); - - /* Reencode header of list now that we know the number of elements. */ - if (!(uint32_encode(state, &list_count, major_type))) { - FAIL(); - } - - if (max_header_len != header_len) { - const uint8_t *start = state->payload + max_header_len - header_len; - uint32_t body_size = payload - start; - memmove(state->payload_mut, - state->payload + max_header_len - header_len, - body_size); - /* Reset payload pointer to end of list */ - state->payload += body_size; - } else { - /* Reset payload pointer to end of list */ - state->payload = payload; - } -#else - if (!encode_header_byte(state, CBOR_MAJOR_TYPE_PRIM, 31)) { - FAIL(); - } -#endif - return true; -} - - -bool list_end_encode(cbor_state_t *state, uint32_t max_num) -{ - return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_LIST); -} - - -bool map_end_encode(cbor_state_t *state, uint32_t max_num) -{ - return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_MAP); -} - - -bool nilx_put(cbor_state_t *state, const void *input) -{ - (void)input; - return primx_encode(state, 22); -} - - -bool boolx_encode(cbor_state_t *state, const bool *input) -{ - if (!primx_encode(state, *input + BOOL_TO_PRIM)) { - FAIL(); - } - return true; -} - - -bool boolx_put(cbor_state_t *state, bool input) -{ - if (!primx_encode(state, input + BOOL_TO_PRIM)) { - FAIL(); - } - return true; -} - - -bool double_encode(cbor_state_t *state, double *input) -{ - if (!value_encode(state, CBOR_MAJOR_TYPE_PRIM, input, - sizeof(*input))) { - FAIL(); - } - - return true; -} - - -bool double_put(cbor_state_t *state, double input) -{ - return double_encode(state, &input); -} - - -bool any_encode(cbor_state_t *state, void *input) -{ - return nilx_put(state, input); -} - - -bool tag_encode(cbor_state_t *state, uint32_t tag) -{ - if (!value_encode(state, CBOR_MAJOR_TYPE_TAG, &tag, sizeof(tag))) { - FAIL(); - } - state->elem_count--; - - return true; -} - - -bool multi_encode(uint32_t min_encode, - uint32_t max_encode, - const uint32_t *num_encode, - cbor_encoder_t encoder, - cbor_state_t *state, - const void *input, - uint32_t result_len) -{ - if (!PTR_VALUE_IN_RANGE(uint32_t, num_encode, NULL, &max_encode)) { - FAIL(); - } - for (uint32_t i = 0; i < *num_encode; i++) { - if (!encoder(state, (const uint8_t *)input + i*result_len)) { - FAIL(); - } - } - cbor_print("Found %zu elements.\n", *num_encode); - return true; -} - - -bool present_encode(const uint32_t *present, - cbor_encoder_t encoder, - cbor_state_t *state, - const void *input) -{ - uint32_t num_encode = *present; - bool retval = multi_encode(0, 1, &num_encode, encoder, state, input, 0); - return retval; -} diff --git a/boot/boot_serial/src/cbor_encode.h b/boot/boot_serial/src/cbor_encode.h deleted file mode 100644 index 4c53d459..00000000 --- a/boot/boot_serial/src/cbor_encode.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * This file has been copied from the cddl-gen submodule. - * Commit 9f77837f9950da1633d22abf6181a830521a6688 - */ - -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef CBOR_ENCODE_H__ -#define CBOR_ENCODE_H__ -#include -#include -#include -#include "cbor_common.h" - - -/** Encode a PINT/NINT into a int32_t. - * - * @param[inout] state The current state of the decoding. - * @param[out] result Where to place the encoded value. - * - * @retval true Everything is ok. - * @retval false If the payload is exhausted. - */ -bool intx32_encode(cbor_state_t *state, const int32_t *input); -bool intx32_put(cbor_state_t *state, int32_t result); - -/** Encode a PINT into a uint32_t. */ -bool uintx32_encode(cbor_state_t *state, const uint32_t *result); -bool uintx32_put(cbor_state_t *state, uint32_t result); - -/** Encode a BSTR header. - * - * The rest of the string can be encoded as CBOR. - * A state backup is created to keep track of the element count. - * - * @retval true Header encoded correctly - * @retval false Header encoded incorrectly, or backup failed. - */ -bool bstrx_cbor_start_encode(cbor_state_t *state, const cbor_string_type_t *result); - -/** Finalize encoding a CBOR-encoded BSTR. - * - * Restore element count from backup. - */ -bool bstrx_cbor_end_encode(cbor_state_t *state); - -/** Encode a BSTR, */ -bool bstrx_encode(cbor_state_t *state, const cbor_string_type_t *result); - -/** Encode a TSTR. */ -bool tstrx_encode(cbor_state_t *state, const cbor_string_type_t *result); - -#define tstrx_put(state, string) \ - tstrx_encode(state, &(cbor_string_type_t){.value = (const uint8_t *)string, .len = (sizeof(string) - 1)}) - -#define tstrx_put_term(state, string) \ - tstrx_encode(state, &(cbor_string_type_t){.value = (const uint8_t *)string, .len = strlen((const char *)string)}) - -/** Encode a LIST header. - * - * The contents of the list can be decoded via subsequent function calls. - * A state backup is created to keep track of the element count. - */ -bool list_start_encode(cbor_state_t *state, uint32_t max_num); - -/** Encode a MAP header. */ -bool map_start_encode(cbor_state_t *state, uint32_t max_num); - -/** Encode end of a LIST. Do some checks and deallocate backup. */ -bool list_end_encode(cbor_state_t *state, uint32_t max_num); - -/** Encode end of a MAP. Do some checks and deallocate backup. */ -bool map_end_encode(cbor_state_t *state, uint32_t max_num); - -/** Encode a "nil" primitive value. result should be NULL. */ -bool nilx_put(cbor_state_t *state, const void *result); - -/** Encode a boolean primitive value. */ -bool boolx_encode(cbor_state_t *state, const bool *result); -bool boolx_put(cbor_state_t *state, bool result); - -/** Encode a float */ -bool float_encode(cbor_state_t *state, double *result); -bool float_put(cbor_state_t *state, double result); - -/** Dummy encode "any": Encode a "nil". input should be NULL. */ -bool any_encode(cbor_state_t *state, void *input); - -/** Encode a tag. */ -bool tag_encode(cbor_state_t *state, uint32_t tag); - -/** Encode 0 or more elements with the same type and constraints. - * - * @details This must not necessarily encode all elements in a list. E.g. if - * the list contains 3 INTS between 0 and 100 followed by 0 to 2 BSTRs - * with length 8, that could be done with: - * - * @code{c} - * uint32_t int_min = 0; - * uint32_t int_max = 100; - * uint32_t bstr_size = 8; - * uint32_t ints[3]; - * cbor_string_type_t bstrs[2] = ; - * bool res; - * - * res = list_start_encode(state, 5); - * // check res - * res = multi_encode(3, 3, &num_encode, uintx32_encode, state, - * ints, 4); - * // check res - * res = multi_encode(0, 2, &num_encode, strx_encode, state, - * bstrs, sizeof(cbor_string_type_t)); - * // check res - * res = list_end_encode(state, 5); - * // check res - * @endcode - * - * @param[in] min_encode The minimum acceptable number of elements. - * @param[in] max_encode The maximum acceptable number of elements. - * @param[in] num_encode The actual number of elements. - * @param[in] encoder The encoder function to call under the hood. This - * function will be called with the provided arguments - * repeatedly until the function fails (returns false) - * or until it has been called @p max_encode times. - * result is moved @p result_len bytes for each call - * to @p encoder, i.e. @p result refers to an array - * of result variables. - * @param[in] input Source of the encoded values. Must be an array - * of length at least @p max_encode. - * @param[in] result_len The length of the result variables. Must be the - * length of the elements in result. - * - * @retval true If at least @p min_encode variables were correctly encoded. - * @retval false If @p encoder failed before having encoded @p min_encode - * values. - */ -bool multi_encode(uint32_t min_encode, uint32_t max_encode, const uint32_t *num_encode, - cbor_encoder_t encoder, cbor_state_t *state, const void *input, - uint32_t result_len); - -bool present_encode(const uint32_t *present, - cbor_encoder_t encoder, - cbor_state_t *state, - const void *input); - -#endif /* CBOR_ENCODE_H__ */ diff --git a/boot/boot_serial/src/regenerate_serial_recovery_cbor.sh b/boot/boot_serial/src/regenerate_serial_recovery_cbor.sh index 08d12200..1f2137a4 100755 --- a/boot/boot_serial/src/regenerate_serial_recovery_cbor.sh +++ b/boot/boot_serial/src/regenerate_serial_recovery_cbor.sh @@ -1,36 +1,30 @@ #!/bin/bash if [ "$1" == "--help" ] || [ "$1" == "" ]; then - echo "Regenerate serial_recovery_cbor.c|h if the cddl-gen submodule is updated." + echo "Regenerate serial_recovery_cbor.c|h if the zcbor submodule is updated." echo "Usage: $0 " - echo " e.g. $0 \"2021 Nordic Semiconductor ASA\"" + echo " e.g. $0 \"2022 Nordic Semiconductor ASA\"" exit -1 fi add_copy_notice() { echo "$(printf '/* - * This file has been %s from the cddl-gen submodule. + * This file has been %s from the zcbor library. * Commit %s */ -' "$2" "$(git -C ../../../ext/cddl-gen rev-parse HEAD)"; cat $1;)" > $1 +' "$2" "$(zcbor --version)"; cat $1;)" > $1 } -echo "Copying cbor_decode.c|h" +echo "Copying zcbor_decode.c|h" copy_with_copy_notice() { cp $1 $2 add_copy_notice $2 "copied" } -copy_with_copy_notice ../../../ext/cddl-gen/src/cbor_decode.c cbor_decode.c -copy_with_copy_notice ../../../ext/cddl-gen/src/cbor_encode.c cbor_encode.c -copy_with_copy_notice ../../../ext/cddl-gen/src/cbor_common.c cbor_common.c -copy_with_copy_notice ../../../ext/cddl-gen/include/cbor_decode.h cbor_decode.h -copy_with_copy_notice ../../../ext/cddl-gen/include/cbor_encode.h cbor_encode.h -copy_with_copy_notice ../../../ext/cddl-gen/include/cbor_common.h cbor_common.h echo "Generating serial_recovery_cbor.c|h" -python3 ../../../ext/cddl-gen/cddl_gen/cddl_gen.py -c serial_recovery.cddl code -d -t Upload --oc serial_recovery_cbor.c --oh serial_recovery_cbor.h --time-header +zcbor -c serial_recovery.cddl code -d -t Upload --oc serial_recovery_cbor.c --oh serial_recovery_cbor.h --time-header --copy-sources add_copyright() { echo "$(printf '/* @@ -44,6 +38,10 @@ echo "$(printf '/* add_copyright serial_recovery_cbor.c "$1" add_copyright serial_recovery_cbor.h "$1" -add_copy_notice serial_recovery_cbor.c "generated" -add_copy_notice serial_recovery_cbor.h "generated" -add_copy_notice types_serial_recovery_cbor.h "generated" +add_copyright serial_recovery_cbor_types.h "$1" +add_copy_notice zcbor_decode.c "copied" +add_copy_notice zcbor_encode.c "copied" +add_copy_notice zcbor_common.c "copied" +add_copy_notice zcbor_decode.h "copied" +add_copy_notice zcbor_encode.h "copied" +add_copy_notice zcbor_common.h "copied" diff --git a/boot/boot_serial/src/serial_recovery_cbor.c b/boot/boot_serial/src/serial_recovery_cbor.c index 2561b706..b00e48cc 100644 --- a/boot/boot_serial/src/serial_recovery_cbor.c +++ b/boot/boot_serial/src/serial_recovery_cbor.c @@ -1,25 +1,21 @@ /* - * This file has been generated from the cddl-gen submodule. - * Commit 9f77837f9950da1633d22abf6181a830521a6688 - */ - -/* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2022 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ /* - * Generated with cddl_gen.py (https://github.com/NordicSemiconductor/cddl-gen) - * at: 2021-08-02 17:09:42 - * Generated with a default_max_qty of 3 + * Generated using zcbor version 0.4.0 + * https://github.com/NordicSemiconductor/zcbor + * at: 2022-03-31 12:37:11 + * Generated with a --default-max-qty of 3 */ #include #include #include #include -#include "cbor_decode.h" +#include "zcbor_decode.h" #include "serial_recovery_cbor.h" #if DEFAULT_MAX_QTY != 3 @@ -28,67 +24,76 @@ static bool decode_Member( - cbor_state_t *state, struct Member_ *result) + zcbor_state_t *state, struct Member_ *result) { - cbor_print("%s\n", __func__); - cbor_string_type_t tmp_str; + zcbor_print("%s\r\n", __func__); + struct zcbor_string tmp_str; bool int_res; - bool tmp_result = (((union_start_code(state) && (int_res = (((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"image", - tmp_str.len = sizeof("image") - 1, &tmp_str))))) - && (intx32_decode(state, (&(*result)._Member_image)))) && (((*result)._Member_choice = _Member_image) || 1)) - || (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"data", - tmp_str.len = sizeof("data") - 1, &tmp_str))))) - && (bstrx_decode(state, (&(*result)._Member_data)))) && (((*result)._Member_choice = _Member_data) || 1))) - || (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"len", - tmp_str.len = sizeof("len") - 1, &tmp_str))))) - && (intx32_decode(state, (&(*result)._Member_len)))) && (((*result)._Member_choice = _Member_len) || 1))) - || (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"off", - tmp_str.len = sizeof("off") - 1, &tmp_str))))) - && (intx32_decode(state, (&(*result)._Member_off)))) && (((*result)._Member_choice = _Member_off) || 1))) - || (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"sha", - tmp_str.len = sizeof("sha") - 1, &tmp_str))))) - && (bstrx_decode(state, (&(*result)._Member_sha)))) && (((*result)._Member_choice = _Member_sha) || 1)))), union_end_code(state), int_res)))); + bool tmp_result = (((zcbor_union_start_code(state) && (int_res = (((((zcbor_tstr_expect(state, ((tmp_str.value = (uint8_t *)"image", tmp_str.len = sizeof("image") - 1, &tmp_str))))) + && (zcbor_int32_decode(state, (&(*result)._Member_image)))) && (((*result)._Member_choice = _Member_image) || 1)) + || (zcbor_union_elem_code(state) && ((((zcbor_tstr_expect(state, ((tmp_str.value = (uint8_t *)"data", tmp_str.len = sizeof("data") - 1, &tmp_str))))) + && (zcbor_bstr_decode(state, (&(*result)._Member_data)))) && (((*result)._Member_choice = _Member_data) || 1))) + || (zcbor_union_elem_code(state) && ((((zcbor_tstr_expect(state, ((tmp_str.value = (uint8_t *)"len", tmp_str.len = sizeof("len") - 1, &tmp_str))))) + && (zcbor_int32_decode(state, (&(*result)._Member_len)))) && (((*result)._Member_choice = _Member_len) || 1))) + || (zcbor_union_elem_code(state) && ((((zcbor_tstr_expect(state, ((tmp_str.value = (uint8_t *)"off", tmp_str.len = sizeof("off") - 1, &tmp_str))))) + && (zcbor_int32_decode(state, (&(*result)._Member_off)))) && (((*result)._Member_choice = _Member_off) || 1))) + || (zcbor_union_elem_code(state) && ((((zcbor_tstr_expect(state, ((tmp_str.value = (uint8_t *)"sha", tmp_str.len = sizeof("sha") - 1, &tmp_str))))) + && (zcbor_bstr_decode(state, (&(*result)._Member_sha)))) && (((*result)._Member_choice = _Member_sha) || 1)))), zcbor_union_end_code(state), int_res)))); if (!tmp_result) - cbor_trace(); + zcbor_trace(); + + return tmp_result; +} + +static bool decode_repeated_Upload_members( + zcbor_state_t *state, struct Upload_members *result) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = (((decode_Member(state, (&(*result)._Upload_members))))); + + if (!tmp_result) + zcbor_trace(); return tmp_result; } static bool decode_Upload( - cbor_state_t *state, struct Upload *result) + zcbor_state_t *state, struct Upload *result) { - cbor_print("%s\n", __func__); - bool int_res; + zcbor_print("%s\r\n", __func__); - bool tmp_result = (((map_start_decode(state) && (int_res = (multi_decode(1, 5, &(*result)._Upload_members_count, (void *)decode_Member, state, (&(*result)._Upload_members), sizeof(struct Member_))), ((map_end_decode(state)) && int_res))))); + bool tmp_result = (((zcbor_map_start_decode(state) && ((zcbor_multi_decode(1, 5, &(*result)._Upload_members_count, (zcbor_decoder_t *)decode_repeated_Upload_members, state, (&(*result)._Upload_members), sizeof(struct Upload_members))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_map_end_decode(state)))); if (!tmp_result) - cbor_trace(); + zcbor_trace(); return tmp_result; } -__attribute__((unused)) static bool type_test_decode_Upload( - struct Upload *result) -{ - /* This function should not be called, it is present only to test that - * the types of the function and struct match, since this information - * is lost with the casts in the entry function. - */ - return decode_Upload(NULL, result); -} - - -bool cbor_decode_Upload( - const uint8_t *payload, uint32_t payload_len, +int cbor_decode_Upload( + const uint8_t *payload, size_t payload_len, struct Upload *result, - uint32_t *payload_len_out) + size_t *payload_len_out) { - return entry_function(payload, payload_len, (const void *)result, - payload_len_out, (void *)decode_Upload, - 1, 2); + zcbor_state_t states[4]; + + zcbor_new_state(states, sizeof(states) / sizeof(zcbor_state_t), payload, payload_len, 1); + + bool ret = decode_Upload(states, result); + + if (ret && (payload_len_out != NULL)) { + *payload_len_out = MIN(payload_len, + (size_t)states[0].payload - (size_t)payload); + } + + if (!ret) { + int ret = zcbor_pop_error(states); + return (ret == ZCBOR_SUCCESS) ? ZCBOR_ERR_UNKNOWN : ret; + } + return ZCBOR_SUCCESS; } diff --git a/boot/boot_serial/src/serial_recovery_cbor.h b/boot/boot_serial/src/serial_recovery_cbor.h index f167d9b5..cdf5335c 100644 --- a/boot/boot_serial/src/serial_recovery_cbor.h +++ b/boot/boot_serial/src/serial_recovery_cbor.h @@ -1,18 +1,14 @@ /* - * This file has been generated from the cddl-gen submodule. - * Commit 9f77837f9950da1633d22abf6181a830521a6688 - */ - -/* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2022 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ /* - * Generated with cddl_gen.py (https://github.com/NordicSemiconductor/cddl-gen) - * at: 2021-08-02 17:09:42 - * Generated with a default_max_qty of 3 + * Generated using zcbor version 0.4.0 + * https://github.com/NordicSemiconductor/zcbor + * at: 2022-03-31 12:37:11 + * Generated with a --default-max-qty of 3 */ #ifndef SERIAL_RECOVERY_CBOR_H__ @@ -22,18 +18,18 @@ #include #include #include -#include "cbor_decode.h" -#include "types_serial_recovery_cbor.h" +#include "zcbor_decode.h" +#include "serial_recovery_cbor_types.h" #if DEFAULT_MAX_QTY != 3 #error "The type file was generated with a different default_max_qty than this file" #endif -bool cbor_decode_Upload( - const uint8_t *payload, uint32_t payload_len, +int cbor_decode_Upload( + const uint8_t *payload, size_t payload_len, struct Upload *result, - uint32_t *payload_len_out); + size_t *payload_len_out); #endif /* SERIAL_RECOVERY_CBOR_H__ */ diff --git a/boot/boot_serial/src/serial_recovery_cbor_types.h b/boot/boot_serial/src/serial_recovery_cbor_types.h new file mode 100644 index 00000000..d890568d --- /dev/null +++ b/boot/boot_serial/src/serial_recovery_cbor_types.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Generated using zcbor version 0.4.0 + * https://github.com/NordicSemiconductor/zcbor + * at: 2022-03-31 12:37:11 + * Generated with a --default-max-qty of 3 + */ + +#ifndef SERIAL_RECOVERY_CBOR_TYPES_H__ +#define SERIAL_RECOVERY_CBOR_TYPES_H__ + +#include +#include +#include +#include +#include "zcbor_decode.h" + +/** Which value for --default-max-qty this file was created with. + * + * The define is used in the other generated file to do a build-time + * compatibility check. + * + * See `zcbor --help` for more information about --default-max-qty + */ +#define DEFAULT_MAX_QTY 3 + +struct Member_ { + union { + struct { + int32_t _Member_image; + }; + struct { + struct zcbor_string _Member_data; + }; + struct { + int32_t _Member_len; + }; + struct { + int32_t _Member_off; + }; + struct { + struct zcbor_string _Member_sha; + }; + }; + enum { + _Member_image, + _Member_data, + _Member_len, + _Member_off, + _Member_sha, + } _Member_choice; +}; + +struct Upload_members { + struct Member_ _Upload_members; +}; + +struct Upload { + struct Upload_members _Upload_members[5]; + uint_fast32_t _Upload_members_count; +}; + + +#endif /* SERIAL_RECOVERY_CBOR_TYPES_H__ */ diff --git a/boot/boot_serial/src/types_serial_recovery_cbor.h b/boot/boot_serial/src/types_serial_recovery_cbor.h deleted file mode 100644 index 88560178..00000000 --- a/boot/boot_serial/src/types_serial_recovery_cbor.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file has been generated from the cddl-gen submodule. - * Commit 9f77837f9950da1633d22abf6181a830521a6688 - */ - -/* - * Generated with cddl_gen.py (https://github.com/NordicSemiconductor/cddl-gen) - * at: 2021-08-02 17:09:42 - * Generated with a default_max_qty of 3 - */ - -#ifndef TYPES_SERIAL_RECOVERY_CBOR_H__ -#define TYPES_SERIAL_RECOVERY_CBOR_H__ - -#include -#include -#include -#include -#include "cbor_decode.h" - -#define DEFAULT_MAX_QTY 3 - -struct Member_ { - union { - struct { - int32_t _Member_image; - }; - struct { - cbor_string_type_t _Member_data; - }; - struct { - int32_t _Member_len; - }; - struct { - int32_t _Member_off; - }; - struct { - cbor_string_type_t _Member_sha; - }; - }; - enum { - _Member_image, - _Member_data, - _Member_len, - _Member_off, - _Member_sha, - } _Member_choice; -}; - -struct Upload { - struct Member_ _Upload_members[5]; - uint32_t _Upload_members_count; -}; - - -#endif /* TYPES_SERIAL_RECOVERY_CBOR_H__ */ diff --git a/boot/boot_serial/src/zcbor_common.c b/boot/boot_serial/src/zcbor_common.c new file mode 100644 index 00000000..71962d66 --- /dev/null +++ b/boot/boot_serial/src/zcbor_common.c @@ -0,0 +1,229 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.4.0 + */ + +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "zcbor_common.h" + +_Static_assert((sizeof(size_t) == sizeof(void *)), + "This code needs size_t to be the same length as pointers."); + +_Static_assert((sizeof(zcbor_state_t) >= sizeof(struct zcbor_state_constant)), + "This code needs zcbor_state_t to be at least as large as zcbor_backups_t."); + +bool zcbor_new_backup(zcbor_state_t *state, uint_fast32_t new_elem_count) +{ + ZCBOR_CHECK_ERROR(); + + if ((state->constant_state->current_backup) + >= state->constant_state->num_backups) { + ZCBOR_ERR(ZCBOR_ERR_NO_BACKUP_MEM); + } + + state->payload_moved = false; + + (state->constant_state->current_backup)++; + + /* use the backup at current_backup - 1, since otherwise, the 0th + * backup would be unused. */ + uint_fast32_t i = (state->constant_state->current_backup) - 1; + + memcpy(&state->constant_state->backup_list[i], state, + sizeof(zcbor_state_t)); + + state->elem_count = new_elem_count; + + return true; +} + + +bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, + uint_fast32_t max_elem_count) +{ + const uint8_t *payload = state->payload; + const uint_fast32_t elem_count = state->elem_count; + + ZCBOR_CHECK_ERROR(); + + if (state->constant_state->current_backup == 0) { + zcbor_print("No backups available.\r\n"); + ZCBOR_ERR(ZCBOR_ERR_NO_BACKUP_ACTIVE); + } + + if (flags & ZCBOR_FLAG_RESTORE) { + /* use the backup at current_backup - 1, since otherwise, the + * 0th backup would be unused. */ + uint_fast32_t i = state->constant_state->current_backup - 1; + + if (!(flags & ZCBOR_FLAG_TRANSFER_PAYLOAD)) { + if (state->constant_state->backup_list[i].payload_moved) { + zcbor_print("Payload pointer out of date.\r\n"); + ZCBOR_FAIL(); + } + } + memcpy(state, &state->constant_state->backup_list[i], + sizeof(zcbor_state_t)); + } + + if (flags & ZCBOR_FLAG_CONSUME) { + state->constant_state->current_backup--; + } + + if (elem_count > max_elem_count) { + zcbor_print("elem_count: %" PRIuFAST32 " (expected max %" PRIuFAST32 ")\r\n", + elem_count, max_elem_count); + ZCBOR_ERR(ZCBOR_ERR_HIGH_ELEM_COUNT); + } + + if (flags & ZCBOR_FLAG_TRANSFER_PAYLOAD) { + state->payload = payload; + } + + return true; +} + +static void update_backups(zcbor_state_t *state, uint8_t const *new_payload_end) +{ + if (state->constant_state) { + for (int i = 0; i < state->constant_state->current_backup; i++) { + state->constant_state->backup_list[i].payload_end = new_payload_end; + state->constant_state->backup_list[i].payload_moved = true; + } + } +} + + +bool zcbor_union_start_code(zcbor_state_t *state) +{ + if (!zcbor_new_backup(state, state->elem_count)) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_union_elem_code(zcbor_state_t *state) +{ + if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE, state->elem_count)) { + ZCBOR_FAIL(); + } + return true; +} + +bool zcbor_union_end_code(zcbor_state_t *state) +{ + if (!zcbor_process_backup(state, ZCBOR_FLAG_CONSUME, state->elem_count)) { + ZCBOR_FAIL(); + } + return true; +} + +bool zcbor_new_state(zcbor_state_t *state_array, uint_fast32_t n_states, + const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count) +{ + state_array[0].payload = payload; + state_array[0].payload_end = payload + payload_len; + state_array[0].elem_count = elem_count; + state_array[0].indefinite_length_array = false; + state_array[0].payload_moved = false; + state_array[0].constant_state = NULL; + + if(n_states < 2) { + return false; + } + + /* Use the last state as a struct zcbor_state_constant object. */ + state_array[0].constant_state = (struct zcbor_state_constant *)&state_array[n_states - 1]; + state_array[0].constant_state->backup_list = NULL; + state_array[0].constant_state->num_backups = n_states - 2; + state_array[0].constant_state->current_backup = 0; + state_array[0].constant_state->error = ZCBOR_SUCCESS; +#ifdef ZCBOR_STOP_ON_ERROR + state_array[0].constant_state->stop_on_error = false; +#endif + if (n_states > 2) { + state_array[0].constant_state->backup_list = &state_array[1]; + } + return true; +} + +void zcbor_update_state(zcbor_state_t *state, + const uint8_t *payload, size_t payload_len) +{ + state->payload = payload; + state->payload_end = payload + payload_len; + + update_backups(state, state->payload_end); +} + + +bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, + uint_fast32_t num_fragments) +{ + size_t total_len = 0; + + if (fragments == NULL) { + return false; + } + + for (uint_fast32_t i = 0; i < num_fragments; i++) { + if (fragments[i].offset != total_len) { + return false; + } + if (fragments[i].fragment.value == NULL) { + return false; + } + if (fragments[i].total_len != fragments[0].total_len) { + return false; + } + total_len += fragments[i].fragment.len; + if (total_len > fragments[0].total_len) { + return false; + } + } + + if (num_fragments && total_len != fragments[0].total_len) { + return false; + } + + if (num_fragments && (fragments[0].total_len == ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH)) { + for (uint_fast32_t i = 0; i < num_fragments; i++) { + fragments[i].total_len = total_len; + } + } + + return true; +} + +bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, + uint_fast32_t num_fragments, uint8_t *result, size_t *result_len) +{ + size_t total_len = 0; + + if (!fragments) { + return false; + } + + for (uint_fast32_t i = 0; i < num_fragments; i++) { + if ((total_len > *result_len) + || (fragments[i].fragment.len > (*result_len - total_len))) { + return false; + } + memcpy(&result[total_len], + fragments[i].fragment.value, fragments[i].fragment.len); + total_len += fragments[i].fragment.len; + } + + *result_len = total_len; + return true; +} diff --git a/boot/boot_serial/src/zcbor_common.h b/boot/boot_serial/src/zcbor_common.h new file mode 100644 index 00000000..eae2ffa3 --- /dev/null +++ b/boot/boot_serial/src/zcbor_common.h @@ -0,0 +1,371 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.4.0 + */ + +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZCBOR_COMMON_H__ +#define ZCBOR_COMMON_H__ +#include +#include +#include + + +/** Convenience type that allows pointing to strings directly inside the payload + * without the need to copy out. + */ +struct zcbor_string { + const uint8_t *value; + size_t len; +}; + + +/** Type representing a string fragment. + * + * Don't modify any member variables, or subsequent calls may fail. +**/ +struct zcbor_string_fragment { + struct zcbor_string fragment; ///! Location and length of the fragment. + size_t offset; ///! The offset in the full string at which this fragment belongs. + size_t total_len; ///! The total length of the string this fragment is a part of. +}; + + +/** Size to use in struct zcbor_string_fragment when the real size is unknown. */ +#define ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH SIZE_MAX + +#ifdef ZCBOR_VERBOSE +#include +#define zcbor_trace() (printk("bytes left: %zu, byte: 0x%x, elem_count: 0x%" PRIxFAST32 ", %s:%d\n",\ + (size_t)state->payload_end - (size_t)state->payload, *state->payload, \ + state->elem_count, __FILE__, __LINE__)) + +#define zcbor_print_assert(expr, ...) \ +do { \ + printk("ASSERTION \n \"" #expr \ + "\"\nfailed at %s:%d with message:\n ", \ + __FILE__, __LINE__); \ + printk(__VA_ARGS__);\ +} while(0) +#define zcbor_print(...) printk(__VA_ARGS__) +#else +#define zcbor_trace() ((void)state) +#define zcbor_print_assert(...) +#define zcbor_print(...) +#endif + +#ifdef ZCBOR_ASSERTS +#define zcbor_assert(expr, ...) \ +do { \ + if (!(expr)) { \ + zcbor_print_assert(expr, __VA_ARGS__); \ + ZCBOR_FAIL(); \ + } \ +} while(0) +#else +#define zcbor_assert(expr, ...) +#endif + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + + +struct zcbor_state_constant; + +typedef struct { +union { + uint8_t *payload_mut; + uint8_t const *payload; /**< The current place in the payload. Will be + updated when an element is correctly + processed. */ +}; + uint8_t const *payload_bak; /**< Temporary backup of payload. */ + uint_fast32_t elem_count; /**< The current element is part of a LIST or a MAP, + and this keeps count of how many elements are + expected. This will be checked before processing + and decremented if the element is correctly + processed. */ + uint8_t const *payload_end; /**< The end of the payload. This will be + checked against payload before + processing each element. */ + bool indefinite_length_array; /**< Is set to true if the decoder is currently + decoding the contents of an indefinite- + length array. */ + bool payload_moved; /**< Is set to true while the state is stored as a backup + if @ref zcbor_update_state is called, since that function + updates the payload_end of all backed-up states. */ + struct zcbor_state_constant *constant_state; /**< The part of the state that is + not backed up and duplicated. */ +} zcbor_state_t; + +struct zcbor_state_constant { + zcbor_state_t *backup_list; + uint_fast32_t current_backup; + uint_fast32_t num_backups; + int error; +#ifdef ZCBOR_STOP_ON_ERROR + bool stop_on_error; +#endif +}; + +/** Function pointer type used with zcbor_multi_decode. + * + * This type is compatible with all decoding functions here and in the generated + * code, except for zcbor_multi_decode. + */ +typedef bool(zcbor_encoder_t)(zcbor_state_t *, const void *); +typedef bool(zcbor_decoder_t)(zcbor_state_t *, void *); + +/** Enumeration representing the major types available in CBOR. + * + * The major type is represented in the 3 first bits of the header byte. + */ +typedef enum +{ + ZCBOR_MAJOR_TYPE_PINT = 0, ///! Positive Integer + ZCBOR_MAJOR_TYPE_NINT = 1, ///! Negative Integer + ZCBOR_MAJOR_TYPE_BSTR = 2, ///! Byte String + ZCBOR_MAJOR_TYPE_TSTR = 3, ///! Text String + ZCBOR_MAJOR_TYPE_LIST = 4, ///! List + ZCBOR_MAJOR_TYPE_MAP = 5, ///! Map + ZCBOR_MAJOR_TYPE_TAG = 6, ///! Semantic Tag + ZCBOR_MAJOR_TYPE_PRIM = 7, ///! Primitive Type +} zcbor_major_type_t; + + +/** Convenience macro for failing out of a decoding/encoding function. +*/ +#define ZCBOR_FAIL() \ +do {\ + zcbor_trace(); \ + return false; \ +} while(0) + +#define ZCBOR_ERR(err) \ +do { \ + zcbor_error(state, err); \ + ZCBOR_FAIL(); \ +} while(0) + +#define ZCBOR_ERR_IF(expr, err) \ +do {\ + if (expr) { \ + ZCBOR_ERR(err); \ + } \ +} while(0) + +#define ZCBOR_CHECK_PAYLOAD() \ + ZCBOR_ERR_IF(state->payload >= state->payload_end, ZCBOR_ERR_NO_PAYLOAD) + +#ifdef ZCBOR_STOP_ON_ERROR +#define ZCBOR_CHECK_ERROR() \ +do { \ + if (!zcbor_check_error(state)) { \ + ZCBOR_FAIL(); \ + } \ +} while(0) +#else +#define ZCBOR_CHECK_ERROR() +#endif + +#define ZCBOR_VALUE_IN_HEADER 23 ///! Values below this are encoded directly in the header. +#define ZCBOR_VALUE_IS_1_BYTE 24 ///! The next 1 byte contains the value. +#define ZCBOR_VALUE_IS_2_BYTES 25 ///! The next 2 bytes contain the value. +#define ZCBOR_VALUE_IS_4_BYTES 26 ///! The next 4 bytes contain the value. +#define ZCBOR_VALUE_IS_8_BYTES 27 ///! The next 8 bytes contain the value. +#define ZCBOR_VALUE_IS_INDEFINITE_LENGTH 31 ///! The list or map has indefinite length, and will instead be terminated by a 0xFF token. + +#define ZCBOR_BOOL_TO_PRIM ((uint8_t)20) ///! In CBOR, false/true have the values 20/21 + +#define ZCBOR_FLAG_RESTORE 1UL ///! Restore from the backup. Overwrite the current state with the state from the backup. +#define ZCBOR_FLAG_CONSUME 2UL ///! Consume the backup. Remove the backup from the stack of backups. +#define ZCBOR_FLAG_TRANSFER_PAYLOAD 4UL ///! Keep the pre-restore payload after restoring. + +#define ZCBOR_SUCCESS 0 +#define ZCBOR_ERR_NO_BACKUP_MEM 1 +#define ZCBOR_ERR_NO_BACKUP_ACTIVE 2 +#define ZCBOR_ERR_LOW_ELEM_COUNT 3 +#define ZCBOR_ERR_HIGH_ELEM_COUNT 4 +#define ZCBOR_ERR_INT_SIZE 5 +#define ZCBOR_ERR_FLOAT_SIZE 6 +#define ZCBOR_ERR_ADDITIONAL_INVAL 7 ///! > 27 +#define ZCBOR_ERR_NO_PAYLOAD 8 +#define ZCBOR_ERR_PAYLOAD_NOT_CONSUMED 9 +#define ZCBOR_ERR_WRONG_TYPE 10 +#define ZCBOR_ERR_WRONG_VALUE 11 +#define ZCBOR_ERR_WRONG_RANGE 12 +#define ZCBOR_ERR_ITERATIONS 13 +#define ZCBOR_ERR_ASSERTION 14 +#define ZCBOR_ERR_UNKNOWN 31 + +/** The largest possible elem_count. */ +#ifdef UINT_FAST32_MAX +#define ZCBOR_MAX_ELEM_COUNT UINT_FAST32_MAX +#else +#define ZCBOR_MAX_ELEM_COUNT ((uint_fast32_t)(-1L)) +#endif + +/** Initial value for elem_count for when it just needs to be large. */ +#define ZCBOR_LARGE_ELEM_COUNT (ZCBOR_MAX_ELEM_COUNT - 16) + + +/** Values defined by RFC8949 via www.iana.org/assignments/cbor-tags/cbor-tags.xhtml */ +enum zcbor_rfc8949_tag { + ZCBOR_TAG_TIME_TSTR = 0, ///! text string Standard date/time string + ZCBOR_TAG_TIME_NUM = 1, ///! integer or float Epoch-based date/time + ZCBOR_TAG_UBIGNUM_BSTR = 2, ///! byte string Unsigned bignum + ZCBOR_TAG_BIGNUM_BSTR = 3, ///! byte string Negative bignum + ZCBOR_TAG_DECFRAC_ARR = 4, ///! array Decimal fraction + ZCBOR_TAG_BIGFLOAT_ARR = 5, ///! array Bigfloat + ZCBOR_TAG_2BASE64URL = 21, ///! (any) Expected conversion to base64url encoding + ZCBOR_TAG_2BASE64 = 22, ///! (any) Expected conversion to base64 encoding + ZCBOR_TAG_2BASE16 = 23, ///! (any) Expected conversion to base16 encoding + ZCBOR_TAG_BSTR = 24, ///! byte string Encoded CBOR data item + ZCBOR_TAG_URI_TSTR = 32, ///! text string URI + ZCBOR_TAG_BASE64URL_TSTR = 33, ///! text string base64url + ZCBOR_TAG_BASE64_TSTR = 34, ///! text string base64 + ZCBOR_TAG_MIME_TSTR = 36, ///! text string MIME message + ZCBOR_TAG_CBOR = 55799, ///! (any) Self-described CBOR +}; + + +/** Take a backup of the current state. Overwrite the current elem_count. */ +bool zcbor_new_backup(zcbor_state_t *state, uint_fast32_t new_elem_count); + +/** Consult the most recent backup. In doing so, check whether elem_count is + * less than or equal to max_elem_count. + * Also, take action based on the flags (See ZCBOR_FLAG_*). + */ +bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, uint_fast32_t max_elem_count); + +/** Convenience function for starting encoding/decoding of a union. + * + * That is, for attempting to encode, or especially decode, multiple options. + * Makes a new backup. + */ +bool zcbor_union_start_code(zcbor_state_t *state); + +/** Convenience function before encoding/decoding one element of a union. + * + * Call this before attempting each option. + * Restores the backup, without consuming it. + */ +bool zcbor_union_elem_code(zcbor_state_t *state); + +/** Convenience function before encoding/decoding one element of a union. + * + * Consumes the backup without restoring it. + */ +bool zcbor_union_end_code(zcbor_state_t *state); + +/** Initialize a state with backups. + * One of the states in the array is used as a struct zcbor_state_constant object. + * This means that you get a state with (n_states - 2) backups. + * The constant state is mandatory so n_states must be at least 2. + * payload, payload_len, and elem_count are used to initialize the first state. + * in the array, which is the state that can be passed to cbor functions. + * + * @retval false if n_states < 2 + * @retval true otherwise + */ +bool zcbor_new_state(zcbor_state_t *state_array, uint_fast32_t n_states, + const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count); + +#ifdef ZCBOR_STOP_ON_ERROR +/** Check stored error and fail if present, but only if stop_on_error is true. */ +static inline bool zcbor_check_error(const zcbor_state_t *state) +{ + return !(state->constant_state->stop_on_error && state->constant_state->error); +} +#endif + +/** Return the current error state, replacing it with SUCCESS. */ +static inline int zcbor_pop_error(zcbor_state_t *state) +{ + int err = state->constant_state->error; + + state->constant_state->error = ZCBOR_SUCCESS; + return err; +} + +/** Write the provided error to the error state. */ +static inline void zcbor_error(zcbor_state_t *state, int err) +{ +#ifdef ZCBOR_STOP_ON_ERROR + if (zcbor_check_error(state)) +#endif + { + state->constant_state->error = err; + } +} + +/** Whether the current payload is exhausted. */ +static inline bool zcbor_payload_at_end(const zcbor_state_t *state) +{ + return (state->payload == state->payload_end); +} + +/** Update the current payload pointer (and payload_end). + * + * For use when the payload is divided into multiple chunks. + * + * This function also updates all backups to the new payload_end. + * This sets a flag so that if a backup is processed with the flag + * @ref ZCBOR_FLAG_RESTORE, but without the flag + * @ref ZCBOR_FLAG_TRANSFER_PAYLOAD since this would cause an invalid state. + * + * @param[inout] state The current state, will be updated with + * the new payload pointer. + * @param[in] payload The new payload chunk. + * @param[in] payload_len The length of the new payload chunk. + */ +void zcbor_update_state(zcbor_state_t *state, + const uint8_t *payload, size_t payload_len); + +/** Check that the provided fragments are complete and in the right order. + * + * If the total length is not known, the total_len can have the value + * @ref ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH. If so, all fragments will be + * updated with the actual total length. + * + * @param[in] fragments An array of string fragments. Cannot be NULL. + * @param[in] num_fragments The number of fragments in @p fragments. + * + * @retval true If the fragments are in the right order, and there are no + * fragments missing. + * @retval false If not all fragments have the same total_len, or gaps are + * found, or if any fragment value is NULL. + */ +bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, + uint_fast32_t num_fragments); + +/** Assemble the fragments into a single string. + * + * The fragments are copied in the order they appear, without regard for + * offset or total_len. To ensure that the fragments are correct, first + * validate with @ref zcbor_validate_string_fragments. + * + * @param[in] fragments An array of string fragments. Cannot be NULL. + * @param[in] num_fragments The number of fragments in @p fragments. + * @param[out] result The buffer to place the assembled string into. + * @param[inout] result_len In: The length of the @p result. + * Out: The length of the assembled string. + * + * @retval true On success. + * @retval false If the assembled string would be larger than the buffer. + * The buffer might still be written to. + */ +bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, + uint_fast32_t num_fragments, uint8_t *result, size_t *result_len); + +#endif /* ZCBOR_COMMON_H__ */ diff --git a/boot/boot_serial/src/zcbor_debug.h b/boot/boot_serial/src/zcbor_debug.h new file mode 100644 index 00000000..f34ad7f2 --- /dev/null +++ b/boot/boot_serial/src/zcbor_debug.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZCBOR_DEBUG_H__ +#define ZCBOR_DEBUG_H__ +#include +#include +#include +#include "zcbor_common.h" + +__attribute__((used)) +static void zcbor_print_compare_lines(const uint8_t *str1, const uint8_t *str2, uint32_t size) +{ + for (uint32_t j = 0; j < size; j++) { + printk ("%x ", str1[j]); + } + printk("\r\n"); + for (uint32_t j = 0; j < size; j++) { + printk ("%x ", str2[j]); + } + printk("\r\n"); + for (uint32_t j = 0; j < size; j++) { + printk ("%x ", str1[j] != str2[j]); + } + printk("\r\n"); + printk("\r\n"); +} + +__attribute__((used)) +static void zcbor_print_compare_strings(const uint8_t *str1, const uint8_t *str2, uint32_t size) +{ + for (uint32_t i = 0; i <= size / 16; i++) { + printk("line %d (char %d)\r\n", i, i*16); + zcbor_print_compare_lines(&str1[i*16], &str2[i*16], + MIN(16, (size - i*16))); + } + printk("\r\n"); +} + +__attribute__((used)) +static void zcbor_print_compare_strings_diff(const uint8_t *str1, const uint8_t *str2, uint32_t size) +{ + bool printed = false; + for (uint32_t i = 0; i <= size / 16; i++) { + if (memcmp(&str1[i*16], &str2[i*16], MIN(16, (size - i*16)) != 0)) { + printk("line %d (char %d)\r\n", i, i*16); + zcbor_print_compare_lines(&str1[i*16], &str2[i*16], + MIN(16, (size - i*16))); + printed = true; + } + } + if (printed) { + printk("\r\n"); + } +} + +#endif /* ZCBOR_DEBUG_H__ */ diff --git a/boot/boot_serial/src/zcbor_decode.c b/boot/boot_serial/src/zcbor_decode.c new file mode 100644 index 00000000..a525c205 --- /dev/null +++ b/boot/boot_serial/src/zcbor_decode.c @@ -0,0 +1,919 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.4.0 + */ + +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "zcbor_decode.h" +#include "zcbor_common.h" + + +/** Return value length from additional value. + */ +static uint_fast32_t additional_len(uint8_t additional) +{ + if (ZCBOR_VALUE_IS_1_BYTE <= additional && additional <= ZCBOR_VALUE_IS_8_BYTES) { + /* 24 => 1 + * 25 => 2 + * 26 => 4 + * 27 => 8 + */ + return 1U << (additional - ZCBOR_VALUE_IS_1_BYTE); + } + return 0; +} + +/** Extract the major type, i.e. the first 3 bits of the header byte. */ +#define MAJOR_TYPE(header_byte) (((header_byte) >> 5) & 0x7) + +/** Extract the additional info, i.e. the last 5 bits of the header byte. */ +#define ADDITIONAL(header_byte) ((header_byte) & 0x1F) + + +#define FAIL_AND_DECR_IF(expr, err) \ +do {\ + if (expr) { \ + (state->payload)--; \ + ZCBOR_ERR(err); \ + } \ +} while(0) + +static bool initial_checks(zcbor_state_t *state) +{ + ZCBOR_CHECK_ERROR(); + ZCBOR_CHECK_PAYLOAD(); + return true; +} + +static bool type_check(zcbor_state_t *state, zcbor_major_type_t exp_major_type) +{ + if (!initial_checks(state)) { + ZCBOR_FAIL(); + } + zcbor_major_type_t major_type = MAJOR_TYPE(*state->payload); + + if (major_type != exp_major_type) { + ZCBOR_ERR(ZCBOR_ERR_WRONG_TYPE); + } + return true; +} + +#define INITIAL_CHECKS() \ +do {\ + if (!initial_checks(state)) { \ + ZCBOR_FAIL(); \ + } \ +} while(0) + +#define INITIAL_CHECKS_WITH_TYPE(exp_major_type) \ +do {\ + if (!type_check(state, exp_major_type)) { \ + ZCBOR_FAIL(); \ + } \ +} while(0) + +#define ERR_RESTORE(err) \ +do { \ + state->payload = state->payload_bak; \ + state->elem_count++; \ + ZCBOR_ERR(err); \ +} while(0) + +#define FAIL_RESTORE() \ +do { \ + state->payload = state->payload_bak; \ + state->elem_count++; \ + ZCBOR_FAIL(); \ +} while(0) + +/** Get a single value. + * + * @details @p ppayload must point to the header byte. This function will + * retrieve the value (either from within the additional info, or from + * the subsequent bytes) and return it in the result. The result can + * have arbitrary length. + * + * The function will also validate + * - Min/max constraints on the value. + * - That @p payload doesn't overrun past @p payload_end. + * - That @p elem_count has not been exhausted. + * + * @p ppayload and @p elem_count are updated if the function + * succeeds. If not, they are left unchanged. + * + * CBOR values are always big-endian, so this function converts from + * big to little-endian if necessary (@ref CONFIG_BIG_ENDIAN). + */ +static bool value_extract(zcbor_state_t *state, + void *const result, uint_fast32_t result_len) +{ + zcbor_trace(); + zcbor_assert(result_len != 0, "0-length result not supported.\r\n"); + zcbor_assert(result != NULL, NULL); + + INITIAL_CHECKS(); + ZCBOR_ERR_IF((state->elem_count == 0), ZCBOR_ERR_LOW_ELEM_COUNT); + + uint8_t *u8_result = (uint8_t *)result; + uint8_t additional = ADDITIONAL(*state->payload); + + state->payload_bak = state->payload; + (state->payload)++; + + memset(result, 0, result_len); + if (additional <= ZCBOR_VALUE_IN_HEADER) { +#ifdef CONFIG_BIG_ENDIAN + u8_result[result_len - 1] = additional; +#else + u8_result[0] = additional; +#endif /* CONFIG_BIG_ENDIAN */ + } else { + uint_fast32_t len = additional_len(additional); + + FAIL_AND_DECR_IF(len > result_len, ZCBOR_ERR_INT_SIZE); + FAIL_AND_DECR_IF(len == 0, ZCBOR_ERR_ADDITIONAL_INVAL); // additional_len() did not recognize the additional value. + FAIL_AND_DECR_IF((state->payload + len) > state->payload_end, + ZCBOR_ERR_NO_PAYLOAD); + +#ifdef CONFIG_BIG_ENDIAN + memcpy(&u8_result[result_len - len], state->payload, len); +#else + for (uint_fast32_t i = 0; i < len; i++) { + u8_result[i] = (state->payload)[len - i - 1]; + } +#endif /* CONFIG_BIG_ENDIAN */ + + (state->payload) += len; + } + + (state->elem_count)--; + return true; +} + + +bool zcbor_int32_decode(zcbor_state_t *state, int32_t *result) +{ + int64_t result64; + + if (zcbor_int64_decode(state, &result64)) { + if (result64 > INT32_MAX) { + ERR_RESTORE(ZCBOR_ERR_INT_SIZE); + } + *result = (int32_t)result64; + return true; + } else { + ZCBOR_FAIL(); + } +} + + +bool zcbor_int64_decode(zcbor_state_t *state, int64_t *result) +{ + INITIAL_CHECKS(); + uint8_t major_type = MAJOR_TYPE(*state->payload); + uint64_t uint_result; + int64_t int_result; + + if (major_type != ZCBOR_MAJOR_TYPE_PINT + && major_type != ZCBOR_MAJOR_TYPE_NINT) { + /* Value to be read doesn't have the right type. */ + ZCBOR_ERR(ZCBOR_ERR_WRONG_TYPE); + } + + if (!value_extract(state, &uint_result, sizeof(uint_result))) { + ZCBOR_FAIL(); + } + + zcbor_print("uintval: %" PRIu64 "\r\n", uint_result); + + int_result = (int64_t)uint_result; + + if (int_result < 0) { + /* Value is too large to fit in a signed integer. */ + ERR_RESTORE(ZCBOR_ERR_INT_SIZE); + } + + if (major_type == ZCBOR_MAJOR_TYPE_NINT) { + /* Convert from CBOR's representation. */ + *result = -1 - int_result; + } else { + *result = int_result; + } + + zcbor_print("val: %" PRIi64 "\r\n", *result); + return true; +} + + +bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result) +{ + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PINT); + + if (!value_extract(state, result, sizeof(*result))) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_uint32_expect_union(zcbor_state_t *state, uint32_t result) +{ + zcbor_union_elem_code(state); + return zcbor_uint32_expect(state, result); +} + + +bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t result) +{ + zcbor_union_elem_code(state); + return zcbor_uint64_expect(state, result); +} + + +bool zcbor_int32_expect(zcbor_state_t *state, int32_t result) +{ + return zcbor_int64_expect(state, result); +} + + +bool zcbor_int64_expect(zcbor_state_t *state, int64_t result) +{ + int64_t value; + + if (!zcbor_int64_decode(state, &value)) { + ZCBOR_FAIL(); + } + + if (value != result) { + zcbor_print("%" PRIi64 " != %" PRIi64 "\r\n", value, result); + ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); + } + return true; +} + + +bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result) +{ + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PINT); + + if (!value_extract(state, result, sizeof(*result))) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t result) +{ + return zcbor_uint64_expect(state, result); +} + + +bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t result) +{ + uint64_t value; + + if (!zcbor_uint64_decode(state, &value)) { + ZCBOR_FAIL(); + } + if (value != result) { + zcbor_print("%" PRIu64 " != %" PRIu64 "\r\n", value, result); + ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); + } + return true; +} + + +static bool str_start_decode(zcbor_state_t *state, + struct zcbor_string *result, zcbor_major_type_t exp_major_type) +{ + INITIAL_CHECKS_WITH_TYPE(exp_major_type); + + if (!value_extract(state, &result->len, sizeof(result->len))) { + ZCBOR_FAIL(); + } + + result->value = state->payload; + return true; +} + + +static bool str_overflow_check(zcbor_state_t *state, struct zcbor_string *result) +{ + if (result->len > (state->payload_end - state->payload)) { + zcbor_print("error: 0x%zu > 0x%zu\r\n", + result->len, + (state->payload_end - state->payload)); + ERR_RESTORE(ZCBOR_ERR_NO_PAYLOAD); + } + return true; +} + + +bool zcbor_bstr_start_decode(zcbor_state_t *state, struct zcbor_string *result) +{ + if (result == NULL) { + struct zcbor_string dummy; + result = &dummy; + } + + if(!str_start_decode(state, result, ZCBOR_MAJOR_TYPE_BSTR)) { + ZCBOR_FAIL(); + } + + if (!str_overflow_check(state, result)) { + ZCBOR_FAIL(); + } + + if (!zcbor_new_backup(state, ZCBOR_MAX_ELEM_COUNT)) { + FAIL_RESTORE(); + } + + state->payload_end = result->value + result->len; + return true; +} + + +bool zcbor_bstr_end_decode(zcbor_state_t *state) +{ + ZCBOR_ERR_IF(state->payload != state->payload_end, ZCBOR_ERR_PAYLOAD_NOT_CONSUMED); + + if (!zcbor_process_backup(state, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, + ZCBOR_MAX_ELEM_COUNT)) { + ZCBOR_FAIL(); + } + + return true; +} + + +static void partition_fragment(const zcbor_state_t *state, + struct zcbor_string_fragment *result) +{ + result->fragment.len = MIN(result->fragment.len, + (size_t)state->payload_end - (size_t)state->payload); +} + + +static bool start_decode_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *result, + zcbor_major_type_t exp_major_type) +{ + if(!str_start_decode(state, &result->fragment, exp_major_type)) { + ZCBOR_FAIL(); + } + + result->offset = 0; + result->total_len = result->fragment.len; + partition_fragment(state, result); + state->payload_end = state->payload + result->fragment.len; + + return true; +} + +bool zcbor_bstr_start_decode_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *result) +{ + if (!start_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_BSTR)) { + ZCBOR_FAIL(); + } + if (!zcbor_new_backup(state, ZCBOR_MAX_ELEM_COUNT)) { + FAIL_RESTORE(); + } + return true; +} + + +void zcbor_next_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *prev_fragment, + struct zcbor_string_fragment *result) +{ + memcpy(result, prev_fragment, sizeof(*result)); + result->fragment.value = state->payload_mut; + result->offset += prev_fragment->fragment.len; + result->fragment.len = result->total_len - result->offset; + + partition_fragment(state, result); + zcbor_print("New fragment length %zu\r\n", result->fragment.len); + + state->payload += result->fragment.len; +} + + +void zcbor_bstr_next_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *prev_fragment, + struct zcbor_string_fragment *result) +{ + memcpy(result, prev_fragment, sizeof(*result)); + result->fragment.value = state->payload_mut; + result->offset += prev_fragment->fragment.len; + result->fragment.len = result->total_len - result->offset; + + partition_fragment(state, result); + zcbor_print("fragment length %zu\r\n", result->fragment.len); + state->payload_end = state->payload + result->fragment.len; +} + + +bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment) +{ + return (fragment->total_len == (fragment->offset + fragment->fragment.len)); +} + + +static bool str_decode(zcbor_state_t *state, struct zcbor_string *result, + zcbor_major_type_t exp_major_type) +{ + if (!str_start_decode(state, result, exp_major_type)) { + ZCBOR_FAIL(); + } + + if (!str_overflow_check(state, result)) { + ZCBOR_FAIL(); + } + + state->payload += result->len; + return true; +} + + +static bool str_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result, + zcbor_major_type_t exp_major_type) +{ + if (!start_decode_fragment(state, result, exp_major_type)) { + ZCBOR_FAIL(); + } + + (state->payload) += result->fragment.len; + return true; +} + + +static bool str_expect(zcbor_state_t *state, struct zcbor_string *result, + zcbor_major_type_t exp_major_type) +{ + struct zcbor_string tmp_result; + + if (!str_decode(state, &tmp_result, exp_major_type)) { + ZCBOR_FAIL(); + } + if ((tmp_result.len != result->len) + || memcmp(result->value, tmp_result.value, tmp_result.len)) { + ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); + } + return true; +} + + +bool zcbor_bstr_decode(zcbor_state_t *state, struct zcbor_string *result) +{ + return str_decode(state, result, ZCBOR_MAJOR_TYPE_BSTR); +} + + +bool zcbor_bstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result) +{ + return str_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_BSTR); +} + + +bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *result) +{ + return str_expect(state, result, ZCBOR_MAJOR_TYPE_BSTR); +} + + +bool zcbor_tstr_decode(zcbor_state_t *state, struct zcbor_string *result) +{ + return str_decode(state, result, ZCBOR_MAJOR_TYPE_TSTR); +} + + +bool zcbor_tstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result) +{ + return str_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_TSTR); +} + + +bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *result) +{ + return str_expect(state, result, ZCBOR_MAJOR_TYPE_TSTR); +} + + +static bool list_map_start_decode(zcbor_state_t *state, + zcbor_major_type_t exp_major_type) +{ + uint_fast32_t new_elem_count; + bool indefinite_length_array = false; + + INITIAL_CHECKS_WITH_TYPE(exp_major_type); + + if (ADDITIONAL(*state->payload) == ZCBOR_VALUE_IS_INDEFINITE_LENGTH) { + /* Indefinite length array. */ + new_elem_count = ZCBOR_LARGE_ELEM_COUNT; + ZCBOR_ERR_IF(state->elem_count == 0, ZCBOR_ERR_LOW_ELEM_COUNT); + indefinite_length_array = true; + state->payload++; + state->elem_count--; + } else { + if (!value_extract(state, &new_elem_count, sizeof(new_elem_count))) { + ZCBOR_FAIL(); + } + } + + if (!zcbor_new_backup(state, new_elem_count)) { + FAIL_RESTORE(); + } + + state->indefinite_length_array = indefinite_length_array; + + return true; +} + + +bool zcbor_list_start_decode(zcbor_state_t *state) +{ + return list_map_start_decode(state, ZCBOR_MAJOR_TYPE_LIST); +} + + +bool zcbor_map_start_decode(zcbor_state_t *state) +{ + bool ret = list_map_start_decode(state, ZCBOR_MAJOR_TYPE_MAP); + + if (ret && !state->indefinite_length_array) { + if (state->elem_count >= (ZCBOR_MAX_ELEM_COUNT / 2)) { + /* The new elem_count is too large. */ + ERR_RESTORE(ZCBOR_ERR_INT_SIZE); + } + state->elem_count *= 2; + } + return ret; +} + + +static bool array_end_expect(zcbor_state_t *state) +{ + INITIAL_CHECKS(); + ZCBOR_ERR_IF(*state->payload != 0xFF, ZCBOR_ERR_WRONG_TYPE); + + state->payload++; + return true; +} + + +static bool list_map_end_decode(zcbor_state_t *state) +{ + uint_fast32_t max_elem_count = 0; + + if (state->indefinite_length_array) { + if (!array_end_expect(state)) { + ZCBOR_FAIL(); + } + max_elem_count = ZCBOR_MAX_ELEM_COUNT; + state->indefinite_length_array = false; + } + if (!zcbor_process_backup(state, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, + max_elem_count)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_list_end_decode(zcbor_state_t *state) +{ + return list_map_end_decode(state); +} + + +bool zcbor_map_end_decode(zcbor_state_t *state) +{ + return list_map_end_decode(state); +} + + +bool zcbor_list_map_end_force_decode(zcbor_state_t *state) +{ + if (!zcbor_process_backup(state, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, + ZCBOR_MAX_ELEM_COUNT)) { + ZCBOR_FAIL(); + } + + return true; +} + + +static bool primx_expect(zcbor_state_t *state, uint8_t result) +{ + uint32_t value; + + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); + + if (!value_extract(state, &value, sizeof(value))) { + ZCBOR_FAIL(); + } + + if (value != result) { + ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); + } + return true; +} + + +bool zcbor_nil_expect(zcbor_state_t *state, void *unused) +{ + if (!primx_expect(state, 22)) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_undefined_expect(zcbor_state_t *state, void *unused) +{ + if (!primx_expect(state, 23)) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_bool_decode(zcbor_state_t *state, bool *result) +{ + if (zcbor_bool_expect(state, false)) { + *result = false; + } else if (zcbor_bool_expect(state, true)) { + *result = true; + } else { + ZCBOR_FAIL(); + } + + zcbor_print("boolval: %u\r\n", *result); + return true; +} + + +bool zcbor_bool_expect(zcbor_state_t *state, bool result) +{ + if (!primx_expect(state, (uint8_t)(!!result) + ZCBOR_BOOL_TO_PRIM)) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_float32_decode(zcbor_state_t *state, float *result) +{ + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); + ZCBOR_ERR_IF(ADDITIONAL(*state->payload) != ZCBOR_VALUE_IS_4_BYTES, ZCBOR_ERR_FLOAT_SIZE); + + if (!value_extract(state, result, sizeof(*result))) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float32_expect(zcbor_state_t *state, float result) +{ + float value; + + if (!zcbor_float32_decode(state, &value)) { + ZCBOR_FAIL(); + } + if (value != result) { + ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); + } + return true; +} + + +bool zcbor_float64_decode(zcbor_state_t *state, double *result) +{ + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); + ZCBOR_ERR_IF(ADDITIONAL(*state->payload) != ZCBOR_VALUE_IS_8_BYTES, ZCBOR_ERR_FLOAT_SIZE); + + if (!value_extract(state, result, sizeof(*result))) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float64_expect(zcbor_state_t *state, double result) +{ + double value; + + if (!zcbor_float64_decode(state, &value)) { + ZCBOR_FAIL(); + } + if (value != result) { + ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); + } + return true; +} + + +bool zcbor_float_decode(zcbor_state_t *state, double *result) +{ + float float_result; + + if (zcbor_float32_decode(state, &float_result)) { + *result = (double)float_result; + } else if (!zcbor_float64_decode(state, result)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float_expect(zcbor_state_t *state, double result) +{ + if (zcbor_float32_expect(state, (float)result)) { + /* Do nothing */ + } else if (!zcbor_float64_expect(state, result)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_any_skip(zcbor_state_t *state, void *result) +{ + zcbor_assert(result == NULL, + "'any' type cannot be returned, only skipped.\r\n"); + + INITIAL_CHECKS(); + uint8_t major_type = MAJOR_TYPE(*state->payload); + uint8_t additional = ADDITIONAL(*state->payload); + uint_fast32_t value; + uint_fast32_t num_decode; + uint_fast32_t temp_elem_count; + uint_fast32_t elem_count_bak = state->elem_count; + uint8_t const *payload_bak = state->payload; + uint64_t tag_dummy; + + payload_bak = state->payload; + + if (!zcbor_multi_decode(0, ZCBOR_LARGE_ELEM_COUNT, &num_decode, + (zcbor_decoder_t *)zcbor_tag_decode, state, + (void *)&tag_dummy, 0)) { + state->elem_count = elem_count_bak; + state->payload = payload_bak; + ZCBOR_FAIL(); + } + + if ((major_type == ZCBOR_MAJOR_TYPE_MAP) || (major_type == ZCBOR_MAJOR_TYPE_LIST)) { + if (additional == ZCBOR_VALUE_IS_INDEFINITE_LENGTH) { + ZCBOR_ERR_IF(state->elem_count == 0, ZCBOR_ERR_LOW_ELEM_COUNT); + state->payload++; + state->elem_count--; + temp_elem_count = state->elem_count; + payload_bak = state->payload; + state->elem_count = ZCBOR_LARGE_ELEM_COUNT; + if (!zcbor_multi_decode(0, ZCBOR_LARGE_ELEM_COUNT, &num_decode, + (zcbor_decoder_t *)zcbor_any_skip, state, + NULL, 0) + || (state->payload >= state->payload_end) + || !(*(state->payload++) == 0xFF)) { + state->elem_count = elem_count_bak; + state->payload = payload_bak; + ZCBOR_FAIL(); + } + state->elem_count = temp_elem_count; + return true; + } + } + + if (!value_extract(state, &value, sizeof(value))) { + /* Can happen because of elem_count (or payload_end) */ + ZCBOR_FAIL(); + } + + switch (major_type) { + case ZCBOR_MAJOR_TYPE_BSTR: + case ZCBOR_MAJOR_TYPE_TSTR: + /* 'value' is the length of the BSTR or TSTR */ + if (value > (state->payload_end - state->payload)) { + ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); + } + (state->payload) += value; + break; + case ZCBOR_MAJOR_TYPE_MAP: + value *= 2; /* Because all members have a key. */ + /* Fallthrough */ + case ZCBOR_MAJOR_TYPE_LIST: + temp_elem_count = state->elem_count; + state->elem_count = value; + if (!zcbor_multi_decode(value, value, &num_decode, + (zcbor_decoder_t *)zcbor_any_skip, state, + NULL, 0)) { + state->elem_count = elem_count_bak; + state->payload = payload_bak; + ZCBOR_FAIL(); + } + state->elem_count = temp_elem_count; + break; + default: + /* Do nothing */ + break; + } + + return true; +} + + +bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result) +{ + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_TAG); + + if (!value_extract(state, result, sizeof(*result))) { + ZCBOR_FAIL(); + } + state->elem_count++; + return true; +} + + +bool zcbor_tag_expect(zcbor_state_t *state, uint32_t result) +{ + uint32_t tag_val; + + if (!zcbor_tag_decode(state, &tag_val)) { + ZCBOR_FAIL(); + } + if (tag_val != result) { + ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); + } + return true; +} + + +bool zcbor_multi_decode(uint_fast32_t min_decode, + uint_fast32_t max_decode, + uint_fast32_t *num_decode, + zcbor_decoder_t decoder, + zcbor_state_t *state, + void *result, + uint_fast32_t result_len) +{ + ZCBOR_CHECK_ERROR(); + for (uint_fast32_t i = 0; i < max_decode; i++) { + uint8_t const *payload_bak = state->payload; + uint_fast32_t elem_count_bak = state->elem_count; + + if (!decoder(state, + (uint8_t *)result + i*result_len)) { + *num_decode = i; + state->payload = payload_bak; + state->elem_count = elem_count_bak; + ZCBOR_ERR_IF(i < min_decode, ZCBOR_ERR_ITERATIONS); + zcbor_print("Found %" PRIuFAST32 " elements.\r\n", i); + return true; + } + } + zcbor_print("Found %" PRIuFAST32 " elements.\r\n", max_decode); + *num_decode = max_decode; + return true; +} + + +bool zcbor_present_decode(uint_fast32_t *present, + zcbor_decoder_t decoder, + zcbor_state_t *state, + void *result) +{ + uint_fast32_t num_decode; + bool retval = zcbor_multi_decode(0, 1, &num_decode, decoder, state, result, 0); + + zcbor_assert(retval, "zcbor_multi_decode should not fail with these parameters.\r\n"); + + *present = num_decode; + return retval; +} + + +bool zcbor_new_decode_state(zcbor_state_t *state_array, uint_fast32_t n_states, + const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count) +{ + return zcbor_new_state(state_array, n_states, payload, payload_len, elem_count); +} diff --git a/boot/boot_serial/src/zcbor_decode.h b/boot/boot_serial/src/zcbor_decode.h new file mode 100644 index 00000000..33a51fe3 --- /dev/null +++ b/boot/boot_serial/src/zcbor_decode.h @@ -0,0 +1,336 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.4.0 + */ + +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZCBOR_DECODE_H__ +#define ZCBOR_DECODE_H__ +#include +#include +#include +#include "zcbor_common.h" + +/** The zcbor_decode library provides functions for decoding CBOR data elements. + * + * See The README for an introduction to CBOR, including the meaning of pint, + * nint, bstr etc. + */ + + +/** The following applies to all single-value decode functions that don't have docs. + * + * @param[inout] state The current state of the decoding. + * @param[out] result Where to place the decoded value. + * + * @retval true If the value was decoded correctly. + * @retval false If the value has the wrong type, the payload overflowed, the + * element count was exhausted, or the value was larger than can + * fit in the result variable. + */ + +/** Decode and consume a pint/nint. */ +bool zcbor_int32_decode(zcbor_state_t *state, int32_t *result); +bool zcbor_int64_decode(zcbor_state_t *state, int64_t *result); +bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result); +bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result); + +/** The following applies to all _expect() functions that don't have docs. + * + * @param[inout] state The current state of the decoding. + * @param[in] result The expected value. + * + * @retval true If the result was decoded correctly and has the expected value. + * @retval false If the decoding failed or the result doesn't have the + * expected value. + */ +/** Consume and expect a pint/nint with a certain value. */ +bool zcbor_int32_expect(zcbor_state_t *state, int32_t result); +bool zcbor_int64_expect(zcbor_state_t *state, int64_t result); +bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t result); +bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t result); + +/** Consume and expect a pint with a certain value, within a union. + * + * Calls @ref zcbor_union_elem_code then @ref zcbor_uint32_expect. + */ +bool zcbor_uint32_expect_union(zcbor_state_t *state, uint32_t result); +bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t result); + +/** Decode and consume a bstr/tstr */ +bool zcbor_bstr_decode(zcbor_state_t *state, struct zcbor_string *result); +bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *result); +bool zcbor_tstr_decode(zcbor_state_t *state, struct zcbor_string *result); +bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *result); + +/** Consume and expect a bstr/tstr with the value of the provided string literal. + * + * @param[inout] state The current state of the encoding. + * @param[in] string The value to expect. A pointer to the string. + * @param[in] len The length of the string pointed to by @p string. + */ +static inline bool zcbor_bstr_expect_ptr(zcbor_state_t *state, uint8_t *ptr, size_t len) +{ + return zcbor_bstr_expect(state, &(struct zcbor_string){.value = ptr, .len = len}); +} +static inline bool zcbor_tstr_expect_ptr(zcbor_state_t *state, uint8_t *ptr, size_t len) +{ + return zcbor_tstr_expect(state, &(struct zcbor_string){.value = ptr, .len = len}); +} + + +/** Consume and expect a bstr/tstr with the value of the provided string literal. + * + * @param[inout] state The current state of the encoding. + * @param[in] string The value to expect. A string literal, e.g. "Foo", so + * that sizeof(string) - 1 is the length of the string. + */ +#define zcbor_bstr_expect_lit(state, string) \ + zcbor_bstr_expect_ptr(state, string, sizeof(string) - 1) +#define zcbor_tstr_expect_lit(state, string) \ + zcbor_tstr_expect_ptr(state, string, sizeof(string) - 1) + +/** Consume and expect a bstr/tstr with the value of the provided null-terminated string. + * + * @param[inout] state The current state of the encoding. + * @param[in] string The value to expect. Must be a null-terminated string, + * so that strlen can be used. + */ +#define zcbor_bstr_expect_term(state, string) \ + zcbor_bstr_expect_ptr(state, string, strlen(string)) +#define zcbor_tstr_expect_term(state, string) \ + zcbor_tstr_expect_ptr(state, string, strlen(string)) + +/** Consume and expect a bstr/tstr with the value of the provided char array literal. + * + * @param[inout] state The current state of the encoding. + * @param[in] string The value to expect. An array literal, e.g. {'F', 'o', 'o'}, + * so that sizeof(string) is the length of the string. + */ +#define zcbor_bstr_expect_arr(state, string) \ + zcbor_bstr_expect_ptr(state, string, (sizeof(string))) +#define zcbor_tstr_expect_arr(state, string) \ + zcbor_tstr_expect_ptr(state, string, (sizeof(string))) + +/** Decode and consume a tag. */ +bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result); +bool zcbor_tag_expect(zcbor_state_t *state, uint32_t result); + +/** Decode and consume a boolean primitive value. */ +bool zcbor_bool_decode(zcbor_state_t *state, bool *result); +bool zcbor_bool_expect(zcbor_state_t *state, bool result); + +/** Decode and consume a float */ +bool zcbor_float32_decode(zcbor_state_t *state, float *result); +bool zcbor_float32_expect(zcbor_state_t *state, float result); +bool zcbor_float64_decode(zcbor_state_t *state, double *result); +bool zcbor_float64_expect(zcbor_state_t *state, double result); +bool zcbor_float_decode(zcbor_state_t *state, double *result); +bool zcbor_float_expect(zcbor_state_t *state, double result); + +/** Consume and expect a "nil"/"undefined" primitive value. + * + * @param[inout] state The current state of the encoding. + * @param[in] unused Unused parameter to maintain signature parity with + * @ref zcbor_decoder_t. + */ +bool zcbor_nil_expect(zcbor_state_t *state, void *unused); +bool zcbor_undefined_expect(zcbor_state_t *state, void *unused); + +/** Skip a single element, regardless of type and value. + * + * @param[inout] state The current state of the encoding. + * @param[in] unused Unused parameter to maintain signature parity with + * @ref zcbor_decoder_t. + */ +bool zcbor_any_skip(zcbor_state_t *state, void *unused); + +/** Decode and consume a bstr header. + * + * The rest of the string can be decoded as CBOR. + * A state backup is created to keep track of the element count. + * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. + * + * @retval true Header decoded correctly + * @retval false Header decoded incorrectly, or backup failed. + */ +bool zcbor_bstr_start_decode(zcbor_state_t *state, struct zcbor_string *result); + +/** Finalize decoding a CBOR-encoded bstr. + * + * Restore element count from backup. + */ +bool zcbor_bstr_end_decode(zcbor_state_t *state); + +/** Start decoding a bstr/tstr, even if the payload contains only part of it. + * + * This must be followed by a call to @ref zcbor_update_state, which can be + * followed by a call to @ref zcbor_next_fragment. Do not call this function + * again on subsequent fragments of the same string. + * + * This consumes the remaining payload as long as it belongs to the string. + */ +bool zcbor_bstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); +bool zcbor_tstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); + +/** Extract the next fragment of a string. + * + * Use this function to extract all but the first fragment. + */ +void zcbor_next_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *prev_fragment, + struct zcbor_string_fragment *result); + +/** Decode and consume a bstr header, assuming the payload does not contain the whole bstr. + * + * The rest of the string can be decoded as CBOR. + * A state backup is created to keep track of the element count. + * Call @ref zcbor_update_state followed by @ref zcbor_bstr_next_fragment when + * the current payload has been exhausted. + * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. + */ +bool zcbor_bstr_start_decode_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *result); + +/** Start decoding the next fragment of a string. + * + * Use this function to extract all but the first fragment of a CBOR-encoded + * bstr. + */ +void zcbor_bstr_next_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *prev_fragment, + struct zcbor_string_fragment *result); + +/** Can be used on any fragment to tell if it is the final fragment of the string. */ +bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment); + +/** Decode and consume a list/map header. + * + * The contents of the list can be decoded via subsequent function calls. + * A state backup is created to keep track of the element count. + * Call @ref zcbor_list_end_decode / @ref zcbor_map_end_decode when done + * decoding the contents of the list/map + * + * @retval true Header decoded correctly + * @retval false Header decoded incorrectly, or backup failed. + */ +bool zcbor_list_start_decode(zcbor_state_t *state); +bool zcbor_map_start_decode(zcbor_state_t *state); + +/** Finalize decoding a list/map + * + * Check that the list/map had the correct number of elements, and restore the + * previous element count from the backup. + * + * Use @ref zcbor_list_map_end_force_decode to forcibly consume the backup if + * something has gone wrong. + * + * @retval true Everything ok. + * @retval false Element count not correct. + */ +bool zcbor_list_end_decode(zcbor_state_t *state); +bool zcbor_map_end_decode(zcbor_state_t *state); +bool zcbor_list_map_end_force_decode(zcbor_state_t *state); + +/** Decode 0 or more elements with the same type and constraints. + * + * The decoded values will appear consecutively in the @p result array. + * + * The following is an example of decoding a list containing 3 INTS followed by + * 0 to 2 bstrs: + * + * @code{c} + * uint32_t ints[3]; + * struct zcbor_string bstrs[2]; + * uint32_t num_decode; + * bool res; + * + * res = zcbor_list_start_decode(state); + * res = res && zcbor_multi_decode(3, 3, &num_decode, zcbor_uint32_decode, + * state, ints, sizeof(ints[0])); + * res = res && zcbor_multi_decode(0, 2, &num_decode, zcbor_bstr_decode, + * state, bstrs, sizeof(bstrs[0])); + * res = res && zcbor_list_end_decode(state); + * // check res + * @endcode + * + * The @ref zcbor_decoder_t type is designed to be compatible with all single- + * value decoder functions in this library, e.g. @ref zcbor_uint32_decode, + * @ref zcbor_tstr_expect, @ref zcbor_nil_expect, etc. For _expect() functions, + * @p result will be used as a value instead of an array/pointer, so + * @p result_len will determine how much the value changes for each call. + * To decode the same value multiple times, use a @p result_len of 0. + * This function can also be used with custom decoder functions, such as those + * generated by the zcbor.py script, which for example decodes larger chunks of + * the data at once. + * + * @param[in] min_decode The minimum acceptable number of elements. + * @param[in] max_decode The maximum acceptable number of elements. + * @param[out] num_decode The actual number of elements decoded. + * @param[in] decoder The decoder function to call under the hood. This + * function will be called with the provided arguments + * repeatedly until the function fails (returns false) + * or until it has been called @p max_decode times. + * The result pointer is moved @p result_len bytes for + * each call to @p decoder, i.e. @p result refers to + * an array of result variables. + * @param[out] result Where to place the decoded values. Must be an array + * of at least @p max_decode elements. + * @param[in] result_len The length of each result variable. Must be the + * length of the individual elements of @p result. + * + * @retval true If at least @p min_decode variables were correctly decoded. + * @retval false If @p decoder failed before having decoded @p min_decode + * values. + */ +bool zcbor_multi_decode(uint_fast32_t min_decode, uint_fast32_t max_decode, uint_fast32_t *num_decode, + zcbor_decoder_t decoder, zcbor_state_t *state, void *result, + uint_fast32_t result_len); + +/** Attempt to decode a value that might not be present in the data. + * + * Works like @ref zcbor_multi_decode, with @p present as num_decode. + * Will return true, even if the data is not present. + * + * @param[out] present Whether or not the data was present and successfully decoded. + * @param[in] decoder The decoder to attempt. + * @param[out] result The result, if present. + * + * @return Should always return true. + */ +bool zcbor_present_decode(uint_fast32_t *present, + zcbor_decoder_t decoder, + zcbor_state_t *state, + void *result); + +/** See @ref zcbor_new_state() */ +bool zcbor_new_decode_state(zcbor_state_t *state_array, uint_fast32_t n_states, + const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count); + +/** Convenience macro for declaring and initializing a state with backups. + * + * This gives you a state variable named @p name. The variable functions like + * a pointer. + * + * The return value from @ref zcbor_new_encode_state can be safely ignored + * because the only error condition is n_states < 2, and this macro adds 2 to + * num_backups to get n_states, so it can never be < 2. + * + * @param[in] name The name of the new state variable. + * @param[in] num_backups The number of backup slots to keep in the state. + * @param[in] payload The payload to work on. + * @param[in] payload_size The size (in bytes) of @p payload. + * @param[in] elem_count The starting elem_count (typically 1). + */ +#define ZCBOR_STATE_D(name, num_backups, payload, payload_size, elem_count) \ +zcbor_state_t name[((num_backups) + 2)]; \ +do { \ + (void)zcbor_new_decode_state(name, ARRAY_SIZE(name), payload, payload_size, elem_count); \ +} while(0) + +#endif /* ZCBOR_DECODE_H__ */ diff --git a/boot/boot_serial/src/zcbor_encode.c b/boot/boot_serial/src/zcbor_encode.c new file mode 100644 index 00000000..2a4d5e38 --- /dev/null +++ b/boot/boot_serial/src/zcbor_encode.c @@ -0,0 +1,587 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.4.0 + */ + +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "zcbor_encode.h" +#include "zcbor_common.h" + +_Static_assert((sizeof(size_t) == sizeof(void *)), + "This code needs size_t to be the same length as pointers."); + + +static uint8_t log2ceil(uint_fast32_t val) +{ + switch(val) { + case 1: return 0; + case 2: return 1; + case 3: return 2; + case 4: return 2; + case 5: return 3; + case 6: return 3; + case 7: return 3; + case 8: return 3; + } + + zcbor_print("Should not come here.\r\n"); + return 0; +} + +static uint8_t get_additional(uint_fast32_t len, uint8_t value0) +{ + return len == 0 ? value0 : (uint8_t)(24 + log2ceil(len)); +} + +static bool encode_header_byte(zcbor_state_t *state, + zcbor_major_type_t major_type, uint8_t additional) +{ + ZCBOR_CHECK_ERROR(); + ZCBOR_CHECK_PAYLOAD(); + + zcbor_assert(additional < 32, NULL); + + *(state->payload_mut++) = (uint8_t)((major_type << 5) | (additional & 0x1F)); + return true; +} + + +static uint_fast32_t get_encoded_len(const void *const result, uint_fast32_t result_len); + + +/** Encode a single value. + */ +static bool value_encode_len(zcbor_state_t *state, zcbor_major_type_t major_type, + const void *const result, uint_fast32_t result_len) +{ + uint8_t *u8_result = (uint8_t *)result; + uint_fast32_t encoded_len = get_encoded_len(result, result_len); + + if ((state->payload + 1 + encoded_len) > state->payload_end) { + ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); + } + + if (!encode_header_byte(state, major_type, + get_additional(encoded_len, u8_result[0]))) { + ZCBOR_FAIL(); + } + state->payload_mut--; + zcbor_trace(); + state->payload_mut++; + +#ifdef CONFIG_BIG_ENDIAN + memcpy(state->payload_mut, u8_result, encoded_len); + state->payload_mut += encoded_len; +#else + for (; encoded_len > 0; encoded_len--) { + *(state->payload_mut++) = u8_result[encoded_len - 1]; + } +#endif /* CONFIG_BIG_ENDIAN */ + + state->elem_count++; + return true; +} + + +static uint_fast32_t get_result_len(const void *const input, uint_fast32_t max_result_len) +{ + uint8_t *u8_result = (uint8_t *)input; + uint_fast32_t len = max_result_len; + + for (; len > 0; len--) { +#ifdef CONFIG_BIG_ENDIAN + if (u8_result[max_result_len - len] != 0) { +#else + if (u8_result[len - 1] != 0) { +#endif /* CONFIG_BIG_ENDIAN */ + break; + } + } + + /* Round up to nearest power of 2. */ + return len <= 2 ? len : (uint8_t)(1 << log2ceil(len)); +} + + +static const void *get_result(const void *const input, uint_fast32_t max_result_len, + uint_fast32_t result_len) +{ +#ifdef CONFIG_BIG_ENDIAN + return &((uint8_t *)input)[max_result_len - result_len]; +#else + return input; +#endif +} + + +static uint_fast32_t get_encoded_len(const void *const result, uint_fast32_t result_len) +{ + const uint8_t *u8_result = (const uint8_t *)result; + + if ((result_len == 1) && (u8_result[0] <= ZCBOR_VALUE_IN_HEADER)) { + return 0; + } + return result_len; +} + + +static bool value_encode(zcbor_state_t *state, zcbor_major_type_t major_type, + const void *const input, uint_fast32_t max_result_len) +{ + zcbor_assert(max_result_len != 0, "0-length result not supported.\r\n"); + + uint_fast32_t result_len = get_result_len(input, max_result_len); + const void *const result = get_result(input, max_result_len, result_len); + + return value_encode_len(state, major_type, result, result_len); +} + + +bool zcbor_int32_put(zcbor_state_t *state, int32_t input) +{ + return zcbor_int64_put(state, input); +} + + +bool zcbor_int64_put(zcbor_state_t *state, int64_t input) +{ + zcbor_major_type_t major_type; + + if (input < 0) { + major_type = ZCBOR_MAJOR_TYPE_NINT; + /* Convert from CBOR's representation. */ + input = -1 - input; + } else { + major_type = ZCBOR_MAJOR_TYPE_PINT; + input = input; + } + + if (!value_encode(state, major_type, &input, 8)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input) +{ + return zcbor_int32_put(state, *input); +} + + +static bool uint32_encode(zcbor_state_t *state, const uint32_t *input, + zcbor_major_type_t major_type) +{ + if (!value_encode(state, major_type, input, 4)) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_uint32_encode(zcbor_state_t *state, const uint32_t *input) +{ + if (!uint32_encode(state, input, ZCBOR_MAJOR_TYPE_PINT)) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input) +{ + return zcbor_int64_put(state, *input); +} + + +static bool uint64_encode(zcbor_state_t *state, const uint64_t *input, + zcbor_major_type_t major_type) +{ + if (!value_encode(state, major_type, input, 8)) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_uint64_encode(zcbor_state_t *state, const uint64_t *input) +{ + if (!uint64_encode(state, input, ZCBOR_MAJOR_TYPE_PINT)) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_uint32_put(zcbor_state_t *state, uint32_t input) +{ + return zcbor_uint64_put(state, input); +} + + +bool zcbor_uint64_put(zcbor_state_t *state, uint64_t input) +{ + if (!uint64_encode(state, &input, ZCBOR_MAJOR_TYPE_PINT)) { + ZCBOR_FAIL(); + } + return true; +} + + +static bool str_start_encode(zcbor_state_t *state, + const struct zcbor_string *input, zcbor_major_type_t major_type) +{ + if (input->value && ((get_result_len(&input->len, sizeof(input->len)) + + 1 + input->len + (size_t)state->payload) + > (size_t)state->payload_end)) { + ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); + } + if (!value_encode(state, major_type, &input->len, sizeof(input->len))) { + ZCBOR_FAIL(); + } + + return true; +} + + +static bool primitive_put(zcbor_state_t *state, uint32_t input) +{ + if (!uint32_encode(state, &input, ZCBOR_MAJOR_TYPE_PRIM)) { + ZCBOR_FAIL(); + } + return true; +} + + +static size_t remaining_str_len(zcbor_state_t *state) +{ + size_t max_len = (size_t)state->payload_end - (size_t)state->payload; + size_t result_len = get_result_len(&max_len, sizeof(max_len)); + + return max_len - result_len - 1; +} + + +bool zcbor_bstr_start_encode(zcbor_state_t *state) +{ + if (!zcbor_new_backup(state, 0)) { + ZCBOR_FAIL(); + } + + uint64_t max_len = remaining_str_len(state); + + /* Encode a dummy header */ + if (!uint64_encode(state, &max_len, + ZCBOR_MAJOR_TYPE_BSTR)) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result) +{ + const uint8_t *payload = state->payload; + struct zcbor_string dummy_value; + + if (result == NULL) { + /* Use a dummy value for the sake of the length calculation below. + * Will not be returned. + */ + result = &dummy_value; + } + + if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME, 0xFFFFFFFF)) { + ZCBOR_FAIL(); + } + + result->value = state->payload_end - remaining_str_len(state); + result->len = (size_t)payload - (size_t)result->value; + + /* Reencode header of list now that we know the number of elements. */ + if (!zcbor_bstr_encode(state, result)) { + ZCBOR_FAIL(); + } + return true; +} + + +static bool str_encode(zcbor_state_t *state, + const struct zcbor_string *input, zcbor_major_type_t major_type) +{ + if (input->len > (state->payload_end - state->payload)) { + ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); + } + if (!str_start_encode(state, input, major_type)) { + ZCBOR_FAIL(); + } + if (state->payload_mut != input->value) { + /* Use memmove since string might be encoded into the same space + * because of bstrx_cbor_start_encode/bstrx_cbor_end_encode. */ + memmove(state->payload_mut, input->value, input->len); + } + state->payload += input->len; + return true; +} + + +bool zcbor_bstr_encode(zcbor_state_t *state, const struct zcbor_string *input) +{ + return str_encode(state, input, ZCBOR_MAJOR_TYPE_BSTR); +} + + +bool zcbor_tstr_encode(zcbor_state_t *state, const struct zcbor_string *input) +{ + return str_encode(state, input, ZCBOR_MAJOR_TYPE_TSTR); +} + + +static bool list_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num, + zcbor_major_type_t major_type) +{ +#ifdef ZCBOR_CANONICAL + if (!zcbor_new_backup(state, 0)) { + ZCBOR_FAIL(); + } + + /* Encode dummy header with max number of elements. */ + if (!value_encode(state, major_type, &max_num, sizeof(max_num))) { + ZCBOR_FAIL(); + } + state->elem_count--; /* Because of dummy header. */ +#else + if (!encode_header_byte(state, major_type, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) { + ZCBOR_FAIL(); + } +#endif + return true; +} + + +bool zcbor_list_start_encode(zcbor_state_t *state, uint_fast32_t max_num) +{ + return list_map_start_encode(state, max_num, ZCBOR_MAJOR_TYPE_LIST); +} + + +bool zcbor_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num) +{ + return list_map_start_encode(state, max_num, ZCBOR_MAJOR_TYPE_MAP); +} + + +#ifdef ZCBOR_CANONICAL +static uint_fast32_t get_encoded_len2(const void *const input, uint_fast32_t max_result_len) +{ + uint_fast32_t result_len = get_result_len(input, max_result_len); + const void *const result = get_result(input, max_result_len, result_len); + + return get_encoded_len(result, result_len); +} +#endif + + +static bool list_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num, + zcbor_major_type_t major_type) +{ +#ifdef ZCBOR_CANONICAL + uint_fast32_t list_count = ((major_type == ZCBOR_MAJOR_TYPE_LIST) ? + state->elem_count + : (state->elem_count / 2)); + + const uint8_t *payload = state->payload; + + uint_fast32_t max_header_len = get_encoded_len2(&max_num, 4); + uint_fast32_t header_len = get_encoded_len2(&list_count, 4); + + if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME, 0xFFFFFFFF)) { + ZCBOR_FAIL(); + } + + zcbor_print("list_count: %" PRIuFAST32 "\r\n", list_count); + + /* Reencode header of list now that we know the number of elements. */ + if (!(value_encode(state, major_type, &list_count, sizeof(list_count)))) { + ZCBOR_FAIL(); + } + + if (max_header_len != header_len) { + const uint8_t *start = state->payload + max_header_len - header_len; + size_t body_size = (size_t)payload - (size_t)start; + memmove(state->payload_mut, + state->payload + max_header_len - header_len, + body_size); + /* Reset payload pointer to end of list */ + state->payload += body_size; + } else { + /* Reset payload pointer to end of list */ + state->payload = payload; + } +#else + if (!encode_header_byte(state, ZCBOR_MAJOR_TYPE_PRIM, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) { + ZCBOR_FAIL(); + } +#endif + return true; +} + + +bool zcbor_list_end_encode(zcbor_state_t *state, uint_fast32_t max_num) +{ + return list_map_end_encode(state, max_num, ZCBOR_MAJOR_TYPE_LIST); +} + + +bool zcbor_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num) +{ + return list_map_end_encode(state, max_num, ZCBOR_MAJOR_TYPE_MAP); +} + + +bool zcbor_list_map_end_force_encode(zcbor_state_t *state) +{ +#ifdef ZCBOR_CANONICAL + if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME, + ZCBOR_MAX_ELEM_COUNT)) { + ZCBOR_FAIL(); + } +#endif + return true; +} + + +bool zcbor_nil_put(zcbor_state_t *state, const void *unused) +{ + (void)unused; + return primitive_put(state, 22); +} + + +bool zcbor_undefined_put(zcbor_state_t *state, const void *unused) +{ + (void)unused; + return primitive_put(state, 23); +} + + +bool zcbor_bool_encode(zcbor_state_t *state, const bool *input) +{ + if (!primitive_put(state, (uint32_t)(*input + ZCBOR_BOOL_TO_PRIM))) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_bool_put(zcbor_state_t *state, bool input) +{ + if (!primitive_put(state, (uint32_t)(input + ZCBOR_BOOL_TO_PRIM))) { + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_float64_encode(zcbor_state_t *state, const double *input) +{ + if (!value_encode(state, ZCBOR_MAJOR_TYPE_PRIM, input, + sizeof(*input))) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float64_put(zcbor_state_t *state, double input) +{ + return zcbor_float64_encode(state, &input); +} + + +bool zcbor_float32_encode(zcbor_state_t *state, const float *input) +{ + if (!value_encode(state, ZCBOR_MAJOR_TYPE_PRIM, input, + sizeof(*input))) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float32_put(zcbor_state_t *state, float input) +{ + return zcbor_float32_encode(state, &input); +} + + +bool zcbor_tag_encode(zcbor_state_t *state, uint32_t tag) +{ + if (!value_encode(state, ZCBOR_MAJOR_TYPE_TAG, &tag, sizeof(tag))) { + ZCBOR_FAIL(); + } + state->elem_count--; + + return true; +} + + +bool zcbor_multi_encode_minmax(uint_fast32_t min_encode, + uint_fast32_t max_encode, + const uint_fast32_t *num_encode, + zcbor_encoder_t encoder, + zcbor_state_t *state, + const void *input, + uint_fast32_t result_len) +{ + + if ((*num_encode >= min_encode) && (*num_encode <= max_encode)) { + return zcbor_multi_encode(*num_encode, encoder, state, input, result_len); + } else { + ZCBOR_ERR(ZCBOR_ERR_ITERATIONS); + } +} + +bool zcbor_multi_encode(uint_fast32_t num_encode, + zcbor_encoder_t encoder, + zcbor_state_t *state, + const void *input, + uint_fast32_t result_len) +{ + ZCBOR_CHECK_ERROR(); + for (uint_fast32_t i = 0; i < num_encode; i++) { + if (!encoder(state, (const uint8_t *)input + i*result_len)) { + ZCBOR_FAIL(); + } + } + zcbor_print("Encoded %" PRIuFAST32 " elements.\n", num_encode); + return true; +} + + +bool zcbor_present_encode(const uint_fast32_t *present, + zcbor_encoder_t encoder, + zcbor_state_t *state, + const void *input) +{ + return zcbor_multi_encode(!!*present, encoder, state, input, 0); +} + + +bool zcbor_new_encode_state(zcbor_state_t *state_array, uint_fast32_t n_states, + uint8_t *payload, size_t payload_len, uint_fast32_t elem_count) +{ + return zcbor_new_state(state_array, n_states, payload, payload_len, elem_count); +} diff --git a/boot/boot_serial/src/zcbor_encode.h b/boot/boot_serial/src/zcbor_encode.h new file mode 100644 index 00000000..e1290217 --- /dev/null +++ b/boot/boot_serial/src/zcbor_encode.h @@ -0,0 +1,280 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.4.0 + */ + +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZCBOR_ENCODE_H__ +#define ZCBOR_ENCODE_H__ +#include +#include +#include +#include "zcbor_common.h" + +/** The zcbor_encode library provides functions for encoding CBOR data elements. + * + * See The README for an introduction to CBOR, including the meaning of pint, + * nint, bstr etc. + */ + + +/** The following param and retval docs apply to all single value encoding functions + * + * @param[inout] state The current state of the encoding. + * @param[in] input The value to encode. + * + * @retval true Everything is ok. + * @retval false If the payload is exhausted. Or an unexpected error happened. + */ + +/** Encode a pint/nint. */ +bool zcbor_int32_put(zcbor_state_t *state, int32_t input); +bool zcbor_int64_put(zcbor_state_t *state, int64_t input); +bool zcbor_uint32_put(zcbor_state_t *state, uint32_t result); +bool zcbor_uint64_put(zcbor_state_t *state, uint64_t input); + +/** Encode a pint/nint from a pointer. + * + * Can be used for bulk encoding with @ref zcbor_multi_encode. + */ +bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input); +bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input); +bool zcbor_uint32_encode(zcbor_state_t *state, const uint32_t *result); +bool zcbor_uint64_encode(zcbor_state_t *state, const uint64_t *input); + +/** Encode a bstr. */ +bool zcbor_bstr_encode(zcbor_state_t *state, const struct zcbor_string *input); +/** Encode a tstr. */ +bool zcbor_tstr_encode(zcbor_state_t *state, const struct zcbor_string *input); + +/** Encode a pointer to a string as a bstr/tstr. + * + * @param[inout] state The current state of the encoding. + * @param[in] string The value to encode. A pointer to the string + * @param[in] len The length of the string pointed to by @p string. + */ +static inline bool zcbor_bstr_encode_ptr(zcbor_state_t *state, uint8_t *ptr, size_t len) +{ + return zcbor_bstr_encode(state, &(struct zcbor_string){.value = ptr, .len = len}); +} +static inline bool zcbor_tstr_encode_ptr(zcbor_state_t *state, uint8_t *ptr, size_t len) +{ + return zcbor_tstr_encode(state, &(struct zcbor_string){.value = ptr, .len = len}); +} + +/** Encode a string literal as a bstr/tstr. + * + * @param[inout] state The current state of the encoding. + * @param[in] string The value to encode. A string literal, e.g. "Foo", so + * that sizeof(string) - 1 is the length of the string. + */ +#define zcbor_bstr_put_lit(state, string) \ + zcbor_bstr_encode_ptr(state, string, sizeof(string) - 1) +#define zcbor_tstr_put_lit(state, string) \ + zcbor_tstr_encode_ptr(state, string, sizeof(string) - 1) + +/** Encode null-terminated string as a bstr/tstr. + * + * @param[inout] state The current state of the encoding. + * @param[in] string The value to encode. Must be a null-terminated string, + * so that strlen can be used. + */ +#define zcbor_bstr_put_term(state, string) \ + zcbor_bstr_encode_ptr(state, string, strlen(string)) +#define zcbor_tstr_put_term(state, string) \ + zcbor_tstr_encode_ptr(state, string, strlen(string)) + +/** Encode a char array literal as a bstr/tstr. + * + * @param[inout] state The current state of the encoding. + * @param[in] string The value to encode. An array literal, e.g. {'F', 'o', 'o'}, + * so that sizeof(string) is the length of the string. + */ +#define zcbor_bstr_put_arr(state, string) \ + zcbor_bstr_encode_ptr(state, string, sizeof(string)) +#define zcbor_tstr_put_arr(state, string) \ + zcbor_tstr_encode_ptr(state, string, sizeof(string)) + +/** Encode a tag. Must be called before encoding the value being tagged. */ +bool zcbor_tag_encode(zcbor_state_t *state, uint32_t input); + +/** Encode a boolean primitive value. */ +bool zcbor_bool_put(zcbor_state_t *state, bool input); +bool zcbor_bool_encode(zcbor_state_t *state, const bool *input); + +/** Encode a float */ +bool zcbor_float32_put(zcbor_state_t *state, float input); +bool zcbor_float32_encode(zcbor_state_t *state, const float *input); +bool zcbor_float64_put(zcbor_state_t *state, double input); +bool zcbor_float64_encode(zcbor_state_t *state, const double *input); + +/** Encode a "nil"/"undefined" primitive value. @p unused should be NULL. + * + * @param[inout] state The current state of the encoding. + * @param[in] unused Unused parameter to maintain signature parity with + * @ref zcbor_encoder_t. + */ +bool zcbor_nil_put(zcbor_state_t *state, const void *unused); +bool zcbor_undefined_put(zcbor_state_t *state, const void *unused); + +/** Encode a bstr header. + * + * The rest of the string can be encoded as CBOR. + * A state backup is created to keep track of the element count. + * Call @ref zcbor_bstr_end_encode when done encoding the contents of the bstr. + * + * @param[inout] state The current state of the encoding. + * + * @retval true Header encoded correctly + * @retval false Header encoded incorrectly, or backup failed. + */ +bool zcbor_bstr_start_encode(zcbor_state_t *state); + +/** Finalize encoding a CBOR-encoded bstr. + * + * Restore element count from backup. + */ +bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result); + +/** Encode a list/map header. + * + * The contents of the list/map can be encoded via subsequent function calls. + * If ZCBOR_CANONICAL is defined, a state backup is created to keep track of the + * element count. + * When all members have been encoded, call @ref zcbor_list_end_encode / + * @ref zcbor_map_end_encode to close the list/map. + * + * @param[inout] state The current state of the encoding. + * @param[in] max_num The maximum number of members in the list/map. + * This serves as a size hint for the header. Must be + * equal to the max_num provided to the corresponding + * @ref zcbor_list_end_encode / @ref zcbor_map_end_encode + * call. + * Only used when ZCBOR_CANONICAL is defined. + */ +bool zcbor_list_start_encode(zcbor_state_t *state, uint_fast32_t max_num); +bool zcbor_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num); + +/** Encode the end of a list/map. Do some checks and deallocate backup. + * + * - Default: Adds a list terminator (0xFF) to mark the + * end of the list/map. + * - If ZCBOR_CANONICAL is defined: Instead encodes the number of members in + * the list/map header. If the header ends up a different size than expected, + * the list/map contents are moved using memmove(). + * + * Use @ref zcbor_list_map_end_force_encode to forcibly consume the backup if + * something has gone wrong. + * + * @param[inout] state The current state of the encoding. + * @param[in] max_num The maximum number of members in the list/map. Must be + * equal to the max_num provided to the corresponding + * @ref zcbor_list_start_encode call. + * Only used when ZCBOR_CANONICAL is defined. + */ +bool zcbor_list_end_encode(zcbor_state_t *state, uint_fast32_t max_num); +bool zcbor_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num); +bool zcbor_list_map_end_force_encode(zcbor_state_t *state); + +/** Encode 0 or more elements with the same type and constraints. + * + * The encoded values are taken from the @p input array. + * + * The following is an example of encoding a list containing 3 INTS followed by + * 0 to 2 bstrs: + * + * @code{c} + * uint32_t ints[3] = ; + * struct zcbor_string bstrs[2] = ; + * bool res; + * + * res = zcbor_list_start_encode(state, 5); + * res = res && zcbor_multi_encode(3, zcbor_uint32_encode, state, + * ints, sizeof(uint32_t)); + * res = res && zcbor_multi_encode(2, zcbor_bstr_encode, state, + * bstrs, sizeof(struct zcbor_string)); + * res = res && zcbor_list_end_encode(state, 5); + * // check res + * @endcode + * + * The @ref zcbor_encoder_t type is designed to be compatible with all single- + * value encoder functions in this library, e.g. @ref zcbor_uint32_encode, + * @ref zcbor_tstr_put, @ref zcbor_nil_put, etc. For _put() functions, + * @p input will be used as a value instead of an array/pointer, so + * @p input_len will determine how much the value changes for each call. + * To encode the same value multiple times, use a @p input_len of 0. + * This function can also be used with custom decoder functions, such as those + * generated by the zcbor.py script, which for example encodes larger chunks of + * the data at once. + * + * @param[in] num_encode The actual number of elements. + * @param[in] encoder The encoder function to call under the hood. This + * function will be called with the provided arguments + * repeatedly until the function fails (returns false) + * or until it has been called @p max_encode times. + * The input pointer is moved @p input_len bytes for + * each call to @p encoder, i.e. @p input refers to an + * array of input variables. + * @param[in] input Source of the encoded values. Must be an array of + * at least @p max_encode elements. + * @param[in] input_len The length of the input variables. Must be the + * length of the individual elements in input. + * + * @retval true If at least @p min_encode variables were correctly encoded. + * @retval false If @p encoder failed before having encoded @p min_encode + * values. + */ +bool zcbor_multi_encode(uint_fast32_t num_encode, + zcbor_encoder_t encoder, + zcbor_state_t *state, + const void *input, + uint_fast32_t result_len); + +/** Works like @ref zcbor_multi_encode + * + * But first checks that @p num_encode is between @p min_encode and @p max_encode. + */ +bool zcbor_multi_encode_minmax(uint_fast32_t min_encode, uint_fast32_t max_encode, const uint_fast32_t *num_encode, + zcbor_encoder_t encoder, zcbor_state_t *state, const void *input, + uint_fast32_t input_len); + +/** Runs @p encoder on @p state and @p input if @p present is true. + * + * Calls @ref zcbor_multi_encode under the hood. + */ +bool zcbor_present_encode(const uint_fast32_t *present, + zcbor_encoder_t encoder, + zcbor_state_t *state, + const void *input); + +/** See @ref zcbor_new_state() */ +bool zcbor_new_encode_state(zcbor_state_t *state_array, uint_fast32_t n_states, + uint8_t *payload, size_t payload_len, uint_fast32_t elem_count); + +/** Convenience macro for declaring and initializing a state with backups. + * + * This gives you a state variable named @p name. The variable functions like + * a pointer. + * + * The return value from @ref zcbor_new_encode_state can be safely ignored + * because the only error condition is n_states < 2, and this macro adds 2 to + * num_backups to get n_states, so it can never be < 2. + * + * @param[in] name The name of the new state variable. + * @param[in] num_backups The number of backup slots to keep in the state. + * @param[in] payload The payload to work on. + * @param[in] payload_size The size (in bytes) of @p payload. + * @param[in] elem_count The starting elem_count (typically 1). + */ +#define ZCBOR_STATE_E(name, num_backups, payload, payload_size, elem_count) \ +zcbor_state_t name[((num_backups) + 2)]; \ +do { \ + (void)zcbor_new_encode_state(name, ARRAY_SIZE(name), payload, payload_size, elem_count); \ +} while(0) + +#endif /* ZCBOR_ENCODE_H__ */ diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 026ce2b3..db9067a9 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -252,9 +252,9 @@ if(CONFIG_MCUBOOT_SERIAL) zephyr_sources(${BOOT_DIR}/zephyr/serial_adapter.c) zephyr_sources(${BOOT_DIR}/boot_serial/src/boot_serial.c) zephyr_sources(${BOOT_DIR}/boot_serial/src/serial_recovery_cbor.c) - zephyr_sources(${BOOT_DIR}/boot_serial/src/cbor_decode.c) - zephyr_sources(${BOOT_DIR}/boot_serial/src/cbor_encode.c) - zephyr_sources(${BOOT_DIR}/boot_serial/src/cbor_common.c) + zephyr_sources(${BOOT_DIR}/boot_serial/src/zcbor_decode.c) + zephyr_sources(${BOOT_DIR}/boot_serial/src/zcbor_encode.c) + zephyr_sources(${BOOT_DIR}/boot_serial/src/zcbor_common.c) zephyr_include_directories(${BOOT_DIR}/bootutil/include) zephyr_include_directories(${BOOT_DIR}/boot_serial/include) diff --git a/ext/cddl-gen b/ext/cddl-gen deleted file mode 160000 index 9f77837f..00000000 --- a/ext/cddl-gen +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9f77837f9950da1633d22abf6181a830521a6688