Reference ROM_EXT Manifest Format

Contributors(s): Sam Elliott, Garret Kelly, Silvestrs Timofejevs, Miguel Osorio

Status: Draft

This describes the signed image format for a ROM_EXT image. This format is based on the requirements outlined in the Reference Mask ROM Secure Boot Description.

ROM_EXTs are the second boot stage in the Reference Secure Boot implementation. ROM_EXTs are supplied by the Silicon Creator. ROM_EXTs are programmed into the chip’s flash.

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|                      manifest_identifier                      |
|                          - reserved -                         |
|                                                               |
+                                                               +
|                                                               |
+                  image_signature (3072 bits)                  +
|                                                               |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  break  ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|                                                               |
|                          image_length                         |
|                         image_version                         |
|                                                               |
+                        image_timestamp                        +
|                                                               |
|                 signature_key_public_exponent                 |
|                          - reserved -                         |
|                                                               |
+                                                               +
|                                                               |
+                  usage_constraints (256 bits)                 +
|                                                               |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  break  ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|                                                               |
|                                                               |
+                                                               +
|                                                               |
+                    peripheral_lockdown_info                   +
|                                                               |
+                                                               +
|                                                               |
|                                                               |
+                                                               +
|                                                               |
+               signature_key_modulus (3072 bits)               +
|                                                               |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  break  ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|                                                               |
|                       extension0_offset                       |
|                      extension0_checksum                      |
|                       extension1_offset                       |
|                      extension1_checksum                      |
|                       extension2_offset                       |
|                      extension2_checksum                      |
|                       extension3_offset                       |
|                      extension3_checksum                      |
|                                                               |
+                                                               +
|                                                               |
+                           code image                          +
|                                                               |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  break  ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|                                                               |


  • All Offsets in the manifest are specified in bytes from the beginning of the ROM_EXT Manifest Identifier field.

  • All numeric and enumeration field values are stored little-endian. Fields below are noted as one of:

    • a N-bit (signed or unsigned) numeric value;
    • a N-bit enumeration value;
    • a sequence of N-bit (signed or unsigned) numeric values; or
    • a sequence of bytes.

    All numeric and enumeration values are stored little-endian.

    A byte only ever means an 8-bit data value, whose interpretation is undefined.

  • All fields below are 32-bit (4-byte) aligned unless otherwise specified.

    Open Q: The ordering below is still subject to alignment requirements for different fields, and may change in future.

  • The Image Signature, ROM_EXT Signature Key Modulus and Image are not shown to scale. This is denoted using ~~~ break ~~~ lines, which specify a truncation of field size displayed in the diagram, not that a new field has started.

    • The Signature and Modulus are each 3072 bits long (they are notionally int32_t[96]s).

    • The Code Image itself is variable length, where the length of the entire image (including the manifest) is given in the Length field.

  • Reserved areas are not documented below. Conforming implementations will not parse these fields, but will produce images where those bits are all zero. Reserved areas remain read-only, as they are signed as part of the image. Updating these fields will fail validation.

    Reserved fields have fixed size and unspecified alignment.

Field Descriptions

  1. ROM_EXT Manifest Identifier This is a 32-bit enumeration value which is used by the Mask ROM to identify that an image with the above format is resident in flash. A particular Mask ROM version can only parse one ROM_EXT image format, there is no expected support for differing behaviour based on this field, beyond erroring when ROM_EXT images are missing from flash storage.

    This is used by any ROM_EXT image parsers to identify a ROM_EXT image.

  2. Image Signature This is a RSA-3072 signature of the hash of all the fields that follow the signature. This is a sequence of 32-bit values. The signed area of the image starts immediately after this field, and runs to the end of the image (as defined by the image length). All content outside that range is unsigned (including the Manifest Identifier, and the Image Signature itself).

    This is used by the Mask ROM during secure boot to validate that a ROM_EXT image has been produced by a Silicon Creator for this chip. This is also validated at other times, including during firmware update.

    If the image signature is a sequence of all zeroes, the image is unsigned. Unsigned images must not be booted.

  3. Image Length This denotes the Offset of the end of the image, in bytes. As with other offsets, this is calculated from the start of the ROM_EXT Manifest Identifier field. This is a 32-bit unsigned numeric value.

    This is used when signing, validating, and loading the image. This happens in the Mask ROM, as well as during firmware update.

  4. Image Version This is a version number for the ROM_EXT image. It is a 32-bit unsigned numeric value.

    Open Q How will we use this?

  5. Image Timestamp This is a Unix Timestamp describing when the ROM_EXT image was prepared, in seconds since 00:00:00 UTC on 1 January 1970 (the Unix Epoch). This is a 64-bit signed numeric value.

    This is not used by the Mask ROM when validating the image, but is part of the signed image.

    Alignment This is 64-bit aligned.

  6. Signature Key Public Exponent This is the RSA public exponent to be used during signature verification. This is a 32-bit numeric value.

    This is used when validating the image. This happens in the Mask ROM, as well as during firmware update.

  7. Usage Constraint This is a 256-bit unsigned numeric value.

    This allows the ROM_EXT author to constrain a ROM_EXT to a single device or a group of devices, such that the ROM_EXT will not validate (and therefore will not boot) on devices not in that group.

    The Mask ROM will use this value to calculate a 1024-byte “device usage value” which is used when validating the signature of a ROM_EXT. The exact interpretation of the Usage Constraints value is left as an implementation detail.

  8. Peripheral Lockdown Info This is a 128-bit value which describes how some peripherals should be configured, before the write-enable bits for their configuration registers are cleared.

    This is used by the Mask ROM to configure specific peripherals (including, for example, pinmux and padctrl), in such a way that their configuration cannot be updated by the ROM_EXT or any other later firmware.

    Open Q We don’t have inifnite space for this, so what configurations might we want to make and then lock?

    Open Q Required Alignment. Assuming 32-bit for the moment. We’re currently tight for space, so this may turn into an Offset to later in the image.

  9. Signature Key Modulus This is a RSA-3072 modulus, used in both the signing and signature verification operations. This is a sequence of 32-bit values.

    This is used when signing and validating the image. This happens in the Mask ROM, as well as during firmware update.

  10. Extensions This is a sequence of 4 (Offset, Checksum) pairs. These allow for the ROM_EXT manifest format to be extended without redesigning the manifest entirely.

    Extensions are ignored by the Mask ROM. They may be parsed by the ROM_EXT itself and any later firmware stages.

    The Offset field denotes the byte offset in the image (including the manifest) where the extension can be found. The length of the respective data is defined by the extension itself (it can have either a static or variable length), but the manifest includes a Checksum field which must be used to store a checksum of the extension’s data, using CRC32.

    Each Offset field is a 32-bit unsigned numeric value. Each Checksum field is a 32-bit numeric value.

    Extension pairs may be allocated a specific use. These fields should be treated as Reserved until they are allocated. Once an extension pair has an allocated use, it will not be used for any other use, unless the Manifest Image Identifier also changes (In this way, the Identifier also works as a versioning token for the manifest format). When an extension pair is allocated, the extension may define an alignment requirement for the its data. The extension’s data must be at least byte-aligned.

    Open Q We could allocate more of these pairs, as we have quite a few bytes between the end of the last pair, and the first 256-byte-aligned address in the code image (see the Code Image field description.). Do we want to?

  11. Code Image This is a sequence of bytes that make up the code and data of the ROM_EXT image. This data will include any data required for Extensions.

    Execution begins at the address 128 (0x80) bytes beyond the first 256-byte (0x100-byte) aligned offset at the start of the ROM_EXT code image (measuring the offset from the start of the ROM_EXT image). This leaves the possibility of the Mask ROM initializing mtvec with the first 256-byte aligned offset in the ROM_EXT code image, before jumping into ROM_EXT code. This matches how Ibex boots.

    The total manifest length is currently 0x370 (880) bytes, so the first valid mtvec address is at offset 0x400 (1024) bytes from the beginning of the ROM_EXT image, and the entry address is therefore 0x480 (1152) bytes from the beginning of the ROM_EXT image.

    This does leave 144 (0x90) bytes between the end of the manifest and the first valid mtvec. It is up to the image as to how this is used–it could be used for extension data or for routines. We could also reserve this space so the manifest can be extended later, but this is the intention of the Extension entries.

    Open Q Do we want to relax the requirement to match how ibex boots? We still want a static entry address so we don’t have to validate that it is in bounds.

    Open Q Do we want to set mtvec before jumping to the ROM_EXT? This could cause double fault issues if ROM_EXT is not unlocked by the comparator before the jump happens.

Data Not in the Header

  • .data + .bss section sizes, for establishing PMP regions. The PMP regions should be established by the ROM_EXT image as it sets up its own execution. This is not the responsibility of Mask ROM, as of yet.

  • .idata section offset, for copying initialization values into .data section in RAM, as again, this is the responsibility of the ROM_EXT image, not Mask ROM.

  • Software Binding Tag (aka ROM_EXT Security Descriptor)

    A 256-bit input is needed to help seed the CreatorRootKey, as part of preparing the key manager for later use.

    There was originally a proposal to have the party that prepared the image set the software binding tag explicitly, using a field in the manifest. However, we have chosen to always use a 256-bit digest of the ROM_EXT image itself.

    This means future ROM_EXTs can not read data encrypted with a previous ROM_EXT’s key. A different ROM_EXT image will result in a different CreatorRootKey.

    This would have been used by the Mask ROM as an input for the key manager.

  • Signature Algorithm Identifier We originally planned to have this field in the ROM_EXT manifest, but with the padding scheme, it is redundant, so it has been removed.

Development Versions (Subject to Change)

ROM_EXT Manifest Identifier: 0x4552544F (Reads “OTRE” when Disassembled – OpenTitan ROM_EXT)

Signature Algorithm Identifier: TBC

Signature Key Public Exponent: TBC

Development Signature Key Pair: TBC. We will create a dummy key pair for development, but this will not be used in production software.

Extension Allocation:

Identifier Pair Use Length Alignment
0x4552544F 0 Unallocated
0x4552544F 1 Unallocated
0x4552544F 2 Unallocated
0x4552544F 3 Unallocated

Software Deliverables

  • A C Library for parsing/extracting this image format on-device.

    This should take a Base Address, and parse using offsets from that, rather than a fixed address at the start of flash. This is so we can parse both ROM_EXT Slot A and Slot B using the same library.

  • A linker script (and assembly files) that can create a ROM_EXT ELF file containing all the code and data.

    The aim is to use absolute addresses for the stack and any in-RAM data, so that we end up mostly position-independent.

    Open Q: The ROM_EXT may need to be told which address the current image starts at when it boots.

  • A developer utility for taking a ROM_EXT ELF file and turning it into a correctly signed image for loading into either slot using the existing spiflash utility. This utility should also be able to validate a signed ROM_EXT image, to ensure that what we signed can be validated both on- and off-device.

    This utility will also have to take a Software Binding Tag and other metadata as input, for injecting into the image. It should almost certainly also create a receipt of the information it just signed, in a machine-parseable format.

  • (Potentially) a developer utility for assembling binary images that contain the entire contents of flash (ROM_EXT + BL0 + Owner Firmware + Persisted Data, for each of Slot A and B), for testing.

Open Q There are lots of open questions about position-independent code issues and requirements, as we want to load the same image into Slot A or Slot B, without having to re-link or re-compile the image (note we only have one entry address). At least initially, we will only create images that can work from Slot A, and later we will add support ensuring these images are linked in a way that they can run from Slot B without modification.

How To Validate a ROM_EXT Image

Below we provide an abstract definition of how to sign and verify a ROM_EXT image. This description is provided so that there is a specification of what the signing and validation systems are implementing, so that alternate implementations may be produced if necessary.


  • rom_ext - ROM_EXT Image, including manifest and contents (Variable Length) signed_area(rom_ext) denotes just the area between the start of the signed contents and the end of the image.
  • device_usage_value - Device-Calculated Usage Constraint Value (1024 bytes). This is the “device usage value” described above, as calculated by the Mask ROM.
  • system_state_value - Device System State Value (32 bytes). This is a Mask ROM calculated value that summarises the current device state.
  • private_key - RSA Private Key
  • public_key - RSA Public Key
  • signature - ROM_EXT RSA Signature,
  • || - Denotes concatenation without a delimiter.
  • := - Denotes assignment.


  • We primarily use RSASSA-PKCS1-V1_5-SIGN and RSASSA-PKCS1-V1_5-VERIFY for signatures and verification.
  • RSA Signing and Verification is done with 3072-bit keys.
  • The Hash operation may be done with SHA2-256, SHA3-256, SHA3-384, or SHA3-512, depending on the Signature Algorithm Identifier provided in the manifest. The Hash operation is required to provide a security level equivalent to that provided by the signature.


This is usually done on a host machine, which does not have access to a real OT device. Thus there has to be a way for the host signer to predict the value of device_usage_value and system_state_value, as they would be calculated on-device.

The private_key is never available on-device, in this scheme.

system_state_value := predict_system_state_value()
device_usage_value := predict_device_usage_value(rom_ext.usage_constraint)

message := system_state_value || device_usage_value || signed_area(rom_ext)
signature := RSASSA-PKCS1-V1_5-SIGN(private_key, message)


Usually, validation is done on-device, where device_usage_value and system_state_value can be calculated.

However, we also want to be able to validate the signature off-device, so still need a way to predict the value of device_usage_value and system_state_value. Off-device, we will use the same predict_ systems as used above.

This document does not cover how a device should ensure that public_key is allowed to validate images for a given device.

system_state_value := calculate_system_state_value()
device_usage_value := calculate_device_usage_value(rom_ext.usage_constraint)
signature := rom_ext.signature

message := system_state_value || device_usage_value || signed_area(rom_ext)
result := RSASSA-PKCS1-V1_5-VERIFY(public_key, message, signature)