diff options
author | Bill Richardson <wfrichar@chromium.org> | 2015-10-15 00:23:18 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2015-10-15 19:57:13 -0700 |
commit | 02ac2885fd797fba7f12ef040f0eb041dda7af20 (patch) | |
tree | 8c8386e3fc07bb5f7cc8c5c485cf10a58dec1340 /futility/file_type_rwsig.c | |
parent | df0e1a391fa7b8d7bdb31f9623fbbcbb158cd2ad (diff) | |
download | vboot-02ac2885fd797fba7f12ef040f0eb041dda7af20.tar.gz |
futility: Revised support for RO+RW firmware
The "rwsig" type is used for independent device firmware (not
Chromebook BIOS) that need to verify themselves instead of using
software sync.
The expected use case is that a RO firmware contains a
vb2_public_key struct along with an FMAP or other pointers to a
slot for RW firmware. The RW firmware slot reserves room for a
vb2_signature struct.
This CL changes the args and behavior of the rwsig type, so that
the RW firmware can be [re]signed independently of the rest of
the image.
BUG=chrome-os-partner:46254
BRANCH=smaug,ToT
TEST=make runtests, manual
Create a keypair:
futility create --desc "Key One" tests/testkeys/key_rsa2048.pem foo
Sign a RW binary and build a complete image out of the parts:
futility sign --type rwsig --prikey foo.vbprik2 rw.bin sig.bin
dd if=/dev/zero bs=65536 count=1 of=image.bin
dd if=rw.bin of=image.bin conv=notrunc
dd if=sig.bin bs=$((65536 - 1024)) seek=1 of=image.bin conv=notrunc
Verify both the separate parts and the combined image:
futility show --type rwsig --pubkey foo.vbpubk2 rw.bin sig.bin
futility show --type rwsig --pubkey foo.vbpubk2 image.bin
Re-sign the combined image with a different keypair:
futility create --desc "Key Two" tests/testkeys/key_rsa1024.pem bar
futility sign --type rwsig --prikey bar.vbprik2 image.bin
Now the first key no longer verifies:
futility show --type rwsig --pubkey foo.vbpubk2 image.bin
But the second key does:
futility show --type rwsig --pubkey bar.vbpubk2 image.bin
Change-Id: Ifdddab08f218f506eb1dce28851b153d70140a7b
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/305980
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'futility/file_type_rwsig.c')
-rw-r--r-- | futility/file_type_rwsig.c | 274 |
1 files changed, 162 insertions, 112 deletions
diff --git a/futility/file_type_rwsig.c b/futility/file_type_rwsig.c index 6b757fff..e50ff32f 100644 --- a/futility/file_type_rwsig.c +++ b/futility/file_type_rwsig.c @@ -30,112 +30,160 @@ #include "host_signature2.h" #include "util_misc.h" -/* - * Reserved space for the public key and signature. This may not be enough for - * larger key sizes since the vb2 structs are more than just the raw bits. - */ -#define PUBKEY_RSVD_SIZE 2048 #define SIGNATURE_RSVD_SIZE 1024 -/* True if start + size > max */ -static int bigger_than(uint32_t start, uint32_t size, uint32_t max) +static inline void vb2_print_bytes(const void *ptr, uint32_t len) { - int r = start > max || size > max || start > max - size; - if (r) - Debug("%s: 0x%x + 0x%x > 0x%x\n", __func__, start, size, max); - return r; + const uint8_t *buf = (const uint8_t *)ptr; + int i; + for (i = 0; i < len; i++) + printf("%02x", *buf++); } -/* True if one region overlaps the other */ -static int overlaps(uint32_t start_a, uint32_t size_a, - uint32_t start_b, uint32_t size_b) +static void show_sig(const char *name, const struct vb2_signature *sig) { - if (start_a < start_b && start_a <= start_b - size_a) - return 0; - if (start_b < start_a && start_b <= start_a - size_b) - return 0; - Debug("%s: 0x%x + 0x%x overlaps 0x%x + 0x%x\n", - __func__, start_a, size_a, start_b, size_b); - return 1; + const struct vb2_text_vs_enum *entry; + printf("Signature: %s\n", name); + printf(" Vboot API: 2.1\n"); + printf(" Desc: \"%s\"\n", vb2_common_desc(sig)); + entry = vb2_lookup_by_num(vb2_text_vs_sig, sig->sig_alg); + printf(" Signature Algorithm: %d %s\n", sig->sig_alg, + entry ? entry->name : "(invalid)"); + entry = vb2_lookup_by_num(vb2_text_vs_hash, sig->hash_alg); + printf(" Hash Algorithm: %d %s\n", sig->hash_alg, + entry ? entry->name : "(invalid)"); + printf(" Total size: 0x%x (%d)\n", sig->c.total_size, + sig->c.total_size); + printf(" ID: "); + vb2_print_bytes(&sig->id, sizeof(sig->id)); + printf("\n"); + printf(" Data size: 0x%x (%d)\n", sig->data_size, + sig->data_size); } -/* Return 1 if okay, 0 if not */ -static int parse_size_opts(const uint8_t *buf, uint32_t len, - uint32_t *rw_offset_ptr, uint32_t *rw_size_ptr, - uint32_t *pkey_offset_ptr, uint32_t *sig_offset_ptr) +int ft_show_rwsig(const char *name, uint8_t *buf, uint32_t len, void *nuthin) { - uint32_t rw_offset, rw_size, pkey_offset, sig_offset; - - /* Start with defaults */ - - /* The image has both RO and RW, evenly split, RO first. */ - rw_size = rw_offset = len / 2; - - /* The public key is up against the end of the RO half */ - pkey_offset = rw_offset - PUBKEY_RSVD_SIZE; - - /* The signature key is up against the end of the whole image */ - sig_offset = len - SIGNATURE_RSVD_SIZE; - - /* The RW image to be signed doesn't include the signature */ - rw_size -= SIGNATURE_RSVD_SIZE; - - /* FIXME: Override the defaults here by looking for an FMAP or similar - * structure telling us where the parts are. */ - - /* We can override any of that with explicit args */ - if (sign_option.rw_offset != 0xffffffff) - rw_offset = sign_option.rw_offset; - if (sign_option.rw_size != 0xffffffff) - rw_size = sign_option.rw_size; - if (sign_option.pkey_offset != 0xffffffff) - pkey_offset = sign_option.pkey_offset; - if (sign_option.sig_offset != 0xffffffff) - sig_offset = sign_option.sig_offset; - - Debug("pkey_offset 0x%08x\n", pkey_offset); - Debug("rw_offset 0x%08x\n", rw_offset); - Debug("rw_size 0x%08x\n", rw_size); - Debug("sig_offset 0x%08x\n", sig_offset); - - /* Now let's do some sanity checks. */ - if (bigger_than(rw_offset, rw_size, len) || - overlaps(rw_offset, rw_size, pkey_offset, PUBKEY_RSVD_SIZE) || - overlaps(rw_offset, rw_size, sig_offset, SIGNATURE_RSVD_SIZE) || - overlaps(pkey_offset, PUBKEY_RSVD_SIZE, - sig_offset, SIGNATURE_RSVD_SIZE)) { - printf("size/offset values are bogus\n"); - return 0; + const struct vb2_signature *sig = 0; + struct vb2_public_key key; + uint8_t workbuf[VB2_VERIFY_DATA_WORKBUF_BYTES] + __attribute__ ((aligned (VB2_WORKBUF_ALIGN))); + struct vb2_workbuf wb; + uint32_t data_size, sig_size = SIGNATURE_RSVD_SIZE; + uint8_t *data; + + Debug("%s(): name %s\n", __func__, name); + Debug("%s(): len 0x%08x (%d)\n", __func__, len, len); + + /* Am I just looking at a signature file? */ + Debug("Looking for signature at 0x0\n"); + sig = (const struct vb2_signature *)buf; + if (VB2_SUCCESS == vb2_verify_signature(sig, len)) { + show_sig(name, sig); + if (!show_option.fv) { + printf("No data available to verify\n"); + return show_option.strict; + } + data = show_option.fv; + data_size = show_option.fv_size; + } else { + /* Where would it be? */ + if (show_option.sig_size) + sig_size = show_option.sig_size; + + Debug("Looking for signature at 0x%x\n", len - sig_size); + + if (len < sig_size) { + Debug("File is too small\n"); + return 1; + } + + sig = (const struct vb2_signature *)(buf + len - sig_size); + if (VB2_SUCCESS == vb2_verify_signature(sig, sig_size)) { + show_sig(name, sig); + data = buf; + data_size = sig->data_size; + } else { + return 1; + } + } + + if (!show_option.pkey) { + printf("No public key available to verify with\n"); + return show_option.strict; } - *rw_offset_ptr = rw_offset; - *rw_size_ptr = rw_size; - *pkey_offset_ptr = pkey_offset; - *sig_offset_ptr = sig_offset; + /* We already did this once, so it should work again */ + if (vb2_unpack_key(&key, + (const uint8_t *)show_option.pkey, + show_option.pkey->c.total_size)) { + Debug("Can't unpack pubkey\n"); + return 1; + } - return 1; + /* The sig is destroyed by the verify operation, so make a copy */ + { + uint8_t sigbuf[sig->c.total_size]; + memcpy(sigbuf, sig, sizeof(sigbuf)); + + vb2_workbuf_init(&wb, workbuf, sizeof(workbuf)); + + if (vb2_verify_data(data, data_size, + (struct vb2_signature *)sigbuf, + (const struct vb2_public_key *)&key, + &wb)) { + printf("Signature verification failed\n"); + return 1; + } + } + + printf("Signature verification succeeded.\n"); + return 0; } int ft_sign_rwsig(const char *name, uint8_t *buf, uint32_t len, void *data) { struct vb2_signature *sig = 0; + uint32_t r, data_size = len, sig_size = SIGNATURE_RSVD_SIZE; int retval = 1; - uint32_t rw_offset, rw_size; /* what to sign */ - uint32_t pkey_offset, sig_offset; /* where to put blobs */ - uint32_t r; Debug("%s(): name %s\n", __func__, name); Debug("%s(): len 0x%08x (%d)\n", __func__, len, len); - /* Figure out what to sign and where to put the blobs */ - if (!parse_size_opts(buf, len, - &rw_offset, &rw_size, - &pkey_offset, &sig_offset)) - goto done; + /* If we don't have a distinct OUTFILE, look for an existing sig */ + if (sign_option.inout_file_count < 2) { + const struct vb2_signature *old_sig; + + /* Where would it be? */ + if (sign_option.sig_size) + sig_size = sign_option.sig_size; + + Debug("Looking for old signature at 0x%x\n", len - sig_size); + + if (len < sig_size) { + fprintf(stderr, "File is too small\n"); + return 1; + } + + /* Take a look */ + old_sig = (const struct vb2_signature *)(buf + len - sig_size); + if (vb2_verify_signature(old_sig, sig_size)) { + fprintf(stderr, "Can't find a valid signature\n"); + return 1; + } + + /* Use the same exent again */ + data_size = old_sig->data_size; + + Debug("Found sig: data_size is 0x%x (%d)\n", data_size, + data_size); + } + + /* Unless overridden */ + if (sign_option.data_size) + data_size = sign_option.data_size; /* Sign the blob */ - r = vb2_sign_data(&sig, buf + rw_offset, rw_size, - sign_option.prikey, 0); + r = vb2_sign_data(&sig, buf, data_size, sign_option.prikey, 0); if (r) { fprintf(stderr, "Unable to sign data (error 0x%08x, if that helps)\n", @@ -143,43 +191,45 @@ int ft_sign_rwsig(const char *name, uint8_t *buf, uint32_t len, void *data) goto done; } - Debug("sig_offset 0x%08x\n", sig_offset); - Debug("sig_size 0x%08x\n", sig->c.total_size); - - if (sig->c.total_size > SIGNATURE_RSVD_SIZE) - fprintf(stderr, "WARNING: The signature may be too large" - " (0x%08x > %08x)\n", - sig->c.total_size, SIGNATURE_RSVD_SIZE); - - /* Update the signature */ - memcpy(buf + sig_offset, sig, sig->c.total_size); - - /* If weren't given a public key, we're done */ - if (!sign_option.pkey) { - fprintf(stderr, "No public key given; not updating RO\n"); - retval = 0; - goto done; + if (sign_option.inout_file_count < 2) { + /* Overwrite the old signature */ + if (sig->c.total_size > sig_size) { + fprintf(stderr, "New sig is too large (%d > %d)\n", + sig->c.total_size, sig_size); + goto done; + } + memset(buf + len - sig_size, 0xff, sig_size); + memcpy(buf + len - sig_size, sig, sig->c.total_size); + } else { + /* Write the signature to a new file */ + r = vb2_write_object(sign_option.outfile, sig); + if (r) { + fprintf(stderr, "Unable to write sig" + " (error 0x%08x, if that helps)\n", r); + goto done; + } } - Debug("pkey_offset 0x%08x\n", pkey_offset); - Debug("pkey_size 0x%08x\n", sign_option.pkey->c.total_size); - - if (sign_option.pkey->c.total_size > PUBKEY_RSVD_SIZE) - fprintf(stderr, "WARNING: The public key may be too large" - " (0x%08x > %08x)\n", - sign_option.pkey->c.total_size, PUBKEY_RSVD_SIZE); - - /* Update the public key */ - memcpy(buf + pkey_offset, sign_option.pkey, - sign_option.pkey->c.total_size); - /* Finally */ retval = 0; done: + if (sig) + free(sig); if (sign_option.prikey) vb2_private_key_free(sign_option.prikey); - if (sign_option.pkey) - free(sign_option.pkey); return retval; } + +enum futil_file_type ft_recognize_rwsig(uint8_t *buf, uint32_t len) +{ + if (!vb2_verify_signature((const struct vb2_signature *)buf, len)) + return FILE_TYPE_RWSIG; + + if (!vb2_verify_signature((const struct vb2_signature *) + (buf + len - SIGNATURE_RSVD_SIZE), + SIGNATURE_RSVD_SIZE)) + return FILE_TYPE_RWSIG; + + return FILE_TYPE_UNKNOWN; +} |