[Skiboot] [PATCH] libstb/create-container: Sync with sb-signing-utils
Stewart Smith
stewart at linux.vnet.ibm.com
Wed Dec 13 17:31:31 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.
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 | 4 +-
libstb/create-container-utils.c | 137 ++++++++++
libstb/create-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/sign-with-local-keys.sh | 16 +-
11 files changed, 824 insertions(+), 159 deletions(-)
create mode 100644 libstb/create-container-utils.c
create mode 100644 libstb/create-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
diff --git a/Makefile.main b/Makefile.main
index 73c91962ed83..90f8461feb2e 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,./libstb/sign-with-local-keys.sh $< $@ 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,./libstb/sign-with-local-keys.sh $< $@ 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..396c1c629055 100644
--- a/libstb/Makefile.inc
+++ b/libstb/Makefile.inc
@@ -14,9 +14,9 @@ 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/create-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,$<)
clean: create-container-clean
diff --git a/libstb/create-container-utils.c b/libstb/create-container-utils.c
new file mode 100644
index 000000000000..05d87171b3a1
--- /dev/null
+++ b/libstb/create-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.h"
+#include "create-container-utils.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(®expr, pattern, REG_EXTENDED | REG_NOSUB)))
+ die(EX_SOFTWARE, "%s", "failure to compile regex");
+
+ if (!(r = regexec(®expr, input, 0, NULL, 0)))
+ result = true;
+
+ regfree(®expr);
+ 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(®expr, pattern, REG_EXTENDED | REG_NOSUB)))
+ die(EX_SOFTWARE, "%s", "failure to compile regex");
+
+ if (!(r = regexec(®expr, input, 0, NULL, 0)))
+ result = true;
+
+ regfree(®expr);
+ return result;
+}
diff --git a/libstb/create-container-utils.h b/libstb/create-container-utils.h
new file mode 100644
index 000000000000..d3337b10dd55
--- /dev/null
+++ b/libstb/create-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..f5dc3e59ab93 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 "create-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/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
--
2.14.3
More information about the Skiboot
mailing list