mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 02:05:01 +00:00
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>
This commit is contained in:
committed by
chrome-bot
parent
df0e1a391f
commit
02ac2885fd
@@ -29,6 +29,8 @@
|
|||||||
#include "util_misc.h"
|
#include "util_misc.h"
|
||||||
#include "vb1_helper.h"
|
#include "vb1_helper.h"
|
||||||
#include "vboot_common.h"
|
#include "vboot_common.h"
|
||||||
|
#include "2api.h"
|
||||||
|
#include "host_key2.h"
|
||||||
|
|
||||||
/* Options */
|
/* Options */
|
||||||
struct show_option_s show_option = {
|
struct show_option_s show_option = {
|
||||||
@@ -395,6 +397,7 @@ int ft_show_kernel_preamble(const char *name, uint8_t *buf, uint32_t len,
|
|||||||
enum no_short_opts {
|
enum no_short_opts {
|
||||||
OPT_PADDING = 1000,
|
OPT_PADDING = 1000,
|
||||||
OPT_TYPE,
|
OPT_TYPE,
|
||||||
|
OPT_PUBKEY,
|
||||||
OPT_HELP,
|
OPT_HELP,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -415,8 +418,8 @@ static const char usage[] = "\n"
|
|||||||
" --type TYPE Override the detected file type\n"
|
" --type TYPE Override the detected file type\n"
|
||||||
" Use \"--type help\" for a list\n"
|
" Use \"--type help\" for a list\n"
|
||||||
"Type-specific options:\n"
|
"Type-specific options:\n"
|
||||||
" -k|--publickey FILE"
|
" -k|--publickey FILE.vbpubk Public key in vb1 format\n"
|
||||||
" Use this public key for validation\n"
|
" --pubkey FILE.vpubk2 Public key in vb2 format\n"
|
||||||
" -f|--fv FILE Verify this payload (FW_MAIN_A/B)\n"
|
" -f|--fv FILE Verify this payload (FW_MAIN_A/B)\n"
|
||||||
" --pad NUM Kernel vblock padding size\n"
|
" --pad NUM Kernel vblock padding size\n"
|
||||||
" --strict "
|
" --strict "
|
||||||
@@ -441,6 +444,7 @@ static const struct option long_opts[] = {
|
|||||||
{"pad", 1, NULL, OPT_PADDING},
|
{"pad", 1, NULL, OPT_PADDING},
|
||||||
{"type", 1, NULL, OPT_TYPE},
|
{"type", 1, NULL, OPT_TYPE},
|
||||||
{"strict", 0, &show_option.strict, 1},
|
{"strict", 0, &show_option.strict, 1},
|
||||||
|
{"pubkey", 1, NULL, OPT_PUBKEY},
|
||||||
{"help", 0, NULL, OPT_HELP},
|
{"help", 0, NULL, OPT_HELP},
|
||||||
{NULL, 0, NULL, 0},
|
{NULL, 0, NULL, 0},
|
||||||
};
|
};
|
||||||
@@ -528,6 +532,12 @@ static int do_show(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
type_override = 1;
|
type_override = 1;
|
||||||
break;
|
break;
|
||||||
|
case OPT_PUBKEY:
|
||||||
|
if (vb2_packed_key_read(&show_option.pkey, optarg)) {
|
||||||
|
fprintf(stderr, "Error reading %s\n", optarg);
|
||||||
|
errorcnt++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case OPT_HELP:
|
case OPT_HELP:
|
||||||
print_help(argc, argv);
|
print_help(argc, argv);
|
||||||
return !!errorcnt;
|
return !!errorcnt;
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ struct sign_option_s sign_option = {
|
|||||||
.rw_size = 0xffffffff,
|
.rw_size = 0xffffffff,
|
||||||
.ro_offset = 0xffffffff,
|
.ro_offset = 0xffffffff,
|
||||||
.rw_offset = 0xffffffff,
|
.rw_offset = 0xffffffff,
|
||||||
.pkey_offset = 0xffffffff,
|
.sig_size = 1024,
|
||||||
.sig_offset = 0xffffffff,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Helper to complain about invalid args. Returns num errors discovered */
|
/* Helper to complain about invalid args. Returns num errors discovered */
|
||||||
@@ -424,7 +423,7 @@ static void print_help_usbpd1(int argc, char *argv[])
|
|||||||
"\n"
|
"\n"
|
||||||
"This signs a %s.\n"
|
"This signs a %s.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The INPUT is assumed to consist of equal-sized RO and RW"
|
"The INFILE is assumed to consist of equal-sized RO and RW"
|
||||||
" sections,\n"
|
" sections,\n"
|
||||||
"with the public key at the end of of the RO section and the"
|
"with the public key at the end of of the RO section and the"
|
||||||
" signature\n"
|
" signature\n"
|
||||||
@@ -464,7 +463,6 @@ static void print_help_usbpd1(int argc, char *argv[])
|
|||||||
"\n");
|
"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The rwsig help is the same as the usbpd1 help, for now anyway. */
|
|
||||||
static void print_help_rwsig(int argc, char *argv[])
|
static void print_help_rwsig(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
printf("\n"
|
printf("\n"
|
||||||
@@ -472,35 +470,30 @@ static void print_help_rwsig(int argc, char *argv[])
|
|||||||
"\n"
|
"\n"
|
||||||
"This signs a %s.\n"
|
"This signs a %s.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The INPUT is assumed to consist of equal-sized RO and RW"
|
"The INFILE is a binary blob of arbitrary size."
|
||||||
" sections.\n"
|
" It is signed using the\n"
|
||||||
"Signing the RW image will put the signature in the RW half."
|
"private key and the vb2_signature blob emitted.\n"
|
||||||
" If the public\n"
|
"\n"
|
||||||
"key is provided, it will be copied to the RO half.\n"
|
"If no OUTFILE is specified, the INFILE should contain"
|
||||||
|
" an existing\n"
|
||||||
|
"vb2_signature blob near its end. The data_size from that"
|
||||||
|
" signature is\n"
|
||||||
|
"used to re-sign a portion of the INFILE, and the old"
|
||||||
|
" signature blob is\n"
|
||||||
|
"replaced.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
"\n"
|
"\n"
|
||||||
" --prikey FILE.vbprik2 "
|
" --prikey FILE.vbprik2 "
|
||||||
" Private key in vb2 format\n"
|
"Private key in vb2 format (required)\n"
|
||||||
" --pubkey FILE.vbpubk2"
|
" --sig_size NUM "
|
||||||
" Public key in vb2 format\n"
|
"Offset from the end of INFILE where the\n"
|
||||||
"\n"
|
|
||||||
"The size and offset assumptions can be overridden. "
|
|
||||||
"All numbers are in bytes.\n"
|
|
||||||
"Specify a size of 0 to ignore that section.\n"
|
|
||||||
"\n"
|
|
||||||
" --rw_size NUM"
|
|
||||||
" Size of the RW section (default half)\n"
|
|
||||||
" --rw_offset NUM"
|
|
||||||
" Start of the RW section (default half)\n"
|
|
||||||
" --sig_offset NUM"
|
|
||||||
" Where to place the signature (default is\n"
|
|
||||||
" "
|
" "
|
||||||
" near the end of the RW image)\n"
|
"signature blob should be located\n"
|
||||||
" --pkey_offset NUM"
|
|
||||||
" Where to place the public key (default is\n"
|
|
||||||
" "
|
" "
|
||||||
" near the end of the RO image)\n"
|
"(default 1024 bytes)\n"
|
||||||
|
" --data_size NUM "
|
||||||
|
"Number of bytes of INFILE to sign\n"
|
||||||
"\n",
|
"\n",
|
||||||
argv[0],
|
argv[0],
|
||||||
futil_file_type_name(FILE_TYPE_RWSIG),
|
futil_file_type_name(FILE_TYPE_RWSIG),
|
||||||
@@ -529,7 +522,7 @@ static const char usage_default[] = "\n"
|
|||||||
" raw linux kernel (vmlinuz) kernel partition image\n"
|
" raw linux kernel (vmlinuz) kernel partition image\n"
|
||||||
" kernel partition (/dev/sda2) same, or signed in-place\n"
|
" kernel partition (/dev/sda2) same, or signed in-place\n"
|
||||||
" usbpd1 firmware image same, or signed in-place\n"
|
" usbpd1 firmware image same, or signed in-place\n"
|
||||||
" RO+RW firmware image same, or signed in-place\n"
|
" RW device image same, or signed in-place\n"
|
||||||
"\n"
|
"\n"
|
||||||
"For more information, use \"" MYNAME " help %s TYPE\", where\n"
|
"For more information, use \"" MYNAME " help %s TYPE\", where\n"
|
||||||
"TYPE is one of:\n\n";
|
"TYPE is one of:\n\n";
|
||||||
@@ -575,10 +568,9 @@ enum no_short_opts {
|
|||||||
OPT_RW_SIZE,
|
OPT_RW_SIZE,
|
||||||
OPT_RO_OFFSET,
|
OPT_RO_OFFSET,
|
||||||
OPT_RW_OFFSET,
|
OPT_RW_OFFSET,
|
||||||
OPT_PKEY_OFFSET,
|
OPT_DATA_SIZE,
|
||||||
OPT_SIG_OFFSET,
|
OPT_SIG_SIZE,
|
||||||
OPT_PRIKEY,
|
OPT_PRIKEY,
|
||||||
OPT_PUBKEY,
|
|
||||||
OPT_HELP,
|
OPT_HELP,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -614,11 +606,10 @@ static const struct option long_opts[] = {
|
|||||||
{"rw_size", 1, NULL, OPT_RW_SIZE},
|
{"rw_size", 1, NULL, OPT_RW_SIZE},
|
||||||
{"ro_offset", 1, NULL, OPT_RO_OFFSET},
|
{"ro_offset", 1, NULL, OPT_RO_OFFSET},
|
||||||
{"rw_offset", 1, NULL, OPT_RW_OFFSET},
|
{"rw_offset", 1, NULL, OPT_RW_OFFSET},
|
||||||
{"pkey_offset", 1, NULL, OPT_PKEY_OFFSET},
|
{"data_size", 1, NULL, OPT_DATA_SIZE},
|
||||||
{"sig_offset", 1, NULL, OPT_SIG_OFFSET},
|
{"sig_size", 1, NULL, OPT_SIG_SIZE},
|
||||||
{"prikey", 1, NULL, OPT_PRIKEY},
|
{"prikey", 1, NULL, OPT_PRIKEY},
|
||||||
{"privkey", 1, NULL, OPT_PRIKEY}, /* alias */
|
{"privkey", 1, NULL, OPT_PRIKEY}, /* alias */
|
||||||
{"pubkey", 1, NULL, OPT_PUBKEY},
|
|
||||||
{"help", 0, NULL, OPT_HELP},
|
{"help", 0, NULL, OPT_HELP},
|
||||||
{NULL, 0, NULL, 0},
|
{NULL, 0, NULL, 0},
|
||||||
};
|
};
|
||||||
@@ -646,7 +637,6 @@ static int do_sign(int argc, char *argv[])
|
|||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
uint32_t buf_len;
|
uint32_t buf_len;
|
||||||
char *e = 0;
|
char *e = 0;
|
||||||
int inout_file_count = 0;
|
|
||||||
int mapping;
|
int mapping;
|
||||||
int helpind = 0;
|
int helpind = 0;
|
||||||
int longindex;
|
int longindex;
|
||||||
@@ -715,11 +705,11 @@ static int do_sign(int argc, char *argv[])
|
|||||||
sign_option.fv_specified = 1;
|
sign_option.fv_specified = 1;
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case OPT_INFILE:
|
case OPT_INFILE:
|
||||||
inout_file_count++;
|
sign_option.inout_file_count++;
|
||||||
infile = optarg;
|
infile = optarg;
|
||||||
break;
|
break;
|
||||||
case OPT_OUTFILE:
|
case OPT_OUTFILE:
|
||||||
inout_file_count++;
|
sign_option.inout_file_count++;
|
||||||
sign_option.outfile = optarg;
|
sign_option.outfile = optarg;
|
||||||
break;
|
break;
|
||||||
case OPT_BOOTLOADER:
|
case OPT_BOOTLOADER:
|
||||||
@@ -785,13 +775,13 @@ static int do_sign(int argc, char *argv[])
|
|||||||
errorcnt += parse_number_opt(optarg, "rw_offset",
|
errorcnt += parse_number_opt(optarg, "rw_offset",
|
||||||
&sign_option.rw_offset);
|
&sign_option.rw_offset);
|
||||||
break;
|
break;
|
||||||
case OPT_PKEY_OFFSET:
|
case OPT_DATA_SIZE:
|
||||||
errorcnt += parse_number_opt(optarg, "pkey_offset",
|
errorcnt += parse_number_opt(optarg, "data_size",
|
||||||
&sign_option.pkey_offset);
|
&sign_option.data_size);
|
||||||
break;
|
break;
|
||||||
case OPT_SIG_OFFSET:
|
case OPT_SIG_SIZE:
|
||||||
errorcnt += parse_number_opt(optarg, "sig_offset",
|
errorcnt += parse_number_opt(optarg, "sig_size",
|
||||||
&sign_option.sig_offset);
|
&sign_option.sig_size);
|
||||||
break;
|
break;
|
||||||
case OPT_PEM_SIGNPRIV:
|
case OPT_PEM_SIGNPRIV:
|
||||||
sign_option.pem_signpriv = optarg;
|
sign_option.pem_signpriv = optarg;
|
||||||
@@ -834,12 +824,6 @@ static int do_sign(int argc, char *argv[])
|
|||||||
errorcnt++;
|
errorcnt++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_PUBKEY:
|
|
||||||
if (vb2_packed_key_read(&sign_option.pkey, optarg)) {
|
|
||||||
fprintf(stderr, "Error reading %s\n", optarg);
|
|
||||||
errorcnt++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OPT_HELP:
|
case OPT_HELP:
|
||||||
helpind = optind - 1;
|
helpind = optind - 1;
|
||||||
break;
|
break;
|
||||||
@@ -882,14 +866,14 @@ static int do_sign(int argc, char *argv[])
|
|||||||
fprintf(stderr, "ERROR: missing input filename\n");
|
fprintf(stderr, "ERROR: missing input filename\n");
|
||||||
goto done;
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
inout_file_count++;
|
sign_option.inout_file_count++;
|
||||||
infile = argv[optind++];
|
infile = argv[optind++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look for an output file if we don't have one, just in case. */
|
/* Look for an output file if we don't have one, just in case. */
|
||||||
if (!sign_option.outfile && argc - optind > 0) {
|
if (!sign_option.outfile && argc - optind > 0) {
|
||||||
inout_file_count++;
|
sign_option.inout_file_count++;
|
||||||
sign_option.outfile = argv[optind++];
|
sign_option.outfile = argv[optind++];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -945,7 +929,7 @@ static int do_sign(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
case FILE_TYPE_KERN_PREAMBLE:
|
case FILE_TYPE_KERN_PREAMBLE:
|
||||||
errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
|
errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
|
||||||
if (sign_option.vblockonly || inout_file_count > 1)
|
if (sign_option.vblockonly || sign_option.inout_file_count > 1)
|
||||||
sign_option.create_new_outfile = 1;
|
sign_option.create_new_outfile = 1;
|
||||||
break;
|
break;
|
||||||
case FILE_TYPE_RAW_FIRMWARE:
|
case FILE_TYPE_RAW_FIRMWARE:
|
||||||
@@ -982,7 +966,7 @@ static int do_sign(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
Debug("infile=%s\n", infile);
|
Debug("infile=%s\n", infile);
|
||||||
Debug("inout_file_count=%d\n", inout_file_count);
|
Debug("sign_option.inout_file_count=%d\n", sign_option.inout_file_count);
|
||||||
Debug("sign_option.create_new_outfile=%d\n",
|
Debug("sign_option.create_new_outfile=%d\n",
|
||||||
sign_option.create_new_outfile);
|
sign_option.create_new_outfile);
|
||||||
|
|
||||||
@@ -1021,7 +1005,7 @@ static int do_sign(int argc, char *argv[])
|
|||||||
} else {
|
} else {
|
||||||
/* We'll read-modify-write the output file */
|
/* We'll read-modify-write the output file */
|
||||||
mapping = MAP_RW;
|
mapping = MAP_RW;
|
||||||
if (inout_file_count > 1)
|
if (sign_option.inout_file_count > 1)
|
||||||
futil_copy_file_or_die(infile, sign_option.outfile);
|
futil_copy_file_or_die(infile, sign_option.outfile);
|
||||||
Debug("open RW %s\n", sign_option.outfile);
|
Debug("open RW %s\n", sign_option.outfile);
|
||||||
infile = sign_option.outfile;
|
infile = sign_option.outfile;
|
||||||
@@ -1042,7 +1026,7 @@ static int do_sign(int argc, char *argv[])
|
|||||||
errorcnt += futil_file_type_sign(sign_option.type, infile,
|
errorcnt += futil_file_type_sign(sign_option.type, infile,
|
||||||
buf, buf_len);
|
buf, buf_len);
|
||||||
|
|
||||||
errorcnt += futil_unmap_file(ifd, MAP_RW, buf, buf_len);
|
errorcnt += futil_unmap_file(ifd, mapping, buf, buf_len);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (ifd >= 0 && close(ifd)) {
|
if (ifd >= 0 && close(ifd)) {
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ FILE_TYPE(CHROMIUMOS_DISK, "disk_img", "chromiumos disk image",
|
|||||||
NONE,
|
NONE,
|
||||||
NONE,
|
NONE,
|
||||||
NONE)
|
NONE)
|
||||||
FILE_TYPE(RWSIG, "rwsig", "RO+RW firmware image",
|
FILE_TYPE(RWSIG, "rwsig", "RW device image",
|
||||||
NONE,
|
R_(ft_recognize_rwsig),
|
||||||
NONE,
|
S_(ft_show_rwsig),
|
||||||
S_(ft_sign_rwsig))
|
S_(ft_sign_rwsig))
|
||||||
/* Firmware for USB Type-C power adapters */
|
/* Firmware for USB Type-C power adapters */
|
||||||
FILE_TYPE(USBPD1, "usbpd1", "USB-PD charger image (v1.0)",
|
FILE_TYPE(USBPD1, "usbpd1", "USB-PD charger image (v1.0)",
|
||||||
|
|||||||
@@ -30,112 +30,160 @@
|
|||||||
#include "host_signature2.h"
|
#include "host_signature2.h"
|
||||||
#include "util_misc.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
|
#define SIGNATURE_RSVD_SIZE 1024
|
||||||
|
|
||||||
/* True if start + size > max */
|
static inline void vb2_print_bytes(const void *ptr, uint32_t len)
|
||||||
static int bigger_than(uint32_t start, uint32_t size, uint32_t max)
|
|
||||||
{
|
{
|
||||||
int r = start > max || size > max || start > max - size;
|
const uint8_t *buf = (const uint8_t *)ptr;
|
||||||
if (r)
|
int i;
|
||||||
Debug("%s: 0x%x + 0x%x > 0x%x\n", __func__, start, size, max);
|
for (i = 0; i < len; i++)
|
||||||
return r;
|
printf("%02x", *buf++);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* True if one region overlaps the other */
|
static void show_sig(const char *name, const struct vb2_signature *sig)
|
||||||
static int overlaps(uint32_t start_a, uint32_t size_a,
|
|
||||||
uint32_t start_b, uint32_t size_b)
|
|
||||||
{
|
{
|
||||||
if (start_a < start_b && start_a <= start_b - size_a)
|
const struct vb2_text_vs_enum *entry;
|
||||||
return 0;
|
printf("Signature: %s\n", name);
|
||||||
if (start_b < start_a && start_b <= start_a - size_b)
|
printf(" Vboot API: 2.1\n");
|
||||||
return 0;
|
printf(" Desc: \"%s\"\n", vb2_common_desc(sig));
|
||||||
Debug("%s: 0x%x + 0x%x overlaps 0x%x + 0x%x\n",
|
entry = vb2_lookup_by_num(vb2_text_vs_sig, sig->sig_alg);
|
||||||
__func__, start_a, size_a, start_b, size_b);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ft_show_rwsig(const char *name, uint8_t *buf, uint32_t len, void *nuthin)
|
||||||
|
{
|
||||||
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return 1 if okay, 0 if not */
|
sig = (const struct vb2_signature *)(buf + len - sig_size);
|
||||||
static int parse_size_opts(const uint8_t *buf, uint32_t len,
|
if (VB2_SUCCESS == vb2_verify_signature(sig, sig_size)) {
|
||||||
uint32_t *rw_offset_ptr, uint32_t *rw_size_ptr,
|
show_sig(name, sig);
|
||||||
uint32_t *pkey_offset_ptr, uint32_t *sig_offset_ptr)
|
data = buf;
|
||||||
{
|
data_size = sig->data_size;
|
||||||
uint32_t rw_offset, rw_size, pkey_offset, sig_offset;
|
} else {
|
||||||
|
return 1;
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*rw_offset_ptr = rw_offset;
|
if (!show_option.pkey) {
|
||||||
*rw_size_ptr = rw_size;
|
printf("No public key available to verify with\n");
|
||||||
*pkey_offset_ptr = pkey_offset;
|
return show_option.strict;
|
||||||
*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)
|
int ft_sign_rwsig(const char *name, uint8_t *buf, uint32_t len, void *data)
|
||||||
{
|
{
|
||||||
struct vb2_signature *sig = 0;
|
struct vb2_signature *sig = 0;
|
||||||
|
uint32_t r, data_size = len, sig_size = SIGNATURE_RSVD_SIZE;
|
||||||
int retval = 1;
|
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(): name %s\n", __func__, name);
|
||||||
Debug("%s(): len 0x%08x (%d)\n", __func__, len, len);
|
Debug("%s(): len 0x%08x (%d)\n", __func__, len, len);
|
||||||
|
|
||||||
/* Figure out what to sign and where to put the blobs */
|
/* If we don't have a distinct OUTFILE, look for an existing sig */
|
||||||
if (!parse_size_opts(buf, len,
|
if (sign_option.inout_file_count < 2) {
|
||||||
&rw_offset, &rw_size,
|
const struct vb2_signature *old_sig;
|
||||||
&pkey_offset, &sig_offset))
|
|
||||||
goto done;
|
/* 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 */
|
/* Sign the blob */
|
||||||
r = vb2_sign_data(&sig, buf + rw_offset, rw_size,
|
r = vb2_sign_data(&sig, buf, data_size, sign_option.prikey, 0);
|
||||||
sign_option.prikey, 0);
|
|
||||||
if (r) {
|
if (r) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Unable to sign data (error 0x%08x, if that helps)\n",
|
"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;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug("sig_offset 0x%08x\n", sig_offset);
|
if (sign_option.inout_file_count < 2) {
|
||||||
Debug("sig_size 0x%08x\n", sig->c.total_size);
|
/* Overwrite the old signature */
|
||||||
|
if (sig->c.total_size > sig_size) {
|
||||||
if (sig->c.total_size > SIGNATURE_RSVD_SIZE)
|
fprintf(stderr, "New sig is too large (%d > %d)\n",
|
||||||
fprintf(stderr, "WARNING: The signature may be too large"
|
sig->c.total_size, sig_size);
|
||||||
" (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;
|
goto done;
|
||||||
}
|
}
|
||||||
|
memset(buf + len - sig_size, 0xff, sig_size);
|
||||||
Debug("pkey_offset 0x%08x\n", pkey_offset);
|
memcpy(buf + len - sig_size, sig, sig->c.total_size);
|
||||||
Debug("pkey_size 0x%08x\n", sign_option.pkey->c.total_size);
|
} else {
|
||||||
|
/* Write the signature to a new file */
|
||||||
if (sign_option.pkey->c.total_size > PUBKEY_RSVD_SIZE)
|
r = vb2_write_object(sign_option.outfile, sig);
|
||||||
fprintf(stderr, "WARNING: The public key may be too large"
|
if (r) {
|
||||||
" (0x%08x > %08x)\n",
|
fprintf(stderr, "Unable to write sig"
|
||||||
sign_option.pkey->c.total_size, PUBKEY_RSVD_SIZE);
|
" (error 0x%08x, if that helps)\n", r);
|
||||||
|
goto done;
|
||||||
/* Update the public key */
|
}
|
||||||
memcpy(buf + pkey_offset, sign_option.pkey,
|
}
|
||||||
sign_option.pkey->c.total_size);
|
|
||||||
|
|
||||||
/* Finally */
|
/* Finally */
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (sig)
|
||||||
|
free(sig);
|
||||||
if (sign_option.prikey)
|
if (sign_option.prikey)
|
||||||
vb2_private_key_free(sign_option.prikey);
|
vb2_private_key_free(sign_option.prikey);
|
||||||
if (sign_option.pkey)
|
|
||||||
free(sign_option.pkey);
|
|
||||||
|
|
||||||
return retval;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -465,8 +465,6 @@ enum futil_file_type ft_recognize_usbpd1(uint8_t *buf, uint32_t len)
|
|||||||
uint32_t ro_size, rw_size, ro_offset, rw_offset;
|
uint32_t ro_size, rw_size, ro_offset, rw_offset;
|
||||||
int s, h;
|
int s, h;
|
||||||
|
|
||||||
Debug("%s(): len 0x%08x (%d)\n", __func__, len, len);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we don't use any headers to identify or locate the pubkey and
|
* Since we don't use any headers to identify or locate the pubkey and
|
||||||
* signature, in order to identify blob as the right type we have to
|
* signature, in order to identify blob as the right type we have to
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ struct show_option_s {
|
|||||||
int strict;
|
int strict;
|
||||||
int t_flag;
|
int t_flag;
|
||||||
enum futil_file_type type;
|
enum futil_file_type type;
|
||||||
|
struct vb2_packed_key *pkey;
|
||||||
|
uint32_t sig_size;
|
||||||
};
|
};
|
||||||
extern struct show_option_s show_option;
|
extern struct show_option_s show_option;
|
||||||
|
|
||||||
@@ -53,6 +55,7 @@ struct sign_option_s {
|
|||||||
int vblockonly;
|
int vblockonly;
|
||||||
char *outfile;
|
char *outfile;
|
||||||
int create_new_outfile;
|
int create_new_outfile;
|
||||||
|
int inout_file_count;
|
||||||
char *pem_signpriv;
|
char *pem_signpriv;
|
||||||
int pem_algo_specified;
|
int pem_algo_specified;
|
||||||
uint32_t pem_algo;
|
uint32_t pem_algo;
|
||||||
@@ -61,9 +64,8 @@ struct sign_option_s {
|
|||||||
enum vb2_hash_algorithm hash_alg;
|
enum vb2_hash_algorithm hash_alg;
|
||||||
uint32_t ro_size, rw_size;
|
uint32_t ro_size, rw_size;
|
||||||
uint32_t ro_offset, rw_offset;
|
uint32_t ro_offset, rw_offset;
|
||||||
uint32_t pkey_offset, sig_offset;
|
uint32_t data_size, sig_size;
|
||||||
struct vb2_private_key *prikey;
|
struct vb2_private_key *prikey;
|
||||||
struct vb2_packed_key *pkey;
|
|
||||||
};
|
};
|
||||||
extern struct sign_option_s sign_option;
|
extern struct sign_option_s sign_option;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user