clang-format: copy latest and re-format
clang-format-17 has some backwards incompatible changes that require
additional settings for best compatibility and re-running the formatter.
Copy the latest .clang-format from the docs repository and reformat the
repository.
Change-Id: I4610d1d37873b2019baa2ae22c036f81f4319214
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/subprojects/libcr51sign/src/libcr51sign.c b/subprojects/libcr51sign/src/libcr51sign.c
index fff1826..75d8b70 100644
--- a/subprojects/libcr51sign/src/libcr51sign.c
+++ b/subprojects/libcr51sign/src/libcr51sign.c
@@ -53,943 +53,923 @@
#define BUILD_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)]))
#endif
- typedef enum libcr51sign_validation_failure_reason failure_reason;
+typedef enum libcr51sign_validation_failure_reason failure_reason;
- // Returns the bytes size of keys used in the given signature_scheme.
- // Return error if signature_scheme is invalid.
- //
- static failure_reason get_key_size(enum signature_scheme signature_scheme,
- uint16_t* key_size)
+// Returns the bytes size of keys used in the given signature_scheme.
+// Return error if signature_scheme is invalid.
+//
+static failure_reason get_key_size(enum signature_scheme signature_scheme,
+ uint16_t* key_size)
+{
+ switch (signature_scheme)
{
- switch (signature_scheme)
- {
- case SIGNATURE_RSA2048_PKCS15:
- *key_size = 256;
- return LIBCR51SIGN_SUCCESS;
- case SIGNATURE_RSA3072_PKCS15:
- *key_size = 384;
- return LIBCR51SIGN_SUCCESS;
- case SIGNATURE_RSA4096_PKCS15:
- case SIGNATURE_RSA4096_PKCS15_SHA512:
- *key_size = 512;
- return LIBCR51SIGN_SUCCESS;
- default:
- return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
- }
+ case SIGNATURE_RSA2048_PKCS15:
+ *key_size = 256;
+ return LIBCR51SIGN_SUCCESS;
+ case SIGNATURE_RSA3072_PKCS15:
+ *key_size = 384;
+ return LIBCR51SIGN_SUCCESS;
+ case SIGNATURE_RSA4096_PKCS15:
+ case SIGNATURE_RSA4096_PKCS15_SHA512:
+ *key_size = 512;
+ return LIBCR51SIGN_SUCCESS;
+ default:
+ return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
+ }
+}
+
+// Returns the hash_type for a given signature scheme
+// Returns error if scheme is invalid.
+failure_reason get_hash_type_from_signature(enum signature_scheme scheme,
+ enum hash_type* type)
+{
+ switch (scheme)
+ {
+ case SIGNATURE_RSA2048_PKCS15:
+ case SIGNATURE_RSA3072_PKCS15:
+ case SIGNATURE_RSA4096_PKCS15:
+ *type = HASH_SHA2_256;
+ return LIBCR51SIGN_SUCCESS;
+ case SIGNATURE_RSA4096_PKCS15_SHA512:
+ *type = HASH_SHA2_512;
+ return LIBCR51SIGN_SUCCESS;
+ default:
+ return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
+ }
+}
+
+// Check if the given hash_type is supported.
+// Returns error if hash_type is not supported.
+static failure_reason is_hash_type_supported(enum hash_type type)
+{
+ switch (type)
+ {
+ case HASH_SHA2_256:
+ case HASH_SHA2_512:
+ return LIBCR51SIGN_SUCCESS;
+ default:
+ return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
+ }
+}
+
+// Determines digest size for a given hash_type.
+// Returns error if hash_type is not supported.
+static failure_reason get_hash_digest_size(enum hash_type type, uint32_t* size)
+{
+ switch (type)
+ {
+ case HASH_SHA2_256:
+ *size = LIBCR51SIGN_SHA256_DIGEST_SIZE;
+ return LIBCR51SIGN_SUCCESS;
+ case HASH_SHA2_512:
+ *size = LIBCR51SIGN_SHA512_DIGEST_SIZE;
+ return LIBCR51SIGN_SUCCESS;
+ default:
+ return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
+ }
+}
+
+// Determines hash struct size for a given hash_type.
+// Returns error if hash_type is not supported.
+static failure_reason get_hash_struct_size(enum hash_type type, uint32_t* size)
+{
+ switch (type)
+ {
+ case HASH_SHA2_256:
+ *size = sizeof(struct hash_sha256);
+ return LIBCR51SIGN_SUCCESS;
+ case HASH_SHA2_512:
+ *size = sizeof(struct hash_sha256);
+ return LIBCR51SIGN_SUCCESS;
+ default:
+ return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
+ }
+}
+
+// Checks that:
+// - The signing key is trusted
+// - The target version is not denylisted
+// If validating a staged update, also checks that:
+// - The target image family matches the current image family
+// - The image type transition is legal (i.e. dev -> *|| prod -> prod) or
+// alternatively that the hardware ID is allowlisted
+// Assuming the caller has performed following:
+// board_get_base_key_index();
+// board_get_key_array
+// Possible return codes:
+// LIBCR51SIGN_SUCCESS = 0,
+// LIBCR51SIGN_ERROR_RUNTIME_FAILURE = 1,
+// LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR = 3,
+// LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY = 4,
+// LIBCR51SIGN_ERROR_IMAGE_TYPE_DISALLOWED = 5,
+
+static failure_reason validate_transition(const struct libcr51sign_ctx* ctx,
+ const struct libcr51sign_intf* intf,
+ uint32_t signature_struct_offset)
+{
+ BUILD_ASSERT((offsetof(struct signature_rsa2048_pkcs15, modulus) ==
+ SIGNATURE_OFFSET &&
+ offsetof(struct signature_rsa3072_pkcs15, modulus) ==
+ SIGNATURE_OFFSET &&
+ offsetof(struct signature_rsa4096_pkcs15, modulus) ==
+ SIGNATURE_OFFSET));
+
+ // Read up to the modulus.
+ enum
+ {
+ read_len = SIGNATURE_OFFSET
+ };
+ uint8_t buffer[read_len];
+ int rv;
+ rv = intf->read(ctx, signature_struct_offset, read_len, buffer);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx, "validate_transition: failed to read signature struct\n");
+ return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
+ }
+ if (*(uint32_t*)buffer != SIGNATURE_MAGIC)
+ {
+ CPRINTS(ctx, "validate_transition: bad signature magic\n");
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
}
- // Returns the hash_type for a given signature scheme
- // Returns error if scheme is invalid.
- failure_reason get_hash_type_from_signature(enum signature_scheme scheme,
- enum hash_type* type)
+ if (ctx->descriptor.image_family != ctx->current_image_family &&
+ ctx->descriptor.image_family != IMAGE_FAMILY_ALL &&
+ ctx->current_image_family != IMAGE_FAMILY_ALL)
{
- switch (scheme)
- {
- case SIGNATURE_RSA2048_PKCS15:
- case SIGNATURE_RSA3072_PKCS15:
- case SIGNATURE_RSA4096_PKCS15:
- *type = HASH_SHA2_256;
- return LIBCR51SIGN_SUCCESS;
- case SIGNATURE_RSA4096_PKCS15_SHA512:
- *type = HASH_SHA2_512;
- return LIBCR51SIGN_SUCCESS;
- default:
- return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
- }
+ CPRINTS(ctx, "validate_transition: invalid image family\n");
+ return LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY;
}
- // Check if the given hash_type is supported.
- // Returns error if hash_type is not supported.
- static failure_reason is_hash_type_supported(enum hash_type type)
+ if (intf->is_production_mode == NULL)
{
- switch (type)
+ CPRINTS(ctx, "validate_transition: missing is_production_mode\n");
+ return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
+ }
+ if (intf->is_production_mode() && (ctx->descriptor.image_type == IMAGE_DEV))
+ {
+ CPRINTS(ctx, "validate_transition: checking exemption allowlist\n");
+
+ // If function is NULL or if the function call return false, return
+ // error
+ if (intf->prod_to_dev_downgrade_allowed == NULL ||
+ !intf->prod_to_dev_downgrade_allowed())
{
- case HASH_SHA2_256:
- case HASH_SHA2_512:
- return LIBCR51SIGN_SUCCESS;
- default:
- return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
+ CPRINTS(ctx, "validate_transition: illegal image type\n");
+ return LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED;
}
}
+ return LIBCR51SIGN_SUCCESS;
+}
- // Determines digest size for a given hash_type.
- // Returns error if hash_type is not supported.
- static failure_reason get_hash_digest_size(enum hash_type type,
- uint32_t* size)
+// If caller had provided read_and_hash_update call that, otherwise call
+// read and then update.
+
+static failure_reason read_and_hash_update(const struct libcr51sign_ctx* ctx,
+ const struct libcr51sign_intf* intf,
+ uint32_t offset, uint32_t size)
+{
+ uint8_t read_buffer[MAX_READ_SIZE];
+ int rv;
+ int read_size;
+
+ if (intf->read_and_hash_update)
{
- switch (type)
- {
- case HASH_SHA2_256:
- *size = LIBCR51SIGN_SHA256_DIGEST_SIZE;
- return LIBCR51SIGN_SUCCESS;
- case HASH_SHA2_512:
- *size = LIBCR51SIGN_SHA512_DIGEST_SIZE;
- return LIBCR51SIGN_SUCCESS;
- default:
- return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
- }
+ rv = intf->read_and_hash_update((void*)ctx, offset, size);
}
-
- // Determines hash struct size for a given hash_type.
- // Returns error if hash_type is not supported.
- static failure_reason get_hash_struct_size(enum hash_type type,
- uint32_t* size)
+ else
{
- switch (type)
+ if (!intf->hash_update)
{
- case HASH_SHA2_256:
- *size = sizeof(struct hash_sha256);
- return LIBCR51SIGN_SUCCESS;
- case HASH_SHA2_512:
- *size = sizeof(struct hash_sha256);
- return LIBCR51SIGN_SUCCESS;
- default:
- return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
- }
- }
-
- // Checks that:
- // - The signing key is trusted
- // - The target version is not denylisted
- // If validating a staged update, also checks that:
- // - The target image family matches the current image family
- // - The image type transition is legal (i.e. dev -> *|| prod -> prod) or
- // alternatively that the hardware ID is allowlisted
- // Assuming the caller has performed following:
- // board_get_base_key_index();
- // board_get_key_array
- // Possible return codes:
- // LIBCR51SIGN_SUCCESS = 0,
- // LIBCR51SIGN_ERROR_RUNTIME_FAILURE = 1,
- // LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR = 3,
- // LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY = 4,
- // LIBCR51SIGN_ERROR_IMAGE_TYPE_DISALLOWED = 5,
-
- static failure_reason
- validate_transition(const struct libcr51sign_ctx* ctx,
- const struct libcr51sign_intf* intf,
- uint32_t signature_struct_offset)
- {
- BUILD_ASSERT((offsetof(struct signature_rsa2048_pkcs15, modulus) ==
- SIGNATURE_OFFSET &&
- offsetof(struct signature_rsa3072_pkcs15, modulus) ==
- SIGNATURE_OFFSET &&
- offsetof(struct signature_rsa4096_pkcs15, modulus) ==
- SIGNATURE_OFFSET));
-
- // Read up to the modulus.
- enum
- {
- read_len = SIGNATURE_OFFSET
- };
- uint8_t buffer[read_len];
- int rv;
- rv = intf->read(ctx, signature_struct_offset, read_len, buffer);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(ctx,
- "validate_transition: failed to read signature struct\n");
- return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
- }
- if (*(uint32_t*)buffer != SIGNATURE_MAGIC)
- {
- CPRINTS(ctx, "validate_transition: bad signature magic\n");
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
-
- if (ctx->descriptor.image_family != ctx->current_image_family &&
- ctx->descriptor.image_family != IMAGE_FAMILY_ALL &&
- ctx->current_image_family != IMAGE_FAMILY_ALL)
- {
- CPRINTS(ctx, "validate_transition: invalid image family\n");
- return LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY;
- }
-
- if (intf->is_production_mode == NULL)
- {
- CPRINTS(ctx, "validate_transition: missing is_production_mode\n");
+ CPRINTS(ctx, "read_and_hash_update: missing hash_update\n");
return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
}
- if (intf->is_production_mode() &&
- (ctx->descriptor.image_type == IMAGE_DEV))
+ do
{
- CPRINTS(ctx, "validate_transition: checking exemption allowlist\n");
-
- // If function is NULL or if the function call return false, return
- // error
- if (intf->prod_to_dev_downgrade_allowed == NULL ||
- !intf->prod_to_dev_downgrade_allowed())
+ read_size = size < MAX_READ_SIZE ? size : MAX_READ_SIZE;
+ rv = intf->read((void*)ctx, offset, read_size, read_buffer);
+ if (rv != LIBCR51SIGN_SUCCESS)
{
- CPRINTS(ctx, "validate_transition: illegal image type\n");
- return LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED;
+ return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
}
- }
- return LIBCR51SIGN_SUCCESS;
+ rv = intf->hash_update((void*)ctx, read_buffer, read_size);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
+ }
+ offset += read_size;
+ size -= read_size;
+ } while (size > 0);
+ }
+ return rv;
+}
+
+// Validates the image_region array, namely that:
+// - The regions are aligned, contiguous & exhaustive
+// - That the image descriptor resides in a static region
+//
+// 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, 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) +
+ LIBCR51SIGN_SHA512_DIGEST_SIZE];
+ uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
+ uint32_t byte_count, region_count, image_size, hash_offset, digest_size;
+ uint32_t i;
+ uint8_t d_region_num = 0;
+ int rv;
+ const struct image_region* region;
+
+ if (image_regions == NULL)
+ {
+ CPRINTS(ctx, "Missing image region input\n");
+ return LIBCR51SIGN_ERROR_INVALID_REGION_INPUT;
}
- // If caller had provided read_and_hash_update call that, otherwise call
- // read and then update.
+ BUILD_ASSERT((MEMBER_SIZE(struct hash_sha256, hash_magic) ==
+ MEMBER_SIZE(struct hash_sha512, hash_magic)));
+ image_size = ctx->descriptor.image_size;
+ region_count = ctx->descriptor.region_count;
+ hash_offset = d_offset + sizeof(struct image_descriptor) +
+ region_count * sizeof(struct image_region);
+ // Read the image_region array.
- static failure_reason
- read_and_hash_update(const struct libcr51sign_ctx* ctx,
- const struct libcr51sign_intf* intf,
- uint32_t offset, uint32_t size)
+ if (region_count > ARRAY_SIZE(image_regions->image_regions))
{
- uint8_t read_buffer[MAX_READ_SIZE];
- int rv;
- int read_size;
+ CPRINTS(ctx, "validate_payload_regions: "
+ "ctx->descriptor.region_count is greater "
+ "than LIBCR51SIGN_MAX_REGION_COUNT\n");
+ return LIBCR51SIGN_ERROR_INVALID_REGION_SIZE;
+ }
- if (intf->read_and_hash_update)
+ rv = intf->read(ctx, d_offset + sizeof(struct image_descriptor),
+ region_count * sizeof(struct image_region),
+ (uint8_t*)&image_regions->image_regions);
+
+ image_regions->region_count = region_count;
+
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx, "validate_payload_regions: failed to read region array\n");
+ return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
+ }
+
+ // 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)\n",
+ i, (const char*)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)
{
- rv = intf->read_and_hash_update((void*)ctx, offset, size);
+ CPRINTS(ctx, "validate_payload_regions: regions must be sector "
+ "aligned\n");
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
}
- else
+ if (region->region_offset != byte_count ||
+ region->region_size > image_size - byte_count)
{
- if (!intf->hash_update)
+ CPRINTS(ctx, "validate_payload_regions: invalid region array\n");
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
+ }
+ byte_count += region->region_size;
+ // The image descriptor must be part of a static region.
+ if (d_offset >= region->region_offset && d_offset < byte_count)
+ {
+ d_region_num = i;
+ CPRINTS(ctx,
+ "validate_payload_regions: image descriptor in region %d\n",
+ i);
+ // The descriptor can't span regions.
+ if (ctx->descriptor.descriptor_area_size > byte_count ||
+ !(region->region_attributes & IMAGE_REGION_STATIC))
{
- CPRINTS(ctx, "read_and_hash_update: missing hash_update\n");
- return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
+ CPRINTS(ctx,
+ "validate_payload_regions: descriptor must reside in "
+ "static region\n");
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
}
- do
- {
- read_size = size < MAX_READ_SIZE ? size : MAX_READ_SIZE;
- rv = intf->read((void*)ctx, offset, read_size, read_buffer);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
- }
- rv = intf->hash_update((void*)ctx, read_buffer, read_size);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
- }
- offset += read_size;
- size -= read_size;
- } while (size > 0);
}
+ }
+ if (byte_count != image_size)
+ {
+ CPRINTS(ctx, "validate_payload_regions: invalid image size\n");
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
+ }
+
+ rv = get_hash_digest_size(ctx->descriptor.hash_type, &digest_size);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
return rv;
}
- // Validates the image_region array, namely that:
- // - The regions are aligned, contiguous & exhaustive
- // - That the image descriptor resides in a static region
- //
- // 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, struct libcr51sign_validated_regions* image_regions)
+ rv = intf->read(ctx, hash_offset,
+ MEMBER_SIZE(struct hash_sha256, hash_magic) + digest_size,
+ magic_and_digest);
+ if (rv != LIBCR51SIGN_SUCCESS)
{
- // Allocate buffer to accomodate largest supported hash-type(SHA512)
- uint8_t magic_and_digest[MEMBER_SIZE(struct hash_sha512, hash_magic) +
- LIBCR51SIGN_SHA512_DIGEST_SIZE];
- uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
- uint32_t byte_count, region_count, image_size, hash_offset, digest_size;
- uint32_t i;
- uint8_t d_region_num = 0;
- int rv;
- const struct image_region* region;
-
- if (image_regions == NULL)
- {
- CPRINTS(ctx, "Missing image region input\n");
- return LIBCR51SIGN_ERROR_INVALID_REGION_INPUT;
- }
-
- BUILD_ASSERT((MEMBER_SIZE(struct hash_sha256, hash_magic) ==
- MEMBER_SIZE(struct hash_sha512, hash_magic)));
- image_size = ctx->descriptor.image_size;
- region_count = ctx->descriptor.region_count;
- 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\n");
- return LIBCR51SIGN_ERROR_INVALID_REGION_SIZE;
- }
-
- rv = intf->read(ctx, d_offset + sizeof(struct image_descriptor),
- region_count * sizeof(struct image_region),
- (uint8_t*)&image_regions->image_regions);
-
- image_regions->region_count = region_count;
-
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(ctx,
- "validate_payload_regions: failed to read region array\n");
- return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
- }
-
- // 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)\n",
- i, (const char*)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\n");
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
- if (region->region_offset != byte_count ||
- region->region_size > image_size - byte_count)
- {
- CPRINTS(ctx,
- "validate_payload_regions: invalid region array\n");
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
- byte_count += region->region_size;
- // The image descriptor must be part of a static region.
- if (d_offset >= region->region_offset && d_offset < byte_count)
- {
- d_region_num = i;
- CPRINTS(
- ctx,
- "validate_payload_regions: image descriptor in region %d\n",
- i);
- // The descriptor can't span regions.
- if (ctx->descriptor.descriptor_area_size > byte_count ||
- !(region->region_attributes & IMAGE_REGION_STATIC))
- {
- CPRINTS(
- ctx,
- "validate_payload_regions: descriptor must reside in "
- "static region\n");
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
- }
- }
- if (byte_count != image_size)
- {
- CPRINTS(ctx, "validate_payload_regions: invalid image size\n");
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
-
- rv = get_hash_digest_size(ctx->descriptor.hash_type, &digest_size);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return rv;
- }
-
- rv = intf->read(ctx, hash_offset,
- MEMBER_SIZE(struct hash_sha256, hash_magic) +
- digest_size,
- magic_and_digest);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(
- ctx,
+ CPRINTS(ctx,
"validate_payload_regions: failed to read hash from flash\n");
- return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
- }
- if (*(uint32_t*)magic_and_digest != HASH_MAGIC)
- {
- CPRINTS(ctx, "validate_payload_regions: bad hash magic\n");
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
- rv = intf->hash_init(ctx, ctx->descriptor.hash_type);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(ctx, "validate_payload_regions: hash_init failed\n");
- return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
- }
- for (i = 0; i < region_count; i++)
- {
- uint32_t hash_start, hash_size;
- region = image_regions->image_regions + i;
+ return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
+ }
+ if (*(uint32_t*)magic_and_digest != HASH_MAGIC)
+ {
+ CPRINTS(ctx, "validate_payload_regions: bad hash magic\n");
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
+ }
+ rv = intf->hash_init(ctx, ctx->descriptor.hash_type);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx, "validate_payload_regions: hash_init failed\n");
+ return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
+ }
+ for (i = 0; i < region_count; i++)
+ {
+ uint32_t hash_start, hash_size;
+ region = image_regions->image_regions + i;
- if (!(region->region_attributes & IMAGE_REGION_STATIC))
+ if (!(region->region_attributes & IMAGE_REGION_STATIC))
+ {
+ continue;
+ }
+ hash_start = region->region_offset;
+ hash_size = region->region_size;
+
+ // Skip the descriptor.
+ do
+ {
+ if (i == d_region_num)
{
- continue;
+ hash_size = d_offset - hash_start;
}
- hash_start = region->region_offset;
- hash_size = region->region_size;
- // Skip the descriptor.
- do
+ if (!hash_size)
{
- if (i == d_region_num)
- {
- hash_size = d_offset - hash_start;
- }
-
- if (!hash_size)
- {
- hash_start += ctx->descriptor.descriptor_area_size;
- hash_size = (region->region_offset + region->region_size -
- hash_start);
- }
- CPRINTS("validate_payload_regions: hashing %s (%x - %x)\n",
- (const char*)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);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return rv;
- }
- hash_start += hash_size;
- } while (hash_start != region->region_offset + region->region_size);
- }
- rv = intf->hash_final((void*)ctx, (uint8_t*)dcrypto_digest);
-
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
- }
-
- if (memcmp(magic_and_digest +
- MEMBER_SIZE(struct hash_sha256, hash_magic),
- dcrypto_digest, digest_size))
- {
- CPRINTS(ctx, "validate_payload_regions: invalid hash\n");
- return LIBCR51SIGN_ERROR_INVALID_HASH;
- }
- // Image is valid.
- 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
-
- static failure_reason
- is_signature_scheme_supported(enum signature_scheme scheme)
- {
- switch (scheme)
- {
- case SIGNATURE_RSA2048_PKCS15:
- case SIGNATURE_RSA3072_PKCS15:
- case SIGNATURE_RSA4096_PKCS15:
- case SIGNATURE_RSA4096_PKCS15_SHA512:
- return LIBCR51SIGN_SUCCESS;
- default:
- return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
- }
- }
-
- // Returns size of signature struct size in |size|
- // Returns nonzero on error, zero on success
-
- static failure_reason
- get_signature_struct_size(enum signature_scheme scheme, uint32_t* size)
- {
- switch (scheme)
- {
- case SIGNATURE_RSA2048_PKCS15:
- *size = sizeof(struct signature_rsa2048_pkcs15);
- return LIBCR51SIGN_SUCCESS;
- case SIGNATURE_RSA3072_PKCS15:
- *size = sizeof(struct signature_rsa3072_pkcs15);
- return LIBCR51SIGN_SUCCESS;
- case SIGNATURE_RSA4096_PKCS15:
- case SIGNATURE_RSA4096_PKCS15_SHA512:
- *size = sizeof(struct signature_rsa4096_pkcs15);
- return LIBCR51SIGN_SUCCESS;
- default:
- return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
- }
- }
-
- static failure_reason
- get_signature_field_offset(enum signature_scheme scheme,
- uint32_t* offset)
- {
- switch (scheme)
- {
- case SIGNATURE_RSA2048_PKCS15:
- *offset = offsetof(struct signature_rsa2048_pkcs15, signature);
- return LIBCR51SIGN_SUCCESS;
- case SIGNATURE_RSA3072_PKCS15:
- *offset = offsetof(struct signature_rsa3072_pkcs15, signature);
- return LIBCR51SIGN_SUCCESS;
- case SIGNATURE_RSA4096_PKCS15:
- case SIGNATURE_RSA4096_PKCS15_SHA512:
- *offset = offsetof(struct signature_rsa4096_pkcs15, signature);
- return LIBCR51SIGN_SUCCESS;
- default:
- return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
- }
- }
-
- // Validates the signature (of type scheme) read from "device" at
- //"raw_signature_offset" with "public_key" over a SHA256/SHA512 digest of
- // EEPROM area "data_offset:data_size".
-
- static failure_reason validate_signature(
- const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
- uint32_t data_offset, uint32_t data_size, enum signature_scheme scheme,
- uint32_t raw_signature_offset)
- {
- uint8_t signature[LIBCR51SIGN_MAX_SIGNATURE_SIZE];
- uint16_t key_size;
- uint32_t digest_size;
- uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
- int rv;
- enum hash_type hash_type;
-
- if (!intf->hash_init)
- {
- CPRINTS(ctx, "validate_signature: missing hash_init\n");
- return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
- }
- rv = get_hash_type_from_signature(scheme, &hash_type);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(
- ctx,
- "validate_payload_regions: hash_type from signature failed\n");
- return rv;
- }
- rv = intf->hash_init(ctx, hash_type);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(ctx, "validate_payload_regions: hash_init failed\n");
- return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
- }
- rv = read_and_hash_update(ctx, intf, data_offset, data_size);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(ctx, "validate_signature: hash_update failed\n");
- return rv;
- }
- if (!intf->hash_final)
- {
- CPRINTS(ctx, "validate_signature: missing hash_final\n");
- return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
- }
- rv = intf->hash_final((void*)ctx, dcrypto_digest);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(ctx,
- "validate_signature: hash_final failed (status = %d)\n",
- rv);
- return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
- }
- rv = get_key_size(scheme, &key_size);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return rv;
- }
-
- rv = intf->read(ctx, raw_signature_offset, key_size, signature);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(
- ctx,
- "validate_signature: failed to read signature (status = %d)\n",
- rv);
- return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
- }
- if (!intf->verify_signature)
- {
- CPRINTS(ctx, "validate_signature: missing verify_signature\n");
- return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
- }
- rv = get_hash_digest_size(hash_type, &digest_size);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return rv;
- }
- rv = intf->verify_signature(ctx, scheme, signature, key_size,
- dcrypto_digest, digest_size);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(ctx,
- "validate_signature: verification failed (status = %d)\n",
- rv);
- return LIBCR51SIGN_ERROR_INVALID_SIGNATURE;
- }
- CPRINTS(ctx, "validate_signature: verification succeeded\n");
- return LIBCR51SIGN_SUCCESS;
- }
-
- // Sanity checks the image descriptor & validates its signature.
- // This function does not validate the image_region array or image hash.
- //
- //@param[in] ctx context which describes the image and holds opaque private
- // data for the user of the library
- //@param[in] intf function pointers which interface to the current system
- // and environment
- //@param offset Absolute image descriptor flash offset.
- //@param relative_offset Image descriptor offset relative to image start.
- //@param max_size Maximum size of the flash space in bytes.
- //@param descriptor Output pointer to an image_descriptor struct
-
- static failure_reason validate_descriptor(
- const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
- uint32_t offset, uint32_t relative_offset, uint32_t max_size)
- {
- uint32_t max_descriptor_size, signed_size, signature_scheme,
- signature_offset;
- uint32_t signature_struct_offset, signature_struct_size,
- hash_struct_size;
- int rv;
-
- max_descriptor_size = max_size - relative_offset;
- if (max_size < relative_offset ||
- max_descriptor_size < sizeof(struct image_descriptor))
- {
- CPRINTS(ctx, "validate_descriptor: invalid arguments\n");
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
-
- rv = intf->read(ctx, offset, sizeof(ctx->descriptor),
- (uint8_t*)&ctx->descriptor);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(ctx, "validate_descriptor: failed to read descriptor\n");
- return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
- }
- if (ctx->descriptor.descriptor_magic != DESCRIPTOR_MAGIC ||
- ctx->descriptor.descriptor_offset != relative_offset ||
- ctx->descriptor.region_count == 0 ||
- ctx->descriptor.descriptor_area_size > max_descriptor_size ||
- ctx->descriptor.image_size > max_size)
- {
- CPRINTS(ctx, "validate_descriptor: invalid descriptor\n");
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
- if (intf->image_size_valid == NULL)
- {
- // Preserve original behavior of requiring exact image_size match if
- // no operator is provided.
- if (ctx->descriptor.image_size != max_size)
- {
- CPRINTS(ctx, "validate_descriptor: invalid image size\n");
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
+ hash_start += ctx->descriptor.descriptor_area_size;
+ hash_size =
+ (region->region_offset + region->region_size - hash_start);
}
- }
- else if (!intf->image_size_valid(ctx->descriptor.image_size))
- {
- CPRINTS(ctx, "validate_descriptor: invalid image size\n");
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
- if (ctx->descriptor.image_type != IMAGE_DEV &&
- ctx->descriptor.image_type != IMAGE_PROD &&
- ctx->descriptor.image_type != IMAGE_BREAKOUT &&
- ctx->descriptor.image_type != IMAGE_TEST &&
- ctx->descriptor.image_type != IMAGE_UNSIGNED_INTEGRITY)
- {
- CPRINTS(ctx, "validate_descriptor: bad image type\n");
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
- // Although the image_descriptor struct supports unauthenticated
- // images, Haven will not allow it.
- // Haven only supports SHA256 + RSA2048/RSA3072_PKCS15 currently.
-
- signature_scheme = ctx->descriptor.signature_scheme;
-
- rv = is_signature_scheme_supported(signature_scheme);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return rv;
- }
- rv = is_hash_type_supported(ctx->descriptor.hash_type);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(ctx, "validate_payload_regions: invalid hash type\n");
- return rv;
- }
- if (ctx->descriptor.descriptor_major > MAX_MAJOR_VERSION ||
- ctx->descriptor.region_count > LIBCR51SIGN_MAX_REGION_COUNT)
- {
- CPRINTS(ctx, "validate_descriptor: unsupported descriptor\n");
- return LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR;
- }
- rv = get_signature_struct_size(signature_scheme,
- &signature_struct_size);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return rv;
- }
-
- // Compute the size of the signed portion of the image descriptor.
- signed_size = sizeof(struct image_descriptor) +
- ctx->descriptor.region_count *
- sizeof(struct image_region);
- rv = get_hash_struct_size(ctx->descriptor.hash_type, &hash_struct_size);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return rv;
- }
- signed_size += hash_struct_size;
- if (ctx->descriptor.denylist_size)
- {
- signed_size += sizeof(struct denylist);
- signed_size += ctx->descriptor.denylist_size *
- sizeof(struct denylist_record);
- }
- if (ctx->descriptor.blob_size)
- {
- signed_size += sizeof(struct blob);
- // Previous additions are guaranteed not to overflow.
- if (ctx->descriptor.blob_size >
- ctx->descriptor.descriptor_area_size - signed_size)
- {
- CPRINTS(ctx, "validate_descriptor: invalid blob size (0x%x)\n",
- ctx->descriptor.blob_size);
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
- signed_size += ctx->descriptor.blob_size;
- }
- if (signature_struct_size >
- ctx->descriptor.descriptor_area_size - signed_size)
- {
- CPRINTS(ctx,
- "validate_descriptor: invalid descriptor area size "
- "(expected = 0x%x, actual = 0x%x)\n",
- ctx->descriptor.descriptor_area_size,
- signed_size + signature_struct_size);
- return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
- }
- signature_struct_offset = signed_size;
- // Omit the actual signature.
- rv = get_signature_field_offset(signature_scheme, &signature_offset);
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return rv;
- }
- signed_size += signature_offset;
-
- // Lookup key & validate transition.
- rv = validate_transition(ctx, intf, offset + signature_struct_offset);
-
- if (rv != LIBCR51SIGN_SUCCESS)
- {
- return rv;
- }
- return validate_signature(ctx, intf, offset, signed_size,
- signature_scheme, offset + signed_size);
- }
-
- // Scans the external EEPROM for a magic value at "alignment" boundaries.
- //
- //@param device Handle to the external EEPROM.
- //@param magic 8-byte pattern to search for.
- //@param start_offset Offset to begin searching at.
- //@param limit Exclusive address (e.g. EEPROM size).
- //@param alignment Alignment boundaries (POW2) to search on.
- //@param header_offset Location to place the new header offset.
- //@return LIBCR51SIGN_SUCCESS (or non-zero on error).
-
- int scan_for_magic_8(const struct libcr51sign_ctx* ctx,
- const struct libcr51sign_intf* intf, uint64_t magic,
- uint32_t start_offset, uint32_t limit,
- uint32_t alignment, uint32_t* header_offset)
- {
- uint64_t read_data;
- uint32_t offset;
- int rv;
-
- if (limit <= start_offset || limit > ctx->end_offset ||
- limit < sizeof(magic) || !POWER_OF_TWO(alignment))
- {
- return LIBCR51SIGN_ERROR_INVALID_ARGUMENT;
- }
-
- if (!intf->read)
- {
- CPRINTS(ctx, "scan_for_magic_8: missing intf->read\n");
- return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
- }
- // Align start_offset to the next valid boundary.
- start_offset = ((start_offset - 1) & ~(alignment - 1)) + alignment;
- for (offset = start_offset; offset < limit - sizeof(magic);
- offset += alignment)
- {
- rv = intf->read((void*)ctx, offset, sizeof(read_data),
- (uint8_t*)&read_data);
+ CPRINTS("validate_payload_regions: hashing %s (%x - %x)\n",
+ (const char*)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);
if (rv != LIBCR51SIGN_SUCCESS)
{
return rv;
}
- if (read_data == magic)
- {
- if (header_offset)
- {
- *header_offset = offset;
- }
- return LIBCR51SIGN_SUCCESS;
- }
- }
- // Failed to locate magic.
- return LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC;
+ hash_start += hash_size;
+ } while (hash_start != region->region_offset + region->region_size);
+ }
+ rv = intf->hash_final((void*)ctx, (uint8_t*)dcrypto_digest);
+
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
}
- // 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
- // the rest of the image to verify its integrity.
- //
- // @param[in] ctx - context which describes the image and holds opaque
- // private
- // 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,
- struct libcr51sign_validated_regions* image_regions)
+ if (memcmp(magic_and_digest + MEMBER_SIZE(struct hash_sha256, hash_magic),
+ dcrypto_digest, digest_size))
{
- uint32_t image_limit = 0;
- int rv, rv_first_desc = LIBCR51SIGN_SUCCESS;
- uint32_t descriptor_offset;
+ CPRINTS(ctx, "validate_payload_regions: invalid hash\n");
+ return LIBCR51SIGN_ERROR_INVALID_HASH;
+ }
+ // Image is valid.
+ return LIBCR51SIGN_SUCCESS;
+}
- if (!ctx)
+// 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
+
+static failure_reason
+ is_signature_scheme_supported(enum signature_scheme scheme)
+{
+ switch (scheme)
+ {
+ case SIGNATURE_RSA2048_PKCS15:
+ case SIGNATURE_RSA3072_PKCS15:
+ case SIGNATURE_RSA4096_PKCS15:
+ case SIGNATURE_RSA4096_PKCS15_SHA512:
+ return LIBCR51SIGN_SUCCESS;
+ default:
+ return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
+ }
+}
+
+// Returns size of signature struct size in |size|
+// Returns nonzero on error, zero on success
+
+static failure_reason get_signature_struct_size(enum signature_scheme scheme,
+ uint32_t* size)
+{
+ switch (scheme)
+ {
+ case SIGNATURE_RSA2048_PKCS15:
+ *size = sizeof(struct signature_rsa2048_pkcs15);
+ return LIBCR51SIGN_SUCCESS;
+ case SIGNATURE_RSA3072_PKCS15:
+ *size = sizeof(struct signature_rsa3072_pkcs15);
+ return LIBCR51SIGN_SUCCESS;
+ case SIGNATURE_RSA4096_PKCS15:
+ case SIGNATURE_RSA4096_PKCS15_SHA512:
+ *size = sizeof(struct signature_rsa4096_pkcs15);
+ return LIBCR51SIGN_SUCCESS;
+ default:
+ return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
+ }
+}
+
+static failure_reason get_signature_field_offset(enum signature_scheme scheme,
+ uint32_t* offset)
+{
+ switch (scheme)
+ {
+ case SIGNATURE_RSA2048_PKCS15:
+ *offset = offsetof(struct signature_rsa2048_pkcs15, signature);
+ return LIBCR51SIGN_SUCCESS;
+ case SIGNATURE_RSA3072_PKCS15:
+ *offset = offsetof(struct signature_rsa3072_pkcs15, signature);
+ return LIBCR51SIGN_SUCCESS;
+ case SIGNATURE_RSA4096_PKCS15:
+ case SIGNATURE_RSA4096_PKCS15_SHA512:
+ *offset = offsetof(struct signature_rsa4096_pkcs15, signature);
+ return LIBCR51SIGN_SUCCESS;
+ default:
+ return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
+ }
+}
+
+// Validates the signature (of type scheme) read from "device" at
+//"raw_signature_offset" with "public_key" over a SHA256/SHA512 digest of
+// EEPROM area "data_offset:data_size".
+
+static failure_reason validate_signature(const struct libcr51sign_ctx* ctx,
+ const struct libcr51sign_intf* intf,
+ uint32_t data_offset,
+ uint32_t data_size,
+ enum signature_scheme scheme,
+ uint32_t raw_signature_offset)
+{
+ uint8_t signature[LIBCR51SIGN_MAX_SIGNATURE_SIZE];
+ uint16_t key_size;
+ uint32_t digest_size;
+ uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
+ int rv;
+ enum hash_type hash_type;
+
+ if (!intf->hash_init)
+ {
+ CPRINTS(ctx, "validate_signature: missing hash_init\n");
+ return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
+ }
+ rv = get_hash_type_from_signature(scheme, &hash_type);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx,
+ "validate_payload_regions: hash_type from signature failed\n");
+ return rv;
+ }
+ rv = intf->hash_init(ctx, hash_type);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx, "validate_payload_regions: hash_init failed\n");
+ return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
+ }
+ rv = read_and_hash_update(ctx, intf, data_offset, data_size);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx, "validate_signature: hash_update failed\n");
+ return rv;
+ }
+ if (!intf->hash_final)
+ {
+ CPRINTS(ctx, "validate_signature: missing hash_final\n");
+ return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
+ }
+ rv = intf->hash_final((void*)ctx, dcrypto_digest);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx, "validate_signature: hash_final failed (status = %d)\n",
+ rv);
+ return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
+ }
+ rv = get_key_size(scheme, &key_size);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ return rv;
+ }
+
+ rv = intf->read(ctx, raw_signature_offset, key_size, signature);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx,
+ "validate_signature: failed to read signature (status = %d)\n",
+ rv);
+ return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
+ }
+ if (!intf->verify_signature)
+ {
+ CPRINTS(ctx, "validate_signature: missing verify_signature\n");
+ return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
+ }
+ rv = get_hash_digest_size(hash_type, &digest_size);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ return rv;
+ }
+ rv = intf->verify_signature(ctx, scheme, signature, key_size,
+ dcrypto_digest, digest_size);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx, "validate_signature: verification failed (status = %d)\n",
+ rv);
+ return LIBCR51SIGN_ERROR_INVALID_SIGNATURE;
+ }
+ CPRINTS(ctx, "validate_signature: verification succeeded\n");
+ return LIBCR51SIGN_SUCCESS;
+}
+
+// Sanity checks the image descriptor & validates its signature.
+// This function does not validate the image_region array or image hash.
+//
+//@param[in] ctx context which describes the image and holds opaque private
+// data for the user of the library
+//@param[in] intf function pointers which interface to the current system
+// and environment
+//@param offset Absolute image descriptor flash offset.
+//@param relative_offset Image descriptor offset relative to image start.
+//@param max_size Maximum size of the flash space in bytes.
+//@param descriptor Output pointer to an image_descriptor struct
+
+static failure_reason validate_descriptor(const struct libcr51sign_ctx* ctx,
+ const struct libcr51sign_intf* intf,
+ uint32_t offset,
+ uint32_t relative_offset,
+ uint32_t max_size)
+{
+ uint32_t max_descriptor_size, signed_size, signature_scheme,
+ signature_offset;
+ uint32_t signature_struct_offset, signature_struct_size, hash_struct_size;
+ int rv;
+
+ max_descriptor_size = max_size - relative_offset;
+ if (max_size < relative_offset ||
+ max_descriptor_size < sizeof(struct image_descriptor))
+ {
+ CPRINTS(ctx, "validate_descriptor: invalid arguments\n");
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
+ }
+
+ rv = intf->read(ctx, offset, sizeof(ctx->descriptor),
+ (uint8_t*)&ctx->descriptor);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx, "validate_descriptor: failed to read descriptor\n");
+ return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
+ }
+ if (ctx->descriptor.descriptor_magic != DESCRIPTOR_MAGIC ||
+ ctx->descriptor.descriptor_offset != relative_offset ||
+ ctx->descriptor.region_count == 0 ||
+ ctx->descriptor.descriptor_area_size > max_descriptor_size ||
+ ctx->descriptor.image_size > max_size)
+ {
+ CPRINTS(ctx, "validate_descriptor: invalid descriptor\n");
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
+ }
+ if (intf->image_size_valid == NULL)
+ {
+ // Preserve original behavior of requiring exact image_size match if
+ // no operator is provided.
+ if (ctx->descriptor.image_size != max_size)
{
- CPRINTS(ctx, "Missing context\n");
- return LIBCR51SIGN_ERROR_INVALID_CONTEXT;
+ CPRINTS(ctx, "validate_descriptor: invalid image size\n");
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
}
- else if (!intf)
+ }
+ else if (!intf->image_size_valid(ctx->descriptor.image_size))
+ {
+ CPRINTS(ctx, "validate_descriptor: invalid image size\n");
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
+ }
+ if (ctx->descriptor.image_type != IMAGE_DEV &&
+ ctx->descriptor.image_type != IMAGE_PROD &&
+ ctx->descriptor.image_type != IMAGE_BREAKOUT &&
+ ctx->descriptor.image_type != IMAGE_TEST &&
+ ctx->descriptor.image_type != IMAGE_UNSIGNED_INTEGRITY)
+ {
+ CPRINTS(ctx, "validate_descriptor: bad image type\n");
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
+ }
+ // Although the image_descriptor struct supports unauthenticated
+ // images, Haven will not allow it.
+ // Haven only supports SHA256 + RSA2048/RSA3072_PKCS15 currently.
+
+ signature_scheme = ctx->descriptor.signature_scheme;
+
+ rv = is_signature_scheme_supported(signature_scheme);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ return rv;
+ }
+ rv = is_hash_type_supported(ctx->descriptor.hash_type);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx, "validate_payload_regions: invalid hash type\n");
+ return rv;
+ }
+ if (ctx->descriptor.descriptor_major > MAX_MAJOR_VERSION ||
+ ctx->descriptor.region_count > LIBCR51SIGN_MAX_REGION_COUNT)
+ {
+ CPRINTS(ctx, "validate_descriptor: unsupported descriptor\n");
+ return LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR;
+ }
+ rv = get_signature_struct_size(signature_scheme, &signature_struct_size);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ return rv;
+ }
+
+ // Compute the size of the signed portion of the image descriptor.
+ signed_size = sizeof(struct image_descriptor) +
+ ctx->descriptor.region_count * sizeof(struct image_region);
+ rv = get_hash_struct_size(ctx->descriptor.hash_type, &hash_struct_size);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ return rv;
+ }
+ signed_size += hash_struct_size;
+ if (ctx->descriptor.denylist_size)
+ {
+ signed_size += sizeof(struct denylist);
+ signed_size += ctx->descriptor.denylist_size *
+ sizeof(struct denylist_record);
+ }
+ if (ctx->descriptor.blob_size)
+ {
+ signed_size += sizeof(struct blob);
+ // Previous additions are guaranteed not to overflow.
+ if (ctx->descriptor.blob_size >
+ ctx->descriptor.descriptor_area_size - signed_size)
{
- CPRINTS(ctx, "Missing interface\n");
- return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
+ CPRINTS(ctx, "validate_descriptor: invalid blob size (0x%x)\n",
+ ctx->descriptor.blob_size);
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
}
+ signed_size += ctx->descriptor.blob_size;
+ }
+ if (signature_struct_size >
+ ctx->descriptor.descriptor_area_size - signed_size)
+ {
+ CPRINTS(ctx,
+ "validate_descriptor: invalid descriptor area size "
+ "(expected = 0x%x, actual = 0x%x)\n",
+ ctx->descriptor.descriptor_area_size,
+ signed_size + signature_struct_size);
+ return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
+ }
+ signature_struct_offset = signed_size;
+ // Omit the actual signature.
+ rv = get_signature_field_offset(signature_scheme, &signature_offset);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ return rv;
+ }
+ signed_size += signature_offset;
- rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC, ctx->start_offset,
- ctx->end_offset, DESCRIPTOR_ALIGNMENT,
- &descriptor_offset);
- while (rv == LIBCR51SIGN_SUCCESS)
+ // Lookup key & validate transition.
+ rv = validate_transition(ctx, intf, offset + signature_struct_offset);
+
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ return rv;
+ }
+ return validate_signature(ctx, intf, offset, signed_size, signature_scheme,
+ offset + signed_size);
+}
+
+// Scans the external EEPROM for a magic value at "alignment" boundaries.
+//
+//@param device Handle to the external EEPROM.
+//@param magic 8-byte pattern to search for.
+//@param start_offset Offset to begin searching at.
+//@param limit Exclusive address (e.g. EEPROM size).
+//@param alignment Alignment boundaries (POW2) to search on.
+//@param header_offset Location to place the new header offset.
+//@return LIBCR51SIGN_SUCCESS (or non-zero on error).
+
+int scan_for_magic_8(const struct libcr51sign_ctx* ctx,
+ const struct libcr51sign_intf* intf, uint64_t magic,
+ uint32_t start_offset, uint32_t limit, uint32_t alignment,
+ uint32_t* header_offset)
+{
+ uint64_t read_data;
+ uint32_t offset;
+ int rv;
+
+ if (limit <= start_offset || limit > ctx->end_offset ||
+ limit < sizeof(magic) || !POWER_OF_TWO(alignment))
+ {
+ return LIBCR51SIGN_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (!intf->read)
+ {
+ CPRINTS(ctx, "scan_for_magic_8: missing intf->read\n");
+ return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
+ }
+ // Align start_offset to the next valid boundary.
+ start_offset = ((start_offset - 1) & ~(alignment - 1)) + alignment;
+ for (offset = start_offset; offset < limit - sizeof(magic);
+ offset += alignment)
+ {
+ rv = intf->read((void*)ctx, offset, sizeof(read_data),
+ (uint8_t*)&read_data);
+ if (rv != LIBCR51SIGN_SUCCESS)
{
- CPRINTS(ctx, "validate: potential image descriptor found @%x\n",
- descriptor_offset);
- // Validation is split into 2 functions to minimize
- // stack usage.
-
- rv = validate_descriptor(ctx, intf, descriptor_offset,
- descriptor_offset - ctx->start_offset,
- ctx->end_offset - ctx->start_offset);
- if (rv != LIBCR51SIGN_SUCCESS)
+ return rv;
+ }
+ if (read_data == magic)
+ {
+ if (header_offset)
{
- CPRINTS(ctx, "validate: validate_descriptor() failed ec%d\n",
- rv);
+ *header_offset = offset;
}
+ return LIBCR51SIGN_SUCCESS;
+ }
+ }
+ // Failed to locate magic.
+ return LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC;
+}
+// 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
+// the rest of the image to verify its integrity.
+//
+// @param[in] ctx - context which describes the image and holds opaque
+// private
+// 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,
+ struct libcr51sign_validated_regions* image_regions)
+{
+ uint32_t image_limit = 0;
+ int rv, rv_first_desc = LIBCR51SIGN_SUCCESS;
+ uint32_t descriptor_offset;
+
+ if (!ctx)
+ {
+ CPRINTS(ctx, "Missing context\n");
+ return LIBCR51SIGN_ERROR_INVALID_CONTEXT;
+ }
+ else if (!intf)
+ {
+ CPRINTS(ctx, "Missing interface\n");
+ return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
+ }
+
+ rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC, ctx->start_offset,
+ ctx->end_offset, DESCRIPTOR_ALIGNMENT,
+ &descriptor_offset);
+ while (rv == LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx, "validate: potential image descriptor found @%x\n",
+ descriptor_offset);
+ // Validation is split into 2 functions to minimize
+ // stack usage.
+
+ rv = validate_descriptor(ctx, intf, descriptor_offset,
+ descriptor_offset - ctx->start_offset,
+ ctx->end_offset - ctx->start_offset);
+ if (rv != LIBCR51SIGN_SUCCESS)
+ {
+ CPRINTS(ctx, "validate: validate_descriptor() failed ec%d\n", rv);
+ }
+
+ if (rv == LIBCR51SIGN_SUCCESS)
+ {
+ rv = validate_payload_regions_helper(ctx, intf, descriptor_offset,
+ image_regions);
if (rv == LIBCR51SIGN_SUCCESS)
{
- rv = validate_payload_regions_helper(
- ctx, intf, descriptor_offset, image_regions);
- if (rv == LIBCR51SIGN_SUCCESS)
- {
- CPRINTS(ctx, "validate: success!\n");
- return rv;
- }
- CPRINTS(ctx,
- "validate: validate_payload_regions() failed ec%d\n",
- rv);
+ CPRINTS(ctx, "validate: success!\n");
+ return rv;
}
- // Store the first desc fail reason if any
- if (rv != LIBCR51SIGN_SUCCESS &&
- rv_first_desc == LIBCR51SIGN_SUCCESS)
- rv_first_desc = rv;
-
- // scan_for_magic_8() will round up to the next aligned boundary.
- descriptor_offset++;
- image_limit = ctx->end_offset - ctx->start_offset;
- rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC,
- descriptor_offset, image_limit,
- DESCRIPTOR_ALIGNMENT, &descriptor_offset);
+ CPRINTS(ctx, "validate: validate_payload_regions() failed ec%d\n",
+ rv);
}
- CPRINTS(ctx, "validate: failed to validate image ec%d\n", rv);
- // If desc validation failed for some reason then return that reason
- if (rv_first_desc != LIBCR51SIGN_SUCCESS)
- return rv_first_desc;
- else
- return rv;
+ // Store the first desc fail reason if any
+ if (rv != LIBCR51SIGN_SUCCESS && rv_first_desc == LIBCR51SIGN_SUCCESS)
+ rv_first_desc = rv;
+
+ // scan_for_magic_8() will round up to the next aligned boundary.
+ descriptor_offset++;
+ image_limit = ctx->end_offset - ctx->start_offset;
+ rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC, descriptor_offset,
+ image_limit, DESCRIPTOR_ALIGNMENT,
+ &descriptor_offset);
}
+ CPRINTS(ctx, "validate: failed to validate image ec%d\n", rv);
+ // If desc validation failed for some reason then return that reason
+ if (rv_first_desc != LIBCR51SIGN_SUCCESS)
+ return rv_first_desc;
+ else
+ return rv;
+}
- // @func to returns the libcr51sign error code as a string
- // @param[in] ec - Error code
- // @return error code in string format
+// @func to returns the libcr51sign error code as a string
+// @param[in] ec - Error code
+// @return error code in string format
- const char* libcr51sign_errorcode_to_string(failure_reason ec)
+const char* libcr51sign_errorcode_to_string(failure_reason ec)
+{
+ switch (ec)
{
- switch (ec)
- {
- case LIBCR51SIGN_SUCCESS:
- return "Success";
- case LIBCR51SIGN_ERROR_RUNTIME_FAILURE:
- return "Runtime Error Failure";
- case LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR:
- return "Unsupported descriptor";
- case LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR:
- return "Invalid descriptor";
- case LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY:
- return "Invalid image family";
- case LIBCR51SIGN_ERROR_IMAGE_TYPE_DISALLOWED:
- return "Image type disallowed";
- case LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED:
- return "Dev downgrade disallowed";
- case LIBCR51SIGN_ERROR_UNTRUSTED_KEY:
- return "Untrusted key";
- case LIBCR51SIGN_ERROR_INVALID_SIGNATURE:
- return "Invalid signature";
- case LIBCR51SIGN_ERROR_INVALID_HASH:
- return "Invalid hash";
- case LIBCR51SIGN_ERROR_INVALID_HASH_TYPE:
- return "Invalid hash type";
- case LIBCR51SIGN_ERROR_INVALID_ARGUMENT:
- return "Invalid Argument";
- case LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC:
- return "Failed to locate descriptor";
- case LIBCR51SIGN_ERROR_INVALID_CONTEXT:
- return "Invalid context";
- case LIBCR51SIGN_ERROR_INVALID_INTERFACE:
- 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";
- }
+ case LIBCR51SIGN_SUCCESS:
+ return "Success";
+ case LIBCR51SIGN_ERROR_RUNTIME_FAILURE:
+ return "Runtime Error Failure";
+ case LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR:
+ return "Unsupported descriptor";
+ case LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR:
+ return "Invalid descriptor";
+ case LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY:
+ return "Invalid image family";
+ case LIBCR51SIGN_ERROR_IMAGE_TYPE_DISALLOWED:
+ return "Image type disallowed";
+ case LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED:
+ return "Dev downgrade disallowed";
+ case LIBCR51SIGN_ERROR_UNTRUSTED_KEY:
+ return "Untrusted key";
+ case LIBCR51SIGN_ERROR_INVALID_SIGNATURE:
+ return "Invalid signature";
+ case LIBCR51SIGN_ERROR_INVALID_HASH:
+ return "Invalid hash";
+ case LIBCR51SIGN_ERROR_INVALID_HASH_TYPE:
+ return "Invalid hash type";
+ case LIBCR51SIGN_ERROR_INVALID_ARGUMENT:
+ return "Invalid Argument";
+ case LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC:
+ return "Failed to locate descriptor";
+ case LIBCR51SIGN_ERROR_INVALID_CONTEXT:
+ return "Invalid context";
+ case LIBCR51SIGN_ERROR_INVALID_INTERFACE:
+ 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";
}
+}
#ifdef __cplusplus
} // extern "C"