diff options
Diffstat (limited to 'firmware/lib20')
-rw-r--r-- | firmware/lib20/include/vb2_common.h | 16 | ||||
-rw-r--r-- | firmware/lib20/include/vb2_struct.h | 88 | ||||
-rw-r--r-- | firmware/lib20/kernel.c | 112 |
3 files changed, 213 insertions, 3 deletions
diff --git a/firmware/lib20/include/vb2_common.h b/firmware/lib20/include/vb2_common.h index 4067d694..a71cfe6c 100644 --- a/firmware/lib20/include/vb2_common.h +++ b/firmware/lib20/include/vb2_common.h @@ -156,4 +156,20 @@ int vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble, const struct vb2_public_key *key, const struct vb2_workbuf *wb); +/** + * Check the sanity of a kernel preamble using a public key. + * + * The signature in the preamble is destroyed during the check. + * + * @param preamble Preamble to verify + * @param size Size of preamble buffer + * @param key Key to use to verify preamble + * @param wb Work buffer + * @return VB2_SUCCESS, or non-zero error code if error. + */ +int vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble, + uint32_t size, + const struct vb2_public_key *key, + const struct vb2_workbuf *wb); + #endif /* VBOOT_REFERENCE_VB2_COMMON_H_ */ diff --git a/firmware/lib20/include/vb2_struct.h b/firmware/lib20/include/vb2_struct.h index ec28e719..d3e2f400 100644 --- a/firmware/lib20/include/vb2_struct.h +++ b/firmware/lib20/include/vb2_struct.h @@ -81,8 +81,6 @@ struct vb2_keyblock { /* Version of this header format */ uint32_t header_version_major; - - /* Version of this header format */ uint32_t header_version_minor; /* @@ -121,7 +119,7 @@ struct vb2_keyblock { #define FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR 2 #define FIRMWARE_PREAMBLE_HEADER_VERSION_MINOR 1 -/* Flags for VbFirmwarePreambleHeader.flags */ +/* Flags for vb2_fw_preamble.flags */ /* Reserved; do not use */ #define VB2_FIRMWARE_PREAMBLE_RESERVED0 0x00000001 /* Do not allow use of any hardware crypto accelerators. */ @@ -178,4 +176,88 @@ struct vb2_fw_preamble { #define EXPECTED_VB2_FW_PREAMBLE_SIZE 108 +/* Kernel preamble header */ +#define KERNEL_PREAMBLE_HEADER_VERSION_MAJOR 2 +#define KERNEL_PREAMBLE_HEADER_VERSION_MINOR 2 + +/* Flags for vb2_kernel_preamble.flags */ +/* Kernel image type = bits 1:0 */ +#define VB2_KERNEL_PREAMBLE_KERNEL_TYPE_MASK 0x00000003 +#define VB2_KERNEL_PREAMBLE_KERNEL_TYPE_CROS 0 +#define VB2_KERNEL_PREAMBLE_KERNEL_TYPE_BOOTIMG 1 +/* Kernel types 2,3 are reserved for future use */ + +/* + * Preamble block for kernel, version 2.2 + * + * This should be followed by: + * 1) The signature data for the kernel body, pointed to by + * body_signature.sig_offset. + * 2) The signature data for (vb2_kernel_preamble + body signature data), + * pointed to by preamble_signature.sig_offset. + * 3) The 16-bit vmlinuz header, which is used for reconstruction of + * vmlinuz image. + */ +struct vb2_kernel_preamble { + /* + * Size of this preamble, including keys, signatures, vmlinuz header, + * and padding, in bytes + */ + uint32_t preamble_size; + uint32_t reserved0; + + /* Signature for this preamble (header + body signature) */ + struct vb2_signature preamble_signature; + + /* Version of this header format */ + uint32_t header_version_major; + uint32_t header_version_minor; + + /* Kernel version */ + uint32_t kernel_version; + uint32_t reserved1; + + /* Load address for kernel body */ + uint64_t body_load_address; + + /* Address of bootloader, after body is loaded at body_load_address */ + uint64_t bootloader_address; + + /* Size of bootloader in bytes */ + uint32_t bootloader_size; + uint32_t reserved2; + + /* Signature for the kernel body */ + struct vb2_signature body_signature; + + /* + * Fields added in header version 2.1. You must verify the header + * version before reading these fields! + */ + + /* + * Address of 16-bit header for vmlinuz reassembly. Readers should + * return 0 for header version < 2.1. + */ + uint64_t vmlinuz_header_address; + + /* Size of 16-bit header for vmlinuz in bytes. Readers should return 0 + for header version < 2.1 */ + uint32_t vmlinuz_header_size; + uint32_t reserved3; + + /* + * Fields added in header version 2.2. You must verify the header + * version before reading these fields! + */ + + /* + * Flags; see VB2_KERNEL_PREAMBLE_*. Readers should return 0 for + * header version < 2.2. + */ + uint32_t flags; +} __attribute__((packed)); + +#define EXPECTED_VB2_KERNEL_PREAMBLE_SIZE 116 + #endif /* VBOOT_REFERENCE_VB2_STRUCT_H_ */ diff --git a/firmware/lib20/kernel.c b/firmware/lib20/kernel.c new file mode 100644 index 00000000..ec47ce77 --- /dev/null +++ b/firmware/lib20/kernel.c @@ -0,0 +1,112 @@ +/* Copyright 2015 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. + * + * Kernel verified boot functions + */ + +#include "2sysincludes.h" +#include "2rsa.h" +#include "2sha.h" +#include "vb2_common.h" + +int vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble, + uint32_t size, + const struct vb2_public_key *key, + const struct vb2_workbuf *wb) +{ + struct vb2_signature *sig = &preamble->preamble_signature; + + VB2_DEBUG("Verifying kernel preamble.\n"); + + /* Sanity checks before attempting signature of data */ + if(size < sizeof(*preamble)) { + VB2_DEBUG("Not enough data for preamble header.\n"); + return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER; + } + if (preamble->header_version_major != + KERNEL_PREAMBLE_HEADER_VERSION_MAJOR) { + VB2_DEBUG("Incompatible kernel preamble header version.\n"); + return VB2_ERROR_PREAMBLE_HEADER_VERSION; + } + if (preamble->header_version_minor < 2) { + VB2_DEBUG("Old preamble header format not supported\n"); + return VB2_ERROR_PREAMBLE_HEADER_OLD; + } + if (size < preamble->preamble_size) { + VB2_DEBUG("Not enough data for preamble.\n"); + return VB2_ERROR_PREAMBLE_SIZE; + } + + /* Check signature */ + if (vb2_verify_signature_inside(preamble, preamble->preamble_size, + sig)) { + VB2_DEBUG("Preamble signature off end of preamble\n"); + return VB2_ERROR_PREAMBLE_SIG_OUTSIDE; + } + + /* Make sure advertised signature data sizes are sane. */ + if (preamble->preamble_size < sig->data_size) { + VB2_DEBUG("Signature calculated past end of the block\n"); + return VB2_ERROR_PREAMBLE_SIGNED_TOO_MUCH; + } + + if (vb2_verify_data((const uint8_t *)preamble, size, sig, key, wb)) { + VB2_DEBUG("Preamble signature validation failed\n"); + return VB2_ERROR_PREAMBLE_SIG_INVALID; + } + + /* Verify we signed enough data */ + if (sig->data_size < sizeof(struct vb2_fw_preamble)) { + VB2_DEBUG("Didn't sign enough data\n"); + return VB2_ERROR_PREAMBLE_SIGNED_TOO_LITTLE; + } + + /* Verify body signature is inside the signed data */ + if (vb2_verify_signature_inside(preamble, sig->data_size, + &preamble->body_signature)) { + VB2_DEBUG("Body signature off end of preamble\n"); + return VB2_ERROR_PREAMBLE_BODY_SIG_OUTSIDE; + } + + /* + * If bootloader is present, verify it's covered by the body + * signature. + */ + if (preamble->bootloader_size) { + const void *body_ptr = + (const void *)(uintptr_t)preamble->body_load_address; + const void *bootloader_ptr = + (const void *)(uintptr_t)preamble->bootloader_address; + if (vb2_verify_member_inside(body_ptr, + preamble->body_signature.data_size, + bootloader_ptr, + preamble->bootloader_size, + 0, 0)) { + VB2_DEBUG("Bootloader off end of signed data\n"); + return VB2_ERROR_PREAMBLE_BOOTLOADER_OUTSIDE; + } + } + + /* + * If vmlinuz header is present, verify it's covered by the body + * signature. + */ + if (preamble->vmlinuz_header_size) { + const void *body_ptr = + (const void *)(uintptr_t)preamble->body_load_address; + const void *vmlinuz_header_ptr = (const void *) + (uintptr_t)preamble->vmlinuz_header_address; + if (vb2_verify_member_inside(body_ptr, + preamble->body_signature.data_size, + vmlinuz_header_ptr, + preamble->vmlinuz_header_size, + 0, 0)) { + VB2_DEBUG("Vmlinuz header off end of signed data\n"); + return VB2_ERROR_PREAMBLE_VMLINUZ_HEADER_OUTSIDE; + } + } + + /* Success */ + return VB2_SUCCESS; +} |