Chromium Code Reviews| 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 23111e93cd042732da327f85a38955e8fbe28c2c..5a1e9785949fd374f403e604d40f46cb805854fb 100644 |
| --- a/src/platform/vboot_reference/vkernel/kernel_image_fw.c |
| +++ b/src/platform/vboot_reference/vkernel/kernel_image_fw.c |
| @@ -21,11 +21,19 @@ char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = { |
| "Invalid Image.", |
| "Kernel Key Signature Failed.", |
| "Invalid Kernel Verification Algorithm.", |
| - "Config Signature Failed.", |
| + "Preamble Signature Failed.", |
| "Kernel Signature Failed.", |
| "Wrong Kernel Magic.", |
| }; |
| +inline uint64_t GetKernelPreambleLen(void) { |
| + return (FIELD_LEN(kernel_version) + |
| + FIELD_LEN(kernel_len) + |
| + FIELD_LEN(bootloader_offset) + |
| + FIELD_LEN(bootloader_size) + |
| + FIELD_LEN(padded_header_size)); |
| +} |
| + |
| uint64_t GetVblockHeaderSize(const uint8_t* vkernel_blob) { |
| uint64_t len = 0; |
| uint16_t firmware_sign_algorithm; |
| @@ -58,19 +66,18 @@ uint64_t GetVblockHeaderSize(const uint8_t* vkernel_blob) { |
| 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 */ |
| + GetKernelPreambleLen() + |
| + siglen_map[kernel_sign_algorithm] + /* preamble_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, |
| - int* firmware_algorithm, |
| - int* kernel_algorithm, |
| - int* kernel_header_len) { |
| +int VerifyKernelKeyHeader(const uint8_t* firmware_key_blob, |
| + const uint8_t* header_blob, |
| + const int dev_mode, |
| + int* firmware_algorithm, |
| + int* kernel_algorithm, |
| + int* kernel_header_len) { |
| int kernel_sign_key_len; |
| int firmware_sign_key_len; |
| uint16_t header_version, header_len; |
| @@ -115,7 +122,7 @@ int VerifyKernelHeader(const uint8_t* firmware_key_blob, |
| if (header_len != (base_header_checksum_offset + |
| kernel_sign_key_len + |
| FIELD_LEN(header_checksum))) { |
| - debug("VerifyKernelHeader: Header length mismatch\n"); |
| + debug("VerifyKernelKeyHeader: Header length mismatch\n"); |
| return VERIFY_KERNEL_INVALID_IMAGE; |
| } |
| *kernel_header_len = (int) header_len; |
| @@ -129,7 +136,7 @@ int VerifyKernelHeader(const uint8_t* firmware_key_blob, |
| kernel_sign_key_len), |
| FIELD_LEN(header_checksum))) { |
| Free(header_checksum); |
| - debug("VerifyKernelHeader: Invalid header hash\n"); |
| + debug("VerifyKernelKeyHeader: Invalid header hash\n"); |
| return VERIFY_KERNEL_INVALID_IMAGE; |
| } |
| Free(header_checksum); |
| @@ -146,71 +153,43 @@ int VerifyKernelHeader(const uint8_t* firmware_key_blob, |
| return 0; |
| } |
| -int VerifyKernelConfig(RSAPublicKey* kernel_sign_key, |
| - const uint8_t* config_blob, |
| - int algorithm, |
| - uint64_t* kernel_len) { |
| - int signature_len = siglen_map[algorithm]; |
| - const uint8_t* config_signature = NULL; |
| - const uint8_t* kernel_config = NULL; |
| - uint8_t* digest = NULL; |
| - DigestContext ctx; |
| - |
| - 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); |
| +int VerifyKernelPreamble(RSAPublicKey* kernel_sign_key, |
| + const uint8_t* preamble_blob, |
| + int algorithm, |
| + uint64_t* kernel_len) { |
| + int preamble_len = GetKernelPreambleLen(); |
| + if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */ |
| + preamble_blob, /* Data to verify */ |
| + preamble_len, /* Length of data */ |
| + preamble_blob + preamble_len, /* Expected Signature */ |
| + algorithm)) |
| + return VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED; |
| Memcpy(kernel_len, |
| - config_blob + FIELD_LEN(kernel_version), |
| + preamble_blob + FIELD_LEN(kernel_version), |
| FIELD_LEN(kernel_len)); |
| return 0; |
| } |
| int VerifyKernelData(RSAPublicKey* kernel_sign_key, |
| - const uint8_t* config_blob, |
| + const uint8_t* preamble_blob, |
| const uint8_t* kernel_data, |
| uint64_t kernel_len, |
| int algorithm) { |
| int signature_len = siglen_map[algorithm]; |
| const uint8_t* kernel_signature = NULL; |
| - const uint8_t* kernel_config = NULL; |
| uint8_t* digest = NULL; |
| DigestContext ctx; |
| - kernel_signature = config_blob + (FIELD_LEN(kernel_version) + |
| - FIELD_LEN(kernel_len) + |
| - signature_len); |
| - kernel_config = kernel_signature + signature_len; |
| + kernel_signature = preamble_blob + (GetKernelPreambleLen() + |
| + 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 |
| + /* Since the kernel signature is computed over the kernel preamble |
| + * and kernel image data, which does not form a contiguous |
| * region of 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)); |
| + preamble_blob, |
| + GetKernelPreambleLen()); |
| DigestUpdate(&ctx, kernel_data, kernel_len); |
| digest = DigestFinal(&ctx); |
| if (!RSAVerifyBinaryWithDigest_f( |
| @@ -225,6 +204,65 @@ int VerifyKernelData(RSAPublicKey* kernel_sign_key, |
| return 0; |
| } |
| +int VerifyKernelHeader(const uint8_t* firmware_key_blob, |
| + const uint8_t* kernel_header_blob, |
| + const int dev_mode, |
| + const uint8_t** preamble_blob, |
| + const uint8_t** expected_kernel_signature, |
| + RSAPublicKey** kernel_sign_key, |
| + int* kernel_sign_algorithm, |
| + uint64_t* kernel_len) { |
| + int error_code; |
| + int firmware_sign_algorithm; /* Firmware signing key algorithm. */ |
| + int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len, |
| + header_len; |
| + const uint8_t* header_ptr; /* Pointer to header. */ |
| + const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */ |
| + |
| + /* Note: All the offset calculations are based on struct FirmwareImage which |
|
Randall Spangler
2010/05/26 16:35:23
KernelImage
|
| + * is defined in include/firmware_image.h. */ |
| + |
| + /* Compare magic bytes. */ |
| + if (SafeMemcmp(kernel_header_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) |
| + return VERIFY_KERNEL_WRONG_MAGIC; |
| + header_ptr = kernel_header_blob + KERNEL_MAGIC_SIZE; |
| + |
| + /* Only continue if header verification succeeds. */ |
| + if ((error_code = VerifyKernelKeyHeader(firmware_key_blob, header_ptr, |
| + dev_mode, |
| + &firmware_sign_algorithm, |
| + kernel_sign_algorithm, |
| + &header_len))) { |
| + debug("VerifyKernelHeader: Kernel Key Header verification failed.\n"); |
| + return error_code; /* AKA jump to recovery. */ |
| + } |
| + /* Parse signing key into RSAPublicKey structure since it is required multiple |
| + * times. */ |
| + kernel_sign_key_len = RSAProcessedKeySize(*kernel_sign_algorithm); |
| + kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) + |
| + FIELD_LEN(header_len) + |
| + FIELD_LEN(firmware_sign_algorithm) + |
| + FIELD_LEN(kernel_sign_algorithm) + |
| + FIELD_LEN(kernel_key_version)); |
| + *kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr, |
| + kernel_sign_key_len); |
| + kernel_signature_len = siglen_map[*kernel_sign_algorithm]; |
| + kernel_key_signature_len = siglen_map[firmware_sign_algorithm]; |
| + |
| + /* Only continue if preamble verification succeeds. */ |
| + *preamble_blob = (header_ptr + header_len + kernel_key_signature_len); |
| + if ((error_code = VerifyKernelPreamble(*kernel_sign_key, *preamble_blob, |
| + *kernel_sign_algorithm, |
| + kernel_len))) { |
| + RSAPublicKeyFree(*kernel_sign_key); |
| + return error_code; /* AKA jump to recovery. */ |
| + } |
| + *expected_kernel_signature = (*preamble_blob + |
| + GetKernelPreambleLen() + |
| + kernel_signature_len); /* Skip preamble. */ |
| + return 0; |
| +} |
| + |
| int VerifyKernel(const uint8_t* firmware_key_blob, |
| const uint8_t* kernel_blob, |
| const int dev_mode) { |
| @@ -237,7 +275,7 @@ int VerifyKernel(const uint8_t* firmware_key_blob, |
| uint64_t kernel_len; |
| const uint8_t* header_ptr; /* Pointer to header. */ |
| const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */ |
| - const uint8_t* config_ptr; /* Pointer to kernel config block. */ |
| + const uint8_t* preamble_ptr; /* Pointer to kernel preamble block. */ |
| const uint8_t* kernel_ptr; /* Pointer to kernel signature/data. */ |
| /* Note: All the offset calculations are based on struct FirmwareImage which |
| @@ -249,9 +287,9 @@ int VerifyKernel(const uint8_t* firmware_key_blob, |
| header_ptr = kernel_blob + KERNEL_MAGIC_SIZE; |
| /* Only continue if header verification succeeds. */ |
| - if ((error_code = VerifyKernelHeader(firmware_key_blob, header_ptr, dev_mode, |
| - &firmware_sign_algorithm, |
| - &kernel_sign_algorithm, &header_len))) { |
| + if ((error_code = VerifyKernelKeyHeader(firmware_key_blob, header_ptr, dev_mode, |
| + &firmware_sign_algorithm, |
| + &kernel_sign_algorithm, &header_len))) { |
| debug("VerifyKernel: Kernel header verification failed.\n"); |
| return error_code; /* AKA jump to recovery. */ |
| } |
| @@ -268,23 +306,21 @@ int VerifyKernel(const uint8_t* firmware_key_blob, |
| kernel_signature_len = siglen_map[kernel_sign_algorithm]; |
| kernel_key_signature_len = siglen_map[firmware_sign_algorithm]; |
| - /* Only continue if config verification succeeds. */ |
| - config_ptr = (header_ptr + header_len + kernel_key_signature_len); |
| - if ((error_code = VerifyKernelConfig(kernel_sign_key, config_ptr, |
| - kernel_sign_algorithm, |
| - &kernel_len))) { |
| + /* Only continue if preamble verification succeeds. */ |
| + preamble_ptr = (header_ptr + header_len + kernel_key_signature_len); |
| + if ((error_code = VerifyKernelPreamble(kernel_sign_key, preamble_ptr, |
| + kernel_sign_algorithm, |
| + &kernel_len))) { |
| RSAPublicKeyFree(kernel_sign_key); |
| return error_code; /* AKA jump to recovery. */ |
| } |
| /* Only continue if kernel data verification succeeds. */ |
| - kernel_ptr = (config_ptr + |
| - FIELD_LEN(kernel_version) + |
| - FIELD_LEN(kernel_len) + |
| - 2 * kernel_signature_len + /* config and kernel signature. */ |
| - FIELD_LEN(kernel_config)); |
| + kernel_ptr = (preamble_ptr + |
| + GetKernelPreambleLen() + |
| + 2 * kernel_signature_len); /* preamble and kernel signature. */ |
| if ((error_code = VerifyKernelData(kernel_sign_key, /* Verification key */ |
| - config_ptr, /* Start of config block */ |
| + preamble_ptr, /* Start of preamble */ |
| kernel_ptr, /* Start of kernel image */ |
| kernel_len, /* Length of kernel image. */ |
| kernel_sign_algorithm))) { |