blob: 4b1e1a84c8b2004a950b04cf120a78412c12bf99 [file] [log] [blame]
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
/* _Static_assert is usually not enabled in C++ mode by compilers. */
#include <assert.h>
#define _Static_assert static_assert
#endif
/* This structure encodes a superset of what we have historically encoded in:
* - FMAP & HMAP
* - BBINFO
* - BIOS signature header
*
* Unless explicitly noted all fields are little-endian & offset/size fields
* are in bytes. This struct must reside in a IMAGE_REGION_STATIC region.
* In the context of Hoth it must also reside on a 64K boundary.
* The size of the hashed/signed portion of the descriptor region can be
* determined solely by parsing the (fixed) image_descriptor struct.
*
* --------------------------------Flash layout--------------------------------
* | struct image_descriptor (signed) |
* | struct image_region[region_count] (signed) |
* ----------------------------------------------------------------------------
* | (optional: hash_type) struct hash_* (signed) |
* ----------------------------------------------------------------------------
* | (optional: denylist_size) struct denylist (signed) |
* | struct denylist_record[denylist_size] (signed) |
* ----------------------------------------------------------------------------
* | (optional: blob_size) struct blob (signed) |
* | uint8_t blob[blob_size] (signed) |
* ----------------------------------------------------------------------------
* | (optional: signature_scheme) struct signature_* (partially signed) |
* ----------------------------------------------------------------------------
*/
// clang-format off
#define IMAGE_REGION_STATIC (1 << 0)
#define IMAGE_REGION_COMPRESSED (1 << 1)
#define IMAGE_REGION_WRITE_PROTECTED (1 << 2)
#define IMAGE_REGION_READ_PROTECTED (1 << 3)
#define IMAGE_REGION_PERSISTENT (1 << 4)
#define IMAGE_REGION_PERSISTENT_RELOCATABLE (1 << 5)
#define IMAGE_REGION_PERSISTENT_EXPANDABLE (1 << 6)
#define IMAGE_REGION_OVERRIDE (1 << 7)
#define IMAGE_REGION_OVERRIDE_ON_TRANSITION (1 << 8)
#define IMAGE_REGION_MAILBOX (1 << 9)
#define IMAGE_REGION_SKIP_BOOT_VALIDATION (1 << 10)
#define IMAGE_REGION_EMPTY (1 << 11)
// clang-format on
/* Little endian on flash. */
#define DESCRIPTOR_MAGIC 0x5f435344474d495f // "_IMGDSC_"
#define HASH_MAGIC 0x48534148 // "HASH"
#define DENYLIST_MAGIC 0x4b434c42 // "BLCK"
#define BLOB_MAGIC 0x424f4c42 // "BLOB"
#define SIGNATURE_MAGIC 0x4e474953 // "SIGN"
/* Values for 'blob_data.blob_type_magic'. Little-endian on flash. */
/* Indicates that 'blob_data.blob_payload' contains a serialized
* platforms.security.titan.DescriptorExtensions protocol buffer message. There
* must be zero or one DescriptorExtensions in an image. If more than one is
* found, the image descriptor is invalid and the image must be treated as
* unsigned.
*/
#define BLOB_TYPE_MAGIC_DESCRIPTOR_EXTENSIONS 0x58454250 // "PBEX"
/* Indicates that 'blob_data.blob_payload' contains an image_mauv structure.
* There must be zero or one image_mauv
* structures in an image. If more than one is found, the image descriptor is
* invalid and the image must be treated as unsigned.
*/
#define BLOB_TYPE_MAGIC_MAUV 0x5655414D // "MAUV"
/* Indicates that 'blob_data.blob_payload' contains a 32-byte sha256 hash of
* all the IMAGE_REGION_STATIC partitions that don't have
* IMAGE_REGION_SKIP_BOOT_VALIDATION set.
*/
#define BLOB_TYPE_MAGIC_BOOT_HASH_SHA256 0x48534842 // "BHSH"
/* Indicates that 'blob_data.blob_payload' contains a lockdown_control
* structure. There must be zero or
* one lockdown_status structures in an image. If more than one is found, the
* image descriptor is invalid and the image must be treated as unsigned.
*/
#define BLOB_TYPE_MAGIC_LOCKDOWN_CONTROL 0x4E444B4C // "LKDN"
/* Indicates the type of the image. The type of the image also indicates the
* family of key that was used to sign the image. If the image type is signed
* with a key stored in RKM, then a corresponding enumeration should be added to
* keyspec.proto.
*
* Note: if the image type is IMAGE_UNSIGNED_INTEGRITY, the signature_scheme has
* to be of type
* *_NO_SIGNATURE. Also, all other image types cannot transition to an image of
* type IMAGE_UNSIGNED_INTEGRITY.
*
* The way to verify an image of type IMAGE_UNSIGNED_INTEGRITY differs from
* other types of images as it is not signed with an asymmetric key. Instead,
* one can verify the integrity by computing the shasum over the descriptor.
*/
enum image_type
{
IMAGE_DEV = 0,
IMAGE_PROD = 1,
IMAGE_BREAKOUT = 2,
IMAGE_TEST = 3,
IMAGE_UNSIGNED_INTEGRITY = 4
};
enum hash_type
{
HASH_NONE = 0,
HASH_SHA2_224 = 1,
HASH_SHA2_256 = 2,
HASH_SHA2_384 = 3,
HASH_SHA2_512 = 4,
HASH_SHA3_224 = 5,
HASH_SHA3_256 = 6,
HASH_SHA3_384 = 7,
HASH_SHA3_512 = 8
};
/* Note: If the image is of type IMAGE_UNSIGNED_INTEGRITY, the signature_scheme
* has to be of type *_ONLY_NO_SIGNATURE.
*/
enum signature_scheme
{
SIGNATURE_NONE = 0,
SIGNATURE_RSA2048_PKCS15 = 1,
SIGNATURE_RSA3072_PKCS15 = 2,
SIGNATURE_RSA4096_PKCS15 = 3,
SIGNATURE_RSA4096_PKCS15_SHA512 = 4,
SHA256_ONLY_NO_SIGNATURE = 5
};
/* Payload image family. Distinct from the Hoth image family. */
enum image_family
{
IMAGE_FAMILY_ALL = 0,
// values < 256 are reserved for Google-internal use
};
#define IMAGE_REGION_PROTECTED_ALIGNMENT (4096)
#define IMAGE_REGION_PROTECTED_PAGE_LENGTH (4096)
struct image_region
{
uint8_t region_name[32]; // null-terminated ASCII string
uint32_t region_offset; // read- and write- protected regions must be
// aligned to IMAGE_REGION_PROTECTED_ALIGNMENT.
// Other regions are also aligned which
// simplifies their implementation.
uint32_t region_size; // read- and write- protected regions must be a
// multiple of IMAGE_REGION_PROTECTED_PAGE_LENGTH.
/* Regions will not be persisted across different versions.
* This field is intended to flag potential incompatibilities in the
* context of data migration (e.g. the ELOG format changed between
* two BIOS releases).
*/
uint16_t region_version;
/* See IMAGE_REGION_* defines above. */
uint16_t region_attributes;
} __attribute__((__packed__));
/* Main structure (major=1, minor=0). Verification process:
* - Hash(image_descriptor + region_count * struct image_region +
* struct hash +
* struct denylist + denylist_size * struct denylist_record +
* struct blob + uint8_t blob[blob_size])
* - Verify the signature_* over the hash computed in the previous step
* - Compute the rolling hash of the regions marked IMAGE_REGION_STATIC
* - The image descriptor is excluded from the hash (descriptor_size bytes)
* - Compare the computed hash to the struct hash_*.hash
*/
struct image_descriptor
{
uint64_t descriptor_magic = 0; // #define DESCRIPTOR_MAGIC
/* Major revisions of this structure are not backwards compatible. */
uint8_t descriptor_major = 0;
/* Minor revisions of this structure are backwards compatible. */
uint8_t descriptor_minor = 0;
/* Padding. */
uint16_t reserved_0 = 0;
/* This field allows us to mitigate a DOS vector if we end up
* scanning the image to discover the image descriptor. The offset
* and size are hashed with the rest of the descriptor to prevent
* an attacker from copying a valid descriptor to a different
* location.
*
* The offset is relative to the start of the image data.
*/
uint32_t descriptor_offset = 0;
/* Includes this struct as well as the auxiliary structs (hash_*,
* signature_*, denylist, and blob). This many bytes will be skipped when
* computing the hash of the region this struct resides in. Tail padding is
* allowed but must be all 0xff's.
*/
uint32_t descriptor_area_size = 0;
/*** Image information. ***/
/* Null-terminated ASCII string. For BIOS this would be the platform
* family-genus-version-date. Intended for consumption by system
* software that generates human readable output.
*/
uint8_t image_name[32];
/* Image transitions are enforced to be from/to the same family.
* 0 is treated as a wildcard (can upgrade to/from any image family).
* See image_family enum above.
*/
uint32_t image_family = 0;
/* Follow the Kibbles versioning scheme. */
uint32_t image_major = 0;
uint32_t image_minor = 0;
uint32_t image_point = 0;
uint32_t image_subpoint = 0;
/* Seconds since epoch. */
uint64_t build_timestamp = 0;
/* image_type enum { DEV, PROD, BREAKOUT, UNSIGNED_INTEGRITY} */
uint8_t image_type = 0;
/* 0: no denylist struct, 1: watermark only, >1: watermark + denylist */
uint8_t denylist_size = 0;
/* hash_type enum { NONE, SHA2_224, SHA2_256, ...} */
uint8_t hash_type = 0;
/* signature_scheme enum { NONE, RSA2048_PKCS15, ...}
* If set, hash_type must be set as well (cannot be NONE).
*/
uint8_t signature_scheme = 0;
/* struct image_region array size. */
uint8_t region_count = 0;
uint8_t reserved_1 = 0;
uint16_t reserved_2 = 0;
/* The sum of the image_region.region_size fields must add up. */
uint32_t image_size = 0;
/* Authenticated opaque data exposed to system software. Must be a multiple
* of 4 to maintain alignment. Does not include the blob struct magic.
*/
uint32_t blob_size = 0;
/* The list is strictly ordered by region_offset.
* Must exhaustively describe the image.
*/
#ifndef OMIT_VARIABLE_ARRAYS
struct image_region image_regions[];
#endif
} __attribute__((__packed__));
/* Hash the static regions (IMAGE_REGION_STATIC) excluding this descriptor
* structure i.e. skipping image_descriptor.descriptor_size bytes (optional).
*/
struct hash_sha256
{
uint32_t hash_magic; // #define HASH_MAGIC
uint8_t hash[32];
} __attribute__((__packed__));
struct hash_sha512
{
uint32_t hash_magic; // #define HASH_MAGIC
uint8_t hash[64];
} __attribute__((__packed__));
struct denylist_record
{
uint32_t image_major;
uint32_t image_minor;
uint32_t image_point;
uint32_t image_subpoint;
} __attribute__((__packed__));
struct denylist
{
uint32_t denylist_magic; // #define DENYLIST_MAGIC
/* Deny list. The first entry is the watermark. All subsequent entries must
* be newer than the watermark.
*/
#ifndef OMIT_VARIABLE_ARRAYS
struct denylist_record denylist_record[];
#endif
} __attribute__((__packed__));
struct blob
{
uint32_t blob_magic; // #define BLOB_MAGIC
#ifndef OMIT_VARIABLE_ARRAYS
/* Array of blob_data structures - see blob_data below for details. */
uint8_t blobs[];
#endif
} __attribute__((__packed__));
/* blob data is expected to be aligned to 4 bytes */
#define BLOB_DATA_ALIGNMENT (4)
/* If blobs[] is non-empty, it is expected to contain one more more instances
* of this struct. Each blob_data is followed by the minimum number of padding
* bytes (0-3) needed to maintain 4-byte alignment of blob_data structures.
* Padding bytes must be 0xFF and must be ignored by readers of blobs[].
*
* The ordering of the blob_data structures is undefined. Readers of blobs[]
* must locate expected blob_data by inspecting blob_type_magic of each
* blob_data. Readers are expected to ignore unknown blob_type_magic values,
* skipping over them to allow for future types.
*
* If blob_size is greater than zero but less than sizeof(struct blob_data), the
* blobs list is invalid. The blobs list is also invalid if there are multiple
* blob_data structures and the last one is truncated due to blob_size being too
* small to hold blob_payload_size. Readers must walk the entire length of the
* blob_data list to validate the list is well-formed. Any image with an
* invalid blobs list has an invalid descriptor and must be treated the same as
* an unsigned image.
*/
struct blob_data
{
/* BLOB_TYPE_MAGIC_* */
uint32_t blob_type_magic;
/* Size of the data contained in blob_payload. Need not be a multiple of 4
* bytes. Must have sizeof(struct blob_data) + blob_payload_size <=
* blob_size.
*/
uint32_t blob_payload_size;
#ifndef OMIT_VARIABLE_ARRAYS
uint8_t blob_payload[];
#endif
} __attribute__((__packed__));
#define IMAGE_MAUV_STRUCT_VERSION 1
struct image_mauv
{
/* Version of the MAUV structure. */
uint32_t mauv_struct_version;
/* padding for 64-bit alignment of payload_security_version
* must be set to 0xffffffff */
uint32_t reserved_0;
/* The version of the payload in which this `struct image_mauv` was
* embedded. This would be better inside of `struct image_descriptor`, but
* that structure doesn't have any spare fields or a reasonable way to grow
* the structure. When processing firmware updates, the update will be
* aborted if `payload_security_version` of the update payload is less than
* the `minimum_acceptable_update_version` in gNVRAM.
*/
uint64_t payload_security_version;
/* A monotonic counter that should be increased whenever the
* `minimum_acceptable_update_version or version_denylist fields are
* changed. In order for the image_mauv structure in gNVRAM to be updated
* after an payload update, the `mauv_update_timestamp` field in the new
* payload must be greater than the `mauv_update_timestamp` field in gNVRAM.
*
* Although the firmware doesn't assign any semantic meaning to this value,
* by convention should be the number of seconds since the unix epoch at the
* time the payload was signed.
*/
uint64_t mauv_update_timestamp;
/* Minimum acceptable update version. An update to a payload with its
* `payload_security_version` field less than this field in gNVRAM is
* forbidden. This value is not monotonic.
*/
uint64_t minimum_acceptable_update_version;
/* padding for 64-bit alignment of version_denylist
* must be set to 0xffffffff */
uint32_t reserved_1;
/* Number of entries in the denylist. */
uint32_t version_denylist_num_entries;
/* A version denylist. Updates to any version in this list will be rejected
* by the firmware.
*/
#ifndef OMIT_VARIABLE_ARRAYS
uint64_t version_denylist[];
#endif
} __attribute__((packed));
_Static_assert(offsetof(struct image_mauv, payload_security_version) %
sizeof(uint64_t) ==
0,
"bad payload_security_version alignment");
#ifndef OMIT_VARIABLE_ARRAYS
_Static_assert(offsetof(struct image_mauv, version_denylist) %
sizeof(uint64_t) ==
0,
"bad denylist alignment");
#endif
// When A/B updates are enabled, SPS_EEPROM_LOCKDOWN_IMMUTABLE is invalid.
enum sps_eeprom_lockdown_status
{
// Unverified or invalid image. All writes allowed.
SPS_EEPROM_LOCKDOWN_FAILSAFE = 0,
// Valid image. Static regions are write protected. Write-protected
// non-static
// regions are still writable. In single image mode, can
// transition to SPS_EEPROM_LOCKDOWN_IMMUTABLE from this state.
SPS_EEPROM_LOCKDOWN_READY = 1,
// Entire image is write protected outside of the mailbox image region. Note
// that the payload image may be modified through EC Host mailbox
// update commands.
SPS_EEPROM_LOCKDOWN_IMMUTABLE = 2,
// Valid image. Immutable static and write-protected non-static regions. In
// single image mode, must reset to update.
SPS_EEPROM_LOCKDOWN_ENABLED = 3
};
#define LOCKDOWN_CONTROL_STRUCT_VERSION 1
struct lockdown_control
{
/* Version of the lockdown_status structure. */
uint32_t lockdown_control_struct_version;
/* The default lockdown status for a valid signed payload image. The value
* is identical to `enum sps_eeprom_lockdown_status`. 0 = Failsafe, 1 =
* Ready.
*/
uint32_t default_status;
};
/* RSA4096 is the largest key type currently supported. */
#define MAX_KEY_SIZE_NBYTES 512
/* Signature of the hash of the image_descriptor structure up to and including
* this struct but excluding the signature field (optional).
*/
struct signature_rsa2048_pkcs15
{
uint32_t signature_magic; // #define SIGNATURE_MAGIC
/* Monotonic index of the key used to sign the image (starts at 1). */
uint16_t key_index;
/* Used to revoke keys, persisted by the enforcer. */
uint16_t min_key_index;
uint32_t exponent; // little-endian
uint8_t modulus[256]; // big-endian
uint8_t signature[256]; // big-endian
} __attribute__((__packed__));
struct signature_rsa3072_pkcs15
{
uint32_t signature_magic; // #define SIGNATURE_MAGIC
/* Monotonic index of the key used to sign the image (starts at 1). */
uint16_t key_index;
/* Used to revoke keys, persisted by the enforcer. */
uint16_t min_key_index;
uint32_t exponent; // little-endian
uint8_t modulus[384]; // big-endian
uint8_t signature[384]; // big-endian
} __attribute__((__packed__));
struct signature_rsa4096_pkcs15
{
uint32_t signature_magic; // #define SIGNATURE_MAGIC
/* Monotonic index of the key used to sign the image (starts at 1). */
uint16_t key_index;
/* Used to revoke keys, persisted by the enforcer. */
uint16_t min_key_index;
uint32_t exponent; // little-endian
uint8_t modulus[512]; // big-endian
uint8_t signature[512]; // big-endian
} __attribute__((__packed__));
struct sha256_only_no_signature
{
uint32_t signature_magic; // #define SIGNATURE_MAGIC
uint8_t digest[32];
} __attribute__((__packed__));