summaryrefslogtreecommitdiffstats
path: root/libstb
diff options
context:
space:
mode:
Diffstat (limited to 'libstb')
-rw-r--r--libstb/Makefile.inc2
-rw-r--r--libstb/container.h8
-rw-r--r--libstb/create-container.c381
-rwxr-xr-xlibstb/sign-with-local-keys.sh36
4 files changed, 415 insertions, 12 deletions
diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc
index 8eba0091..64be4d67 100644
--- a/libstb/Makefile.inc
+++ b/libstb/Makefile.inc
@@ -15,7 +15,7 @@ $(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS)
libstb/create-container: libstb/create-container.c
$(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) \
- -Wpadded -O0 -g -I$(SRC) -I$(SRC)/include -o $@ $<,$<)
+ -Wpadded -O0 -g -I$(SRC) -I$(SRC)/include -o $@ $< -lssl -lcrypto,$<)
clean: create-container-clean
diff --git a/libstb/container.h b/libstb/container.h
index f8965d40..c125bc1a 100644
--- a/libstb/container.h
+++ b/libstb/container.h
@@ -149,4 +149,12 @@ int parse_stb_container(const void* data, size_t len, struct parsed_stb_containe
void stb_print_data(const void *data, size_t len);
+void getPublicKeyRaw(ecc_key_t *pubkeyraw, char *inFile);
+
+void getSigRaw(ecc_signature_t *sigraw, char *inFile);
+
+void writeHdr(void *ph, const char *outFile, int hdr_type);
+
+void printBytes(char *lead, unsigned char *buffer, size_t buflen, int wrap);
+
#endif /* __STB_CONTAINER_H */
diff --git a/libstb/create-container.c b/libstb/create-container.c
index b7ec175b..85e0e082 100644
--- a/libstb/create-container.c
+++ b/libstb/create-container.c
@@ -31,6 +31,220 @@
#include <sys/mman.h>
#include <fcntl.h>
#include <assert.h>
+#include <sysexits.h>
+
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/pem.h>
+#include <openssl/sha.h>
+
+#define PREFIX_HDR 0
+#define SOFTWARE_HDR 1
+
+char *progname;
+int debug;
+
+void usage(int status);
+
+void getPublicKeyRaw(ecc_key_t *pubkeyraw, char *inFile)
+{
+ EVP_PKEY* pkey;
+ EC_KEY *key;
+ const EC_GROUP *ecgrp;
+ const EC_POINT *ecpoint;
+ BIGNUM *pubkeyBN;
+ unsigned char pubkeyData[1 + 2*EC_COORDBYTES];
+
+ FILE *fp = fopen( inFile, "r");
+ pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
+ assert(pkey);
+
+ key = EVP_PKEY_get1_EC_KEY(pkey);
+ assert(key);
+ ecgrp = EC_KEY_get0_group(key);
+ assert(ecgrp);
+ ecpoint = EC_KEY_get0_public_key(key);
+ assert(ecpoint);
+ pubkeyBN = EC_POINT_point2bn(ecgrp, ecpoint, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL);
+ BN_bn2bin(pubkeyBN, pubkeyData);
+
+ if (debug)
+ printBytes((char *)"pubkey (RAW) = ", &pubkeyData[1], sizeof(pubkeyData) - 1, 32);
+
+ memcpy(*pubkeyraw, &pubkeyData[1], sizeof(ecc_key_t));
+
+ EC_KEY_free(key);
+ EVP_PKEY_free(pkey);
+ fclose(fp);
+
+ return;
+}
+
+void getSigRaw(ecc_signature_t *sigraw, char *inFile)
+{
+ ECDSA_SIG* signature;
+ int fdin;
+ struct stat s;
+ void *infile;
+ unsigned char outbuf[2*EC_COORDBYTES];
+ int r, rlen, roff, slen, soff;
+
+ fdin = open(inFile, O_RDONLY);
+ assert(fdin > 0);
+ r = fstat(fdin, &s);
+ assert(r==0);
+
+ infile = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fdin, 0);
+ assert(infile);
+
+ signature = d2i_ECDSA_SIG(NULL, (const unsigned char **) &infile, 7 + 2*EC_COORDBYTES);
+
+ memset(&outbuf, 0, sizeof(outbuf));
+
+ rlen = BN_num_bytes(signature->r);
+ roff = 66 - rlen;
+ BN_bn2bin(signature->r, &outbuf[roff]);
+
+ slen = BN_num_bytes(signature->s);
+ soff = 66 + (66 - slen);
+ BN_bn2bin(signature->s, &outbuf[soff]);
+
+ if (debug)
+ printBytes((char *)"sig (RAW) = ", outbuf, sizeof(outbuf), 32);
+
+ memcpy(*sigraw, outbuf, 2*EC_COORDBYTES);
+
+ ECDSA_SIG_free(signature);
+
+ return;
+}
+
+void writeHdr(void *hdr, const char *outFile, int hdr_type)
+{
+ int fdout;
+ int r, hdr_sz;
+ const char *lead;
+ unsigned char md[SHA512_DIGEST_LENGTH];
+
+ fdout = open(outFile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ assert(fdout > 0);
+
+ switch (hdr_type) {
+ case PREFIX_HDR:
+ hdr_sz = sizeof(ROM_prefix_header_raw);
+ break;
+ case SOFTWARE_HDR:
+ hdr_sz = sizeof(ROM_sw_header_raw);
+ break;
+ }
+
+ r = write(fdout, (const void *)hdr, hdr_sz);
+ assert(r > 0);
+
+ if (debug) {
+ if (hdr_type == PREFIX_HDR)
+ lead = "PR hdr hash = ";
+ else
+ lead = "SW hdr hash = ";
+
+ SHA512(hdr, r, md);
+ printBytes((char *)lead, md, sizeof(md), 32);
+ }
+
+ close(fdout);
+
+ return;
+}
+
+void printBytes(char *lead, unsigned char *buffer, size_t buflen, int wrap)
+{
+ int i;
+ int leadbytes = strlen(lead);
+ leadbytes = leadbytes > 30 ? 30 : leadbytes;
+
+ fprintf (stderr, "%s", lead);
+ for (i = 1; i < buflen + 1; i++) {
+ fprintf (stderr, "%02x", buffer[i - 1]);
+ if (((i % wrap) == 0) && (i < buflen))
+ fprintf (stderr, "\n%*c", leadbytes, ' ');
+ }
+ fprintf (stderr, "\n");
+}
+
+__attribute__((__noreturn__)) void usage (int status)
+{
+ if (status != 0) {
+ fprintf(stderr, "Try '%s --help' for more information.\n", progname);
+ }
+ else {
+ printf("Usage: %s [options]\n", progname);
+ printf(
+ "\n"
+ "Options:\n"
+ " -d, --debug show additional debug info\n"
+ " -h, --help display this message and exit\n"
+ " -a, --hw_key_a file containing HW key A private key in PEM format\n"
+ " -b, --hw_key_b file containing HW key B private key in PEM format\n"
+ " -c, --hw_key_c file containing HW key C private key in PEM format\n"
+ " -p, --sw_key_p file containing SW key P private key in PEM format\n"
+ " -q, --sw_key_q file containing SW key Q private key in PEM format\n"
+ " -r, --sw_key_r file containing SW key R private key in PEM format\n"
+ " -A, --hw_sig_a file containing HW key A signature in DER format\n"
+ " -B, --hw_sig_b file containing HW key B signature in DER format\n"
+ " -C, --hw_sig_c file containing HW key C signature in DER format\n"
+ " -P, --sw_sig_p file containing SW key P signature in DER format\n"
+ " -Q, --sw_sig_q file containing SW key Q signature in DER format\n"
+ " -R, --sw_sig_r file containing SW key R signature in DER format\n"
+ " -L, --payload file containing the payload to be signed\n"
+ " -I, --imagefile file to write containerized payload (output)\n"
+ " --dumpPrefixHdr file to dump Prefix header blob (to be signed)\n"
+ " --dumpSwHdr file to dump Software header blob (to be signed)\n"
+ "\n");
+ };
+ exit(status);
+}
+
+static struct option const opts[] = {
+ { "debug", no_argument, 0, 'd' },
+ { "help", no_argument, 0, 'h' },
+ { "hw_key_a", required_argument, 0, 'a' },
+ { "hw_key_b", required_argument, 0, 'b' },
+ { "hw_key_c", required_argument, 0, 'c' },
+ { "sw_key_p", required_argument, 0, 'p' },
+ { "sw_key_q", required_argument, 0, 'q' },
+ { "sw_key_r", required_argument, 0, 'r' },
+ { "hw_sig_a", required_argument, 0, 'A' },
+ { "hw_sig_b", required_argument, 0, 'B' },
+ { "hw_sig_c", required_argument, 0, 'C' },
+ { "sw_sig_p", required_argument, 0, 'P' },
+ { "sw_sig_q", required_argument, 0, 'Q' },
+ { "sw_sig_r", required_argument, 0, 'R' },
+ { "payload", required_argument, 0, 'L' },
+ { "imagefile", required_argument, 0, 'I' },
+ { "dumpPrefixHdr", required_argument, 0, 128 },
+ { "dumpSwHdr", required_argument, 0, 129 },
+ {NULL, 0, 0, 0}
+};
+
+static struct {
+ char *hw_keyfn_a;
+ char *hw_keyfn_b;
+ char *hw_keyfn_c;
+ char *sw_keyfn_p;
+ char *sw_keyfn_q;
+ char *sw_keyfn_r;
+ char *hw_sigfn_a;
+ char *hw_sigfn_b;
+ char *hw_sigfn_c;
+ char *sw_sigfn_p;
+ char *sw_sigfn_q;
+ char *sw_sigfn_r;
+ char *imagefn;
+ char *payloadfn;
+ char *prhdrfn;
+ char *swhdrfn;
+} params;
+
int main(int argc, char* argv[])
{
@@ -45,29 +259,119 @@ int main(int argc, char* argv[])
ROM_prefix_header_raw *ph;
ROM_prefix_data_raw *pd;
ROM_sw_header_raw *swh;
+ ROM_sw_sig_raw *ssig;
+
+ unsigned char md[SHA512_DIGEST_LENGTH];
+ void *p;
+ ecc_key_t pubkeyraw;
+ ecc_signature_t sigraw;
+ int indexptr;
+
+ progname = strrchr (argv[0], '/');
+ if (progname != NULL)
+ ++progname;
+ else
+ progname = argv[0];
memset(container, 0, SECURE_BOOT_HEADERS_SIZE);
- if (argc<3)
- return -1;
+ while (1) {
+ int opt;
+ opt = getopt_long(argc, argv, "a:b:c:p:q:r:A:B:C:P:Q:R:L:I:dh", opts, &indexptr);
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'h':
+ case '?':
+ usage(EX_OK);
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'a':
+ params.hw_keyfn_a = optarg;
+ break;
+ case 'b':
+ params.hw_keyfn_b = optarg;
+ break;
+ case 'c':
+ params.hw_keyfn_c = optarg;
+ break;
+ case 'p':
+ params.sw_keyfn_p = optarg;
+ break;
+ case 'q':
+ params.sw_keyfn_q = optarg;
+ break;
+ case 'r':
+ params.sw_keyfn_r = optarg;
+ break;
+ case 'A':
+ params.hw_sigfn_a = optarg;
+ break;
+ case 'B':
+ params.hw_sigfn_b = optarg;
+ break;
+ case 'C':
+ params.hw_sigfn_c = optarg;
+ break;
+ case 'P':
+ params.sw_sigfn_p = optarg;
+ break;
+ case 'Q':
+ params.sw_sigfn_q = optarg;
+ break;
+ case 'R':
+ params.sw_sigfn_r = optarg;
+ break;
+ case 'L':
+ params.payloadfn = optarg;
+ break;
+ case 'I':
+ params.imagefn = optarg;
+ break;
+ case 128:
+ params.prhdrfn = optarg;
+ break;
+ case 129:
+ params.swhdrfn = optarg;
+ break;
+ default:
+ usage(EX_USAGE);
+ }
+ }
+// }
- fdin = open(argv[1], O_RDONLY);
+ fdin = open(params.payloadfn, O_RDONLY);
assert(fdin > 0);
r = fstat(fdin, &s);
assert(r==0);
- infile = mmap(NULL, s.st_size, PROT_READ, 0, fdin, 0);
+ infile = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fdin, 0);
assert(infile);
- fdout = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ fdout = open(params.imagefn, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
assert(fdout > 0);
c->magic_number = cpu_to_be32(ROM_MAGIC_NUMBER);
- c->version = 1;
+ c->version = cpu_to_be16(1);
c->container_size = cpu_to_be64(SECURE_BOOT_HEADERS_SIZE + s.st_size);
c->target_hrmor = 0;
c->stack_pointer = 0;
memset(c->hw_pkey_a, 0, sizeof(ecc_key_t));
memset(c->hw_pkey_b, 0, sizeof(ecc_key_t));
memset(c->hw_pkey_c, 0, sizeof(ecc_key_t));
+ if (params.hw_keyfn_a) {
+ getPublicKeyRaw(&pubkeyraw, params.hw_keyfn_a);
+ memcpy(c->hw_pkey_a, pubkeyraw, sizeof(ecc_key_t));
+ }
+ if (params.hw_keyfn_b) {
+ getPublicKeyRaw(&pubkeyraw, params.hw_keyfn_b);
+ memcpy(c->hw_pkey_b, pubkeyraw, sizeof(ecc_key_t));
+ }
+ if (params.hw_keyfn_c) {
+ getPublicKeyRaw(&pubkeyraw, params.hw_keyfn_c);
+ memcpy(c->hw_pkey_c, pubkeyraw, sizeof(ecc_key_t));
+ }
ph = container + sizeof(ROM_container_raw);
ph->ver_alg.version = cpu_to_be16(1);
@@ -75,21 +379,53 @@ int main(int argc, char* argv[])
ph->ver_alg.sig_alg = 1;
ph->code_start_offset = 0;
ph->reserved = 0;
- ph->flags = 0;
- ph->sw_key_count = 1; // 1, not 0. Because Hostboot
- memset(ph->payload_hash, 0, sizeof(sha2_hash_t)); // TODO
+ ph->flags = cpu_to_be32(0x80000000);
+ memset(ph->payload_hash, 0, sizeof(sha2_hash_t));
ph->ecid_count = 0;
pd = (ROM_prefix_data_raw*)ph->ecid;
memset(pd->hw_sig_a, 0, sizeof(ecc_signature_t));
memset(pd->hw_sig_b, 0, sizeof(ecc_signature_t));
memset(pd->hw_sig_c, 0, sizeof(ecc_signature_t));
+ if (params.hw_sigfn_a) {
+ getSigRaw(&sigraw, params.hw_sigfn_a);
+ memcpy(pd->hw_sig_a, sigraw, sizeof(ecc_key_t));
+ }
+ if (params.hw_sigfn_b) {
+ getSigRaw(&sigraw, params.hw_sigfn_b);
+ memcpy(pd->hw_sig_b, sigraw, sizeof(ecc_key_t));
+ }
+ if (params.hw_sigfn_c) {
+ getSigRaw(&sigraw, params.hw_sigfn_c);
+ memcpy(pd->hw_sig_c, sigraw, sizeof(ecc_key_t));
+ }
memset(pd->sw_pkey_p, 0, sizeof(ecc_key_t));
memset(pd->sw_pkey_q, 0, sizeof(ecc_key_t));
memset(pd->sw_pkey_r, 0, sizeof(ecc_key_t));
- ph->payload_size = cpu_to_be64(sizeof(ecc_signature_t)*3 + ph->sw_key_count * sizeof(ecc_key_t));
+ if (params.sw_keyfn_p) {
+ getPublicKeyRaw(&pubkeyraw, params.sw_keyfn_p);
+ memcpy(pd->sw_pkey_p, pubkeyraw, sizeof(ecc_key_t));
+ ph->sw_key_count++;
+ }
+ if (params.sw_keyfn_q) {
+ getPublicKeyRaw(&pubkeyraw, params.sw_keyfn_q);
+ memcpy(pd->sw_pkey_q, pubkeyraw, sizeof(ecc_key_t));
+ ph->sw_key_count++;
+ }
+ if (params.sw_keyfn_r) {
+ getPublicKeyRaw(&pubkeyraw, params.sw_keyfn_r);
+ memcpy(pd->sw_pkey_r, pubkeyraw, sizeof(ecc_key_t));
+ ph->sw_key_count++;
+ }
+ ph->payload_size = cpu_to_be64(ph->sw_key_count * sizeof(ecc_key_t));
+ p = SHA512(pd->sw_pkey_p, sizeof(ecc_key_t) * ph->sw_key_count, md);
+ assert(p);
+ memcpy(ph->payload_hash, md, sizeof(sha2_hash_t));
- swh = (ROM_sw_header_raw*)(((void*)pd) + be64_to_cpu(ph->payload_size));
+ if (params.prhdrfn)
+ writeHdr((void *)ph, params.prhdrfn, PREFIX_HDR);
+
+ swh = (ROM_sw_header_raw*)(((uint8_t*)pd) + sizeof(ecc_signature_t)*3 + be64_to_cpu(ph->payload_size));
swh->ver_alg.version = cpu_to_be16(1);
swh->ver_alg.hash_alg = 1;
swh->ver_alg.sig_alg = 1;
@@ -98,6 +434,29 @@ int main(int argc, char* argv[])
swh->flags = 0;
swh->reserved_0 = 0;
swh->payload_size = cpu_to_be64(s.st_size);
+ p = SHA512(infile, s.st_size, md);
+ assert(p);
+ memcpy(swh->payload_hash, md, sizeof(sha2_hash_t));
+
+ if (params.swhdrfn)
+ writeHdr((void *)swh, params.swhdrfn, SOFTWARE_HDR);
+
+ ssig = (ROM_sw_sig_raw*)(((uint8_t*)swh) + sizeof(ROM_sw_header_raw));
+ memset(ssig->sw_sig_p, 0, sizeof(ecc_signature_t));
+ memset(ssig->sw_sig_q, 0, sizeof(ecc_signature_t));
+ memset(ssig->sw_sig_r, 0, sizeof(ecc_signature_t));
+ if (params.sw_sigfn_p) {
+ getSigRaw(&sigraw, params.sw_sigfn_p);
+ memcpy(ssig->sw_sig_p, sigraw, sizeof(ecc_key_t));
+ }
+ if (params.sw_sigfn_q) {
+ getSigRaw(&sigraw, params.sw_sigfn_q);
+ memcpy(ssig->sw_sig_q, sigraw, sizeof(ecc_key_t));
+ }
+ if (params.sw_sigfn_r) {
+ getSigRaw(&sigraw, params.sw_sigfn_r);
+ memcpy(ssig->sw_sig_r, sigraw, sizeof(ecc_key_t));
+ }
r = write(fdout, container, SECURE_BOOT_HEADERS_SIZE);
assert(r == 4096);
diff --git a/libstb/sign-with-local-keys.sh b/libstb/sign-with-local-keys.sh
new file mode 100755
index 00000000..d9fed37a
--- /dev/null
+++ b/libstb/sign-with-local-keys.sh
@@ -0,0 +1,36 @@
+#!/bin/bash -x
+
+PAYLOAD=$1
+OUTPUT=$2
+
+if [ ! -f $PAYLOAD ]; then
+ echo "Can't read PAYLOAD";
+ exit 1;
+fi
+
+KEYLOC="/tmp/keys"
+T=`mktemp -d`
+
+# Build enough of the container to create the Prefix and Software headers.
+./create-container -a $KEYLOC/hw_key_a.key -b $KEYLOC/hw_key_b.key -c $KEYLOC/hw_key_c.key \
+ -p $KEYLOC/sw_key_a.key \
+ --payload $PAYLOAD --imagefile $OUTPUT \
+ --dumpPrefixHdr $T/prefix_hdr --dumpSwHdr $T/software_hdr
+
+# Sign the Prefix header.
+openssl dgst -SHA512 -sign $KEYLOC/hw_key_a.key $T/prefix_hdr > $T/hw_key_a.sig
+openssl dgst -SHA512 -sign $KEYLOC/hw_key_b.key $T/prefix_hdr > $T/hw_key_b.sig
+openssl dgst -SHA512 -sign $KEYLOC/hw_key_c.key $T/prefix_hdr > $T/hw_key_c.sig
+
+# Sign the Software header.
+# Only one SW key in Nick's repo, and it has a confusing name (should be "sw_key_p")
+openssl dgst -SHA512 -sign $KEYLOC/sw_key_a.key $T/software_hdr > $T/sw_key_p.sig
+
+# Build the full container with signatures.
+./create-container -a $KEYLOC/hw_key_a.key -b $KEYLOC/hw_key_b.key -c $KEYLOC/hw_key_c.key \
+ -p $KEYLOC/sw_key_a.key \
+ -A $T/hw_key_a.sig -B $T/hw_key_b.sig -C $T/hw_key_c.sig \
+ -P $T/sw_key_p.sig \
+ --payload $PAYLOAD --imagefile $OUTPUT
+
+rm -rf $T
OpenPOWER on IntegriCloud