google-misc: libcr51sign: add feature to fetch image regions
Change-Id: I6bd45b0f855ac7c035b294e461bbe9821fb3895b
Signed-off-by: Willy Tu <wltu@google.com>
diff --git a/subprojects/libcr51sign/cr51_image_descriptor.h b/subprojects/libcr51sign/cr51_image_descriptor.h
index 1341ba9..0f4bf6f 100644
--- a/subprojects/libcr51sign/cr51_image_descriptor.h
+++ b/subprojects/libcr51sign/cr51_image_descriptor.h
@@ -56,6 +56,10 @@
#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)
/* Little endian on flash. */
#define DESCRIPTOR_MAGIC 0x5f435344474d495f // "_IMGDSC_"
@@ -68,11 +72,12 @@
/* Indicates the type of the image. The type of the image also indicates the
* family of key that was used to sign the image.
*
- * Note: if the image type is IMAGE_SELF, the signature_scheme has to be of type
+ * 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_SELF.
+ * type IMAGE_UNSIGNED_INTEGRITY.
*
- * The way to verify an image of type IMAGE_SELF differs from
+ * 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.
*/
@@ -82,7 +87,7 @@
IMAGE_PROD = 1,
IMAGE_BREAKOUT = 2,
IMAGE_TEST = 3,
- IMAGE_SELF = 4
+ IMAGE_UNSIGNED_INTEGRITY = 4
};
enum hash_type
@@ -98,8 +103,8 @@
HASH_SHA3_512 = 8
};
-/* Note: If the image is of type IMAGE_SELF, the signature_scheme has to be of
- * type *_ONLY_NO_SIGNATURE.
+/* Note: If the image is of type IMAGE_UNSIGNED_INTEGRITY, the signature_scheme
+ * has to be of type *_ONLY_NO_SIGNATURE.
*/
enum signature_scheme
{
@@ -196,7 +201,7 @@
/* Seconds since epoch. */
uint64_t build_timestamp;
- /* image_type enum { DEV, PROD, BREAKOUT, SELF} */
+ /* image_type enum { DEV, PROD, BREAKOUT, UNSIGNED_INTEGRITY} */
uint8_t image_type;
/* 0: no denylist struct, 1: watermark only, >1: watermark + denylist */
uint8_t denylist_size;
diff --git a/subprojects/libcr51sign/libcr51sign.c b/subprojects/libcr51sign/libcr51sign.c
index 5546f86..7d2e1bb 100644
--- a/subprojects/libcr51sign/libcr51sign.c
+++ b/subprojects/libcr51sign/libcr51sign.c
@@ -37,8 +37,6 @@
// Maximum version supported. Major revisions are not backwards compatible.
#define MAX_MAJOR_VERSION 1
-#define MAX_REGION_COUNT 16
-
// Descriptor alignment on the external EEPROM.
#define DESCRIPTOR_ALIGNMENT (64 * 1024)
@@ -125,10 +123,10 @@
switch (type)
{
case HASH_SHA2_256:
- *size = SHA256_DIGEST_SIZE;
+ *size = LIBCR51SIGN_SHA256_DIGEST_SIZE;
return LIBCR51SIGN_SUCCESS;
case HASH_SHA2_512:
- *size = SHA512_DIGEST_SIZE;
+ *size = LIBCR51SIGN_SHA512_DIGEST_SIZE;
return LIBCR51SIGN_SUCCESS;
default:
return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
@@ -183,7 +181,10 @@
SIGNATURE_OFFSET));
// Read up to the modulus.
- const uint32_t read_len = SIGNATURE_OFFSET;
+ enum
+ {
+ read_len = SIGNATURE_OFFSET
+ };
uint8_t buffer[read_len];
// "modulus" & "signature" will not be indexed.
struct signature_rsa4096_pkcs15* sig_data = (void*)&buffer;
@@ -282,19 +283,24 @@
// If the array is consistent, proceeds to hash the static regions and
// validates the hash. d_offset is the absolute image descriptor offset
- static failure_reason
- validate_payload_regions(const struct libcr51sign_ctx* ctx,
- struct libcr51sign_intf* intf,
- uint32_t d_offset)
+ static failure_reason validate_payload_regions(
+ const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
+ uint32_t d_offset, struct libcr51sign_validated_regions* image_regions)
{
// Allocate buffer to accomodate largest supported hash-type(SHA512)
uint8_t magic_and_digest[MEMBER_SIZE(struct hash_sha512, hash_magic) +
- SHA512_DIGEST_SIZE];
- uint8_t dcrypto_digest[SHA512_DIGEST_SIZE];
- struct image_region regions[MAX_REGION_COUNT];
+ LIBCR51SIGN_SHA512_DIGEST_SIZE];
+ uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
uint32_t byte_count, region_count, image_size, hash_offset, digest_size;
uint8_t d_region_num = 0;
int i, rv;
+ struct image_region const* region;
+
+ if (image_regions == NULL)
+ {
+ CPRINTS(ctx, "Missing image region input");
+ return LIBCR51SIGN_ERROR_INVALID_REGION_INPUT;
+ }
BUILD_ASSERT((MEMBER_SIZE(struct hash_sha256, hash_magic) ==
MEMBER_SIZE(struct hash_sha512, hash_magic)));
@@ -303,9 +309,22 @@
hash_offset = d_offset + sizeof(struct image_descriptor) +
region_count * sizeof(struct image_region);
// Read the image_region array.
+
+ if (region_count > ARRAY_SIZE(image_regions->image_regions))
+ {
+ CPRINTS(ctx, "validate_payload_regions: "
+ "ctx->descriptor.region_count is greater "
+ "than LIBCR51SIGN_MAX_REGION_COUNT");
+ return LIBCR51SIGN_ERROR_INVALID_REGION_SIZE;
+ }
+
rv = intf->read(
ctx, d_offset + offsetof(struct image_descriptor, image_regions),
- region_count * sizeof(struct image_region), (uint8_t*)®ions);
+ region_count * sizeof(struct image_region),
+ (uint8_t*)&image_regions->image_regions);
+
+ image_regions->region_count = region_count;
+
if (rv != LIBCR51SIGN_SUCCESS)
{
CPRINTS(ctx,
@@ -316,27 +335,29 @@
// Validate that the regions are contiguous & exhaustive.
for (i = 0, byte_count = 0; i < region_count; i++)
{
+ region = image_regions->image_regions + i;
+
CPRINTS(ctx,
"validate_payload_regions: region #%d \"%s\" (%x - %x)", i,
- regions[i].region_name, regions[i].region_offset,
- regions[i].region_offset + regions[i].region_size);
- if ((regions[i].region_offset % IMAGE_REGION_ALIGNMENT) != 0 ||
- (regions[i].region_size % IMAGE_REGION_ALIGNMENT) != 0)
+ region->region_name, region->region_offset,
+ region->region_offset + region->region_size);
+ if ((region->region_offset % IMAGE_REGION_ALIGNMENT) != 0 ||
+ (region->region_size % IMAGE_REGION_ALIGNMENT) != 0)
{
CPRINTS(
ctx,
"validate_payload_regions: regions must be sector aligned");
return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
}
- if (regions[i].region_offset != byte_count ||
- regions[i].region_size > image_size - byte_count)
+ if (region->region_offset != byte_count ||
+ region->region_size > image_size - byte_count)
{
CPRINTS(ctx, "validate_payload_regions: invalid region array");
return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
}
- byte_count += regions[i].region_size;
+ byte_count += region->region_size;
// The image descriptor must be part of a static region.
- if (d_offset >= regions[i].region_offset && d_offset < byte_count)
+ if (d_offset >= region->region_offset && d_offset < byte_count)
{
d_region_num = i;
CPRINTS(
@@ -345,7 +366,7 @@
i);
// The descriptor can't span regions.
if (ctx->descriptor.descriptor_area_size > byte_count ||
- !(regions[i].region_attributes & IMAGE_REGION_STATIC))
+ !(region->region_attributes & IMAGE_REGION_STATIC))
{
CPRINTS(
ctx,
@@ -391,12 +412,14 @@
for (i = 0; i < region_count; i++)
{
uint32_t hash_start, hash_size;
- if (!(regions[i].region_attributes & IMAGE_REGION_STATIC))
+ region = image_regions->image_regions + i;
+
+ if (!(region->region_attributes & IMAGE_REGION_STATIC))
{
continue;
}
- hash_start = regions[i].region_offset;
- hash_size = regions[i].region_size;
+ hash_start = region->region_offset;
+ hash_size = region->region_size;
// Skip the descriptor.
do
@@ -409,11 +432,11 @@
if (!hash_size)
{
hash_start += ctx->descriptor.descriptor_area_size;
- hash_size = (regions[i].region_offset +
- regions[i].region_size - hash_start);
+ hash_size = (region->region_offset + region->region_size -
+ hash_start);
}
CPRINTS("validate_payload_regions: hashing %s (%x - %x)",
- regions[i].region_name, hash_start,
+ region->region_name, hash_start,
hash_start + hash_size);
// Read the image_region array.
rv = read_and_hash_update(ctx, intf, hash_start, hash_size);
@@ -422,8 +445,7 @@
return rv;
}
hash_start += hash_size;
- } while (hash_start !=
- regions[i].region_offset + regions[i].region_size);
+ } while (hash_start != region->region_offset + region->region_size);
}
rv = intf->hash_final((void*)ctx, (uint8_t*)dcrypto_digest);
@@ -443,6 +465,35 @@
return LIBCR51SIGN_SUCCESS;
}
+ // Create empty image_regions to pass to validate_payload_regions
+ // Support validate_payload_regions_helper to remove image_regions as a
+ // required input.
+
+ static failure_reason
+ allocate_and_validate_payload_regions(const struct libcr51sign_ctx* ctx,
+ struct libcr51sign_intf* intf,
+ uint32_t d_offset)
+ {
+ struct libcr51sign_validated_regions image_regions;
+ return validate_payload_regions(ctx, intf, d_offset, &image_regions);
+ }
+
+ // Wrapper around validate_payload_regions to allow nullptr for
+ // image_regions. Calls allocate_and_validate_payload_regions when
+ // image_regions is nullptr to create placer holder image_regions.
+
+ static failure_reason validate_payload_regions_helper(
+ const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
+ uint32_t d_offset, struct libcr51sign_validated_regions* image_regions)
+ {
+ if (image_regions)
+ {
+ return validate_payload_regions(ctx, intf, d_offset, image_regions);
+ }
+
+ return allocate_and_validate_payload_regions(ctx, intf, d_offset);
+ }
+
// Check if the given signature_scheme is supported.
// Returns nonzero on error, zero on success
@@ -514,10 +565,10 @@
uint32_t data_offset, uint32_t data_size, enum signature_scheme scheme,
uint32_t raw_signature_offset)
{
- uint8_t signature[MAX_SIGNATURE_SIZE];
+ uint8_t signature[LIBCR51SIGN_MAX_SIGNATURE_SIZE];
uint16_t key_size;
uint32_t digest_size;
- uint8_t dcrypto_digest[SHA512_DIGEST_SIZE];
+ uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
int rv;
enum hash_type hash_type;
@@ -646,7 +697,7 @@
ctx->descriptor.image_type != IMAGE_PROD &&
ctx->descriptor.image_type != IMAGE_BREAKOUT &&
ctx->descriptor.image_type != IMAGE_TEST &&
- ctx->descriptor.image_type != IMAGE_SELF)
+ ctx->descriptor.image_type != IMAGE_UNSIGNED_INTEGRITY)
{
CPRINTS(ctx, "validate_descriptor: bad image type");
return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
@@ -669,7 +720,7 @@
return rv;
}
if (ctx->descriptor.descriptor_major > MAX_MAJOR_VERSION ||
- ctx->descriptor.region_count > MAX_REGION_COUNT)
+ ctx->descriptor.region_count > LIBCR51SIGN_MAX_REGION_COUNT)
{
CPRINTS(ctx, "validate_descriptor: unsupported descriptor");
return LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR;
@@ -804,11 +855,14 @@
// data for the user of the library
// @param[in] intf - function pointers which interface to the current system
// and environment
+ // @param[out] image_regions - image_region pointer to an array for the
+ // output
//
// @return nonzero on error, zero on success
- failure_reason libcr51sign_validate(const struct libcr51sign_ctx* ctx,
- struct libcr51sign_intf* intf)
+ failure_reason libcr51sign_validate(
+ const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
+ struct libcr51sign_validated_regions* image_regions)
{
uint32_t image_limit = 0;
int rv, rv_first_desc = LIBCR51SIGN_SUCCESS;
@@ -846,7 +900,8 @@
if (rv == LIBCR51SIGN_SUCCESS)
{
- rv = validate_payload_regions(ctx, intf, descriptor_offset);
+ rv = validate_payload_regions_helper(
+ ctx, intf, descriptor_offset, image_regions);
if (rv == LIBCR51SIGN_SUCCESS)
{
CPRINTS(ctx, "validate: success!");
@@ -916,6 +971,10 @@
return "Invalid interface";
case LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME:
return "Invalid signature scheme";
+ case LIBCR51SIGN_ERROR_INVALID_REGION_INPUT:
+ return "Invalid image region input";
+ case LIBCR51SIGN_ERROR_INVALID_REGION_SIZE:
+ return "Invalid image region size";
default:
return "Unknown error";
}
diff --git a/subprojects/libcr51sign/libcr51sign.h b/subprojects/libcr51sign/libcr51sign.h
index 7210d26..d56fc05 100644
--- a/subprojects/libcr51sign/libcr51sign.h
+++ b/subprojects/libcr51sign/libcr51sign.h
@@ -26,11 +26,13 @@
{
#endif
-#define SHA256_DIGEST_SIZE 32
-#define SHA512_DIGEST_SIZE 64
+#define LIBCR51SIGN_SHA256_DIGEST_SIZE 32
+#define LIBCR51SIGN_SHA512_DIGEST_SIZE 64
+
+#define LIBCR51SIGN_MAX_REGION_COUNT 16
// Currently RSA4096 (in bytes).
-#define MAX_SIGNATURE_SIZE 512
+#define LIBCR51SIGN_MAX_SIGNATURE_SIZE 512
// List of common error codes that can be returned
enum libcr51sign_validation_failure_reason
@@ -59,6 +61,9 @@
LIBCR51SIGN_ERROR_INVALID_INTERFACE = 14,
LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME = 15,
LIBCR51SIGN_ERROR_MAX = 16,
+ // Invalid image region
+ LIBCR51SIGN_ERROR_INVALID_REGION_INPUT = 17,
+ LIBCR51SIGN_ERROR_INVALID_REGION_SIZE = 18,
};
struct libcr51sign_ctx
@@ -164,6 +169,12 @@
bool (*is_production_mode)();
};
+ struct libcr51sign_validated_regions
+ {
+ uint32_t region_count;
+ struct image_region image_regions[LIBCR51SIGN_MAX_REGION_COUNT];
+ };
+
// Check whether the signature on the image is valid.
// Validates the authenticity of an EEPROM image. Scans for & validates the
// signature on the image descriptor. If the descriptor validates, hashes
@@ -174,12 +185,14 @@
// data for the user of the library
// @param[in] intf - function pointers which interface to the current system
// and environment
+ // @param[out] image_regions - image_region pointer to an array for the
+ // output
//
// @return nonzero on error, zero on success
- enum libcr51sign_validation_failure_reason
- libcr51sign_validate(const struct libcr51sign_ctx* ctx,
- struct libcr51sign_intf* intf);
+ enum libcr51sign_validation_failure_reason libcr51sign_validate(
+ const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
+ struct libcr51sign_validated_regions* image_regions);
// Function to convert error code to string format
// @param[in] ec - error code