imgtool: Add CBOR encoded boot record to TLV area
Add new '--boot-record' option for imgtool to add a new type of TLV to
the image manifest called BOOT_RECORD. This TLV contains CBOR encoded
data with some basic information about the image (SW component) it
belongs to, these are the following:
- SW type (role of the software component)
- SW version
- Signer ID (identifies the signing authority)
- Measurement value (hash of the image)
- Measurement type (algorithm used to calculate the measurement value)
The boot_record.py file and most of the modifications in image.py are
coming from the Trusted Firmware-M project
(https://www.trustedfirmware.org/about/).
Hash of the source commit: 08d5572b4bcee306d8cf709c2200359a22d5b72c.
This patch is based on the recommendations of Arm's Platform Security
Architecture (PSA) and its purpose is to support compliance with it.
Change-Id: I379ccc57b48ad2311837cb3fd90f5f9d1c9b5bac
Signed-off-by: David Vincze <david.vincze@linaro.org>
diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py
index 9701e21..644a028 100644
--- a/scripts/imgtool/image.py
+++ b/scripts/imgtool/image.py
@@ -19,6 +19,7 @@
"""
from . import version as versmod
+from .boot_record import create_sw_component_data
import click
from enum import Enum
from intelhex import IntelHex
@@ -42,6 +43,7 @@
MAX_ALIGN = 8
DEP_IMAGES_KEY = "images"
DEP_VERSIONS_KEY = "versions"
+MAX_SW_TYPE_LENGTH = 12 # Bytes
# Image header flags.
IMAGE_F = {
@@ -63,6 +65,7 @@
'ENCEC256': 0x32,
'DEPENDENCY': 0x40,
'SEC_CNT': 0x50,
+ 'BOOT_RECORD': 0x60,
}
TLV_SIZE = 4
@@ -256,9 +259,18 @@
format=PublicFormat.UncompressedPoint)
return cipherkey, ciphermac, pubk
- def create(self, key, enckey, dependencies=None):
+ def create(self, key, enckey, dependencies=None, sw_type=None):
self.enckey = enckey
+ # Calculate the hash of the public key
+ if key is not None:
+ pub = key.get_public_bytes()
+ sha = hashlib.sha256()
+ sha.update(pub)
+ pubbytes = sha.digest()
+ else:
+ pubbytes = bytes(hashlib.sha256().digest_size)
+
protected_tlv_size = 0
if self.security_counter is not None:
@@ -266,6 +278,32 @@
# = 4 + 4 = 8 Bytes
protected_tlv_size += TLV_SIZE + 4
+ if sw_type is not None:
+ if len(sw_type) > MAX_SW_TYPE_LENGTH:
+ msg = "'{}' is too long ({} characters) for sw_type. Its " \
+ "maximum allowed length is 12 characters.".format(
+ sw_type, len(sw_type))
+ raise click.UsageError(msg)
+
+ image_version = (str(self.version.major) + '.'
+ + str(self.version.minor) + '.'
+ + str(self.version.revision))
+
+ # The image hash is computed over the image header, the image
+ # itself and the protected TLV area. However, the boot record TLV
+ # (which is part of the protected area) should contain this hash
+ # before it is even calculated. For this reason the script fills
+ # this field with zeros and the bootloader will insert the right
+ # value later.
+ digest = bytes(hashlib.sha256().digest_size)
+
+ # Create CBOR encoded boot record
+ boot_record = create_sw_component_data(sw_type, image_version,
+ "SHA256", digest,
+ pubbytes)
+
+ protected_tlv_size += TLV_SIZE + len(boot_record)
+
if dependencies is not None:
# Size of a Dependency TLV = Header ('HH') + Payload('IBBHI')
# = 4 + 12 = 16 Bytes
@@ -293,6 +331,9 @@
payload = struct.pack(e + 'I', self.security_counter)
prot_tlv.add('SEC_CNT', payload)
+ if sw_type is not None:
+ prot_tlv.add('BOOT_RECORD', boot_record)
+
if dependencies is not None:
for i in range(dependencies_num):
payload = struct.pack(
@@ -319,10 +360,6 @@
tlv.add('SHA256', digest)
if key is not None:
- pub = key.get_public_bytes()
- sha = hashlib.sha256()
- sha.update(pub)
- pubbytes = sha.digest()
tlv.add('KEYHASH', pubbytes)
# `sign` expects the full image payload (sha256 done internally),