Index: src/platform/vboot_reference/vkernel/kernel_image_fw.c |
diff --git a/src/platform/vboot_reference/vkernel/kernel_image_fw.c b/src/platform/vboot_reference/vkernel/kernel_image_fw.c |
index 734111c6840e75acb8be72adaf721a586f443f25..23111e93cd042732da327f85a38955e8fbe28c2c 100644 |
--- a/src/platform/vboot_reference/vkernel/kernel_image_fw.c |
+++ b/src/platform/vboot_reference/vkernel/kernel_image_fw.c |
@@ -15,11 +15,6 @@ |
/* Macro to determine the size of a field structure in the KernelImage |
* structure. */ |
#define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field)) |
-#define KERNEL_CONFIG_FIELD_LEN (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) + \ |
- FIELD_LEN(options.cmd_line) + \ |
- FIELD_LEN(options.kernel_len) + \ |
- FIELD_LEN(options.kernel_load_addr) + \ |
- FIELD_LEN(options.kernel_entry_addr)) |
char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = { |
"Success.", |
@@ -31,6 +26,45 @@ char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = { |
"Wrong Kernel Magic.", |
}; |
+uint64_t GetVblockHeaderSize(const uint8_t* vkernel_blob) { |
+ uint64_t len = 0; |
+ uint16_t firmware_sign_algorithm; |
+ uint16_t kernel_sign_algorithm; |
+ int algorithms_offset = (FIELD_LEN(magic) + |
+ FIELD_LEN(header_version) + |
+ FIELD_LEN(header_len)); |
+ if (SafeMemcmp(vkernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) { |
+ debug("Not a valid verified boot kernel blob.\n"); |
+ return 0; |
+ } |
+ Memcpy(&firmware_sign_algorithm, |
+ vkernel_blob + algorithms_offset, |
+ sizeof(firmware_sign_algorithm)); |
+ Memcpy(&kernel_sign_algorithm, |
+ vkernel_blob + algorithms_offset + FIELD_LEN(kernel_sign_algorithm), |
+ sizeof(kernel_sign_algorithm)); |
+ if (firmware_sign_algorithm >= kNumAlgorithms) { |
+ debug("Invalid firmware signing algorithm.\n"); |
+ return 0; |
+ } |
+ if (kernel_sign_algorithm >= kNumAlgorithms) { |
+ debug("Invalid kernel signing algorithm.\n"); |
+ return 0; |
+ } |
+ len = algorithms_offset; /* magic, header length and version. */ |
+ len += (FIELD_LEN(firmware_sign_algorithm) + |
+ FIELD_LEN(kernel_sign_algorithm) + |
+ FIELD_LEN(kernel_key_version) + |
+ RSAProcessedKeySize(kernel_sign_algorithm) + /* kernel_sign_key */ |
+ FIELD_LEN(header_checksum) + |
+ siglen_map[firmware_sign_algorithm] + /* kernel_key_signature */ |
+ FIELD_LEN(kernel_version) + |
+ FIELD_LEN(kernel_len) + |
+ siglen_map[kernel_sign_algorithm] + /* config_signature */ |
+ siglen_map[kernel_sign_algorithm]); /* kernel_signature */ |
+ return len; |
+} |
+ |
int VerifyKernelHeader(const uint8_t* firmware_key_blob, |
const uint8_t* header_blob, |
const int dev_mode, |
@@ -116,43 +150,73 @@ int VerifyKernelConfig(RSAPublicKey* kernel_sign_key, |
const uint8_t* config_blob, |
int algorithm, |
uint64_t* kernel_len) { |
- uint64_t len; |
- if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */ |
- config_blob, /* Data to verify */ |
- KERNEL_CONFIG_FIELD_LEN, /* Length of data */ |
- config_blob + KERNEL_CONFIG_FIELD_LEN, /* Expected |
- * Signature */ |
- algorithm)) |
- return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED; |
+ int signature_len = siglen_map[algorithm]; |
+ const uint8_t* config_signature = NULL; |
+ const uint8_t* kernel_config = NULL; |
+ uint8_t* digest = NULL; |
+ DigestContext ctx; |
- Memcpy(&len, |
- config_blob + (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) + |
- FIELD_LEN(options.cmd_line)), |
- sizeof(len)); |
- *kernel_len = len; |
+ config_signature = config_blob + (FIELD_LEN(kernel_version) + |
+ FIELD_LEN(kernel_len)); |
+ kernel_config = config_signature + 2 * signature_len; /* kernel and config |
+ * signature. */ |
+ /* Since the kernel config signature is computed over the kernel version, |
+ * kernel length and config, which does not form a contiguous region memory, |
+ * we calculate the message digest ourselves. */ |
+ DigestInit(&ctx, algorithm); |
+ DigestUpdate(&ctx, |
+ config_blob, |
+ FIELD_LEN(kernel_version) + FIELD_LEN(kernel_len)); |
+ DigestUpdate(&ctx, |
+ kernel_config, |
+ FIELD_LEN(kernel_config)); |
+ digest = DigestFinal(&ctx); |
+ if (!RSAVerifyBinaryWithDigest_f( |
+ NULL, kernel_sign_key, /* Key to use. */ |
+ digest, /* Digest of the Data to verify. */ |
+ config_signature, /* Expected signature. */ |
+ algorithm)) { |
+ Free(digest); |
+ return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED; |
+ } |
+ Free(digest); |
+ Memcpy(kernel_len, |
+ config_blob + FIELD_LEN(kernel_version), |
+ FIELD_LEN(kernel_len)); |
return 0; |
} |
int VerifyKernelData(RSAPublicKey* kernel_sign_key, |
- const uint8_t* kernel_config_start, |
- const uint8_t* kernel_data_start, |
+ const uint8_t* config_blob, |
+ const uint8_t* kernel_data, |
uint64_t kernel_len, |
int algorithm) { |
int signature_len = siglen_map[algorithm]; |
- uint8_t* digest; |
+ const uint8_t* kernel_signature = NULL; |
+ const uint8_t* kernel_config = NULL; |
+ uint8_t* digest = NULL; |
DigestContext ctx; |
- /* Since the kernel signature is computed over the kernel version, options |
- * and data, which does not form a contiguous region of memory, we calculate |
- * the message digest ourselves. */ |
+ kernel_signature = config_blob + (FIELD_LEN(kernel_version) + |
+ FIELD_LEN(kernel_len) + |
+ signature_len); |
+ kernel_config = kernel_signature + signature_len; |
+ |
+ /* Since the kernel signature is computed over the kernel version, length, |
+ * config cmd line, and kernel image data, which does not form a contiguous |
+ * region of memory, we calculate the message digest ourselves. */ |
DigestInit(&ctx, algorithm); |
- DigestUpdate(&ctx, kernel_config_start, KERNEL_CONFIG_FIELD_LEN); |
- DigestUpdate(&ctx, kernel_data_start + signature_len, kernel_len); |
+ DigestUpdate(&ctx, |
+ config_blob, |
+ FIELD_LEN(kernel_version) + FIELD_LEN(kernel_len)); |
+ DigestUpdate(&ctx, kernel_config, |
+ FIELD_LEN(kernel_config)); |
+ DigestUpdate(&ctx, kernel_data, kernel_len); |
digest = DigestFinal(&ctx); |
if (!RSAVerifyBinaryWithDigest_f( |
NULL, kernel_sign_key, /* Key to use. */ |
digest, /* Digest of the data to verify. */ |
- kernel_data_start, /* Expected Signature */ |
+ kernel_signature, /* Expected Signature */ |
algorithm)) { |
Free(digest); |
return VERIFY_KERNEL_SIGNATURE_FAILED; |
@@ -214,11 +278,15 @@ int VerifyKernel(const uint8_t* firmware_key_blob, |
} |
/* Only continue if kernel data verification succeeds. */ |
kernel_ptr = (config_ptr + |
- KERNEL_CONFIG_FIELD_LEN + /* Skip config block/signature. */ |
- kernel_signature_len); |
- |
- if ((error_code = VerifyKernelData(kernel_sign_key, config_ptr, kernel_ptr, |
- kernel_len, |
+ FIELD_LEN(kernel_version) + |
+ FIELD_LEN(kernel_len) + |
+ 2 * kernel_signature_len + /* config and kernel signature. */ |
+ FIELD_LEN(kernel_config)); |
+ |
+ if ((error_code = VerifyKernelData(kernel_sign_key, /* Verification key */ |
+ config_ptr, /* Start of config block */ |
+ kernel_ptr, /* Start of kernel image */ |
+ kernel_len, /* Length of kernel image. */ |
kernel_sign_algorithm))) { |
RSAPublicKeyFree(kernel_sign_key); |
return error_code; /* AKA jump to recovery. */ |
@@ -248,6 +316,7 @@ uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) { |
return 0; |
if (kernel_sign_algorithm >= kNumAlgorithms) |
return 0; |
+ |
kernel_key_signature_len = siglen_map[firmware_sign_algorithm]; |
kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm); |
kernel_ptr += (FIELD_LEN(kernel_key_version) + |