boot_serial: Upgrade from cddl-gen 0.1.0 to zcbor 0.4.0

cddl-gen has been renamed to zcbor.
Update regenerate_serial_recovery_cbor.sh and regenerate/recopy all
files.

Remove the submodule in ext/ since it is no longer necessary when
the zcbor package is installed (only needed for regeneration, not
for building).

Signed-off-by: Øyvind Rønningstad <oyvind.ronningstad@nordicsemi.no>
diff --git a/.gitmodules b/.gitmodules
index dcd3a70..bf510c9 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 06a173e..5dd4ea2 100644
--- a/.mbedignore
+++ b/.mbedignore
@@ -11,7 +11,6 @@
 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 a11284f..4a4a63d 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 <sys/reboot.h>
@@ -99,17 +99,12 @@
 
 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 @@
  */
 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 @@
     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 @@
     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 @@
                 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 @@
      */
 
     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 @@
 
 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 @@
 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 @@
             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 @@
     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 8a4cd9c..0000000
--- 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 <stddef.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-#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 e652908..0000000
--- 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 <stdint.h>
-#include <stdbool.h>
-#include <stddef.h>
-
-
-/** 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 <sys/printk.h>
-#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 9707729..0000000
--- 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 <stdint.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-#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 5bdc800..0000000
--- 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 <stdint.h>
-#include <stdbool.h>
-#include <stddef.h>
-#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 d12dc94..0000000
--- 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 <stdint.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-#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 4c53d45..0000000
--- 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 <stdint.h>
-#include <stdbool.h>
-#include <stddef.h>
-#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] = <initialize here>;
- *              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 08d1220..1f2137a 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 <copyright>"
-	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 @@
 
 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 2561b70..b00e48c 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 <stdint.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <string.h>
-#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 f167d9b..cdf5335 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 <stdbool.h>
 #include <stddef.h>
 #include <string.h>
-#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 0000000..d890568
--- /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 <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#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 8856017..0000000
--- 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 <stdint.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-#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 0000000..71962d6
--- /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 <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.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_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 0000000..eae2ffa
--- /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 <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+
+/** 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 <sys/printk.h>
+#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 0000000..f34ad7f
--- /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 <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#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 0000000..a525c20
--- /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 <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#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 0000000..33a51fe
--- /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 <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#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 0000000..2a4d5e3
--- /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 <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#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 0000000..e129021
--- /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 <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#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] = <initialize>;
+ *     struct zcbor_string bstrs[2] = <initialize>;
+ *     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 026ce2b..db9067a 100644
--- a/boot/zephyr/CMakeLists.txt
+++ b/boot/zephyr/CMakeLists.txt
@@ -252,9 +252,9 @@
   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 9f77837..0000000
--- a/ext/cddl-gen
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 9f77837f9950da1633d22abf6181a830521a6688