diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | firmware/lib20/include/vb2_common.h | 22 | ||||
-rw-r--r-- | firmware/lib20/include/vb2_struct.h | 4 | ||||
-rw-r--r-- | firmware/lib20/kernel.c | 46 | ||||
-rw-r--r-- | futility/cmd_show.c | 106 | ||||
-rw-r--r-- | futility/vb1_helper.c | 5 | ||||
-rw-r--r-- | futility/vb1_helper.h | 3 | ||||
-rw-r--r-- | host/lib/include/util_misc.h | 15 | ||||
-rw-r--r-- | host/lib/util_misc.c | 18 | ||||
-rw-r--r-- | host/lib21/include/host_key2.h | 8 | ||||
-rw-r--r-- | tests/vb20_common3_tests.c | 7 |
11 files changed, 151 insertions, 87 deletions
@@ -293,7 +293,7 @@ INCLUDES += \ # If we're not building for a specific target, just stub out things like the # TPM commands and various external functions that are provided by the BIOS. ifeq (${FIRMWARE_ARCH},) -INCLUDES += -Ihost/include -Ihost/lib/include +INCLUDES += -Ihost/include -Ihost/lib/include -Ihost/lib21/include endif # Firmware library, used by the other firmware components (depthcharge, @@ -1199,7 +1199,7 @@ ${TEST20_BINS}: ${FWLIB20} ${TEST20_BINS}: LIBS += ${FWLIB20} ${TEST21_BINS}: ${UTILLIB21} -${TEST21_BINS}: INCLUDES += -Ihost/lib21/include -Ifirmware/lib21/include +${TEST21_BINS}: INCLUDES += -Ifirmware/lib21/include ${TEST21_BINS}: LIBS += ${UTILLIB21} ${TESTBDB_BINS}: ${FWLIB2X} ${UTILBDB} diff --git a/firmware/lib20/include/vb2_common.h b/firmware/lib20/include/vb2_common.h index 0ab89cab..536fbbb0 100644 --- a/firmware/lib20/include/vb2_common.h +++ b/firmware/lib20/include/vb2_common.h @@ -204,4 +204,26 @@ int vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble, const struct vb2_public_key *key, const struct vb2_workbuf *wb); +/** + * Retrieve the 16-bit vmlinuz header address and size from the preamble. + * + * Size 0 means there is no 16-bit vmlinuz header present. Old preamble + * versions (<2.1) return 0 for both fields. + * + * @param preamble Preamble to check + * @param vmlinuz_header_address Destination for header address + * @param vmlinuz_header_size Destination for header size + */ +void vb2_kernel_get_vmlinuz_header(const struct vb2_kernel_preamble *preamble, + uint64_t *vmlinuz_header_address, + uint32_t *vmlinuz_header_size); + +/** + * Get the flags for the kernel preamble. + * + * @param preamble Preamble to check + * @return Flags for the preamble. Old preamble versions (<2.2) return 0. + */ +uint32_t vb2_kernel_get_flags(const struct vb2_kernel_preamble *preamble); + #endif /* VBOOT_REFERENCE_VB2_COMMON_H_ */ diff --git a/firmware/lib20/include/vb2_struct.h b/firmware/lib20/include/vb2_struct.h index f644a5fa..eeaf0cec 100644 --- a/firmware/lib20/include/vb2_struct.h +++ b/firmware/lib20/include/vb2_struct.h @@ -268,6 +268,8 @@ struct vb2_kernel_preamble { uint32_t flags; } __attribute__((packed)); -#define EXPECTED_VB2_KERNEL_PREAMBLE_SIZE 116 +#define EXPECTED_VB2_KERNEL_PREAMBLE_2_0_SIZE 96 +#define EXPECTED_VB2_KERNEL_PREAMBLE_2_1_SIZE 112 +#define EXPECTED_VB2_KERNEL_PREAMBLE_2_2_SIZE 116 #endif /* VBOOT_REFERENCE_VB2_STRUCT_H_ */ diff --git a/firmware/lib20/kernel.c b/firmware/lib20/kernel.c index 609f2461..4ded5d55 100644 --- a/firmware/lib20/kernel.c +++ b/firmware/lib20/kernel.c @@ -249,11 +249,12 @@ int vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble, const struct vb2_workbuf *wb) { struct vb2_signature *sig = &preamble->preamble_signature; + uint32_t min_size = EXPECTED_VB2_KERNEL_PREAMBLE_2_0_SIZE; VB2_DEBUG("Verifying kernel preamble.\n"); - /* Sanity checks before attempting signature of data */ - if(size < sizeof(*preamble)) { + /* Make sure it's even safe to look at the struct */ + if(size < min_size) { VB2_DEBUG("Not enough data for preamble header.\n"); return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER; } @@ -262,9 +263,14 @@ int vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble, 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 (preamble->header_version_minor >= 2) + min_size = EXPECTED_VB2_KERNEL_PREAMBLE_2_2_SIZE; + else if (preamble->header_version_minor == 1) + min_size = EXPECTED_VB2_KERNEL_PREAMBLE_2_1_SIZE; + if(preamble->preamble_size < min_size) { + VB2_DEBUG("Preamble size too small for header.\n"); + return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER; } if (size < preamble->preamble_size) { VB2_DEBUG("Not enough data for preamble.\n"); @@ -325,7 +331,8 @@ int vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble, * If vmlinuz header is present, verify it's covered by the body * signature. */ - if (preamble->vmlinuz_header_size) { + if (preamble->header_version_minor >= 1 && + preamble->vmlinuz_header_size) { const void *body_ptr = (const void *)(uintptr_t)preamble->body_load_address; const void *vmlinuz_header_ptr = (const void *) @@ -442,3 +449,30 @@ int vb2_load_kernel_preamble(struct vb2_context *ctx) return VB2_SUCCESS; } + +void vb2_kernel_get_vmlinuz_header(const struct vb2_kernel_preamble *preamble, + uint64_t *vmlinuz_header_address, + uint32_t *vmlinuz_header_size) +{ + if (preamble->header_version_minor < 1) { + *vmlinuz_header_address = 0; + *vmlinuz_header_size = 0; + } else { + /* + * Set header and size only if the preamble header version is > + * 2.1 as they don't exist in version 2.0 (Note that we don't + * need to check header_version_major; if that's not 2 then + * VerifyKernelPreamble() would have already failed. + */ + *vmlinuz_header_address = preamble->vmlinuz_header_address; + *vmlinuz_header_size = preamble->vmlinuz_header_size; + } +} + +uint32_t vb2_kernel_get_flags(const struct vb2_kernel_preamble *preamble) +{ + if (preamble->header_version_minor < 2) + return 0; + + return preamble->flags; +} diff --git a/futility/cmd_show.c b/futility/cmd_show.c index b2781809..d3cfc7fd 100644 --- a/futility/cmd_show.c +++ b/futility/cmd_show.c @@ -30,11 +30,10 @@ #include "futility.h" #include "futility_options.h" #include "host_common.h" +#include "host_key2.h" #include "util_misc.h" #include "vb1_helper.h" #include "vb2_common.h" -#include "vboot_common.h" -#include "host_key2.h" /* Options */ struct show_option_s show_option = { @@ -43,7 +42,7 @@ struct show_option_s show_option = { }; /* Shared work buffer */ -static uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE]; +static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]; static struct vb2_workbuf wb; void show_pubkey(const struct vb2_packed_key *pubkey, const char *sp) @@ -102,30 +101,24 @@ int ft_show_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data) int ft_show_privkey(const char *name, uint8_t *buf, uint32_t len, void *data) { - VbPrivateKey key; - const unsigned char *start; + struct vb2_packed_private_key *pkey = + (struct vb2_packed_private_key *)buf; + struct vb2_private_key key; + const unsigned char *start = pkey->key_data; - key.algorithm = *(typeof(key.algorithm) *)buf; - start = buf + sizeof(key.algorithm); - if (len <= sizeof(key.algorithm)) { + if (len <= sizeof(*pkey)) { printf("%s looks bogus\n", name); return 1; } - len -= sizeof(key.algorithm); + len -= sizeof(*pkey); key.rsa_private_key = d2i_RSAPrivateKey(NULL, &start, len); printf("Private Key file: %s\n", name); printf(" Vboot API: 1.0\n"); - printf(" Algorithm: %" PRIu64 " %s\n", key.algorithm, - vb1_crypto_name(key.algorithm)); - printf(" Key sha1sum: "); - if (key.rsa_private_key) { - PrintPrivKeySha1Sum(&key); - RSA_free(key.rsa_private_key); - } else { - printf("<error>"); - } - printf("\n"); + printf(" Algorithm: %u %s\n", pkey->algorithm, + vb1_crypto_name(pkey->algorithm)); + printf(" Key sha1sum: %s\n", + private_key_sha1_string(&key)); return 0; } @@ -294,13 +287,7 @@ int ft_show_kernel_preamble(const char *name, uint8_t *buf, uint32_t len, { struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf; struct vb2_public_key *sign_key = show_option.k; - uint8_t *kernel_blob = 0; - uint64_t kernel_size = 0; - int good_sig = 0; int retval = 0; - uint64_t vmlinuz_header_size = 0; - uint64_t vmlinuz_header_address = 0; - uint32_t flags = 0; /* Check the hash... */ if (VB2_SUCCESS != vb2_verify_keyblock_hash(keyblock, len, &wb)) { @@ -309,6 +296,7 @@ int ft_show_kernel_preamble(const char *name, uint8_t *buf, uint32_t len, } /* If we have a key, check the signature too */ + int good_sig = 0; if (sign_key && VB2_SUCCESS == vb2_verify_keyblock(keyblock, len, sign_key, &wb)) good_sig = 1; @@ -319,57 +307,56 @@ int ft_show_kernel_preamble(const char *name, uint8_t *buf, uint32_t len, if (show_option.strict && (!sign_key || !good_sig)) retval = 1; - RSAPublicKey *rsa = PublicKeyToRSA((VbPublicKey *)&keyblock->data_key); - if (!rsa) { + struct vb2_public_key data_key; + if (VB2_SUCCESS != + vb2_unpack_key(&data_key, (const uint8_t *)&keyblock->data_key, + keyblock->data_key.key_offset + + keyblock->data_key.key_size)) { fprintf(stderr, "Error parsing data key in %s\n", name); return 1; } + uint32_t more = keyblock->keyblock_size; - VbKernelPreambleHeader *preamble = - (VbKernelPreambleHeader *)(buf + more); + struct vb2_kernel_preamble *pre2 = + (struct vb2_kernel_preamble *)(buf + more); - if (VBOOT_SUCCESS != VerifyKernelPreamble(preamble, - len - more, rsa)) { + if (VB2_SUCCESS != vb2_verify_kernel_preamble(pre2, len - more, + &data_key, &wb)) { printf("%s is invalid\n", name); return 1; } printf("Kernel Preamble:\n"); - printf(" Size: 0x%" PRIx64 "\n", - preamble->preamble_size); - printf(" Header version: %" PRIu32 ".%" PRIu32 "\n", - preamble->header_version_major, - preamble->header_version_minor); - printf(" Kernel version: %" PRIu64 "\n", - preamble->kernel_version); + printf(" Size: 0x%x\n", pre2->preamble_size); + printf(" Header version: %u.%u\n", + pre2->header_version_major, + pre2->header_version_minor); + printf(" Kernel version: %u\n", pre2->kernel_version); printf(" Body load address: 0x%" PRIx64 "\n", - preamble->body_load_address); - printf(" Body size: 0x%" PRIx64 "\n", - preamble->body_signature.data_size); + pre2->body_load_address); + printf(" Body size: 0x%x\n", + pre2->body_signature.data_size); printf(" Bootloader address: 0x%" PRIx64 "\n", - preamble->bootloader_address); - printf(" Bootloader size: 0x%" PRIx64 "\n", - preamble->bootloader_size); - - if (VbGetKernelVmlinuzHeader(preamble, - &vmlinuz_header_address, - &vmlinuz_header_size) - != VBOOT_SUCCESS) { - fprintf(stderr, "Unable to retrieve Vmlinuz Header!"); - return 1; - } + pre2->bootloader_address); + printf(" Bootloader size: 0x%x\n", pre2->bootloader_size); + + uint64_t vmlinuz_header_address = 0; + uint32_t vmlinuz_header_size = 0; + vb2_kernel_get_vmlinuz_header(pre2, + &vmlinuz_header_address, + &vmlinuz_header_size); if (vmlinuz_header_size) { printf(" Vmlinuz_header address: 0x%" PRIx64 "\n", vmlinuz_header_address); - printf(" Vmlinuz header size: 0x%" PRIx64 "\n", + printf(" Vmlinuz header size: 0x%x\n", vmlinuz_header_size); } - if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) - flags = preamble->flags; - printf(" Flags: 0x%" PRIx32 "\n", flags); + printf(" Flags: 0x%x\n", vb2_kernel_get_flags(pre2)); /* Verify kernel body */ + uint8_t *kernel_blob = 0; + uint64_t kernel_size = 0; if (show_option.fv) { /* It's in a separate file, which we've already read in */ kernel_blob = show_option.fv; @@ -386,15 +373,16 @@ int ft_show_kernel_preamble(const char *name, uint8_t *buf, uint32_t len, return 1; } - if (0 != VerifyData(kernel_blob, kernel_size, - &preamble->body_signature, rsa)) { + if (VB2_SUCCESS != + vb2_verify_data(kernel_blob, kernel_size, &pre2->body_signature, + &data_key, &wb)) { fprintf(stderr, "Error verifying kernel body.\n"); return 1; } printf("Body verification succeeded.\n"); - printf("Config:\n%s\n", kernel_blob + KernelCmdLineOffset(preamble)); + printf("Config:\n%s\n", kernel_blob + kernel_cmd_line_offset(pre2)); return retval; } diff --git a/futility/vb1_helper.c b/futility/vb1_helper.c index c4cdda21..13c5f5e6 100644 --- a/futility/vb1_helper.c +++ b/futility/vb1_helper.c @@ -130,7 +130,7 @@ static unsigned int find_cmdline_start(uint8_t *buf_ptr, unsigned int max_len) } /* Offset of kernel command line string from the start of the kernel blob */ -uint64_t KernelCmdLineOffset(VbKernelPreambleHeader *preamble) +uint64_t kernel_cmd_line_offset(const struct vb2_kernel_preamble *preamble) { return preamble->bootloader_address - preamble->body_load_address - CROS_CONFIG_SIZE - CROS_PARAMS_SIZE; @@ -628,7 +628,8 @@ int VerifyKernelBlob(uint8_t *kernel_blob, } printf("Body verification succeeded.\n"); - printf("Config:\n%s\n", kernel_blob + KernelCmdLineOffset(g_preamble)); + printf("Config:\n%s\n", kernel_blob + kernel_cmd_line_offset( + (struct vb2_kernel_preamble *)g_preamble)); rv = 0; done: diff --git a/futility/vb1_helper.h b/futility/vb1_helper.h index fbe36184..8f3b5000 100644 --- a/futility/vb1_helper.h +++ b/futility/vb1_helper.h @@ -6,6 +6,7 @@ #ifndef VBOOT_REFERENCE_FUTILITY_VB1_HELPER_H_ #define VBOOT_REFERENCE_FUTILITY_VB1_HELPER_H_ +struct vb2_kernel_preamble; struct vb2_packed_key; /** @@ -54,6 +55,6 @@ int VerifyKernelBlob(uint8_t *kernel_blob, const char *keyblock_outfile, uint64_t min_version); -uint64_t KernelCmdLineOffset(VbKernelPreambleHeader *preamble); +uint64_t kernel_cmd_line_offset(const struct vb2_kernel_preamble *preamble); #endif /* VBOOT_REFERENCE_FUTILITY_VB1_HELPER_H_ */ diff --git a/host/lib/include/util_misc.h b/host/lib/include/util_misc.h index 648f2da8..b6372db1 100644 --- a/host/lib/include/util_misc.h +++ b/host/lib/include/util_misc.h @@ -12,6 +12,7 @@ #include "vboot_struct.h" struct rsa_st; struct vb2_packed_key; +struct vb2_private_key; /** * Returns the SHA1 digest of the packed key data as a string. @@ -26,8 +27,18 @@ struct vb2_packed_key; */ const char *packed_key_sha1_string(const struct vb2_packed_key *key); -/* Prints the sha1sum of a VbPrivateKey to stdout. */ -void PrintPrivKeySha1Sum(VbPrivateKey *key); +/** + * Returns the SHA1 digest of the private key data as a string. + * + * The returned string is a global static buffer, so each call to this + * overwrites the previous digest string. So don't call this more than once + * per printf(). + * + * @param key Key to print digest for + * + * @return A string containing the SHA1 digest. + */ +const char *private_key_sha1_string(const struct vb2_private_key *key); /* * Our packed RSBPublicKey buffer (historically in files ending with ".keyb", diff --git a/host/lib/util_misc.c b/host/lib/util_misc.c index 2b0f91c8..56d21b38 100644 --- a/host/lib/util_misc.c +++ b/host/lib/util_misc.c @@ -21,6 +21,7 @@ #include "host_common.h" #include "util_misc.h" #include "vb2_common.h" +#include "host_key2.h" #include "vboot_common.h" const char *packed_key_sha1_string(const struct vb2_packed_key *key) @@ -29,10 +30,10 @@ const char *packed_key_sha1_string(const struct vb2_packed_key *key) uint32_t buflen = key->key_size; uint8_t digest[VB2_SHA1_DIGEST_SIZE]; static char dest[VB2_SHA1_DIGEST_SIZE * 2 + 1]; - char *dnext = dest; vb2_digest_buffer(buf, buflen, VB2_HASH_SHA1, digest, sizeof(digest)); + char *dnext = dest; int i; for (i = 0; i < sizeof(digest); i++) dnext += sprintf(dnext, "%02x", digest[i]); @@ -40,24 +41,27 @@ const char *packed_key_sha1_string(const struct vb2_packed_key *key) return dest; } -void PrintPrivKeySha1Sum(VbPrivateKey *key) +const char *private_key_sha1_string(const struct vb2_private_key *key) { uint8_t *buf; uint32_t buflen; uint8_t digest[VB2_SHA1_DIGEST_SIZE]; - int i; + static char dest[VB2_SHA1_DIGEST_SIZE * 2 + 1]; - if (vb_keyb_from_rsa(key->rsa_private_key, &buf, &buflen)) { - printf("<error>"); - return; + if (!key->rsa_private_key || + vb_keyb_from_rsa(key->rsa_private_key, &buf, &buflen)) { + return "<error>"; } vb2_digest_buffer(buf, buflen, VB2_HASH_SHA1, digest, sizeof(digest)); + char *dnext = dest; + int i; for (i = 0; i < sizeof(digest); i++) - printf("%02x", digest[i]); + dnext += sprintf(dnext, "%02x", digest[i]); free(buf); + return dest; } int vb_keyb_from_rsa(struct rsa_st *rsa_private_key, diff --git a/host/lib21/include/host_key2.h b/host/lib21/include/host_key2.h index 7c95ac16..e58b37d7 100644 --- a/host/lib21/include/host_key2.h +++ b/host/lib21/include/host_key2.h @@ -22,6 +22,14 @@ struct vb2_private_key { struct vb2_id id; /* Key ID */ }; +struct vb2_packed_private_key { + /* Signature algorithm used by the key (enum vb2_crypto_algorithm) */ + uint32_t algorithm; + uint32_t reserved2; + /* Key data formatted for d2i_RSAPrivateKey() */ + uint8_t key_data[0]; +}; + /* Convert between enums and human-readable form. Terminated with {0, 0}. */ struct vb2_text_vs_enum { const char *name; diff --git a/tests/vb20_common3_tests.c b/tests/vb20_common3_tests.c index 0e135bda..95207382 100644 --- a/tests/vb20_common3_tests.c +++ b/tests/vb20_common3_tests.c @@ -425,13 +425,6 @@ static void test_verify_kernel_preamble(const VbPublicKey *public_key, TEST_SUCC(vb2_verify_kernel_preamble(h, hsize, &rsa, &wb), "vb2_verify_kernel_preamble() minor++"); - Memcpy(h, hdr, hsize); - h->header_version_minor--; - resign_kernel_preamble(h, private_key); - TEST_EQ(vb2_verify_kernel_preamble(h, hsize, &rsa, &wb), - VB2_ERROR_PREAMBLE_HEADER_OLD, - "vb2_verify_kernel_preamble() 2.1 not supported"); - /* Check signature */ Memcpy(h, hdr, hsize); h->preamble_signature.sig_offset = hsize; |