summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/ap_ro_root_key_hash.inc9
-rw-r--r--common/ap_ro_integrity_check.c285
2 files changed, 145 insertions, 149 deletions
diff --git a/board/cr50/ap_ro_root_key_hash.inc b/board/cr50/ap_ro_root_key_hash.inc
index 77cd53bd8f..af6ffa53fc 100644
--- a/board/cr50/ap_ro_root_key_hash.inc
+++ b/board/cr50/ap_ro_root_key_hash.inc
@@ -10,7 +10,8 @@
* sha256sum tests/devkeys/kernel_subkey.vbpubk
*/
-0x36, 0xb9, 0xc5, 0xfa, 0x6f, 0x5d, 0x04, 0x32,
-0xb9, 0xac, 0xbe, 0x8e, 0x2b, 0x7d, 0xa2, 0xe6,
-0x02, 0x16, 0x2a, 0x87, 0xa4, 0x25, 0x57, 0x5c,
-0x6d, 0x7b, 0xa9, 0x75, 0xa0, 0x44, 0x07, 0x08,
+0xe4, 0x32, 0xf2, 0x3d, 0x81, 0x1b, 0xe7, 0x95,
+0xaf, 0x8d, 0xdf, 0x60, 0x01, 0xd2, 0xa6, 0xc3,
+0xe2, 0x67, 0x5e, 0x32, 0x90, 0xbc, 0x02, 0x41,
+0x00, 0xe2, 0xa1, 0x0d, 0x0f, 0xd9, 0xc6, 0xee
+
diff --git a/common/ap_ro_integrity_check.c b/common/ap_ro_integrity_check.c
index 37e2a6311c..d1df192469 100644
--- a/common/ap_ro_integrity_check.c
+++ b/common/ap_ro_integrity_check.c
@@ -140,41 +140,6 @@ struct fmap_area_header {
uint16_t area_flags;
} __packed;
-/*
- * 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;
- uint16_t size; /* Size of this struct in bytes inclusive */
- 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. */
- /*
- * 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 VerifiedSection entries. */
- struct ro_range ranges[0];
-};
/* Cryptographic entities defined in vboot_reference. */
struct vb2_signature {
@@ -247,15 +212,57 @@ struct vb2_keyblock {
};
/*
+ * 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,
- * vb2_signature signature of the two objects above
+ * 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
- * vb2_packed_key RSA public key to use to verify the vb2_keyblock above.
- * The hash of this key is saved in the root_key_hash array
- * above.
*/
/*
@@ -273,20 +280,13 @@ enum vb2_crypto_algorithm {
struct gvd_container {
uint32_t offset;
struct gsc_verification_data gvd;
+ struct ro_ranges ranges;
};
-struct sig_container {
- uint32_t offset;
- struct vb2_signature sigh;
-};
struct kb_container {
uint32_t offset;
struct vb2_keyblock *kb;
};
-struct rootk_container {
- uint32_t offset;
- struct vb2_packed_key *rootk;
-};
/*
* Local representation of the RSA key and hashing mode, necessary for
@@ -826,40 +826,29 @@ static uint32_t find_fmap(struct fmap_header *fmh)
*/
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;
- if ((gvdc->gvd.gv_magic != GSC_VD_MAGIC) ||
- (gvdc->gvd.size !=
- (sizeof(gvdc->gvd) +
- sizeof(struct ro_range) * gvdc->gvd.range_count)) ||
- (gvdc->gvd.fmap_location != fmap_offset)) {
+ 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;
}
- return 0;
-}
-
-/**
- * Read signature structure header.
- *
- * This function does not yet read the entire signature, it reads the header
- * to determine the size of the signature to be able to gain access to the
- * next field in the RO_GSCVD layout. This is done to save memory on the heap,
- * and defer signature memory allocation until the signature is necessary,
- * leaving the heap available for root key and key block.
- *
- * @param sigc pointer to the signature container.
- *
- * @return zero on success, -1 on failure.
- */
-static int read_signature_header(struct sig_container *sigc)
-{
- if (read_ap_spi(&sigc->sigh, sigc->offset, sizeof(sigc->sigh),
- __LINE__) ||
- (sigc->sigh.sig_offset != sizeof(sigc->sigh))) {
- CPRINTS("Failed to read signature at %x", sigc->offset);
+ 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;
}
@@ -969,48 +958,61 @@ static int read_keyblock(struct kb_container *kbc)
* function returns error. Once the key is read verify its validity by
* comparing its hash against the known value.
*
- * @param rootkc container to place the root key into
+ * @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(struct rootk_container *rootkc)
+static int read_rootk(const struct gvd_container *gvdc,
+ struct vb2_packed_key **prootk)
{
struct sha256_ctx ctx;
- struct vb2_packed_key rootk;
size_t total_size;
+ struct vb2_packed_key *rootk;
+ const struct gsc_verification_data *gvd;
+ uint32_t key_offset;
- if (read_ap_spi(&rootk, rootkc->offset, sizeof(rootk), __LINE__) ||
- (rootk.key_offset != sizeof(rootk))) {
- CPRINTS("Failed to read root key at %x", rootkc->offset);
- return -1;
- }
+ gvd = &gvdc->gvd;
+
+ *prootk = NULL;
/* Let's read the root key body. */
- total_size = sizeof(rootk) + rootk.key_size + rootk.key_offset;
- if (shared_mem_acquire(total_size, (char **)&rootkc->rootk) !=
+ total_size = sizeof(*rootk) + gvd->root_key_header.key_size;
+ if (shared_mem_acquire(total_size, (char **)&rootk) !=
EC_SUCCESS) {
- rootkc->rootk = NULL;
- CPRINTS("Failed to allocated %d bytes",
- rootk.key_size + rootk.key_offset);
+ CPRINTS("Failed to allocate %d bytes", total_size);
return -1;
}
- /* Copy key rootk header. */
- memcpy(rootkc->rootk, &rootk, sizeof(rootk));
- if (read_ap_spi(rootkc->rootk + 1, rootkc->offset + sizeof(rootk),
- total_size - sizeof(rootk), __LINE__))
+ /* 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, rootkc->rootk, sizeof(rootk) + rootk.key_size);
+ 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;
}
@@ -1063,21 +1065,20 @@ static int validate_ranges_sha(const struct ro_range *ranges, size_t count,
* Read ranges as defined in gsc_verification_data structure.
*
* @param gvdc pointer to the gsc_verifcation_data container
- * @param ranges pointer to the array of ro_ranges structure to fill up
*
* @return zero on success, non zero on failure.
*/
-static int read_ranges(const struct gvd_container *gvdc,
- struct ro_ranges *ranges)
+static int read_ranges(struct gvd_container *gvdc)
{
size_t range_count = gvdc->gvd.range_count;
- if (range_count > ARRAY_SIZE(ranges->ranges)) {
+ if (range_count > ARRAY_SIZE(gvdc->ranges.ranges)) {
CPRINTS("Too many ranges in gvd (%d)", range_count);
return -1;
}
- return read_ap_spi(ranges->ranges, gvdc->offset + sizeof(gvdc->gvd),
+ return read_ap_spi(&gvdc->ranges,
+ gvdc->offset + sizeof(gvdc->gvd),
sizeof(struct ro_range) * range_count, __LINE__);
}
@@ -1091,43 +1092,43 @@ static int read_ranges(const struct gvd_container *gvdc,
* from AP flash, based on signature container information.
*
* @param gvd pointer to the gsc_verification_data header
- * @param ranges pointer to the array of ranges, AP flash offset:size pairs
* @param key pointer RSA key used for signing, vb2 representation
- * @param sig_container pointer to signature container, vb2 representation
*
* return 0 on success, nonzero on failure.
*/
-static int verify_gvd_signature(const struct gsc_verification_data *gvd,
- const struct ro_ranges *ranges,
- const struct vb2_packed_key *key,
- const struct sig_container *sigc)
+static int verify_gvd_signature(const struct gvd_container *gvdc,
+ const struct vb2_packed_key *key)
{
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))
return -1;
- if (shared_mem_acquire(sigc->sigh.sig_size, (char **)&sig_body) !=
- EC_SUCCESS) {
+ 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",
- sigc->sigh.sig_size);
+ gvdc->gvd.sig_header.sig_size);
return EC_ERROR_HW_INTERNAL;
}
- if (read_ap_spi(sig_body, sigc->offset + sigc->sigh.sig_offset,
- sigc->sigh.sig_size, __LINE__))
+ if (read_ap_spi(sig_body, sig_body_offset, sig_size, __LINE__))
goto exit;
- blocks[0].base = gvd;
- blocks[0].size = sizeof(*gvd);
- blocks[1].base = ranges;
- blocks[1].size = gvd->range_count * sizeof(ranges->ranges[0]);
+ 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, sigc->sigh.sig_size);
+ rv = verify_signature(blocks, &rsa_key, sig_body, sig_size);
exit:
CPRINTS("GVDC %sOK", rv ? "NOT " : "");
@@ -1148,15 +1149,15 @@ exit:
* If the dedicated page is not empty, it is erased.
*
* @param gvdc pointer to the gsc_verification_data container
- * @param ranges pointer to the ranges structure, gvd stores the range count
*
* @return 0 on success, non-zero on failure.
*/
-static int save_gvd_hash(struct gvd_container *gvdc, struct ro_ranges *ranges)
+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",
@@ -1181,6 +1182,7 @@ static int save_gvd_hash(struct gvd_container *gvdc, struct ro_ranges *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);
@@ -1211,25 +1213,26 @@ static int save_gvd_hash(struct gvd_container *gvdc, struct ro_ranges *ranges)
/**
* Verify gsc_verification_data cache.
*
- * @param gvd pointer to gsc_verification_data
- * @param ranges pointer to ro_ranges, gvd stores the range_count
+ * @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 gsc_verification_data *gvd,
- const struct ro_ranges *ranges,
+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, gvd, sizeof(*gvd));
+ SHA256_update(&ctx, &gvdc->gvd, sizeof(gvdc->gvd));
+
+ ranges = &gvdc->ranges;
SHA256_update(&ctx, ranges->ranges,
- gvd->range_count * sizeof(ranges->ranges[0]));
+ gvdc->gvd.range_count * sizeof(ranges->ranges[0]));
return DCRYPTO_equals(SHA256_final(&ctx), descriptor->digest,
SHA256_DIGEST_SIZE) != DCRYPTO_OK;
@@ -1251,7 +1254,6 @@ static int8_t validate_cached_ap_ro_v2(const struct gvd_descriptor *descriptor)
uint32_t fmap_offset;
struct gvd_container gvdc;
- struct ro_ranges ranges;
fmap_offset = descriptor->fmap_offset;
gvdc.offset = descriptor->gvd_offset;
@@ -1259,14 +1261,15 @@ static int8_t validate_cached_ap_ro_v2(const struct gvd_descriptor *descriptor)
if (read_gscvd_header(fmap_offset, &gvdc))
return -1;
- if (read_ranges(&gvdc, &ranges))
+ if (read_ranges(&gvdc))
return -1;
- if (gvd_cache_check(&gvdc.gvd, &ranges, descriptor)) {
+ if (gvd_cache_check(&gvdc, descriptor)) {
CPRINTS("GVD HASH MISMATCH!!");
return -1;
}
- return validate_ranges_sha(ranges.ranges, gvdc.gvd.range_count,
+
+ return validate_ranges_sha(gvdc.ranges.ranges, gvdc.gvd.range_count,
gvdc.gvd.ranges_digest) ==
EC_SUCCESS ? 0 : -1;
}
@@ -1287,13 +1290,11 @@ static int8_t validate_and_cache_ap_ro_v2_from_flash(void)
uint32_t fmap_offset;
struct fmap_header fmh;
struct gvd_container gvdc;
- struct sig_container sigc;
struct kb_container kbc;
- struct rootk_container rootkc;
struct vb_rsa_pubk pubk;
- struct ro_ranges ranges;
struct fmap_area_header fmap;
struct fmap_area_header gscvd;
+ struct vb2_packed_key *rootk = NULL;
int rv = -1;
@@ -1309,47 +1310,41 @@ static int8_t validate_and_cache_ap_ro_v2_from_flash(void)
if (read_gscvd_header(fmap_offset, &gvdc))
return -1;
- if (read_ranges(&gvdc, &ranges))
- return -1;
-
- /* Signature comes after gscvd. */
- sigc.offset = gvdc.offset + gvdc.gvd.size;
- if (read_signature_header(&sigc))
+ if (read_ranges(&gvdc))
return -1;
- kbc.offset = sigc.offset + sigc.sigh.sig_offset + sigc.sigh.sig_size;
+ kbc.offset = gvdc.offset + gvdc.gvd.size;
if (read_keyblock(&kbc))
return -1;
- rootkc.offset = kbc.offset + kbc.kb->keyblock_size;
- if (read_rootk(&rootkc))
+ if (read_rootk(&gvdc, &rootk))
goto exit;
/* Root key hash matches, let's verify the platform key. */
- if (unpack_pubk(rootkc.rootk, &pubk))
+ if (unpack_pubk(rootk, &pubk))
goto exit;
if (verify_keyblock(&kbc, &pubk))
goto exit;
- shared_mem_release(rootkc.rootk);
- rootkc.rootk = NULL;
+ shared_mem_release(rootk);
+ rootk = NULL;
- if (verify_gvd_signature(&gvdc.gvd, &ranges, &kbc.kb->data_key, &sigc))
+ if (verify_gvd_signature(&gvdc, &kbc.kb->data_key))
return -1;
- rv = validate_ranges_sha(ranges.ranges, gvdc.gvd.range_count,
+ rv = validate_ranges_sha(gvdc.ranges.ranges, gvdc.gvd.range_count,
gvdc.gvd.ranges_digest);
if (!rv) {
/* Verification succeeded, save the hash for the next time. */
- rv = save_gvd_hash(&gvdc, &ranges);
+ rv = save_gvd_hash(&gvdc);
}
exit:
if (kbc.kb)
shared_mem_release(kbc.kb);
- if (rootkc.rootk)
- shared_mem_release(rootkc.rootk);
+ if (rootk)
+ shared_mem_release(rootk);
return rv;
}