From patchwork Wed Dec 13 09:41:56 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stewart Smith X-Patchwork-Id: 847910 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3yxWvX6Jhnz9sPm for ; Wed, 13 Dec 2017 20:42:48 +1100 (AEDT) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3yxWvW4W94zDrd7 for ; Wed, 13 Dec 2017 20:42:47 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=stewart@linux.vnet.ibm.com; receiver=) Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3yxWts4kHvzDrd0 for ; Wed, 13 Dec 2017 20:42:12 +1100 (AEDT) Received: from pps.filterd (m0098421.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id vBD9dCDt123651 for ; Wed, 13 Dec 2017 04:42:09 -0500 Received: from e37.co.us.ibm.com (e37.co.us.ibm.com [32.97.110.158]) by mx0a-001b2d01.pphosted.com with ESMTP id 2etxd0scy4-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Wed, 13 Dec 2017 04:42:09 -0500 Received: from localhost by e37.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 13 Dec 2017 02:42:08 -0700 Received: from b03cxnp07028.gho.boulder.ibm.com (9.17.130.15) by e37.co.us.ibm.com (192.168.1.137) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 13 Dec 2017 02:42:06 -0700 Received: from b03ledav003.gho.boulder.ibm.com (b03ledav003.gho.boulder.ibm.com [9.17.130.234]) by b03cxnp07028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id vBD9g6rS852254; Wed, 13 Dec 2017 02:42:06 -0700 Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 54DD16A045; Wed, 13 Dec 2017 02:42:06 -0700 (MST) Received: from birb.localdomain (unknown [9.102.53.225]) by b03ledav003.gho.boulder.ibm.com (Postfix) with SMTP id DEBF86A03F; Wed, 13 Dec 2017 02:42:04 -0700 (MST) Received: by birb.localdomain (Postfix, from userid 1000) id BFC024EC5DD; Wed, 13 Dec 2017 20:42:01 +1100 (AEDT) From: Stewart Smith To: skiboot@lists.ozlabs.org Date: Wed, 13 Dec 2017 20:41:56 +1100 X-Mailer: git-send-email 2.14.3 X-TM-AS-GCONF: 00 x-cbid: 17121309-0024-0000-0000-000017A573FA X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00008197; HX=3.00000241; KW=3.00000007; PH=3.00000004; SC=3.00000244; SDB=6.00959546; UDB=6.00485289; IPR=6.00739568; BA=6.00005740; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009; ZB=6.00000000; ZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00018516; XFM=3.00000015; UTC=2017-12-13 09:42:07 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17121309-0025-0000-0000-00004DE14B04 Message-Id: <20171213094156.9009-1-stewart@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-12-13_04:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=4 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1709140000 definitions=main-1712130139 Subject: [Skiboot] [PATCH v2] libstb/(create|print)-container: Sync with sb-signing-utils X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.24 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" 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 Signed-off-by: Stewart Smith --- 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 +#include +#include +#include +#include +#include + +#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(®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/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 +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include "container.h" - +#include #include #include -#include -#include #include -#include -#include -#include #include -#include -#include +#include #include +#include -#include -#include -#include -#include +#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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; iver_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; ihw_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 +