diff --git a/sys/include/suit.h b/sys/include/suit.h index f352abe86f..c7e3c2a039 100644 --- a/sys/include/suit.h +++ b/sys/include/suit.h @@ -14,10 +14,10 @@ * @experimental * * @note The current implementation of this specification is based on the - * IETF-SUIT-v3 draft. The module is still experimental and will change to + * IETF-SUIT-v9 draft. The module is still experimental and will change to * match future draft specifications * - * @see https://tools.ietf.org/html/draft-ietf-suit-manifest-03 + * @see https://tools.ietf.org/html/draft-ietf-suit-manifest-09 * * @{ * @@ -52,7 +52,9 @@ extern "C" { /** * @brief Maximum number of components supported in a SUIT manifest */ -#define SUIT_COMPONENT_MAX (1U) +#ifndef CONFIG_SUIT_COMPONENT_MAX +#define CONFIG_SUIT_COMPONENT_MAX (1U) +#endif /** * @brief Current SUIT serialization format version @@ -126,13 +128,59 @@ enum { }; /** - * @brief SUIT component struct + * @name SUIT parameters + * @{ + */ +typedef enum { + SUIT_PARAMETER_VENDOR_IDENTIFIER = 1, + SUIT_PARAMETER_CLASS_IDENTIFIER = 2, + SUIT_PARAMETER_IMAGE_DIGEST = 3, + SUIT_PARAMETER_USE_BEFORE = 4, + SUIT_PARAMETER_COMPONENT_OFFSET = 5, + SUIT_PARAMETER_STRICT_ORDER = 12, + SUIT_PARAMETER_SOFT_FAILURE = 13, + SUIT_PARAMETER_IMAGE_SIZE = 14, + SUIT_PARAMETER_ENCRYPTION_INFO = 18, + SUIT_PARAMETER_COMPRESSION_INFO = 19, + SUIT_PARAMETER_UNPACK_INFO = 20, + SUIT_PARAMETER_URI = 21, + SUIT_PARAMETER_SOURCE_COMPONENT = 22, + SUIT_PARAMETER_RUN_ARGS = 23, + SUIT_PARAMETER_DEVICE_IDENTIFIER = 24, + SUIT_PARAMETER_MINIMUM_BATTERY = 26, + SUIT_PARAMETER_UPDATE_PRIORITY = 27, + SUIT_PARAMETER_VERSION = 28, + SUIT_PARAMETER_WAIT_INFO = 29, + SUIT_PARAMETER_URI_LIST = 30, +} suit_parameter_t; +/** @} */ + +/** + * @brief SUIT parameter reference + * + * A 16-bit offset is enough to reference content inside the manifest itself. */ typedef struct { - uint32_t size; /**< Size */ - nanocbor_value_t identifier; /**< Identifier */ - nanocbor_value_t url; /**< Url */ - nanocbor_value_t digest; /**< Digest */ + uint16_t offset; /**< offset to the start of the content */ +} suit_param_ref_t; + +/** + * @brief SUIT component struct as decoded from the manifest + * + * The parameters are references to CBOR-encoded information in the manifest. + */ +typedef struct { + suit_param_ref_t identifier; /**< Component identifier */ + suit_param_ref_t param_vendor_id; /**< Vendor ID */ + suit_param_ref_t param_class_id; /**< Class ID */ + suit_param_ref_t param_digest; /**< Payload verification digest */ + suit_param_ref_t param_uri; /**< Payload fetch URI */ + suit_param_ref_t param_size; /**< Payload size */ + + /** + * @brief Component offset inside the device memory. + */ + suit_param_ref_t param_component_offset; } suit_component_t; /** @@ -146,9 +194,9 @@ typedef struct { uint32_t validated; /**< bitfield of validated policies */ uint32_t state; /**< bitfield holding state information */ /** List of components in the manifest */ - suit_component_t components[SUIT_COMPONENT_MAX]; + suit_component_t components[CONFIG_SUIT_COMPONENT_MAX]; unsigned components_len; /**< Current number of components */ - uint32_t component_current; /**< Current component index */ + uint8_t component_current; /**< Current component index */ riotboot_flashwrite_t *writer; /**< Pointer to the riotboot flash writer */ /** Manifest validation buffer */ uint8_t validation_buf[SUIT_COSE_BUF_SIZE]; @@ -165,6 +213,20 @@ typedef struct { */ #define SUIT_MANIFEST_HAVE_IMAGE (0x2) +/** + * @brief Component index representing all components + * + * Used when suit-directive-set-component-index = True + */ +#define SUIT_MANIFEST_COMPONENT_ALL (UINT8_MAX) + +/** + * @brief Component index representing no components + * + * Used when suit-directive-set-component-index = False + */ +#define SUIT_MANIFEST_COMPONENT_NONE (SUIT_MANIFEST_COMPONENT_ALL - 1) + /** * @brief Parse a manifest * diff --git a/sys/include/suit/handlers.h b/sys/include/suit/handlers.h index 538bf7e124..95529f927d 100644 --- a/sys/include/suit/handlers.h +++ b/sys/include/suit/handlers.h @@ -135,14 +135,14 @@ extern const suit_manifest_handler_t suit_command_sequence_handlers[]; extern const size_t suit_command_sequence_handlers_len; /** - * @brief SUIT container handlers reference + * @brief SUIT envelope handlers reference */ -extern const suit_manifest_handler_t suit_container_handlers[]; +extern const suit_manifest_handler_t suit_envelope_handlers[]; /** - * @brief length of the SUIT container handlers + * @brief length of the SUIT envelope handlers */ -extern const size_t suit_container_handlers_len; +extern const size_t suit_envelope_handlers_len; /** * @brief SUIT common handlers reference @@ -193,6 +193,36 @@ int suit_handle_manifest_structure_bstr(suit_manifest_t *manifest, const suit_manifest_handler_t *handlers, size_t handlers_len); +/** + * @brief Create an internal @ref suit_param_ref_t from a NanoCBOR value + * reference. + * + * The resulting @p ref only contains a 16 bit offset to the location of the + * NanoCBOR value, saving some RAM for each stored reference. + * + * @param manifest SUIT manifest context + * @param ref reference to store + * @param val NanoCBOR value to convert to a reference + * + * @returns The offset of the nanocbor value inside the manifest + * bytestring + */ +uint16_t suit_param_ref_to_cbor(suit_manifest_t *manifest, + suit_param_ref_t *ref, + nanocbor_value_t *val); + +/** + * @brief Create a NanoCBOR value reference from an internal + * @ref suit_param_ref_t. + * + * @param manifest SUIT manifest context + * @param ref reference to parse + * @param val NanoCBOR value to restore + */ +void suit_param_cbor_to_ref(suit_manifest_t *manifest, + suit_param_ref_t *ref, + nanocbor_value_t *val); + #ifdef __cplusplus } #endif diff --git a/sys/suit/handlers.c b/sys/suit/handlers.c index 5d98c4ce38..e83782c05d 100644 --- a/sys/suit/handlers.c +++ b/sys/suit/handlers.c @@ -20,6 +20,7 @@ #include #include +#include #include "suit/handlers.h" #include "suit.h" @@ -36,6 +37,24 @@ static suit_manifest_handler_t _get_handler(int key, return map[key]; } +uint16_t suit_param_ref_to_cbor(suit_manifest_t *manifest, + suit_param_ref_t *ref, + nanocbor_value_t *val) +{ + size_t len = manifest->len - ref->offset; + const uint8_t *start = manifest->buf + ref->offset; + nanocbor_decoder_init(val, start, len); + return ref->offset; +} + +void suit_param_cbor_to_ref(suit_manifest_t *manifest, + suit_param_ref_t *ref, + nanocbor_value_t *val) +{ + assert(val->cur >= manifest->buf); + ref->offset = val->cur - manifest->buf; +} + int suit_handle_manifest_structure(suit_manifest_t *manifest, nanocbor_value_t *it, const suit_manifest_handler_t *handlers, diff --git a/sys/suit/handlers_command_seq.c b/sys/suit/handlers_command_seq.c index 3a5bb3cc43..3883460f79 100644 --- a/sys/suit/handlers_command_seq.c +++ b/sys/suit/handlers_command_seq.c @@ -24,6 +24,7 @@ #include #include +#include #include "kernel_defines.h" #include "suit/conditions.h" @@ -39,22 +40,33 @@ #include "log.h" +static suit_component_t *_get_component(suit_manifest_t *manifest) +{ + /* Out-of-bounds check has been done in the _dtv_set_comp_idx, True/False + * not handled here intentionally */ + assert(manifest->component_current < CONFIG_SUIT_COMPONENT_MAX); + return &manifest->components[manifest->component_current]; +} + static int _validate_uuid(suit_manifest_t *manifest, - nanocbor_value_t *it, + suit_param_ref_t *ref, uuid_t *uuid) { - (void)manifest; const uint8_t *uuid_manifest_ptr; size_t len = sizeof(uuid_t); - char uuid_str[UUID_STR_LEN + 1]; - char uuid_str2[UUID_STR_LEN + 1]; - if (nanocbor_get_bstr(it, &uuid_manifest_ptr, &len) < 0) { + nanocbor_value_t it; + + if ((suit_param_ref_to_cbor(manifest, ref, &it) == 0) || + (nanocbor_get_bstr(&it, &uuid_manifest_ptr, &len) < 0)) { return SUIT_ERR_INVALID_MANIFEST; } + char uuid_str[UUID_STR_LEN + 1]; + char uuid_str2[UUID_STR_LEN + 1]; uuid_to_string((uuid_t *)uuid_manifest_ptr, uuid_str); uuid_to_string(uuid, uuid_str2); LOG_INFO("Comparing %s to %s from manifest\n", uuid_str2, uuid_str); + return uuid_equal(uuid, (uuid_t *)uuid_manifest_ptr) ? SUIT_OK : SUIT_ERR_COND; @@ -65,8 +77,11 @@ static int _cond_vendor_handler(suit_manifest_t *manifest, nanocbor_value_t *it) { (void)key; + (void)it; LOG_INFO("validating vendor ID\n"); - int rc = _validate_uuid(manifest, it, suit_get_vendor_id()); + suit_component_t *comp = _get_component(manifest); + int rc = _validate_uuid(manifest, &comp->param_vendor_id, + suit_get_vendor_id()); if (rc == SUIT_OK) { LOG_INFO("validating vendor ID: OK\n"); manifest->validated |= SUIT_VALIDATED_VENDOR; @@ -79,8 +94,11 @@ static int _cond_class_handler(suit_manifest_t *manifest, nanocbor_value_t *it) { (void)key; + (void)it; LOG_INFO("validating class id\n"); - int rc = _validate_uuid(manifest, it, suit_get_class_id()); + suit_component_t *comp = _get_component(manifest); + int rc = _validate_uuid(manifest, &comp->param_class_id, + suit_get_class_id()); if (rc == SUIT_OK) { LOG_INFO("validating class id: OK\n"); manifest->validated |= SUIT_VALIDATED_CLASS; @@ -95,18 +113,24 @@ static int _cond_comp_offset(suit_manifest_t *manifest, (void)manifest; (void)key; uint32_t offset; + uint32_t report; - int rc = nanocbor_get_uint32(it, &offset); - if (rc < 0) { - LOG_WARNING("_cond_comp_offset(): expected int, got rc=%i type=%i\n", - rc, nanocbor_get_type(it)); + suit_component_t *comp = _get_component(manifest); + + /* Grab offset from param */ + if (nanocbor_get_uint32(it, &report) < 0) { + LOG_WARNING("_cond_comp_offset(): expected None param\n"); return SUIT_ERR_INVALID_MANIFEST; } + nanocbor_value_t param_offset; + suit_param_ref_to_cbor(manifest, &comp->param_component_offset, + ¶m_offset); + nanocbor_get_uint32(¶m_offset, &offset); uint32_t other_offset = (uint32_t)riotboot_slot_offset( riotboot_slot_other()); - LOG_INFO("Comparing manifest offset %u with other slot offset %u\n", - (unsigned)offset, (unsigned)other_offset); + LOG_INFO("Comparing manifest offset %"PRIx32" with other slot offset %"PRIx32"\n", + offset, other_offset); return other_offset == offset ? SUIT_OK : SUIT_ERR_COND; } @@ -115,17 +139,26 @@ static int _dtv_set_comp_idx(suit_manifest_t *manifest, nanocbor_value_t *it) { (void)key; - if (nanocbor_get_type(it) == NANOCBOR_TYPE_FLOAT) { - LOG_DEBUG("_dtv_set_comp_idx() ignoring boolean and floats\n)"); - nanocbor_skip(it); + bool index = false; + uint32_t new_index; + + /* It can be a bool, meaning all or none of the components */ + if (nanocbor_get_bool(it, &index) >= 0) { + new_index = index ? + SUIT_MANIFEST_COMPONENT_ALL : SUIT_MANIFEST_COMPONENT_NONE; } - else if (nanocbor_get_uint32(it, &manifest->component_current) < 0) { + /* It can be a positive integer, meaning one of the components */ + else if (nanocbor_get_uint32(it, &new_index) < 0) { return SUIT_ERR_INVALID_MANIFEST; } - if (manifest->component_current >= SUIT_COMPONENT_MAX) { + /* And if it is an integer it must be within the allowed bounds */ + else if (new_index >= CONFIG_SUIT_COMPONENT_MAX) { return SUIT_ERR_INVALID_MANIFEST; } - LOG_DEBUG("Setting component index to %d\n", + + /* Update the manifest context */ + manifest->component_current = new_index; + LOG_INFO("Setting component index to %d\n", (int)manifest->component_current); return 0; } @@ -158,9 +191,9 @@ static int _dtv_try_each(suit_manifest_t *manifest, nanocbor_value_t _container = container; /* `_container` should be CBOR _bstr wrapped according to the spec, but * it is not */ - res = suit_handle_manifest_structure(manifest, &_container, - suit_command_sequence_handlers, - suit_command_sequence_handlers_len); + res = suit_handle_manifest_structure_bstr(manifest, &_container, + suit_command_sequence_handlers, + suit_command_sequence_handlers_len); nanocbor_skip(&container); @@ -172,32 +205,6 @@ static int _dtv_try_each(suit_manifest_t *manifest, return res; } -static int _param_get_uri_list(suit_manifest_t *manifest, - nanocbor_value_t *it) -{ - LOG_DEBUG("got url list\n"); - manifest->components[manifest->component_current].url = *it; - return 0; -} -static int _param_get_digest(suit_manifest_t *manifest, nanocbor_value_t *it) -{ - LOG_DEBUG("got digest\n"); - manifest->components[manifest->component_current].digest = *it; - return 0; -} - -static int _param_get_img_size(suit_manifest_t *manifest, - nanocbor_value_t *it) -{ - int res = nanocbor_get_uint32(it, &manifest->components[0].size); - - if (res < 0) { - LOG_DEBUG("error getting image size\n"); - return res; - } - return res; -} - static int _dtv_set_param(suit_manifest_t *manifest, int key, nanocbor_value_t *it) { @@ -207,34 +214,50 @@ static int _dtv_set_param(suit_manifest_t *manifest, int key, nanocbor_enter_map(it, &map); + suit_component_t *comp = _get_component(manifest); + while (!nanocbor_at_end(&map)) { /* map points to the key of the param */ int32_t param_key; - nanocbor_get_int32(&map, ¶m_key); - LOG_DEBUG("Current component index: %" PRIi32 "\n", - manifest->component_current); + if (nanocbor_get_int32(&map, ¶m_key) < 0) { + return SUIT_ERR_INVALID_MANIFEST; + } LOG_DEBUG("param_key=%" PRIi32 "\n", param_key); - int res; + unsigned int type = nanocbor_get_type(&map); + /* Filter 'complex' types and only allow int, nint, bstr and tstr types + * for parameter values */ + if (type > NANOCBOR_TYPE_TSTR) { + return SUIT_ERR_INVALID_MANIFEST; + } + suit_param_ref_t *ref; switch (param_key) { - case 6: /* SUIT URI LIST */ - res = _param_get_uri_list(manifest, &map); + case SUIT_PARAMETER_VENDOR_IDENTIFIER: + ref = &comp->param_vendor_id; break; - case 11: /* SUIT DIGEST */ - res = _param_get_digest(manifest, &map); + case SUIT_PARAMETER_CLASS_IDENTIFIER: + ref = &comp->param_class_id; break; - case 12: /* SUIT IMAGE SIZE */ - res = _param_get_img_size(manifest, &map); + case SUIT_PARAMETER_IMAGE_DIGEST: + ref = &comp->param_digest; + break; + case SUIT_PARAMETER_COMPONENT_OFFSET: + ref = &comp->param_component_offset; + break; + case SUIT_PARAMETER_IMAGE_SIZE: + ref = &comp->param_size; + break; + case SUIT_PARAMETER_URI: + ref = &comp->param_uri; break; default: LOG_DEBUG("Unsupported parameter %" PRIi32 "\n", param_key); - res = SUIT_ERR_UNSUPPORTED; + return SUIT_ERR_UNSUPPORTED; } + suit_param_cbor_to_ref(manifest, ref, &map); + + /* Simple skip is sufficient to skip non-complex types */ nanocbor_skip(&map); - - if (res) { - return res; - } } return SUIT_OK; } @@ -247,8 +270,12 @@ static int _dtv_fetch(suit_manifest_t *manifest, int key, const uint8_t *url; size_t url_len; + suit_component_t *comp = _get_component(manifest); - int err = nanocbor_get_tstr(&manifest->components[0].url, &url, &url_len); + nanocbor_value_t param_uri; + suit_param_ref_to_cbor(manifest, &comp->param_uri, + ¶m_uri); + int err = nanocbor_get_tstr(¶m_uri, &url, &url_len); if (err < 0) { LOG_DEBUG("URL parsing failed\n)"); return err; @@ -293,6 +320,25 @@ static int _dtv_fetch(suit_manifest_t *manifest, int key, return SUIT_OK; } +static int _get_digest(nanocbor_value_t *bstr, const uint8_t **digest, size_t *digest_len) +{ + /* Bstr is a byte string with a cbor array containing the type and the + * digest */ + + const uint8_t *digest_struct; + size_t digest_struct_len; + uint32_t digest_type; + nanocbor_value_t digest_it; + nanocbor_value_t arr_it; + + nanocbor_get_bstr(bstr, &digest_struct, &digest_struct_len); + + nanocbor_decoder_init(&digest_it, digest_struct, digest_struct_len); + nanocbor_enter_array(&digest_it, &arr_it); + nanocbor_get_uint32(&arr_it, &digest_type); + return nanocbor_get_bstr(&arr_it, digest, digest_len); +} + static int _dtv_verify_image_match(suit_manifest_t *manifest, int key, nanocbor_value_t *_it) { @@ -301,21 +347,30 @@ static int _dtv_verify_image_match(suit_manifest_t *manifest, int key, const uint8_t *digest; size_t digest_len; int target_slot = riotboot_slot_other(); + suit_component_t *comp = _get_component(manifest); + + uint32_t img_size; + nanocbor_value_t param_size; + if ((suit_param_ref_to_cbor(manifest, &comp->param_size, ¶m_size) == 0) || + (nanocbor_get_uint32(¶m_size, &img_size) < 0)) { + return SUIT_ERR_INVALID_MANIFEST; + } LOG_INFO("Verifying image digest\n"); - nanocbor_value_t _v = manifest->components[0].digest; - int res = nanocbor_get_subcbor(&_v, &digest, &digest_len); + nanocbor_value_t _v; + if (suit_param_ref_to_cbor(manifest, &comp->param_digest, &_v) == 0) { + return SUIT_ERR_INVALID_MANIFEST; + } + + int res = _get_digest(&_v, &digest, &digest_len); + if (res < 0) { LOG_DEBUG("Unable to parse digest structure\n"); 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, + res = riotboot_flashwrite_verify_sha256(digest, + img_size, target_slot); if (res != 0) { return SUIT_ERR_COND; diff --git a/sys/suit/handlers_common.c b/sys/suit/handlers_common.c index 6bfac92bfb..06ee864d98 100644 --- a/sys/suit/handlers_common.c +++ b/sys/suit/handlers_common.c @@ -35,11 +35,6 @@ static int _component_handler(suit_manifest_t *manifest, int key, { (void)manifest; (void)key; - const uint8_t *subcbor; - size_t sub_size; - nanocbor_value_t _it; - nanocbor_get_bstr(it, &subcbor, &sub_size); - nanocbor_decoder_init(&_it, subcbor, sub_size); /* This is a list of lists, something like: * [ @@ -48,18 +43,26 @@ static int _component_handler(suit_manifest_t *manifest, int key, * ] * */ nanocbor_value_t arr; - if (nanocbor_enter_array(&_it, &arr) < 0) { + if (nanocbor_enter_array(it, &arr) < 0) { LOG_DEBUG("components field not an array %d\n", nanocbor_get_type(it)); return SUIT_ERR_INVALID_MANIFEST; } unsigned n = 0; while (!nanocbor_at_end(&arr)) { + if (n >= CONFIG_SUIT_COMPONENT_MAX) { + LOG_INFO("Too many components found: %u, Supported: %u\n", + n, CONFIG_SUIT_COMPONENT_MAX); + return SUIT_ERR_UNSUPPORTED; + } + suit_component_t *component = &manifest->components[n]; nanocbor_value_t comp; if (nanocbor_enter_array(&arr, &comp) < 0) { LOG_DEBUG("component elements field not an array %d\n", nanocbor_get_type(it)); return SUIT_ERR_INVALID_MANIFEST; } + suit_param_cbor_to_ref(manifest, &component->identifier, &comp); + /* Ensure that all parts of the identifier are a bstr */ while (!nanocbor_at_end(&comp)) { const uint8_t *identifier; size_t id_len; @@ -71,11 +74,10 @@ static int _component_handler(suit_manifest_t *manifest, int key, nanocbor_leave_container(&arr, &comp); n++; } - if (n > 1) { - LOG_INFO("More than 1 component found, exiting\n"); - return SUIT_ERR_UNSUPPORTED; + manifest->components_len = n; + if (n) { + manifest->state |= SUIT_MANIFEST_HAVE_COMPONENTS; } - manifest->state |= SUIT_MANIFEST_HAVE_COMPONENTS; return 0; } diff --git a/sys/suit/handlers_container.c b/sys/suit/handlers_envelope.c similarity index 60% rename from sys/suit/handlers_container.c rename to sys/suit/handlers_envelope.c index a3beba5dd7..0b955d73a5 100644 --- a/sys/suit/handlers_container.c +++ b/sys/suit/handlers_envelope.c @@ -38,45 +38,12 @@ static int _auth_handler(suit_manifest_t *manifest, int key, (void)key; cose_sign_dec_t verify; const uint8_t *cose_buf; - const uint8_t *cose_container; - size_t container_len; + const uint8_t *auth_container; + size_t auth_container_len; size_t cose_len = 0; /* It is a list of cose signatures */ - int res = nanocbor_get_bstr(it, &cose_container, &container_len); - if (res < 0) { - LOG_INFO("Unable to get COSE signature\n"); - return SUIT_ERR_INVALID_MANIFEST; - } - - nanocbor_value_t _cont, arr; - nanocbor_decoder_init(&_cont, cose_container, container_len); - - int rc = nanocbor_enter_array(&_cont, &arr); - if (rc < 0) { - LOG_INFO("Unable to enter COSE signatures\n"); - return SUIT_ERR_INVALID_MANIFEST; - } - - uint32_t tag; - nanocbor_get_tag(&arr, &tag); - arr.remaining++; - res = nanocbor_get_subcbor(&arr, &cose_buf, &cose_len); - if (res < 0) { - LOG_INFO("Unable to get subcbor: %d\n", res); - } - - res = cose_sign_decode(&verify, cose_buf, cose_len); - if (res < 0) { - LOG_INFO("Unable to parse COSE signature\n"); - return SUIT_ERR_INVALID_MANIFEST; - } - - /* Iterate over signatures, should only be a single signature */ - cose_signature_dec_t signature; - - cose_sign_signature_iter_init(&signature); - if (!cose_sign_signature_iter(&verify, &signature)) { - LOG_INFO("Unable to get signature iteration\n"); + if (nanocbor_get_bstr(it, &auth_container, &auth_container_len) < 0) { + LOG_INFO("Unable to get auth container\n"); return SUIT_ERR_INVALID_MANIFEST; } @@ -86,20 +53,55 @@ static int _auth_handler(suit_manifest_t *manifest, int key, cose_key_set_keys(&pkey, COSE_EC_CURVE_ED25519, COSE_ALGO_EDDSA, (uint8_t *)public_key, NULL, NULL); - LOG_INFO("suit: verifying manifest signature\n"); - int verification = cose_sign_verify(&verify, &signature, - &pkey, manifest->validation_buf, - SUIT_COSE_BUF_SIZE); - if (verification != 0) { - LOG_INFO("Unable to validate signature: %d\n", verification); - return SUIT_ERR_SIGNATURE; + nanocbor_value_t _cont, arr; + nanocbor_decoder_init(&_cont, auth_container, auth_container_len); + + int rc = nanocbor_enter_array(&_cont, &arr); + if (rc < 0) { + LOG_INFO("Unable to enter COSE signatures\n"); + return SUIT_ERR_INVALID_MANIFEST; } - manifest->cose_payload = verify.payload; - manifest->cose_payload_len = verify.payload_len; - manifest->state |= SUIT_STATE_COSE_AUTHENTICATED; + int res = SUIT_ERR_SIGNATURE; - return 0; + while (!nanocbor_at_end(&arr)) { + res = nanocbor_get_bstr(&arr, &cose_buf, &cose_len); + if (res < 0) { + LOG_INFO("Unable to get COSE bstr: %d\n", res); + return SUIT_ERR_INVALID_MANIFEST; + } + if (!(manifest->state & SUIT_STATE_COSE_AUTHENTICATED)) { + res = cose_sign_decode(&verify, cose_buf, cose_len); + if (res < 0) { + LOG_INFO("Unable to parse COSE signature\n"); + return SUIT_ERR_INVALID_MANIFEST; + } + /* Iterate over signatures, should only be a single signature */ + cose_signature_dec_t signature; + + cose_sign_signature_iter_init(&signature); + if (!cose_sign_signature_iter(&verify, &signature)) { + LOG_INFO("Unable to get signature iteration\n"); + return SUIT_ERR_INVALID_MANIFEST; + } + LOG_INFO("suit: verifying manifest signature\n"); + int verification = cose_sign_verify(&verify, &signature, + &pkey, manifest->validation_buf, + SUIT_COSE_BUF_SIZE); + if (verification == 0) { + manifest->state |= SUIT_STATE_COSE_AUTHENTICATED; + res = SUIT_OK; + manifest->cose_payload = verify.payload; + manifest->cose_payload_len = verify.payload_len; + } + else { + LOG_INFO("Unable to validate signature: %d\n", verification); + } + } + } + + + return res; } static int _manifest_handler(suit_manifest_t *manifest, int key, @@ -142,10 +144,10 @@ static int _manifest_handler(suit_manifest_t *manifest, int key, } /* begin{code-style-ignore} */ -const suit_manifest_handler_t suit_container_handlers[] = { +const suit_manifest_handler_t suit_envelope_handlers[] = { [SUIT_WRAPPER_AUTHENTICATION] = _auth_handler, [SUIT_WRAPPER_MANIFEST] = _manifest_handler, }; /* end{code-style-ignore} */ -const size_t suit_container_handlers_len = ARRAY_SIZE(suit_container_handlers); +const size_t suit_envelope_handlers_len = ARRAY_SIZE(suit_envelope_handlers); diff --git a/sys/suit/suit.c b/sys/suit/suit.c index 7ca96bc333..1473982049 100644 --- a/sys/suit/suit.c +++ b/sys/suit/suit.c @@ -42,8 +42,8 @@ int suit_parse(suit_manifest_t *manifest, const uint8_t *buf, manifest->buf = buf; manifest->len = len; nanocbor_decoder_init(&it, buf, len); - LOG_DEBUG("Starting container sequence handler\n"); + LOG_DEBUG("Starting envelope sequence handler\n"); return suit_handle_manifest_structure(manifest, &it, - suit_container_handlers, - suit_container_handlers_len); + suit_envelope_handlers, + suit_envelope_handlers_len); } diff --git a/sys/suit/transport/coap.c b/sys/suit/transport/coap.c index 93bb4bee73..6c63841e5e 100644 --- a/sys/suit/transport/coap.c +++ b/sys/suit/transport/coap.c @@ -42,6 +42,7 @@ #ifdef MODULE_SUIT #include "suit.h" +#include "suit/handlers.h" #endif #if defined(MODULE_PROGRESS_BAR) @@ -75,14 +76,26 @@ static char _url[SUIT_URL_MAX]; static uint8_t _manifest_buf[SUIT_MANIFEST_BUFSIZE]; #ifdef MODULE_SUIT -static inline void _print_download_progress(size_t offset, size_t len, - uint32_t image_size) +static inline void _print_download_progress(suit_manifest_t *manifest, + size_t offset, size_t len) { + (void)manifest; (void)offset; (void)len; - (void)image_size; DEBUG("_suit_flashwrite(): writing %u bytes at pos %u\n", len, offset); #if defined(MODULE_PROGRESS_BAR) + uint32_t image_size; + nanocbor_value_t param_size; + suit_param_ref_t *ref_size = + &manifest->components[manifest->component_current].param_size; + + /* Grab the total image size from the manifest */ + if ((suit_param_ref_to_cbor(manifest, ref_size, ¶m_size) == 0) || + (nanocbor_get_uint32(¶m_size, &image_size) < 0)) { + /* Early exit if the total image size can't be determined */ + return; + } + if (image_size != 0) { char _suffix[7] = { 0 }; uint8_t _progress = 100 * (offset + len) / image_size; @@ -419,7 +432,7 @@ int suit_flashwrite_helper(void *arg, size_t offset, uint8_t *buf, size_t len, return -1; } - _print_download_progress(offset, len, manifest->components[0].size); + _print_download_progress(manifest, offset, len); return riotboot_flashwrite_putbytes(writer, buf, len, more); }