summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMary Ruthven <mruthven@chromium.org>2022-08-26 11:32:12 -0700
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-09-23 01:57:37 +0000
commit3cd09fe99b278ccece53248a01b04078e7ae6798 (patch)
tree4e900d0d6c8518b9728330538f88f48a60907cd4
parent9123b238b7be811a73bffbf2cd69f63c30c80170 (diff)
downloadchrome-ec-3cd09fe99b278ccece53248a01b04078e7ae6798.tar.gz
ap_ro_integrity_check: remove v2 support
Remove most of the v2 support. Keep finding the FMAP and put it behind FIND_FMAP, so we can use it to find the gbb. BUG=none TEST=manual # erase AP RO hash. Make sure AP RO verification is skipped and # the device boots. [128.981224 RO Validation triggered] [128.982357 ap_ro_check_unsupported: RO verification not ...] [129.109138 AC: R-] # Set the hash. Make sure validation runs. [56.397819 RO Validation triggered] [56.399009 enable_spi_pinmux: AP] [56.401519 spi_hash_pp_done: AP] ... Change-Id: Id52180c352a57e0e1e3cdc18bc3ee0fcce4c222c Signed-off-by: Mary Ruthven <mruthven@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3869309 Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
-rw-r--r--common/ap_ro_integrity_check.c1054
1 files changed, 56 insertions, 998 deletions
diff --git a/common/ap_ro_integrity_check.c b/common/ap_ro_integrity_check.c
index 18f87ea4fd..16506b96d9 100644
--- a/common/ap_ro_integrity_check.c
+++ b/common/ap_ro_integrity_check.c
@@ -27,22 +27,14 @@
#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ##args)
#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ##args)
-#define VB2_KEYBLOCK_MAGIC "CHROMEOS"
-#define VB2_KEYBLOCK_MAGIC_SIZE (sizeof(VB2_KEYBLOCK_MAGIC) - 1)
-
/* FMAP must be aligned at 4K or larger power of 2 boundary. */
#define LOWEST_FMAP_ALIGNMENT (4 * 1024)
#define FMAP_SIGNATURE "__FMAP__"
-#define GSCVD_AREA_NAME "RO_GSCVD"
#define FMAP_AREA_NAME "FMAP"
#define FMAP_SIGNATURE_SIZE (sizeof(FMAP_SIGNATURE) - 1)
#define FMAP_NAMELEN 32
#define FMAP_MAJOR_VERSION 1
#define FMAP_MINOR_VERSION 1
-#define KEYBLOCK_MAJOR_VERSION 2
-#define KEYBLOCK_MINOR_VERSION 1
-
-#define LOWEST_ACCEPTABLE_GVD_ROLLBACK 1
/*
* A somewhat arbitrary maximum number of AP RO hash ranges to save. There are
@@ -90,17 +82,6 @@ struct ap_ro_check_payload {
} __packed;
/*
- * Hash of previously read and validated gsc verification data, stored in the
- * local cache.
- */
-struct gvd_descriptor {
- uint32_t fmap_offset; /* Offsets in SPI flash. */
- uint32_t gvd_offset;
- uint32_t rollback;
- uint8_t digest[SHA256_DIGEST_SIZE];
-};
-
-/*
* Header added for storing of the AP RO check information in the H1 flash
* page. The checksum is a 4 byte truncated sha256 of the saved payload, just
* a validity check.
@@ -108,7 +89,6 @@ struct gvd_descriptor {
struct ap_ro_check_header {
uint8_t version;
uint8_t type;
- /* This field is ignored when type is AP_RO_HASH_TYPE_GSCVD. */
uint16_t num_ranges;
uint32_t checksum;
};
@@ -124,15 +104,13 @@ BUILD_ASSERT(AP_RO_DATA_SPACE_SIZE >=
/* Format of the AP RO check information saved in the H1 flash page. */
struct ap_ro_check {
struct ap_ro_check_header header;
- union {
- /* Used by the V1 scheme. */
- struct ap_ro_check_payload payload;
- /* Used by the V2 scheme. */
- struct gvd_descriptor descriptor;
- };
+ struct ap_ro_check_payload payload;
};
+#ifdef FIND_FMAP
+/*****************************************************************************/
/* FMAP structures borrowed from host/lib/include/fmap.h in vboot_reference. */
+
struct fmap_header {
char fmap_signature[FMAP_SIGNATURE_SIZE];
uint8_t fmap_ver_major;
@@ -149,169 +127,10 @@ struct fmap_area_header {
char area_name[FMAP_NAMELEN];
uint16_t area_flags;
} __packed;
+#endif /* FIND_FMAP */
-
-/* Cryptographic entities defined in vboot_reference. */
-struct vb2_signature {
- /* Offset of signature data from start of this struct */
- uint32_t sig_offset;
- uint32_t reserved0;
-
- /* Size of signature data in bytes */
- uint32_t sig_size;
- uint32_t reserved1;
-
- /* Size of the data block which was signed in bytes */
- uint32_t data_size;
- uint32_t reserved2;
-};
-
-struct vb2_packed_key {
- /* Offset of key data from start of this struct */
- uint32_t key_offset;
- uint32_t reserved0;
-
- /* Size of key data in bytes (NOT strength of key in bits) */
- uint32_t key_size;
- uint32_t reserved1;
-
- /* Signature algorithm used by the key (enum vb2_crypto_algorithm) */
- uint32_t algorithm;
- uint32_t reserved2;
-
- /* Key version */
- uint32_t key_version;
- uint32_t reserved3;
-};
-
-struct vb2_keyblock {
- /* Magic number */
- uint8_t magic[VB2_KEYBLOCK_MAGIC_SIZE];
-
- /* Version of this header format */
- uint32_t header_version_major;
- uint32_t header_version_minor;
-
- /*
- * Length of this entire keyblock, including keys, signatures, and
- * padding, in bytes
- */
- uint32_t keyblock_size;
- uint32_t reserved0;
-
- /*
- * Signature for this keyblock (header + data pointed to by data_key)
- * For use with signed data keys
- */
- struct vb2_signature keyblock_signature;
-
- /*
- * SHA-512 hash for this keyblock (header + data pointed to by
- * data_key) For use with unsigned data keys.
- *
- * Only supported for kernel keyblocks, not firmware keyblocks.
- */
- struct vb2_signature keyblock_hash;
-
- /* Flags for key (VB2_KEYBLOCK_FLAG_*) */
- uint32_t keyblock_flags;
- uint32_t reserved1;
-
- /* Key to verify the chunk of data */
- struct vb2_packed_key data_key;
-};
-
-/*
- * Header of GSC Verification data saved in AP RO flash. The variable element
- * of range_count RO ranges is placed adjacent to this structure in the AP RO
- * flash.
- */
-#define GSC_VD_MAGIC 0x65666135 /* Little endian '5 a f e' */
-struct gsc_verification_data {
- uint32_t gv_magic;
- /*
- * Size of this structure in bytes, including the ranges array,
- * signature and root key bodies.
- */
- uint16_t size;
- uint16_t major_version; /* Version of this struct layout. Starts at 0 */
- uint16_t minor_version;
- /*
- * GSC will cache the counter value and will not accept verification
- * data blobs with a lower value.
- */
- uint16_t rollback_counter;
- uint32_t gsc_board_id; /* Locks blob to certain platform. */
- uint32_t gsc_flags; /* A field for future enhancements. */
- /*
- * The location of fmap that points to this blob. This location must
- * also be in one of the verified sections, expressed as offset in
- * flash
- */
- uint32_t fmap_location;
- uint32_t hash_alg; /* one of enum vb2_hash_algorithm alg. */
- struct vb2_signature sig_header;
- struct vb2_packed_key root_key_header;
- /*
- * SHAxxx(ranges[0].offset..ranges[0].size || ... ||
- * ranges[n].offset..ranges[n].size)
- *
- * Let the digest space allow to accommodate the largest possible one.
- */
- uint8_t ranges_digest[SHA512_DIGEST_SIZE];
- uint32_t range_count; /* Number of gscvd_ro_range entries. */
- struct ro_range ranges[0];
-};
-
-/*
- * The layout of RO_GSCVD area of AP RO flash is as follows:
- * struct gsc_verication_data,
- * ro_ranges, number of ranges is found in gsc verification data,
- * gvd signature body signature of the two objects above, signature header is
- * included in gsc_verification data
- * root key body root key, used as root of trust, key header is included in
- * gsc_verification_data
- * vb2_keyblock contains the key used to generate the signature and
- * the signature of the key
- */
-
-/*
- * Supported combination for signature and hashing algorithms used to wrap the
- * platform key, a subset of the values defined in vboot_reference.
- */
-enum vb2_crypto_algorithm {
- VB2_ALG_RSA4096_SHA256 = 7,
-};
-
-/*
- * Containers for various objects, including the offsets of the objects in the
- * AP RO flash.
- */
-struct gvd_container {
- uint32_t offset;
- struct gsc_verification_data gvd;
- struct ro_ranges ranges;
-};
-
-struct kb_container {
- uint32_t offset;
- struct vb2_keyblock *kb;
-};
-
-/*
- * Local representation of the RSA key and hashing mode, necessary for
- * verifying RSA signatures.
- */
-struct vb_rsa_pubk {
- struct RSA rsa;
- enum hashing_mode hashing;
-};
-
-/* A helper structure representing a memory block in the GSC address space. */
-struct memory_block {
- const void *base;
- size_t size;
-};
+/*****************************************************************************/
+/* V1 Factory Support (AP_RO_HASH_TYPE_FACTORY) */
/* One of the AP RO verification outcomes, internal representation. */
enum ap_ro_check_result {
@@ -335,175 +154,6 @@ static const struct ap_ro_check *p_chk =
static enum ap_ro_status apro_result = AP_RO_NOT_RUN;
static uint8_t apro_fail_status_cleared;
-
-/*
- * In dev signed Cr50 images this is the hash of
- * tests/devkeys/kernel_subkey.vbpubk from vboot_reference tree. Will be
- * replaced with the hash of the real root prod key by the signer, before prod
- * signing.
- */
-const __attribute__((section(".rodata.root_key_hash")))
-uint8_t root_key_hash[] = {
-#include "ap_ro_root_key_hash.inc"
-};
-
-/**
- * Read AP flash area into provided buffer.
- *
- * Expects AP flash access to be provisioned. Max size to read is limited.
- *
- * @param buf pointer to the buffer to read to.
- * @param offset offset into the flash to read from.
- * @param size number of bytes to read.
- * @param code_line line number where this function was invoked from.
- *
- * @return zero on success, -1 on failure.
- */
-static int read_ap_spi(void *buf, uint32_t offset, size_t size, int code_line)
-{
- if (size > MAX_SUPPORTED_RANGE_SIZE) {
- CPRINTS("%s: request to read %d bytes in line %d", __func__,
- size, code_line);
- return -1;
- }
-
- if (usb_spi_read_buffer(buf, offset, size)) {
- CPRINTS("Failed to read %d bytes at offset 0x%x in line %d",
- size, offset, code_line);
- return -1;
- }
-
- return 0;
-}
-
-/*
- **
- * Convert RSA public key representation between vb2 and dcrypto.
- *
- * Note that for signature verification the only required parameters are
- * exponent, N, and hashing type used to prepare the digest for signing. This
- * function ignores the d component of the key.
- *
- * Some basic validity checks are performed on input data.
- *
- * @param packedk vb2 packed RSA key read from AP flash.
- * @param pubk dcrypto representation of the RSA key, used for signature
- * verification.
- *
- * @return zero on success, -1 on failure.
- */
-static int unpack_pubk(const struct vb2_packed_key *packedk,
- struct vb_rsa_pubk *pubk)
-{
- const uint32_t *buf32;
- uint32_t exp_key_size;
- uint32_t exp_sig_size;
- uint32_t arr_size;
-
- switch (packedk->algorithm) {
- case VB2_ALG_RSA4096_SHA256:
- exp_sig_size = 512;
- pubk->hashing = HASH_SHA256;
- break;
- default:
- CPRINTS("unsupported algorithm %d", packedk->algorithm);
- return -1;
- }
-
- exp_key_size = exp_sig_size * 2 + 8;
- if (packedk->key_size != exp_key_size) {
- CPRINTS("key size mismatch %d %d", packedk->key_size,
- exp_key_size);
- return -1;
- }
-
- buf32 = (uint32_t *)((uintptr_t)packedk + packedk->key_offset);
-
- arr_size = buf32[0];
-
- if (arr_size != (exp_sig_size / sizeof(uint32_t))) {
- CPRINTS("array size mismatch %d %d", arr_size,
- (exp_sig_size / sizeof(uint32_t)));
- return -1;
- }
-
- pubk->rsa.e = 65537; /* This is the only exponent we support. */
- pubk->rsa.N.dmax = arr_size;
- pubk->rsa.N.d = (struct access_helper *)(buf32 + 2);
- pubk->rsa.d.dmax = 0; /* Not needed for signature verification. */
-
- return 0;
-}
-
-/**
- * Verify signature of the requested memory space.
- *
- * Memory space is represented as one or more memory_block structures.
- *
- * @param blocks a pointer to array of memory_block structures, the last entry
- * in the array has .base set to NULL.
- * @param pubk public RSA key used to verify the signature
- * @param sig_body pointer to the signature blob
- * @param sig_size size of the signature blob
- *
- * @return zero on success, non zero of failure (either incorrect hashing
- * algorithm or signature mismatch)
- */
-static int verify_signature(struct memory_block *blocks,
- const struct vb_rsa_pubk *pubk,
- const void *sig_body, size_t sig_size)
-{
- const void *digest;
- uint32_t digest_size;
- size_t i;
- union hash_ctx ctx;
-
- digest_size = DCRYPTO_hash_size(pubk->hashing);
-
- if (!digest_size ||
- DCRYPTO_hw_hash_init(&ctx, pubk->hashing) != DCRYPTO_OK)
- return -1; /* Will never happen, inputs have been verified. */
-
- for (i = 0; blocks[i].base; i++)
- HASH_update(&ctx, blocks[i].base, blocks[i].size);
-
- digest = HASH_final(&ctx);
-
- return DCRYPTO_rsa_verify(&pubk->rsa, digest, digest_size, sig_body,
- sig_size, PADDING_MODE_PKCS1, pubk->hashing) -
- DCRYPTO_OK;
-}
-
-/**
- * Verify that the passed in key block is signed with the passed in key.
- *
- * @param kbc container of the signed key block
- * @param pubk RSA public key to validate the key block signature
- *
- * @return zero on success, non zero on failure,
- */
-static int verify_keyblock(const struct kb_container *kbc,
- const struct vb_rsa_pubk *pubk)
-{
- int rv;
- struct memory_block blocks[2];
- const void *sig_body;
-
- blocks[1].base = NULL;
-
- blocks[0].size = kbc->kb->keyblock_signature.data_size;
- blocks[0].base = kbc->kb;
-
- sig_body = (const void *)((uintptr_t)&kbc->kb->keyblock_signature +
- kbc->kb->keyblock_signature.sig_offset);
- rv = verify_signature(blocks, pubk, sig_body,
- kbc->kb->keyblock_signature.sig_size);
-
- CPRINTS("Keyblock %sOK", rv ? "NOT " : "");
-
- return rv;
-}
-
/* Clear validate_ap_ro_boot state. */
void ap_ro_device_reset(void)
{
@@ -673,33 +323,6 @@ static int verify_ap_ro_check_space(void)
return EC_SUCCESS;
}
-/**
- * Check if v2 gsc verification data hash is present in the flash page.
- *
- * @return pointer to the valid gvd_descriptor, NULL if not found.
- */
-static const struct gvd_descriptor *find_v2_entry(void)
-{
- struct sha256_ctx ctx;
-
- if ((p_chk->header.version < AP_RO_HASH_LAYOUT_VERSION_1) ||
- (p_chk->header.type != AP_RO_HASH_TYPE_GSCVD))
- return NULL;
-
- /* Verify entry integrity. */
- if (DCRYPTO_hw_sha256_init(&ctx) != DCRYPTO_OK)
- return NULL;
-
- SHA256_update(&ctx, &p_chk->descriptor, sizeof(p_chk->descriptor));
- if (DCRYPTO_equals(SHA256_final(&ctx), &p_chk->header.checksum,
- sizeof(p_chk->header.checksum)) != DCRYPTO_OK) {
- CPRINTS("Descriptor checksum mismatch!");
- return NULL;
- }
-
- return &p_chk->descriptor;
-}
-
/*
* ap_ro_check_unsupported: Returns non-zero value if AP RO verification is
* unsupported.
@@ -726,8 +349,8 @@ static enum ap_ro_check_vc_errors ap_ro_check_unsupported(int add_flash_event)
return ARCVE_NOT_PROGRAMMED;
}
- /* Is the contents intact? */
- if (!find_v2_entry() && (verify_ap_ro_check_space() != EC_SUCCESS)) {
+ /* Are the v1 contents intact? */
+ if (verify_ap_ro_check_space() != EC_SUCCESS) {
CPRINTS("%s: unable to read ap ro space", __func__);
if (add_flash_event)
ap_ro_add_flash_event(APROF_SPACE_INVALID);
@@ -737,243 +360,6 @@ static enum ap_ro_check_vc_errors ap_ro_check_unsupported(int add_flash_event)
}
/**
- * Find FMAP and RO_GSCVD areas in the FMAP table in AP flash.
- *
- * @param offset offset of the fmap in the flash
- * @param nareas number of areas in fmap
- * @param gscvd container to save RO_GSCVD area information in
- *
- * @return zero on success, -1 if both areas not found.
- */
-static int find_gscvd(uint32_t offset, uint16_t nareas,
- struct fmap_area_header *gscvd)
-{
- uint16_t i;
- struct fmap_area_header fmah;
-
- if (nareas > 64) {
- CPRINTS("%s: too many areas: %d", __func__, nareas);
- return -1;
- }
-
- for (i = 0; i < nareas; i++) {
- if (read_ap_spi(&fmah, offset, sizeof(fmah), __LINE__))
- return -1;
-
- if (!memcmp(fmah.area_name, GSCVD_AREA_NAME,
- sizeof(GSCVD_AREA_NAME))) {
- memcpy(gscvd, &fmah, sizeof(*gscvd));
- return 0;
- }
- offset += sizeof(fmah);
- }
-
- CPRINTS("Could not find %s area", GSCVD_AREA_NAME);
-
- return -1;
-}
-
-/**
- * Read gsc verification data from AP flash.
- *
- * @param fmap_offset offset of FMAP in AP flash, used for validity check
- * @param gvdc pointer to the gvd container, the offset field initialized.
- *
- * @return zero on successful read, -1 otherwise.
- */
-static int read_gscvd_header(uint32_t fmap_offset, struct gvd_container *gvdc)
-{
- uint32_t expected_size;
- const struct gsc_verification_data *gvd;
- struct board_id id;
-
- if (read_ap_spi(&gvdc->gvd, gvdc->offset, sizeof(gvdc->gvd), __LINE__))
- return -1;
-
- gvd = &gvdc->gvd;
-
- expected_size = sizeof(struct gsc_verification_data) +
- sizeof(struct ro_range) * gvd->range_count +
- gvd->sig_header.sig_size + gvd->root_key_header.key_size;
-
- if ((gvd->gv_magic != GSC_VD_MAGIC) || (gvd->size != expected_size) ||
- (gvd->fmap_location != fmap_offset)) {
- CPRINTS("Inconsistent GSCVD contents");
- return -1;
- }
-
- if ((read_board_id(&id) != EC_SUCCESS) ||
- (id.type != gvd->gsc_board_id)) {
- CPRINTS("Board ID mismatch %#07x != %#08x",
- id.type, gvd->gsc_board_id);
- return -1;
- }
-
- return 0;
-}
-
-/**
- * Check if an element fits into the keyblock.
- *
- * @param kb keyblock to check against
- * @param el address of the element
- * @param data_offset element's data base offset from the element address
- * @param data_size element's data size
- *
- * @return true if the element fits, false otherwise
- */
-static bool element_fits(const struct vb2_keyblock *kb,
- const void *el,
- uint32_t data_offset,
- uint32_t data_size)
-{
- uintptr_t kb_base;
- uint32_t headroom;
- uintptr_t el_base;
- uint32_t size;
-
- kb_base = (uintptr_t)kb;
- size = kb->keyblock_size;
- el_base = (uintptr_t) el;
- headroom = kb_base + size - el_base;
-
- return (((el_base > kb_base) && (el_base < (kb_base + size))) &&
- (data_offset < headroom) &&
- (data_size <= (headroom - data_offset)));
-}
-
-/*
- * Read keyblock from AP flash.
- *
- * First read the header of the keyblock to determine the amount of memory it
- * needs, then allocated the necessary memory and read the full keyblock into
- * it. The caller will free allocated memory even if keyblock verification
- * fails and this function returns the error.
- *
- * Verify validity of the read keyblock by checking the version fields and
- * verifying that the component structures fit into the keyblock.
- *
- * @param kbc container to read the keyblock into.
- *
- * @return zero on success, -1 on failure.
- */
-static int read_keyblock(struct kb_container *kbc)
-{
- struct vb2_keyblock kb;
-
- if (read_ap_spi(&kb, kbc->offset, sizeof(kb), __LINE__) ||
- (memcmp(kb.magic, VB2_KEYBLOCK_MAGIC, sizeof(kb.magic)))) {
- CPRINTS("Failed to read keyblock at %x", kbc->offset);
- return -1;
- }
-
- /* Let's allocate memory for the full keyblock. */
- if (shared_mem_acquire(kb.keyblock_size, (char **)&kbc->kb) !=
- EC_SUCCESS) {
- kbc->kb = NULL;
- CPRINTS("Failed to allocate %d bytes for keyblock",
- kb.keyblock_size);
- return -1;
- }
-
- /* Copy keyblock header into the allocated buffer. */
- memcpy(kbc->kb, &kb, sizeof(kb));
-
- /* Read the rest of the keyblock. */
- if (read_ap_spi(kbc->kb + 1, kbc->offset + sizeof(kb),
- kb.keyblock_size - sizeof(kb), __LINE__))
- return -1;
-
- /*
- * Check keyblock version and verify that all incorporated structures
- * fit in.
- */
- if ((kb.header_version_major != KEYBLOCK_MAJOR_VERSION) ||
- (kb.header_version_minor != KEYBLOCK_MINOR_VERSION) ||
- !element_fits(kbc->kb,
- &kbc->kb->keyblock_signature,
- kbc->kb->keyblock_signature.sig_offset,
- kbc->kb->keyblock_signature.sig_size) ||
- !element_fits(kbc->kb,
- &kbc->kb->keyblock_hash,
- kbc->kb->keyblock_hash.sig_offset,
- kbc->kb->keyblock_hash.sig_size) ||
- !element_fits(kbc->kb,
- &kbc->kb->data_key,
- kbc->kb->data_key.key_offset,
- kbc->kb->data_key.key_size)) {
- CPRINTS("Invalid keyblock contents");
- return -1;
- }
- return 0;
-}
-
-/**
- * Read root key from AP flash.
- *
- * Allocate memory for the key, the caller will free the memory even if this
- * function returns error. Once the key is read verify its validity by
- * comparing its hash against the known value.
- *
- * @param gvdc pointer to the previously filled GVD container
- * @param rootk pointer to pointer to contain root key
- *
- * @return zero on success, -1 on failure.
- */
-static int read_rootk(const struct gvd_container *gvdc,
- struct vb2_packed_key **prootk)
-{
- struct sha256_ctx ctx;
- size_t total_size;
- struct vb2_packed_key *rootk;
- const struct gsc_verification_data *gvd;
- uint32_t key_offset;
-
- gvd = &gvdc->gvd;
-
- *prootk = NULL;
-
- /* Let's read the root key body. */
- total_size = sizeof(*rootk) + gvd->root_key_header.key_size;
- if (shared_mem_acquire(total_size, (char **)&rootk) !=
- EC_SUCCESS) {
- CPRINTS("Failed to allocate %d bytes", total_size);
- return -1;
- }
-
- /* Copy rootk header. */
- memcpy(rootk, &gvd->root_key_header, sizeof(*rootk));
-
- /* Copy rootk body. */
- key_offset = gvdc->offset +
- offsetof(struct gsc_verification_data, root_key_header) +
- gvdc->gvd.root_key_header.key_offset;
-
- /* Use 'rootk + 1' as a pointer to memory adjacent to the header. */
- if (read_ap_spi(rootk + 1,
- key_offset,
- gvd->root_key_header.key_size,
- __LINE__))
- return -1;
-
- if (DCRYPTO_hw_sha256_init(&ctx) != DCRYPTO_OK)
- return -1;
-
- SHA256_update(&ctx, rootk + 1, rootk->key_size);
- if (DCRYPTO_equals(SHA256_final(&ctx), root_key_hash,
- sizeof(root_key_hash)) != DCRYPTO_OK) {
- CPRINTS("Root key digest mismatch");
- return -1;
- }
-
- /* Adjust key_offset to point to the uploaded key body. */
- rootk->key_offset = sizeof(*rootk);
- *prootk = rootk;
-
- return 0;
-}
-
-/**
* Validate hash of AP flash ranges.
*
* Invoke service function to sequentially calculate sha256 hash of the AP
@@ -1018,337 +404,53 @@ enum ap_ro_check_result validate_ranges_sha(const struct ro_range *ranges,
return ROV_SUCCEEDED;
}
-/**
- * Read ranges as defined in gsc_verification_data structure.
- *
- * @param gvdc pointer to the gsc_verifcation_data container
- *
- * @return zero on success, non zero on failure.
- */
-static int read_ranges(struct gvd_container *gvdc)
-{
- size_t range_count = gvdc->gvd.range_count;
-
- if (range_count > ARRAY_SIZE(gvdc->ranges.ranges)) {
- CPRINTS("Too many ranges in gvd (%d)", range_count);
- return -1;
- }
-
- return read_ap_spi(&gvdc->ranges,
- gvdc->offset + sizeof(gvdc->gvd),
- sizeof(struct ro_range) * range_count, __LINE__);
-}
+#ifdef FIND_FMAP
/**
- * Verify validity of the gsc_verification_data
- *
- * The signature covers the structure itself and the ranges array describing
- * which AP flash area are covered.
+ * Read AP flash area into provided buffer.
*
- * This function allocates and frees memory to read the actual signature blob
- * from AP flash, based on signature container information.
+ * Expects AP flash access to be provisioned. Max size to read is limited.
*
- * @param gvd pointer to the gsc_verification_data header
- * @param key pointer RSA key used for signing, vb2 representation
+ * @param buf pointer to the buffer to read to.
+ * @param offset offset into the flash to read from.
+ * @param size number of bytes to read.
+ * @param code_line line number where this function was invoked from.
*
- * return 0 on success, nonzero on failure.
+ * @return zero on success, -1 on failure.
*/
-static int verify_gvd_signature(const struct gvd_container *gvdc,
- const struct vb2_packed_key *key)
+static int read_ap_spi(void *buf, uint32_t offset, size_t size, int code_line)
{
- struct vb_rsa_pubk rsa_key;
- void *sig_body;
- int rv = -1;
- struct memory_block blocks[3];
- uint32_t sig_body_offset;
- uint32_t sig_size;
-
- if (unpack_pubk(key, &rsa_key))
+ if (size > MAX_SUPPORTED_RANGE_SIZE) {
+ CPRINTS("%s: request to read %d bytes in line %d", __func__,
+ size, code_line);
return -1;
-
- sig_body_offset = gvdc->offset +
- offsetof(struct gsc_verification_data, sig_header) +
- gvdc->gvd.sig_header.sig_offset;
- sig_size = gvdc->gvd.sig_header.sig_size;
- if (shared_mem_acquire(sig_size, (char **)&sig_body) != EC_SUCCESS) {
- CPRINTS("Failed to allocate %d bytes for sig body",
- gvdc->gvd.sig_header.sig_size);
- return EC_ERROR_HW_INTERNAL;
}
- if (read_ap_spi(sig_body, sig_body_offset, sig_size, __LINE__))
- goto exit;
-
- blocks[0].base = &gvdc->gvd;
- blocks[0].size = sizeof(gvdc->gvd);
- blocks[1].base = &gvdc->ranges;
- blocks[1].size = gvdc->gvd.range_count * sizeof(gvdc->ranges.ranges[0]);
- blocks[2].base = NULL;
-
- rv = verify_signature(blocks, &rsa_key, sig_body, sig_size);
-
-exit:
- CPRINTS("GVDC %sOK", rv ? "NOT " : "");
-
- shared_mem_release(sig_body);
- return rv;
-}
-
-/**
- * Calculate and save GVD hash in the dedicated flash page.
- *
- * Attempts to save gsc_verification_data of previous generations are rejected.
- *
- * The GVD hash is saved along with a 4 byte checksum (truncated sha256 of the
- * hash) which allows to confirm validity of the saved hash on the following
- * verification attempts.
- *
- * If the dedicated page is not empty, it is erased.
- *
- * @param gvdc pointer to the gsc_verification_data container
- *
- * @return 0 on success, non-zero on failure.
- */
-static int save_gvd_hash(struct gvd_container *gvdc)
-{
- struct ap_ro_check ro_check;
- struct sha256_ctx ctx;
- int rv;
- struct ro_ranges *ranges;
-
- if (gvdc->gvd.rollback_counter < LOWEST_ACCEPTABLE_GVD_ROLLBACK) {
- CPRINTS("Rejecting GVD rollback %d",
- gvdc->gvd.rollback_counter);
+ if (usb_spi_read_buffer(buf, offset, size)) {
+ CPRINTS("Failed to read %d bytes at offset 0x%x in line %d",
+ size, offset, code_line);
return -1;
}
- ro_check.header.version = AP_RO_HASH_LAYOUT_VERSION_1;
- ro_check.header.type = AP_RO_HASH_TYPE_GSCVD;
- /*
- * Not used, but set this field to make sure
- * ap_ro_check_unsupported() is not
- * tripped.
- */
- ro_check.header.num_ranges = 0;
-
- ro_check.descriptor.fmap_offset = gvdc->gvd.fmap_location;
- ro_check.descriptor.gvd_offset = gvdc->offset;
- ro_check.descriptor.rollback = gvdc->gvd.rollback_counter;
-
- /* Calculate SHA256 of the GVD header and ranges. */
- if (DCRYPTO_hw_sha256_init(&ctx) != DCRYPTO_OK)
- return EC_ERROR_HW_INTERNAL;
-
- ranges = &gvdc->ranges;
- SHA256_update(&ctx, &gvdc->gvd, sizeof(gvdc->gvd));
- SHA256_update(&ctx, ranges->ranges,
- sizeof(ranges->ranges[0]) * gvdc->gvd.range_count);
- memcpy(ro_check.descriptor.digest, SHA256_final(&ctx),
- sizeof(ro_check.descriptor.digest));
-
- /* Now truncated sha256 of the descriptor. */
- if (DCRYPTO_hw_sha256_init(&ctx) != DCRYPTO_OK)
- return EC_ERROR_HW_INTERNAL;
- SHA256_update(&ctx, &ro_check.descriptor, sizeof(ro_check.descriptor));
- memcpy(&ro_check.header.checksum, SHA256_final(&ctx),
- sizeof(ro_check.header.checksum));
-
- if (p_chk->header.num_ranges != (uint16_t)~0) {
- CPRINTS("Erasing GVD cache page");
- ap_ro_erase_hash();
- }
-
- flash_open_ro_window(h1_flash_offset_, sizeof(ro_check));
- rv = flash_physical_write(h1_flash_offset_, sizeof(ro_check),
- (char *)&ro_check);
- flash_close_ro_window();
-
- CPRINTS("GVD HASH saving %ssucceeded", rv ? "NOT " : "");
- return rv;
-}
-
-/**
- * Verify that GVD in the AP flash has not changed.
- *
- * Calculate the GVD SHA256 digest and compare it with the cached digest
- * value.
- *
- * @param gvdc pointer to the gsc_verification_data container
- * @param descriptor pointer to the descriptor containing cached hash value to
- * compare against.
- *
- * @return zero on success, non zero on failure/
- */
-static int gvd_cache_check(const struct gvd_container *gvdc,
- const struct gvd_descriptor *descriptor)
-{
- struct sha256_ctx ctx;
- const struct ro_ranges *ranges;
-
- if (DCRYPTO_hw_sha256_init(&ctx) != DCRYPTO_OK)
- return EC_ERROR_HW_INTERNAL;
-
- SHA256_update(&ctx, &gvdc->gvd, sizeof(gvdc->gvd));
-
- ranges = &gvdc->ranges;
- SHA256_update(&ctx, ranges->ranges,
- gvdc->gvd.range_count * sizeof(ranges->ranges[0]));
-
- return DCRYPTO_equals(SHA256_final(&ctx), descriptor->digest,
- SHA256_DIGEST_SIZE) != DCRYPTO_OK;
-}
-
-/**
- * Validate cached AP RO GVD entry.
- *
- * Check if the locally cached hash of gsc_verification_data matches and if
- * so, verify the hash of the AP RO ranges stored in GVD.
- *
- * @param descriptor points to locally cached hash of gsc_verification_data.
- *
- * @return ROV_SUCCEEDED if succeeded, ROV_FAILED otherwise.
- */
-static enum ap_ro_check_result validate_cached_ap_ro_v2(
- const struct gvd_descriptor *descriptor)
-{
-
- uint32_t fmap_offset;
- struct gvd_container gvdc;
-
- fmap_offset = descriptor->fmap_offset;
- gvdc.offset = descriptor->gvd_offset;
-
- if (read_gscvd_header(fmap_offset, &gvdc))
- return ROV_NOT_FOUND;
-
- if (read_ranges(&gvdc))
- return ROV_NOT_FOUND;
-
- if (gvd_cache_check(&gvdc, descriptor)) {
- CPRINTS("GVD HASH MISMATCH!!");
- return ROV_FAILED;
- }
-
- return validate_ranges_sha(gvdc.ranges.ranges, gvdc.gvd.range_count,
- gvdc.gvd.ranges_digest);
-}
-
-static bool check_is_required(void)
-{
- uint32_t value;
- int rv;
-
- rv = flash_physical_info_read_word(INFO_APRV_DATA_OFFSET, &value);
-
- return !value || (rv != EC_SUCCESS);
-}
-
-static int require_future_checks(void)
-{
- uint32_t value = 0;
- int rv;
-
- flash_info_write_enable();
- rv = flash_info_physical_write(INFO_APRV_DATA_OFFSET,
- sizeof(value),
- (const char *)&value);
- flash_info_write_disable();
-
- return rv;
-}
-
-/**
- * Try validating RO_GSCVD FMAP area.
- *
- * This function receives the AP flash offsets of FMAP and RO_GSCVD area. The
- * function tries to cryptographically verify the GVD, starting with the hash
- * of the root key, then signature of the key block, and then signature of
- * gsc_verification_data and the hash of the RO ranges.
- *
- * @return ROV_SUCCEEDED if succeeded, ROV_FAILED otherwise.
- */
-static enum ap_ro_check_result check_gscvd(uint32_t fmap_offset,
- uint32_t gscvd_offset)
-{
- struct gvd_container gvdc;
- struct kb_container kbc;
- struct vb_rsa_pubk pubk;
- struct vb2_packed_key *rootk = NULL;
- enum ap_ro_check_result rv = ROV_FAILED;
-
- gvdc.offset = gscvd_offset;
-
- if (read_gscvd_header(fmap_offset, &gvdc))
- return ROV_NOT_FOUND;
-
- if (read_ranges(&gvdc))
- return rv;
-
- kbc.offset = gvdc.offset + gvdc.gvd.size;
- if (read_keyblock(&kbc))
- return rv;
-
- if (read_rootk(&gvdc, &rootk))
- goto exit;
-
- /* Root key hash matches, let's verify the platform key. */
- if (unpack_pubk(rootk, &pubk))
- goto exit;
-
- if (verify_keyblock(&kbc, &pubk))
- goto exit;
-
- shared_mem_release(rootk);
- rootk = NULL;
-
- if (verify_gvd_signature(&gvdc, &kbc.kb->data_key))
- return rv;
-
- rv = validate_ranges_sha(gvdc.ranges.ranges, gvdc.gvd.range_count,
- gvdc.gvd.ranges_digest);
- if (rv == ROV_SUCCEEDED) {
- if (!check_is_required()) {
- /*
- * Make sure from now on only signed images will be
- * allowed.
- */
- if (require_future_checks() != EC_SUCCESS) {
- rv = ROV_FAILED;
- goto exit;
- }
- }
-
- /* Verification succeeded, save the hash for the next time. */
- if (save_gvd_hash(&gvdc))
- rv = ROV_FAILED;
- }
-exit:
- if (kbc.kb)
- shared_mem_release(kbc.kb);
-
- if (rootk)
- shared_mem_release(rootk);
-
- return rv;
+ return 0;
}
/*
- * Iterate through AP flash at 4K intervals looking for FMAP. Once FMAP is
- * found call a function to verify the FMAP GVD section. Return if
- * verification succeeds, if it fails - keep scanning the flash looking for
- * more FMAP sections.
+ * Find the FMAP in RO flash.
*
- * Return zero if a valid GVD was found, -1 otherwise.
+ * Iterate through AP flash at 4K intervals looking for FMAP.
+ * This isn't used right now. It was used as a part of v2 support. It'll
+ * get used to find the gbb in a followup cl.
+ *
+ * Return ROV_SUCCEEDED if a valid FMAP was found, ROV_FAILED otherwise.
*/
-static enum ap_ro_check_result validate_and_cache_ap_ro_v2_from_flash(void)
+static enum ap_ro_check_result find_fmap(void)
{
uint32_t offset;
- bool ro_gscvd_found = false;
for (offset = 0; offset < MAX_SUPPORTED_FLASH_SIZE;
offset += LOWEST_FMAP_ALIGNMENT) {
struct fmap_header fmh;
- struct fmap_area_header gscvd;
if (read_ap_spi(fmh.fmap_signature, offset,
sizeof(fmh.fmap_signature), __LINE__))
@@ -1373,21 +475,12 @@ static enum ap_ro_check_result validate_and_cache_ap_ro_v2_from_flash(void)
continue;
}
- if (find_gscvd(offset + sizeof(struct fmap_header),
- fmh.fmap_nareas, &gscvd))
- continue;
-
- ro_gscvd_found = true;
-
- if (check_gscvd(offset, gscvd.area_offset) == ROV_SUCCEEDED)
- return ROV_SUCCEEDED;
+ return ROV_SUCCEEDED;
}
- if (ro_gscvd_found)
- return ROV_FAILED;
-
- return ROV_NOT_FOUND;
+ return ROV_FAILED;
}
+#endif /* FIND_FMAP */
/*
* A hook used to keep the EC in reset, no matter what keys the user presses,
@@ -1439,80 +532,45 @@ int ec_rst_override(void)
static uint8_t do_ap_ro_check(void)
{
enum ap_ro_check_result rv;
- enum ap_ro_check_vc_errors support_status;
- bool v1_record_found;
apro_result = AP_RO_IN_PROGRESS;
apro_fail_status_cleared = 0;
- support_status = ap_ro_check_unsupported(true);
- if ((support_status == ARCVE_BOARD_ID_BLOCKED) ||
- (support_status == ARCVE_FLASH_READ_FAILED)) {
+ if (ap_ro_check_unsupported(true) != ARCVE_OK ||
+ p_chk->header.type != AP_RO_HASH_TYPE_FACTORY) {
apro_result = AP_RO_UNSUPPORTED_TRIGGERED;
+ ap_ro_add_flash_event(APROF_CHECK_UNSUPPORTED);
return EC_ERROR_UNIMPLEMENTED;
}
enable_ap_spi_hash_shortcut();
- v1_record_found = (support_status == ARCVE_OK) &&
- (p_chk->header.type == AP_RO_HASH_TYPE_FACTORY);
- if (v1_record_found) {
- rv = validate_ranges_sha(p_chk->payload.ranges,
- p_chk->header.num_ranges,
- p_chk->payload.digest);
- } else {
- rv = ROV_NOT_FOUND;
- }
-
- /* If V1 check has not succeeded, try checking for V2. */
- if (rv != ROV_SUCCEEDED) {
- const struct gvd_descriptor *descriptor;
- enum ap_ro_check_result rv2;
+ rv = validate_ranges_sha(p_chk->payload.ranges,
+ p_chk->header.num_ranges,
+ p_chk->payload.digest);
- descriptor = find_v2_entry();
-
- if (descriptor)
- rv2 = validate_cached_ap_ro_v2(descriptor);
-
- if ((rv2 != ROV_SUCCEEDED) || !descriptor)
- /* There could have been a legitimate RO change. */
- rv2 = validate_and_cache_ap_ro_v2_from_flash();
- /*
- * Unless V2 entry is not found, override the V1 result.
- */
- if (rv2 != ROV_NOT_FOUND)
- rv = rv2;
- }
disable_ap_spi_hash_shortcut();
+ /* Failure reason has already been reported. */
if (rv != ROV_SUCCEEDED) {
- /* Failure reason has already been reported. */
-
- if ((rv == ROV_FAILED) || check_is_required()) {
- apro_result = AP_RO_FAIL;
- ap_ro_add_flash_event(APROF_CHECK_FAILED);
- keep_ec_in_reset();
- /*
- * Map failures into EC_ERROR_CRC, this will make sure
- * that in case this was invoked by the operator
- * keypress, the device will not continue booting.
- *
- * Both explicit failure to verify OR any error if
- * cached descriptor was found should block the
- * booting.
- */
- return EC_ERROR_CRC;
- }
-
- apro_result = AP_RO_UNSUPPORTED_TRIGGERED;
- ap_ro_add_flash_event(APROF_CHECK_UNSUPPORTED);
- return EC_ERROR_UNIMPLEMENTED;
+ CPRINTS("AP RO FAILED!");
+ apro_result = AP_RO_FAIL;
+ ap_ro_add_flash_event(APROF_CHECK_FAILED);
+ keep_ec_in_reset();
+ /*
+ * Map failures into EC_ERROR_CRC, this will make sure
+ * that in case this was invoked by the operator
+ * keypress, the device will not continue booting.
+ *
+ * Both explicit failure to verify OR any error if
+ * cached descriptor was found should block the
+ * booting.
+ */
+ return EC_ERROR_CRC;
}
-
apro_result = AP_RO_PASS_UNVERIFIED_GBB;
ap_ro_add_flash_event(APROF_CHECK_SUCCEEDED);
CPRINTS("AP RO PASS!");
release_ec_reset_override();
-
return EC_SUCCESS;
}