mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-26 03:05:10 +00:00
VerifyKernelHeader() fills a KernelImage*
Rather than copying individual fields. More suitable for use in LoadKernel(). Added StatefulSkip(), so that fields in the input stream can be skipped more cleanly. Review URL: http://codereview.chromium.org/2327001
This commit is contained in:
@@ -125,30 +125,29 @@ int VerifyKernelData(RSAPublicKey* kernel_sign_key,
|
|||||||
* using the firmware public key [firmware_key_blob]. If [dev_mode] is 1
|
* using the firmware public key [firmware_key_blob]. If [dev_mode] is 1
|
||||||
* (active), then key header verification is skipped.
|
* (active), then key header verification is skipped.
|
||||||
*
|
*
|
||||||
* Fills in a pointer to expected kernel data signature
|
* On success, fills in the fields of image with the kernel header and
|
||||||
* within [kernel_header_blob] in [expected_kernel_signature].
|
* preamble fields.
|
||||||
|
*
|
||||||
|
* Note that pointers in the image point directly into the input
|
||||||
|
* kernel_header_blob. image->kernel_data is set to NULL, since it's not
|
||||||
|
* part of the header and preamble data itself.
|
||||||
*
|
*
|
||||||
* The signing key to use for kernel data verification is returned in
|
* 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.
|
* [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.
|
* Returns 0 on success, error code on failure.
|
||||||
*/
|
*/
|
||||||
int VerifyKernelHeader(const uint8_t* firmware_key_blob,
|
int VerifyKernelHeader(const uint8_t* firmware_key_blob,
|
||||||
const uint8_t* kernel_header_blob,
|
const uint8_t* kernel_header_blob,
|
||||||
|
uint64_t kernel_header_blob_len,
|
||||||
const int dev_mode,
|
const int dev_mode,
|
||||||
const uint8_t** expected_kernel_signature,
|
KernelImage *image,
|
||||||
RSAPublicKey** kernel_sign_key,
|
RSAPublicKey** kernel_sign_key);
|
||||||
int* kernel_sign_algorithm,
|
|
||||||
uint64_t* kernel_len);
|
|
||||||
|
|
||||||
/* Performs a chained verify of the kernel blob [kernel_blob]. If
|
/* Performs a chained verify of the kernel blob [kernel_blob]. If
|
||||||
* [dev_mode] is 0 [inactive], then the pre-processed public signing key
|
* [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,
|
* [root_key_blob] is used to verify the signature of the signing key,
|
||||||
* else the check is skipped.
|
* else the check is skipped.
|
||||||
*
|
|
||||||
*
|
|
||||||
* Returns 0 on success, error code on failure.
|
* Returns 0 on success, error code on failure.
|
||||||
*
|
*
|
||||||
* NOTE: The length of the kernel blob is derived from reading the fields
|
* NOTE: The length of the kernel blob is derived from reading the fields
|
||||||
|
|||||||
@@ -22,6 +22,16 @@ typedef struct MemcpyState {
|
|||||||
uint8_t overrun; /* Flag set to 1 when an overrun occurs. */
|
uint8_t overrun; /* Flag set to 1 when an overrun occurs. */
|
||||||
} MemcpyState;
|
} MemcpyState;
|
||||||
|
|
||||||
|
/* Skip [len] bytes only if there's enough data to skip according
|
||||||
|
* to [state].
|
||||||
|
* On success, return a meaningless but non-NULL pointer and updates [state].
|
||||||
|
* On failure, return NULL, set remaining_len in state to -1.
|
||||||
|
*
|
||||||
|
* Useful for iterating through a binary blob to populate a struct. After the
|
||||||
|
* first failure (buffer overrun), successive calls will always fail.
|
||||||
|
*/
|
||||||
|
void* StatefulSkip(MemcpyState* state, uint64_t len);
|
||||||
|
|
||||||
/* Copy [len] bytes into [dst] only if there's enough data to read according
|
/* Copy [len] bytes into [dst] only if there's enough data to read according
|
||||||
* to [state].
|
* to [state].
|
||||||
* On success, return [dst] and update [state].
|
* On success, return [dst] and update [state].
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "cryptolib.h"
|
#include "cryptolib.h"
|
||||||
#include "rollback_index.h"
|
#include "rollback_index.h"
|
||||||
|
#include "stateful_util.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
|
||||||
/* Macro to determine the size of a field structure in the KernelImage
|
/* Macro to determine the size of a field structure in the KernelImage
|
||||||
@@ -187,61 +188,91 @@ int VerifyKernelData(RSAPublicKey* kernel_sign_key,
|
|||||||
|
|
||||||
int VerifyKernelHeader(const uint8_t* firmware_key_blob,
|
int VerifyKernelHeader(const uint8_t* firmware_key_blob,
|
||||||
const uint8_t* kernel_header_blob,
|
const uint8_t* kernel_header_blob,
|
||||||
|
uint64_t kernel_header_blob_len,
|
||||||
const int dev_mode,
|
const int dev_mode,
|
||||||
const uint8_t** expected_kernel_signature,
|
KernelImage *image,
|
||||||
RSAPublicKey** kernel_sign_key,
|
RSAPublicKey** kernel_sign_key) {
|
||||||
int* kernel_sign_algorithm,
|
|
||||||
uint64_t* kernel_len) {
|
|
||||||
int error_code;
|
int error_code;
|
||||||
int firmware_sign_algorithm; /* Firmware signing key algorithm. */
|
int firmware_sign_algorithm; /* Firmware signing key algorithm. */
|
||||||
|
int kernel_sign_algorithm; /* Kernel signing key algorithm. */
|
||||||
int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
|
int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
|
||||||
header_len;
|
header_len;
|
||||||
|
uint64_t kernel_len;
|
||||||
const uint8_t* header_ptr = NULL; /* Pointer to key header. */
|
const uint8_t* header_ptr = NULL; /* Pointer to key header. */
|
||||||
const uint8_t* preamble_ptr = NULL; /* Pointer to start of preamble. */
|
const uint8_t* preamble_ptr = NULL; /* Pointer to start of preamble. */
|
||||||
const uint8_t* kernel_sign_key_ptr = NULL; /* Pointer to signing key. */
|
MemcpyState st;
|
||||||
|
|
||||||
/* Note: All the offset calculations are based on struct FirmwareImage which
|
/* Note: All the offset calculations are based on struct KernelImage which
|
||||||
* is defined in include/firmware_image.h. */
|
* is defined in include/kernel_image_fw.h. */
|
||||||
|
st.remaining_buf = (void *)kernel_header_blob;
|
||||||
|
st.remaining_len = kernel_header_blob_len;
|
||||||
|
st.overrun = 0;
|
||||||
|
|
||||||
/* Compare magic bytes. */
|
/* Clear destination image struct */
|
||||||
if (SafeMemcmp(kernel_header_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE))
|
Memset(image, 0, sizeof(KernelImage));
|
||||||
|
|
||||||
|
/* Read and compare magic bytes. */
|
||||||
|
StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
|
||||||
|
if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
|
||||||
return VERIFY_KERNEL_WRONG_MAGIC;
|
return VERIFY_KERNEL_WRONG_MAGIC;
|
||||||
|
}
|
||||||
|
StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version));
|
||||||
|
StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len));
|
||||||
|
StatefulMemcpy(&st, &image->firmware_sign_algorithm,
|
||||||
|
FIELD_LEN(firmware_sign_algorithm));
|
||||||
|
StatefulMemcpy(&st, &image->kernel_sign_algorithm,
|
||||||
|
FIELD_LEN(kernel_sign_algorithm));
|
||||||
|
|
||||||
header_ptr = kernel_header_blob + KERNEL_MAGIC_SIZE;
|
header_ptr = kernel_header_blob + KERNEL_MAGIC_SIZE;
|
||||||
|
|
||||||
/* Only continue if header verification succeeds. */
|
/* Only continue if header verification succeeds. */
|
||||||
if ((error_code = VerifyKernelKeyHeader(firmware_key_blob, header_ptr,
|
if ((error_code = VerifyKernelKeyHeader(firmware_key_blob, header_ptr,
|
||||||
dev_mode,
|
dev_mode,
|
||||||
&firmware_sign_algorithm,
|
&firmware_sign_algorithm,
|
||||||
kernel_sign_algorithm,
|
&kernel_sign_algorithm,
|
||||||
&header_len))) {
|
&header_len))) {
|
||||||
debug("VerifyKernelHeader: Kernel Key Header verification failed.\n");
|
debug("VerifyKernelHeader: Kernel Key Header verification failed.\n");
|
||||||
return error_code; /* AKA jump to recovery. */
|
return error_code; /* AKA jump to recovery. */
|
||||||
}
|
}
|
||||||
/* Parse signing key into RSAPublicKey structure since it is required multiple
|
|
||||||
* times. */
|
/* Read pre-processed public half of the kernel signing key. */
|
||||||
kernel_sign_key_len = RSAProcessedKeySize(*kernel_sign_algorithm);
|
kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
|
||||||
kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
|
StatefulMemcpy(&st, &image->kernel_key_version,
|
||||||
FIELD_LEN(header_len) +
|
FIELD_LEN(kernel_key_version));
|
||||||
FIELD_LEN(firmware_sign_algorithm) +
|
image->kernel_sign_key = (uint8_t*)st.remaining_buf;
|
||||||
FIELD_LEN(kernel_sign_algorithm) +
|
StatefulSkip(&st, kernel_sign_key_len);
|
||||||
FIELD_LEN(kernel_key_version));
|
StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
|
||||||
*kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
|
|
||||||
|
/* Parse signing key into RSAPublicKey structure since it is
|
||||||
|
* required multiple times. */
|
||||||
|
*kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
|
||||||
kernel_sign_key_len);
|
kernel_sign_key_len);
|
||||||
kernel_signature_len = siglen_map[*kernel_sign_algorithm];
|
kernel_signature_len = siglen_map[kernel_sign_algorithm];
|
||||||
kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
|
kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
|
||||||
|
image->kernel_key_signature = (uint8_t*)st.remaining_buf;
|
||||||
|
StatefulSkip(&st, kernel_signature_len);
|
||||||
|
|
||||||
/* Only continue if preamble verification succeeds. */
|
/* Only continue if preamble verification succeeds. */
|
||||||
preamble_ptr = (header_ptr + header_len + kernel_key_signature_len);
|
/* TODO: should pass the remaining len into VerifyKernelPreamble() */
|
||||||
|
preamble_ptr = (const uint8_t*)st.remaining_buf;
|
||||||
if ((error_code = VerifyKernelPreamble(*kernel_sign_key, preamble_ptr,
|
if ((error_code = VerifyKernelPreamble(*kernel_sign_key, preamble_ptr,
|
||||||
*kernel_sign_algorithm,
|
kernel_sign_algorithm,
|
||||||
kernel_len))) {
|
&kernel_len))) {
|
||||||
RSAPublicKeyFree(*kernel_sign_key);
|
RSAPublicKeyFree(*kernel_sign_key);
|
||||||
return error_code; /* AKA jump to recovery. */
|
return error_code; /* AKA jump to recovery. */
|
||||||
}
|
}
|
||||||
*expected_kernel_signature = (preamble_ptr +
|
|
||||||
GetKernelPreambleLen(*kernel_sign_algorithm) -
|
/* Copy preamble fields */
|
||||||
kernel_signature_len); /* Skip beginning of
|
StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
|
||||||
* preamble. */
|
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));
|
||||||
|
image->kernel_signature = (uint8_t*)st.remaining_buf;
|
||||||
|
StatefulSkip(&st, kernel_signature_len);
|
||||||
|
image->preamble_signature = (uint8_t*)st.remaining_buf;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,18 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void* StatefulSkip(MemcpyState* state, uint64_t len) {
|
||||||
|
if (state->overrun)
|
||||||
|
return NULL;
|
||||||
|
if (len > state->remaining_len) {
|
||||||
|
state->overrun = 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
state->remaining_buf += len;
|
||||||
|
state->remaining_len -= len;
|
||||||
|
return state; // have to return something non-NULL
|
||||||
|
}
|
||||||
|
|
||||||
void* StatefulMemcpy(MemcpyState* state, void* dst,
|
void* StatefulMemcpy(MemcpyState* state, void* dst,
|
||||||
uint64_t len) {
|
uint64_t len) {
|
||||||
if (state->overrun)
|
if (state->overrun)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ int main(void)
|
|||||||
VerifyKernelKeyHeader(0, 0, 0, 0, 0, 0);
|
VerifyKernelKeyHeader(0, 0, 0, 0, 0, 0);
|
||||||
VerifyKernelPreamble(0, 0, 0, 0);
|
VerifyKernelPreamble(0, 0, 0, 0);
|
||||||
VerifyKernelData(0, 0, 0, 0, 0);
|
VerifyKernelData(0, 0, 0, 0, 0);
|
||||||
VerifyKernelHeader(0, 0, 0, 0, 0, 0, 0);
|
VerifyKernelHeader(0, 0, 0, 0, 0, 0);
|
||||||
VerifyKernel(0, 0, 0);
|
VerifyKernel(0, 0, 0);
|
||||||
GetLogicalKernelVersion(0);
|
GetLogicalKernelVersion(0);
|
||||||
VerifyKernelDriver_f(0, 0, 0, 0);
|
VerifyKernelDriver_f(0, 0, 0, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user