VBoot Reference: Make kernel_config a 4K byte block, and move it after the verified boot block.
The kernel_config is now stored as a 4K binary block instead of the kconfig_options structure that was being used before. Since the verified boot code doesn't care what kernel config options are (other than the length of the kernel image and for verifying them before the rest of kernel), it is ok to keep them as a blackbox.
This CL also changes the verified boot kernel layout - VBlock Data followed by Kernel Config followed by the Kernel Image. This will allow them to be stored separately, or as a concatenated block (for easy memory mapping during kernel load). This should ease the process of generating a layout for verified boot kernel images which is also compatible with legacy BIOSes that don't support this mechanism.
Finally, there is also a new firmware API function to determine the size of a kernel verified boot block, given a pointer to its beginning (for determining the offset to the kernel config and data).
Review URL: http://codereview.chromium.org/1732022
diff --git a/tests/kernel_image_tests.c b/tests/kernel_image_tests.c
index eee0417..15f75bd 100644
--- a/tests/kernel_image_tests.c
+++ b/tests/kernel_image_tests.c
@@ -40,14 +40,14 @@
/* Tampered KernelImage Verification Tests. */
void VerifyKernelImageTamperTest(KernelImage* image,
RSAPublicKey* firmware_key) {
- image->options.kernel_load_addr = 0xFFFF;
+ image->kernel_config[0] ^= 0xFF;
TEST_EQ(VerifyKernelImage(firmware_key, image, DEV_MODE_ENABLED),
VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED,
"KernelImage Config Tamper Verification (Dev Mode)");
TEST_EQ(VerifyKernelImage(firmware_key, image, DEV_MODE_DISABLED),
VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED,
"KernelImage Config Tamper Verification (Trusted)");
- image->options.kernel_load_addr = 0;
+ image->kernel_config[0] ^= 0xFF;
image->kernel_data[0] = 'T';
TEST_EQ(VerifyKernelImage(firmware_key, image, DEV_MODE_ENABLED),
diff --git a/tests/kernel_splicing_tests.c b/tests/kernel_splicing_tests.c
index d4c9bb5..9335d93 100644
--- a/tests/kernel_splicing_tests.c
+++ b/tests/kernel_splicing_tests.c
@@ -63,7 +63,7 @@
Memcpy(image2->kernel_signature, image1->kernel_signature,
siglen_map[0]);
Memcpy(image2->kernel_data, image1->kernel_data,
- image2->options.kernel_len);
+ image2->kernel_len);
TEST_EQ(VerifyKernelImage(firmware_key, image2, 0),
VERIFY_KERNEL_SIGNATURE_FAILED,
diff --git a/tests/test_common.c b/tests/test_common.c
index 6f68d35..6027a89 100644
--- a/tests/test_common.c
+++ b/tests/test_common.c
@@ -160,12 +160,8 @@
/* Populate kernel options and data with dummy data. */
image->kernel_version = kernel_version;
- image->options.version[0] = 1;
- image->options.version[1] = 0;
- Memset(image->options.cmd_line, 0, sizeof(image->options.cmd_line));
- image->options.kernel_len = kernel_len;
- image->options.kernel_load_addr = 0;
- image->options.kernel_entry_addr = 0;
+ Memset(image->kernel_config, 0, sizeof(image->kernel_config));
+ image->kernel_len = kernel_len;
image->kernel_key_signature = image->kernel_signature = NULL;
image->kernel_data = Malloc(kernel_len);
Memset(image->kernel_data, kernel_data_fill_char, kernel_len);
@@ -237,7 +233,7 @@
return NULL;
if (is_corrupt) {
/* Invalidate image. */
- Memset(image->kernel_data, 'X', image->options.kernel_len);
+ Memset(image->kernel_data, 'X', image->kernel_len);
}
kernel_blob = GetKernelBlob(image, &len);
KernelImageFree(image);
diff --git a/utility/include/kernel_utility.h b/utility/include/kernel_utility.h
index 49290f2..16967ad 100644
--- a/utility/include/kernel_utility.h
+++ b/utility/include/kernel_utility.h
@@ -70,8 +70,8 @@
int kernel_sign_algorithm_;
int kernel_key_version_;
int kernel_version_;
- kconfig_options options_;
- uint8_t* cmd_line_;
+ uint64_t kernel_len_;
+ uint8_t* kernel_config_;
std::string in_file_;
std::string out_file_;
diff --git a/utility/kernel_utility.cc b/utility/kernel_utility.cc
index 8957891..f7ce214 100644
--- a/utility/kernel_utility.cc
+++ b/utility/kernel_utility.cc
@@ -35,21 +35,16 @@
kernel_sign_algorithm_(-1),
kernel_key_version_(-1),
kernel_version_(-1),
- cmd_line_(NULL),
+ kernel_len_(0),
+ kernel_config_(NULL),
is_generate_(false),
is_verify_(false),
is_describe_(false),
is_only_vblock_(false) {
- // Populate kernel config options with defaults.
- options_.version[0] = 1;
- options_.version[1] = 0;
- options_.kernel_len = 0;
- options_.kernel_load_addr = 0;
- options_.kernel_entry_addr = 0;
}
KernelUtility::~KernelUtility() {
- Free(cmd_line_);
+ Free(kernel_config_);
RSAPublicKeyFree(firmware_key_pub_);
KernelImageFree(image_);
}
@@ -76,9 +71,6 @@
"--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"
- "--config_version <version>\n"
- "--kernel_load_addr <addr>\n"
- "--kernel_entry_addr <addr>\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++) {
@@ -102,9 +94,6 @@
{"out", 1, 0, 0},
{"generate", 0, 0, 0},
{"verify", 0, 0, 0},
- {"config_version", 1, 0, 0},
- {"kernel_load_addr", 1, 0, 0},
- {"kernel_entry_addr", 1, 0, 0},
{"describe", 0, 0, 0},
{"config", 1, 0, 0},
{"vblock", 0, 0, 0},
@@ -171,32 +160,13 @@
case 11: // verify
is_verify_ = true;
break;
- case 12: // config_version
- if (2 != sscanf(optarg, "%d.%d", &options_.version[0],
- &options_.version[1]))
- return false;
- break;
- case 13: // kernel_load_addr
- errno = 0;
- options_.kernel_load_addr =
- strtol(optarg, reinterpret_cast<char**>(NULL), 10);
- if (errno)
- return false;
- break;
- case 14: // kernel_entry_addr
- errno = 0;
- options_.kernel_entry_addr =
- strtol(optarg, reinterpret_cast<char**>(NULL), 10);
- if (errno)
- return false;
- break;
- case 15: // describe
+ case 12: // describe
is_describe_ = true;
break;
- case 16: // config
+ case 13: // config
config_file_ = optarg;
break;
- case 17: // vblock
+ case 14: // vblock
is_only_vblock_ = true;
break;
}
@@ -248,22 +218,20 @@
CalculateKernelHeaderChecksum(image_, image_->header_checksum);
image_->kernel_version = kernel_version_;
- image_->options.version[0] = options_.version[0];
- image_->options.version[1] = options_.version[1];
if (!config_file_.empty()) {
- cmd_line_ = BufferFromFile(config_file_.c_str(), &len);
- if (len >= sizeof(image_->options.cmd_line)) {
+ 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_->options.cmd_line, cmd_line_, len);
+ Memcpy(image_->kernel_config,
+ kernel_config_, len);
} else {
- Memset(image_->options.cmd_line, 0, sizeof(image_->options.cmd_line));
+ Memset(image_->kernel_config, 0,
+ sizeof(image_->kernel_config));
}
- image_->options.kernel_load_addr = options_.kernel_load_addr;
- image_->options.kernel_entry_addr = options_.kernel_entry_addr;
image_->kernel_data = BufferFromFile(in_file_.c_str(),
- &image_->options.kernel_len);
+ &image_->kernel_len);
if (!image_)
return false;
// Generate and add the signatures.
diff --git a/vkernel/include/kernel_image_fw.h b/vkernel/include/kernel_image_fw.h
index 6446e8c..f753e4c 100644
--- a/vkernel/include/kernel_image_fw.h
+++ b/vkernel/include/kernel_image_fw.h
@@ -15,21 +15,11 @@
#define KERNEL_MAGIC "CHROMEOS"
#define KERNEL_MAGIC_SIZE 8
-#define KERNEL_CMD_LINE_SIZE 4096
+#define KERNEL_CONFIG_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 */
@@ -55,16 +45,19 @@
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. */
-
+ uint64_t kernel_len; /* Length of the actual kernel image. */
+ uint8_t* config_signature; /* Signature on the concatenation of
+ * [kernel_version], [kernel_len] and
+ * [kernel_config]. */
/* 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]. */
+ * [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. */
uint8_t* kernel_data; /* Actual kernel data. */
} KernelImage;
@@ -81,6 +74,13 @@
extern char* kVerifyKernelErrors[VERIFY_KERNEL_MAX];
+/* Returns the length of the Kernel Verified Boot header excluding
+ * [kernel_config] and [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
* pre-processed public firmware signing key [firmware_sign_key_blob].
diff --git a/vkernel/kernel_image.c b/vkernel/kernel_image.c
index cc18467..6833ef6 100644
--- a/vkernel/kernel_image.c
+++ b/vkernel/kernel_image.c
@@ -29,7 +29,9 @@
if (image) {
image->kernel_sign_key = NULL;
image->kernel_key_signature = NULL;
- Memset(image->options.cmd_line, 0, sizeof(image->options.cmd_line));
+ Memset(image->kernel_config,
+ 0,
+ sizeof(image->kernel_config));
image->config_signature = NULL;
image->kernel_signature = NULL;
image->kernel_data = NULL;
@@ -136,24 +138,18 @@
/* Read the kernel config. */
StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
- StatefulMemcpy(&st, &image->options.version, FIELD_LEN(options.version));
- StatefulMemcpy(&st, &image->options.cmd_line, FIELD_LEN(options.cmd_line));
- StatefulMemcpy(&st, &image->options.kernel_len,
- FIELD_LEN(options.kernel_len));
- StatefulMemcpy(&st, &image->options.kernel_load_addr,
- FIELD_LEN(options.kernel_load_addr));
- StatefulMemcpy(&st, &image->options.kernel_entry_addr,
- FIELD_LEN(options.kernel_entry_addr));
+ StatefulMemcpy(&st, &image->kernel_len, FIELD_LEN(kernel_len));
- /* Read kernel config signature. */
+ /* Read config and kernel signatures. */
image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
-
image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
- image->kernel_data = (uint8_t*) Malloc(image->options.kernel_len);
- StatefulMemcpy(&st, image->kernel_data, image->options.kernel_len);
+ /* Read kernel config command line and kernel image data. */
+ StatefulMemcpy(&st, image->kernel_config, FIELD_LEN(kernel_config));
+ image->kernel_data = (uint8_t*) Malloc(image->kernel_len);
+ StatefulMemcpy(&st, image->kernel_data, image->kernel_len);
if(st.overrun || st.remaining_len != 0) { /* Overrun or underrun. */
Free(kernel_buf);
@@ -222,31 +218,25 @@
return header_blob;
}
-int GetKernelConfigLen() {
+int GetKernelConfigLen(const KernelImage* image) {
return (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));
+ FIELD_LEN(kernel_len) +
+ FIELD_LEN(kernel_config));
}
uint8_t* GetKernelConfigBlob(const KernelImage* image) {
uint8_t* config_blob = NULL;
MemcpyState st;
- config_blob = (uint8_t*) Malloc(GetKernelConfigLen());
- st.remaining_len = GetKernelConfigLen();
+ config_blob = (uint8_t*) Malloc(GetKernelConfigLen(image));
+ st.remaining_len = GetKernelConfigLen(image);
st.remaining_buf = config_blob;
st.overrun = 0;
StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
- StatefulMemcpy_r(&st, image->options.version, FIELD_LEN(options.version));
- StatefulMemcpy_r(&st, image->options.cmd_line, FIELD_LEN(options.cmd_line));
- StatefulMemcpy_r(&st, &image->options.kernel_len,
- FIELD_LEN(options.kernel_len));
- StatefulMemcpy_r(&st, &image->options.kernel_load_addr,
- FIELD_LEN(options.kernel_load_addr));
- StatefulMemcpy_r(&st, &image->options.kernel_entry_addr,
- FIELD_LEN(options.kernel_entry_addr));
+ StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len));
+ StatefulMemcpy_r(&st, image->kernel_config, FIELD_LEN(kernel_config));
+
if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */
Free(config_blob);
return NULL;
@@ -259,7 +249,6 @@
int kernel_signature_len;
uint8_t* kernel_blob = NULL;
uint8_t* header_blob = NULL;
- uint8_t* config_blob = NULL;
MemcpyState st;
if (!image)
@@ -269,26 +258,27 @@
*blob_len = (FIELD_LEN(magic) +
GetKernelHeaderLen(image) +
kernel_key_signature_len +
- GetKernelConfigLen() +
+ GetKernelConfigLen(image) +
2 * kernel_signature_len +
- image->options.kernel_len);
+ image->kernel_len);
kernel_blob = (uint8_t*) Malloc(*blob_len);
st.remaining_len = *blob_len;
st.remaining_buf = kernel_blob;
st.overrun = 0;
header_blob = GetKernelHeaderBlob(image);
- config_blob = GetKernelConfigBlob(image);
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);
- StatefulMemcpy_r(&st, config_blob, GetKernelConfigLen());
+ /* Copy over kernel config 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->kernel_signature, kernel_signature_len);
- StatefulMemcpy_r(&st, image->kernel_data, image->options.kernel_len);
+ StatefulMemcpy_r(&st, image->kernel_config, FIELD_LEN(kernel_config));
+ StatefulMemcpy_r(&st, image->kernel_data, image->kernel_len);
- Free(config_blob);
Free(header_blob);
if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
@@ -325,8 +315,9 @@
success = 0;
}
} else {
- /* Exclude the kernel_data. */
- int vblock_len = blob_len - image->options.kernel_len;
+ /* Exclude kernel_config and kernel_data. */
+ int vblock_len = blob_len - (image->kernel_len +
+ sizeof(image->kernel_config));
if (vblock_len != write(fd, kernel_blob, vblock_len)) {
debug("Couldn't write Kernel Image Verification block to file: %s\n",
input_file);
@@ -356,17 +347,11 @@
/* TODO(gauravsh): Output hash and key signature here? */
/* Print preamble. */
printf("Kernel Version = %d\n"
- "Kernel Config Version = %d.%d\n"
"Kernel Config command line = \"%s\"\n"
- "kernel Length = %" PRId64 "\n"
- "Kernel Load Address = %" PRId64 "\n"
- "Kernel Entry Address = %" PRId64 "\n\n",
+ "kernel Length = %" PRId64 "\n",
image->kernel_version,
- image->options.version[0], image->options.version[1],
- image->options.cmd_line,
- image->options.kernel_len,
- image->options.kernel_load_addr,
- image->options.kernel_entry_addr);
+ image->kernel_config,
+ image->kernel_len);
/* TODO(gauravsh): Output kernel signature here? */
}
@@ -436,16 +421,10 @@
DigestInit(&ctx, image->kernel_sign_algorithm);
DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
FIELD_LEN(kernel_version));
- DigestUpdate(&ctx, (uint8_t*) image->options.version,
- FIELD_LEN(options.version));
- DigestUpdate(&ctx, (uint8_t*) image->options.cmd_line,
- FIELD_LEN(options.cmd_line));
- DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
- FIELD_LEN(options.kernel_len));
- DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
- FIELD_LEN(options.kernel_load_addr));
- DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
- FIELD_LEN(options.kernel_entry_addr));
+ 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,
kernel_signature_size, image->kernel_sign_algorithm,
@@ -459,17 +438,11 @@
DigestInit(&kernel_ctx, image->kernel_sign_algorithm);
DigestUpdate(&kernel_ctx, (uint8_t*) &image->kernel_version,
FIELD_LEN(kernel_version));
- DigestUpdate(&kernel_ctx, (uint8_t*) image->options.version,
- FIELD_LEN(options.version));
- DigestUpdate(&kernel_ctx, (uint8_t*) image->options.cmd_line,
- FIELD_LEN(options.cmd_line));
- DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_len,
- FIELD_LEN(options.kernel_len));
- DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_load_addr,
- FIELD_LEN(options.kernel_load_addr));
- DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_entry_addr,
- FIELD_LEN(options.kernel_entry_addr));
- DigestUpdate(&kernel_ctx, image->kernel_data, image->options.kernel_len);
+ 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);
kernel_digest = DigestFinal(&kernel_ctx);
if (!RSAVerify(kernel_sign_key, image->kernel_signature,
kernel_signature_size, image->kernel_sign_algorithm,
@@ -523,7 +496,7 @@
config_blob = GetKernelConfigBlob(image);
if (!(config_signature = SignatureBuf(config_blob,
- GetKernelConfigLen(),
+ GetKernelConfigLen(image),
kernel_signing_key_file,
image->kernel_sign_algorithm))) {
debug("Could not compute signature on the kernel config.\n");
@@ -536,14 +509,14 @@
Free(config_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->options.kernel_len);
- Memcpy(kernel_buf, config_blob, GetKernelConfigLen());
- Memcpy(kernel_buf + GetKernelConfigLen(), image->kernel_data,
- image->options.kernel_len);
+ kernel_buf = (uint8_t*) Malloc(GetKernelConfigLen(image) +
+ image->kernel_len);
+ Memcpy(kernel_buf, config_blob, GetKernelConfigLen(image));
+ Memcpy(kernel_buf + GetKernelConfigLen(image), image->kernel_data,
+ image->kernel_len);
if (!(kernel_signature = SignatureBuf(kernel_buf,
- GetKernelConfigLen() +
- image->options.kernel_len,
+ GetKernelConfigLen(image) +
+ image->kernel_len,
kernel_signing_key_file,
image->kernel_sign_algorithm))) {
Free(config_blob);
diff --git a/vkernel/kernel_image_fw.c b/vkernel/kernel_image_fw.c
index 734111c..23111e9 100644
--- a/vkernel/kernel_image_fw.c
+++ b/vkernel/kernel_image_fw.c
@@ -15,11 +15,6 @@
/* Macro to determine the size of a field structure in the KernelImage
* structure. */
#define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field))
-#define KERNEL_CONFIG_FIELD_LEN (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) + \
- FIELD_LEN(options.cmd_line) + \
- FIELD_LEN(options.kernel_len) + \
- FIELD_LEN(options.kernel_load_addr) + \
- FIELD_LEN(options.kernel_entry_addr))
char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = {
"Success.",
@@ -31,6 +26,45 @@
"Wrong Kernel Magic.",
};
+uint64_t GetVblockHeaderSize(const uint8_t* vkernel_blob) {
+ uint64_t len = 0;
+ uint16_t firmware_sign_algorithm;
+ uint16_t kernel_sign_algorithm;
+ int algorithms_offset = (FIELD_LEN(magic) +
+ FIELD_LEN(header_version) +
+ FIELD_LEN(header_len));
+ if (SafeMemcmp(vkernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
+ debug("Not a valid verified boot kernel blob.\n");
+ return 0;
+ }
+ Memcpy(&firmware_sign_algorithm,
+ vkernel_blob + algorithms_offset,
+ sizeof(firmware_sign_algorithm));
+ Memcpy(&kernel_sign_algorithm,
+ vkernel_blob + algorithms_offset + FIELD_LEN(kernel_sign_algorithm),
+ sizeof(kernel_sign_algorithm));
+ if (firmware_sign_algorithm >= kNumAlgorithms) {
+ debug("Invalid firmware signing algorithm.\n");
+ return 0;
+ }
+ if (kernel_sign_algorithm >= kNumAlgorithms) {
+ debug("Invalid kernel signing algorithm.\n");
+ return 0;
+ }
+ len = algorithms_offset; /* magic, header length and version. */
+ len += (FIELD_LEN(firmware_sign_algorithm) +
+ FIELD_LEN(kernel_sign_algorithm) +
+ FIELD_LEN(kernel_key_version) +
+ RSAProcessedKeySize(kernel_sign_algorithm) + /* kernel_sign_key */
+ FIELD_LEN(header_checksum) +
+ siglen_map[firmware_sign_algorithm] + /* kernel_key_signature */
+ FIELD_LEN(kernel_version) +
+ FIELD_LEN(kernel_len) +
+ siglen_map[kernel_sign_algorithm] + /* config_signature */
+ siglen_map[kernel_sign_algorithm]); /* kernel_signature */
+ return len;
+}
+
int VerifyKernelHeader(const uint8_t* firmware_key_blob,
const uint8_t* header_blob,
const int dev_mode,
@@ -116,43 +150,73 @@
const uint8_t* config_blob,
int algorithm,
uint64_t* kernel_len) {
- uint64_t len;
- if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */
- config_blob, /* Data to verify */
- KERNEL_CONFIG_FIELD_LEN, /* Length of data */
- config_blob + KERNEL_CONFIG_FIELD_LEN, /* Expected
- * Signature */
- algorithm))
- return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
+ int signature_len = siglen_map[algorithm];
+ const uint8_t* config_signature = NULL;
+ const uint8_t* kernel_config = NULL;
+ uint8_t* digest = NULL;
+ DigestContext ctx;
- Memcpy(&len,
- config_blob + (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) +
- FIELD_LEN(options.cmd_line)),
- sizeof(len));
- *kernel_len = len;
+ config_signature = config_blob + (FIELD_LEN(kernel_version) +
+ FIELD_LEN(kernel_len));
+ kernel_config = config_signature + 2 * signature_len; /* kernel and config
+ * signature. */
+ /* Since the kernel config signature is computed over the kernel version,
+ * kernel length and config, which does not form a contiguous region memory,
+ * we calculate the message digest ourselves. */
+ DigestInit(&ctx, algorithm);
+ DigestUpdate(&ctx,
+ config_blob,
+ FIELD_LEN(kernel_version) + FIELD_LEN(kernel_len));
+ DigestUpdate(&ctx,
+ kernel_config,
+ FIELD_LEN(kernel_config));
+ digest = DigestFinal(&ctx);
+ if (!RSAVerifyBinaryWithDigest_f(
+ NULL, kernel_sign_key, /* Key to use. */
+ digest, /* Digest of the Data to verify. */
+ config_signature, /* Expected signature. */
+ algorithm)) {
+ Free(digest);
+ return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
+ }
+ Free(digest);
+ Memcpy(kernel_len,
+ config_blob + FIELD_LEN(kernel_version),
+ FIELD_LEN(kernel_len));
return 0;
}
int VerifyKernelData(RSAPublicKey* kernel_sign_key,
- const uint8_t* kernel_config_start,
- const uint8_t* kernel_data_start,
+ const uint8_t* config_blob,
+ const uint8_t* kernel_data,
uint64_t kernel_len,
int algorithm) {
int signature_len = siglen_map[algorithm];
- uint8_t* digest;
+ const uint8_t* kernel_signature = NULL;
+ const uint8_t* kernel_config = NULL;
+ uint8_t* digest = NULL;
DigestContext ctx;
- /* Since the kernel signature is computed over the kernel version, options
- * and data, which does not form a contiguous region of memory, we calculate
- * the message digest ourselves. */
+ kernel_signature = config_blob + (FIELD_LEN(kernel_version) +
+ FIELD_LEN(kernel_len) +
+ signature_len);
+ kernel_config = kernel_signature + signature_len;
+
+ /* Since the kernel signature is computed over the kernel version, length,
+ * config cmd line, and kernel image data, which does not form a contiguous
+ * region of memory, we calculate the message digest ourselves. */
DigestInit(&ctx, algorithm);
- DigestUpdate(&ctx, kernel_config_start, KERNEL_CONFIG_FIELD_LEN);
- DigestUpdate(&ctx, kernel_data_start + signature_len, kernel_len);
+ DigestUpdate(&ctx,
+ config_blob,
+ FIELD_LEN(kernel_version) + FIELD_LEN(kernel_len));
+ DigestUpdate(&ctx, kernel_config,
+ FIELD_LEN(kernel_config));
+ DigestUpdate(&ctx, kernel_data, kernel_len);
digest = DigestFinal(&ctx);
if (!RSAVerifyBinaryWithDigest_f(
NULL, kernel_sign_key, /* Key to use. */
digest, /* Digest of the data to verify. */
- kernel_data_start, /* Expected Signature */
+ kernel_signature, /* Expected Signature */
algorithm)) {
Free(digest);
return VERIFY_KERNEL_SIGNATURE_FAILED;
@@ -214,11 +278,15 @@
}
/* Only continue if kernel data verification succeeds. */
kernel_ptr = (config_ptr +
- KERNEL_CONFIG_FIELD_LEN + /* Skip config block/signature. */
- kernel_signature_len);
+ FIELD_LEN(kernel_version) +
+ FIELD_LEN(kernel_len) +
+ 2 * kernel_signature_len + /* config and kernel signature. */
+ FIELD_LEN(kernel_config));
- if ((error_code = VerifyKernelData(kernel_sign_key, config_ptr, kernel_ptr,
- kernel_len,
+ if ((error_code = VerifyKernelData(kernel_sign_key, /* Verification key */
+ config_ptr, /* Start of config block */
+ kernel_ptr, /* Start of kernel image */
+ kernel_len, /* Length of kernel image. */
kernel_sign_algorithm))) {
RSAPublicKeyFree(kernel_sign_key);
return error_code; /* AKA jump to recovery. */
@@ -248,6 +316,7 @@
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) +