Index: vkernel/kernel_image.c |
diff --git a/vkernel/kernel_image.c b/vkernel/kernel_image.c |
deleted file mode 100644 |
index 392ee1fc344f2dcd8867e55fd947c9d506ca2ee4..0000000000000000000000000000000000000000 |
--- a/vkernel/kernel_image.c |
+++ /dev/null |
@@ -1,754 +0,0 @@ |
-/* 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 generating and manipulating a verified boot kernel image. |
- * (Userland portion) |
- */ |
-#include "kernel_image.h" |
- |
-#include <fcntl.h> |
-#include <stddef.h> |
-#include <stdio.h> |
-#include <sys/types.h> |
-#include <sys/stat.h> |
-#include <unistd.h> |
- |
-#include "cryptolib.h" |
-#include "file_keys.h" |
-#include "kernel_blob.h" |
-#include "rollback_index.h" |
-#include "signature_digest.h" |
-#include "stateful_util.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)) |
- |
-KernelImage* KernelImageNew(void) { |
- KernelImage* image = (KernelImage*) Malloc(sizeof(KernelImage)); |
- if (image) { |
- image->kernel_sign_key = NULL; |
- image->kernel_key_signature = NULL; |
- image->preamble_signature = NULL; |
- image->kernel_signature = NULL; |
- image->kernel_data = NULL; |
- image->padded_header_size = 0x4000; |
- } |
- return image; |
-} |
- |
-void KernelImageFree(KernelImage* image) { |
- if (image) { |
- Free(image->kernel_sign_key); |
- Free(image->kernel_key_signature); |
- Free(image->preamble_signature); |
- Free(image->kernel_signature); |
- Free(image->kernel_data); |
- Free(image); |
- } |
-} |
- |
-uint64_t GetHeaderSizeOnDisk(const KernelImage* image) { |
- uint64_t kernel_signature_len = siglen_map[image->kernel_sign_algorithm]; |
- uint64_t kernel_key_signature_len = |
- siglen_map[image->firmware_sign_algorithm]; |
- |
- return FIELD_LEN(magic) + |
- GetKernelHeaderLen(image) + |
- kernel_key_signature_len + |
- GetKernelPreambleLen(image->kernel_sign_algorithm) + |
- kernel_signature_len; |
-} |
- |
- |
-KernelImage* ReadKernelImage(const char* input_file) { |
- uint64_t file_size; |
- uint64_t on_disk_header_size; |
- uint64_t on_disk_padding; |
- int header_len = 0; |
- int kernel_key_signature_len; |
- int kernel_sign_key_len; |
- int kernel_signature_len; |
- uint8_t* kernel_buf; |
- uint8_t header_checksum[FIELD_LEN(header_checksum)]; |
- MemcpyState st; |
- KernelImage* image = KernelImageNew(); |
- |
- if (!image) |
- return NULL; |
- |
- kernel_buf = BufferFromFile(input_file, &file_size); |
- |
- st.remaining_len = file_size; |
- st.remaining_buf = kernel_buf; |
- st.overrun = 0; |
- |
- /* Read and compare magic bytes. */ |
- StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE); |
- |
- if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) { |
- debug("Wrong Kernel Magic.\n"); |
- Free(kernel_buf); |
- return NULL; |
- } |
- 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)); |
- |
- /* Valid Kernel Key signing algorithm. */ |
- if (image->firmware_sign_algorithm >= kNumAlgorithms) { |
- Free(kernel_buf); |
- return NULL; |
- } |
- |
- /* Valid Kernel Signing Algorithm? */ |
- if (image->kernel_sign_algorithm >= kNumAlgorithms) { |
- Free(kernel_buf); |
- return NULL; |
- } |
- |
- /* Compute size of pre-processed RSA public keys and signatures. */ |
- kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm]; |
- kernel_sign_key_len = RSAProcessedKeySize(image->kernel_sign_algorithm); |
- kernel_signature_len = siglen_map[image->kernel_sign_algorithm]; |
- |
- /* Check whether key header length is correct. */ |
- header_len = GetKernelHeaderLen(image); |
- if (header_len != image->header_len) { |
- debug("Header length mismatch. Got: %d, Expected: %d\n", |
- image->header_len, header_len); |
- Free(kernel_buf); |
- return NULL; |
- } |
- |
- /* Read pre-processed public half of the kernel signing key. */ |
- StatefulMemcpy(&st, &image->kernel_key_version, |
- FIELD_LEN(kernel_key_version)); |
- image->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len); |
- StatefulMemcpy(&st, image->kernel_sign_key, kernel_sign_key_len); |
- StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum)); |
- |
- /* Check whether the header checksum matches. */ |
- CalculateKernelHeaderChecksum(image, header_checksum); |
- if (SafeMemcmp(header_checksum, image->header_checksum, |
- FIELD_LEN(header_checksum))) { |
- debug("Invalid kernel header checksum!\n"); |
- Free(kernel_buf); |
- return NULL; |
- } |
- |
- /* Read key signature. */ |
- image->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len); |
- StatefulMemcpy(&st, image->kernel_key_signature, |
- kernel_key_signature_len); |
- |
- /* 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 preamble and kernel signatures. */ |
- image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len); |
- StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len); |
- image->preamble_signature = (uint8_t*) Malloc(kernel_signature_len); |
- StatefulMemcpy(&st, image->preamble_signature, kernel_signature_len); |
- |
- /* Skip over the rest of the padded header, unless we're already past it. */ |
- on_disk_header_size = file_size - st.remaining_len; |
- if (image->padded_header_size > on_disk_header_size) { |
- on_disk_padding = image->padded_header_size - on_disk_header_size; |
- if (st.remaining_len < on_disk_padding) |
- st.overrun = -1; |
- st.remaining_buf += on_disk_padding; |
- st.remaining_len -= on_disk_padding; |
- } |
- |
- /* Read kernel image data. */ |
- image->kernel_data = (uint8_t*) Malloc(image->kernel_len); |
- StatefulMemcpy(&st, image->kernel_data, image->kernel_len); |
- |
- if(st.overrun) { |
- Free(kernel_buf); |
- return NULL; |
- } |
- Free(kernel_buf); |
- return image; |
-} |
- |
-int GetKernelHeaderLen(const KernelImage* image) { |
- return (FIELD_LEN(header_version) + FIELD_LEN(header_len) + |
- FIELD_LEN(firmware_sign_algorithm) + |
- FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) + |
- RSAProcessedKeySize(image->kernel_sign_algorithm) + |
- FIELD_LEN(header_checksum)); |
-} |
- |
-void CalculateKernelHeaderChecksum(const KernelImage* image, |
- uint8_t* header_checksum) { |
- uint8_t* checksum; |
- DigestContext ctx; |
- DigestInit(&ctx, SHA512_DIGEST_ALGORITHM); |
- DigestUpdate(&ctx, (uint8_t*) &image->header_version, |
- sizeof(image->header_version)); |
- DigestUpdate(&ctx, (uint8_t*) &image->header_len, |
- sizeof(image->header_len)); |
- DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm, |
- sizeof(image->firmware_sign_algorithm)); |
- DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm, |
- sizeof(image->kernel_sign_algorithm)); |
- DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version, |
- sizeof(image->kernel_key_version)); |
- DigestUpdate(&ctx, image->kernel_sign_key, |
- RSAProcessedKeySize(image->kernel_sign_algorithm)); |
- checksum = DigestFinal(&ctx); |
- Memcpy(header_checksum, checksum, FIELD_LEN(header_checksum)); |
- Free(checksum); |
- return; |
-} |
- |
-uint8_t* GetKernelHeaderBlob(const KernelImage* image) { |
- uint8_t* header_blob = NULL; |
- MemcpyState st; |
- |
- header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image)); |
- st.remaining_len = GetKernelHeaderLen(image); |
- st.remaining_buf = header_blob; |
- st.overrun = 0; |
- |
- StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version)); |
- StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len)); |
- StatefulMemcpy_r(&st, &image->firmware_sign_algorithm, |
- FIELD_LEN(firmware_sign_algorithm)); |
- StatefulMemcpy_r(&st, &image->kernel_sign_algorithm, |
- FIELD_LEN(kernel_sign_algorithm)); |
- StatefulMemcpy_r(&st, &image->kernel_key_version, |
- FIELD_LEN(kernel_key_version)); |
- StatefulMemcpy_r(&st, image->kernel_sign_key, |
- RSAProcessedKeySize(image->kernel_sign_algorithm)); |
- StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum)); |
- |
- if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */ |
- Free(header_blob); |
- return NULL; |
- } |
- return header_blob; |
-} |
- |
-uint8_t* GetKernelPreambleBlob(const KernelImage* image) { |
- uint8_t* preamble_blob = NULL; |
- MemcpyState st; |
- |
- preamble_blob = (uint8_t*) Malloc( |
- GetKernelPreambleLen(image->kernel_sign_algorithm)); |
- st.remaining_len = GetKernelPreambleLen(image->kernel_sign_algorithm); |
- 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->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->kernel_signature, |
- siglen_map[image->kernel_sign_algorithm]); |
- |
- if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */ |
- Free(preamble_blob); |
- return NULL; |
- } |
- return preamble_blob; |
-} |
- |
-uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) { |
- int kernel_key_signature_len; |
- int kernel_signature_len; |
- uint8_t* kernel_blob = NULL; |
- uint8_t* header_blob = NULL; |
- MemcpyState st; |
- uint64_t on_disk_header_size; |
- uint64_t on_disk_padding = 0; |
- |
- if (!image) |
- return NULL; |
- kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm]; |
- kernel_signature_len = siglen_map[image->kernel_sign_algorithm]; |
- on_disk_header_size = GetHeaderSizeOnDisk(image); |
- if (image->padded_header_size > on_disk_header_size) |
- on_disk_padding = image->padded_header_size - on_disk_header_size; |
- *blob_len = on_disk_header_size + on_disk_padding + 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); |
- |
- 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 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->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->kernel_signature, kernel_signature_len); |
- StatefulMemcpy_r(&st, image->preamble_signature, kernel_signature_len); |
- /* Copy a bunch of zeros to pad out the header */ |
- if (on_disk_padding) |
- StatefulMemset_r(&st, 0, on_disk_padding); |
- StatefulMemcpy_r(&st, image->kernel_data, image->kernel_len); |
- |
- Free(header_blob); |
- |
- if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */ |
- debug("GetKernelBlob() failed.\n"); |
- Free(kernel_blob); |
- return NULL; |
- } |
- return kernel_blob; |
-} |
- |
-int WriteKernelImage(const char* output_file, |
- const KernelImage* image, |
- int is_only_vblock, |
- int is_subkey_out) { |
- int fd; |
- int success = 1; |
- uint8_t* kernel_blob = NULL; |
- uint8_t* subkey_out_buf = NULL; |
- uint8_t* subkey_header = NULL; |
- uint64_t blob_len; |
- |
- if (!image) |
- return 0; |
- if (-1 == (fd = creat(output_file, 0666))) { |
- debug("Couldn't open file for writing kernel image: %s\n", |
- output_file); |
- return 0; |
- } |
- if (is_subkey_out) { |
- blob_len = GetKernelHeaderLen(image) + |
- siglen_map[image->firmware_sign_algorithm]; |
- subkey_out_buf = (uint8_t*) Malloc(blob_len); |
- subkey_header = GetKernelHeaderBlob(image); |
- Memcpy(subkey_out_buf, subkey_header, GetKernelHeaderLen(image)); |
- Memcpy(subkey_out_buf + GetKernelHeaderLen(image), |
- image->kernel_key_signature, |
- siglen_map[image->firmware_sign_algorithm]); |
- if (blob_len != write(fd, subkey_out_buf, blob_len)) { |
- debug("Couldn't write Kernel Subkey header to file: %s\n", |
- output_file); |
- success = 0; |
- } |
- Free(subkey_header); |
- Free(subkey_out_buf); |
- close(fd); |
- return success; |
- } |
- |
- kernel_blob = GetKernelBlob(image, &blob_len); |
- if (!kernel_blob) { |
- debug("Couldn't create kernel blob from KernelImage.\n"); |
- return 0; |
- } |
- if (!is_only_vblock) { |
- if (blob_len != write(fd, kernel_blob, blob_len)) { |
- debug("Couldn't write Kernel Image to file: %s\n", |
- output_file); |
- success = 0; |
- } |
- } else { |
- /* 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", |
- output_file); |
- success = 0; |
- } |
- } |
- Free(kernel_blob); |
- close(fd); |
- return success; |
-} |
- |
-void PrintKernelImage(const KernelImage* image) { |
- uint64_t header_size; |
- |
- if (!image) |
- return; |
- |
- header_size = GetHeaderSizeOnDisk(image); |
- if (image->padded_header_size > header_size) |
- header_size = image->padded_header_size; |
- |
- |
- /* Print header. */ |
- printf("Header Version = %d\n" |
- "Header Length = %d\n" |
- "Kernel Key Signature Algorithm = %s\n" |
- "Kernel Signature Algorithm = %s\n" |
- "Kernel Key Version = %d\n\n", |
- image->header_version, |
- image->header_len, |
- algo_strings[image->firmware_sign_algorithm], |
- algo_strings[image->kernel_sign_algorithm], |
- image->kernel_key_version); |
- /* TODO(gauravsh): Output hash and key signature here? */ |
- /* Print preamble. */ |
- printf("Kernel Version = %d\n" |
- "kernel Length = %" PRId64 " (0x%" PRIx64 ")\n" |
- "Bootloader Offset = %" PRId64 " (0x%" PRIx64 ")\n" |
- "Bootloader Size = %" PRId64 " (0x%" PRIx64 ")\n" |
- "Padded Header Size = %" PRId64 " (0x%" PRIx64 ")\n\n" |
- "Actual Header Size on disk = %" PRIu64 " (0x%" PRIx64 ")\n", |
- image->kernel_version, |
- image->kernel_len, image->kernel_len, |
- image->bootloader_offset, image->bootloader_offset, |
- image->bootloader_size, image->bootloader_size, |
- image->padded_header_size, image->padded_header_size, |
- header_size, header_size); |
- /* TODO(gauravsh): Output kernel signature here? */ |
-} |
- |
- |
-int VerifyKernelImage(const RSAPublicKey* firmware_key, |
- const KernelImage* image, |
- const int dev_mode) { |
- RSAPublicKey* kernel_sign_key = NULL; |
- uint8_t* header_digest = NULL; |
- uint8_t* preamble_digest = NULL; |
- uint8_t* kernel_digest = NULL; |
- int kernel_sign_key_size; |
- int kernel_signature_size; |
- int error_code = 0; |
- DigestContext ctx; |
- if (!image) |
- return VERIFY_KERNEL_INVALID_IMAGE; |
- |
- /* Verify kernel key signature on the key header if we |
- * are not in dev mode. |
- * |
- * TODO(gauravsh): Add additional sanity checks here for: |
- * 1) verifying the header length is correct. |
- * 2) header_checksum is correct. |
- */ |
- |
- if (image->firmware_sign_algorithm >= kNumAlgorithms) |
- return VERIFY_KERNEL_INVALID_ALGORITHM; |
- if (image->kernel_sign_algorithm >= kNumAlgorithms) |
- return VERIFY_KERNEL_INVALID_ALGORITHM; |
- |
- if (!dev_mode) { |
- DigestInit(&ctx, image->firmware_sign_algorithm); |
- DigestUpdate(&ctx, (uint8_t*) &image->header_version, |
- FIELD_LEN(header_version)); |
- DigestUpdate(&ctx, (uint8_t*) &image->header_len, |
- FIELD_LEN(header_len)); |
- DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm, |
- FIELD_LEN(firmware_sign_algorithm)); |
- DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm, |
- FIELD_LEN(kernel_sign_algorithm)); |
- DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version, |
- FIELD_LEN(kernel_key_version)); |
- DigestUpdate(&ctx, image->kernel_sign_key, |
- RSAProcessedKeySize(image->kernel_sign_algorithm)); |
- DigestUpdate(&ctx, image->header_checksum, |
- FIELD_LEN(header_checksum)); |
- header_digest = DigestFinal(&ctx); |
- if (!RSAVerify(firmware_key, image->kernel_key_signature, |
- siglen_map[image->firmware_sign_algorithm], |
- image->firmware_sign_algorithm, |
- header_digest)) { |
- debug("VerifyKernelImage(): Key signature check failed.\n"); |
- error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED; |
- goto verify_failure; |
- } |
- } |
- |
- /* Get kernel signing key to verify the rest of the kernel. */ |
- kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm); |
- kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key, |
- kernel_sign_key_size); |
- kernel_signature_size = siglen_map[image->kernel_sign_algorithm]; |
- |
- /* 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->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)); |
- DigestUpdate(&ctx, (uint8_t*) image->kernel_signature, |
- kernel_signature_size); |
- preamble_digest = DigestFinal(&ctx); |
- if (!RSAVerify(kernel_sign_key, image->preamble_signature, |
- kernel_signature_size, image->kernel_sign_algorithm, |
- preamble_digest)) { |
- error_code = VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED; |
- goto verify_failure; |
- } |
- |
- /* Verify kernel signature - kernel signature is computed on the contents |
- * of kernel_data. |
- * Association between the kernel_data and preamble is maintained by making |
- * the kernel signature a part of the preamble and verifying it as part |
- * of preamble signature checking. */ |
- |
- kernel_digest = DigestBuf(image->kernel_data, |
- image->kernel_len, |
- image->kernel_sign_algorithm); |
- if (!RSAVerify(kernel_sign_key, image->kernel_signature, |
- kernel_signature_size, image->kernel_sign_algorithm, |
- kernel_digest)) { |
- error_code = VERIFY_KERNEL_SIGNATURE_FAILED; |
- goto verify_failure; |
- } |
- |
-verify_failure: |
- RSAPublicKeyFree(kernel_sign_key); |
- Free(kernel_digest); |
- Free(preamble_digest); |
- Free(header_digest); |
- return error_code; |
-} |
- |
-const char* VerifyKernelErrorString(int error) { |
- return kVerifyKernelErrors[error]; |
-} |
- |
-int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) { |
- uint8_t* header_blob = NULL; |
- uint8_t* signature = NULL; |
- int signature_len = siglen_map[image->firmware_sign_algorithm]; |
- if (!image || !firmware_key_file) |
- return 0; |
- header_blob = GetKernelHeaderBlob(image); |
- if (!header_blob) |
- return 0; |
- if (!(signature = SignatureBuf(header_blob, |
- GetKernelHeaderLen(image), |
- firmware_key_file, |
- image->firmware_sign_algorithm))) { |
- Free(header_blob); |
- return 0; |
- } |
- image->kernel_key_signature = Malloc(signature_len); |
- Memcpy(image->kernel_key_signature, signature, signature_len); |
- Free(signature); |
- Free(header_blob); |
- return 1; |
-} |
- |
-int AddKernelSignature(KernelImage* image, |
- const char* kernel_signing_key_file) { |
- uint8_t* preamble_blob = NULL; |
- uint8_t* preamble_signature = NULL; |
- uint8_t* kernel_signature = NULL; |
- uint8_t* kernel_buf; |
- int algorithm = image->kernel_sign_algorithm; |
- int signature_len = siglen_map[algorithm]; |
- |
- /* Kernel signature must be calculated first as its used for computing the |
- * preamble signature. */ |
- kernel_buf = (uint8_t*) Malloc(image->kernel_len); |
- Memcpy(kernel_buf, image->kernel_data, image->kernel_len); |
- if (!(kernel_signature = SignatureBuf(kernel_buf, |
- image->kernel_len, |
- kernel_signing_key_file, |
- algorithm))) { |
- Free(preamble_blob); |
- Free(kernel_buf); |
- debug("Could not compute signature on the kernel.\n"); |
- return 0; |
- } |
- image->kernel_signature = (uint8_t*) Malloc(signature_len); |
- Memcpy(image->kernel_signature, kernel_signature, signature_len); |
- |
- |
- preamble_blob = GetKernelPreambleBlob(image); |
- if (!(preamble_signature = SignatureBuf(preamble_blob, |
- GetKernelPreambleLen(algorithm), |
- kernel_signing_key_file, |
- algorithm))) { |
- debug("Could not compute signature on the kernel preamble.\n"); |
- Free(preamble_blob); |
- return 0; |
- } |
- image->preamble_signature = (uint8_t*) Malloc(signature_len); |
- Memcpy(image->preamble_signature, preamble_signature, signature_len); |
- |
- Free(preamble_signature); |
- Free(preamble_blob); |
- Free(kernel_signature); |
- Free(kernel_buf); |
- return 1; |
-} |
- |
-/* Return the smallest integral multiple of [alignment] that is equal to or |
- * greater than [val]. Used to determine the number of |
- * pages/sectors/blocks/whatever needed to contain [val] items/bytes/etc. */ |
-static uint64_t roundup(uint64_t val, uint64_t alignment) { |
- uint64_t rem = val % alignment; |
- if ( rem ) |
- return val + (alignment - rem); |
- return val; |
-} |
- |
-/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we |
- * don't find one, we'll use the whole thing. */ |
-static unsigned int find_cmdline_start(char *input, unsigned int max_len) { |
- int start = 0; |
- int i; |
- for(i = 0; i < max_len-1 && input[i]; i++) { |
- if (input[i] == '-' && input[i+1] == '-') { /* found a "--" */ |
- if ((i == 0 || input[i-1] == ' ') && /* nothing before it */ |
- (i+2 >= max_len || input[i+2] == ' ')) { /* nothing after it */ |
- start = i+2; /* note: hope there's a trailing '\0' */ |
- break; |
- } |
- } |
- } |
- while(input[start] == ' ') /* skip leading spaces */ |
- start++; |
- |
- return start; |
-} |
- |
-uint8_t* GenerateKernelBlob(const char* kernel_file, |
- const char* config_file, |
- const char* bootloader_file, |
- uint64_t* ret_blob_len, |
- uint64_t* ret_bootloader_offset, |
- uint64_t* ret_bootloader_size) { |
- uint8_t* kernel_buf; |
- uint8_t* config_buf; |
- uint8_t* bootloader_buf; |
- uint8_t* blob = 0; |
- uint64_t kernel_size; |
- uint64_t config_size; |
- uint64_t bootloader_size; |
- uint64_t blob_size; |
- uint64_t kernel32_start = 0; |
- uint64_t kernel32_size = 0; |
- uint64_t bootloader_mem_start; |
- uint64_t bootloader_mem_size; |
- uint64_t now; |
- struct linux_kernel_header *lh = 0; |
- struct linux_kernel_params *params = 0; |
- uint32_t cmdline_addr; |
- uint64_t i; |
- |
- /* Read the input files. */ |
- kernel_buf = BufferFromFile(kernel_file, &kernel_size); |
- if (!kernel_buf) |
- goto done0; |
- |
- config_buf = BufferFromFile(config_file, &config_size); |
- if (!config_buf) |
- goto done1; |
- if (config_size >= CROS_CONFIG_SIZE) { /* need room for trailing '\0' */ |
- error("config file %s is too large (>= %d bytes)\n", |
- config_file, CROS_CONFIG_SIZE); |
- goto done1; |
- } |
- |
- /* Replace any newlines with spaces in the config file. */ |
- for (i=0; i < config_size; i++) |
- if (config_buf[i] == '\n') |
- config_buf[i] = ' '; |
- |
- bootloader_buf = BufferFromFile(bootloader_file, &bootloader_size); |
- if (!bootloader_buf) |
- goto done2; |
- |
- /* The first part of vmlinuz is a header, followed by a real-mode boot stub. |
- * We only want the 32-bit part. */ |
- if (kernel_size) { |
- lh = (struct linux_kernel_header *)kernel_buf; |
- kernel32_start = (lh->setup_sects+1) << 9; |
- kernel32_size = kernel_size - kernel32_start; |
- } |
- |
- /* Allocate and zero the blob we need. */ |
- blob_size = roundup(kernel32_size, CROS_ALIGN) + |
- CROS_CONFIG_SIZE + |
- CROS_PARAMS_SIZE + |
- roundup(bootloader_size, CROS_ALIGN); |
- blob = (uint8_t *)Malloc(blob_size); |
- if (!blob) { |
- error("Couldn't allocate %ld bytes.\n", blob_size); |
- goto done3; |
- } |
- Memset(blob, 0, blob_size); |
- now = 0; |
- |
- /* Copy the 32-bit kernel. */ |
- if (kernel32_size) |
- Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size); |
- now += roundup(now + kernel32_size, CROS_ALIGN); |
- |
- /* Find the load address of the commandline. We'll need it later. */ |
- cmdline_addr = CROS_32BIT_ENTRY_ADDR + now |
- + find_cmdline_start((char *)config_buf, config_size); |
- |
- /* Copy the config. */ |
- if (config_size) |
- Memcpy(blob + now, config_buf, config_size); |
- now += CROS_CONFIG_SIZE; |
- |
- /* The zeropage data is next. Overlay the linux_kernel_header onto it, and |
- * tweak a few fields. */ |
- params = (struct linux_kernel_params *)(blob + now); |
- |
- if (kernel_size) |
- Memcpy(&(params->setup_sects), &(lh->setup_sects), |
- sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects)); |
- params->boot_flag = 0; |
- params->ramdisk_image = 0; /* we don't support initrd */ |
- params->ramdisk_size = 0; |
- params->type_of_loader = 0xff; |
- params->cmd_line_ptr = cmdline_addr; |
- now += CROS_PARAMS_SIZE; |
- |
- /* Finally, append the bootloader. Remember where it will load in memory, too. |
- */ |
- bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now; |
- bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN); |
- if (bootloader_size) |
- Memcpy(blob + now, bootloader_buf, bootloader_size); |
- now += bootloader_mem_size; |
- |
- /* Pass back some info. */ |
- if (ret_blob_len) |
- *ret_blob_len = blob_size; |
- if (ret_bootloader_offset) |
- *ret_bootloader_offset = bootloader_mem_start; |
- if (ret_bootloader_size) |
- *ret_bootloader_size = bootloader_mem_size; |
- |
- /* Clean up and return the blob. */ |
-done3: |
- Free(bootloader_buf); |
-done2: |
- Free(config_buf); |
-done1: |
- Free(kernel_buf); |
-done0: |
- return blob; |
-} |