diff options
author | Stewart Smith <stewart@linux.vnet.ibm.com> | 2017-12-13 17:26:42 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2017-12-18 21:30:57 -0600 |
commit | 6e05c6f21b34f9c4f6597ace36dfca9624c7923c (patch) | |
tree | 4215358d42122cc17c5c6198c1d8b306b1161a88 /libstb/create-container.c | |
parent | 63ef6f54445e52e0cd3af4672e73c047484a6a12 (diff) | |
download | skiboot-6e05c6f21b34f9c4f6597ace36dfca9624c7923c.zip skiboot-6e05c6f21b34f9c4f6597ace36dfca9624c7923c.tar.gz skiboot-6e05c6f21b34f9c4f6597ace36dfca9624c7923c.tar.bz2 |
libstb/(create|print)-container: Sync with sb-signing-utils
The sb-signing-utils project has improved upon the skeleton
create-container tool that existed in skiboot, including
being able to (quite easily) create *signed* images.
This commit brings in that code (and makes it build in the
skiboot build environment) and updates our skiboot.*.stb
generating code to use the development keys.
We also update print-container as well, syncing it with the
upstream project.
Derived from github.com:open-power/sb-signing-utils.git
at v0.3-5-gcb111c03ad7f
(and yes, changes here will be submitted upstream)
Cc: Dave Heller <hellerda@linux.vnet.ibm.com>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'libstb/create-container.c')
-rw-r--r-- | libstb/create-container.c | 541 |
1 files changed, 394 insertions, 147 deletions
diff --git a/libstb/create-container.c b/libstb/create-container.c index 5cf80a0..4207e1c 100644 --- a/libstb/create-container.c +++ b/libstb/create-container.c @@ -1,4 +1,4 @@ -/* Copyright 2013-2016 IBM Corp. +/* Copyright 2017 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,205 +16,280 @@ #include <config.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <limits.h> +#include <openssl/bn.h> +#include <openssl/ec.h> +#include <openssl/ecdsa.h> +#include <openssl/evp.h> +#include <openssl/opensslv.h> +#include <openssl/ossl_typ.h> +#include <openssl/pem.h> +#include <openssl/sha.h> #include <stdbool.h> #include <types.h> -#include "container.h" - +#include <stdint.h> #include <stdio.h> #include <stdlib.h> -#include <getopt.h> -#include <unistd.h> #include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> #include <sys/mman.h> -#include <fcntl.h> -#include <assert.h> +#include <sys/stat.h> #include <sysexits.h> +#include <unistd.h> -#include <openssl/ec.h> -#include <openssl/ecdsa.h> -#include <openssl/pem.h> -#include <openssl/sha.h> +#include "ccan/endian/endian.h" +#include "ccan/short_types/short_types.h" +#include "container-utils.h" +#include "container.h" -#define PREFIX_HDR 0 -#define SOFTWARE_HDR 1 +#define CONTAINER_HDR 0 +#define PREFIX_HDR 1 +#define SOFTWARE_HDR 2 char *progname; -int debug; + +bool verbose, debug; +int wrap = 100; 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); + unsigned char pubkeyData[1 + 2 * EC_COORDBYTES]; + + FILE *fp = fopen(inFile, "r"); + if (!fp) + die(EX_NOINPUT, "Cannot open key file: %s: %s", inFile, strerror(errno)); + + if ((pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL))) { + debug_msg("File \"%s\" is a PEM private key", inFile); + fclose(fp); + } else { + fclose(fp); + fp = fopen(inFile, "r"); + if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL))) { + debug_msg("File \"%s\" is a PEM public key", inFile); + } + fclose(fp); + } - memcpy(*pubkeyraw, &pubkeyData[1], sizeof(ecc_key_t)); + if (pkey) { + EC_KEY *key; + const EC_GROUP *ecgrp; + const EC_POINT *ecpoint; + BIGNUM *pubkeyBN; + + key = EVP_PKEY_get1_EC_KEY(pkey); + if (!key) + die(EX_SOFTWARE, "%s", "Cannot EVP_PKEY_get1_EC_KEY"); + + ecgrp = EC_KEY_get0_group(key); + if (!ecgrp) + die(EX_SOFTWARE, "%s", "Cannot EC_KEY_get0_group"); + + ecpoint = EC_KEY_get0_public_key(key); + if (!ecpoint) + die(EX_SOFTWARE, "%s", "Cannot EC_KEY_get0_public_key"); + + pubkeyBN = EC_POINT_point2bn(ecgrp, ecpoint, POINT_CONVERSION_UNCOMPRESSED, + NULL, NULL); + BN_bn2bin(pubkeyBN, pubkeyData); + + BN_free(pubkeyBN); + EC_KEY_free(key); + EVP_PKEY_free(pkey); + } + else { + /* The file is not a public or private key in PEM format. So we check if + * it is a p521 pubkey in RAW format, in which case it will be 133 bytes + * with a leading byte of 0x04, indicating an uncompressed key. */ + int fdin, r; + struct stat s; + void *infile = NULL; + + fdin = open(inFile, O_RDONLY); + if (fdin <= 0) + die(EX_NOINPUT, "Cannot open key file: %s: %s", inFile, strerror(errno)); + + r = fstat(fdin, &s); + if (r != 0) + die(EX_NOINPUT, "Cannot stat key file: %s", inFile); + + if (s.st_size == 1 + 2 * EC_COORDBYTES) + infile = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fdin, 0); + + close(fdin); + + if (!infile || (*(unsigned char*) infile != 0x04)) { + die(EX_DATAERR, + "File \"%s\" is not in expected format (private or public key in PEM, or public key RAW)", + inFile); + } + else + debug_msg("File \"%s\" is a RAW public key", inFile); + + memcpy(pubkeyData, infile, sizeof(ecc_key_t) + 1); + } - EC_KEY_free(key); - EVP_PKEY_free(pkey); - fclose(fp); + // Remove the leading byte + memcpy(*pubkeyraw, &pubkeyData[1], sizeof(ecc_key_t)); 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; + int r; + int rlen, roff, slen, soff; const BIGNUM *sr, *ss; + unsigned char outbuf[2 * EC_COORDBYTES]; + ECDSA_SIG* signature; fdin = open(inFile, O_RDONLY); - assert(fdin > 0); + if (fdin <= 0) + die(EX_NOINPUT, "Cannot open sig file: %s: %s", inFile, strerror(errno)); + r = fstat(fdin, &s); - assert(r==0); + if (r != 0) + die(EX_NOINPUT, "Cannot stat sig file: %s", inFile); infile = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fdin, 0); - assert(infile); + if (!infile) + die(EX_OSERR, "%s", "Cannot mmap file"); + + close(fdin); + + if (s.st_size == 2 * EC_COORDBYTES) { + /* The file is a p521 signature in RAW format. */ + debug_msg("File \"%s\" is a RAW signature", inFile); + memcpy(sigraw, infile, sizeof(ecc_signature_t)); + } + else { + /* Assume the file is a p521 signature in DER format. + * Convert the DER to a signature object, then extract the RAW. */ + debug_msg("File \"%s\" is a DER signature", inFile); - signature = d2i_ECDSA_SIG(NULL, (const unsigned char **) &infile, 7 + 2*EC_COORDBYTES); + signature = d2i_ECDSA_SIG(NULL, + (const unsigned char **) &infile, 7 + 2 * EC_COORDBYTES); - memset(&outbuf, 0, sizeof(outbuf)); + memset(&outbuf, 0, sizeof(outbuf)); #if OPENSSL_VERSION_NUMBER >= 0x10100000L - ECDSA_SIG_get0(signature, &sr, &ss); + ECDSA_SIG_get0(signature, &sr, &ss); #else - sr = signature->r; - ss = signature->s; + sr = signature->r; + ss = signature->s; #endif - rlen = BN_num_bytes(sr); - roff = 66 - rlen; - BN_bn2bin(sr, &outbuf[roff]); - - slen = BN_num_bytes(ss); - soff = 66 + (66 - slen); - BN_bn2bin(sr, &outbuf[soff]); + rlen = BN_num_bytes(sr); + roff = 66 - rlen; + BN_bn2bin(sr, &outbuf[roff]); - if (debug) - printBytes((char *)"sig (RAW) = ", outbuf, sizeof(outbuf), 32); + slen = BN_num_bytes(ss); + soff = 66 + (66 - slen); + BN_bn2bin(ss, &outbuf[soff]); - memcpy(*sigraw, outbuf, 2*EC_COORDBYTES); - - ECDSA_SIG_free(signature); - close(fdin); + memcpy(sigraw, outbuf, sizeof(ecc_signature_t)); + ECDSA_SIG_free(signature); + } return; } void writeHdr(void *hdr, const char *outFile, int hdr_type) { int fdout; - int r, hdr_sz=0; - const char *lead; + int r, hdr_sz; 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 CONTAINER_HDR: + hdr_sz = SECURE_BOOT_HEADERS_SIZE; + break; case PREFIX_HDR: hdr_sz = sizeof(ROM_prefix_header_raw); + SHA512(hdr, hdr_sz, md); + verbose_print((char *) "PR header hash = ", md, sizeof(md)); break; case SOFTWARE_HDR: hdr_sz = sizeof(ROM_sw_header_raw); + SHA512(hdr, hdr_sz, md); + verbose_print((char *) "SW header hash = ", md, sizeof(md)); break; + default: + die(EX_SOFTWARE, "Unknown header type (%d)", hdr_type); } - r = write(fdout, (const void *)hdr, hdr_sz); - assert(r > 0); + fdout = open(outFile, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fdout <= 0) + die(EX_CANTCREAT, "Cannot create output file: %s", outFile); - if (debug) { - if (hdr_type == PREFIX_HDR) - lead = "PR hdr hash = "; - else - lead = "SW hdr hash = "; + r = write(fdout, (const void *) hdr, hdr_sz); + close(fdout); - SHA512(hdr, r, md); - printBytes((char *)lead, md, sizeof(md), 32); - } + if (r < hdr_sz) + die(EX_SOFTWARE, "Error writing header file (r = %d)", r); - close(fdout); + debug_msg("Wrote %d bytes to %s", r, outFile); 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); + 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" + " -v, --verbose show verbose output\n" + " -d, --debug show additional debug output\n" + " -w, --wrap column to wrap long output in verbose mode\n" + " -a, --hw_key_a file containing HW key A key in PEM or RAW format\n" + " -b, --hw_key_b file containing HW key B key in PEM or RAW format\n" + " -c, --hw_key_c file containing HW key C key in PEM or RAW format\n" + " -p, --sw_key_p file containing SW key P key in PEM or RAW format\n" + " -q, --sw_key_q file containing SW key Q key in PEM or RAW format\n" + " -r, --sw_key_r file containing SW key R key in PEM or RAW 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" + " -l, --payload file containing the payload to be signed\n" + " -I, --imagefile file to write containerized image (output)\n" + " -o, --hw-cs-offset code start offset for prefix header in hex\n" + " -O, --sw-cs-offset code start offset for software header in hex\n" + " -f, --hw-flags prefix header flags in hex\n" + " -F, --sw-flags software header flags in hex\n" + " -L, --label character field up to 8 bytes, written to SW header\n" " --dumpPrefixHdr file to dump Prefix header blob (to be signed)\n" " --dumpSwHdr file to dump Software header blob (to be signed)\n" + " --dumpContrHdr file to dump full Container header (w/o payload)\n" + "Note:\n" + "- Keys A,B,C,P,Q,R must be valid p521 ECC keys. Keys may be provided as public\n" + " or private key in PEM format, or public key in uncompressed raw format.\n" "\n"); }; exit(status); } static struct option const opts[] = { - { "debug", no_argument, 0, 'd' }, { "help", no_argument, 0, 'h' }, + { "verbose", no_argument, 0, 'v' }, + { "debug", no_argument, 0, 'd' }, + { "wrap", required_argument, 0, 'w' }, { "hw_key_a", required_argument, 0, 'a' }, { "hw_key_b", required_argument, 0, 'b' }, { "hw_key_c", required_argument, 0, 'c' }, @@ -227,11 +302,17 @@ static struct option const opts[] = { { "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' }, + { "payload", required_argument, 0, 'l' }, { "imagefile", required_argument, 0, 'I' }, + { "hw-cs-offset", required_argument, 0, 'o' }, + { "sw-cs-offset", required_argument, 0, 'O' }, + { "hw-flags", required_argument, 0, 'f' }, + { "sw-flags", required_argument, 0, 'F' }, + { "label", required_argument, 0, 'L' }, { "dumpPrefixHdr", required_argument, 0, 128 }, { "dumpSwHdr", required_argument, 0, 129 }, - {NULL, 0, 0, 0} + { "dumpContrHdr", required_argument, 0, 130 }, + { NULL, 0, NULL, 0 } }; static struct { @@ -249,21 +330,31 @@ static struct { char *sw_sigfn_r; char *imagefn; char *payloadfn; + char *hw_cs_offset; + char *sw_cs_offset; + char *hw_flags; + char *sw_flags; + char *label; char *prhdrfn; char *swhdrfn; + char *cthdrfn; } params; int main(int argc, char* argv[]) { int fdin, fdout; + int indexptr; + unsigned int size, offset; void *container = malloc(SECURE_BOOT_HEADERS_SIZE); - struct stat s; - char *buf = malloc(4096); + char *buf = malloc(SECURE_BOOT_HEADERS_SIZE); + struct stat payload_st; off_t l; void *infile; int r; - ROM_container_raw *c = (ROM_container_raw*)container; + uint32_t data; + uint64_t data64; + ROM_container_raw *c = (ROM_container_raw*) container; ROM_prefix_header_raw *ph; ROM_prefix_data_raw *pd; ROM_sw_header_raw *swh; @@ -273,9 +364,8 @@ int main(int argc, char* argv[]) void *p; ecc_key_t pubkeyraw; ecc_signature_t sigraw; - int indexptr; - progname = strrchr (argv[0], '/'); + progname = strrchr(argv[0], '/'); if (progname != NULL) ++progname; else @@ -285,7 +375,8 @@ int main(int argc, char* argv[]) 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); + opt = getopt_long(argc, argv, "hvdw:a:b:c:p:q:r:A:B:C:P:Q:R:L:I:o:O:f:F:l:", + opts, &indexptr); if (opt == -1) break; @@ -294,8 +385,15 @@ int main(int argc, char* argv[]) case '?': usage(EX_OK); break; + case 'v': + verbose = true; + break; case 'd': - debug = 1; + debug = true; + break; + case 'w': + wrap = atoi(optarg); + wrap = (wrap < 2) ? INT_MAX : wrap; break; case 'a': params.hw_keyfn_a = optarg; @@ -333,36 +431,62 @@ int main(int argc, char* argv[]) case 'R': params.sw_sigfn_r = optarg; break; - case 'L': + case 'l': params.payloadfn = optarg; break; case 'I': params.imagefn = optarg; break; + case 'o': + params.hw_cs_offset = optarg; + break; + case 'O': + params.sw_cs_offset = optarg; + break; + case 'f': + params.hw_flags = optarg; + break; + case 'F': + params.sw_flags = optarg; + break; + case 'L': + params.label = optarg; + break; case 128: params.prhdrfn = optarg; break; case 129: params.swhdrfn = optarg; break; + case 130: + params.cthdrfn = optarg; + break; default: usage(EX_USAGE); } } -// } fdin = open(params.payloadfn, 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); - fdout = open(params.imagefn, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - assert(fdout > 0); + if (fdin <= 0) + die(EX_NOINPUT, "Cannot open payload file: %s", params.payloadfn); + + r = fstat(fdin, &payload_st); + if (r != 0) + die(EX_NOINPUT, "Cannot stat payload file: %s", params.payloadfn); + infile = mmap(NULL, payload_st.st_size, PROT_READ, MAP_PRIVATE, fdin, 0); + if (!infile) + die(EX_OSERR, "%s", "Cannot mmap file"); + + fdout = open(params.imagefn, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fdout <= 0) + die(EX_CANTCREAT, "Cannot create output file: %s", params.imagefn); + + // Container creation starts here. c->magic_number = cpu_to_be32(ROM_MAGIC_NUMBER); c->version = cpu_to_be16(1); - c->container_size = cpu_to_be64(SECURE_BOOT_HEADERS_SIZE + s.st_size); + c->container_size = cpu_to_be64(SECURE_BOOT_HEADERS_SIZE + payload_st.st_size); c->target_hrmor = 0; c->stack_pointer = 0; memset(c->hw_pkey_a, 0, sizeof(ecc_key_t)); @@ -370,111 +494,234 @@ int main(int argc, char* argv[]) memset(c->hw_pkey_c, 0, sizeof(ecc_key_t)); if (params.hw_keyfn_a) { getPublicKeyRaw(&pubkeyraw, params.hw_keyfn_a); + verbose_print((char *) "pubkey A = ", pubkeyraw, sizeof(pubkeyraw)); memcpy(c->hw_pkey_a, pubkeyraw, sizeof(ecc_key_t)); } if (params.hw_keyfn_b) { getPublicKeyRaw(&pubkeyraw, params.hw_keyfn_b); + verbose_print((char *) "pubkey B = ", pubkeyraw, sizeof(pubkeyraw)); memcpy(c->hw_pkey_b, pubkeyraw, sizeof(ecc_key_t)); } if (params.hw_keyfn_c) { getPublicKeyRaw(&pubkeyraw, params.hw_keyfn_c); + verbose_print((char *) "pubkey C = ", pubkeyraw, sizeof(pubkeyraw)); memcpy(c->hw_pkey_c, pubkeyraw, sizeof(ecc_key_t)); } + p = SHA512(c->hw_pkey_a, sizeof(ecc_key_t) * 3, md); + if (!p) + die(EX_SOFTWARE, "%s", "Cannot get SHA512"); + verbose_print((char *) "HW keys hash = ", md, sizeof(md)); ph = container + sizeof(ROM_container_raw); ph->ver_alg.version = cpu_to_be16(1); ph->ver_alg.hash_alg = 1; ph->ver_alg.sig_alg = 1; - ph->code_start_offset = 0; + + // Set code-start-offset. + if (params.hw_cs_offset) { + if (!isValidHex(params.hw_cs_offset, 4)) + die(EX_DATAERR, "%s", + "Invalid input for hw-cs-offset, expecting a 4 byte hexadecimal value"); + sscanf(params.hw_cs_offset, "%lx", &data64); + ph->code_start_offset = cpu_to_be64(data64); + verbose_msg("hw-cs-offset = %#010lx", data64); + } else { + ph->code_start_offset = 0; + } ph->reserved = 0; - ph->flags = cpu_to_be32(0x80000000); + + // Set flags. + if (params.hw_flags) { + if (!isValidHex(params.hw_flags, 4)) + die(EX_DATAERR, "%s", + "Invalid input for hw-flags, expecting a 4 byte hexadecimal value"); + sscanf(params.hw_flags, "%x", &data); + ph->flags = cpu_to_be32(data); + verbose_msg("hw-flags = %#010x", data); + } else { + 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; + 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)); + + // Write the HW signatures. if (params.hw_sigfn_a) { getSigRaw(&sigraw, params.hw_sigfn_a); + verbose_print((char *) "signature A = ", sigraw, sizeof(sigraw)); memcpy(pd->hw_sig_a, sigraw, sizeof(ecc_key_t)); } if (params.hw_sigfn_b) { getSigRaw(&sigraw, params.hw_sigfn_b); + verbose_print((char *) "signature B = ", sigraw, sizeof(sigraw)); memcpy(pd->hw_sig_b, sigraw, sizeof(ecc_key_t)); } if (params.hw_sigfn_c) { getSigRaw(&sigraw, params.hw_sigfn_c); + verbose_print((char *) "signature C = ", sigraw, sizeof(sigraw)); 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)); + + // Write the FW keys. if (params.sw_keyfn_p) { getPublicKeyRaw(&pubkeyraw, params.sw_keyfn_p); + verbose_print((char *) "pubkey P = ", pubkeyraw, sizeof(pubkeyraw)); 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); + verbose_print((char *) "pubkey Q = ", pubkeyraw, sizeof(pubkeyraw)); 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); + verbose_print((char *) "pubkey R = ", pubkeyraw, sizeof(pubkeyraw)); memcpy(pd->sw_pkey_r, pubkeyraw, sizeof(ecc_key_t)); ph->sw_key_count++; } + debug_msg("sw_key_count = %u", ph->sw_key_count); ph->payload_size = cpu_to_be64(ph->sw_key_count * sizeof(ecc_key_t)); + + // Calculate the SW keys hash. p = SHA512(pd->sw_pkey_p, sizeof(ecc_key_t) * ph->sw_key_count, md); - assert(p); + if (!p) + die(EX_SOFTWARE, "%s", "Cannot get SHA512"); memcpy(ph->payload_hash, md, sizeof(sha2_hash_t)); + verbose_print((char *) "SW keys hash = ", md, sizeof(md)); + // Dump the Prefix header. if (params.prhdrfn) - writeHdr((void *)ph, params.prhdrfn, PREFIX_HDR); + 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 = (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; - swh->code_start_offset = 0; + + // Set code-start-offset. + if (params.sw_cs_offset) { + if (!isValidHex(params.sw_cs_offset, 4)) + die(EX_DATAERR, "%s", + "Invalid input for sw-cs-offset, expecting a 4 byte hexadecimal value"); + sscanf(params.sw_cs_offset, "%lx", &data64); + swh->code_start_offset = cpu_to_be64(data64); + verbose_msg("sw-cs-offset = %#010lx", data64); + } else { + swh->code_start_offset = 0; + } swh->reserved = 0; - swh->flags = 0; + + // Add component ID (label). + if (params.label) { + if (!isValidAscii(params.label, 0)) + die(EX_DATAERR, "%s", + "Invalid input for label, expecting a 8 char ASCII value"); + strncpy((char *) &swh->reserved, params.label, 8); + verbose_msg("component ID (was reserved) = %.8s", + (char * ) &swh->reserved); + } + + // Set flags. + if (params.sw_flags) { + if (!isValidHex(params.sw_flags, 4)) + die(EX_DATAERR, "%s", + "Invalid input for sw-flags, expecting a 4 byte hexadecimal value"); + sscanf(params.sw_flags, "%x", &data); + swh->flags = cpu_to_be32(data); + verbose_msg("sw-flags = %#010x", data); + } else { + swh->flags = cpu_to_be32(0x00000000); + } swh->reserved_0 = 0; - swh->payload_size = cpu_to_be64(s.st_size); - p = SHA512(infile, s.st_size, md); - assert(p); + swh->payload_size = cpu_to_be64(payload_st.st_size); + + // Calculate the payload hash. + p = SHA512(infile, payload_st.st_size, md); + if (!p) + die(EX_SOFTWARE, "%s", "Cannot get SHA512"); memcpy(swh->payload_hash, md, sizeof(sha2_hash_t)); + verbose_print((char *) "Payload hash = ", md, sizeof(md)); + // Dump the Software header. if (params.swhdrfn) - writeHdr((void *)swh, params.swhdrfn, SOFTWARE_HDR); + writeHdr((void *) swh, params.swhdrfn, SOFTWARE_HDR); - ssig = (ROM_sw_sig_raw*)(((uint8_t*)swh) + sizeof(ROM_sw_header_raw)); + 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)); + + // Write the HW signatures. if (params.sw_sigfn_p) { getSigRaw(&sigraw, params.sw_sigfn_p); + verbose_print((char *) "signature P = ", sigraw, sizeof(sigraw)); memcpy(ssig->sw_sig_p, sigraw, sizeof(ecc_key_t)); } if (params.sw_sigfn_q) { getSigRaw(&sigraw, params.sw_sigfn_q); + verbose_print((char *) "signature Q = ", sigraw, sizeof(sigraw)); memcpy(ssig->sw_sig_q, sigraw, sizeof(ecc_key_t)); } if (params.sw_sigfn_r) { getSigRaw(&sigraw, params.sw_sigfn_r); + verbose_print((char *) "signature R = ", sigraw, sizeof(sigraw)); memcpy(ssig->sw_sig_r, sigraw, sizeof(ecc_key_t)); } + // Dump the full container header. + if (params.cthdrfn) + writeHdr((void *) c, params.cthdrfn, CONTAINER_HDR); + + // Print container stats. + size = (uint8_t*) ph - (uint8_t *) c; + offset = (uint8_t*) c - (uint8_t *) c; + verbose_msg("HW header size = %4u (%#06x) at offset %4u (%#06x)", + size, size, offset, offset); + size = (uint8_t*) pd - (uint8_t *) ph; + offset = (uint8_t*) ph - (uint8_t *) c; + verbose_msg("Prefix header size = %4u (%#06x) at offset %4u (%#06x)", + size, size, offset, offset); + size = (uint8_t*) swh - (uint8_t *) pd; + offset = (uint8_t*) pd - (uint8_t *) c; + verbose_msg("Prefix data size = %4u (%#06x) at offset %4u (%#06x)", + size, size, offset, offset); + size = (uint8_t*) ssig - (uint8_t *) swh; + offset = (uint8_t*) swh - (uint8_t *) c; + verbose_msg("SW header size = %4u (%#06x) at offset %4u (%#06x)", + size, size, offset, offset); + size = sizeof(ecc_key_t) * ph->sw_key_count; + offset = (uint8_t*) ssig - (uint8_t *) c; + verbose_msg("SW signature size = %4u (%#06x) at offset %4u (%#06x)", + size, size, offset, offset); + + verbose_msg("TOTAL HEADER SIZE = %4d (%#0x)", SECURE_BOOT_HEADERS_SIZE, + SECURE_BOOT_HEADERS_SIZE); + verbose_msg("PAYLOAD SIZE = %4lu (%#0lx)", + be64_to_cpu(swh->payload_size), be64_to_cpu(swh->payload_size)); + verbose_msg("TOTAL CONTAINER SIZE = %4lu (%#0lx)", + be64_to_cpu(c->container_size), be64_to_cpu(c->container_size)); + + // Write container. r = write(fdout, container, SECURE_BOOT_HEADERS_SIZE); - assert(r == 4096); - read(fdin, buf, s.st_size%4096); - write(fdout, buf, s.st_size%4096); - l = s.st_size - s.st_size%4096; + if (r != 4096) + die(EX_SOFTWARE, "Cannot write container (r = %d)", r); + r = read(fdin, buf, payload_st.st_size % 4096); + r = write(fdout, buf, payload_st.st_size % 4096); + l = payload_st.st_size - payload_st.st_size % 4096; while (l) { - read(fdin, buf, 4096); - write(fdout, buf, 4096); - l-=4096; + r = read(fdin, buf, 4096); + r = write(fdout, buf, 4096); + l -= 4096; }; close(fdin); close(fdout); |