diff options
author | Mary Ruthven <mruthven@chromium.org> | 2022-08-26 11:32:12 -0700 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2022-09-23 01:57:37 +0000 |
commit | 3cd09fe99b278ccece53248a01b04078e7ae6798 (patch) | |
tree | 4e900d0d6c8518b9728330538f88f48a60907cd4 | |
parent | 9123b238b7be811a73bffbf2cd69f63c30c80170 (diff) | |
download | chrome-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.c | 1054 |
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; } |