Subject: [Suit] [suit]: draft-moran-suit-manifest-02

From: Brendan Moran <[email-masked]>
Date: Tue, 3 Jul 2018 21:08:02 +0000

This draft is a significant departure from previous drafts, so I think it is important to highlight the changes. The draft requires a lot of text that hasn’t been written yet, so I will try to put some of that here for discussion.

https://datatracker.ietf.org/doc/draft-moran-suit-manifest/

# Summary of changes
There are a large number of changes in this draft. In addition, the text description of the manifest is yet to be completed. The top level manifest element remains a CBOR array. The primary reason for this is that many of the initial elements are mandatory (see the information model for more detail). In addition to this, the ordering is important because the manifest is a signed document. COSE uses the same paradigm: where fields are mandatory, they are encoded as an array. Where there are optional fields (COSE_Headers) they are encoded as a map (if unsigned) or as a map, wrapped in a bstr if signed.

The primary changes are:

1. Severable text
2. Digest Info is moved to a top-level element
3. Sequence number is now called sequence number instead of timestamp
4. Conditions are divided into preconditions and postconditions
5. Dependencies, Aliases, and payload info are now resources
6. Payloadinfo is divided into resources, processors, and targets

# Severable text:
Text is for humans. Devices shouldn’t parse it. Therefore, we have moved text information out of the manifest. However, humans need to know that the text they are reading correctly corresponds to the manifest they are looking at. Therefore, we have made a container for a COSE_Sign / COSE_Mac and a map of text values. In addition to this, the text values are hashed and the hash is included in the manifest to ensure that the text portion is not modified or corrupted in transit.

This means that, while a manifest with text may be delivered to an update server, that server can strip off the text and deliver only the authenticated, machine-readable part to a target device. This results in reduced bandwidth, reduced buffer sizes, more expressive text information, and reduced opportunity to abuse variably sized fields.

# Digest info at the top level
Digests are used in many places in the manifest. The information required to interpret digests, therefore, must be a top-level element. All digests in any given manifest must use the same digest algorithm.

# Sequence Number
The use of timestamp as sequence number has caused confusion regularly, so we have changed timestamp to sequence number in this draft.

# PreConditions and PostConditions
There has been significant debate about the use of preconditions and postconditions, with several important use cases. Because of this, conditions has been divided into preconditions and postconditions.

# Dependencies, Aliases, PayloadInfo
Each of these has very similar information. Because of this, it seems reasonable to group them into a common structure that just identifies the type of reference.

# Resources, Processors, Targets
To satisfy complex requirements, we considered several use-cases:

Differential update of a dual XIP MCU. To accomplish this and still obtain good compression, the installed image must be un-relocated, then a diff must be applied, then the resulting image must be relocated, then written to storage. This is even more complicated if the diff is compressed and encrypted. Furthermore, there are some differential algorithms that will need to be able to read the data they have written, which means that the target image must also be possible to read, un-relocate, and feed into the differential unpacking engine.

Shared compression table. Several components of an update may be delivered with a single common compression table. If this is the case, then each target image must be decompressed using two inputs: the compressed file and the compression table

The result of this is that we concluded that resources and targets cannot considered the same. While they are the same in the “raw binary” case, and they still appear to be the same in linear-processing case (where all processors have only one input and one output), once differential compression, table compression, and relocation are considered, it is clear that, since processors can require multiple inputs, there must be a way to describe each of these inputs. This clarifies that resources are distinct from the final image that is installed to a device.

Because of this distinction and in order to describe complex use-cases, we have included a mechanism of describing the resources as input nodes to a graph, the installation targets as output nodes from the graph, and the intermediate states as internal nodes of the graph, where each processor forms an edge on the graph.

For the installation of any given target, we expect that this graph could be reduced to a tree with an installation target at the root.

In the simple case, a raw binary payload, one resource is required, identifying an output node, and one installation target is required, identifying the same node as an input node.

Describing this structure as a graph, rather than a tree for each target is a design tradeoff. We believe that the graph as several advantages. First, it reduces the nesting depth of the CBOR parser. This is an important consideration for how much memory is consumed. Second, it allows a validator to iterate over the graph and identify whether it supports each specified processor without any comprehension of the tree structures or graph connectedness. Third, it eliminates repetitive description of resources and intermediates that are used in multiple trees, which could be used to eliminate download (resource acquisition) and processing overhead. We don’t think that the reduction in manifest size would be significant.

As always, your input is most welcome!

Thanks,
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: Kvamtrø, Frank Audun <[email-masked]>
Date: Wed, 4 Jul 2018 09:04:56 +0000

Having a single digest in manifest requirement may be a bit restrictive. There
are new standards in draft like the CNSA
(https://tools.ietf.org/id/draft-jenkins-cnsa-cert-crl-profile-02.html) that
requires SHA-384 instead of the SHA-256 that is commonly used. I wonder if there
will be requirements to support multiple digest types at the same time.

The DigestInfo in a manifest could be used as a source for pre-validation of the
supported feature set, and in this mindset I think it wouldn't be difficult to
add support for multiple digest types with some small change. If the DigestInfo
is an array of types supported instead of a single entry, then the restriction
goes away.

I also wonder if the digests should also contain the digest type (i.e. an
enumerated value). It shouldn't be too costly in size, and it would have some
immediate benefits:

    1. Simple bootloaders can use post-conditions without expressive
       requirements to understand additional data from the manifest formats.
       This could be used for basic validation of copy routines
    2. The Post-conditions can be stored after the update to signify the
       "current state" of the firmware, with little to no extra information
       to describe how to process them
    3. Post-conditions can be concatenated from multiple manifests, as they
       are more-or-less self-contained.

Regards
Frank Audun Kvamtrø

From: Suit [mailto:[email-masked]] On Behalf Of Brendan Moran
Sent: 3. juli 2018 23:08
To: suit <[email-masked]>
Cc: Hannes Tschofenig <[email-masked]>
Subject: [Suit] [suit]: draft-moran-suit-manifest-02

# Summary of changes

The primary changes are:

1. Severable text

# Severable text:

# Sequence Number

Thanks,
Brendan

---

From: Rønningstad, Øyvind <[email-masked]>
Date: Fri, 6 Jul 2018 13:50:38 +0000

How about making more information severable (like with text)? Some information is short-lived, like the processing steps, while other information could be of interest after the update is complete, like the postConditions and sequence number. I'm wondering if we can make a split, so the relevant parts of the manifest can be stored for later reference. Something like the following:

AuthenticatedManifest = [
  authenticatedManifest: COSE_Mac / COSE_Sign,
  updateProcess:         bstr .cbor UpdateProcess,
  text:                  bstr .cbor TextMap,
]

UpdateProcess = [
  nonce :              bstr,
  textReference :      bstr,
  preConditions :      [ * PreCondition ],
  directives :         [ * Directive ],
  resources :          [ * ResourceInfo ],
  processors :         [ * ProcessingStep ],
  targets :            [ * TargetInfo ],
  extensions :         { * int => bstr}
]

Manifest = [
  manifestVersion :    1,
  digestInfo :         DigestInfo,
  sequence :           SequenceNumber,
  postConditions :     [ * PostCondition ],
  processReference :   bstr ; Digest of the update process, so it can later be discarded.
]

Øyvind

# Summary of changes

The primary changes are:

1. Severable text

# Severable text:

# Sequence Number

Thanks,
Brendan

---

From: David Brown <[email-masked]>
Date: Mon, 9 Jul 2018 13:16:51 -0600

On Tue, Jul 03, 2018 at 09:08:02PM +0000, Brendan Moran wrote:
>This draft is a significant departure from previous drafts, so I think it is
>important to highlight the changes. The draft requires a lot of text that
>hasn’t been written yet, so I will try to put some of that here for discussion.
>
>[1]https://datatracker.ietf.org/doc/draft-moran-suit-manifest/

>Digests are used in many places in the manifest. The information required to
>interpret digests, therefore, must be a top-level element. All digests in any
>given manifest must use the same digest algorithm.

Is this possibly overly constraining?  For very resource-constrained
devices, it is reasonable to expect the device to only have a single
digest algorithm available in it.  Would we want another digest
algorithm available to allow higher-processing systems to perhaps use
a stronger check.

I think if we want require a single digest format per manifest, there
should at least be motivating text for doing it this way, as well as
why there is only a single digest allowed per entity.

David

---

From: David Brown <[email-masked]>
Date: Wed, 11 Jul 2018 11:44:23 -0600

On Fri, Jul 06, 2018 at 01:50:38PM +0000, Rønningstad, Øyvind wrote:

>How about making more information severable (like with text)? Some information
>is short-lived, like the processing steps, while other information could be of
>interest after the update is complete, like the postConditions and sequence
>number. I'm wondering if we can make a split, so the relevant parts of the
>manifest can be stored for later reference. Something like the following:

I have another proposal for this.

Motivation: The manifest will be processed by different entities that
will differ in processing capability.  We want to make it easy to
include potentially complex information in the manifest, without
having to burden lower-resource entities that don't need to process
this information.  The goal is to make the manifest format more
generally processable.

Proposal: Assocate with each entity in the manifest additional
information describing the audience for that information.  

One way to do this would be to change the top-level of the manifest to
something like:

Manifest = [
  manifestVersion: 1,
  digestInfo:      DigestInfo,
  sequence:        SequenceNumber,
  info:            { * int => bstr }
]

This would be similar to how extensions are handled, except that all
of the existing instructions would be formatted in the same way.  A
given entity would know the fields that it is able to process, and any
other fields it can simply skip (as it is just a bstr).

This adds some complexity to the normal processing, and it would be
important to require, for example that the entries in 'info' are in
order by key in order to have a canonical representation.

David

---

From: David Brown <[email-masked]>
Date: Wed, 11 Jul 2018 11:47:26 -0600

>  extensions :         { * int => bstr}

The textReference has to be in the Manifest that is covered by the
signature.  As stated here, none of the updateProcess or text
information is covered by a signature.

This could be done by moving textReference above into the Manifest, as
well as adding an updateProcessReference that would contain a digest
of the updateProcess.  This adds complexity to verifying this
additional information, but would indeed then allow them to be
severed, while still being covered by the signature.

David

---

From: David Brown <[email-masked]>
Date: Wed, 11 Jul 2018 11:48:47 -0600

Sorry, most of this can be ignored, as I missed the processReference
field in the Manifest.  I would still suggest putting the
textReference in the Manifest as well so that it doesn't require as
deep of nesting to verify the text.

David

---

From: Kvamtrø, Frank Audun <[email-masked]>
Date: Thu, 12 Jul 2018 08:35:29 +0000

Glad the meaning sunk in. I think we get into some small problems by creating
names that aren't self-explanatory. Especially if they are duplicated and/or
represented in a few different ways in the format.

We agree that we could place the textReference in the manifest so that we know 
what to discard at a later stage. It will make it easy for a simple bootloader 
to do the information severing, if it only needs to keep the signature and/or 
manifest after the update...

I've rewritten the initial idea by Øyvind for severability with the 
textReference  (now named textDigest) in the main manifest. I've also renamed 
the processReference to be updateProcessDigest. Stating digest in the instance 
name makes it easier for humans to parse IMHO.

; Example of extracting long-lived information so it can be stored while 
; short-lived processing info is discarded.

UpdateProcess = [
  nonce :              bstr,
 
Manifest = [
  manifestVersion :     1,
  digestInfo :          DigestInfo,
  sequence :            SequenceNumber,
  postConditions :      [ * PostCondition ],
  updateProcessDigest : bstr,
  textDigest :          bstr
]

I'm still a bit curious why DigestInfo needs to be split away from the digests.
I would like to support multiple digest-types through a manifest and I would
naturally assume the same methodology as the TLS standard - i.e. prepending the 
digest type with the digest (enum + digest content). It even allows for a TV 
encoding of the data instead of TLV (if need be). I'm not arguing against
removing the DigestInfo structure, in case there is a need for parameter data. 
But I think there should be little penalty changing the digestInfo  in the 
manifest to an array of DigestInfos, and using an enum/int identifier to 
reference between the digests and the DigestInfo...

Regards
Frank Audun Kvamtrø

> -----Original Message-----
> From: Suit [mailto:[email-masked]] On Behalf Of David Brown
> Sent: 11. juli 2018 19:49
> To: Rønningstad, Øyvind <[email-masked]>
> Cc: Hannes Tschofenig <[email-masked]>; suit <[email-masked]>;
> Brendan Moran <[email-masked]>
> Subject: Re: [Suit] [suit]: draft-moran-suit-manifest-02
> 
> Sorry, most of this can be ignored, as I missed the processReference field in the
> Manifest.  I would still suggest putting the textReference in the Manifest as well
> so that it doesn't require as deep of nesting to verify the text.
> 
> David
> 
> >well as adding an updateProcessReference that would contain a digest of
> >the updateProcess.  This adds complexity to verifying this additional
> >information, but would indeed then allow them to be severed, while
> >still being covered by the signature.
> >
> >David
> 
> _______________________________________________
> Suit mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/suit

---

From: David Brown <[email-masked]>
Date: Fri, 13 Jul 2018 10:18:48 -0600

>[1]https://datatracker.ietf.org/doc/draft-moran-suit-manifest/

Yesterday, I spent some time going through this draft to try and
create an example manifest based on how MCUboot currently behaves.  I
found many things that I wasn't clear on the meaning of, and wasn't
quite certain how to structure the manifest for my, what I believe, is
a fairly simple case.

In addition, I feel there is an assumption in the manifest that the
processing will be done in two parts:

   1. Parse the CBOR into some kind of in-memory data structure.
   2. Traverse this structure in various ways, making decisions and
      performing processing.

This is a lot to ask of code on a resource-constrained device, where
we likely are going to only have tens of kB of code space available.
I would like to consider making the manifest in such a manner that it
is possible to construct at least a simple version that can be
processed linearly (in CBOR order).

## What MCUboot does

Targets using MCUboot currently use a manifest format that is combined
directly with the image.  It is formatted something like:

         -----------------------
         | Header
         |   ...
         |   Image length
         |   ...
         -----------------------
         | Padding
         -----------------------
         | Execute in place
         |   firmware image
         | ...
         -----------------------
         | Manifest header
         -----------------------
         | TLV encoded manifest
         +----------------------

The flash memory is divided as follows:

         +-------------------------
         | Bootloader
         +-------------------------
         | Slot 0
         |    XIP Application Code
         +-------------------------
         | Slot 1
         |    Update image
         +-------------------------
         | Scratch
         +-------------------------

The two actors involve that are running on the MCU are: 1. The update
application, and 2. MCUboot itself.

The update application is code combined with the normal application
running on the target.  It is responsible for downloading this image,
possibly verifying it, and writing it into flash in Slot 1.  This code
is part of the image running in slot 0.  Once this is written, it
reboots.

MCUboot, upon boot, checks slot 1 for a manifest, and if there is a
valid update present, performs either a "swap", exchanging the data in
slot 0 and slot 1 (using scratch to be robust against power loss), or
overwrites slot 1 onto slot 0 (depends on how it is configured).  It
then verifies the image in slot 0, and if valid transfers control into
the XIP image in slot 0.

The TLV manifest is currently quite simple, an essentialy consists of
a series of steps that MCUboot walks through.  These steps can consist
of:

    - Compute a hash of the image and compare with XXXXX
    - Verify a signature of the hash using a built-in public key.

There can be multiple signatures, generally to support either multiple
algorithms, or to support multiple signers.  When it completes the
processing, it checks that it did indeed verify a hash, and at least
one signature, at which point it will boot.

## Encoding this in a SUIT manifest.

My initial assumption was that we could place the SUIT manifest in the
above images where the current Manifest header and TLV manifest live.
It would not be difficult to distinguish between a COSE_Sign block and
the existing header, although it is unlikely that the code could be
compiled to include processing for both formats.

I envision the processing something along the lines of:

   1.  MCUboot decodes the COSE_Sign data.  Although COSE seems to
   also assume that it will be decoded into RAM and processed there,
   it isn't too difficult to simply record decoded offsets, and
   construct the Sig_structure virtually, invoking the hash algorithm
   incrementally.  My initial guess is that the code to process this
   would take perhaps 2-3 times as much code to process as the current
   TLV processing.  The result will be a pointer and length to the
   payload, which is the SUIT manifest.

   2.  MCUboot then decodes the SUIT manifest.  The goal is for it to
   determine: 1. Does this manifest describe the attached image, 2. Is
   the manifest applicable, and 3.  Should it do an image swap (for
   example if the newer image is in slot 1).

In light of this, I tried to come up with a sample manifest, but it
wasn't clear to me where and what things should be conveyed in it.
Keep in mind that ideally, the manifest could be processed in a single
pass, possibly with a small amount of RAM used to point back to key
information gained.  I came up with the following:

   - The preconditions would be one or more IdConditions to associated
     the image with a particular device.  This adds functionality to
     what MCUboot currently does.

   - Possibly a 'dependency' resource (functionality needed for future
     multiple image work).

   - A payload resource that describes the payload this manifest is
     attached to.

Perhaps this is sufficient for this use case.  Given that I don't
understand what the 'inode' and 'onode' fields represent, I'm not sure
how processors and targets would be configured to describe this.
Maybe they are intended for a more complex use case.  I will send
another email about my confusion in this regard.

Given the above, in the manifest, the 'digestInfo', 'textReference',
'nonce', and 'sequence' would have meaningful values.  There would
probably be some 'preConditions', and 'resources', but the rest of the
arrays would be blank.  Does my interpretation seem reasonable? Or
would it also be expected that the processing and/or directives be
involved in this case.

For our use case, the two actors perform different steps, and it may
not even be meaningful to encode that information in the manifest.  If
we do want to encode the steps to perform, something would need to be
added to indicate which actor is supposed to perform which steps.

David

---

From: David Brown <[email-masked]>
Date: Fri, 13 Jul 2018 10:39:41 -0600

>[1]https://datatracker.ietf.org/doc/draft-moran-suit-manifest/

In this email, I wanted to enumerate the parts of the current manifest
draft that are either unclear to me (possibly just needing more
explanation) and/or should be reworked.

1.  Signature contents.

A few things need to be spelled out about the COSE_Mac and COSE_Sign
blocks:

  - The payload should be a "Manifest".

  - What is the content type used for this.  Presumably, we will
    register one for a SUIT manifest, when the RFC is finalized, but
    it does need to be stated.  Just stating it is CBOR could also
    work, but then a processor would have to look into the payload to
    determine if it is a manifest.

  - Is the CBOR for the manifest tagged?  If so, we should register a
    tag for our manifest format.

2.  DigestInfo

We need to define the values for digestAlgorithm, and what is
contained in digestParameters.  Are these related to the values
defined in COSE, or at least do they come from the same number space?

3.  Encoding of ProcessingStep, Pre and Post conditions.

Using different arrays with the first element of the array is a number
indicating the meaning of the remainder of the array is different than
how I've seen other data represented in CBOR.  I'm presuming that this
is so that order can preserved, where as a map would require a
specific order for a canonical encoding.  I don't know the
ramifications of this on processing code.  It is certainly legal from
CBOR's point of view.

Other possibilities would be to have the fields be an array of pairs,
similar to how a map would be encoded, but described as an array so
that order could be preserved.  I don't know if this can be
represented in CDDL.

It could also be an array of maps.  The grouping simply used to allow
ordering to be enforced when that is needed.

4.  The Directive encoding

The CDDL grammar allows the "=>" to be used inside of an array (so
this parses), but there are no example or explanation of what this
would mean.  Do we intend for the Directive to be a map, or are we
hoping to have something of an ordered map, similar to what I
described above as an array of pairs.

5.  Use of numbers.

We have numerous fields that make use of small integers.  Is the
intent that these be fixed, and any additional values only be allowed
in the 'extensions' field?

6.  Extensions.

The extensions are described as maps.  Do we envision a case where
ordering needs to be preserved in extensions?

In addition, do we need to have something similar to the criticality
header in COSE where a manifest can say certain extensions are
mandatory, and that an actor that doesn't understand that extension
should reject the manifest?

Thanks,
David