diff --git a/sys/include/suit/v4/suit.h b/sys/include/suit/v4/suit.h index c7420cef4c..0f2defc0a4 100644 --- a/sys/include/suit/v4/suit.h +++ b/sys/include/suit/v4/suit.h @@ -177,17 +177,6 @@ int suit_v4_parse(suit_v4_manifest_t *manifest, const uint8_t *buf, size_t len); */ int suit_v4_policy_check(suit_v4_manifest_t *manifest); -/** - * @brief Initialize a cbor iterator for SUIT cbor map container parsing - * - * @param[in] map the cbor container - * @param[in] it the cbor iterator - * - * @return SUIT_OK when initialization is successful - * @return SUIT_ERR_INVALID_MANIFEST if the manifest is not a cbor container - */ -int suit_cbor_map_iterate_init(nanocbor_value_t *map, nanocbor_value_t *it); - /** * @brief Iterate over a cbor map container * @@ -200,53 +189,6 @@ int suit_cbor_map_iterate_init(nanocbor_value_t *map, nanocbor_value_t *it); */ int suit_cbor_map_iterate(nanocbor_value_t *it, nanocbor_value_t *key, nanocbor_value_t *value); -/** - * @brief Get cbor value as int32_t - * - * @param[in] it cbor container iterator - * @param[out] out address of the returned integer - * - * @return SUIT_OK on success - * @return SUIT_ERR_INVALID_MANIFEST if value doesn't fit in an int - */ -int suit_cbor_get_int32(nanocbor_value_t *it, int32_t *out); - -/** - * @brief Get cbor value as unsigned - * - * @param[in] it cbor container iterator - * @param[out] out address of the returned unsigned - * - * @return SUIT_OK on success - * @return SUIT_ERR_INVALID_MANIFEST if value doesn't fit or cannot - * be converted to unsigned - */ -int suit_cbor_get_uint(nanocbor_value_t *it, unsigned *out); - -/** - * @brief Get cbor value as unsigned long - * - * @param[in] it cbor container iterator - * @param[out] out address of the returned unsigned long - * - * @return SUIT_OK on success - * @return SUIT_ERR_INVALID_MANIFEST if value doesn't fit or cannot - * be converted to unsigned long - */ -int suit_cbor_get_uint32(nanocbor_value_t *it, uint32_t *out); - -/** - * @brief Get cbor value as string - * - * @param[in] it cbor container iterator - * @param[out] buf address of the string buffer - * @param[out] len address of the len of the string - * - * @return SUIT_OK on success - * @return SUIT_ERR_INVALID_MANIFEST if value is not a valid string - */ -int suit_cbor_get_string(nanocbor_value_t *it, const uint8_t **buf, size_t *len); - /** * @brief Parser a cbor subsequence * diff --git a/sys/suit/v4/cbor.c b/sys/suit/v4/cbor.c index d000697f93..3ec824ad40 100644 --- a/sys/suit/v4/cbor.c +++ b/sys/suit/v4/cbor.c @@ -36,118 +36,47 @@ #define ENABLE_DEBUG (0) #include "debug.h" - static suit_manifest_handler_t _manifest_get_auth_wrapper_handler(int key); typedef suit_manifest_handler_t (*suit_manifest_handler_getter_t)(int key); -int suit_cbor_map_iterate_init(nanocbor_value_t *map, nanocbor_value_t *it) -{ - if (nanocbor_get_type(map) != NANOCBOR_TYPE_MAP) { - LOG_INFO("suit_v4_parse(): manifest not a map\n)"); - return SUIT_ERR_INVALID_MANIFEST; - } - - nanocbor_enter_map(map, it); - - return SUIT_OK; -} - -int suit_cbor_map_iterate(nanocbor_value_t *it, nanocbor_value_t *key, - nanocbor_value_t *value) -{ - if (nanocbor_at_end(it)) { - return 0; - } - - *key = *it; - nanocbor_skip(it); - - *value = *it; - nanocbor_skip(it); - - return 1; -} - -int suit_cbor_get_int32(nanocbor_value_t *it, int32_t *out) -{ - int res = nanocbor_get_int32(it, out); - - if (res < NANOCBOR_OK) { - LOG_DEBUG("suit_cbor_get_int32() error %u\n", res); - return SUIT_ERR_INVALID_MANIFEST; - } - - return SUIT_OK; -} - -int suit_cbor_get_string(nanocbor_value_t *it, const uint8_t **buf, size_t *len) -{ - if (nanocbor_get_type(it) == NANOCBOR_TYPE_TSTR) { - if (nanocbor_get_tstr(it, buf, len) < 0) { - return SUIT_ERR_INVALID_MANIFEST; - } - return SUIT_OK; - } - else if (nanocbor_get_type(it) == NANOCBOR_TYPE_BSTR) { - if (nanocbor_get_bstr(it, buf, len) < 0) { - return SUIT_ERR_INVALID_MANIFEST; - } - return SUIT_OK; - } - else { - LOG_DEBUG("suit_cbor_get_string(): unexpected type: %i\n", - nanocbor_get_type(it)); - return SUIT_ERR_INVALID_MANIFEST; - } -} - -int suit_cbor_get_uint32(nanocbor_value_t *it, uint32_t *out) -{ - if (nanocbor_get_uint32(it, out) < 0) { - return SUIT_ERR_INVALID_MANIFEST; - } - return SUIT_OK; -} - -int suit_cbor_get_uint(nanocbor_value_t *it, unsigned *out) -{ - return suit_cbor_get_uint32(it, (uint32_t *)out); -} - int suit_cbor_subparse(nanocbor_value_t *bseq, nanocbor_value_t *it) { const uint8_t *bytes; size_t bytes_len = 0; - int res = suit_cbor_get_string(bseq, &bytes, &bytes_len); - if (res != SUIT_OK) { - return res; + int res = nanocbor_get_bstr(bseq, &bytes, &bytes_len); + if (res < 0) { + return SUIT_ERR_INVALID_MANIFEST; } nanocbor_decoder_init(it, bytes, bytes_len); return SUIT_OK; } -static int _v4_parse(suit_v4_manifest_t *manifest, const uint8_t *buf, - size_t len, suit_manifest_handler_getter_t getter) +int _v4_parse(suit_v4_manifest_t *manifest, const uint8_t *buf, + size_t len, suit_manifest_handler_getter_t getter) { - nanocbor_value_t it, map, key, value; + nanocbor_value_t it, map; nanocbor_decoder_init(&it, buf, len); map = it; - if (suit_cbor_map_iterate_init(&map, &it) != SUIT_OK) { + if (nanocbor_enter_map(&map, &it) < 0) { LOG_DEBUG("suit _v4_parse(): manifest not a map!\n"); return SUIT_ERR_INVALID_MANIFEST; } - while (suit_cbor_map_iterate(&it, &key, &value)) { + while (!nanocbor_at_end(&it)) { int32_t integer_key; - if (suit_cbor_get_int32(&key, &integer_key) != SUIT_OK) { + + if (nanocbor_get_int32(&it, &integer_key) < 0) { return SUIT_ERR_INVALID_MANIFEST; } LOG_DEBUG("got key val=%" PRIi32 "\n", integer_key); suit_manifest_handler_t handler = getter(integer_key); + nanocbor_value_t value = it; + nanocbor_skip(&it); + if (handler) { int res = handler(manifest, integer_key, &value); if (res < 0) { @@ -179,7 +108,7 @@ static int _auth_handler(suit_v4_manifest_t *manifest, int key, (void)key; const uint8_t *cose_buf; size_t cose_len = 0; - int res = suit_cbor_get_string(it, &cose_buf, &cose_len); + int res = nanocbor_get_bstr(it, &cose_buf, &cose_len); if (res < 0) { LOG_INFO("Unable to get COSE signature\n"); @@ -200,7 +129,7 @@ static int _manifest_handler(suit_v4_manifest_t *manifest, int key, const uint8_t *manifest_buf; size_t manifest_len; - suit_cbor_get_string(it, &manifest_buf, &manifest_len); + nanocbor_get_bstr(it, &manifest_buf, &manifest_len); /* Validate the COSE struct first now that we have the payload */ cose_sign_decode_set_payload(&manifest->verify, manifest_buf, manifest_len); @@ -243,7 +172,7 @@ static suit_manifest_handler_t _suit_manifest_get_handler(int key, } /* begin{code-style-ignore} */ -static suit_manifest_handler_t _auth_handlers[] = { +static const suit_manifest_handler_t _auth_handlers[] = { [ 0] = NULL, [ 1] = _auth_handler, [ 2] = _manifest_handler, diff --git a/sys/suit/v4/handlers.c b/sys/suit/v4/handlers.c index 19f2c9cfc9..ee79d1ff90 100644 --- a/sys/suit/v4/handlers.c +++ b/sys/suit/v4/handlers.c @@ -45,7 +45,7 @@ static int _validate_uuid(suit_v4_manifest_t *manifest, nanocbor_value_t *it, uu size_t len = sizeof(uuid_t); char uuid_str[UUID_STR_LEN + 1]; char uuid_str2[UUID_STR_LEN + 1]; - if (suit_cbor_get_string(it, &uuid_manifest_ptr, &len) != SUIT_OK) { + if (nanocbor_get_bstr(it, &uuid_manifest_ptr, &len) < 0) { return SUIT_ERR_INVALID_MANIFEST; } @@ -84,7 +84,7 @@ static int _cond_comp_offset(suit_v4_manifest_t *manifest, int key, nanocbor_val (void)manifest; (void)key; uint32_t offset; - suit_cbor_get_uint32(it, &offset); + nanocbor_get_uint32(it, &offset); uint32_t other_offset = (uint32_t)riotboot_slot_get_hdr(riotboot_slot_other()) \ - CPU_FLASH_BASE; LOG_INFO("Comparing manifest offset %u with other slot offset %u\n", @@ -98,13 +98,12 @@ static int _dtv_set_comp_idx(suit_v4_manifest_t *manifest, int key, nanocbor_val if (nanocbor_get_type(it) == NANOCBOR_TYPE_FLOAT) { LOG_DEBUG("_dtv_set_comp_idx() ignoring boolean and floats\n)"); nanocbor_skip(it); - return 0; } - int res = suit_cbor_get_int32(it, &manifest->component_current); - if (!res) { - LOG_DEBUG("Setting component index to %d\n", (int)manifest->component_current); + else if (nanocbor_get_int32(it, &manifest->component_current) < 0) { + return SUIT_ERR_INVALID_MANIFEST; } - return res; + LOG_DEBUG("Setting component index to %d\n", (int)manifest->component_current); + return 0; } static int _dtv_run_seq_cond(suit_v4_manifest_t *manifest, int key, nanocbor_value_t *it) @@ -130,8 +129,8 @@ static int _param_get_digest(suit_v4_manifest_t *manifest, nanocbor_value_t *it) static int _param_get_img_size(suit_v4_manifest_t *manifest, nanocbor_value_t *it) { - int res = suit_cbor_get_uint32(it, &manifest->components[0].size); - if (res) { + int res = nanocbor_get_uint32(it, &manifest->components[0].size); + if (res < 0) { LOG_DEBUG("error getting image size\n"); return res; } @@ -149,7 +148,7 @@ static int _dtv_set_param(suit_v4_manifest_t *manifest, int key, nanocbor_value_ while (!nanocbor_at_end(&map)) { /* map points to the key of the param */ int32_t param_key; - suit_cbor_get_int32(&map, ¶m_key); + nanocbor_get_int32(&map, ¶m_key); LOG_DEBUG("Setting component index to %" PRIi32 "\n", manifest->component_current); LOG_DEBUG("param_key=%" PRIi32 "\n", param_key); int res; @@ -199,40 +198,38 @@ static int _dtv_fetch(suit_v4_manifest_t *manifest, int key, nanocbor_value_t *_ return err; } - /* confirm the document contains an array */ - if (nanocbor_get_type(&it) != NANOCBOR_TYPE_ARR) { + nanocbor_value_t url_it; + /* enter container, confirm it is an array, too */ + if (nanocbor_enter_array(&it, &url_it) < 0) { LOG_DEBUG("url list no array\n)"); - LOG_DEBUG("type: %u\n", nanocbor_get_type(&it)); + return SUIT_ERR_INVALID_MANIFEST; } - /* enter container, confirm it is an array, too */ - nanocbor_value_t url_it; - nanocbor_enter_array(&it, &url_it); - if (nanocbor_get_type(&url_it) != NANOCBOR_TYPE_ARR) { + nanocbor_value_t url_value_it; + if (nanocbor_enter_array(&url_it, &url_value_it) < 0) { LOG_DEBUG("url entry no array\n)"); + return SUIT_ERR_INVALID_MANIFEST; } /* expect two entries: priority as int, url as byte string. bail out if not. */ - nanocbor_value_t url_value_it; - nanocbor_enter_array(&url_it, &url_value_it); - - /* check that first array entry is an int (the priotity of the url) */ - if (nanocbor_get_type(&url_value_it) != NANOCBOR_TYPE_UINT) { - LOG_DEBUG("expected URL priority (int), got %d\n", nanocbor_get_type(&url_value_it)); + uint32_t prio; + /* check that first array entry is an int (the priority of the url) */ + if (nanocbor_get_uint32(&url_value_it, &prio) < 0) { + LOG_DEBUG("expected URL priority (int), got %d\n", + nanocbor_get_type(&url_value_it)); return -1; } + LOG_DEBUG("URL priority %"PRIu32"\n", prio); - /* skip URL priority (currently unused) */ - nanocbor_skip(&url_value_it); - - int res = suit_cbor_get_string(&url_value_it, &url, &url_len); - if (res) { + int res = nanocbor_get_tstr(&url_value_it, &url, &url_len); + if (res < 0) { LOG_DEBUG("error parsing URL\n)"); - return -1; + return SUIT_ERR_INVALID_MANIFEST; } if (url_len >= manifest->urlbuf_len) { - LOG_INFO("url too large: %u>%u\n)", (unsigned)url_len, (unsigned)manifest->urlbuf_len); - return -1; + LOG_INFO("url too large: %u>%u\n)", (unsigned)url_len, + (unsigned)manifest->urlbuf_len); + return SUIT_ERR_UNSUPPORTED; } memcpy(manifest->urlbuf, url, url_len); manifest->urlbuf[url_len] = '\0'; @@ -241,12 +238,13 @@ static int _dtv_fetch(suit_v4_manifest_t *manifest, int key, nanocbor_value_t *_ nanocbor_leave_container(&it, &url_it); } - LOG_DEBUG("_dtv_fetch() fetching \"%s\" (url_len=%u)\n", manifest->urlbuf, (unsigned)url_len); + LOG_DEBUG("_dtv_fetch() fetching \"%s\" (url_len=%u)\n", manifest->urlbuf, + (unsigned)url_len); int target_slot = riotboot_slot_other(); riotboot_flashwrite_init(manifest->writer, target_slot); - int res = suit_coap_get_blockwise_url(manifest->urlbuf, COAP_BLOCKSIZE_64, suit_flashwrite_helper, - manifest); + int res = suit_coap_get_blockwise_url(manifest->urlbuf, COAP_BLOCKSIZE_64, + suit_flashwrite_helper, manifest); if (res) { LOG_INFO("image download failed\n)"); @@ -256,16 +254,17 @@ static int _dtv_fetch(suit_v4_manifest_t *manifest, int key, nanocbor_value_t *_ const uint8_t *digest; size_t digest_len; - res = suit_cbor_get_string(&manifest->components[0].digest, &digest, &digest_len); - if (res) { - return res; + res = nanocbor_get_bstr(&manifest->components[0].digest, &digest, &digest_len); + if (res < 0) { + return SUIT_ERR_INVALID_MANIFEST; } /* "digest" points to a 36 byte string that includes the digest type. * riotboot_flashwrite_verify_sha256() is only interested in the 32b digest, * so shift the pointer accordingly. */ - res = riotboot_flashwrite_verify_sha256(digest + 4, manifest->components[0].size, target_slot); + res = riotboot_flashwrite_verify_sha256(digest + 4, manifest->components[0].size, + target_slot); if (res) { LOG_INFO("image verification failed\n"); return res; @@ -283,8 +282,7 @@ static int _version_handler(suit_v4_manifest_t *manifest, int key, (void)key; /* Validate manifest version */ int32_t version = -1; - if ((nanocbor_get_type(it) == NANOCBOR_TYPE_UINT) && - (nanocbor_get_int32(it, &version) >= 0)) { + if (nanocbor_get_int32(it, &version) >= 0) { if (version == SUIT_VERSION) { manifest->validated |= SUIT_VALIDATED_VERSION; LOG_INFO("suit: validated manifest version\n)"); @@ -299,35 +297,33 @@ static int _version_handler(suit_v4_manifest_t *manifest, int key, static int _seq_no_handler(suit_v4_manifest_t *manifest, int key, nanocbor_value_t *it) { - (void)manifest; (void)key; - (void)it; int32_t seq_nr; - if ((nanocbor_get_type(it) == NANOCBOR_TYPE_UINT)) { - nanocbor_get_int32(it, &seq_nr); - const riotboot_hdr_t *hdr = riotboot_slot_get_hdr(riotboot_slot_current()); - if (seq_nr <= (int32_t)hdr->version) { - LOG_INFO("%"PRId32" <= %"PRId32"\n", seq_nr, hdr->version); - LOG_INFO("seq_nr <= running image\n)"); + if (nanocbor_get_int32(it, &seq_nr) < 0) { + LOG_INFO("Unable to get sequence number\n"); + return SUIT_ERR_INVALID_MANIFEST; + } + const riotboot_hdr_t *hdr = riotboot_slot_get_hdr(riotboot_slot_current()); + if (seq_nr <= (int32_t)hdr->version) { + LOG_INFO("%"PRId32" <= %"PRId32"\n", seq_nr, hdr->version); + LOG_INFO("seq_nr <= running image\n)"); + return -1; + } + + hdr = riotboot_slot_get_hdr(riotboot_slot_other()); + if (riotboot_hdr_validate(hdr) == 0) { + if (seq_nr<= (int32_t)hdr->version) { + LOG_INFO("%"PRIu32" <= %"PRIu32"\n", seq_nr, hdr->version); + LOG_INFO("seq_nr <= other image\n)"); return -1; } - - hdr = riotboot_slot_get_hdr(riotboot_slot_other()); - if (riotboot_hdr_validate(hdr) == 0) { - if (seq_nr<= (int32_t)hdr->version) { - LOG_INFO("%"PRIu32" <= %"PRIu32"\n", seq_nr, hdr->version); - LOG_INFO("seq_nr <= other image\n)"); - return -1; - } - } - LOG_INFO("suit: validated sequence number\n)"); - manifest->validated |= SUIT_VALIDATED_SEQ_NR; - return 0; } - LOG_INFO("Unable to get sequence number\n"); - return -1; + LOG_INFO("suit: validated sequence number\n)"); + manifest->validated |= SUIT_VALIDATED_SEQ_NR; + return 0; + } static int _dependencies_handler(suit_v4_manifest_t *manifest, int key, @@ -349,15 +345,13 @@ static int _component_handler(suit_v4_manifest_t *manifest, int key, nanocbor_value_t arr; LOG_DEBUG("storing components\n)"); - if (nanocbor_get_type(it) != NANOCBOR_TYPE_ARR) { + if (nanocbor_enter_array(it, &arr) < 0) { LOG_DEBUG("components field not an array\n"); return -1; } - nanocbor_enter_array(it, &arr); - unsigned n = 0; while (!nanocbor_at_end(&arr)) { - nanocbor_value_t map, key, value; + nanocbor_value_t map; if (n < SUIT_V4_COMPONENT_MAX) { manifest->components_len += 1; } @@ -366,30 +360,36 @@ static int _component_handler(suit_v4_manifest_t *manifest, int key, return SUIT_ERR_INVALID_MANIFEST; } - suit_cbor_map_iterate_init(&arr, &map); + if (nanocbor_enter_map(&arr, &map) < 0) { + LOG_DEBUG("suit _v4_parse(): manifest not a map!\n"); + return SUIT_ERR_INVALID_MANIFEST; + } suit_v4_component_t *current = &manifest->components[n]; - while (suit_cbor_map_iterate(&map, &key, &value)) { + while (!nanocbor_at_end(&map)) { + /* handle key, value */ int32_t integer_key; - if (suit_cbor_get_int32(&key, &integer_key)) { + if (nanocbor_get_int32(&map, &integer_key) < 0) { return SUIT_ERR_INVALID_MANIFEST; } switch (integer_key) { case SUIT_COMPONENT_IDENTIFIER: - current->identifier = value; + current->identifier = map; break; case SUIT_COMPONENT_SIZE: LOG_DEBUG("skipping SUIT_COMPONENT_SIZE"); break; case SUIT_COMPONENT_DIGEST: - current->digest = value; + current->digest = map; break; default: - LOG_DEBUG("ignoring unexpected component data (nr. %" PRIi32 ")\n", integer_key); + LOG_DEBUG("ignoring unexpected component data (nr. %" PRIi32 ")\n", + integer_key); } + nanocbor_skip(&map); LOG_DEBUG("component %u parsed\n", n); } @@ -407,7 +407,7 @@ static int _component_handler(suit_v4_manifest_t *manifest, int key, } /* begin{code-style-ignore} */ -static suit_manifest_handler_t global_handlers[] = { +static const suit_manifest_handler_t global_handlers[] = { [ 0] = NULL, [ 1] = _version_handler, [ 2] = _seq_no_handler, @@ -422,7 +422,7 @@ static suit_manifest_handler_t global_handlers[] = { static const unsigned global_handlers_len = ARRAY_SIZE(global_handlers); /* begin{code-style-ignore} */ -static suit_manifest_handler_t _sequence_handlers[] = { +static const suit_manifest_handler_t _sequence_handlers[] = { [ 0] = NULL, [ 1] = _cond_vendor_handler, [ 2] = _cond_class_handler, @@ -456,10 +456,13 @@ suit_manifest_handler_t suit_manifest_get_manifest_handler(int key) global_handlers_len); } -static int _common_sequence_handler(suit_v4_manifest_t *manifest, int key, nanocbor_value_t *it) +static int _common_sequence_handler(suit_v4_manifest_t *manifest, int key, + nanocbor_value_t *it) { - suit_manifest_handler_t handler = _suit_manifest_get_handler(key, _sequence_handlers, _sequence_handlers_len); + suit_manifest_handler_t handler = _suit_manifest_get_handler(key, + _sequence_handlers, + _sequence_handlers_len); LOG_DEBUG("Handling handler with key %d at %p\n", key, handler); if (handler) { return handler(manifest, key, it); @@ -488,19 +491,17 @@ int _handle_command_sequence(suit_v4_manifest_t *manifest, nanocbor_value_t *bse return err; } - if (nanocbor_get_type(&it) != NANOCBOR_TYPE_ARR) { - return -1; + if (nanocbor_enter_array(&it, &arr) < 0) { + return SUIT_ERR_INVALID_MANIFEST; } - nanocbor_enter_array(&it, &arr); while (!nanocbor_at_end(&arr)) { nanocbor_value_t map; - if (nanocbor_get_type(&arr) != NANOCBOR_TYPE_MAP) { + if (nanocbor_enter_map(&arr, &map) < 0) { return SUIT_ERR_INVALID_MANIFEST; } - nanocbor_enter_map(&arr, &map); int32_t integer_key; - if (suit_cbor_get_int32(&map, &integer_key)) { + if (nanocbor_get_int32(&map, &integer_key) < 0) { return SUIT_ERR_INVALID_MANIFEST; } int res = handler(manifest, integer_key, &map);