2020-02-26 14:48:24 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2019 Koen Zandberg
|
|
|
|
* 2020 Inria
|
|
|
|
*
|
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
|
|
* directory for more details.
|
|
|
|
*/
|
|
|
|
/**
|
2020-02-26 14:49:35 +01:00
|
|
|
* @ingroup sys_suit
|
2020-02-26 14:48:24 +01:00
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* @file
|
2020-02-26 14:49:35 +01:00
|
|
|
* @brief SUIT Handlers for the command sequences in the common section of
|
2020-02-26 14:52:39 +01:00
|
|
|
* a SUIT manifest.
|
|
|
|
*
|
|
|
|
* This file contains the functions to handle command sequences from a SUIT
|
|
|
|
* manifest. This includes both directives and conditions.
|
2020-02-26 14:48:24 +01:00
|
|
|
*
|
|
|
|
* @author Koen Zandberg <koen@bergzand.net>
|
|
|
|
*
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <nanocbor/nanocbor.h>
|
2020-03-23 10:07:28 +01:00
|
|
|
#include <assert.h>
|
2020-02-26 14:48:24 +01:00
|
|
|
|
|
|
|
#include "kernel_defines.h"
|
|
|
|
#include "suit/conditions.h"
|
|
|
|
#include "suit/handlers.h"
|
|
|
|
#include "suit/policy.h"
|
|
|
|
#include "suit.h"
|
|
|
|
#include "riotboot/hdr.h"
|
|
|
|
#include "riotboot/slot.h"
|
|
|
|
|
2020-02-26 14:49:35 +01:00
|
|
|
#ifdef MODULE_SUIT_TRANSPORT_COAP
|
|
|
|
#include "suit/transport/coap.h"
|
|
|
|
#endif
|
|
|
|
|
2020-02-26 14:48:24 +01:00
|
|
|
#include "log.h"
|
|
|
|
|
2020-03-23 10:07:28 +01:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
2020-02-26 14:48:24 +01:00
|
|
|
static int _validate_uuid(suit_manifest_t *manifest,
|
2020-03-23 10:07:28 +01:00
|
|
|
suit_param_ref_t *ref,
|
2020-02-26 14:48:24 +01:00
|
|
|
uuid_t *uuid)
|
|
|
|
{
|
|
|
|
const uint8_t *uuid_manifest_ptr;
|
|
|
|
size_t len = sizeof(uuid_t);
|
2020-03-23 10:07:28 +01:00
|
|
|
nanocbor_value_t it;
|
|
|
|
|
|
|
|
if ((suit_param_ref_to_cbor(manifest, ref, &it) == 0) ||
|
|
|
|
(nanocbor_get_bstr(&it, &uuid_manifest_ptr, &len) < 0)) {
|
2020-02-26 14:48:24 +01:00
|
|
|
return SUIT_ERR_INVALID_MANIFEST;
|
|
|
|
}
|
|
|
|
|
2020-03-23 10:07:28 +01:00
|
|
|
char uuid_str[UUID_STR_LEN + 1];
|
|
|
|
char uuid_str2[UUID_STR_LEN + 1];
|
2020-02-26 14:48:24 +01:00
|
|
|
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);
|
2020-03-23 10:07:28 +01:00
|
|
|
|
2020-02-26 14:48:24 +01:00
|
|
|
return uuid_equal(uuid, (uuid_t *)uuid_manifest_ptr)
|
|
|
|
? SUIT_OK
|
|
|
|
: SUIT_ERR_COND;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _cond_vendor_handler(suit_manifest_t *manifest,
|
|
|
|
int key,
|
|
|
|
nanocbor_value_t *it)
|
|
|
|
{
|
|
|
|
(void)key;
|
2020-03-23 10:07:28 +01:00
|
|
|
(void)it;
|
2020-02-26 14:48:24 +01:00
|
|
|
LOG_INFO("validating vendor ID\n");
|
2020-03-23 10:07:28 +01:00
|
|
|
suit_component_t *comp = _get_component(manifest);
|
|
|
|
int rc = _validate_uuid(manifest, &comp->param_vendor_id,
|
|
|
|
suit_get_vendor_id());
|
2020-02-26 14:48:24 +01:00
|
|
|
if (rc == SUIT_OK) {
|
|
|
|
LOG_INFO("validating vendor ID: OK\n");
|
|
|
|
manifest->validated |= SUIT_VALIDATED_VENDOR;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _cond_class_handler(suit_manifest_t *manifest,
|
|
|
|
int key,
|
|
|
|
nanocbor_value_t *it)
|
|
|
|
{
|
|
|
|
(void)key;
|
2020-03-23 10:07:28 +01:00
|
|
|
(void)it;
|
2020-02-26 14:48:24 +01:00
|
|
|
LOG_INFO("validating class id\n");
|
2020-03-23 10:07:28 +01:00
|
|
|
suit_component_t *comp = _get_component(manifest);
|
|
|
|
int rc = _validate_uuid(manifest, &comp->param_class_id,
|
|
|
|
suit_get_class_id());
|
2020-02-26 14:48:24 +01:00
|
|
|
if (rc == SUIT_OK) {
|
|
|
|
LOG_INFO("validating class id: OK\n");
|
|
|
|
manifest->validated |= SUIT_VALIDATED_CLASS;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _cond_comp_offset(suit_manifest_t *manifest,
|
|
|
|
int key,
|
|
|
|
nanocbor_value_t *it)
|
|
|
|
{
|
|
|
|
(void)manifest;
|
|
|
|
(void)key;
|
|
|
|
uint32_t offset;
|
2020-03-23 10:07:28 +01:00
|
|
|
uint32_t report;
|
2020-02-26 14:48:24 +01:00
|
|
|
|
2020-03-23 10:07:28 +01:00
|
|
|
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");
|
2020-02-26 14:48:24 +01:00
|
|
|
return SUIT_ERR_INVALID_MANIFEST;
|
|
|
|
}
|
2020-03-23 10:07:28 +01:00
|
|
|
nanocbor_value_t param_offset;
|
|
|
|
suit_param_ref_to_cbor(manifest, &comp->param_component_offset,
|
|
|
|
¶m_offset);
|
|
|
|
nanocbor_get_uint32(¶m_offset, &offset);
|
2020-02-26 14:48:24 +01:00
|
|
|
uint32_t other_offset = (uint32_t)riotboot_slot_offset(
|
|
|
|
riotboot_slot_other());
|
|
|
|
|
2020-03-23 10:07:28 +01:00
|
|
|
LOG_INFO("Comparing manifest offset %"PRIx32" with other slot offset %"PRIx32"\n",
|
|
|
|
offset, other_offset);
|
2020-02-26 14:48:24 +01:00
|
|
|
return other_offset == offset ? SUIT_OK : SUIT_ERR_COND;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _dtv_set_comp_idx(suit_manifest_t *manifest,
|
|
|
|
int key,
|
|
|
|
nanocbor_value_t *it)
|
|
|
|
{
|
|
|
|
(void)key;
|
2020-03-23 10:07:28 +01:00
|
|
|
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;
|
2020-02-26 14:48:24 +01:00
|
|
|
}
|
2020-03-23 10:07:28 +01:00
|
|
|
/* It can be a positive integer, meaning one of the components */
|
|
|
|
else if (nanocbor_get_uint32(it, &new_index) < 0) {
|
2020-02-26 14:48:24 +01:00
|
|
|
return SUIT_ERR_INVALID_MANIFEST;
|
|
|
|
}
|
2020-03-23 10:07:28 +01:00
|
|
|
/* And if it is an integer it must be within the allowed bounds */
|
|
|
|
else if (new_index >= CONFIG_SUIT_COMPONENT_MAX) {
|
2020-02-26 14:49:35 +01:00
|
|
|
return SUIT_ERR_INVALID_MANIFEST;
|
|
|
|
}
|
2020-03-23 10:07:28 +01:00
|
|
|
|
|
|
|
/* Update the manifest context */
|
|
|
|
manifest->component_current = new_index;
|
|
|
|
LOG_INFO("Setting component index to %d\n",
|
2020-02-26 14:48:24 +01:00
|
|
|
(int)manifest->component_current);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _dtv_run_seq_cond(suit_manifest_t *manifest,
|
|
|
|
int key,
|
|
|
|
nanocbor_value_t *it)
|
|
|
|
{
|
|
|
|
(void)key;
|
|
|
|
LOG_DEBUG("Starting conditional sequence handler\n");
|
|
|
|
return suit_handle_manifest_structure_bstr(manifest, it,
|
2020-02-26 14:52:39 +01:00
|
|
|
suit_command_sequence_handlers,
|
|
|
|
suit_command_sequence_handlers_len);
|
2020-02-26 14:48:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int _dtv_try_each(suit_manifest_t *manifest,
|
|
|
|
int key, nanocbor_value_t *it)
|
|
|
|
{
|
|
|
|
(void)key;
|
|
|
|
LOG_DEBUG("Starting suit-directive-try-each handler\n");
|
|
|
|
nanocbor_value_t container;
|
|
|
|
|
|
|
|
if ((nanocbor_enter_array(it, &container) < 0) &&
|
|
|
|
(nanocbor_enter_map(it, &container) < 0)) {
|
|
|
|
return SUIT_ERR_INVALID_MANIFEST;
|
|
|
|
}
|
|
|
|
|
|
|
|
int res = SUIT_ERR_COND;
|
|
|
|
while (!nanocbor_at_end(&container)) {
|
|
|
|
nanocbor_value_t _container = container;
|
|
|
|
/* `_container` should be CBOR _bstr wrapped according to the spec, but
|
|
|
|
* it is not */
|
2020-03-23 10:07:28 +01:00
|
|
|
res = suit_handle_manifest_structure_bstr(manifest, &_container,
|
|
|
|
suit_command_sequence_handlers,
|
|
|
|
suit_command_sequence_handlers_len);
|
2020-02-26 14:48:24 +01:00
|
|
|
|
|
|
|
nanocbor_skip(&container);
|
|
|
|
|
|
|
|
if (res != SUIT_ERR_COND) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _dtv_set_param(suit_manifest_t *manifest, int key,
|
|
|
|
nanocbor_value_t *it)
|
|
|
|
{
|
|
|
|
(void)key;
|
|
|
|
/* `it` points to the entry of the map containing the type and value */
|
|
|
|
nanocbor_value_t map;
|
|
|
|
|
|
|
|
nanocbor_enter_map(it, &map);
|
|
|
|
|
2020-03-23 10:07:28 +01:00
|
|
|
suit_component_t *comp = _get_component(manifest);
|
|
|
|
|
2020-02-26 14:48:24 +01:00
|
|
|
while (!nanocbor_at_end(&map)) {
|
|
|
|
/* map points to the key of the param */
|
|
|
|
int32_t param_key;
|
2020-03-23 10:07:28 +01:00
|
|
|
if (nanocbor_get_int32(&map, ¶m_key) < 0) {
|
|
|
|
return SUIT_ERR_INVALID_MANIFEST;
|
|
|
|
}
|
2020-02-26 14:48:24 +01:00
|
|
|
LOG_DEBUG("param_key=%" PRIi32 "\n", param_key);
|
2020-03-23 10:07:28 +01:00
|
|
|
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;
|
2020-02-26 14:48:24 +01:00
|
|
|
switch (param_key) {
|
2020-03-23 10:07:28 +01:00
|
|
|
case SUIT_PARAMETER_VENDOR_IDENTIFIER:
|
|
|
|
ref = &comp->param_vendor_id;
|
2020-02-26 14:48:24 +01:00
|
|
|
break;
|
2020-03-23 10:07:28 +01:00
|
|
|
case SUIT_PARAMETER_CLASS_IDENTIFIER:
|
|
|
|
ref = &comp->param_class_id;
|
2020-02-26 14:48:24 +01:00
|
|
|
break;
|
2020-03-23 10:07:28 +01:00
|
|
|
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;
|
2020-02-26 14:48:24 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOG_DEBUG("Unsupported parameter %" PRIi32 "\n", param_key);
|
2020-03-23 10:07:28 +01:00
|
|
|
return SUIT_ERR_UNSUPPORTED;
|
2020-02-26 14:48:24 +01:00
|
|
|
}
|
|
|
|
|
2020-03-23 10:07:28 +01:00
|
|
|
suit_param_cbor_to_ref(manifest, ref, &map);
|
2020-02-26 14:48:24 +01:00
|
|
|
|
2020-03-23 10:07:28 +01:00
|
|
|
/* Simple skip is sufficient to skip non-complex types */
|
|
|
|
nanocbor_skip(&map);
|
2020-02-26 14:48:24 +01:00
|
|
|
}
|
|
|
|
return SUIT_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _dtv_fetch(suit_manifest_t *manifest, int key,
|
|
|
|
nanocbor_value_t *_it)
|
|
|
|
{
|
|
|
|
(void)key; (void)_it;
|
|
|
|
LOG_DEBUG("_dtv_fetch() key=%i\n", key);
|
|
|
|
|
|
|
|
const uint8_t *url;
|
|
|
|
size_t url_len;
|
2020-09-26 11:59:32 +02:00
|
|
|
|
|
|
|
/* Check the policy before fetching anything */
|
|
|
|
int res = suit_policy_check(manifest);
|
|
|
|
if (res) {
|
|
|
|
return SUIT_ERR_POLICY_FORBIDDEN;
|
|
|
|
}
|
|
|
|
|
2020-03-23 10:07:28 +01:00
|
|
|
suit_component_t *comp = _get_component(manifest);
|
2020-02-26 14:48:24 +01:00
|
|
|
|
2020-09-26 12:30:24 +02:00
|
|
|
/* Deny the fetch if the component was already fetched before */
|
|
|
|
if (suit_component_check_flag(comp, SUIT_COMPONENT_STATE_FETCHED)) {
|
|
|
|
LOG_ERROR("Component already fetched before\n");
|
|
|
|
return SUIT_ERR_INVALID_MANIFEST;
|
|
|
|
}
|
|
|
|
|
2020-03-23 10:07:28 +01:00
|
|
|
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);
|
2020-02-26 14:48:24 +01:00
|
|
|
if (err < 0) {
|
|
|
|
LOG_DEBUG("URL parsing failed\n)");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
memcpy(manifest->urlbuf, url, url_len);
|
|
|
|
manifest->urlbuf[url_len] = '\0';
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2020-09-26 11:59:32 +02:00
|
|
|
res = -1;
|
2020-02-26 14:48:24 +01:00
|
|
|
|
|
|
|
if (0) {}
|
|
|
|
#ifdef MODULE_SUIT_TRANSPORT_COAP
|
|
|
|
else if (strncmp(manifest->urlbuf, "coap://", 7) == 0) {
|
|
|
|
res = suit_coap_get_blockwise_url(manifest->urlbuf, COAP_BLOCKSIZE_64,
|
|
|
|
suit_flashwrite_helper,
|
|
|
|
manifest);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef MODULE_SUIT_TRANSPORT_MOCK
|
|
|
|
else if (strncmp(manifest->urlbuf, "test://", 7) == 0) {
|
|
|
|
res = SUIT_OK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else {
|
|
|
|
LOG_WARNING("suit: unsupported URL scheme!\n)");
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-09-26 12:30:24 +02:00
|
|
|
suit_component_set_flag(comp, SUIT_COMPONENT_STATE_FETCHED);
|
|
|
|
|
2020-02-26 14:48:24 +01:00
|
|
|
if (res) {
|
2020-09-26 12:30:24 +02:00
|
|
|
suit_component_set_flag(comp, SUIT_COMPONENT_STATE_FETCH_FAILED);
|
|
|
|
/* TODO: The leftover data from a failed fetch should be purged. It
|
|
|
|
* could contain potential malicous data from an attacker */
|
|
|
|
LOG_INFO("image download failed with code %i\n", res);
|
2020-02-26 14:48:24 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DEBUG("Update OK\n");
|
|
|
|
return SUIT_OK;
|
|
|
|
}
|
|
|
|
|
2020-03-23 10:07:28 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-02-26 14:48:24 +01:00
|
|
|
static int _dtv_verify_image_match(suit_manifest_t *manifest, int key,
|
|
|
|
nanocbor_value_t *_it)
|
|
|
|
{
|
|
|
|
(void)key; (void)_it;
|
|
|
|
LOG_DEBUG("dtv_image_match\n");
|
|
|
|
const uint8_t *digest;
|
|
|
|
size_t digest_len;
|
|
|
|
int target_slot = riotboot_slot_other();
|
2020-03-23 10:07:28 +01:00
|
|
|
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;
|
|
|
|
}
|
2020-02-26 14:48:24 +01:00
|
|
|
|
2020-09-26 12:30:24 +02:00
|
|
|
/* Only check the component if it is fetched, but not failed */
|
|
|
|
if (!suit_component_check_flag(comp, SUIT_COMPONENT_STATE_FETCHED) ||
|
|
|
|
suit_component_check_flag(comp, SUIT_COMPONENT_STATE_FETCH_FAILED)) {
|
|
|
|
LOG_ERROR("Fetch failed, or nothing fetched, nothing to check: %u\n",
|
|
|
|
comp->state);
|
|
|
|
return SUIT_ERR_INVALID_MANIFEST;
|
|
|
|
}
|
|
|
|
|
2020-02-26 14:48:24 +01:00
|
|
|
LOG_INFO("Verifying image digest\n");
|
2020-03-23 10:07:28 +01:00
|
|
|
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);
|
|
|
|
|
2020-02-26 14:48:24 +01:00
|
|
|
if (res < 0) {
|
|
|
|
LOG_DEBUG("Unable to parse digest structure\n");
|
|
|
|
return SUIT_ERR_INVALID_MANIFEST;
|
|
|
|
}
|
|
|
|
|
2020-03-23 10:07:28 +01:00
|
|
|
res = riotboot_flashwrite_verify_sha256(digest,
|
|
|
|
img_size,
|
2020-02-26 14:48:24 +01:00
|
|
|
target_slot);
|
|
|
|
if (res != 0) {
|
|
|
|
return SUIT_ERR_COND;
|
|
|
|
}
|
2020-09-26 14:25:12 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* SUIT transport mock doesn't implement the the 'finish' function. Can be
|
|
|
|
* removed as soon as there is a proper storage abstraction layer for SUIT
|
|
|
|
*/
|
|
|
|
if (!IS_ACTIVE(MODULE_SUIT_TRANSPORT_MOCK)) {
|
|
|
|
riotboot_flashwrite_finish(manifest->writer);
|
|
|
|
}
|
2020-02-26 14:48:24 +01:00
|
|
|
return SUIT_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* begin{code-style-ignore} */
|
2020-02-26 14:52:39 +01:00
|
|
|
const suit_manifest_handler_t suit_command_sequence_handlers[] = {
|
2020-02-26 14:48:24 +01:00
|
|
|
[SUIT_COND_VENDOR_ID] = _cond_vendor_handler,
|
|
|
|
[SUIT_COND_CLASS_ID] = _cond_class_handler,
|
|
|
|
[SUIT_COND_IMAGE_MATCH] = _dtv_verify_image_match,
|
|
|
|
[SUIT_COND_COMPONENT_OFFSET] = _cond_comp_offset,
|
|
|
|
[SUIT_DIR_SET_COMPONENT_IDX] = _dtv_set_comp_idx,
|
|
|
|
[SUIT_DIR_TRY_EACH] = _dtv_try_each,
|
|
|
|
[SUIT_DIR_SET_PARAM] = _dtv_set_param,
|
|
|
|
[SUIT_DIR_OVERRIDE_PARAM] = _dtv_set_param,
|
|
|
|
[SUIT_DIR_FETCH] = _dtv_fetch,
|
|
|
|
[SUIT_DIR_RUN_SEQUENCE] = _dtv_run_seq_cond,
|
|
|
|
};
|
|
|
|
/* end{code-style-ignore} */
|
|
|
|
|
2020-02-26 14:52:39 +01:00
|
|
|
const size_t suit_command_sequence_handlers_len = ARRAY_SIZE(suit_command_sequence_handlers);
|