mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-09 17:11:42 +00:00
Change kernel vboot header layout and add support for separate header verification.
This CL adds 2 things: - Instead of having a kernel config, now we have a kernel preamble which contains some important parameters needed by the bootloader in the firmware to kernel hand-off. These parameters are verified using a separate preamble signature in addition to the kernel signature on actual kernel image data. - Adds a new VerifyKernelHeader() API function which verifies the kernel verified boot header excluding the kernel data and also extracts parameters out of this header needed to verify the actual kernel image data (if deemed necessary). This allows for vboot header verification and data verification to be performed separately. Review URL: http://codereview.chromium.org/2234003
This commit is contained in:
@@ -40,14 +40,14 @@ void VerifyKernelImageTest(KernelImage* image,
|
||||
/* Tampered KernelImage Verification Tests. */
|
||||
void VerifyKernelImageTamperTest(KernelImage* image,
|
||||
RSAPublicKey* firmware_key) {
|
||||
image->kernel_config[0] ^= 0xFF;
|
||||
image->bootloader_offset ^= 0xFF;
|
||||
TEST_EQ(VerifyKernelImage(firmware_key, image, DEV_MODE_ENABLED),
|
||||
VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED,
|
||||
VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED,
|
||||
"KernelImage Config Tamper Verification (Dev Mode)");
|
||||
TEST_EQ(VerifyKernelImage(firmware_key, image, DEV_MODE_DISABLED),
|
||||
VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED,
|
||||
VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED,
|
||||
"KernelImage Config Tamper Verification (Trusted)");
|
||||
image->kernel_config[0] ^= 0xFF;
|
||||
image->bootloader_offset ^= 0xFF;
|
||||
|
||||
image->kernel_data[0] = 'T';
|
||||
TEST_EQ(VerifyKernelImage(firmware_key, image, DEV_MODE_ENABLED),
|
||||
|
||||
@@ -160,7 +160,9 @@ KernelImage* GenerateTestKernelImage(int firmware_sign_algorithm,
|
||||
|
||||
/* Populate kernel options and data with dummy data. */
|
||||
image->kernel_version = kernel_version;
|
||||
Memset(image->kernel_config, 0, sizeof(image->kernel_config));
|
||||
image->bootloader_offset = 0;
|
||||
image->bootloader_size = 512;
|
||||
image->padded_header_size = 100;
|
||||
image->kernel_len = kernel_len;
|
||||
image->kernel_key_signature = image->kernel_signature = NULL;
|
||||
image->kernel_data = Malloc(kernel_len);
|
||||
|
||||
@@ -58,11 +58,6 @@ class KernelUtility {
|
||||
std::string firmware_key_pub_file_;
|
||||
std::string kernel_key_file_; // Private key for signing the kernel.
|
||||
std::string kernel_key_pub_file_;
|
||||
std::string config_file_; // File containing kernel config options.
|
||||
// TODO(gauravsh): Currently this just fills in options.cmd_line in struct
|
||||
// KernelImage (from vkernel/kernel_image_fw.h). Ideally we'd like to have
|
||||
// a well defined config file format which is also backwards compatible with
|
||||
// Legacy BIOS boot loaders.
|
||||
|
||||
// Fields of a KernelImage. (read from the command line).
|
||||
int header_version_;
|
||||
|
||||
@@ -36,7 +36,6 @@ KernelUtility::KernelUtility(): image_(NULL),
|
||||
kernel_key_version_(-1),
|
||||
kernel_version_(-1),
|
||||
kernel_len_(0),
|
||||
kernel_config_(NULL),
|
||||
is_generate_(false),
|
||||
is_verify_(false),
|
||||
is_describe_(false),
|
||||
@@ -44,7 +43,6 @@ KernelUtility::KernelUtility(): image_(NULL),
|
||||
}
|
||||
|
||||
KernelUtility::~KernelUtility() {
|
||||
Free(kernel_config_);
|
||||
RSAPublicKeyFree(firmware_key_pub_);
|
||||
KernelImageFree(image_);
|
||||
}
|
||||
@@ -70,7 +68,6 @@ void KernelUtility::PrintUsage(void) {
|
||||
"--in <infile>\t\tKernel Image to sign\n"
|
||||
"--out <outfile>\t\tOutput file for verified boot Kernel image\n\n"
|
||||
"Optional arguments for \"--generate\" include:\n"
|
||||
"--config <file>\t\t\tPopulate contents of kernel config from a file\n"
|
||||
"--vblock\t\t\tJust output the verification block\n\n"
|
||||
"<algoid> (for --*_sign_algorithm) is one of the following:\n";
|
||||
for (int i = 0; i < kNumAlgorithms; i++) {
|
||||
@@ -95,7 +92,6 @@ bool KernelUtility::ParseCmdLineOptions(int argc, char* argv[]) {
|
||||
OPT_GENERATE,
|
||||
OPT_VERIFY,
|
||||
OPT_DESCRIBE,
|
||||
OPT_CONFIG,
|
||||
OPT_VBLOCK,
|
||||
};
|
||||
static struct option long_options[] = {
|
||||
@@ -112,7 +108,6 @@ bool KernelUtility::ParseCmdLineOptions(int argc, char* argv[]) {
|
||||
{"generate", 0, 0, OPT_GENERATE },
|
||||
{"verify", 0, 0, OPT_VERIFY },
|
||||
{"describe", 0, 0, OPT_DESCRIBE },
|
||||
{"config", 1, 0, OPT_CONFIG },
|
||||
{"vblock", 0, 0, OPT_VBLOCK },
|
||||
{NULL, 0, 0, 0}
|
||||
};
|
||||
@@ -176,9 +171,6 @@ bool KernelUtility::ParseCmdLineOptions(int argc, char* argv[]) {
|
||||
case OPT_DESCRIBE:
|
||||
is_describe_ = true;
|
||||
break;
|
||||
case OPT_CONFIG:
|
||||
config_file_ = optarg;
|
||||
break;
|
||||
case OPT_VBLOCK:
|
||||
is_only_vblock_ = true;
|
||||
break;
|
||||
@@ -206,7 +198,6 @@ void KernelUtility::DescribeSignedImage(void) {
|
||||
}
|
||||
|
||||
bool KernelUtility::GenerateSignedImage(void) {
|
||||
uint64_t len;
|
||||
uint64_t kernel_key_pub_len;
|
||||
image_ = KernelImageNew();
|
||||
|
||||
@@ -230,18 +221,6 @@ bool KernelUtility::GenerateSignedImage(void) {
|
||||
CalculateKernelHeaderChecksum(image_, image_->header_checksum);
|
||||
|
||||
image_->kernel_version = kernel_version_;
|
||||
if (!config_file_.empty()) {
|
||||
kernel_config_ = BufferFromFile(config_file_.c_str(), &len);
|
||||
if (len >= sizeof(image_->kernel_config)) {
|
||||
cerr << "Input kernel config file is too big!";
|
||||
return false;
|
||||
}
|
||||
Memcpy(image_->kernel_config,
|
||||
kernel_config_, len);
|
||||
} else {
|
||||
Memset(image_->kernel_config, 0,
|
||||
sizeof(image_->kernel_config));
|
||||
}
|
||||
image_->kernel_data = BufferFromFile(in_file_.c_str(),
|
||||
&image_->kernel_len);
|
||||
if (!image_->kernel_data)
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#define KERNEL_MAGIC "CHROMEOS"
|
||||
#define KERNEL_MAGIC_SIZE 8
|
||||
#define KERNEL_CONFIG_SIZE 4096
|
||||
|
||||
#define DEV_MODE_ENABLED 1
|
||||
#define DEV_MODE_DISABLED 0
|
||||
@@ -41,7 +40,7 @@ typedef struct KernelImage {
|
||||
* firmware_sign_algorithm,
|
||||
* sign_algorithm, sign_key,
|
||||
* key_version] */
|
||||
|
||||
/* End of kernel key header. */
|
||||
uint8_t* kernel_key_signature; /* Signature of the header above. */
|
||||
|
||||
/* Kernel preamble */
|
||||
@@ -49,18 +48,16 @@ typedef struct KernelImage {
|
||||
uint64_t kernel_len; /* Length of the actual kernel image. */
|
||||
uint64_t bootloader_offset; /* Offset of bootloader in kernel_data. */
|
||||
uint64_t bootloader_size; /* Size of bootloader in bytes. */
|
||||
uint8_t* config_signature; /* Signature on the concatenation of
|
||||
* [kernel_version], [kernel_len] and
|
||||
* [kernel_config]. */
|
||||
uint64_t padded_header_size; /* start of kernel_data in disk partition */
|
||||
/* end of preamble */
|
||||
|
||||
uint8_t* preamble_signature; /* Signature on the kernel preamble. */
|
||||
|
||||
/* 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], [kernel_len], [kernel_config]
|
||||
* and [kernel_data]. */
|
||||
/* The kernel config string is stored right before the kernel image data for
|
||||
* easy mapping while loading into the memory. */
|
||||
uint8_t kernel_config[KERNEL_CONFIG_SIZE]; /* Kernel Config command line. */
|
||||
* the kernel preamble and [kernel_data]. */
|
||||
uint8_t* kernel_data; /* Actual kernel data. */
|
||||
|
||||
} KernelImage;
|
||||
@@ -70,50 +67,52 @@ typedef struct KernelImage {
|
||||
#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_PREAMBLE_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];
|
||||
|
||||
/* Returns the length of the verified boot kernel preamble. */
|
||||
uint64_t GetKernelPreambleLen(void);
|
||||
|
||||
/* Returns the length of the Kernel Verified Boot header excluding
|
||||
* [kernel_config] and [kernel_data].
|
||||
* [kernel_data].
|
||||
*
|
||||
* This is always non-zero, so a return value of 0 signifies an error.
|
||||
*/
|
||||
uint64_t GetVBlockHeaderSize(const uint8_t* vkernel_blob);
|
||||
|
||||
/* 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
|
||||
/* Checks for the sanity of the kernel key header at [kernel_header_blob].
|
||||
* If [dev_mode] is enabled, also checks the kernel key signature using the
|
||||
* pre-processed public firmware signing key [firmware_sign_key_blob].
|
||||
*
|
||||
* On success, put firmware signature algorithm in [firmware_algorithm],
|
||||
* On success, puts 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);
|
||||
int VerifyKernelKeyHeader(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].
|
||||
/* Checks the kernel preamble signature at [kernel_preamble_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);
|
||||
int VerifyKernelPreamble(RSAPublicKey* kernel_sign_key,
|
||||
const uint8_t* kernel_preamble_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
|
||||
* 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].
|
||||
*
|
||||
@@ -125,13 +124,35 @@ int VerifyKernelData(RSAPublicKey* kernel_sign_key,
|
||||
uint64_t kernel_len,
|
||||
int algorithm);
|
||||
|
||||
/* Verifies the kernel key header and preamble at [kernel_header_blob]
|
||||
* using the firmware public key [firmware_key_blob]. If [dev_mode] is 1
|
||||
* (active), then key header verification is skipped.
|
||||
*
|
||||
* Fills in a pointer to preamble blob within [kernel_header_blob] in
|
||||
* [preamble_blob], pointer to expected kernel data signature
|
||||
* within [kernel_header_blob] in [expected_kernel_signature].
|
||||
*
|
||||
* The signing key to use for kernel data verification is returned in
|
||||
* [kernel_sign_key], This must be free-d explicitly by the caller after use.
|
||||
* The kernel signing algorithm is returned in [kernel_sign_algorithm] and its
|
||||
* length in [kernel_len].
|
||||
*
|
||||
* Returns 0 on success, error code on failure.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* 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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
* 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))) {
|
||||
|
||||
@@ -29,10 +29,7 @@ KernelImage* KernelImageNew(void) {
|
||||
if (image) {
|
||||
image->kernel_sign_key = NULL;
|
||||
image->kernel_key_signature = NULL;
|
||||
Memset(image->kernel_config,
|
||||
0,
|
||||
sizeof(image->kernel_config));
|
||||
image->config_signature = NULL;
|
||||
image->preamble_signature = NULL;
|
||||
image->kernel_signature = NULL;
|
||||
image->kernel_data = NULL;
|
||||
}
|
||||
@@ -43,7 +40,7 @@ void KernelImageFree(KernelImage* image) {
|
||||
if (image) {
|
||||
Free(image->kernel_sign_key);
|
||||
Free(image->kernel_key_signature);
|
||||
Free(image->config_signature);
|
||||
Free(image->preamble_signature);
|
||||
Free(image->kernel_signature);
|
||||
Free(image->kernel_data);
|
||||
Free(image);
|
||||
@@ -136,18 +133,21 @@ KernelImage* ReadKernelImage(const char* input_file) {
|
||||
StatefulMemcpy(&st, image->kernel_key_signature,
|
||||
kernel_key_signature_len);
|
||||
|
||||
/* Read the kernel config. */
|
||||
/* Read the kernel preamble. */
|
||||
StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
|
||||
StatefulMemcpy(&st, &image->kernel_len, FIELD_LEN(kernel_len));
|
||||
StatefulMemcpy(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset));
|
||||
StatefulMemcpy(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
|
||||
StatefulMemcpy(&st, &image->padded_header_size,
|
||||
FIELD_LEN(padded_header_size));
|
||||
|
||||
/* Read config and kernel signatures. */
|
||||
image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
|
||||
StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
|
||||
image->preamble_signature = (uint8_t*) Malloc(kernel_signature_len);
|
||||
StatefulMemcpy(&st, image->preamble_signature, kernel_signature_len);
|
||||
image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
|
||||
StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
|
||||
|
||||
/* Read kernel config command line and kernel image data. */
|
||||
StatefulMemcpy(&st, image->kernel_config, FIELD_LEN(kernel_config));
|
||||
/* Read kernel image data. */
|
||||
image->kernel_data = (uint8_t*) Malloc(image->kernel_len);
|
||||
StatefulMemcpy(&st, image->kernel_data, image->kernel_len);
|
||||
|
||||
@@ -218,30 +218,27 @@ uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
|
||||
return header_blob;
|
||||
}
|
||||
|
||||
int GetKernelConfigLen(const KernelImage* image) {
|
||||
return (FIELD_LEN(kernel_version) +
|
||||
FIELD_LEN(kernel_len) +
|
||||
FIELD_LEN(kernel_config));
|
||||
}
|
||||
|
||||
uint8_t* GetKernelConfigBlob(const KernelImage* image) {
|
||||
uint8_t* config_blob = NULL;
|
||||
uint8_t* GetKernelPreambleBlob(const KernelImage* image) {
|
||||
uint8_t* preamble_blob = NULL;
|
||||
MemcpyState st;
|
||||
|
||||
config_blob = (uint8_t*) Malloc(GetKernelConfigLen(image));
|
||||
st.remaining_len = GetKernelConfigLen(image);
|
||||
st.remaining_buf = config_blob;
|
||||
preamble_blob = (uint8_t*) Malloc(GetKernelPreambleLen());
|
||||
st.remaining_len = GetKernelPreambleLen();
|
||||
st.remaining_buf = preamble_blob;
|
||||
st.overrun = 0;
|
||||
|
||||
StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
|
||||
StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len));
|
||||
StatefulMemcpy_r(&st, image->kernel_config, FIELD_LEN(kernel_config));
|
||||
StatefulMemcpy_r(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset));
|
||||
StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
|
||||
StatefulMemcpy_r(&st, &image->padded_header_size,
|
||||
FIELD_LEN(padded_header_size));
|
||||
|
||||
if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */
|
||||
Free(config_blob);
|
||||
Free(preamble_blob);
|
||||
return NULL;
|
||||
}
|
||||
return config_blob;
|
||||
return preamble_blob;
|
||||
}
|
||||
|
||||
uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
|
||||
@@ -258,7 +255,7 @@ uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
|
||||
*blob_len = (FIELD_LEN(magic) +
|
||||
GetKernelHeaderLen(image) +
|
||||
kernel_key_signature_len +
|
||||
GetKernelConfigLen(image) +
|
||||
GetKernelPreambleLen() +
|
||||
2 * kernel_signature_len +
|
||||
image->kernel_len);
|
||||
kernel_blob = (uint8_t*) Malloc(*blob_len);
|
||||
@@ -271,12 +268,16 @@ uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
|
||||
StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
|
||||
StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
|
||||
StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
|
||||
/* Copy over kernel config blob (including signatures.) */
|
||||
/* Copy over kernel preamble blob (including signatures.) */
|
||||
StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
|
||||
StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len));
|
||||
StatefulMemcpy_r(&st, image->config_signature, kernel_signature_len);
|
||||
StatefulMemcpy_r(&st, &image->bootloader_offset,
|
||||
FIELD_LEN(bootloader_offset));
|
||||
StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
|
||||
StatefulMemcpy_r(&st, &image->padded_header_size,
|
||||
FIELD_LEN(padded_header_size));
|
||||
StatefulMemcpy_r(&st, image->preamble_signature, kernel_signature_len);
|
||||
StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
|
||||
StatefulMemcpy_r(&st, image->kernel_config, FIELD_LEN(kernel_config));
|
||||
StatefulMemcpy_r(&st, image->kernel_data, image->kernel_len);
|
||||
|
||||
Free(header_blob);
|
||||
@@ -315,9 +316,8 @@ int WriteKernelImage(const char* input_file,
|
||||
success = 0;
|
||||
}
|
||||
} else {
|
||||
/* Exclude kernel_config and kernel_data. */
|
||||
int vblock_len = blob_len - (image->kernel_len +
|
||||
sizeof(image->kernel_config));
|
||||
/* Exclude kernel_data. */
|
||||
int vblock_len = blob_len - (image->kernel_len);
|
||||
if (vblock_len != write(fd, kernel_blob, vblock_len)) {
|
||||
debug("Couldn't write Kernel Image Verification block to file: %s\n",
|
||||
input_file);
|
||||
@@ -347,11 +347,15 @@ void PrintKernelImage(const KernelImage* image) {
|
||||
/* TODO(gauravsh): Output hash and key signature here? */
|
||||
/* Print preamble. */
|
||||
printf("Kernel Version = %d\n"
|
||||
"Kernel Config command line = \"%s\"\n"
|
||||
"kernel Length = %" PRId64 "\n",
|
||||
"kernel Length = %" PRId64 "\n"
|
||||
"Bootloader Offset = %" PRId64 "\n"
|
||||
"Bootloader Size = %" PRId64 "\n"
|
||||
"Padded Header Size = %" PRId64 "\n",
|
||||
image->kernel_version,
|
||||
image->kernel_config,
|
||||
image->kernel_len);
|
||||
image->kernel_len,
|
||||
image->bootloader_offset,
|
||||
image->bootloader_size,
|
||||
image->padded_header_size);
|
||||
/* TODO(gauravsh): Output kernel signature here? */
|
||||
}
|
||||
|
||||
@@ -361,7 +365,7 @@ int VerifyKernelImage(const RSAPublicKey* firmware_key,
|
||||
const int dev_mode) {
|
||||
RSAPublicKey* kernel_sign_key = NULL;
|
||||
uint8_t* header_digest = NULL;
|
||||
uint8_t* config_digest = NULL;
|
||||
uint8_t* preamble_digest = NULL;
|
||||
uint8_t* kernel_digest = NULL;
|
||||
int kernel_sign_key_size;
|
||||
int kernel_signature_size;
|
||||
@@ -417,19 +421,23 @@ int VerifyKernelImage(const RSAPublicKey* firmware_key,
|
||||
kernel_sign_key_size);
|
||||
kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
|
||||
|
||||
/* Verify kernel config signature. */
|
||||
/* Verify kernel preamble signature. */
|
||||
DigestInit(&ctx, image->kernel_sign_algorithm);
|
||||
DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
|
||||
FIELD_LEN(kernel_version));
|
||||
DigestUpdate(&ctx, (uint8_t*) &image->kernel_len,
|
||||
FIELD_LEN(kernel_len));
|
||||
DigestUpdate(&ctx, (uint8_t*) image->kernel_config,
|
||||
FIELD_LEN(kernel_config));
|
||||
config_digest = DigestFinal(&ctx);
|
||||
if (!RSAVerify(kernel_sign_key, image->config_signature,
|
||||
DigestUpdate(&ctx, (uint8_t*) &image->bootloader_offset,
|
||||
FIELD_LEN(bootloader_offset));
|
||||
DigestUpdate(&ctx, (uint8_t*) &image->bootloader_size,
|
||||
FIELD_LEN(bootloader_size));
|
||||
DigestUpdate(&ctx, (uint8_t*) &image->padded_header_size,
|
||||
FIELD_LEN(padded_header_size));
|
||||
preamble_digest = DigestFinal(&ctx);
|
||||
if (!RSAVerify(kernel_sign_key, image->preamble_signature,
|
||||
kernel_signature_size, image->kernel_sign_algorithm,
|
||||
config_digest)) {
|
||||
error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
|
||||
preamble_digest)) {
|
||||
error_code = VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED;
|
||||
goto verify_failure;
|
||||
}
|
||||
|
||||
@@ -440,9 +448,14 @@ int VerifyKernelImage(const RSAPublicKey* firmware_key,
|
||||
FIELD_LEN(kernel_version));
|
||||
DigestUpdate(&kernel_ctx, (uint8_t*) &image->kernel_len,
|
||||
FIELD_LEN(kernel_len));
|
||||
DigestUpdate(&kernel_ctx, (uint8_t*) image->kernel_config,
|
||||
FIELD_LEN(kernel_config));
|
||||
DigestUpdate(&kernel_ctx, image->kernel_data, image->kernel_len);
|
||||
DigestUpdate(&kernel_ctx, (uint8_t*) &image->bootloader_offset,
|
||||
FIELD_LEN(bootloader_offset));
|
||||
DigestUpdate(&kernel_ctx, (uint8_t*) &image->bootloader_size,
|
||||
FIELD_LEN(bootloader_size));
|
||||
DigestUpdate(&kernel_ctx, (uint8_t*) &image->padded_header_size,
|
||||
FIELD_LEN(padded_header_size));
|
||||
DigestUpdate(&kernel_ctx, (uint8_t*) image->kernel_data,
|
||||
image->kernel_len);
|
||||
kernel_digest = DigestFinal(&kernel_ctx);
|
||||
if (!RSAVerify(kernel_sign_key, image->kernel_signature,
|
||||
kernel_signature_size, image->kernel_sign_algorithm,
|
||||
@@ -454,7 +467,7 @@ int VerifyKernelImage(const RSAPublicKey* firmware_key,
|
||||
verify_failure:
|
||||
RSAPublicKeyFree(kernel_sign_key);
|
||||
Free(kernel_digest);
|
||||
Free(config_digest);
|
||||
Free(preamble_digest);
|
||||
Free(header_digest);
|
||||
return error_code;
|
||||
}
|
||||
@@ -488,38 +501,38 @@ int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
|
||||
|
||||
int AddKernelSignature(KernelImage* image,
|
||||
const char* kernel_signing_key_file) {
|
||||
uint8_t* config_blob = NULL;
|
||||
uint8_t* config_signature = NULL;
|
||||
uint8_t* preamble_blob = NULL;
|
||||
uint8_t* preamble_signature = NULL;
|
||||
uint8_t* kernel_signature = NULL;
|
||||
uint8_t* kernel_buf;
|
||||
int signature_len = siglen_map[image->kernel_sign_algorithm];
|
||||
|
||||
config_blob = GetKernelConfigBlob(image);
|
||||
if (!(config_signature = SignatureBuf(config_blob,
|
||||
GetKernelConfigLen(image),
|
||||
kernel_signing_key_file,
|
||||
image->kernel_sign_algorithm))) {
|
||||
debug("Could not compute signature on the kernel config.\n");
|
||||
Free(config_blob);
|
||||
preamble_blob = GetKernelPreambleBlob(image);
|
||||
if (!(preamble_signature = SignatureBuf(preamble_blob,
|
||||
GetKernelPreambleLen(),
|
||||
kernel_signing_key_file,
|
||||
image->kernel_sign_algorithm))) {
|
||||
debug("Could not compute signature on the kernel preamble.\n");
|
||||
Free(preamble_blob);
|
||||
return 0;
|
||||
}
|
||||
|
||||
image->config_signature = (uint8_t*) Malloc(signature_len);
|
||||
Memcpy(image->config_signature, config_signature, signature_len);
|
||||
Free(config_signature);
|
||||
image->preamble_signature = (uint8_t*) Malloc(signature_len);
|
||||
Memcpy(image->preamble_signature, preamble_signature, signature_len);
|
||||
Free(preamble_signature);
|
||||
/* Kernel signature muse be calculated on the kernel version, options and
|
||||
* kernel data to avoid splicing attacks. */
|
||||
kernel_buf = (uint8_t*) Malloc(GetKernelConfigLen(image) +
|
||||
kernel_buf = (uint8_t*) Malloc(GetKernelPreambleLen() +
|
||||
image->kernel_len);
|
||||
Memcpy(kernel_buf, config_blob, GetKernelConfigLen(image));
|
||||
Memcpy(kernel_buf + GetKernelConfigLen(image), image->kernel_data,
|
||||
Memcpy(kernel_buf, preamble_blob, GetKernelPreambleLen());
|
||||
Memcpy(kernel_buf + GetKernelPreambleLen(), image->kernel_data,
|
||||
image->kernel_len);
|
||||
if (!(kernel_signature = SignatureBuf(kernel_buf,
|
||||
GetKernelConfigLen(image) +
|
||||
GetKernelPreambleLen() +
|
||||
image->kernel_len,
|
||||
kernel_signing_key_file,
|
||||
image->kernel_sign_algorithm))) {
|
||||
Free(config_blob);
|
||||
Free(preamble_blob);
|
||||
Free(kernel_buf);
|
||||
debug("Could not compute signature on the kernel.\n");
|
||||
return 0;
|
||||
@@ -528,7 +541,7 @@ int AddKernelSignature(KernelImage* image,
|
||||
Memcpy(image->kernel_signature, kernel_signature, signature_len);
|
||||
Free(kernel_signature);
|
||||
Free(kernel_buf);
|
||||
Free(config_blob);
|
||||
Free(preamble_blob);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user