Internet-Draft | Secure Reporting of Update Status | September 2023 |
Moran & Birkholz | Expires 14 March 2024 | [Page] |
The Software Update for the Internet of Things (SUIT) manifest provides a way for many different update and boot workflows to be described by a common format. However, this does not provide a feedback mechanism for developers in the event that an update or boot fails.¶
This specification describes a lightweight feedback mechanism that allows a developer in possession of a manifest to reconstruct the decisions made and actions performed by a manifest processor.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 14 March 2024.¶
Copyright (c) 2023 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
A SUIT manifest processor can fail to install or boot an update for many reasons. Frequently, the error codes generated by such systems fail to provide developers with enough information to find root causes and produce corrective actions, resulting in extra effort to reproduce failures. Logging the results of each SUIT command can simplify this process.¶
While it is possible to report the results of SUIT commands through existing logging or attestation mechanisms, this comes with several drawbacks:¶
The CBOR objects defined in this document allow devices to:¶
This document provides a definition of a SUIT-specific logging container that may be used in a variety of scenarios.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
Terms used in this specification include:¶
If the developer can be assumed to have a copy of the manifest, then they need little information to reconstruct what the manifest processor has done. They simply need any data that influences the control flow of the manifest. The manifest only supports the following control flow primitives:¶
Of these, only conditions change the behavior of the processor from the default, and then only when the condition fails.¶
Then, to reconstruct the flow of a manifest, all a developer needs is a list of metadata about failed conditions:¶
Most conditions compare a parameter to an actual value, so the "reason" is typically simply the actual value.¶
Since it is possible that a non-condition command (directive) may fail in an exceptional circumstance, this must be included as well. However, a failed directive will terminate processing of the manifest. To accommodate for a failed command and for explicit "completion," an additional "result" element is added as well. In the case of a command failure, the failure reason is typically a numeric error code. However, these error codes need to be standardised in order to be useful.¶
Reconstructing what a device has done in this way is compact, however it requires some reconstruction effort. This is an issue that can be solved by tooling.¶
SUIT_Record = [ suit-record-manifest-id : [* uint ], suit-record-manifest-section : int, suit-record-section-offset : uint, suit-record-component-index : uint, suit-record-properties : SUIT_Parameters, $$SUIT_Record_Extensions ]¶
suit-record-manifest-id is used to identify which manifest contains the command that caused the record to be generated. The manifest id is a list of integers that form a walk of the manifest tree, starting at the root. An empty list indicates that the command was contained in the root manifest. If the list is not empty, the command was contained in one of the root manifest's dependencies, or nested even further below that.¶
For example, suppose that the root manifest has 3 dependencies and each of those dependencies has 2 dependencies of its own:¶
Root¶
A manifest-id of [1,0] would indicate that the current command was contained within Dependency B0. Similarly, a manifest-id of [2,1] would indicate Dependency C1¶
suit-record-manifest-section indicates which section of the manifest was active. This is used in addition to an offset so that the developer can index into severable sections in a predictable way. The value of this element is the value of the key that identified the section in the manifest.¶
suit-record-section-offset is the number of bytes into the current section at which the current command is located.¶
suit-record-component-index is the index of the component that was specified at the time that the report was generated. This field is necessary due to the availability of set-current-component values of True and a list of components. Both of these values cause the manifest processor to loop over commands using a series of component-ids, so the developer needs to know which was selected when the command executed.¶
suit-record-properties contains any measured properties that led to the command failure. For example, this could be the actual value of a SUIT_Digest or class identifier. This is encoded in a SUIT_Parameters block as defined in [I-D.ietf-suit-manifest].¶
Some metadata is common to all records, such as the root manifest: the manifest that is the entry-point for the manifest processor. This metadata is aggregated with a list of SUIT_Records. The SUIT_Report may also contain a list of any system properties that were measured and reported, and a reason for a failure if one occured.¶
SUIT_Report = { suit-reference => SUIT_Reference, ? suit-report-nonce => bstr, suit-report-records => [ * SUIT_Record / system-property-claims ], suit-report-result => true / { suit-report-result-code => int, ; could condense to enum later suit-report-result-record => SUIT_Record, } $$SUIT_Report_Extensions } system-property-claims = { system-component-id => SUIT_Component_Identifier, + SUIT_Parameters, }¶
The suit-reference provides a reference URI and digest for a suit manifest. The uri SHOULD be the canonical URI that is provided in the manifest. The digest is the digest of the manifest.¶
NOTE: The digest is used in preference to other identifiers in the manifest because it allows a manifest to be uniquely identified (collision resistance) whereas other identifiers, such as the sequence number, can collide, particularly in scenarios with multiple trusted signers.¶
The following CDDL describes a SUIT_Reference.¶
SUIT_Reference = { suit-report-manifest-uri : tstr, suit-report-manifest-digest : SUIT_Digest, }¶
suit-report-manifest-digest provides a SUIT_Digest (as defined in [I-D.ietf-suit-manifest]) that is the characteristic digest of the Root manifest.¶
suit-report-manifest-uri provides the reference URI that was provided in the root manifest.¶
suit-report-nonce provides a container for freshness or replay protection information. This field MAY be omitted where the suit-report is authenticated within a container that provides freshness already. For example, attestation evidence typically contains a proof of freshness.¶
suit-report-records is a list of 0 or more SUIT Records or system-property-claims. Because SUIT Records are only generated on failure, in simple cases this can be an empty list. SUIT_Records and suit-system-property-claims are merged into a single list because this reduces the overhead for a constrained node that generates this report. The use of a single append-only log allows report generators to use simple memory management. Because the system-property-claims are encoded as maps and SUIT_Records are encoded as lists, a recipient need only filter the CBOR Type-5 entries from suit-report-records to obtain all system-property-claims.¶
System properties can be extracted from suit-report-records by filtering suit-report-records for maps. System Properties are a list of measured or asserted properties of the system that creates the SUIT_Report. These properties are scoped by component identifier. Because this list is expected to be constructed on the fly by a constrained node, component identifiers may appear more than once. A recipient may convert the result to a more conventional structure:¶
SUIT_Record_System_Properties = { * component-id => { + SUIT_Parameters, } }¶
suit-report-result provides a mechanism to show that the SUIT procedure completed successfully (value is true) or why it failed (value is a map of an error code and a SUIT_Record).¶
The suit-report-result-code indicates the reason for the failure. Values are expected to be CBOR parsing failures, Schema validation failures, COSE validation failures or SUIT processing failures.¶
The suit-report-result-record indicates the exact point in the manifest or manifest dependency tree where the error occured.¶
This document describes how a well-informed verifier can infer the trustworthiness of a remote device. Remote attestation is done by using the SUIT_Manifest_Envelope along with the SUIT_Report to reconstruct the state of the device at boot time. By embedding data used for remote attestation in the SUIT_Report, a remote device can use an append-only log to collect both measurements and debug/failure information into the same document. This document can then be conveyed to a verifier as a part of the attestation evidence. A remote attestation format to convey attestation evidence, such as an Entity Attestation Token (EAT, see [I-D.ietf-rats-eat]), that contains a SUIT_Report MUST also include an integrity measurement of the Manifest Processor & Report Generator.¶
When a Concise Reference Integrity Manifest (CoRIM, see [I-D.birkholz-rats-corim] is delivered in a SUIT_Manifest_Envelope, this codifies the delivery of verification information to the verifier:¶
The Firmware Distributor:¶
The Recipient:¶
The Verifier:¶
This approach simplifies the design of the bootloader since it is able to use an append-only log. It allows a verifier to validate this report against a signed CoRIM that is provided by the firmware author, which simplifies the delivery chain of verification information to the verifier.¶
This information is not intended as Attestation Evidence and while an Attestation Report MAY provide this information for conveying error codes and/or failure reports, it SHOULD be translated into general-purpose claims for use by the Relying Party.¶
Because SUIT is extensible, a manifest author must know what capabilities a device has available. To enable this, a capability report is a set of lists that define which commands, parameters, algorithms, and component IDs are supported by a manifest processor.¶
The CDDL for a SUIT_Capability_Report follows:¶
SUIT_Capability_Report = { suit-component-capabilities => [+ SUIT_Component_Capability ] suit-command-capabilities => [+ int], suit-parameters-capabilities => [+ int], suit-crypt-algo-capabilities => [+ int], ? suit-envelope-capabilities => [+ int], ? suit-manifest-capabilities => [+ int], ? suit-common-capabilities => [+ int], ? suit-text-component-capabilities => [+ int], ? suit-text-capabilities => [+ int], ? suit-dependency-capabilities => [+ int], * [+int] => [+ int], $$SUIT_Capability_Report_Extensions } SUIT_Component_Capability = [*bstr,?true]¶
A SUIT_Component_Capability is similar to a SUIT_Component_ID, with one difference: it may optionally be terminated by a CBOR 'true' which acts as a wild-card match for any component with a prefix matching the SUIT_Component_Capability leading up to the 'true.' This feature is for use with filesystem storage, key value stores, or any other arbitrary-component-id storage systems.¶
When reporting capabilities, it is OPTIONAL to report capabilities that are declared mandatory by the SUIT Manifest [I-D.ietf-suit-manifest]. Capabilities defined by extensions MUST be reported.¶
Additional capability reporting can be added as follows: if a manifest element does not exist in this map, it can be added by specifying the CBOR path to the manifest element in an array and using this as the key. For example SUIT_Dependencies, as described in [I-D.ietf-suit-trust-domains] could have an extension added, which was key 3 in the SUIT_Dependencies map. This capability would be reported as: [3, 3, 1] => [3], where the key consists of the key for SUIT_Manifest (3), the key for SUIT_Common (3), and the key for SUIT_Dependencies (1). Then the value indicates that this manifest processor supports the extension (3).¶
The SUIT_Report is a form of measurement done by the SUIT Manifest Processor as it attempts to invoke a manifest or install a manifest. As a result, the SUIT_Report can be captured in an EAT measurements type. The Verifier MAY convert a SUIT_Report into a more consumable version of the EAT claim by, for example, constructing a measres claim that contains the digest of a component, the vendor ID & class ID of a component, etc.¶
The SUIT_Report MUST be carried in a container or transport that ensures authenticity. The SUIT_Report MUST be transported using one of the following options:¶
In this case, the SUIT_Report is carried as sole payload of a COSE_Encrypt0 or COSE_Sign1 as shown in the CDDL snippet below.¶
SUIT_Report_Protected /= SUIT_Report_COSE_Sign1 .and SUIT_COSE_Profiles SUIT_Report_Protected /= SUIT_Report_COSE_Sign1_Tagged .and SUIT_COSE_Profiles SUIT_Report_Protected /= SUIT_Report_COSE_MAC0 .and SUIT_COSE_Profiles SUIT_Report_Protected /= SUIT_Report_COSE_MAC0_Tagged .and SUIT_COSE_Profiles SUIT_Report_COSE_Sign1_Tagged = #6.18(SUIT_Report_COSE_Sign1) SUIT_Report_COSE_Sign1 = [ protected : bstr, unprotected : {* int => any}, payload : bstr .cbor SUIT_Report_Unprotected, signature : bstr ] SUIT_Report_COSE_MAC0_Tagged = #6.17(SUIT_Report_COSE_MAC0) SUIT_Report_COSE_MAC0 = [ protected : bstr, unprotected : {* int => any}, payload : bstr .cbor SUIT_Report_Unprotected, tag : bstr ] SUIT_Report_Unprotected = SUIT_Report / SUIT_Report_COSE_Encrypt0 SUIT_Report_COSE_Encrypt0 = COSE_Encrypt0¶
Note that SUIT_Report_COSE_Sign1 and SUIT_Report_COSE_MAC0 MUST be combined with a SUIT_COSE_Profile from [I-D.ietf-suit-mti] using the CDDL .and directive. The SUIT_Report_COSE_Encrypt0 carries a ciphertext payload that MUST contain just the ciphertext obtained by encrypting the following CDDL:¶
SUIT_Report_plaintext = bstr .cbor SUIT_Report¶
SUIT_COSE_Profiles define only AES-CTR encryption due to its suitability for firmware distribution. Because AES-CTR is not authenticated, SUIT_Report_Protected defines authenticated containers with an encrypted payload.¶
IANA is requested to allocate a CBOR tag and a coap content-type each for the SUIT_Report, SUIT_Reference, and SUIT_Capability_Report CBOR data structures.¶
IANA is also requested to add a table to the SUIT page for SUIT_Capability_Report_Extensions.¶
There are two aspects to the security considerations for SUIT reports: authenticity and confidentiality. SUIT reports must have guaranteed authenticity for them to be useful. Several options are available to ensure the authenticity of a SUIT report. The report MAY be bundled as the payload of a cryptographic container as described in Section 8. communicated over a secure transport. It may also be communicated as part of an existing authenticated protocol, such as within an EAT token. Ideally, the SUIT_Report SHOULD be communicated as part of an attestation flow, such as within an EAT token, since this proves the authenticity of the environment (hardware, software, or both) in which the SUIT_Report was generated.¶
The SUIT_Report MAY require confidentiality as well. A SUIT_Report could potentially reveal confidential information about the kinds of device that a particular user has. It could also reveal confidential information about intellectual property contained in a device. Where these concerns are relevant, the SUIT_Report MUST be encrypted, for example using a COSE_Encrypt as described in Section 8, or by using secure transport.¶
There are also operational considerations that intersect with these security considerations. In situations where the SUIT report is encrypted as an element of a message within another protocol, care must be taken to ensure that this does not leak information and that the principle of least privilege is respected. For example, in an EAT-based attestation workflow, the Verifier often will not need the full SUIT Report. Similarly, the Relying Party may also not need the SUIT_Report. In this case, the SUIT_Report MUST be encrypted even if the EAT token that contains it is also encrypted.¶
In contrast, however, there are scenarios where the EAT Verifier consumes the SUIT report and translates it into one or more other EAT claims. For example, a SUIT report that shows a particular digest was matched using an suit-condition-image can be translated into a EAT measres (Measurement Results) claim. In this scenario, the Verifier must have access to the full SUIT_Report.¶
The authors would like to thank Dave Thaler for his feedback.¶