Subject: [Suit] Some proposals for updates to the SUIT manifest specification

From: Brendan Moran <[email-masked]>
Date: Wed, 24 Jun 2020 11:28:39 +0000

The other authors and I have been working on refining the specification and filling in some empty parts. There are three topics we’d like to discuss with the working group: First, the text section. Second, the list of Dependency Components. Finally, bstr wrapped fields.

The text section has been misaligned with the rest of the document since multiple components were introduced. Currently, there’s no way to provide a list of component versions, for example. To remedy this, we're proposing a small change to the text section. Today, the text section says:

> SUIT_Text_Map = {SUIT_Text_Keys => tstr}

This should really be:

> SUIT_Text_Map = { SUIT_Text_Keys }
> SUIT_Text_Keys = (
>  ? suit-text-manifest-description => text,
>  ? suit-text-update-description => text,
>  ? suit-text-vendor-name => text,
>  ? suit-text-model-name => text,
>  ? suit-text-vendor-domain => text,
>  ? suit-text-model-info => text,
>  ? suit-text-component-description => text,
>  ? suit-text-manifest-json-source => text,
>  ? suit-text-manifest-yaml-source => text,
>  * $$suit-text-key-extensions)
> )

Notice that there is only one component-specific field, but it is plain text. This is a poor match for the current structure of the suit manifest.

Here is our proposal to correct the mismatch between the manifest and the text section:

> SUIT_Text_Map = {
>  * SUIT_Component_Identifier => { SUIT_Text_Component_Keys },
>  SUIT_Text_Keys,
> }

This will allow any set of components to be described.

The second point is Dependency Components. This information element was introduced to help distinguish between components that are defined in the current manifest and those that are defined by its dependencies. This is a loose definition, however, and I don’t believe that it fits the current definition of the manifest. I believe we should remove Dependency Components. There are two consequences of this action:

1) A parser must validate that all components of a given interdependent set are specified in a given tree of manifests. This was necessary anyway due to Access Control requirements: A parser cannot trust the root manifest to list all components if the signer of that manifest does not have access rights for every component. The result is that this makes the security story clearer.

2) A parser cannot inspect the root manifest to determine whether it can handle enough components to process all component IDs simultaneously. The same security considerations as 1) apply here: the list could only ever have been treated as a hint, it had to be verified during tree traversal. To resolve the missing component count evaluation, The parser can compute the number of required components during either the dependency resolution step (Update flow) or the system validation step (Secure boot flow) in order to test whether it has sufficient memory to handle the components in parallel, or if it must handle them sequentially.

Finally, I have a question regarding the fields wrapped in byte strings. Are the byte strings necessary? I’d like to hear from those who have implemented the specification. Are the byte strings helpful? Or are they pain points?

Here is the justification for them that I drafted to add to the design rationale section of the specification:

> Byte string wrappers are used in several places in the suit manifest. The primary reason for wrappers it to limit the parser extent when invoked at different times, with a possible loss of context.
>
> The elements of the suit envelope are wrapped both to set the extents used by the parser and to simplify integrity checks by clearly defining the length of each element.
>
> The common block is re-parsed in order to find components identifiers from their indices, to find dependency prefixes and digests from their identifiers, and to find the common sequence. The common sequence is wrapped so that it matches other sequences, simplifying the code path.
>
> A severed SUIT command sequence will appear in the envelope, so it must be wrapped as with all envelope elements. For consistency, command sequences are also wrapped in the manifest. This also allows the parser to discern the difference between a command sequence and a SUIT_Digest.
>
> Parameters that are structured types (arrays and maps) are also wrapped in a bstr. This is so that parser extents can be set correctly using only a reference to the beginning of the parameter. This enables a parser to store a simple list of references to parameters that can be retrieved when needed.

My opinion on each of the bstrs is:

1) We must keep the bstr wrappers around all envelope elements.
2) I think we should keep the bstr around structured parameters (Arrays/Maps). This is very useful for late parsing of parameters because they do not always live within the extent of the current manifest.
3) I’m not entirely sure we should keep the bstr wrapper around the common block, but I think it’s useful. It always lives within the extent of the current manifest, so overruns will be detected on the first pass by the parser, and the extent of the common block can be recorded prior to the execution of any command sequences.
4) I would not argue against removing the bstr wrappers around command sequences, provided that we register a tag for either the command sequence or the SUIT Digest.
5) I think we could safely remove the bstr wrappers around the elements inside of the common block, including the command sequence. This incurs a negligible execution time overhead when accessing some common elements, but produces manifests that are a few bytes smaller.

We would very much appreciate input on each of these three topics. Unless there are strong objections, we will modify the text section as described and remove the Dependency Components list. The status of the bstr wrappers is less clear, so we will wait for feedback.

Best Regards,
Brendan

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

---

From: Brendan Moran <[email-masked]>
Date: Tue, 30 Jun 2020 13:57:02 +0000

Hi Koen,

Thanks for taking time to assess the impact of these proposals. I haven’t dealt with the text section yet either!

More comments inline...

Best Regards,
Brendan

On 30 Jun 2020, at 13:20, Koen Zandberg <[email-masked]<mailto:[email-masked]>> wrote:

On 24 Jun 2020, at 12:28, Brendan Moran <[email-masked]<mailto:[email-masked]>> wrote:

SUIT_Text_Map = {

If I understand correctly, this creates a map with mixed bstr/integer
keys. I agree with what you already mentioned, it's not intended for
constrained nodes, this should be fine.

Yes, the idea here was that it’s problematic to rely on the order being the same between the components listed in common and components listed in Text. Because of this, we can list them by component identifier. We could also use an array and have a key for the component ID, but this breaks the semantic of (int => text) pairs. Henk suggested that we could just use the component ID itself to act as the key for the map. This means that we don’t have to add additional hierarchy for, e.g. a list of components.

The other option would be a map of components with component index as key. This would produce less duplication of component IDs (though I don’t think we care about that) and fit the semantics used elsewhere.

I’m ambivalent about which of these to use, but I think we need one of the two. For clarity, I think we should choose one of the two following structures:

Option 1:
SUIT_Text_Map = {

Option 2:
SUIT_Text_Map = {
  ? suit-text-components => { * (uint => { SUIT_Text_Component_Keys } ) },
  SUIT_Text_Keys,
}

The tree traversals for extracting a list of components are much simpler in Option 2, but it introduces a non-text value for a numeric key, which I don’t like. I’m split. Maybe there’s a way to make one of these two cleaner.

To explain what I don’t like about Option 1, imagine that you extract the text section into a hash map. If you want to render a list of affected components, you have to find them all in the map first. That means you need to get a list of all keys and test the type of each one to see if it’s numeric (text) or an array of bstr (Component ID). This means that even finding out how many components there are is O(n). With the Option 2, finding all the components is O(1).

To be clear, I’m not saying that the processing complexity is a big concern to me, I’m just saying it’s a good illustration of what I dislike about Option 1. I’m not saying that me mildly disliking this is a deal-breaker. I’m just wondering if we can come up with something better.

Input welcome!

Remaining question from my
side, is `suit-text-version-dependencies` the human readable form of
`suit-parameter-version`? Noticing that the description of
`suit-text-version-dependencies` mentions that it is a list, does it
require a similar treatment as the component text?

Yes, I believe that’s correct. It should also be a list. Actually, I think that might be easier to solve. I would move the suit-text-version-dependencies key out of the manifest text, into component text. Now, components version dependencies can just be present in the component list, and the suit-text-version-dependencies does not need to be a list.

The second point is Dependency Components. This information element was introduced to help distinguish between components that are defined in the current manifest and those that are defined by its dependencies. This is a loose definition, however, and I don’t believe that it fits the current definition of the manifest. I believe we should remove Dependency Components. There are two consequences of this action:
...
No real opinion on this yet. What you say makes sense. Is there an
implementation around supporting multiple components? The parser in RIOT
supports only a single component. If there is no guarantee that the
dependency component information is correct then in my opinion it can be
removed from the spec.

I haven’t seen a multi-component implementation yet. It sounds like we’re all on the same page. I’ll remove the dependency components section.

...

1) We must keep the bstr wrappers around all envelope elements.
Yes please, this is one of the few places where they really help.
2) I think we should keep the bstr around structured parameters (Arrays/Maps). This is very useful for late parsing of parameters because they do not always live within the extent of the current manifest.
I also strongly agree here. Exactly what you say, allows for
significantly easier iterating over parameters with late parsing.

Sounds like we’re aligned here.

I think the other option is that we could use separate keys for digest and for command sequence. What I don’t like about that option is that it’s not clear what a device should do if both are present and one of the goals of this specification is to eliminate that kind of uncertainty. That being the case, I think I would want a SUIT_Digest tag or a SUIT_Command_Sequence tag. Probably a Command Sequence tag, since that would make the manifest smaller when including digests.

5) I think we could safely remove the bstr wrappers around the elements inside of the common block, including the command sequence. This incurs a negligible execution time overhead when accessing some common elements, but produces manifests that are a few bytes smaller.
I think these last three can also be removed, but I'm not completely
confident yet on this. I think we've discussed this before, any CBOR
structure that is optional to parse by the parser must allow for
skipping it, and skipping a complex structured parameter is relative
costly in CBOR parsers. I think (for now) that anything that must be
parsed doesn't need to be bstring wrapped. This aligns with keeping the
bstr wrappers on the envelope elements, the authentication is handled by
a separate COSE library and can be skipped by the SUIT parser. With late
parameter parsing it is also essential that all parameter values are
simple CBOR structures, which is the case when maps/lists are bstr wrapped.
We would very much appreciate input on each of these three topics. Unless there are strong objections, we will modify the text section as described and remove the Dependency Components list. The status of the bstr wrappers is less clear, so we will wait for feedback.

I'll get back to you on this as soon as I have numbers for the last 3
bstr options.

I look forward to your feedback!

Koen