Boot: Add dependency check to multi-image boot
This patch adds the capability to check image dependencies in case
of multi-image boot. The dependencies are described with a new type
of TLV in the manifest.
Change-Id: If45f81a00d4324c881634f50156f9939e1bf8707
Signed-off-by: David Vincze <david.vincze@arm.com>
diff --git a/docs/design.md b/docs/design.md
index 6573c25..93c0383 100644
--- a/docs/design.md
+++ b/docs/design.md
@@ -64,12 +64,12 @@
struct image_header {
uint32_t ih_magic;
uint32_t ih_load_addr;
- uint16_t ih_hdr_size; /* Size of image header (bytes). */
- uint16_t _pad2;
- uint32_t ih_img_size; /* Does not include header. */
- uint32_t ih_flags; /* IMAGE_F_[...]. */
+ uint16_t ih_hdr_size; /* Size of image header (bytes). */
+ uint16_t ih_protect_tlv_size; /* Size of protected TLV area (bytes). */
+ uint32_t ih_img_size; /* Does not include header. */
+ uint32_t ih_flags; /* IMAGE_F_[...]. */
struct image_version ih_ver;
- uint32_t _pad3;
+ uint32_t _pad1;
};
/** Image TLV header. All fields in little endian. */
@@ -102,11 +102,20 @@
#define IMAGE_TLV_ECDSA256 0x22 /* ECDSA of hash output */
#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */
#define IMAGE_TLV_ED25519 0x24 /* ED25519 of hash output */
+#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */
+#define IMAGE_TLV_ENC_KW128 0x31 /* Key encrypted with AES-KW-128 */
+#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */
```
Optional type-length-value records (TLVs) containing image metadata are placed
after the end of the image.
+The `ih_protect_tlv_size` field indicates the length of the protected TLV area.
+If dependency TLVs are present then the TLV info header and the dependency TLVs
+are also protected and have to be included in the hash calculation. Otherwise
+the hash is only calculated over the image header and the image itself. In this
+case the value of the `ih_protect_tlv_size` field is 0.
+
The `ih_hdr_size` field indicates the length of the header, and therefore the
offset of the image itself. This field provides for backwards compatibility in
case of changes to the format of the image header.
@@ -522,11 +531,15 @@
| Scratch |
+--------------------+
```
-The multiple image boot procedure is organized in loops which iterate over all
-the firmware images. The high-level overview of the boot process is presented
-below.
-
-Procedure:
+MCUBoot is also capable of handling dependencies between images. For example
+if an image needs to be reverted it might be necessary to revert another one too
+(e.g. due to API incompatibilities) or simply to prevent from being updated
+because of an unsatisfied dependency. Therefore all aborted swaps have to be
+completed and all the swap types have to be determined for each image before
+the dependency checks. Dependency handling is described in more detail in a
+following section. The multiple image boot procedure is organized in loops which
+iterate over all the firmware images. The high-level overview of the boot
+process is presented below.
+ ###### Loop 1. Iterate over all images
1. Inspect swap status region of current image; is an interrupted swap being
@@ -557,9 +570,15 @@
+ Skip to next image.
+ ###### Loop 2. Iterate over all images
- At this point there are no aborted swaps and the swap types are determined
- for each image.
+ 1. Does the current image depend on other image(s)?
+ + Yes: Are all the image dependencies satisfied?
+ + Yes: Skip to next image.
+ + No:
+ + Modify swap type depending on what the previous type was.
+ + Restart dependency check from the first image.
+ + No: Skip to next image.
++ ###### Loop 3. Iterate over all images
1. Is an image swap requested?
+ Yes:
+ Perform image update operation.
@@ -567,8 +586,7 @@
+ Skip to next image.
+ No: Skip to next image.
-+ ###### Loop 3. Iterate over all images
-
++ ###### Loop 4. Iterate over all images
1. Validate image in the primary slot (integrity and security check) or
at least do a basic sanity check to avoid booting into an empty flash
area.
@@ -842,3 +860,51 @@
If you want to enable and use encrypted images, see:
[encrypted_images](encrypted_images.md).
+
+## Dependency Check
+
+MCUBoot can handle multiple firmware images. It is possible to update them
+independently but in many cases it can be desired to be able to describe
+dependencies between the images (e.g. to ensure API compliance and avoid
+interoperability issues).
+
+The dependencies between images can be described with additional TLV entries in
+the TLV area after the end of an image. There can be more than one dependency
+entry, but in practice if the platform only supports two individual images then
+there can be maximum one entry which reflects to the other image.
+
+If the TLV area contains dependency TLV entries, then these are required to be
+integrity and authenticity protected. In this case the SHA256 has to be
+calculated over not just the image header and the image but also the TLV info
+header and the dependency TLVs.
+```
+A +---------------------+
+ | Header | <- struct image_header
+ +---------------------+
+ | Payload |
+ +---------------------+
+ | TLV area |
+ | +-----------------+ |
+ | | TLV area header | | <- struct image_tlv_info
+ | +-----------------+ |
+ | | Dependency | | <- Dependency entry (struct image_tlv)
+B | +-----------------+ |
+ | | SHA256 hash | | <- hash from A - B (struct image_tlv)
+C | +-----------------+ |
+ | | Keyhash | | <- indicates which pub. key for sig (struct image_tlv)
+ | +-----------------+ |
+ | | Signature | | <- signature from B - C (struct image_tlv), only hash
+ | +-----------------+ |
+ +---------------------+
+```
+At the phase of dependency check all aborted swaps are finalized if there were
+any. During the dependency check the boot loader verifies whether the image
+dependencies are all satisfied. If at least one of the dependencies of an image
+is not fulfilled then the swap type of that image has to be modified
+accordingly and the dependency check needs to be restarted. This way the number
+of unsatisfied dependencies will decrease or remain the same. There is always at
+least 1 valid configuration. In worst case, the system returns to the initial
+state after dependency check.
+
+For more information on adding dependency entries to an image,
+see: [imgtool](imgtool.md).
diff --git a/docs/imgtool.md b/docs/imgtool.md
index 9d71746..7e17105 100644
--- a/docs/imgtool.md
+++ b/docs/imgtool.md
@@ -58,6 +58,7 @@
-k, --key filename
--align [1|2|4|8] [required]
-v, --version TEXT [required]
+ -d, --dependencies TEXT
-H, --header-size INTEGER [required]
--pad-header Add --header-size zeroed bytes at the beginning
of the image
@@ -95,3 +96,9 @@
The optional `--pad` argument will place a trailer on the image that
indicates that the image should be considered an upgrade. Writing this image
in the secondary slot will then cause the bootloader to upgrade to it.
+
+A dependency can be specified in the following way:
+`-d "(image_id, image_version)"`. The `image_id` is the number of the image
+which the current image depends on. The `image_version` is the minimum version
+of that image to satisfy compliance. For example `-d "(1, 1.2.3+0)"` means this
+image depends on Image 1 which version has to be at least 1.2.3+0.