summaryrefslogtreecommitdiffstats
path: root/libstb/print-container.c
diff options
context:
space:
mode:
authorStewart Smith <stewart@linux.vnet.ibm.com>2017-12-13 17:26:42 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-12-18 21:30:57 -0600
commit6e05c6f21b34f9c4f6597ace36dfca9624c7923c (patch)
tree4215358d42122cc17c5c6198c1d8b306b1161a88 /libstb/print-container.c
parent63ef6f54445e52e0cd3af4672e73c047484a6a12 (diff)
downloadtalos-skiboot-6e05c6f21b34f9c4f6597ace36dfca9624c7923c.tar.gz
talos-skiboot-6e05c6f21b34f9c4f6597ace36dfca9624c7923c.zip
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/print-container.c')
-rw-r--r--libstb/print-container.c706
1 files changed, 706 insertions, 0 deletions
diff --git a/libstb/print-container.c b/libstb/print-container.c
new file mode 100644
index 00000000..17aea12b
--- /dev/null
+++ b/libstb/print-container.c
@@ -0,0 +1,706 @@
+/* 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include <alloca.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/obj_mac.h>
+#include <openssl/opensslv.h>
+#include <openssl/ossl_typ.h>
+#include <openssl/sha.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "ccan/endian/endian.h"
+#include "ccan/short_types/short_types.h"
+#include "container-utils.h"
+#include "container.h"
+
+#define PASSED 1
+#define FAILED 0
+#define UNATTEMPTED -1
+
+char *progname;
+
+bool print_stats;
+bool verbose, debug;
+int wrap = 100;
+
+ecc_key_t ECDSA_KEY_NULL;
+
+typedef struct keyprops {
+ char index;
+ const char *name;
+ const ecc_key_t *key;
+ const ecc_signature_t *sig;
+} Keyprops;
+
+static void usage(int status);
+
+static bool getPayloadHash(int fdin, unsigned char *md);
+static bool getVerificationHash(char *input, unsigned char *md, int len);
+static bool verify_signature(const char *moniker, const unsigned char *dgst,
+ int dgst_len, const ecc_signature_t sig_raw, const ecc_key_t key_raw);
+
+static void print_bytes(char *lead, uint8_t *buffer, size_t buflen)
+{
+ unsigned int i;
+ unsigned int width;
+ unsigned int leadbytes = strlen(lead);
+ leadbytes = leadbytes > 30 ? 30 : leadbytes;
+ width = (wrap - leadbytes) / 2;
+ width = (width < 1) ? INT_MAX : width;
+
+ fprintf(stdout, "%s", lead);
+ for (i = 1; i < buflen + 1; i++) {
+ fprintf(stdout, "%02x", buffer[i - 1]);
+ if (((i % width) == 0) && (i < buflen))
+ fprintf(stdout, "\n%*c", leadbytes, ' ');
+ }
+ fprintf(stdout, "\n");
+}
+
+bool stb_is_container(const void *buf, size_t size)
+{
+ ROM_container_raw *c;
+
+ c = (ROM_container_raw*) buf;
+ if (!buf || size < SECURE_BOOT_HEADERS_SIZE)
+ return false;
+ if (be32_to_cpu(c->magic_number) != ROM_MAGIC_NUMBER)
+ return false;
+ return true;
+}
+
+int parse_stb_container(const void* data, size_t len,
+ struct parsed_stb_container *c)
+{
+ const size_t prefix_data_min_size = 3 * (EC_COORDBYTES * 2);
+ c->buf = data;
+ c->bufsz = len;
+ c->c = data;
+ c->ph = data += sizeof(ROM_container_raw);
+ c->pd = data += sizeof(ROM_prefix_header_raw)
+ + (c->ph->ecid_count * ECID_SIZE);
+ c->sh = data += prefix_data_min_size
+ + c->ph->sw_key_count * (EC_COORDBYTES * 2);
+ c->ssig = data += sizeof(ROM_sw_header_raw) + c->sh->ecid_count * ECID_SIZE;
+
+ return 0;
+}
+
+static void display_version_raw(const ROM_version_raw v)
+{
+ printf("ver_alg:\n");
+ printf(" version: %04x\n", be16_to_cpu(v.version));
+ printf(" hash_alg: %02x (%s)\n", v.hash_alg,
+ (v.hash_alg == 1) ? "SHA512" : "UNKNOWN");
+ printf(" sig_alg: %02x (%s)\n", v.sig_alg,
+ (v.sig_alg == 1) ? "SHA512/ECDSA-521" : "UNKNOWN");
+}
+
+static void display_container_stats(const struct parsed_stb_container *c)
+{
+ unsigned int size, offset;
+
+ printf("Container stats:\n");
+ size = (uint8_t*) c->ph - (uint8_t *) c->c;
+ offset = (uint8_t*) c->c - (uint8_t *) c->buf;
+ printf(" HW header size = %4u (%#06x) at offset %4u (%#06x)\n",
+ size, size, offset, offset);
+ size = (uint8_t*) c->pd - (uint8_t *) c->ph;
+ offset = (uint8_t*) c->ph - (uint8_t *) c->buf;
+ printf(" Prefix header size = %4u (%#06x) at offset %4u (%#06x)\n",
+ size, size, offset, offset);
+ size = (uint8_t*) c->sh - (uint8_t *) c->pd;
+ offset = (uint8_t*) c->pd - (uint8_t *) c->buf;
+ printf(" Prefix data size = %4u (%#06x) at offset %4u (%#06x)\n",
+ size, size, offset, offset);
+ size = (uint8_t*) c->ssig - (uint8_t *) c->sh;
+ offset = (uint8_t*) c->sh - (uint8_t *) c->buf;
+ printf(" SW header size = %4u (%#06x) at offset %4u (%#06x)\n",
+ size, size, offset, offset);
+ size = sizeof(ecc_key_t) * c->ph->sw_key_count;
+ offset = (uint8_t*) c->ssig - (uint8_t *) c->buf;
+ printf(" SW signature size = %4u (%#06x) at offset %4u (%#06x)\n",
+ size, size, offset, offset);
+
+ printf(" TOTAL HEADER SIZE = %4lu (%#0lx)\n", c->bufsz, c->bufsz);
+ printf(" PAYLOAD SIZE = %4lu (%#0lx)\n",
+ be64_to_cpu(c->sh->payload_size), be64_to_cpu(c->sh->payload_size));
+ printf(" TOTAL CONTAINER SIZE = %4lu (%#0lx)\n",
+ be64_to_cpu(c->c->container_size),
+ be64_to_cpu(c->c->container_size));
+ printf("\n");
+}
+
+static void display_container(struct parsed_stb_container c)
+{
+ unsigned char md[SHA512_DIGEST_LENGTH];
+ void *p;
+
+ printf("Container:\n");
+ printf("magic: 0x%04x\n", be32_to_cpu(c.c->magic_number));
+ printf("version: 0x%02x\n", be16_to_cpu(c.c->version));
+ printf("container_size: 0x%08lx (%lu)\n", be64_to_cpu(c.c->container_size),
+ be64_to_cpu(c.c->container_size));
+ printf("target_hrmor: 0x%08lx\n", be64_to_cpu(c.c->target_hrmor));
+ printf("stack_pointer: 0x%08lx\n", be64_to_cpu(c.c->stack_pointer));
+ print_bytes((char *) "hw_pkey_a: ", (uint8_t *) c.c->hw_pkey_a,
+ sizeof(c.c->hw_pkey_a));
+ print_bytes((char *) "hw_pkey_b: ", (uint8_t *) c.c->hw_pkey_b,
+ sizeof(c.c->hw_pkey_b));
+ print_bytes((char *) "hw_pkey_c: ", (uint8_t *) c.c->hw_pkey_c,
+ sizeof(c.c->hw_pkey_c));
+
+ p = SHA512(c.c->hw_pkey_a, sizeof(ecc_key_t) * 3, md);
+ if (!p)
+ die(EX_SOFTWARE, "%s", "Cannot get SHA512");
+ printf("HW keys hash (calculated):\n");
+ print_bytes((char *) " ", (uint8_t *) md, sizeof(md));
+ printf("\n");
+
+ printf("Prefix Header:\n");
+ display_version_raw(c.ph->ver_alg);
+ printf("code_start_offset: %08lx\n", be64_to_cpu(c.ph->code_start_offset));
+ printf("reserved: %08lx\n", be64_to_cpu(c.ph->reserved));
+ printf("flags: %08x\n", be32_to_cpu(c.ph->flags));
+ printf("sw_key_count: %02x\n", c.ph->sw_key_count);
+ printf("payload_size: %08lx\n", be64_to_cpu(c.ph->payload_size));
+ print_bytes((char *) "payload_hash: ", (uint8_t *) c.ph->payload_hash,
+ sizeof(c.ph->payload_hash));
+ printf("ecid_count: %02x\n", c.ph->ecid_count);
+
+ for (int i = 0; i < c.ph->ecid_count; i++) {
+ printf("ecid: ");
+ print_bytes((char *) "ecid: ",
+ (uint8_t *) c.ph->ecid[i].ecid, sizeof(c.ph->ecid[i].ecid));
+ printf("\n");
+ }
+ printf("\n");
+
+ printf("Prefix Data:\n");
+ print_bytes((char *) "hw_sig_a: ", (uint8_t *) c.pd->hw_sig_a, sizeof(c.pd->hw_sig_a));
+ print_bytes((char *) "hw_sig_b: ", (uint8_t *) c.pd->hw_sig_b, sizeof(c.pd->hw_sig_b));
+ print_bytes((char *) "hw_sig_c: ", (uint8_t *) c.pd->hw_sig_c, sizeof(c.pd->hw_sig_c));
+
+ if (c.ph->sw_key_count >=1)
+ print_bytes((char *) "sw_pkey_p: ", (uint8_t *) c.pd->sw_pkey_p, sizeof(c.pd->sw_pkey_p));
+ if (c.ph->sw_key_count >=2)
+ print_bytes((char *) "sw_pkey_q: ", (uint8_t *) c.pd->sw_pkey_q, sizeof(c.pd->sw_pkey_q));
+ if (c.ph->sw_key_count >=3)
+ print_bytes((char *) "sw_pkey_r: ", (uint8_t *) c.pd->sw_pkey_r, sizeof(c.pd->sw_pkey_r));
+
+ printf("\n");
+
+ printf("Software Header:\n");
+ display_version_raw(c.sh->ver_alg);
+ printf("code_start_offset: %08lx\n", be64_to_cpu(c.sh->code_start_offset));
+ printf("reserved: %08lx\n", be64_to_cpu(c.sh->reserved));
+ printf("reserved (ASCII): %.8s\n", (char *) &(c.sh->reserved));
+ printf("flags: %08x\n", be32_to_cpu(c.sh->flags));
+ printf("reserved_0: %02x\n", c.sh->reserved_0);
+ printf("payload_size: %08lx (%lu)\n", be64_to_cpu(c.sh->payload_size),
+ be64_to_cpu(c.sh->payload_size));
+ print_bytes((char *) "payload_hash: ", (uint8_t *) c.sh->payload_hash,
+ sizeof(c.sh->payload_hash));
+ printf("ecid_count: %02x\n", c.sh->ecid_count);
+
+ for (int i = 0; i < c.sh->ecid_count; i++) {
+ printf("ecid: ");
+ print_bytes((char *) "ecid: ",
+ (uint8_t *) c.sh->ecid[i].ecid, sizeof(c.sh->ecid[i].ecid));
+ printf("\n");
+ }
+ printf("\n");
+
+ printf("Software Signatures:\n");
+ print_bytes((char *) "sw_sig_p: ", (uint8_t *) c.ssig->sw_sig_p,
+ sizeof(c.ssig->sw_sig_p));
+ print_bytes((char *) "sw_sig_q: ", (uint8_t *) c.ssig->sw_sig_q,
+ sizeof(c.ssig->sw_sig_q));
+ print_bytes((char *) "sw_sig_r: ", (uint8_t *) c.ssig->sw_sig_r,
+ sizeof(c.ssig->sw_sig_r));
+ printf("\n");
+
+ if (print_stats)
+ display_container_stats(&c);
+}
+
+static bool validate_container(struct parsed_stb_container c, int fdin)
+{
+ static int n;
+ static int status = true;
+
+ Keyprops *k;
+
+ Keyprops hwKeylist[] = {
+ { 'a', "HW_key_A", &(c.c->hw_pkey_a), &(c.pd->hw_sig_a) },
+ { 'b', "HW_key_B", &(c.c->hw_pkey_b), &(c.pd->hw_sig_b) },
+ { 'c', "HW_key_C", &(c.c->hw_pkey_c), &(c.pd->hw_sig_c) },
+ { 0, NULL, NULL, NULL },
+ };
+ Keyprops swKeylist[] = {
+ { 'p', "SW_key_P", &(c.pd->sw_pkey_p), &(c.ssig->sw_sig_p) },
+ { 'q', "SW_key_Q", &(c.pd->sw_pkey_q), &(c.ssig->sw_sig_q) },
+ { 'r', "SW_key_R", &(c.pd->sw_pkey_r), &(c.ssig->sw_sig_r) },
+ { 0, NULL, NULL, NULL },
+ };
+
+ void *md = alloca(SHA512_DIGEST_LENGTH);
+ void *p;
+
+ // Get Prefix header hash.
+ p = SHA512((uint8_t *) c.ph, sizeof(ROM_prefix_header_raw), md);
+ if (!p)
+ die(EX_SOFTWARE, "%s", "Cannot get SHA512");
+ if (verbose) print_bytes((char *) "PR header hash = ", (uint8_t *) md,
+ SHA512_DIGEST_LENGTH);
+
+ // Verify HW key sigs.
+ for (k = hwKeylist; k->index; k++) {
+
+ if (memcmp(k->key, &ECDSA_KEY_NULL, sizeof(ecc_key_t)))
+ status = verify_signature(k->name, md, SHA512_DIGEST_LENGTH,
+ *(k->sig), *(k->key)) && status;
+ else
+ if (verbose) printf("%s is NULL, skipping signature check.\n", k->name);
+ }
+ if (verbose) printf("\n");
+
+ // Get SW header hash.
+ p = SHA512((uint8_t *) c.sh, sizeof(ROM_sw_header_raw), md);
+ if (!p)
+ die(EX_SOFTWARE, "%s", "Cannot get SHA512");
+ if (verbose) print_bytes((char *) "SW header hash = ", (uint8_t *) md,
+ SHA512_DIGEST_LENGTH);
+
+ // Verify SW key sigs.
+ for (k = swKeylist, n = 1; k->index && n <= c.ph->sw_key_count; k++, n++) {
+
+ if (memcmp(k->key, &ECDSA_KEY_NULL, sizeof(ecc_key_t)))
+ status = verify_signature(k->name, md, SHA512_DIGEST_LENGTH,
+ *(k->sig), *(k->key)) && status;
+ else
+ if (verbose) printf("%s is NULL, skipping\n", k->name);
+ }
+ if (verbose) printf("\n");
+
+ // Verify Payload hash.
+ status = getPayloadHash(fdin, md) && status;
+ if (verbose) print_bytes((char *) "Payload hash = ", (uint8_t *) md,
+ SHA512_DIGEST_LENGTH);
+
+ if (memcmp((uint8_t *) c.sh->payload_hash, md, SHA512_DIGEST_LENGTH)) {
+ if (verbose)
+ printf("Payload hash does not agree with value in SW header: MISMATCH\n");
+ status = false;
+ } else {
+ if (verbose)
+ printf("Payload hash agrees with value in SW header: VERIFIED ./\n");
+ status = status && true;
+ }
+ if (verbose) printf("\n");
+
+ // Verify SW keys hash.
+ p = SHA512(c.pd->sw_pkey_p, sizeof(ecc_key_t) * c.ph->sw_key_count, md);
+ if (!p)
+ die(EX_SOFTWARE, "%s", "Cannot get SHA512");
+ if (verbose) print_bytes((char *) "SW keys hash = ", (uint8_t *) md,
+ SHA512_DIGEST_LENGTH);
+
+ if (memcmp((uint8_t *) c.ph->payload_hash, md, SHA512_DIGEST_LENGTH)) {
+ if (verbose)
+ printf("SW keys hash does not agree with value in Prefix header: MISMATCH\n");
+ status = false;
+ } else {
+ if (verbose)
+ printf("SW keys hash agrees with value in Prefix header: VERIFIED ./\n");
+ status = status && true;
+ }
+ if (verbose) printf("\n");
+ return status;
+}
+
+static bool verify_container(struct parsed_stb_container c, char * verify)
+{
+ static int status = false;
+
+ void *md = alloca(SHA512_DIGEST_LENGTH);
+ void *p;
+ void *md_verify;
+
+ p = SHA512(c.c->hw_pkey_a, sizeof(ecc_key_t) * 3, md);
+ if (!p)
+ die(EX_SOFTWARE, "%s", "Cannot get SHA512");
+ if (verbose) print_bytes((char *) "HW keys hash = ", (uint8_t *) md,
+ SHA512_DIGEST_LENGTH);
+
+ md_verify = alloca(SHA512_DIGEST_LENGTH);
+ getVerificationHash(verify, md_verify, SHA512_DIGEST_LENGTH);
+
+ if (memcmp((uint8_t *) md_verify, md, SHA512_DIGEST_LENGTH )) {
+ if (verbose)
+ printf("HW keys hash does not agree with provided value: MISMATCH\n");
+ } else {
+ if (verbose)
+ printf("HW keys hash agrees with provided value: VERIFIED ./\n");
+ status = true;
+ }
+ if (verbose) printf("\n");
+ return status;
+}
+
+static bool verify_signature(const char *moniker, const unsigned char *dgst,
+ int dgst_len, const ecc_signature_t sig_raw, const ecc_key_t key_raw)
+{
+ int r;
+ bool status = false;
+ BIGNUM *r_bn, *s_bn;
+ ECDSA_SIG* ecdsa_sig;
+ EC_KEY *ec_key;
+ const EC_GROUP *ec_group;
+ unsigned char *buffer;
+ BIGNUM *key_bn;
+ EC_POINT *ec_point;
+
+ // Convert the raw sig to a structure that can be handled by openssl.
+ debug_print((char *) "Raw sig = ", (uint8_t *) sig_raw,
+ sizeof(ecc_signature_t));
+
+ r_bn = BN_new();
+ s_bn = BN_new();
+
+ BN_bin2bn((const unsigned char*) &sig_raw[0], 66, r_bn);
+ BN_bin2bn((const unsigned char*) &sig_raw[66], 66, s_bn);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ ecdsa_sig = ECDSA_SIG_new();
+ ECDSA_SIG_set0(ecdsa_sig, r_bn, s_bn);
+#else
+ ecdsa_sig = malloc(sizeof(ECDSA_SIG));
+ ecdsa_sig->r = r_bn;
+ ecdsa_sig->s = s_bn;
+#endif
+
+ // Convert the raw key to a structure that can be handled by openssl.
+ debug_print((char *) "Raw key = ", (uint8_t *) key_raw,
+ sizeof(ecc_key_t));
+
+ ec_key = EC_KEY_new();
+ if (!ec_key)
+ die(EX_SOFTWARE, "%s", "Cannot EC_KEY_new");
+
+ ec_group = EC_GROUP_new_by_curve_name(NID_secp521r1);
+ if (!ec_group)
+ die(EX_SOFTWARE, "%s", "Cannot EC_GROUP_new_by_curve_name");
+
+ r = EC_KEY_set_group(ec_key, ec_group);
+ if (r == 0)
+ die(EX_SOFTWARE, "%s", "Cannot EC_KEY_set_group");
+
+ // Add prefix 0x04, for uncompressed key.
+ buffer = alloca(sizeof(ecc_key_t) + 1);
+ *buffer = 0x04;
+ memcpy(buffer + 1, key_raw, sizeof(ecc_key_t));
+
+ key_bn = BN_new();
+ BN_bin2bn((const unsigned char*) buffer, EC_COORDBYTES * 2 + 1, key_bn);
+
+ ec_point = EC_POINT_bn2point(ec_group, key_bn, NULL, NULL);
+ if (!ec_point)
+ die(EX_SOFTWARE, "%s", "Cannot EC_POINT_bn2point");
+
+ r = EC_KEY_set_public_key(ec_key, (const EC_POINT*) ec_point);
+ if (r == 0)
+ die(EX_SOFTWARE, "%s", "Cannot EC_KEY_set_public_key");
+
+ // Verify the signature.
+ r = ECDSA_do_verify(dgst, dgst_len, ecdsa_sig, ec_key);
+ if (r == 1) {
+ if (verbose) printf("%s signature is good: VERIFIED ./\n", moniker);
+ status = true;
+ } else if (r == 0) {
+ if (verbose) printf("%s signature FAILED to verify.\n", moniker);
+ status = false;
+ } else {
+ die(EX_SOFTWARE, "%s", "Cannot ECDSA_do_verify");
+ }
+
+ BN_free(r_bn);
+ BN_free(s_bn);
+ BN_free(key_bn);
+
+ EC_KEY_free(ec_key);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ ECDSA_SIG_free(ecdsa_sig);
+#else
+ free(ecdsa_sig);
+#endif
+ return status;
+}
+
+static bool getPayloadHash(int fdin, unsigned char *md)
+{
+ struct stat payload_st;
+ void *payload;
+ int r;
+ void *p;
+
+ r = fstat(fdin, &payload_st);
+ if (r != 0)
+ die(EX_NOINPUT, "Cannot stat payload file at descriptor: %d (%s)", fdin,
+ strerror(errno));
+
+ payload = mmap(NULL, payload_st.st_size - SECURE_BOOT_HEADERS_SIZE,
+ PROT_READ, MAP_PRIVATE, fdin, SECURE_BOOT_HEADERS_SIZE);
+ if (!payload)
+ die(EX_OSERR, "Cannot mmap file at descriptor: %d (%s)", fdin,
+ strerror(errno));
+
+ p = SHA512(payload, payload_st.st_size - SECURE_BOOT_HEADERS_SIZE, md);
+ if (!p)
+ die(EX_SOFTWARE, "%s", "Cannot get SHA512");
+
+ return true;
+}
+
+static bool getVerificationHash(char *input, unsigned char *md, int len)
+{
+ char buf[len * 2 + 1 + 2]; // allow trailing \n and leading "0x"
+ char *p;
+ struct stat s;
+ int r;
+
+ if (isValidHex(input, len)) {
+ p = input;
+ } else {
+ int fdin = open(input, O_RDONLY);
+ if (fdin <= 0)
+ die(EX_NOINPUT, "%s",
+ "Verify requested but no valid hash or hash file provided");
+
+ r = fstat(fdin, &s);
+ if (r != 0)
+ die(EX_NOINPUT, "Cannot stat hash file: %s (%s)", input,
+ strerror(errno));
+ if ((size_t) s.st_size > (sizeof(buf)))
+ die(EX_DATAERR,
+ "Verify hash file \"%s\" invalid size: expected a %d byte hexadecimal value",
+ input, len);
+
+ r = read(fdin, buf, s.st_size);
+ if (r <= 0)
+ die(EX_NOINPUT, "Cannot read hash file: %s (%s)", input,
+ strerror(errno));
+ p = (char *) buf;
+
+ for (unsigned int i = 0; i < sizeof(buf); i++) // strip newline char
+ if (buf[i] == '\n')
+ buf[i] = '\0';
+
+ close(fdin);
+ }
+
+ // Convert hexascii to binary.
+ if (isValidHex(p, len)) {
+ if (!strncmp(p, "0x", 2)) // skip leading "0x"
+ p += 2;
+ for (int count = 0; count < len; count++) {
+ sscanf(p, "%2hhx", &md[count]);
+ p += 2;
+ }
+ } else
+ die(EX_DATAERR,
+ "Verify hash file \"%s\" invalid data: expected a %d byte hexadecimal value",
+ input, len);
+
+ return true;
+}
+
+__attribute__((__noreturn__)) static 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"
+ " -h, --help display this message and exit\n"
+ " -v, --verbose show verbose output\n"
+ " -d, --debug show additional debug output\n"
+ " -w, --wrap column at which to wrap long output (wrap=0 => unlimited)\n"
+ " -s, --stats additionally print container stats\n"
+ " -I, --imagefile containerized image to display (input)\n"
+ " --validate perform all checks to ensure is container valid for secure boot\n"
+ " --verify value, or filename containing value, of the HW Keys hash to\n"
+ " verify the container against. must be valid 64 byte hexascii.\n"
+ "\n");
+ };
+ exit(status);
+}
+
+static struct option const opts[] = {
+ { "help", no_argument, 0, 'h' },
+ { "verbose", no_argument, 0, 'v' },
+ { "debug", no_argument, 0, 'd' },
+ { "wrap", required_argument, 0, 'w' },
+ { "stats", no_argument, 0, 's' },
+ { "imagefile", required_argument, 0, 'I' },
+ { "validate", no_argument, 0, 128 },
+ { "verify", required_argument, 0, 129 },
+ { "no-print", no_argument, 0, 130 },
+ { "print", no_argument, 0, 131 },
+ { NULL, 0, NULL, 0 }
+};
+
+static struct {
+ char *imagefn;
+ bool validate;
+ char *verify;
+ bool print_container;
+} params;
+
+
+int main(int argc, char* argv[])
+{
+ int indexptr;
+ int r;
+ struct stat st;
+ void *container;
+ struct parsed_stb_container c;
+ int container_status = EX_OK;
+ int validate_status = UNATTEMPTED;
+ int verify_status = UNATTEMPTED;
+ int fdin;
+
+ params.print_container = true;
+
+ progname = strrchr(argv[0], '/');
+ if (progname != NULL)
+ ++progname;
+ else
+ progname = argv[0];
+
+ while (1) {
+ int opt;
+ opt = getopt_long(argc, argv, "hvdw:sI:", opts, &indexptr);
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'h':
+ case '?':
+ usage(EX_OK);
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'd':
+ debug = true;
+ break;
+ case 'w':
+ wrap = atoi(optarg);
+ wrap = (wrap < 2) ? INT_MAX : wrap;
+ break;
+ case 's':
+ print_stats = true;
+ break;
+ case 'I':
+ params.imagefn = optarg;
+ break;
+ case 128:
+ params.validate = true;
+ break;
+ case 129:
+ params.verify = optarg;
+ break;
+ case 130:
+ params.print_container = false;
+ break;
+ case 131:
+ params.print_container = true;
+ break;
+ default:
+ usage(EX_USAGE);
+ }
+ }
+
+ fdin = open(params.imagefn, O_RDONLY);
+ if (fdin <= 0)
+ die(EX_NOINPUT, "Cannot open container file: %s (%s)", params.imagefn,
+ strerror(errno));
+
+ r = fstat(fdin, &st);
+ if (r != 0)
+ die(EX_NOINPUT, "Cannot stat container file: %s (%s)", params.imagefn,
+ strerror(errno));
+
+ container = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fdin, 0);
+ if (!container)
+ die(EX_OSERR, "Cannot mmap file: %s (%s)", params.imagefn,
+ strerror(errno));
+
+ if (!stb_is_container(container, SECURE_BOOT_HEADERS_SIZE))
+ die(EX_DATAERR, "%s", "Not a container, missing magic number");
+
+ if (parse_stb_container(container, SECURE_BOOT_HEADERS_SIZE, &c) != 0)
+ die(EX_DATAERR, "%s", "Failed to parse container");
+
+ if (params.print_container)
+ display_container(c);
+
+ if (params.validate)
+ validate_status = validate_container(c, fdin);
+
+ if (params.verify)
+ verify_status = verify_container(c, params.verify);
+
+ if ((validate_status != UNATTEMPTED) || (verify_status != UNATTEMPTED)) {
+
+ printf("Container validity check %s. Container verification check %s.\n\n",
+ (validate_status == UNATTEMPTED) ?
+ "not attempted" :
+ ((validate_status == PASSED) ? "PASSED" : "FAILED"),
+ (verify_status == UNATTEMPTED) ?
+ "not attempted" :
+ ((verify_status == PASSED) ? "PASSED" : "FAILED"));
+
+ if ((validate_status == FAILED) || (verify_status == FAILED))
+ container_status = 1;
+ }
+
+ close(fdin);
+ return container_status;
+}
OpenPOWER on IntegriCloud