[Skiboot] [PATCH v2] libstb/(create|print)-container: Sync with sb-signing-utils

Stewart Smith stewart at linux.vnet.ibm.com
Wed Dec 13 20:41:56 AEDT 2017


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 at linux.vnet.ibm.com>
Signed-off-by: Stewart Smith <stewart at linux.vnet.ibm.com>
---
 Makefile.main                     |   4 +-
 libstb/Makefile.inc               |   8 +-
 libstb/container-utils.c          | 137 ++++++++
 libstb/container-utils.h          |  41 +++
 libstb/create-container.c         | 541 +++++++++++++++++++++--------
 libstb/keys/README.md             | 147 ++++++++
 libstb/keys/hw_key_a.key          |  25 ++
 libstb/keys/hw_key_b.key          |  26 ++
 libstb/keys/hw_key_c.key          |  26 ++
 libstb/keys/sw_key_a.key          |  16 +
 libstb/print-container.c          | 706 ++++++++++++++++++++++++++++++++++++++
 libstb/sign-with-local-keys.sh    |  16 +-
 libstb/test/Makefile.check        |  12 +-
 libstb/test/print-stb-container.c | 208 -----------
 libstb/test/t.container.out       |  50 ++-
 15 files changed, 1575 insertions(+), 388 deletions(-)
 create mode 100644 libstb/container-utils.c
 create mode 100644 libstb/container-utils.h
 create mode 100644 libstb/keys/README.md
 create mode 100644 libstb/keys/hw_key_a.key
 create mode 100644 libstb/keys/hw_key_b.key
 create mode 100644 libstb/keys/hw_key_c.key
 create mode 100644 libstb/keys/sw_key_a.key
 create mode 100644 libstb/print-container.c
 delete mode 100644 libstb/test/print-stb-container.c

diff --git a/Makefile.main b/Makefile.main
index 73c91962ed83..040bbd0742b9 100644
--- a/Makefile.main
+++ b/Makefile.main
@@ -207,10 +207,10 @@ $(TARGET).lid: $(TARGET).elf
 	$(call Q,OBJCOPY, $(OBJCOPY) -O binary -S $^ $@, $@)
 
 $(TARGET).lid.stb: $(TARGET).lid libstb/create-container
-	$(call Q,STB-UNSIGNED-CONTAINER,./libstb/create-container --payload $< --imagefile $@,$@)
+	$(call Q,STB-DEVELOPMENT-SIGNED-CONTAINER,$(SRC)/libstb/sign-with-local-keys.sh $< $@ $(SRC)/libstb/keys/,$@)
 
 $(TARGET).lid.xz.stb: $(TARGET).lid.xz libstb/create-container
-	$(call Q,STB-UNSIGNED-CONTAINER,./libstb/create-container --payload $< --imagefile $@,$@)
+	$(call Q,STB-DEVELOPMENT-SIGNED-CONTAINER,$(SRC)/libstb/sign-with-local-keys.sh $< $@ $(SRC)/libstb/keys/,$@)
 
 $(TARGET).tmp.elf: $(ALL_OBJS_1) $(TARGET).lds $(KERNEL)
 	$(call Q,LD, $(CC) $(LDFLAGS) -T $(TARGET).lds $(ALL_OBJS_1) -o $@, $@)
diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc
index 12b15098ae63..3ea530ad7933 100644
--- a/libstb/Makefile.inc
+++ b/libstb/Makefile.inc
@@ -14,9 +14,13 @@ include $(SRC)/$(LIBSTB_DIR)/tss/Makefile.inc
 
 $(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS) $(MBEDTLS)
 
-libstb/create-container: libstb/create-container.c
+libstb/create-container: libstb/create-container.c libstb/container-utils.c
 	$(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) \
-	-Wpadded -O0 -g -I$(SRC) -I$(SRC)/include -o $@ $< -lssl -lcrypto,$<)
+	-Wpadded -O0 -g -I$(SRC) -I$(SRC)/include -o $@ $^ -lssl -lcrypto,$<)
+
+libstb/print-container: libstb/print-container.c libstb/container-utils.c
+	$(call Q, HOSTCC , $(HOSTCC) $(HOSTCFLAGS) \
+	-O0 -g -I$(SRC) -I$(SRC)/include -o $@ $^ -lssl -lcrypto, $<)
 
 clean: create-container-clean
 
diff --git a/libstb/container-utils.c b/libstb/container-utils.c
new file mode 100644
index 000000000000..d2c1f9d9b211
--- /dev/null
+++ b/libstb/container-utils.c
@@ -0,0 +1,137 @@
+/* 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 <regex.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "ccan/short_types/short_types.h"
+#include "container-utils.h"
+#include "container.h"
+
+extern char *progname;
+
+extern bool verbose, debug;
+extern int wrap;
+
+
+void hex_print(char *lead, unsigned char *buffer, size_t buflen)
+{
+	unsigned int i, indent = 4;
+	char prelead[100];
+	const char *pad;
+	int col;
+
+	snprintf(prelead, 100, "--> %s: ", progname);
+
+	pad = (((strlen(prelead) + strlen(lead)) % 2) == 0) ? "" : " ";
+	wrap = ((wrap % 2) == 0) ? wrap : wrap - 1;
+	indent = ((indent % 2) == 0) ? indent : indent - 1;
+	col = fprintf(stdout, "%s%s%s", prelead, lead, pad);
+	for (i = 1; i < buflen + 1; i++) {
+		fprintf(stdout, "%02x", buffer[i - 1]);
+		col = col + 2;
+		if (((col % wrap) == 0) && (i < buflen)) {
+			fprintf(stdout, "\n%*c", indent, ' ');
+			col = indent;
+		}
+	}
+	fprintf(stdout, "\n");
+}
+
+void verbose_print(char *lead, unsigned char *buffer, size_t buflen)
+{
+	if (verbose)
+		hex_print(lead, buffer, buflen);
+}
+
+void debug_print(char *lead, unsigned char *buffer, size_t buflen)
+{
+	if (debug)
+		hex_print(lead, buffer, buflen);
+}
+
+/**
+ * Validate hexadecimal ASCII input of a given length.
+ * - len is the byte len of the resulting value, not the len of the hexascii.
+ * - len = 0 means validate input of arbitrary length.
+*/
+int isValidHex(char *input, int len) {
+	int r;
+	size_t maxlen = 512; // sane limit
+	regex_t regexpr;
+	char pattern[48];
+	char multiplier[8];
+	bool result = false;
+
+	if ((strnlen(input, maxlen) > maxlen * 2) || (len > (int) maxlen))
+		die(EX_DATAERR, "input exceeded max length: %lu", maxlen);
+
+	if (len > 0)
+		sprintf(multiplier, "{%d}", len * 2); // allow this (byte) len only
+	else
+		sprintf(multiplier, "+"); // unlimited
+
+	sprintf(pattern, "^(0x|0X)?[a-fA-F0-9]%s$", multiplier);
+
+	if ((r = regcomp(&regexpr, pattern, REG_EXTENDED | REG_NOSUB)))
+		die(EX_SOFTWARE, "%s", "failure to compile regex");
+
+	if (!(r = regexec(&regexpr, input, 0, NULL, 0)))
+		result = true;
+
+	regfree(&regexpr);
+	return result;
+}
+
+/**
+ * Validate ASCII input up to a given length.
+ * - len is the expected len of the ascii input.
+ * - len = 0 means validate input of arbitrary length.
+ * - NOTE: not all ascii chars are allowed here.
+ */
+int isValidAscii(char *input, int len) {
+	int r;
+	size_t maxlen = 256; // sane limit
+	regex_t regexpr;
+	char pattern[48];
+	char multiplier[8];
+	bool result = false;
+
+	if ((strnlen(input, maxlen) > maxlen) || (len > (int) maxlen))
+		die(EX_DATAERR, "input exceeded max length: %lu", maxlen);
+
+	if (len > 0)
+		sprintf(multiplier, "{,%d}", len);  // allow *up to* this len
+	else
+		sprintf(multiplier, "+"); // unlimited
+
+	sprintf(pattern, "^[a-zA-Z0-9_+-]%s$", multiplier);
+
+	if ((r = regcomp(&regexpr, pattern, REG_EXTENDED | REG_NOSUB)))
+		die(EX_SOFTWARE, "%s", "failure to compile regex");
+
+	if (!(r = regexec(&regexpr, input, 0, NULL, 0)))
+		result = true;
+
+	regfree(&regexpr);
+	return result;
+}
diff --git a/libstb/container-utils.h b/libstb/container-utils.h
new file mode 100644
index 000000000000..d3337b10dd55
--- /dev/null
+++ b/libstb/container-utils.h
@@ -0,0 +1,41 @@
+/* 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.
+ */
+
+#ifndef _CREATE_CONTAINER_UTILS_H
+#define _CREATE_CONTAINER_UTILS_H
+
+#include <stdio.h>
+#include <unistd.h>
+
+#define die(status, msg, ...)						\
+        { fprintf(stderr, "error: %s.%s() line %d: " msg "\n", progname, \
+        		__func__, __LINE__, __VA_ARGS__); exit(status); }
+
+#define debug_msg(msg, ...) \
+        if (debug) fprintf(stderr, "--> %s.%s(): " msg "\n", progname, \
+        		__func__, __VA_ARGS__);
+
+#define verbose_msg(msg, ...) \
+        if (verbose) fprintf(stdout, "--> %s: " msg "\n", progname, \
+        		__VA_ARGS__);
+
+void hex_print(char *lead, unsigned char *buffer, size_t buflen);
+void verbose_print(char *lead, unsigned char *buffer, size_t buflen);
+void debug_print(char *lead, unsigned char *buffer, size_t buflen);
+int isValidHex(char *input, int len);
+int isValidAscii(char *input, int len);
+
+#endif /* _CREATE_CONTAINER_UTILS_H */
diff --git a/libstb/create-container.c b/libstb/create-container.c
index 5cf80a060625..4207e1c0a4b6 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);
diff --git a/libstb/keys/README.md b/libstb/keys/README.md
new file mode 100644
index 000000000000..f70e6c28d12a
--- /dev/null
+++ b/libstb/keys/README.md
@@ -0,0 +1,147 @@
+# Important Information About Secure and Trusted Boot And Signing Keys
+
+## Background
+
+IBM P8 OpenPOWER systems support a limited set of Secure and Trusted Boot
+functionality.  Secure Boot implements a processor based chain of trust.  The
+chain starts with an implicitly trusted component with other components being
+authenticated and integrity checked before being executed on the host processor
+cores.  At the root of this trust chain is the Host Platform Core Root of Trust
+for Measurement (CRTM).  Immutable Read Only Memory (ROM - fixed in the POWER
+processor chip) verifies the initial firmware load.  That firmware verifies
+cryptographic signatures on all subsequent "to be trusted" firmware that is
+loaded for execution on the P8 cores.  Trusted Boot also makes use of this same
+CRTM by measuring and recording FW images via a Trusted Platform Module (TPM)
+before control is passed on to the next layer in the boot stack.  The CRTM
+design is based on a Public Key Infrastructure (PKI) process to validate the
+firmware images before they are executed.  This process makes use of a set of
+hardware and firmware asymmetric keys.  Multiple organizations will want to
+deliver POWER hardware, digitally signed firmware, signed boot code,
+hypervisors, and operating systems.  Each platform manufacturer wants to
+maintain control over its own code and sign it with its own keys.  A single key
+hash is stored in host processor module SEEPROM representing the anchoring root
+set of hardware keys.  The P8 Trusted Boot supports a key management flow that
+makes use of two kinds of hardware root keys, a wide open, well-known, openly
+published public/private key pair (imprint keys) and a set of production keys
+where the private key is protected by a hardware security module (HSM) internal
+to the manufacturing facility of the key owner.
+
+## Purpose Of Imprint Public/Private Keys
+
+It is critical to note that the imprint keys are not to be used for production.
+These are strictly for manufacturing and development level support given the
+open nature of the private part of the Hardware keys.  This allows developers
+and testers to sign images and create builds for Secure and Trusted Boot
+development lab testing.  Systems must be transitioned to production level
+keys for customer environments.
+
+## Manufacturer Key Management Role
+
+If a system is shipped from the System Manufacturer with imprint keys installed
+rather than production level hardware keys, the system must be viewed as running
+with a set of well-known default keys and vulnerable to exploitation.  The
+System Access Administrator must work with the System Manufacturer to insure
+that a key transition process is utilized once a hardware based chain of trust
+is to be enabled as part of Secure or Trusted Boot functionality.
+
+## Intentional Public Release Of Imprint Public/Private Keys
+
+All public and private keys in this directory are being intentionally released
+to enable the developer community to sign code images.  For true security, a
+different set of production signing keys should be used, and the private
+production signing key should be carefully guarded.  Currently, we do not yet
+support production key signing, only development signing.
+
+### Imprint Private Keys
+
+#### Hardware Private Keys
+
+The following files contain the Imprint private keys, in PEM format:
+
+hw_key_a.key
+hw_key_b.key
+hw_key_c.key
+
+#### Software Private Keys
+
+The project does not contain any Software keys.  The sample scripts reuse the
+Hardware keys where input is required for the Software keys.  To generate your
+own software keys use the openssl "ecparam" command.  The following commands
+will generate private software keys P, Q and R:
+
+$ openssl ecparam -genkey -outform pem -noout -name secp521r1 -out sw_key_p.key
+$ openssl ecparam -genkey -outform pem -noout -name secp521r1 -out sw_key_q.key
+$ openssl ecparam -genkey -outform pem -noout -name secp521r1 -out sw_key_r.key
+
+OpenPOWER secure boot supports three keys for Hardware (HW) key signing and (up
+to) three keys for Software (SW) key signing,  This permits a "separation of
+duties" in the firmware signing process, if such a separation is desired.  All
+three HW keys are required, but the SW keys allow for the use of one, two or
+three keys.  A signature is required (i.e. must be present in the container) by
+*all three* firmare keys, and by every (1-3) SW key in use, to create a
+container that will boot with secure mode on.  If a separation of duties is not
+required, the signer may use the same key for all three required HW keys, and
+for the (1-3) required SW keys.  The container will boot as long as all required
+signatures are present.
+
+#### Hardware and Software Public Keys
+
+The public keys can be easily extracted from the private keys.  Use the openssl
+"pkey" command, for example:
+
+$ openssl pkey -pubout -inform pem -outform pem -in sw_key_p.key -out sw_key_p.pub
+
+To build and sign a container locally, the public keys are not required.  The
+signing tool will automatically extract the public key from the private key (for
+inclusion in the container) and will use the private key to create the required
+signatures.
+
+The recommended process for production keys is to not have the private keys
+present on thy system used to build firmware.  In this mode you want to create
+the signatures independently from the op-build process.  Create your private HW
+and SW keys as described above.  Protect the private portion of the key (the
+private key).  Add the public portion of the key (the public key) to ./keys
+directory.  The signing tool will use the public key to populate the container.
+
+In this mode of operation you must sign the Prefix header and Software header
+with the HW and SW keys, respectively.  TODO: Instructions to follow.
+
+#### Hardware Keys Hash
+
+As mentioned above, a single key hash is stored in host processor module SEEPROM
+representing the anchoring root set of HW keys.  This is a 64 byte, SHA512 hash
+of the three HW keys.  On a running OpenPOWER machine this hash may be read from
+an entry in the device tree:
+
+# cat /proc/device-tree/ibm,secureboot/hw-key-hash | xxd -p
+40d487ff7380ed6ad54775d5795fea0de2f541fea9db06b8466a42a320e6
+5f75b48665460017d907515dc2a5f9fc50954d6ee0c9b67d219dfb708535
+1d01d6d1
+
+Note this file is readable both from the target OS and the petitboot shell
+environment.
+
+OpenPOWER secure boot protects the containerized firmware by comparing this hash
+to the hash of the HW public keys in the container (as well as verifying the
+signatures, of course).  If the hashes don't match, the machine won't boot.  For
+this reason you might want to check that the HW keys hash will be correct in
+container you are building.
+
+To check the hash of your HW keys, run the "create-container" tool from the
+sb-signing-utils project.  This command will create no container, but will
+display the SHA512 hash of the input keys:
+
+$ create-container -v -w0 -a /tmp/keys/hw_key_a.key \
+                          -b /tmp/keys/hw_key_b.key \
+                          -c /tmp/keys/hw_key_c.key \
+                          --payload /dev/zero --imagefile /dev/null \
+                          | grep "HW keys hash"
+
+HW keys hash = 40d487ff7380ed6a...
+
+Note this command will work with either public or private keys as input.  The
+tool will also display the hash during normal container creation, when the
+program is run in verbose mode.
+
+To check the hash of the HW keys in an existing container, run the
+"print-container" tool: TODO
diff --git a/libstb/keys/hw_key_a.key b/libstb/keys/hw_key_a.key
new file mode 100644
index 000000000000..8cfd2f2c7878
--- /dev/null
+++ b/libstb/keys/hw_key_a.key
@@ -0,0 +1,25 @@
+!!! Important WARNING About This Private Key !!!
+
+DO NOT STRIP THIS WARNING FROM THIS PRIVATE KEY
+
+This private is being intentionally released by IBM to enable the developer
+community to sign code images.  For true security, a different set of production
+signing keys should be used, and the private production signing key should be
+carefully guarded.
+
+-----BEGIN EC PRIVATE KEY-----
+MIICnAIBAQRBVvu38Sbtau77TPvsvEmYHwAD8WY12vTjRE6SowkePCI0+3k5bawC
+J9rKnafuMLCxE2SzTh5JPonVKhBPZeUpaOugggHGMIIBwgIBATBNBgcqhkjOPQEB
+AkIB////////////////////////////////////////////////////////////
+//////////////////////////8wgZ4EQgH/////////////////////////////
+/////////////////////////////////////////////////////////ARBUZU+
+uWGOHJofkpohoLaFQO6i2nJbmbMV87i0iZGO8QnhVhk5Uex+k3sWUsC9O7G/BzVz
+34g9LDTx70Uf1GtQPwADFQDQnogAKRy4U5bMZxc5MoSqoNpkugSBhQQAxoWOBrcE
+BOnNnj7LZiOVtEKcZIE5BT+1Ifgor2BrTT26oUted+/nWSj+HcEnov+o3jNIs8GF
+akKb+X5+McLlvWYBGDkpaniaO8AEXIpftCx9G9mY9URJV5tEaBevvRcnPmYsl+5y
+mV70JkDFULkBP60HYTU8cIaicsJAiL6Udp/RZlACQgH/////////////////////
+//////////////////////pRhoeDvy+Wa3/MAUj3CaXQO7XJuImcR667b7cekThk
+CQIBAaGBiQOBhgAEALseCHiWoJ4wcnQGjefKigKgnFVDj1D03ikeYzefc2y3wnoe
+8neyeB+X071kpXg83nEAVuxqm1Yn1IMJCP9Tz7NhALhglEF2RzciUSwF+GDx8CW7
+RlSBlxbtEPxpODD8/tImnjRig/OngZFce8fds7NPEUxPsoS7xCQ6V+dSAaYM+QYi
+-----END EC PRIVATE KEY-----
diff --git a/libstb/keys/hw_key_b.key b/libstb/keys/hw_key_b.key
new file mode 100644
index 000000000000..60afd2da5896
--- /dev/null
+++ b/libstb/keys/hw_key_b.key
@@ -0,0 +1,26 @@
+!!! Important WARNING About This Private Key !!!
+
+DO NOT STRIP THIS WARNING FROM THIS PRIVATE KEY
+
+This private is being intentionally released by IBM to enable the developer
+community to sign code images.  For true security, a different set of production
+signing keys should be used, and the private production signing key should be
+carefully guarded.
+
+-----BEGIN EC PRIVATE KEY-----
+MIICnQIBAQRCAQ0nt+2t5RDGWJF6S326TEWyHPdI/VHm+pKvFgCCrVujE7P5oUlv
+GP3HZ3qemUX0RgmRjD27RflVdyOL6IlekHSsoIIBxjCCAcICAQEwTQYHKoZIzj0B
+AQJCAf//////////////////////////////////////////////////////////
+////////////////////////////MIGeBEIB////////////////////////////
+//////////////////////////////////////////////////////////wEQVGV
+PrlhjhyaH5KaIaC2hUDuotpyW5mzFfO4tImRjvEJ4VYZOVHsfpN7FlLAvTuxvwc1
+c9+IPSw08e9FH9RrUD8AAxUA0J6IACkcuFOWzGcXOTKEqqDaZLoEgYUEAMaFjga3
+BATpzZ4+y2YjlbRCnGSBOQU/tSH4KK9ga009uqFLXnfv51ko/h3BJ6L/qN4zSLPB
+hWpCm/l+fjHC5b1mARg5KWp4mjvABFyKX7QsfRvZmPVESVebRGgXr70XJz5mLJfu
+cple9CZAxVC5AT+tB2E1PHCGonLCQIi+lHaf0WZQAkIB////////////////////
+///////////////////////6UYaHg78vlmt/zAFI9wml0Du1ybiJnEeuu2+3HpE4
+ZAkCAQGhgYkDgYYABACTA8hhnkYIZKrc1O0tojIuF5Mhs9/XLMoSfPmDeqSXg2X9
+tjq598htT5uDWU/9WfrISQ9w81RR+blEvcY+GctkEQFJPYdOapsX2TVoNwvlJeVp
+gsQFwer4TOkmNV0FVbH7sJiHRw+ROHC5TOmy9YfQHCc2uAqInaZqPKTz13D8zQCG
+Cw==
+-----END EC PRIVATE KEY-----
diff --git a/libstb/keys/hw_key_c.key b/libstb/keys/hw_key_c.key
new file mode 100644
index 000000000000..1bf4dfb56326
--- /dev/null
+++ b/libstb/keys/hw_key_c.key
@@ -0,0 +1,26 @@
+!!! Important WARNING About This Private Key !!!
+
+DO NOT STRIP THIS WARNING FROM THIS PRIVATE KEY
+
+This private is being intentionally released by IBM to enable the developer
+community to sign code images.  For true security, a different set of production
+signing keys should be used, and the private production signing key should be
+carefully guarded.
+
+-----BEGIN EC PRIVATE KEY-----
+MIICnQIBAQRCASomU+ACnQy0UDtFX53VV2bwBrc3GPK3hbMrsU1E98YmU4eh/Dpj
+FYQOyCPV27GRK8V46a1xvWs57per+X4R9LVdoIIBxjCCAcICAQEwTQYHKoZIzj0B
+AQJCAf//////////////////////////////////////////////////////////
+////////////////////////////MIGeBEIB////////////////////////////
+//////////////////////////////////////////////////////////wEQVGV
+PrlhjhyaH5KaIaC2hUDuotpyW5mzFfO4tImRjvEJ4VYZOVHsfpN7FlLAvTuxvwc1
+c9+IPSw08e9FH9RrUD8AAxUA0J6IACkcuFOWzGcXOTKEqqDaZLoEgYUEAMaFjga3
+BATpzZ4+y2YjlbRCnGSBOQU/tSH4KK9ga009uqFLXnfv51ko/h3BJ6L/qN4zSLPB
+hWpCm/l+fjHC5b1mARg5KWp4mjvABFyKX7QsfRvZmPVESVebRGgXr70XJz5mLJfu
+cple9CZAxVC5AT+tB2E1PHCGonLCQIi+lHaf0WZQAkIB////////////////////
+///////////////////////6UYaHg78vlmt/zAFI9wml0Du1ybiJnEeuu2+3HpE4
+ZAkCAQGhgYkDgYYABAFUBCtSjR9PiJqVhg/EIsNGp0phvJ8gE5XBFTnox8n8a+Ji
+4e7r8Uae9Qea6hnvWa6HzAup1KEJAl6vobyhyItaegDEHRy56UIij9nDVYhSIXia
+EEln8xLVz5cB//hToEtexHUvdax85Nacwco6FyGNxzptGddL+/ds/rkZ05Q1fFUr
+WQ==
+-----END EC PRIVATE KEY-----
diff --git a/libstb/keys/sw_key_a.key b/libstb/keys/sw_key_a.key
new file mode 100644
index 000000000000..548e88000dd3
--- /dev/null
+++ b/libstb/keys/sw_key_a.key
@@ -0,0 +1,16 @@
+!!! Important WARNING About This Private Key !!!
+
+DO NOT STRIP THIS WARNING FROM THIS PRIVATE KEY
+
+This private is being intentionally released by IBM to enable the developer
+community to sign code images.  For true security, a different set of production
+signing keys should be used, and the private production signing key should be
+carefully guarded.
+
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIA1vyq2cSPgwWxVtPIEOqGL3UVsy5juBQz8XekOq6aeYf/nqC9u8u+
+GqCiffgBCPnXfWOWLtkaokYEPuMe7TekzomgBwYFK4EEACOhgYkDgYYABAD8W6NM
+6nVfsYps75ko1gfNrJO9XqbWAuUuyFA/O8S5tPwVP+atGpc4PE+uTEI24t7mkYLa
+kZhnGlmQpjr4fjkFvgAZDwhcQ+hWmzXYEBobYIPgItJi+8GvxBHBZvQWqpVWRfU9
+nSOxLTjjZ3i3dvBnQpCnx4cpTtIJPzFuE+kXqxLDnQ==
+-----END EC PRIVATE KEY-----
diff --git a/libstb/print-container.c b/libstb/print-container.c
new file mode 100644
index 000000000000..17aea12b11b4
--- /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;
+}
diff --git a/libstb/sign-with-local-keys.sh b/libstb/sign-with-local-keys.sh
index d9fed37afcbe..edd2757f5253 100755
--- a/libstb/sign-with-local-keys.sh
+++ b/libstb/sign-with-local-keys.sh
@@ -1,4 +1,4 @@
-#!/bin/bash -x
+#!/bin/bash
 
 PAYLOAD=$1
 OUTPUT=$2
@@ -8,12 +8,13 @@ if [ ! -f $PAYLOAD ]; then
 	exit 1;
 fi
 
-KEYLOC="/tmp/keys"
+KEYLOC=$3
 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 \
+# (reuse HW key for SW key P)
+./libstb/create-container -a $KEYLOC/hw_key_a.key -b $KEYLOC/hw_key_b.key -c $KEYLOC/hw_key_c.key \
+                   -p $KEYLOC/hw_key_a.key \
                     --payload $PAYLOAD --imagefile $OUTPUT \
                     --dumpPrefixHdr $T/prefix_hdr --dumpSwHdr $T/software_hdr
 
@@ -23,12 +24,11 @@ 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
+openssl dgst -SHA512 -sign $KEYLOC/hw_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 \
+./libstb/create-container -a $KEYLOC/hw_key_a.key -b $KEYLOC/hw_key_b.key -c $KEYLOC/hw_key_c.key \
+                   -p $KEYLOC/hw_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
diff --git a/libstb/test/Makefile.check b/libstb/test/Makefile.check
index 00e139768736..d4d7cb46c7a2 100644
--- a/libstb/test/Makefile.check
+++ b/libstb/test/Makefile.check
@@ -1,17 +1,15 @@
 # -*-Makefile-*-
-LIBSTB_TEST := libstb/test/run-stb-container \
-	    libstb/test/print-stb-container
+LIBSTB_TEST := libstb/test/run-stb-container
 
 HOSTCFLAGS+=-I . -I include
 
-libstb/test/print-stb-container-check: libstb/test/print-stb-container-q
-
-libstb/test/print-stb-container-q: libstb/test/print-stb-container
-	$(call Q, TEST , $(VALGRIND) libstb/test/print-stb-container libstb/test/t.container |diff -u libstb/test/t.container.out -, $< t.container)
+libstb/test/print-stb-container-check: libstb/print-container libstb/test/print-stb-container-q
 
+libstb/test/print-stb-container-q: libstb/print-container
+	$(call Q, TEST , $(VALGRIND) libstb/print-container -I libstb/test/t.container |diff -u libstb/test/t.container.out -, $< t.container)
 
 .PHONY : libstb-check
-libstb-check: $(LIBSTB_TEST:%=%-check) $(LIBSTB_TEST:%=%-gcov-run)
+libstb-check: $(LIBSTB_TEST:%=%-check) $(LIBSTB_TEST:%=%-gcov-run) libstb/test/print-stb-container-check
 libstb-check: $(LIBSTB_TEST_NOSTUB:%=%-check) $(LIBSTB_TEST_NOSTUB:%=%-gcov-run)
 
 .PHONY : libstb-coverage
diff --git a/libstb/test/print-stb-container.c b/libstb/test/print-stb-container.c
deleted file mode 100644
index 92a3ab50a351..000000000000
--- a/libstb/test/print-stb-container.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/* Copyright 2016 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 <stdbool.h>
-#include <types.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 <fcntl.h>
-#include <assert.h>
-
-#include "../container.h"
-#include "../container.c"
-
-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_sha2_hash_t(const sha2_hash_t h)
-{
-	int i;
-	for(i=0; i<SHA512_DIGEST_LENGTH; i++)
-		printf("%02x", h[i]);
-}
-
-static void display_ecid(const uint8_t *ecid)
-{
-	for(int i=0; i<ECID_SIZE; i++)
-		printf("%02x", ecid[i]);
-}
-
-static void display_prefix_header(const ROM_prefix_header_raw *p)
-{
-	printf("Prefix Header:\n");
-	display_version_raw(p->ver_alg);
-	printf("code_start_offset: %08lx\n", be64_to_cpu(p->code_start_offset));
-	printf("reserved:          %08lx\n", be64_to_cpu(p->reserved));
-	printf("flags:             %08x\n",  be32_to_cpu(p->flags));
-	printf("sw_key_count:      %02x\n", p->sw_key_count);
-	printf("payload_size:      %08lx\n", be64_to_cpu(p->payload_size));
-	printf("payloah_hash:      ");
-	display_sha2_hash_t(p->payload_hash);
-	printf("\n");
-	printf("ecid_count:        %02x\n", p->ecid_count);
-	for(int i=0; i< p->ecid_count; i++) {
-		printf("ecid:              ");
-		display_ecid(p->ecid[i].ecid);
-		printf("\n");
-	}
-}
-
-static void display_sw_header(const ROM_sw_header_raw *swh)
-{
-	printf("Software Header:\n");
-	display_version_raw(swh->ver_alg);
-	printf("code_start_offset: %08lx\n", be64_to_cpu(swh->code_start_offset));
-	printf("reserved:          %08lx\n", be64_to_cpu(swh->reserved));
-	printf("flags:             %08x\n", be32_to_cpu(swh->flags));
-	printf("reserved_0:        %02x\n", swh->reserved_0);
-	printf("payload_size:      %08lx (%lu)\n", be64_to_cpu(swh->payload_size), be64_to_cpu(swh->payload_size));
-	printf("payloah_hash:      ");
-	display_sha2_hash_t(swh->payload_hash);
-	printf("\n");
-	printf("ecid_count:        %02x\n", swh->ecid_count);
-
-	for(int i=0; i< swh->ecid_count; i++) {
-		printf("ecid:              ");
-		display_ecid(swh->ecid[i].ecid);
-		printf("\n");
-	}
-}
-
-static void display_ec_coord(const uint8_t *e)
-{
-	for(int i=0; i<EC_COORDBYTES*2; i++)
-		printf("%02x", e[i]);
-}
-
-static void display_prefix_data(const int sw_key_count, const ROM_prefix_data_raw *pd)
-{
-	printf("Prefix Data:\n");
-	printf("hw_sig_a:  "); display_ec_coord(pd->hw_sig_a); printf("\n");
-	printf("hw_sig_b:  "); display_ec_coord(pd->hw_sig_b); printf("\n");
-	printf("hw_sig_c:  "); display_ec_coord(pd->hw_sig_c); printf("\n");
-	if (sw_key_count >=1) {
-		printf("sw_pkey_p: "); display_ec_coord(pd->sw_pkey_p); printf("\n");
-	}
-	if (sw_key_count >=2) {
-		printf("sw_pkey_q: "); display_ec_coord(pd->sw_pkey_q); printf("\n");
-	}
-	if (sw_key_count >=3) {
-		printf("sw_pkey_r: "); display_ec_coord(pd->sw_pkey_r); printf("\n");
-	}
-}
-
-static void display_sw_sig(const ROM_sw_sig_raw *s)
-{
-	printf("Software Signatures:\n");
-	printf("sw_sig_p: "); display_ec_coord(s->sw_sig_p); printf("\n");
-	printf("sw_sig_q: "); display_ec_coord(s->sw_sig_q); printf("\n");
-	printf("sw_sig_r: "); display_ec_coord(s->sw_sig_r); printf("\n");
-}
-
-static void display_rom_container_raw(const ROM_container_raw *rcr)
-{
-	printf("Container:\n");
-	printf("magic:          0x%04x\n", be32_to_cpu(rcr->magic_number));
-	printf("version:        0x%02x\n", be16_to_cpu(rcr->version));
-	printf("container_size: 0x%08lx (%lu)\n", be64_to_cpu(rcr->container_size), be64_to_cpu(rcr->container_size));
-	printf("target_hrmor:   0x%08lx\n", be64_to_cpu(rcr->target_hrmor));
-	printf("stack_pointer:  0x%08lx\n", be64_to_cpu(rcr->stack_pointer));
-	printf("hw_pkey_a:\n");
-	for(int i=0; i < EC_COORDBYTES; i++)
-		printf("%02x", rcr->hw_pkey_a[i]);
-	printf("\n");
-	printf("hw_pkey_b:\n");
-	for(int i=0; i < EC_COORDBYTES; i++)
-		printf("%02x", rcr->hw_pkey_b[i]);
-	printf("\n");
-	printf("hw_pkey_c:\n");
-	for(int i=0; i < EC_COORDBYTES; i++)
-		printf("%02x", rcr->hw_pkey_c[i]);
-	printf("\n");
-}
-
-static void display_container(char* f)
-{
-	int fd = open(f, O_RDONLY);
-	void *container = malloc(SECURE_BOOT_HEADERS_SIZE);
-	struct parsed_stb_container c;
-	size_t sz;
-
-	assert(container);
-	if (fd == -1) {
-		perror(strerror(errno));
-		exit(EXIT_FAILURE);
-	}
-
-	sz = read(fd, container, SECURE_BOOT_HEADERS_SIZE);
-	if (sz != SECURE_BOOT_HEADERS_SIZE) {
-		perror(strerror(errno));
-		exit(EXIT_FAILURE);
-	}
-
-	if (!stb_is_container(container, SECURE_BOOT_HEADERS_SIZE)) {
-		fprintf(stderr, "Not a container, missing magic number\n");
-		exit(EXIT_FAILURE);
-	}
-
-	if (parse_stb_container(container, SECURE_BOOT_HEADERS_SIZE, &c) != 0) {
-		fprintf(stderr, "Failed to parse container.\n");
-		exit(EXIT_FAILURE);
-	}
-
-	display_rom_container_raw(c.c);
-	printf("\n");
-
-	display_prefix_header(c.ph);
-	printf("\n");
-
-	display_prefix_data(c.ph->sw_key_count, c.pd);
-	printf("\n");
-
-	display_sw_header(c.sh);
-	printf("\n");
-
-	display_sw_sig(c.ssig);
-
-	free(container);
-	close(fd);
-}
-
-int main(int argc, char* argv[])
-{
-	if (argc != 2) {
-		fprintf(stderr, "Usage %s container_file\n", argv[0]);
-		return 0;
-	}
-
-	display_container(argv[1]);
-
-	return 0;
-}
diff --git a/libstb/test/t.container.out b/libstb/test/t.container.out
index d613282ae975..cd113eebbaf7 100644
--- a/libstb/test/t.container.out
+++ b/libstb/test/t.container.out
@@ -4,12 +4,18 @@ version:        0x01
 container_size: 0x00000000 (0)
 target_hrmor:   0x00000000
 stack_pointer:  0x00000000
-hw_pkey_a:
-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-hw_pkey_b:
-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-hw_pkey_c:
-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+hw_pkey_a: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+hw_pkey_b: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+hw_pkey_c: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+HW keys hash (calculated):
+           03bb354bfebb6f7e2bf5bd30e76c1942587d26cf78200d47db84bc002912ed58f62037e6258b484ed37211a0
+           ad006050a027dc16d4c6182487acd34e57dc6c69
 
 Prefix Header:
 ver_alg:
@@ -21,13 +27,20 @@ reserved:          00000000
 flags:             00000000
 sw_key_count:      00
 payload_size:      00000000
-payloah_hash:      00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+payload_hash:      00000000000000000000000000000000000000000000000000000000000000000000000000000000
+                   000000000000000000000000000000000000000000000000
 ecid_count:        00
 
 Prefix Data:
-hw_sig_a:  000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-hw_sig_b:  000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-hw_sig_c:  000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+hw_sig_a:  0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+hw_sig_b:  0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+hw_sig_c:  0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 
 Software Header:
 ver_alg:
@@ -36,13 +49,22 @@ ver_alg:
   sig_alg:  00 (UNKNOWN)
 code_start_offset: 00000000
 reserved:          00000000
+reserved (ASCII):  
 flags:             00000000
 reserved_0:        00
 payload_size:      00000000 (0)
-payloah_hash:      00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+payload_hash:      00000000000000000000000000000000000000000000000000000000000000000000000000000000
+                   000000000000000000000000000000000000000000000000
 ecid_count:        00
 
 Software Signatures:
-sw_sig_p: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-sw_sig_q: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-sw_sig_r: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+sw_sig_p:  0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+sw_sig_q:  0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+sw_sig_r:  0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
-- 
2.14.3



More information about the Skiboot mailing list