diff --git a/common/utility_stub.c b/common/utility_stub.c index 2d01226fb2..d2244c797b 100644 --- a/common/utility_stub.c +++ b/common/utility_stub.c @@ -8,9 +8,27 @@ #include "utility.h" +#include #include #include +void error(const char *format, ...) { + va_list ap; + va_start(ap, format); + fprintf(stderr, "ERROR: "); + vfprintf(stderr, format, ap); + va_end(ap); + exit(1); +} + +void debug(const char *format, ...) { + va_list ap; + va_start(ap, format); + fprintf(stderr, "WARNING: "); + vfprintf(stderr, format, ap); + va_end(ap); +} + void* Malloc(size_t size) { void* p = malloc(size); if (!p) { diff --git a/include/firmware_image.h b/include/firmware_image.h index 810e3a0456..19a87d9bf7 100644 --- a/include/firmware_image.h +++ b/include/firmware_image.h @@ -2,53 +2,14 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * - * Data structure and API definitions for a verified boot firmware image. + * API definitions for a verified boot firmware image. + * (Userland Portion) */ #ifndef VBOOT_REFERENCE_FIRMWARE_IMAGE_H_ #define VBOOT_REFERENCE_FIRMWARE_IMAGE_H_ -#include - -#include "rsa.h" -#include "sha.h" - -#define FIRMWARE_MAGIC "CHROMEOS" -#define FIRMWARE_MAGIC_SIZE 8 -#define FIRMWARE_PREAMBLE_SIZE 8 - -/* RSA 8192 and SHA-512. */ -#define ROOT_SIGNATURE_ALGORITHM 11 -#define ROOT_SIGNATURE_ALGORITHM_STRING "11" - -typedef struct FirmwareImage { - uint8_t magic[FIRMWARE_MAGIC_SIZE]; - /* Key Header */ - uint16_t header_len; /* Length of the header. */ - uint16_t firmware_sign_algorithm; /* Signature algorithm used by the signing - * key. */ - uint16_t firmware_key_version; /* Key Version# for preventing rollbacks. */ - uint8_t* firmware_sign_key; /* Pre-processed public half of signing key. */ - uint8_t header_checksum[SHA512_DIGEST_SIZE]; /* SHA-512 hash of the header.*/ - - uint8_t firmware_key_signature[RSA8192NUMBYTES]; /* Signature of the header - * above. */ - - /* Firmware Preamble. */ - uint16_t firmware_version; /* Firmware Version# for preventing rollbacks.*/ - uint64_t firmware_len; /* Length of the rest of the R/W firmware data. */ - uint8_t preamble[FIRMWARE_PREAMBLE_SIZE]; /* Remaining preamble data.*/ - - uint8_t* preamble_signature; /* Signature over the preamble. */ - - /* The firmware signature comes first as it may allow us to parallelize - * the firmware data fetch and RSA public operation. - */ - uint8_t* firmware_signature; /* Signature on the Preamble + - [firmware_data]. */ - uint8_t* firmware_data; /* Rest of firmware data */ - -} FirmwareImage; +#include "firmware_image_fw.h" /* Allocate and return a new FirmwareImage structure. */ FirmwareImage* FirmwareImageNew(void); @@ -100,77 +61,11 @@ uint8_t* GetFirmwareBlob(const FirmwareImage* image, uint64_t* blob_len); int WriteFirmwareImage(const char* input_file, const FirmwareImage* image); - /* Pretty print the contents of [image]. Only headers and metadata information * is printed. */ void PrintFirmwareImage(const FirmwareImage* image); -/* Error Codes for VerifyFirmware* family of functions. */ -#define VERIFY_FIRMWARE_SUCCESS 0 -#define VERIFY_FIRMWARE_INVALID_IMAGE 1 -#define VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED 2 -#define VERIFY_FIRMWARE_INVALID_ALGORITHM 3 -#define VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED 4 -#define VERIFY_FIRMWARE_SIGNATURE_FAILED 5 -#define VERIFY_FIRMWARE_WRONG_MAGIC 6 -#define VERIFY_FIRMWARE_WRONG_HEADER_CHECKSUM 7 -#define VERIFY_FIRMWARE_KEY_ROLLBACK 8 -#define VERIFY_FIRMWARE_VERSION_ROLLBACK 9 -#define VERIFY_FIRMWARE_MAX 10 /* Total number of error codes. */ - -extern char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX]; - -/* Checks for the sanity of the firmware header pointed by [header_blob]. - * - * On success, put signature algorithm in [algorithm], header length - * in [header_len], and return 0. - * Else, return error code on failure. - */ -int VerifyFirmwareHeader(const uint8_t* root_key_blob, - const uint8_t* header_blob, - int* algorithm, - int* header_len); - -/* Checks the preamble signature on firmware preamble pointed by - * [preamble_blob] using the signing key [sign_key]. - * - * On success, put firmware length into [firmware_len], and return 0. - * Else, return error code on failure. - */ -int VerifyFirmwarePreamble(RSAPublicKey* sign_key, - const uint8_t* preamble_blob, - int algorithm, - uint64_t* firmware_len); - -/* Checks the signature on the preamble + firmware data at - * [preamble_start] and [firmware_data_start]. - * The length of the actual firmware data is firmware_len and it is assumed to - * be prepended with the signature whose size depends on the signature_algorithm - * [algorithm]. This signature also covers the preamble data (but not the - * preamble signature itself). - * - * Return 0 on success, error code on failure. - */ -int VerifyFirmwareData(RSAPublicKey* sign_key, - const uint8_t* preamble_start, - const uint8_t* firmware_data_start, - uint64_t firmware_len, - int algorithm); - -/* Performs a chained verify of the firmware blob [firmware_blob]. - * - * Returns 0 on success, error code on failure. - * - * NOTE: The length of the firmware blob is derived from reading the fields - * in the first few bytes of the buffer. This might look risky but in firmware - * land, the start address of the firmware_blob will always be fixed depending - * on the memory map on the particular platform. In addition, the signature on - * length itself is checked early in the verification process for extra safety. - */ -int VerifyFirmware(const uint8_t* root_key_blob, - const uint8_t* firmware_blob); - /* Performs a chained verify of the firmware [image]. * * Returns 0 on success, error code on failure. @@ -195,26 +90,4 @@ int AddFirmwareKeySignature(FirmwareImage* image, const char* root_key_file); */ int AddFirmwareSignature(FirmwareImage* image, const char* signing_key_file); -/* Returns the logical version of a firmware blob which is calculated as - * (firmware_key_version << 16 | firmware_version). */ -uint32_t GetLogicalFirmwareVersion(uint8_t* firmware_blob); - -#define BOOT_FIRMWARE_A_CONTINUE 1 -#define BOOT_FIRMWARE_B_CONTINUE 2 -#define BOOT_FIRMWARE_RECOVERY_CONTINUE 3 - -/* This function is the driver used by the RO firmware to - * determine which copy of the firmware to boot from. It performs - * the requisite rollback index checking, including updating them, - * if required. - * - * Returns the code path to follow. It is one of: - * BOOT_FIRMWARE_A_CONTINUE Boot from Firmware A - * BOOT_FIRMWARE_B_CONTINUE Boot from Firmware B - * BOOT_FIRMWARE_RECOVERY_CONTINUE Jump to recovery mode - */ -int VerifyFirmwareDriver_f(uint8_t* root_key_blob, - uint8_t* firmwareA, - uint8_t* firmwareB); - #endif /* VBOOT_REFERENCE_FIRMWARE_IMAGE_H_ */ diff --git a/include/firmware_image_fw.h b/include/firmware_image_fw.h new file mode 100644 index 0000000000..53b558ae85 --- /dev/null +++ b/include/firmware_image_fw.h @@ -0,0 +1,142 @@ +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Data structure and API definitions for a verified boot firmware image. + * (Firmware Portion) + */ + +#ifndef VBOOT_REFERENCE_FIRMWARE_IMAGE_FW_H_ +#define VBOOT_REFERENCE_FIRMWARE_IMAGE_FW_H_ + +#include +#include "rsa.h" +#include "sha.h" + +#define FIRMWARE_MAGIC "CHROMEOS" +#define FIRMWARE_MAGIC_SIZE 8 +#define FIRMWARE_PREAMBLE_SIZE 8 + +/* RSA 8192 and SHA-512. */ +#define ROOT_SIGNATURE_ALGORITHM 11 +#define ROOT_SIGNATURE_ALGORITHM_STRING "11" + +typedef struct FirmwareImage { + uint8_t magic[FIRMWARE_MAGIC_SIZE]; + /* Key Header */ + uint16_t header_len; /* Length of the header. */ + uint16_t firmware_sign_algorithm; /* Signature algorithm used by the signing + * key. */ + uint16_t firmware_key_version; /* Key Version# for preventing rollbacks. */ + uint8_t* firmware_sign_key; /* Pre-processed public half of signing key. */ + uint8_t header_checksum[SHA512_DIGEST_SIZE]; /* SHA-512 hash of the header.*/ + + uint8_t firmware_key_signature[RSA8192NUMBYTES]; /* Signature of the header + * above. */ + + /* Firmware Preamble. */ + uint16_t firmware_version; /* Firmware Version# for preventing rollbacks.*/ + uint64_t firmware_len; /* Length of the rest of the R/W firmware data. */ + uint8_t preamble[FIRMWARE_PREAMBLE_SIZE]; /* Remaining preamble data.*/ + + uint8_t* preamble_signature; /* Signature over the preamble. */ + + /* The firmware signature comes first as it may allow us to parallelize + * the firmware data fetch and RSA public operation. + */ + uint8_t* firmware_signature; /* Signature on the Preamble + + [firmware_data]. */ + uint8_t* firmware_data; /* Rest of firmware data */ + +} FirmwareImage; + + +/* Error Codes for VerifyFirmware* family of functions. */ +#define VERIFY_FIRMWARE_SUCCESS 0 +#define VERIFY_FIRMWARE_INVALID_IMAGE 1 +#define VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED 2 +#define VERIFY_FIRMWARE_INVALID_ALGORITHM 3 +#define VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED 4 +#define VERIFY_FIRMWARE_SIGNATURE_FAILED 5 +#define VERIFY_FIRMWARE_WRONG_MAGIC 6 +#define VERIFY_FIRMWARE_WRONG_HEADER_CHECKSUM 7 +#define VERIFY_FIRMWARE_KEY_ROLLBACK 8 +#define VERIFY_FIRMWARE_VERSION_ROLLBACK 9 +#define VERIFY_FIRMWARE_MAX 10 /* Total number of error codes. */ + +extern char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX]; + +/* Checks for the sanity of the firmware header pointed by [header_blob]. + * + * On success, put signature algorithm in [algorithm], header length + * in [header_len], and return 0. + * Else, return error code on failure. + */ +int VerifyFirmwareHeader(const uint8_t* root_key_blob, + const uint8_t* header_blob, + int* algorithm, + int* header_len); + +/* Checks the preamble signature on firmware preamble pointed by + * [preamble_blob] using the signing key [sign_key]. + * + * On success, put firmware length into [firmware_len], and return 0. + * Else, return error code on failure. + */ +int VerifyFirmwarePreamble(RSAPublicKey* sign_key, + const uint8_t* preamble_blob, + int algorithm, + uint64_t* firmware_len); + +/* Checks the signature on the preamble + firmware data at + * [preamble_start] and [firmware_data_start]. + * The length of the actual firmware data is firmware_len and it is assumed to + * be prepended with the signature whose size depends on the signature_algorithm + * [algorithm]. This signature also covers the preamble data (but not the + * preamble signature itself). + * + * Return 0 on success, error code on failure. + */ +int VerifyFirmwareData(RSAPublicKey* sign_key, + const uint8_t* preamble_start, + const uint8_t* firmware_data_start, + uint64_t firmware_len, + int algorithm); + +/* Performs a chained verify of the firmware blob [firmware_blob]. + * + * Returns 0 on success, error code on failure. + * + * NOTE: The length of the firmware blob is derived from reading the fields + * in the first few bytes of the buffer. This might look risky but in firmware + * land, the start address of the firmware_blob will always be fixed depending + * on the memory map on the particular platform. In addition, the signature on + * length itself is checked early in the verification process for extra safety. + */ +int VerifyFirmware(const uint8_t* root_key_blob, + const uint8_t* firmware_blob); + +/* Returns the logical version of a firmware blob which is calculated as + * (firmware_key_version << 16 | firmware_version). */ +uint32_t GetLogicalFirmwareVersion(uint8_t* firmware_blob); + +#define BOOT_FIRMWARE_A_CONTINUE 1 +#define BOOT_FIRMWARE_B_CONTINUE 2 +#define BOOT_FIRMWARE_RECOVERY_CONTINUE 3 + +/* This function is the driver used by the RO firmware to + * determine which copy of the firmware to boot from. It performs + * the requisite rollback index checking, including updating them, + * if required. + * + * Returns the code path to follow. It is one of: + * BOOT_FIRMWARE_A_CONTINUE Boot from Firmware A + * BOOT_FIRMWARE_B_CONTINUE Boot from Firmware B + * BOOT_FIRMWARE_RECOVERY_CONTINUE Jump to recovery mode + */ +int VerifyFirmwareDriver_f(uint8_t* root_key_blob, + uint8_t* firmwareA, + uint8_t* firmwareB); + + +#endif /* VBOOT_REFERENCE_FIRMWARE_IMAGE_FW_H_ */ diff --git a/include/kernel_image.h b/include/kernel_image.h index 3718624361..0ea8adb39e 100644 --- a/include/kernel_image.h +++ b/include/kernel_image.h @@ -2,73 +2,14 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * - * Data structure and API definitions for a verified boot kernel image. + * API definitions for a generating and manipulating verified boot kernel images. + * (Userland portion.) */ #ifndef VBOOT_REFERENCE_KERNEL_IMAGE_H_ #define VBOOT_REFERENCE_KERNEL_IMAGE_H_ -#include - -#include "rsa.h" -#include "sha.h" - -#define KERNEL_MAGIC "CHROMEOS" -#define KERNEL_MAGIC_SIZE 8 -#define KERNEL_CMD_LINE_SIZE 4096 - -#define DEV_MODE_ENABLED 1 -#define DEV_MODE_DISABLED 0 - -/* Kernel config file options according to the Chrome OS drive map design. */ -typedef struct kconfig_options { - uint32_t version[2]; /* Configuration file version. */ - uint8_t cmd_line[KERNEL_CMD_LINE_SIZE]; /* Kernel command line option string - * terminated by a NULL character. */ - uint64_t kernel_len; /* Size of the kernel. */ - uint64_t kernel_load_addr; /* Load address in memory for the kernel image */ - uint64_t kernel_entry_addr; /* Address to jump to after kernel is loaded. */ -} kconfig_options; - - -typedef struct KernelImage { - uint8_t magic[KERNEL_MAGIC_SIZE]; - /* Key header */ - uint16_t header_version; /* Header version. */ - uint16_t header_len; /* Length of the header. */ - uint16_t firmware_sign_algorithm; /* Signature algorithm used by the firmware - * signing key (used to sign this kernel - * header. */ - uint16_t kernel_sign_algorithm; /* Signature algorithm used by the kernel - * signing key. */ - uint16_t kernel_key_version; /* Key Version# for preventing rollbacks. */ - uint8_t* kernel_sign_key; /* Pre-processed public half of signing key. */ - /* TODO(gauravsh): Do we need a choice of digest algorithms for the header - * checksum? */ - uint8_t header_checksum[SHA512_DIGEST_SIZE]; /* SHA-512 Crytographic hash of - * the concatenation of the - * header fields, i.e. - * [header_len, - * firmware_sign_algorithm, - * sign_algorithm, sign_key, - * key_version] */ - - uint8_t* kernel_key_signature; /* Signature of the header above. */ - - uint16_t kernel_version; /* Kernel Version# for preventing rollbacks. */ - kconfig_options options; /* Other kernel/bootloader options. */ - - uint8_t* config_signature; /* Signature of the kernel config file. */ - - /* The kernel signature comes first as it may allow us to parallelize - * the kernel data fetch and RSA public key operation. - */ - uint8_t* kernel_signature; /* Signature on the concatenation of - * [kernel_version], [options] and - * [kernel_data]. */ - uint8_t* kernel_data; /* Actual kernel data. */ - -} KernelImage; +#include "kernel_image_fw.h" /* Allocate and return a new KernelImage structure. */ KernelImage* KernelImageNew(void); @@ -125,79 +66,6 @@ int WriteKernelImage(const char* input_file, */ void PrintKernelImage(const KernelImage* image); -/* Error Codes for VerifyFirmware. */ -#define VERIFY_KERNEL_SUCCESS 0 -#define VERIFY_KERNEL_INVALID_IMAGE 1 -#define VERIFY_KERNEL_KEY_SIGNATURE_FAILED 2 -#define VERIFY_KERNEL_INVALID_ALGORITHM 3 -#define VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED 4 -#define VERIFY_KERNEL_SIGNATURE_FAILED 5 -#define VERIFY_KERNEL_WRONG_MAGIC 6 -#define VERIFY_KERNEL_MAX 7 /* Generic catch-all. */ - -extern char* kVerifyKernelErrors[VERIFY_KERNEL_MAX]; - -/* Checks for the sanity of the kernel header pointed by [kernel_header_blob]. - * If [dev_mode] is enabled, also checks the firmware key signature using the - * pre-processed public firmware signing key [firmware_sign_key_blob]. - * - * On success, put firmware signature algorithm in [firmware_algorithm], - * kernel signature algorithm in [kernel_algorithm], kernel header - * length in [header_len], and return 0. - * Else, return error code on failure. - */ -int VerifyKernelHeader(const uint8_t* firmware_sign_key_blob, - const uint8_t* kernel_header_blob, - const int dev_mode, - int* firmware_algorithm, - int* kernel_algorithm, - int* header_len); - -/* Checks the kernel config (analogous to preamble for firmware) signature on - * kernel config pointed by [kernel_config_blob] using the signing key - * [kernel_sign_key]. - * - * On success, put kernel length into [kernel_len], and return 0. - * Else, return error code on failure. - */ -int VerifyKernelConfig(RSAPublicKey* kernel_sign_key, - const uint8_t* kernel_config_blob, - int algorithm, - uint64_t* kernel_len); - -/* Checks the signature on the kernel data at location [kernel_data_start]. - * The length of the actual kernel data is kernel _len and it is assumed to - * be prepended with the signature whose size depends on the signature_algorithm - * [algorithm]. - * - * Return 0 on success, error code on failure. - */ -int VerifyKernelData(RSAPublicKey* kernel_sign_key, - const uint8_t* kernel_config_start, - const uint8_t* kernel_data_start, - uint64_t kernel_len, - int algorithm); - -/* Performs a chained verify of the kernel blob [kernel_blob]. If - * [dev_mode] is 0 [inactive], then the pre-processed public signing key - * [root_key_blob] is used to verify the signature of the signing key, - * else the check is skipped. - * - * TODO(gauravsh): Does the dev mode only effect the R/W firmware verification, - * or kernel verification, or both? - * - * Returns 0 on success, error code on failure. - * - * NOTE: The length of the kernel blob is derived from reading the fields - * in the first few bytes of the buffer. This might look risky but in firmware - * land, the start address of the kernel_blob will always be fixed depending - * on the memory map on the particular platform. In addition, the signature on - * length itself is checked early in the verification process for extra safety. - */ -int VerifyKernel(const uint8_t* signing_key_blob, - const uint8_t* kernel_blob, - const int dev_mode); - /* Performs a chained verify of the kernel [image]. If [dev_mode] is * 0 (inactive), then the [firmware_signing_key] is used to verify the signature * of the signing key, else the check is skipped. @@ -227,44 +95,6 @@ int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file); int AddKernelSignature(KernelImage* image, const char* kernel_sigining_key_file); -/* Returns the logical version of a kernel blob which is calculated as - * (kernel_key_version << 16 | kernel_version). */ -uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob); - -#define BOOT_KERNEL_A_CONTINUE 1 -#define BOOT_KERNEL_B_CONTINUE 2 -#define BOOT_KERNEL_RECOVERY_CONTINUE 3 - -/* Contains information about the kernel paritition - * gleaned from the GPT partition table. - * - * Based on the Chromium OS Drive Map design document by - * rspangler@chromium.org. - * -*/ -typedef struct kernel_entry { - uint8_t* kernel_blob; /* Pointer to actual kernel. */ - uint8_t boot_priority; /* 15 = highest, 1 = lowest, 0 = not bootable. */ - uint8_t boot_tries_remaining; /* Used when boot_priority = 0. */ - uint8_t boot_success_flag; /* Set to 1 on successful boot by AU. */ -} kernel_entry; - void PrintKernelEntry(kernel_entry* entry); -/* This function is the driver used by the RW firmware to - * determine which copy of the kernel to boot from. It performs - * the requisite priority and remaining tries checking for a specific - * kernel partition, does rollback index checking, including updating - * if required. - * - * Returns the code path to follow. It is one of: - * BOOT_KERNEL_A_CONTINUE Boot from Kenrel A - * BOOT_KERNEL_B_CONTINUE Boot from Kernel B - * BOOT_KERNEL_RECOVERY_CONTINUE Jump to recovery mode - */ -int VerifyKernelDriver_f(uint8_t* firmware_key_blob, - kernel_entry* kernelA, - kernel_entry* kernelB, - int dev_mode); - #endif /* VBOOT_REFERENCE_KERNEL_IMAGE_H_ */ diff --git a/include/kernel_image_fw.h b/include/kernel_image_fw.h new file mode 100644 index 0000000000..d299b5a28e --- /dev/null +++ b/include/kernel_image_fw.h @@ -0,0 +1,183 @@ +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Data structure and API definitions for a verified boot kernel image. + * (Firmware Portion) + */ + +#ifndef VBOOT_REFERENCE_KERNEL_IMAGE_FW_H_ +#define VBOOT_REFERENCE_KERNEL_IMAGE_FW_H_ + +#include +#include "rsa.h" +#include "sha.h" + +#define KERNEL_MAGIC "CHROMEOS" +#define KERNEL_MAGIC_SIZE 8 +#define KERNEL_CMD_LINE_SIZE 4096 + +#define DEV_MODE_ENABLED 1 +#define DEV_MODE_DISABLED 0 + +/* Kernel config file options according to the Chrome OS drive map design. */ +typedef struct kconfig_options { + uint32_t version[2]; /* Configuration file version. */ + uint8_t cmd_line[KERNEL_CMD_LINE_SIZE]; /* Kernel command line option string + * terminated by a NULL character. */ + uint64_t kernel_len; /* Size of the kernel. */ + uint64_t kernel_load_addr; /* Load address in memory for the kernel image */ + uint64_t kernel_entry_addr; /* Address to jump to after kernel is loaded. */ +} kconfig_options; + +typedef struct KernelImage { + uint8_t magic[KERNEL_MAGIC_SIZE]; + /* Key header */ + uint16_t header_version; /* Header version. */ + uint16_t header_len; /* Length of the header. */ + uint16_t firmware_sign_algorithm; /* Signature algorithm used by the firmware + * signing key (used to sign this kernel + * header. */ + uint16_t kernel_sign_algorithm; /* Signature algorithm used by the kernel + * signing key. */ + uint16_t kernel_key_version; /* Key Version# for preventing rollbacks. */ + uint8_t* kernel_sign_key; /* Pre-processed public half of signing key. */ + /* TODO(gauravsh): Do we need a choice of digest algorithms for the header + * checksum? */ + uint8_t header_checksum[SHA512_DIGEST_SIZE]; /* SHA-512 Crytographic hash of + * the concatenation of the + * header fields, i.e. + * [header_len, + * firmware_sign_algorithm, + * sign_algorithm, sign_key, + * key_version] */ + + uint8_t* kernel_key_signature; /* Signature of the header above. */ + + uint16_t kernel_version; /* Kernel Version# for preventing rollbacks. */ + kconfig_options options; /* Other kernel/bootloader options. */ + + uint8_t* config_signature; /* Signature of the kernel config file. */ + + /* The kernel signature comes first as it may allow us to parallelize + * the kernel data fetch and RSA public key operation. + */ + uint8_t* kernel_signature; /* Signature on the concatenation of + * [kernel_version], [options] and + * [kernel_data]. */ + uint8_t* kernel_data; /* Actual kernel data. */ + +} KernelImage; + +/* Error Codes for VerifyFirmware. */ +#define VERIFY_KERNEL_SUCCESS 0 +#define VERIFY_KERNEL_INVALID_IMAGE 1 +#define VERIFY_KERNEL_KEY_SIGNATURE_FAILED 2 +#define VERIFY_KERNEL_INVALID_ALGORITHM 3 +#define VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED 4 +#define VERIFY_KERNEL_SIGNATURE_FAILED 5 +#define VERIFY_KERNEL_WRONG_MAGIC 6 +#define VERIFY_KERNEL_MAX 7 /* Generic catch-all. */ + +extern char* kVerifyKernelErrors[VERIFY_KERNEL_MAX]; + +/* Checks for the sanity of the kernel header pointed by [kernel_header_blob]. + * If [dev_mode] is enabled, also checks the firmware key signature using the + * pre-processed public firmware signing key [firmware_sign_key_blob]. + * + * On success, put firmware signature algorithm in [firmware_algorithm], + * kernel signature algorithm in [kernel_algorithm], kernel header + * length in [header_len], and return 0. + * Else, return error code on failure. + */ +int VerifyKernelHeader(const uint8_t* firmware_sign_key_blob, + const uint8_t* kernel_header_blob, + const int dev_mode, + int* firmware_algorithm, + int* kernel_algorithm, + int* header_len); + +/* Checks the kernel config (analogous to preamble for firmware) signature on + * kernel config pointed by [kernel_config_blob] using the signing key + * [kernel_sign_key]. + * + * On success, put kernel length into [kernel_len], and return 0. + * Else, return error code on failure. + */ +int VerifyKernelConfig(RSAPublicKey* kernel_sign_key, + const uint8_t* kernel_config_blob, + int algorithm, + uint64_t* kernel_len); + +/* Checks the signature on the kernel data at location [kernel_data_start]. + * The length of the actual kernel data is kernel _len and it is assumed to + * be prepended with the signature whose size depends on the signature_algorithm + * [algorithm]. + * + * Return 0 on success, error code on failure. + */ +int VerifyKernelData(RSAPublicKey* kernel_sign_key, + const uint8_t* kernel_config_start, + const uint8_t* kernel_data_start, + uint64_t kernel_len, + int algorithm); + +/* Performs a chained verify of the kernel blob [kernel_blob]. If + * [dev_mode] is 0 [inactive], then the pre-processed public signing key + * [root_key_blob] is used to verify the signature of the signing key, + * else the check is skipped. + * + * TODO(gauravsh): Does the dev mode only effect the R/W firmware verification, + * or kernel verification, or both? + * + * Returns 0 on success, error code on failure. + * + * NOTE: The length of the kernel blob is derived from reading the fields + * in the first few bytes of the buffer. This might look risky but in firmware + * land, the start address of the kernel_blob will always be fixed depending + * on the memory map on the particular platform. In addition, the signature on + * length itself is checked early in the verification process for extra safety. + */ +int VerifyKernel(const uint8_t* signing_key_blob, + const uint8_t* kernel_blob, + const int dev_mode); + +/* Returns the logical version of a kernel blob which is calculated as + * (kernel_key_version << 16 | kernel_version). */ +uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob); + +#define BOOT_KERNEL_A_CONTINUE 1 +#define BOOT_KERNEL_B_CONTINUE 2 +#define BOOT_KERNEL_RECOVERY_CONTINUE 3 + +/* Contains information about the kernel paritition + * gleaned from the GPT partition table. + * + * Based on the Chromium OS Drive Map design document by + * rspangler@chromium.org. + * +*/ +typedef struct kernel_entry { + uint8_t* kernel_blob; /* Pointer to actual kernel. */ + uint8_t boot_priority; /* 15 = highest, 1 = lowest, 0 = not bootable. */ + uint8_t boot_tries_remaining; /* Used when boot_priority = 0. */ + uint8_t boot_success_flag; /* Set to 1 on successful boot by AU. */ +} kernel_entry; + +/* This function is the driver used by the RW firmware to + * determine which copy of the kernel to boot from. It performs + * the requisite priority and remaining tries checking for a specific + * kernel partition, does rollback index checking, including updating + * if required. + * + * Returns the code path to follow. It is one of: + * BOOT_KERNEL_A_CONTINUE Boot from Kenrel A + * BOOT_KERNEL_B_CONTINUE Boot from Kernel B + * BOOT_KERNEL_RECOVERY_CONTINUE Jump to recovery mode + */ +int VerifyKernelDriver_f(uint8_t* firmware_key_blob, + kernel_entry* kernelA, + kernel_entry* kernelB, + int dev_mode); + +#endif /* VBOOT_REFERENCE_KERNEL_IMAGE_FW_H_ */ diff --git a/include/tlcl.h b/include/tlcl.h index e0b56262d4..2e6d3fd845 100644 --- a/include/tlcl.h +++ b/include/tlcl.h @@ -16,41 +16,6 @@ #include #include -#define POSSIBLY_UNUSED __attribute__((unused)) - -#ifdef __STRICT_ANSI__ -#define INLINE -#else -#define INLINE inline -#endif - -/* Outputs an error message and quits the program. - */ -POSSIBLY_UNUSED -static void error(const char *format, ...) { - va_list ap; - va_start(ap, format); - fprintf(stderr, "ERROR: "); - vfprintf(stderr, format, ap); - va_end(ap); - exit(1); -} - -/* Outputs a warning and continues. - */ -POSSIBLY_UNUSED -static void warning(const char *format, ...) { - va_list ap; - va_start(ap, format); - fprintf(stderr, "WARNING: "); - vfprintf(stderr, format, ap); - va_end(ap); -} - -#define assert(expr) do { if (!(expr)) { \ - error("assert fail: %s at %s:%d\n", \ - #expr, __FILE__, __LINE__); }} while(0) - /* Call this first. */ void TlclLibinit(void); diff --git a/include/utility.h b/include/utility.h index 429223cdf1..8619cd2198 100644 --- a/include/utility.h +++ b/include/utility.h @@ -10,9 +10,20 @@ #ifndef VBOOT_REFERENCE_UTILITY_H_ #define VBOOT_REFERENCE_UTILITY_H_ -#include +#include #include +/* Outputs an error message and quits. */ +void error(const char *format, ...); + +/* Outputs debug/warning messages. */ +void debug(const char *format, ...); + + +#define assert(expr) do { if (!(expr)) { \ + error("assert fail: %s at %s:%d\n", \ + #expr, __FILE__, __LINE__); }} while(0) + /* Combine [msw] and [lsw] uint16s to a uint32_t with its [msw] and * [lsw] forming the most and least signficant 16-bit words. */ diff --git a/tests/Makefile b/tests/Makefile index 3645e7dbce..99e2d3a490 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -8,26 +8,31 @@ INCLUDES ?= -I../include/ TOP ?= ../ BASE_LIBS = $(TOP)/crypto/libcrypto.a $(TOP)/common/libcommon.a -IMAGE_LIBS = $(TOP)/utils/firmware_image.o $(TOP)/utils/kernel_image.o +IMAGE_LIBS = $(TOP)/utils/firmware_image.o \ + $(TOP)/utils/firmware_image_fw.o \ + $(TOP)/utils/kernel_image.o \ + $(TOP)/utils/kernel_image_fw.o UTIL_LIBS = $(TOP)/utils/file_keys.o $(TOP)/utils/signature_digest.o LIBS = $(IMAGE_LIBS) $(UTIL_LIBS) -lcrypto $(BASE_LIBS) -tests: big_firmware_tests \ - big_kernel_tests \ - firmware_image_tests \ - firmware_rollback_tests \ - firmware_splicing_tests \ - firmware_verify_benchmark \ - kernel_image_tests \ - kernel_rollback_tests \ - kernel_splicing_tests \ - kernel_verify_benchmark \ - rsa_padding_test \ - rsa_verify_benchmark \ - sha_benchmark \ - sha_tests \ - verify_firmware_fuzz_driver \ - verify_kernel_fuzz_driver +TEST_BINS = big_firmware_tests \ + big_kernel_tests \ + firmware_image_tests \ + firmware_rollback_tests \ + firmware_splicing_tests \ + firmware_verify_benchmark \ + kernel_image_tests \ + kernel_rollback_tests \ + kernel_splicing_tests \ + kernel_verify_benchmark \ + rsa_padding_test \ + rsa_verify_benchmark \ + sha_benchmark \ + sha_tests \ + verify_firmware_fuzz_driver \ + verify_kernel_fuzz_driver + +all: $(TEST_BINS) big_firmware_tests: big_firmware_tests.c rollback_index_mock.c test_common.c $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS) @@ -87,19 +92,4 @@ verify_kernel_fuzz_driver: verify_kernel_fuzz_driver.c rollback_index_mock.c $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS) clean: - rm -f big_firmware_tests \ - big_kernel_tests \ - firmware_image_tests \ - firmware_rollback_tests \ - firmware_splicing_tests \ - firmware_verify_benchmark \ - kernel_image_tests \ - kernel_rollback_tests \ - kernel_splicing_tests \ - kernel_verify_benchmark \ - rsa_padding_test \ - rsa_verify_benchmark \ - sha_benchmark \ - sha_tests \ - verify_firmware_fuzz_driver \ - verify_kernel_fuzz_driver + rm -f $(TEST_BINS) diff --git a/utils/Makefile b/utils/Makefile index 597638e75b..81de74f104 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -8,43 +8,53 @@ CFLAGS ?= -Wall -DNDEBUG -O3 -Werror INCLUDES ?= -I../include/ TOP ?= ../ -LIBS = firmware_image.o kernel_image.o signature_digest.o file_keys.o \ - rollback_index.o +LIBS = file_keys.o \ + firmware_image.o \ + firmware_image_fw.o \ + kernel_image.o \ + kernel_image_fw.o \ + rollback_index.o \ + signature_digest.o FIRMWARELIBS = $(TOP)/crypto/libcrypto.a $(TOP)/common/libcommon.a -all: dumpRSAPublicKey verify_data file_keys.o signature_digest.o \ - firmware_image.o kernel_image.o signature_digest.o \ - signature_digest_utility firmware_utility kernel_utility \ - rollback_index.o +TARGET_BINS = $(LIBS) \ + dumpRSAPublicKey \ + firmware_utility \ + kernel_utility \ + signature_digest_utility \ + verify_data + +all: $(TARGET_BINS) + +.c.o: + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ dumpRSAPublicKey: dumpRSAPublicKey.c $(CC) $(CFLAGS) $< -o $@ -lcrypto -verify_data: verify_data.c $(LIBS) $(FIRMWARELIBS) - $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARELIBS) -lcrypto - -signature_digest_utility: signature_digest_utility.c $(LIBS) $(FIRMWARELIBS) - $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARELIBS) -lcrypto +firmware_image_fw.o: firmware_image_fw.c + $(CC) $(CFLAGS) -ansi $(INCLUDES) -c $^ -o $@ firmware_utility: firmware_utility.cc $(LIBS) $(FIRMWARELIBS) $(CXX) $(CFLAGS) $(INCLUDES) -ggdb -D__STDC_LIMIT_MACROS $< \ -o $@ $(FIRMWARELIBS) $(LIBS) $(TOP)/common/libcommon.a \ -lcrypto +kernel_image_fw.o: kernel_image_fw.c + $(CC) $(CFLAGS) -ansi $(INCLUDES) -c $< -o $@ + kernel_utility: kernel_utility.cc $(LIBS) $(FIRMWARELIBS) $(CXX) $(CFLAGS) $(INCLUDES) -ggdb -D__STDC_LIMIT_MACROS $< \ -o $@ $(FIRMWARELIBS) $(LIBS) $(TOP)/common/libcommon.a \ -lcrypto -.c.o: - $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ +signature_digest_utility: signature_digest_utility.c $(LIBS) $(FIRMWARELIBS) + $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARELIBS) -lcrypto -firmware_image.o: firmware_image.c - $(CC) -ansi $(CFLAGS) $(INCLUDES) -c $< -o $@ +verify_data: verify_data.c $(LIBS) $(FIRMWARELIBS) + $(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARELIBS) -lcrypto -kernel_image.o: kernel_image.c - $(CC) -ansi $(CFLAGS) $(INCLUDES) -c $< -o $@ clean: - rm -f dumpRSAPublicKey verify_data signature_digest firmware_utility \ - kernel_utility signature_digest_utility $(LIBS) + rm -f $(TARGET_BINS) $(LIBS) + diff --git a/utils/dumpRSAPublicKey.c b/utils/dumpRSAPublicKey.c index b6a5190fb4..837303cbe7 100644 --- a/utils/dumpRSAPublicKey.c +++ b/utils/dumpRSAPublicKey.c @@ -8,7 +8,7 @@ * /tools/DumpPublicKey.java). Uses the OpenSSL X509 and BIGNUM library. */ -#include +#include #include #include #include diff --git a/utils/firmware_image.c b/utils/firmware_image.c index 2e3f92441e..803ef89325 100644 --- a/utils/firmware_image.c +++ b/utils/firmware_image.c @@ -9,14 +9,12 @@ #include #include -#include #include #include #include #include "file_keys.h" #include "padding.h" -#include "rollback_index.h" #include "rsa_utility.h" #include "sha_utility.h" #include "signature_digest.h" @@ -71,7 +69,7 @@ FirmwareImage* ReadFirmwareImage(const char* input_file) { /* Read and compare magic bytes. */ StatefulMemcpy(&st, &image->magic, FIRMWARE_MAGIC_SIZE); if (SafeMemcmp(image->magic, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE)) { - fprintf(stderr, "Wrong Firmware Magic.\n"); + debug("Wrong Firmware Magic.\n"); Free(firmware_buf); return NULL; } @@ -92,8 +90,8 @@ FirmwareImage* ReadFirmwareImage(const char* input_file) { /* Check whether the header length is correct. */ header_len = GetFirmwareHeaderLen(image); if (header_len != image->header_len) { - fprintf(stderr, "Header length mismatch. Got: %d Expected: %d\n", - image->header_len, header_len); + debug("Header length mismatch. Got: %d Expected: %d\n", + image->header_len, header_len); Free(firmware_buf); return NULL; } @@ -109,7 +107,7 @@ FirmwareImage* ReadFirmwareImage(const char* input_file) { CalculateFirmwareHeaderChecksum(image, header_checksum); if (SafeMemcmp(header_checksum, image->header_checksum, FIELD_LEN(header_checksum))) { - fprintf(stderr, "Invalid firmware header checksum!\n"); + debug("Invalid firmware header checksum!\n"); Free(firmware_buf); return NULL; } @@ -271,17 +269,17 @@ int WriteFirmwareImage(const char* input_file, if (!image) return 0; if (-1 == (fd = creat(input_file, S_IRWXU))) { - fprintf(stderr, "Couldn't open file for writing.\n"); + debug("Couldn't open file for writing.\n"); return 0; } firmware_blob = GetFirmwareBlob(image, &blob_len); if (!firmware_blob) { - fprintf(stderr, "Couldn't create firmware blob from FirmwareImage.\n"); + debug("Couldn't create firmware blob from FirmwareImage.\n"); return 0; } if (blob_len != write(fd, firmware_blob, blob_len)) { - fprintf(stderr, "Couldn't write Firmware Image to file: %s\n", input_file); + debug("Couldn't write Firmware Image to file: %s\n", input_file); Free(firmware_blob); close(fd); return 0; @@ -296,7 +294,7 @@ void PrintFirmwareImage(const FirmwareImage* image) { return; /* Print header. */ - printf("Header Length = %d\n" + debug("Header Length = %d\n" "Firmware Signature Algorithm = %s\n" "Firmware Key Version = %d\n\n", image->header_len, @@ -304,201 +302,13 @@ void PrintFirmwareImage(const FirmwareImage* image) { image->firmware_key_version); /* TODO(gauravsh): Output hash and key signature here? */ /* Print preamble. */ - printf("Firmware Version = %d\n" + debug("Firmware Version = %d\n" "Firmware Length = %" PRIu64 "\n\n", image->firmware_version, image->firmware_len); /* Output key signature here? */ } -char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX] = { - "Success.", - "Invalid Image.", - "Root Key Signature Failed.", - "Invalid Verification Algorithm.", - "Preamble Signature Failed.", - "Firmware Signature Failed.", - "Wrong Firmware Magic.", - "Invalid Firmware Header Checksum.", - "Firmware Signing Key Rollback.", - "Firmware Version Rollback." -}; - -int VerifyFirmwareHeader(const uint8_t* root_key_blob, - const uint8_t* header_blob, - int* algorithm, - int* header_len) { - int firmware_sign_key_len; - int root_key_len; - uint16_t hlen, algo; - uint8_t* header_checksum = NULL; - - /* Base Offset for the header_checksum field. Actual offset is - * this + firmware_sign_key_len. */ - int base_header_checksum_offset = (FIELD_LEN(header_len) + - FIELD_LEN(firmware_sign_algorithm) + - FIELD_LEN(firmware_key_version)); - - - root_key_len = RSAProcessedKeySize(ROOT_SIGNATURE_ALGORITHM); - Memcpy(&hlen, header_blob, sizeof(hlen)); - Memcpy(&algo, - header_blob + FIELD_LEN(firmware_sign_algorithm), - sizeof(algo)); - if (algo >= kNumAlgorithms) - return VERIFY_FIRMWARE_INVALID_ALGORITHM; - *algorithm = (int) algo; - firmware_sign_key_len = RSAProcessedKeySize(*algorithm); - - /* Verify that header len is correct. */ - if (hlen != (base_header_checksum_offset + - firmware_sign_key_len + - FIELD_LEN(header_checksum))) - return VERIFY_FIRMWARE_INVALID_IMAGE; - - *header_len = (int) hlen; - - /* Verify if the hash of the header is correct. */ - header_checksum = DigestBuf(header_blob, - *header_len - FIELD_LEN(header_checksum), - SHA512_DIGEST_ALGORITHM); - if (SafeMemcmp(header_checksum, - header_blob + (base_header_checksum_offset + - firmware_sign_key_len), - FIELD_LEN(header_checksum))) { - Free(header_checksum); - return VERIFY_FIRMWARE_WRONG_HEADER_CHECKSUM; - } - Free(header_checksum); - - /* Root key signature on the firmware signing key is always checked - * irrespective of dev mode. */ - if (!RSAVerifyBinary_f(root_key_blob, NULL, /* Key to use */ - header_blob, /* Data to verify */ - *header_len, /* Length of data */ - header_blob + *header_len, /* Expected Signature */ - ROOT_SIGNATURE_ALGORITHM)) - return VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED; - return 0; -} - -int VerifyFirmwarePreamble(RSAPublicKey* firmware_sign_key, - const uint8_t* preamble_blob, - int algorithm, - uint64_t* firmware_len) { - uint64_t len; - int preamble_len; - uint16_t firmware_version; - - Memcpy(&firmware_version, preamble_blob, sizeof(firmware_version)); - - preamble_len = (FIELD_LEN(firmware_version) + - FIELD_LEN(firmware_len) + - FIELD_LEN(preamble)); - if (!RSAVerifyBinary_f(NULL, firmware_sign_key, /* Key to use */ - preamble_blob, /* Data to verify */ - preamble_len, /* Length of data */ - preamble_blob + preamble_len, /* Expected Signature */ - algorithm)) - return VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED; - - Memcpy(&len, preamble_blob + FIELD_LEN(firmware_version), - sizeof(len)); - *firmware_len = len; - return 0; -} - -int VerifyFirmwareData(RSAPublicKey* firmware_sign_key, - const uint8_t* preamble_start, - const uint8_t* firmware_data_start, - uint64_t firmware_len, - int algorithm) { - int signature_len = siglen_map[algorithm]; - uint8_t* digest; - DigestContext ctx; - - /* Since the firmware signature is over the preamble and the firmware data, - * which does not form a contiguous region of memory, we calculate the - * message digest ourselves. */ - DigestInit(&ctx, algorithm); - DigestUpdate(&ctx, preamble_start, GetFirmwarePreambleLen()); - DigestUpdate(&ctx, firmware_data_start + signature_len, firmware_len); - digest = DigestFinal(&ctx); - if (!RSAVerifyBinaryWithDigest_f( - NULL, firmware_sign_key, /* Key to use. */ - digest, /* Digest of the data to verify. */ - firmware_data_start, /* Expected Signature */ - algorithm)) { - Free(digest); - return VERIFY_FIRMWARE_SIGNATURE_FAILED; - } - Free(digest); - return 0; -} - -int VerifyFirmware(const uint8_t* root_key_blob, - const uint8_t* firmware_blob) { - int error_code = 0; - int algorithm; /* Signing key algorithm. */ - RSAPublicKey* firmware_sign_key = NULL; - int firmware_sign_key_len, signature_len, header_len; - uint64_t firmware_len; - const uint8_t* header_ptr = NULL; /* Pointer to header. */ - const uint8_t* firmware_sign_key_ptr = NULL; /* Pointer to signing key. */ - const uint8_t* preamble_ptr = NULL; /* Pointer to preamble block. */ - const uint8_t* firmware_ptr = NULL; /* Pointer to firmware signature/data. */ - - /* Note: All the offset calculations are based on struct FirmwareImage which - * is defined in include/firmware_image.h. */ - - /* Compare magic bytes. */ - if (SafeMemcmp(firmware_blob, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE)) - return VERIFY_FIRMWARE_WRONG_MAGIC; - header_ptr = firmware_blob + FIRMWARE_MAGIC_SIZE; - - /* Only continue if header verification succeeds. */ - if ((error_code = VerifyFirmwareHeader(root_key_blob, header_ptr, - &algorithm, &header_len))) - return error_code; /* AKA jump to revovery. */ - - /* Parse signing key into RSAPublicKey structure since it is required multiple - * times. */ - firmware_sign_key_len = RSAProcessedKeySize(algorithm); - firmware_sign_key_ptr = header_ptr + (FIELD_LEN(header_len) + - FIELD_LEN(firmware_sign_algorithm) + - FIELD_LEN(firmware_key_version)); - firmware_sign_key = RSAPublicKeyFromBuf(firmware_sign_key_ptr, - firmware_sign_key_len); - signature_len = siglen_map[algorithm]; - - /* Only continue if preamble verification succeeds. */ - preamble_ptr = (header_ptr + header_len + - FIELD_LEN(firmware_key_signature)); - if ((error_code = VerifyFirmwarePreamble(firmware_sign_key, preamble_ptr, - algorithm, - &firmware_len))) { - RSAPublicKeyFree(firmware_sign_key); - fprintf(stderr, "Couldn't verify Firmware preamble.\n"); - return error_code; /* AKA jump to recovery. */ - } - /* Only continue if firmware data verification succeeds. */ - firmware_ptr = (preamble_ptr + - GetFirmwarePreambleLen() + - signature_len); - - if ((error_code = VerifyFirmwareData(firmware_sign_key, preamble_ptr, - firmware_ptr, - firmware_len, - algorithm))) { - RSAPublicKeyFree(firmware_sign_key); - fprintf(stderr, "Couldn't verify Firmware data.\n"); - return error_code; /* AKA jump to recovery. */ - } - - RSAPublicKeyFree(firmware_sign_key); - return 0; /* Success! */ -} - int VerifyFirmwareImage(const RSAPublicKey* root_key, const FirmwareImage* image) { RSAPublicKey* firmware_sign_key = NULL; @@ -662,114 +472,3 @@ int AddFirmwareSignature(FirmwareImage* image, const char* signing_key_file) { Free(preamble_blob); return 1; } - -uint32_t GetLogicalFirmwareVersion(uint8_t* firmware_blob) { - uint16_t firmware_key_version; - uint16_t firmware_version; - uint16_t firmware_sign_algorithm; - int firmware_sign_key_len; - Memcpy(&firmware_sign_algorithm, - firmware_blob + (FIELD_LEN(magic) + /* Offset to field. */ - FIELD_LEN(header_len)), - sizeof(firmware_sign_algorithm)); - Memcpy(&firmware_key_version, - firmware_blob + (FIELD_LEN(magic) + /* Offset to field. */ - FIELD_LEN(header_len) + - FIELD_LEN(firmware_sign_algorithm)), - sizeof(firmware_key_version)); - if (firmware_sign_algorithm >= kNumAlgorithms) - return 0; - firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm); - Memcpy(&firmware_version, - firmware_blob + (FIELD_LEN(magic) + /* Offset to field. */ - FIELD_LEN(header_len) + - FIELD_LEN(firmware_key_version) + - firmware_sign_key_len + - FIELD_LEN(header_checksum) + - FIELD_LEN(firmware_key_signature)), - sizeof(firmware_version)); - return CombineUint16Pair(firmware_key_version, firmware_version); -} - -int VerifyFirmwareDriver_f(uint8_t* root_key_blob, - uint8_t* firmwareA, - uint8_t* firmwareB) { - /* Contains the logical firmware version (32-bit) which is calculated as - * (firmware_key_version << 16 | firmware_version) where - * [firmware_key_version] [firmware_version] are both 16-bit. - */ - uint32_t firmwareA_lversion, firmwareB_lversion; - uint8_t firmwareA_is_verified = 0; /* Whether firmwareA verify succeeded. */ - uint32_t min_lversion; /* Minimum of firmware A and firmware lversion. */ - uint32_t stored_lversion; /* Stored logical version in the TPM. */ - - /* Initialize the TPM since we'll be reading the rollback indices. */ - SetupTPM(); - - /* We get the key versions by reading directly from the image blobs without - * any additional (expensive) sanity checking on the blob since it's faster to - * outright reject a firmware with an older firmware key version. A malformed - * or corrupted firmware blob will still fail when VerifyFirmware() is called - * on it. - */ - firmwareA_lversion = GetLogicalFirmwareVersion(firmwareA); - firmwareB_lversion = GetLogicalFirmwareVersion(firmwareB); - min_lversion = Min(firmwareA_lversion, firmwareB_lversion); - stored_lversion = CombineUint16Pair(GetStoredVersion(FIRMWARE_KEY_VERSION), - GetStoredVersion(FIRMWARE_VERSION)); - /* Always try FirmwareA first. */ - if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareA)) - firmwareA_is_verified = 1; - if (firmwareA_is_verified && (stored_lversion < firmwareA_lversion)) { - /* Stored version may need to be updated but only if FirmwareB - * is successfully verified and has a logical version greater than - * the stored logical version. */ - if (stored_lversion < firmwareB_lversion) { - if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB)) { - WriteStoredVersion(FIRMWARE_KEY_VERSION, - (uint16_t) (min_lversion >> 16)); - WriteStoredVersion(FIRMWARE_VERSION, - (uint16_t) (min_lversion & 0x00FFFF)); - stored_lversion = min_lversion; /* Update stored version as it's used - * later. */ - } - } - } - /* Lock Firmware TPM rollback indices from further writes. */ - /* TODO(gauravsh): Figure out if these can be combined into one - * 32-bit location since we seem to always use them together. This can help - * us minimize the number of NVRAM writes/locks (which are limited over flash - * memory lifetimes. - */ - LockStoredVersion(FIRMWARE_KEY_VERSION); - LockStoredVersion(FIRMWARE_VERSION); - - /* Determine which firmware (if any) to jump to. - * - * We always attempt to jump to FirmwareA first. If verification of FirmwareA - * fails, we try FirmwareB. In all cases, if the firmware successfully - * verified but is a rollback, we jump to recovery. - * - * Note: This means that if FirmwareA verified successfully and is a - * rollback, then no attempt is made to check FirmwareB. We still jump to - * recovery. FirmwareB is only used as a backup in case FirmwareA gets - * corrupted. Since newer firmware updates are always written to A, - * the case where firmware A is verified but a rollback should not occur in - * normal operation. - */ - if (firmwareA_is_verified) { - if (stored_lversion <= firmwareA_lversion) - return BOOT_FIRMWARE_A_CONTINUE; - } else { - /* If FirmwareA was not valid, then we skipped over the - * check to update the rollback indices and a Verify of FirmwareB wasn't - * attempted. - * If FirmwareB is not a rollback, then we attempt to do the verification. - */ - if (stored_lversion <= firmwareB_lversion && - (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB))) - return BOOT_FIRMWARE_B_CONTINUE; - } - /* D'oh: No bootable firmware. */ - return BOOT_FIRMWARE_RECOVERY_CONTINUE; -} diff --git a/utils/firmware_image_fw.c b/utils/firmware_image_fw.c new file mode 100644 index 0000000000..f5c7d8919d --- /dev/null +++ b/utils/firmware_image_fw.c @@ -0,0 +1,323 @@ +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Functions for verifying a verified boot firmware image. + * (Firmware Portion) + */ + +#include "firmware_image_fw.h" + +#include "padding.h" +#include "rollback_index.h" +#include "rsa_utility.h" +#include "sha_utility.h" +#include "utility.h" + +/* Macro to determine the size of a field structure in the FirmwareImage + * structure. */ +#define FIELD_LEN(field) (sizeof(((FirmwareImage*)0)->field)) + +char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX] = { + "Success.", + "Invalid Image.", + "Root Key Signature Failed.", + "Invalid Verification Algorithm.", + "Preamble Signature Failed.", + "Firmware Signature Failed.", + "Wrong Firmware Magic.", + "Invalid Firmware Header Checksum.", + "Firmware Signing Key Rollback.", + "Firmware Version Rollback." +}; + +int VerifyFirmwareHeader(const uint8_t* root_key_blob, + const uint8_t* header_blob, + int* algorithm, + int* header_len) { + int firmware_sign_key_len; + int root_key_len; + uint16_t hlen, algo; + uint8_t* header_checksum = NULL; + + /* Base Offset for the header_checksum field. Actual offset is + * this + firmware_sign_key_len. */ + int base_header_checksum_offset = (FIELD_LEN(header_len) + + FIELD_LEN(firmware_sign_algorithm) + + FIELD_LEN(firmware_key_version)); + + + root_key_len = RSAProcessedKeySize(ROOT_SIGNATURE_ALGORITHM); + Memcpy(&hlen, header_blob, sizeof(hlen)); + Memcpy(&algo, + header_blob + FIELD_LEN(firmware_sign_algorithm), + sizeof(algo)); + if (algo >= kNumAlgorithms) + return VERIFY_FIRMWARE_INVALID_ALGORITHM; + *algorithm = (int) algo; + firmware_sign_key_len = RSAProcessedKeySize(*algorithm); + + /* Verify that header len is correct. */ + if (hlen != (base_header_checksum_offset + + firmware_sign_key_len + + FIELD_LEN(header_checksum))) + return VERIFY_FIRMWARE_INVALID_IMAGE; + + *header_len = (int) hlen; + + /* Verify if the hash of the header is correct. */ + header_checksum = DigestBuf(header_blob, + *header_len - FIELD_LEN(header_checksum), + SHA512_DIGEST_ALGORITHM); + if (SafeMemcmp(header_checksum, + header_blob + (base_header_checksum_offset + + firmware_sign_key_len), + FIELD_LEN(header_checksum))) { + Free(header_checksum); + return VERIFY_FIRMWARE_WRONG_HEADER_CHECKSUM; + } + Free(header_checksum); + + /* Root key signature on the firmware signing key is always checked + * irrespective of dev mode. */ + if (!RSAVerifyBinary_f(root_key_blob, NULL, /* Key to use */ + header_blob, /* Data to verify */ + *header_len, /* Length of data */ + header_blob + *header_len, /* Expected Signature */ + ROOT_SIGNATURE_ALGORITHM)) + return VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED; + return 0; +} + +int VerifyFirmwarePreamble(RSAPublicKey* firmware_sign_key, + const uint8_t* preamble_blob, + int algorithm, + uint64_t* firmware_len) { + uint64_t len; + int preamble_len; + uint16_t firmware_version; + + Memcpy(&firmware_version, preamble_blob, sizeof(firmware_version)); + + preamble_len = (FIELD_LEN(firmware_version) + + FIELD_LEN(firmware_len) + + FIELD_LEN(preamble)); + if (!RSAVerifyBinary_f(NULL, firmware_sign_key, /* Key to use */ + preamble_blob, /* Data to verify */ + preamble_len, /* Length of data */ + preamble_blob + preamble_len, /* Expected Signature */ + algorithm)) + return VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED; + + Memcpy(&len, preamble_blob + FIELD_LEN(firmware_version), + sizeof(len)); + *firmware_len = len; + return 0; +} + +int VerifyFirmwareData(RSAPublicKey* firmware_sign_key, + const uint8_t* preamble_start, + const uint8_t* firmware_data_start, + uint64_t firmware_len, + int algorithm) { + int signature_len = siglen_map[algorithm]; + uint8_t* digest; + DigestContext ctx; + + /* Since the firmware signature is over the preamble and the firmware data, + * which does not form a contiguous region of memory, we calculate the + * message digest ourselves. */ + DigestInit(&ctx, algorithm); + DigestUpdate(&ctx, preamble_start, + (FIELD_LEN(firmware_version) + + FIELD_LEN(firmware_len) + + FIELD_LEN(preamble))); + DigestUpdate(&ctx, firmware_data_start + signature_len, firmware_len); + digest = DigestFinal(&ctx); + if (!RSAVerifyBinaryWithDigest_f( + NULL, firmware_sign_key, /* Key to use. */ + digest, /* Digest of the data to verify. */ + firmware_data_start, /* Expected Signature */ + algorithm)) { + Free(digest); + return VERIFY_FIRMWARE_SIGNATURE_FAILED; + } + Free(digest); + return 0; +} + +int VerifyFirmware(const uint8_t* root_key_blob, + const uint8_t* firmware_blob) { + int error_code = 0; + int algorithm; /* Signing key algorithm. */ + RSAPublicKey* firmware_sign_key = NULL; + int firmware_sign_key_len, signature_len, header_len; + uint64_t firmware_len; + const uint8_t* header_ptr = NULL; /* Pointer to header. */ + const uint8_t* firmware_sign_key_ptr = NULL; /* Pointer to signing key. */ + const uint8_t* preamble_ptr = NULL; /* Pointer to preamble block. */ + const uint8_t* firmware_ptr = NULL; /* Pointer to firmware signature/data. */ + + /* Note: All the offset calculations are based on struct FirmwareImage which + * is defined in include/firmware_image.h. */ + + /* Compare magic bytes. */ + if (SafeMemcmp(firmware_blob, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE)) + return VERIFY_FIRMWARE_WRONG_MAGIC; + header_ptr = firmware_blob + FIRMWARE_MAGIC_SIZE; + + /* Only continue if header verification succeeds. */ + if ((error_code = VerifyFirmwareHeader(root_key_blob, header_ptr, + &algorithm, &header_len))) + return error_code; /* AKA jump to revovery. */ + + /* Parse signing key into RSAPublicKey structure since it is required multiple + * times. */ + firmware_sign_key_len = RSAProcessedKeySize(algorithm); + firmware_sign_key_ptr = header_ptr + (FIELD_LEN(header_len) + + FIELD_LEN(firmware_sign_algorithm) + + FIELD_LEN(firmware_key_version)); + firmware_sign_key = RSAPublicKeyFromBuf(firmware_sign_key_ptr, + firmware_sign_key_len); + signature_len = siglen_map[algorithm]; + + /* Only continue if preamble verification succeeds. */ + preamble_ptr = (header_ptr + header_len + + FIELD_LEN(firmware_key_signature)); + if ((error_code = VerifyFirmwarePreamble(firmware_sign_key, preamble_ptr, + algorithm, + &firmware_len))) { + RSAPublicKeyFree(firmware_sign_key); + debug("Couldn't verify Firmware preamble.\n"); + return error_code; /* AKA jump to recovery. */ + } + /* Only continue if firmware data verification succeeds. */ + firmware_ptr = (preamble_ptr + + (FIELD_LEN(firmware_version) + /* Skip the preamble. */ + FIELD_LEN(firmware_len) + + FIELD_LEN(preamble)) + + signature_len); + + if ((error_code = VerifyFirmwareData(firmware_sign_key, preamble_ptr, + firmware_ptr, + firmware_len, + algorithm))) { + RSAPublicKeyFree(firmware_sign_key); + debug("Couldn't verify Firmware data.\n"); + return error_code; /* AKA jump to recovery. */ + } + + RSAPublicKeyFree(firmware_sign_key); + return 0; /* Success! */ +} + +uint32_t GetLogicalFirmwareVersion(uint8_t* firmware_blob) { + uint16_t firmware_key_version; + uint16_t firmware_version; + uint16_t firmware_sign_algorithm; + int firmware_sign_key_len; + Memcpy(&firmware_sign_algorithm, + firmware_blob + (FIELD_LEN(magic) + /* Offset to field. */ + FIELD_LEN(header_len)), + sizeof(firmware_sign_algorithm)); + Memcpy(&firmware_key_version, + firmware_blob + (FIELD_LEN(magic) + /* Offset to field. */ + FIELD_LEN(header_len) + + FIELD_LEN(firmware_sign_algorithm)), + sizeof(firmware_key_version)); + if (firmware_sign_algorithm >= kNumAlgorithms) + return 0; + firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm); + Memcpy(&firmware_version, + firmware_blob + (FIELD_LEN(magic) + /* Offset to field. */ + FIELD_LEN(header_len) + + FIELD_LEN(firmware_key_version) + + firmware_sign_key_len + + FIELD_LEN(header_checksum) + + FIELD_LEN(firmware_key_signature)), + sizeof(firmware_version)); + return CombineUint16Pair(firmware_key_version, firmware_version); +} + +int VerifyFirmwareDriver_f(uint8_t* root_key_blob, + uint8_t* firmwareA, + uint8_t* firmwareB) { + /* Contains the logical firmware version (32-bit) which is calculated as + * (firmware_key_version << 16 | firmware_version) where + * [firmware_key_version] [firmware_version] are both 16-bit. + */ + uint32_t firmwareA_lversion, firmwareB_lversion; + uint8_t firmwareA_is_verified = 0; /* Whether firmwareA verify succeeded. */ + uint32_t min_lversion; /* Minimum of firmware A and firmware lversion. */ + uint32_t stored_lversion; /* Stored logical version in the TPM. */ + + /* Initialize the TPM since we'll be reading the rollback indices. */ + SetupTPM(); + + /* We get the key versions by reading directly from the image blobs without + * any additional (expensive) sanity checking on the blob since it's faster to + * outright reject a firmware with an older firmware key version. A malformed + * or corrupted firmware blob will still fail when VerifyFirmware() is called + * on it. + */ + firmwareA_lversion = GetLogicalFirmwareVersion(firmwareA); + firmwareB_lversion = GetLogicalFirmwareVersion(firmwareB); + min_lversion = Min(firmwareA_lversion, firmwareB_lversion); + stored_lversion = CombineUint16Pair(GetStoredVersion(FIRMWARE_KEY_VERSION), + GetStoredVersion(FIRMWARE_VERSION)); + /* Always try FirmwareA first. */ + if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareA)) + firmwareA_is_verified = 1; + if (firmwareA_is_verified && (stored_lversion < firmwareA_lversion)) { + /* Stored version may need to be updated but only if FirmwareB + * is successfully verified and has a logical version greater than + * the stored logical version. */ + if (stored_lversion < firmwareB_lversion) { + if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB)) { + WriteStoredVersion(FIRMWARE_KEY_VERSION, + (uint16_t) (min_lversion >> 16)); + WriteStoredVersion(FIRMWARE_VERSION, + (uint16_t) (min_lversion & 0x00FFFF)); + stored_lversion = min_lversion; /* Update stored version as it's used + * later. */ + } + } + } + /* Lock Firmware TPM rollback indices from further writes. */ + /* TODO(gauravsh): Figure out if these can be combined into one + * 32-bit location since we seem to always use them together. This can help + * us minimize the number of NVRAM writes/locks (which are limited over flash + * memory lifetimes. + */ + LockStoredVersion(FIRMWARE_KEY_VERSION); + LockStoredVersion(FIRMWARE_VERSION); + + /* Determine which firmware (if any) to jump to. + * + * We always attempt to jump to FirmwareA first. If verification of FirmwareA + * fails, we try FirmwareB. In all cases, if the firmware successfully + * verified but is a rollback, we jump to recovery. + * + * Note: This means that if FirmwareA verified successfully and is a + * rollback, then no attempt is made to check FirmwareB. We still jump to + * recovery. FirmwareB is only used as a backup in case FirmwareA gets + * corrupted. Since newer firmware updates are always written to A, + * the case where firmware A is verified but a rollback should not occur in + * normal operation. + */ + if (firmwareA_is_verified) { + if (stored_lversion <= firmwareA_lversion) + return BOOT_FIRMWARE_A_CONTINUE; + } else { + /* If FirmwareA was not valid, then we skipped over the + * check to update the rollback indices and a Verify of FirmwareB wasn't + * attempted. + * If FirmwareB is not a rollback, then we attempt to do the verification. + */ + if (stored_lversion <= firmwareB_lversion && + (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB))) + return BOOT_FIRMWARE_B_CONTINUE; + } + /* D'oh: No bootable firmware. */ + return BOOT_FIRMWARE_RECOVERY_CONTINUE; +} diff --git a/utils/kernel_image.c b/utils/kernel_image.c index 32e12a85d6..e66ce384fe 100644 --- a/utils/kernel_image.c +++ b/utils/kernel_image.c @@ -3,6 +3,7 @@ * found in the LICENSE file. * * Functions for generating and manipulating a verified boot kernel image. + * (Userland portion) */ #include "kernel_image.h" @@ -75,7 +76,7 @@ KernelImage* ReadKernelImage(const char* input_file) { StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE); if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) { - fprintf(stderr, "Wrong Kernel Magic.\n"); + debug("Wrong Kernel Magic.\n"); Free(kernel_buf); return NULL; } @@ -107,7 +108,7 @@ KernelImage* ReadKernelImage(const char* input_file) { /* Check whether key header length is correct. */ header_len = GetKernelHeaderLen(image); if (header_len != image->header_len) { - fprintf(stderr, "Header length mismatch. Got: %d, Expected: %d\n", + debug("Header length mismatch. Got: %d, Expected: %d\n", image->header_len, header_len); Free(kernel_buf); return NULL; @@ -124,7 +125,7 @@ KernelImage* ReadKernelImage(const char* input_file) { CalculateKernelHeaderChecksum(image, header_checksum); if (SafeMemcmp(header_checksum, image->header_checksum, FIELD_LEN(header_checksum))) { - fprintf(stderr, "Invalid kernel header checksum!\n"); + debug("Invalid kernel header checksum!\n"); Free(kernel_buf); return NULL; } @@ -307,17 +308,17 @@ int WriteKernelImage(const char* input_file, if (!image) return 0; if (-1 == (fd = creat(input_file, S_IRWXU))) { - fprintf(stderr, "Couldn't open file for writing kernel image: %s\n", + debug("Couldn't open file for writing kernel image: %s\n", input_file); return 0; } kernel_blob = GetKernelBlob(image, &blob_len); if (!kernel_blob) { - fprintf(stderr, "Couldn't create kernel blob from KernelImage.\n"); + debug("Couldn't create kernel blob from KernelImage.\n"); return 0; } if (blob_len != write(fd, kernel_blob, blob_len)) { - fprintf(stderr, "Couldn't write Kernel Image to file: %s\n", + debug("Couldn't write Kernel Image to file: %s\n", input_file); Free(kernel_blob); @@ -361,212 +362,6 @@ void PrintKernelImage(const KernelImage* image) { /* TODO(gauravsh): Output kernel signature here? */ } -char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = { - "Success.", - "Invalid Image.", - "Kernel Key Signature Failed.", - "Invalid Kernel Verification Algorithm.", - "Config Signature Failed.", - "Kernel Signature Failed.", - "Wrong Kernel Magic.", -}; - -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 kernel_sign_key_len; - int firmware_sign_key_len; - uint16_t header_version, header_len; - uint16_t firmware_sign_algorithm, kernel_sign_algorithm; - uint8_t* header_checksum = NULL; - - /* Base Offset for the header_checksum field. Actual offset is - * this + kernel_sign_key_len. */ - int base_header_checksum_offset = (FIELD_LEN(header_version) + - FIELD_LEN(header_len) + - FIELD_LEN(firmware_sign_algorithm) + - FIELD_LEN(kernel_sign_algorithm) + - FIELD_LEN(kernel_key_version)); - - Memcpy(&header_version, header_blob, sizeof(header_version)); - Memcpy(&header_len, header_blob + FIELD_LEN(header_version), - sizeof(header_len)); - Memcpy(&firmware_sign_algorithm, - header_blob + (FIELD_LEN(header_version) + - FIELD_LEN(header_len)), - sizeof(firmware_sign_algorithm)); - Memcpy(&kernel_sign_algorithm, - header_blob + (FIELD_LEN(header_version) + - FIELD_LEN(header_len) + - FIELD_LEN(firmware_sign_algorithm)), - sizeof(kernel_sign_algorithm)); - - /* TODO(gauravsh): Make this return two different error types depending - * on whether the firmware or kernel signing algorithm is invalid. */ - if (firmware_sign_algorithm >= kNumAlgorithms) - return VERIFY_KERNEL_INVALID_ALGORITHM; - if (kernel_sign_algorithm >= kNumAlgorithms) - return VERIFY_KERNEL_INVALID_ALGORITHM; - - *firmware_algorithm = (int) firmware_sign_algorithm; - *kernel_algorithm = (int) kernel_sign_algorithm; - kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm); - firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm); - - - /* Verify if header len is correct? */ - if (header_len != (base_header_checksum_offset + - kernel_sign_key_len + - FIELD_LEN(header_checksum))) { - fprintf(stderr, "VerifyKernelHeader: Header length mismatch\n"); - return VERIFY_KERNEL_INVALID_IMAGE; - } - *kernel_header_len = (int) header_len; - - /* Verify if the hash of the header is correct. */ - header_checksum = DigestBuf(header_blob, - header_len - FIELD_LEN(header_checksum), - SHA512_DIGEST_ALGORITHM); - if (SafeMemcmp(header_checksum, - header_blob + (base_header_checksum_offset + - kernel_sign_key_len), - FIELD_LEN(header_checksum))) { - Free(header_checksum); - fprintf(stderr, "VerifyKernelHeader: Invalid header hash\n"); - return VERIFY_KERNEL_INVALID_IMAGE; - } - Free(header_checksum); - - /* Verify kernel key signature unless we are in dev mode. */ - if (!dev_mode) { - if (!RSAVerifyBinary_f(firmware_key_blob, NULL, /* Key to use */ - header_blob, /* Data to verify */ - header_len, /* Length of data */ - header_blob + header_len, /* Expected Signature */ - firmware_sign_algorithm)) - return VERIFY_KERNEL_KEY_SIGNATURE_FAILED; - } - return 0; -} - -int VerifyKernelConfig(RSAPublicKey* kernel_sign_key, - const uint8_t* config_blob, - int algorithm, - uint64_t* kernel_len) { - uint64_t len; - int config_len; - config_len = GetKernelConfigLen(NULL); - if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */ - config_blob, /* Data to verify */ - config_len, /* Length of data */ - config_blob + config_len, /* Expected Signature */ - algorithm)) - return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED; - - Memcpy(&len, - config_blob + (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) + - FIELD_LEN(options.cmd_line)), - sizeof(len)); - *kernel_len = len; - return 0; -} - -int VerifyKernelData(RSAPublicKey* kernel_sign_key, - const uint8_t* kernel_config_start, - const uint8_t* kernel_data_start, - uint64_t kernel_len, - int algorithm) { - int signature_len = siglen_map[algorithm]; - uint8_t* digest; - 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. */ - DigestInit(&ctx, algorithm); - DigestUpdate(&ctx, kernel_config_start, GetKernelConfigLen()); - DigestUpdate(&ctx, kernel_data_start + signature_len, 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 */ - algorithm)) { - Free(digest); - return VERIFY_KERNEL_SIGNATURE_FAILED; - } - Free(digest); - return 0; -} - -int VerifyKernel(const uint8_t* firmware_key_blob, - const uint8_t* kernel_blob, - const int dev_mode) { - int error_code; - int firmware_sign_algorithm; /* Firmware signing key algorithm. */ - int kernel_sign_algorithm; /* Kernel Signing key algorithm. */ - RSAPublicKey* kernel_sign_key; - int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len, - header_len; - 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* kernel_ptr; /* Pointer to kernel signature/data. */ - - /* Note: All the offset calculations are based on struct FirmwareImage which - * is defined in include/firmware_image.h. */ - - /* Compare magic bytes. */ - if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) - return VERIFY_KERNEL_WRONG_MAGIC; - 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))) { - fprintf(stderr, "VerifyKernel: Kernel 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 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))) { - RSAPublicKeyFree(kernel_sign_key); - return error_code; /* AKA jump to recovery. */ - } - /* Only continue if kernel data verification succeeds. */ - kernel_ptr = (config_ptr + - GetKernelConfigLen() + /* Skip config block/signature. */ - kernel_signature_len); - - if ((error_code = VerifyKernelData(kernel_sign_key, config_ptr, kernel_ptr, - kernel_len, - kernel_sign_algorithm))) { - RSAPublicKeyFree(kernel_sign_key); - return error_code; /* AKA jump to recovery. */ - } - RSAPublicKeyFree(kernel_sign_key); - return 0; /* Success! */ -} int VerifyKernelImage(const RSAPublicKey* firmware_key, const KernelImage* image, @@ -617,7 +412,7 @@ int VerifyKernelImage(const RSAPublicKey* firmware_key, siglen_map[image->firmware_sign_algorithm], image->firmware_sign_algorithm, header_digest)) { - fprintf(stderr, "VerifyKernelImage(): Key signature check failed.\n"); + debug("VerifyKernelImage(): Key signature check failed.\n"); error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED; goto verify_failure; } @@ -723,7 +518,7 @@ int AddKernelSignature(KernelImage* image, GetKernelConfigLen(), kernel_signing_key_file, image->kernel_sign_algorithm))) { - fprintf(stderr, "Could not compute signature on the kernel config.\n"); + debug("Could not compute signature on the kernel config.\n"); Free(config_blob); return 0; } @@ -745,7 +540,7 @@ int AddKernelSignature(KernelImage* image, image->kernel_sign_algorithm))) { Free(config_blob); Free(kernel_buf); - fprintf(stderr, "Could not compute signature on the kernel.\n"); + debug("Could not compute signature on the kernel.\n"); return 0; } image->kernel_signature = (uint8_t*) Malloc(signature_len); @@ -756,146 +551,8 @@ int AddKernelSignature(KernelImage* image, return 1; } -uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) { - uint8_t* kernel_ptr; - uint16_t kernel_key_version; - uint16_t kernel_version; - uint16_t firmware_sign_algorithm; - uint16_t kernel_sign_algorithm; - int kernel_key_signature_len; - int kernel_sign_key_len; - kernel_ptr = kernel_blob + (FIELD_LEN(magic) + - FIELD_LEN(header_version) + - FIELD_LEN(header_len)); - Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm)); - kernel_ptr += FIELD_LEN(firmware_sign_algorithm); - Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm)); - kernel_ptr += FIELD_LEN(kernel_sign_algorithm); - Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version)); - - if (firmware_sign_algorithm >= kNumAlgorithms) - 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) + - kernel_sign_key_len + - FIELD_LEN(header_checksum) + - kernel_key_signature_len); - Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version)); - return CombineUint16Pair(kernel_key_version, kernel_version); -} - void PrintKernelEntry(kernel_entry* entry) { - fprintf(stderr, "Boot Priority = %d\n", entry->boot_priority); - fprintf(stderr, "Boot Tries Remaining = %d\n", entry->boot_tries_remaining); - fprintf(stderr, "Boot Success Flag = %d\n", entry->boot_success_flag); -} - -int VerifyKernelDriver_f(uint8_t* firmware_key_blob, - kernel_entry* kernelA, - kernel_entry* kernelB, - int dev_mode) { - int i; - /* Contains the logical kernel version (32-bit) which is calculated as - * (kernel_key_version << 16 | kernel_version) where - * [kernel_key_version], [firmware_version] are both 16-bit. - */ - uint32_t kernelA_lversion, kernelB_lversion; - uint32_t min_lversion; /* Minimum of kernel A and kernel B lversion. */ - uint32_t stored_lversion; /* Stored logical version in the TPM. */ - kernel_entry* try_kernel[2]; /* Kernel in try order. */ - int try_kernel_which[2]; /* Which corresponding kernel in the try order */ - uint32_t try_kernel_lversion[2]; /* Their logical versions. */ - - /* [kernel_to_boot] will eventually contain the boot path to follow - * and is returned to the caller. Initially, we set it to recovery. If - * a valid bootable kernel is found, it will be set to that. */ - int kernel_to_boot = BOOT_KERNEL_RECOVERY_CONTINUE; - - - /* The TPM must already have be initialized, so no need to call SetupTPM(). */ - - /* We get the key versions by reading directly from the image blobs without - * any additional (expensive) sanity checking on the blob since it's faster to - * outright reject a kernel with an older kernel key version. A malformed - * or corrupted kernel blob will still fail when VerifyKernel() is called - * on it. - */ - kernelA_lversion = GetLogicalKernelVersion(kernelA->kernel_blob); - kernelB_lversion = GetLogicalKernelVersion(kernelB->kernel_blob); - min_lversion = Min(kernelA_lversion, kernelB_lversion); - stored_lversion = CombineUint16Pair(GetStoredVersion(KERNEL_KEY_VERSION), - GetStoredVersion(KERNEL_VERSION)); - - /* TODO(gauravsh): The kernel entries kernelA and kernelB come from the - * partition table - verify its signature/checksum before proceeding - * further. */ - - /* The logic for deciding which kernel to boot from is taken from the - * the Chromium OS Drive Map design document. - * - * We went to consider the kernels in their according to their boot - * priority attribute value. - */ - - if (kernelA->boot_priority >= kernelB->boot_priority) { - try_kernel[0] = kernelA; - try_kernel_which[0] = BOOT_KERNEL_A_CONTINUE; - try_kernel_lversion[0] = kernelA_lversion; - try_kernel[1] = kernelB; - try_kernel_which[1] = BOOT_KERNEL_B_CONTINUE; - try_kernel_lversion[1] = kernelB_lversion; - } else { - try_kernel[0] = kernelB; - try_kernel_which[0] = BOOT_KERNEL_B_CONTINUE; - try_kernel_lversion[0] = kernelB_lversion; - try_kernel[1] = kernelA; - try_kernel_which[1] = BOOT_KERNEL_A_CONTINUE; - try_kernel_lversion[1] = kernelA_lversion; - } - - /* TODO(gauravsh): Changes to boot_tries_remaining and boot_priority - * below should be propagated to partition table. This will be added - * once the firmware parition table parsing code is in. */ - for (i = 0; i < 2; i++) { - if ((try_kernel[i]->boot_success_flag || - try_kernel[i]->boot_tries_remaining) && - (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob, - try_kernel[i]->kernel_blob, - dev_mode))) { - if (try_kernel[i]->boot_tries_remaining > 0) - try_kernel[i]->boot_tries_remaining--; - if (stored_lversion > try_kernel_lversion[i]) - continue; /* Rollback: I am afraid I can't let you do that Dave. */ - if (i == 0 && (stored_lversion < try_kernel_lversion[1])) { - /* The higher priority kernel is valid and bootable, See if we - * need to update the stored version for rollback prevention. */ - if (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob, - try_kernel[1]->kernel_blob, - dev_mode)) { - WriteStoredVersion(KERNEL_KEY_VERSION, - (uint16_t) (min_lversion >> 16)); - WriteStoredVersion(KERNEL_VERSION, - (uint16_t) (min_lversion & 0xFFFF)); - stored_lversion = min_lversion; /* Update stored version as it's - * used later. */ - } - } - kernel_to_boot = try_kernel_which[i]; - break; /* We found a valid kernel. */ - } - try_kernel[i]->boot_priority = 0; - } /* for loop. */ - - /* Lock Kernel TPM rollback indices from further writes. - * TODO(gauravsh): Figure out if these can be combined into one - * 32-bit location since we seem to always use them together. This can help - * us minimize the number of NVRAM writes/locks (which are limited over flash - * memory lifetimes. - */ - LockStoredVersion(KERNEL_KEY_VERSION); - LockStoredVersion(KERNEL_VERSION); - return kernel_to_boot; + debug("Boot Priority = %d\n", entry->boot_priority); + debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining); + debug("Boot Success Flag = %d\n", entry->boot_success_flag); } diff --git a/utils/kernel_image_fw.c b/utils/kernel_image_fw.c new file mode 100644 index 0000000000..466d34af90 --- /dev/null +++ b/utils/kernel_image_fw.c @@ -0,0 +1,368 @@ +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Functions for verifying a verified boot kernel image. + * (Firmware portion) + */ + +#include "kernel_image_fw.h" + +#include "padding.h" +#include "rollback_index.h" +#include "rsa_utility.h" +#include "sha_utility.h" +#include "utility.h" + +/* 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.", + "Invalid Image.", + "Kernel Key Signature Failed.", + "Invalid Kernel Verification Algorithm.", + "Config Signature Failed.", + "Kernel Signature Failed.", + "Wrong Kernel Magic.", +}; + +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 kernel_sign_key_len; + int firmware_sign_key_len; + uint16_t header_version, header_len; + uint16_t firmware_sign_algorithm, kernel_sign_algorithm; + uint8_t* header_checksum = NULL; + + /* Base Offset for the header_checksum field. Actual offset is + * this + kernel_sign_key_len. */ + int base_header_checksum_offset = (FIELD_LEN(header_version) + + FIELD_LEN(header_len) + + FIELD_LEN(firmware_sign_algorithm) + + FIELD_LEN(kernel_sign_algorithm) + + FIELD_LEN(kernel_key_version)); + + Memcpy(&header_version, header_blob, sizeof(header_version)); + Memcpy(&header_len, header_blob + FIELD_LEN(header_version), + sizeof(header_len)); + Memcpy(&firmware_sign_algorithm, + header_blob + (FIELD_LEN(header_version) + + FIELD_LEN(header_len)), + sizeof(firmware_sign_algorithm)); + Memcpy(&kernel_sign_algorithm, + header_blob + (FIELD_LEN(header_version) + + FIELD_LEN(header_len) + + FIELD_LEN(firmware_sign_algorithm)), + sizeof(kernel_sign_algorithm)); + + /* TODO(gauravsh): Make this return two different error types depending + * on whether the firmware or kernel signing algorithm is invalid. */ + if (firmware_sign_algorithm >= kNumAlgorithms) + return VERIFY_KERNEL_INVALID_ALGORITHM; + if (kernel_sign_algorithm >= kNumAlgorithms) + return VERIFY_KERNEL_INVALID_ALGORITHM; + + *firmware_algorithm = (int) firmware_sign_algorithm; + *kernel_algorithm = (int) kernel_sign_algorithm; + kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm); + firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm); + + + /* Verify if header len is correct? */ + if (header_len != (base_header_checksum_offset + + kernel_sign_key_len + + FIELD_LEN(header_checksum))) { + debug("VerifyKernelHeader: Header length mismatch\n"); + return VERIFY_KERNEL_INVALID_IMAGE; + } + *kernel_header_len = (int) header_len; + + /* Verify if the hash of the header is correct. */ + header_checksum = DigestBuf(header_blob, + header_len - FIELD_LEN(header_checksum), + SHA512_DIGEST_ALGORITHM); + if (SafeMemcmp(header_checksum, + header_blob + (base_header_checksum_offset + + kernel_sign_key_len), + FIELD_LEN(header_checksum))) { + Free(header_checksum); + debug("VerifyKernelHeader: Invalid header hash\n"); + return VERIFY_KERNEL_INVALID_IMAGE; + } + Free(header_checksum); + + /* Verify kernel key signature unless we are in dev mode. */ + if (!dev_mode) { + if (!RSAVerifyBinary_f(firmware_key_blob, NULL, /* Key to use */ + header_blob, /* Data to verify */ + header_len, /* Length of data */ + header_blob + header_len, /* Expected Signature */ + firmware_sign_algorithm)) + return VERIFY_KERNEL_KEY_SIGNATURE_FAILED; + } + return 0; +} + +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; + + Memcpy(&len, + config_blob + (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) + + FIELD_LEN(options.cmd_line)), + sizeof(len)); + *kernel_len = len; + return 0; +} + +int VerifyKernelData(RSAPublicKey* kernel_sign_key, + const uint8_t* kernel_config_start, + const uint8_t* kernel_data_start, + uint64_t kernel_len, + int algorithm) { + int signature_len = siglen_map[algorithm]; + uint8_t* digest; + 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. */ + DigestInit(&ctx, algorithm); + DigestUpdate(&ctx, kernel_config_start, KERNEL_CONFIG_FIELD_LEN); + DigestUpdate(&ctx, kernel_data_start + signature_len, 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 */ + algorithm)) { + Free(digest); + return VERIFY_KERNEL_SIGNATURE_FAILED; + } + Free(digest); + return 0; +} + +int VerifyKernel(const uint8_t* firmware_key_blob, + const uint8_t* kernel_blob, + const int dev_mode) { + int error_code; + int firmware_sign_algorithm; /* Firmware signing key algorithm. */ + int kernel_sign_algorithm; /* Kernel Signing key algorithm. */ + RSAPublicKey* kernel_sign_key; + int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len, + header_len; + 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* kernel_ptr; /* Pointer to kernel signature/data. */ + + /* Note: All the offset calculations are based on struct FirmwareImage which + * is defined in include/firmware_image.h. */ + + /* Compare magic bytes. */ + if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) + return VERIFY_KERNEL_WRONG_MAGIC; + 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))) { + debug("VerifyKernel: Kernel 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 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))) { + RSAPublicKeyFree(kernel_sign_key); + return error_code; /* AKA jump to recovery. */ + } + /* 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, + kernel_sign_algorithm))) { + RSAPublicKeyFree(kernel_sign_key); + return error_code; /* AKA jump to recovery. */ + } + RSAPublicKeyFree(kernel_sign_key); + return 0; /* Success! */ +} + +uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) { + uint8_t* kernel_ptr; + uint16_t kernel_key_version; + uint16_t kernel_version; + uint16_t firmware_sign_algorithm; + uint16_t kernel_sign_algorithm; + int kernel_key_signature_len; + int kernel_sign_key_len; + kernel_ptr = kernel_blob + (FIELD_LEN(magic) + + FIELD_LEN(header_version) + + FIELD_LEN(header_len)); + Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm)); + kernel_ptr += FIELD_LEN(firmware_sign_algorithm); + Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm)); + kernel_ptr += FIELD_LEN(kernel_sign_algorithm); + Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version)); + + if (firmware_sign_algorithm >= kNumAlgorithms) + 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) + + kernel_sign_key_len + + FIELD_LEN(header_checksum) + + kernel_key_signature_len); + Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version)); + return CombineUint16Pair(kernel_key_version, kernel_version); +} + +int VerifyKernelDriver_f(uint8_t* firmware_key_blob, + kernel_entry* kernelA, + kernel_entry* kernelB, + int dev_mode) { + int i; + /* Contains the logical kernel version (32-bit) which is calculated as + * (kernel_key_version << 16 | kernel_version) where + * [kernel_key_version], [firmware_version] are both 16-bit. + */ + uint32_t kernelA_lversion, kernelB_lversion; + uint32_t min_lversion; /* Minimum of kernel A and kernel B lversion. */ + uint32_t stored_lversion; /* Stored logical version in the TPM. */ + kernel_entry* try_kernel[2]; /* Kernel in try order. */ + int try_kernel_which[2]; /* Which corresponding kernel in the try order */ + uint32_t try_kernel_lversion[2]; /* Their logical versions. */ + + /* [kernel_to_boot] will eventually contain the boot path to follow + * and is returned to the caller. Initially, we set it to recovery. If + * a valid bootable kernel is found, it will be set to that. */ + int kernel_to_boot = BOOT_KERNEL_RECOVERY_CONTINUE; + + + /* The TPM must already have be initialized, so no need to call SetupTPM(). */ + + /* We get the key versions by reading directly from the image blobs without + * any additional (expensive) sanity checking on the blob since it's faster to + * outright reject a kernel with an older kernel key version. A malformed + * or corrupted kernel blob will still fail when VerifyKernel() is called + * on it. + */ + kernelA_lversion = GetLogicalKernelVersion(kernelA->kernel_blob); + kernelB_lversion = GetLogicalKernelVersion(kernelB->kernel_blob); + min_lversion = Min(kernelA_lversion, kernelB_lversion); + stored_lversion = CombineUint16Pair(GetStoredVersion(KERNEL_KEY_VERSION), + GetStoredVersion(KERNEL_VERSION)); + + /* TODO(gauravsh): The kernel entries kernelA and kernelB come from the + * partition table - verify its signature/checksum before proceeding + * further. */ + + /* The logic for deciding which kernel to boot from is taken from the + * the Chromium OS Drive Map design document. + * + * We went to consider the kernels in their according to their boot + * priority attribute value. + */ + + if (kernelA->boot_priority >= kernelB->boot_priority) { + try_kernel[0] = kernelA; + try_kernel_which[0] = BOOT_KERNEL_A_CONTINUE; + try_kernel_lversion[0] = kernelA_lversion; + try_kernel[1] = kernelB; + try_kernel_which[1] = BOOT_KERNEL_B_CONTINUE; + try_kernel_lversion[1] = kernelB_lversion; + } else { + try_kernel[0] = kernelB; + try_kernel_which[0] = BOOT_KERNEL_B_CONTINUE; + try_kernel_lversion[0] = kernelB_lversion; + try_kernel[1] = kernelA; + try_kernel_which[1] = BOOT_KERNEL_A_CONTINUE; + try_kernel_lversion[1] = kernelA_lversion; + } + + /* TODO(gauravsh): Changes to boot_tries_remaining and boot_priority + * below should be propagated to partition table. This will be added + * once the firmware parition table parsing code is in. */ + for (i = 0; i < 2; i++) { + if ((try_kernel[i]->boot_success_flag || + try_kernel[i]->boot_tries_remaining) && + (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob, + try_kernel[i]->kernel_blob, + dev_mode))) { + if (try_kernel[i]->boot_tries_remaining > 0) + try_kernel[i]->boot_tries_remaining--; + if (stored_lversion > try_kernel_lversion[i]) + continue; /* Rollback: I am afraid I can't let you do that Dave. */ + if (i == 0 && (stored_lversion < try_kernel_lversion[1])) { + /* The higher priority kernel is valid and bootable, See if we + * need to update the stored version for rollback prevention. */ + if (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob, + try_kernel[1]->kernel_blob, + dev_mode)) { + WriteStoredVersion(KERNEL_KEY_VERSION, + (uint16_t) (min_lversion >> 16)); + WriteStoredVersion(KERNEL_VERSION, + (uint16_t) (min_lversion & 0xFFFF)); + stored_lversion = min_lversion; /* Update stored version as it's + * used later. */ + } + } + kernel_to_boot = try_kernel_which[i]; + break; /* We found a valid kernel. */ + } + try_kernel[i]->boot_priority = 0; + } /* for loop. */ + + /* Lock Kernel TPM rollback indices from further writes. + * TODO(gauravsh): Figure out if these can be combined into one + * 32-bit location since we seem to always use them together. This can help + * us minimize the number of NVRAM writes/locks (which are limited over flash + * memory lifetimes. + */ + LockStoredVersion(KERNEL_KEY_VERSION); + LockStoredVersion(KERNEL_VERSION); + return kernel_to_boot; +}