summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2018-04-10 07:59:37 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-04-11 11:25:15 -0700
commit80f0f5c7cf42d32ce27690cb303d6ea26b2e01b9 (patch)
treeab5dbdc4fcffc1cc04478cba5476d7e6a1a2dbe7
parent209f47b692bd74fc5afcfeaf0e713ceaa99b9932 (diff)
downloadchrome-ec-80f0f5c7cf42d32ce27690cb303d6ea26b2e01b9.tar.gz
cr50: bypass signing step if cr50-codesigner is not available
When building EC targets in the setups where the Cr50 codesigner utility is not present let's just bypass the signing step. Also removing bitrotten source code of the old codesigner. BRANCH=none BUG=chromium:830302 TEST='make buildall' succeeds even if cr50-codesigner is not available. Change-Id: Ic6c4988455bcee6c45504e1fe781f6e03636d57a Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1005401 Reviewed-by: Allen Webb <allenwebb@google.com> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--chip/g/build.mk8
-rw-r--r--util/signer/aes.cc51
-rw-r--r--util/signer/codesigner.cc601
-rw-r--r--util/signer/common/aes.h24
-rw-r--r--util/signer/common/ecdh.h24
-rw-r--r--util/signer/common/gnubby.h46
-rw-r--r--util/signer/common/image.h61
-rw-r--r--util/signer/common/publickey.h70
-rw-r--r--util/signer/common/signed_header.h78
-rw-r--r--util/signer/ecdh.cc47
-rw-r--r--util/signer/gnubby.cc634
-rw-r--r--util/signer/image.cc517
-rw-r--r--util/signer/publickey.cc278
13 files changed, 5 insertions, 2434 deletions
diff --git a/chip/g/build.mk b/chip/g/build.mk
index 331c5b085f..0c80af042d 100644
--- a/chip/g/build.mk
+++ b/chip/g/build.mk
@@ -4,8 +4,6 @@
# found in the LICENSE file.
#
-SIGNED_IMAGES = 1
-
CORE:=cortex-m
CFLAGS_CPU+=-march=armv7-m -mcpu=cortex-m3
@@ -126,7 +124,11 @@ endif
MANIFEST := util/signer/ec_RW-manifest-dev.json
CR50_RO_KEY ?= rom-testkey-A.pem
-SIGNER = /usr/bin/cr50-codesigner
+REAL_SIGNER = /usr/bin/cr50-codesigner
+ifneq ($(wildcard $(REAL_SIGNER)),)
+SIGNED_IMAGES = 1
+SIGNER := $(REAL_SIGNER)
+endif
ifeq ($(H1_DEVIDS),)
CR50_RW_KEY = loader-testkey-A.pem
diff --git a/util/signer/aes.cc b/util/signer/aes.cc
deleted file mode 100644
index 4d120a102a..0000000000
--- a/util/signer/aes.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include <common/aes.h>
-
-#include <string.h>
-
-#include <openssl/aes.h>
-#include <openssl/cmac.h>
-#include <openssl/sha.h>
-#include <openssl/evp.h>
-
-AES::AES() {}
-AES::~AES() {
- memset(key_, 0, sizeof(key_));
-}
-
-void AES::set_key(const void* key) {
- memcpy(key_, key, sizeof(key_));
-}
-
-void AES::decrypt_block(const void* in, void* out) {
- AES_KEY aes;
- AES_set_decrypt_key(key_, sizeof(key_) * 8, &aes);
- AES_decrypt(reinterpret_cast<const unsigned char*>(in),
- reinterpret_cast<unsigned char*>(out), &aes);
-}
-
-void AES::encrypt_block(const void* in, void* out) {
- AES_KEY aes;
- AES_set_encrypt_key(key_, sizeof(key_) * 8, &aes);
- AES_encrypt(reinterpret_cast<const unsigned char*>(in),
- reinterpret_cast<unsigned char*>(out), &aes);
-}
-
-void AES::cmac(const void* in, size_t in_len, void* out) {
- unsigned char digest[SHA256_DIGEST_LENGTH];
-
- SHA256_CTX sha;
- SHA256_Init(&sha);
- SHA256_Update(&sha, reinterpret_cast<const unsigned char*>(in), in_len);
- SHA256_Final(digest, &sha);
-
- CMAC_CTX* cmac = CMAC_CTX_new();
- CMAC_Init(cmac, key_, sizeof(key_), EVP_aes_128_cbc(), 0);
- CMAC_Update(cmac, digest, sizeof(digest));
- size_t out_len;
- CMAC_Final(cmac, reinterpret_cast<unsigned char*>(out), &out_len);
- CMAC_CTX_free(cmac);
-}
diff --git a/util/signer/codesigner.cc b/util/signer/codesigner.cc
deleted file mode 100644
index 89b23eccd2..0000000000
--- a/util/signer/codesigner.cc
+++ /dev/null
@@ -1,601 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include <assert.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <common/image.h>
-#include <common/publickey.h>
-#include <common/signed_header.h>
-#ifdef HAVE_JSON
-#include <rapidjson/document.h>
-#else
-#include <pmjp.h>
-#endif
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include <fstream>
-#include <iostream>
-#include <sstream>
-
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-
-using namespace std;
-
-#define VERBOSE(...) \
- do { \
- if (FLAGS_verbose) fprintf(stderr, __VA_ARGS__); \
- } while (0)
-#define FATAL(...) \
- do { \
- fprintf(stderr, __VA_ARGS__); \
- abort(); \
- } while (0)
-
-bool FLAGS_verbose = false;
-bool FLAGS_cros = false;
-int last_logical_offset = -1;
-int fuse_index = 0;
-
-// Brute xml parsing.
-// Find HashItem w/ key == name, return val field, recursively.
-static xmlChar* get_val(xmlNodePtr node, const char* key) {
- xmlNode* cur_node = NULL;
- xmlChar* val = NULL;
-
- for (cur_node = node->children; cur_node; cur_node = cur_node->next) {
- if (!strcmp("HashItem", (const char*)(cur_node->name))) {
- // Hardcode parse <HashItem><Key>key</Key><Val>val</Val></HashItem>
- xmlNodePtr key_node = cur_node->children->next;
- xmlNodePtr val_node = cur_node->children->next->next->next;
- xmlChar* keyName = xmlNodeGetContent(key_node);
- xmlChar* valData = xmlNodeGetContent(val_node);
-
- if (!strcmp(key, (const char*)keyName)) {
- // Found our key, save val and done.
- xmlFree(keyName);
- val = valData;
- break;
- }
-
- xmlFree(valData);
- xmlFree(keyName);
- }
-
- val = get_val(cur_node, key);
- if (val) {
- // Found our key somewhere deeper down; done.
- break;
- }
- }
-
- return val;
-}
-
-static bool get_fuse(xmlNodePtr a_node, map<string, uint32_t>* ids,
- map<string, uint32_t>* bits) {
- bool result = false;
-
- // Interested in <HashType>
- if (strcmp("HashType", (const char*)(a_node->name))) {
- return result;
- }
-
- // Values we are interested in.
- xmlChar* RegName = get_val(a_node, "RegName");
- xmlChar* Width = get_val(a_node, "Width");
- xmlChar* FuseLogicalOffset = get_val(a_node, "FuseLogicalOffset");
-
- // Track 1024 fuses at most.
- int fuseLogicalOffset = atoi((const char*)FuseLogicalOffset);
- if (fuseLogicalOffset >= last_logical_offset) {
- last_logical_offset = fuseLogicalOffset;
- ids->insert(make_pair((const char*)RegName, fuse_index++));
- bits->insert(make_pair((const char*)RegName, atoi((const char*)Width)));
- } else {
- // Logical offset is regressing; assume we saw all the fuses.
- // There are multiple sections that list all the fuses in the xml;
- // we only care about parsing them once.
- result = true;
- }
-
- xmlFree(FuseLogicalOffset);
- xmlFree(Width);
- xmlFree(RegName);
-
- return result;
-}
-
-static bool find_fuses(xmlNodePtr a_node, map<string, uint32_t>* ids,
- map<string, uint32_t>* bits) {
- xmlNode* cur_node = NULL;
- bool done = false;
-
- for (cur_node = a_node; !done && cur_node; cur_node = cur_node->next) {
- xmlChar* content = NULL;
-
- if (cur_node->type == XML_TEXT_NODE &&
- (content = xmlNodeGetContent(cur_node)) != NULL) {
- if (!strcmp("FuseLogicalOffset", (const char*)content)) {
- // Found a likely fuse definition section; collect it.
- done = get_fuse(a_node->parent->parent->parent, ids, bits);
- }
- }
-
- if (content) xmlFree(content);
-
- if (!done && cur_node->children) {
- done = find_fuses(cur_node->children, ids, bits);
- }
- }
-
- return done;
-}
-
-static bool find_default_reg_value(xmlNodePtr a_node, const string& regname,
- string* result) {
- xmlNode* cur_node = NULL;
- bool done = false;
-
- for (cur_node = a_node; !done && cur_node; cur_node = cur_node->next) {
- xmlChar* content = NULL;
-
- if (cur_node->type == XML_TEXT_NODE &&
- (content = xmlNodeGetContent(cur_node)) != NULL) {
- if (!strcmp(regname.c_str(), (const char*)content)) {
- xmlChar* val = get_val(cur_node->parent->parent->parent, "Default");
- if (val) {
- result->assign((const char*)val);
- xmlFree(val);
- done = true;
- }
- }
- }
-
- if (content) xmlFree(content);
-
- if (!done && cur_node->children) {
- done = find_default_reg_value(cur_node->children, regname, result);
- }
- }
-
- return done;
-}
-
-// Read XML, populate two maps, name -> val
-bool readXML(const string& filename, map<string, uint32_t>* ids,
- map<string, uint32_t>* bits, uint32_t* p4cl) {
- bool result = false;
- LIBXML_TEST_VERSION
-
- xmlDocPtr doc = xmlReadFile(filename.c_str(), NULL, 0);
-
- if (doc) {
- result = find_fuses(xmlDocGetRootElement(doc), ids, bits);
- string p4clStr;
- result &= find_default_reg_value(xmlDocGetRootElement(doc),
- "SWDP_P4_LAST_SYNC", &p4clStr);
- if (result) {
- *p4cl = atoi(p4clStr.c_str());
- }
- xmlFreeDoc(doc);
- }
-
- xmlCleanupParser();
- xmlMemoryDump();
-
- return result;
-}
-
-// Read JSON, populate map, name -> val
-bool readJSON(const string& filename, string* tag,
- map<string, uint32_t>* values, map<string, uint32_t>* fusemap,
- map<string, uint32_t>* infomap) {
- bool result = false;
-#ifdef HAVE_JSON
- ifstream ifs(filename.c_str());
- if (ifs) {
- // Touch up a bit to allow for comments.
- // Beware: we drop everything past and including '//' from any line.
- // Thus '//' cannot be substring of any value..
- string s;
- while (ifs) {
- string line;
- getline(ifs, line);
- size_t slash = line.find("//");
- if (slash != string::npos) {
- line.erase(slash);
- }
- s.append(line);
- }
-
- // Try parse.
- rapidjson::Document d;
- if (d.Parse(s.c_str()).HasParseError()) {
- FATAL("JSON %s[%lu]: parse error\n", filename.c_str(),
- d.GetErrorOffset());
- } else {
-#define CHECKVALUE(x) \
- do { \
- if (!d.HasMember(x)) { \
- FATAL("manifest is lacking field '%s'\n", x); \
- }; \
- } while (0)
-
-#define GETVALUE(x) \
- do { \
- if (!d.HasMember(x)) { \
- FATAL("manifest is lacking field '%s'\n", x); \
- }; \
- (*values)[x] = d[x].GetInt(); \
- } while (0)
-
- CHECKVALUE("fuses");
- const rapidjson::Document::ValueType& fuses = d["fuses"];
- for (rapidjson::Value::ConstMemberIterator it = fuses.MemberBegin();
- it != fuses.MemberEnd(); ++it) {
- (*fusemap)[it->name.GetString()] = it->value.GetInt();
- }
-
- CHECKVALUE("info");
- const rapidjson::Document::ValueType& infos = d["info"];
- for (rapidjson::Value::ConstMemberIterator it = infos.MemberBegin();
- it != infos.MemberEnd(); ++it) {
- (*infomap)[it->name.GetString()] = it->value.GetInt();
- }
-
- GETVALUE("keyid");
- GETVALUE("p4cl");
- GETVALUE("epoch");
- GETVALUE("major");
- GETVALUE("minor");
- GETVALUE("applysec");
- GETVALUE("config1");
- GETVALUE("err_response");
- GETVALUE("expect_response");
- GETVALUE("timestamp");
-
- CHECKVALUE("tag");
- const rapidjson::Document::ValueType& Tag = d["tag"];
- tag->assign(Tag.GetString());
-
- result = true;
-
-#undef GETVALUE
-#undef CHECKVALUE
- }
- }
-#endif // HAVE_JSON
- return result;
-}
-
-string inputFilename;
-string outputFilename;
-string keyFilename;
-string xmlFilename;
-string jsonFilename;
-string outputFormat;
-string signatureFilename;
-string hashesFilename;
-bool fillPattern = false;
-uint32_t pattern = -1;
-bool fillRandom = false;
-
-void usage(int argc, char* argv[]) {
- fprintf(stderr,
- "Usage: %s options\n"
- "--input=$elf-filename\n"
- "--output=output-filename\n"
- "--key=$pem-filename\n"
- "[--b] ignored option, could be included for forward compatibility\n"
- "[--cros] to sign for the ChromeOS realm w/o manifest\n"
- "[--xml=$xml-filename] typically 'havenTop.xml'\n"
- "[--json=$json-filename] the signing manifest\n"
- "[--format=bin|hex] output file format, hex is default\n"
- "[--signature=$sig-filename] replace signature with file content\n"
- "[--hashes=$hashes-filename] destination file for intermediary "
- "hashes to be signed\n"
- "[--randomfill] to pad image to 512K with random bits\n"
- "[--patternfill=N] to pad image to 512K with pattern N\n"
- "[--verbose]\n",
- argv[0]);
-}
-
-int getOptions(int argc, char* argv[]) {
- static struct option long_options[] = {
- // name, has_arg
- {"b", no_argument, NULL, 'b'},
- {"cros", no_argument, NULL, 'c'},
- {"format", required_argument, NULL, 'f'},
- {"help", no_argument, NULL, 'h'},
- {"input", required_argument, NULL, 'i'},
- {"json", required_argument, NULL, 'j'},
- {"key", required_argument, NULL, 'k'},
- {"output", required_argument, NULL, 'o'},
- {"verbose", no_argument, NULL, 'v'},
- {"xml", required_argument, NULL, 'x'},
- {"signature", required_argument, NULL, 's'},
- {"hashes", required_argument, NULL, 'H'},
- {"randomfill", no_argument, NULL, 'r'},
- {"patternfill", required_argument, NULL, 'p'},
- {"writefuses", required_argument, NULL, 'w'},
- {0, 0, 0, 0}};
- int c, option_index = 0;
- outputFormat.assign("hex");
- while ((c = getopt_long(argc, argv, "i:o:p:k:x:j:f:s:H:bchvr", long_options,
- &option_index)) != -1) {
- switch (c) {
- case 0:
- fprintf(stderr, "option %s", long_options[option_index].name);
- if (optarg) fprintf(stderr, " with arg %s", optarg);
- fprintf(stderr, "\n");
- break;
- case 'b':
- break;
- case 'c':
- FLAGS_cros = true;
- break;
- case 'i':
- inputFilename.assign(optarg);
- break;
- case 'o':
- outputFilename.assign(optarg);
- break;
- case 'k':
- keyFilename.assign(optarg);
- break;
- case 'x':
- xmlFilename.assign(optarg);
- break;
- case 's':
- signatureFilename.assign(optarg);
- break;
- case 'j':
- jsonFilename.assign(optarg);
- break;
- case 'f':
- outputFormat.assign(optarg);
- break;
- case 'H':
- hashesFilename.assign(optarg);
- break;
- case 'r':
- fillRandom = true;
- break;
- case 'p':
- fillPattern = true;
- pattern = strtoul(optarg, NULL, 0);
- break;
- case 'h':
- usage(argc, argv);
- return 1;
-
- case 'v':
- FLAGS_verbose = true;
- break;
- case '?':
- // getopt_long printed error
- return 1;
- }
- }
- if (inputFilename.empty() || outputFilename.empty() || keyFilename.empty() ||
- ((outputFormat != "bin") && (outputFormat != "hex"))) {
- usage(argc, argv);
- return 1;
- }
- return 0;
-}
-
-int main(int argc, char* argv[]) {
- if (getOptions(argc, argv)) {
- exit(1);
- }
-
- PublicKey key(keyFilename);
- if (!key.ok()) return -1;
-
- // Load elf.
- Image image;
- if (!image.fromElf(inputFilename)) return -2;
-
- if (fillPattern) image.fillPattern(pattern);
- if (fillRandom) image.fillRandom();
-
- SignedHeader hdr;
-
- hdr.keyid = key.n0inv();
-
- hdr.ro_base = image.ro_base();
- hdr.ro_max = image.ro_max();
- hdr.rx_base = image.rx_base();
- hdr.rx_max =
- image.rx_max() +
- 12; // TODO: m3 instruction prefetch sets off GLOBALSEC when too tight
- // make sure these are nops or such?
- hdr.timestamp_ = time(NULL);
-
- // Parse signing manifest.
- map<string, uint32_t> values;
- map<string, uint32_t> fuses;
- map<string, uint32_t> infos;
- string tag;
-
- if (jsonFilename.empty()) {
- // Defaults, in case no JSON
- values.insert(make_pair("keyid", key.n0inv()));
- values.insert(make_pair("epoch", MANIFEST_EPOCH));
- values.insert(make_pair("major", MANIFEST_MAJOR));
- values.insert(make_pair("minor", MANIFEST_MINOR));
- }
-
- // Hardcoded expectation. Can be overwritten in JSON w/ new explicit value.
- fuses["FW_DEFINED_DATA_EXTRA_BLK6"] = 0;
-
- if (!jsonFilename.empty() &&
- !readJSON(jsonFilename, &tag, &values, &fuses, &infos)) {
- FATAL("Failed to read JSON from '%s'\n", jsonFilename.c_str());
- }
-
- // Fill in more of hdr, per manifest values
- for (map<string, uint32_t>::const_iterator it = values.begin();
- it != values.end(); ++it) {
- VERBOSE("%s : %u\n", it->first.c_str(), it->second);
- }
-
- hdr.p4cl_ = values["p4cl"];
- hdr.epoch_ = values["epoch"];
- hdr.major_ = values["major"];
- hdr.minor_ = values["minor"];
- hdr.applysec_ = values["applysec"];
- hdr.config1_ = values["config1"];
- hdr.err_response_ = values["err_response"];
- hdr.expect_response_ = values["expect_response"];
- if (values["timestamp"]) hdr.timestamp_ = values["timestamp"];
-
- VERBOSE("timestamp: %ld\n", hdr.timestamp_);
-
- // Check keyId.
- if (values["keyid"] != hdr.keyid) {
- FATAL("mismatched keyid JSON %d vs. key %d\n", values["keyid"], hdr.keyid);
- }
-
- if (FLAGS_cros) {
- if (!tag.empty()) {
- FATAL("--cros whilst also specifying tag per manifest is a no go");
- }
- tag = "\x01\x00\x00\x00"; // cros realm identifier in rwr[0]
- }
-
- // Fill in tag.
- VERBOSE("tag: \"%s\"\n", tag.c_str());
- strncpy((char*)(&hdr.tag), tag.c_str(), sizeof(hdr.tag));
-
- // List the specific fuses and values.
- VERBOSE("care about %lu fuses:\n", fuses.size());
- for (map<string, uint32_t>::const_iterator it = fuses.begin();
- it != fuses.end(); ++it) {
- VERBOSE("fuse '%s' should have value %u\n", it->first.c_str(), it->second);
- }
-
- // Parse xml.
- map<string, uint32_t> fuse_ids;
- map<string, uint32_t> fuse_bits;
- uint32_t xml_p4cl = 0;
-
- if (!xmlFilename.empty() &&
- !readXML(xmlFilename, &fuse_ids, &fuse_bits, &xml_p4cl)) {
- FATAL("Failed to read XML from '%s'\n", xmlFilename.c_str());
- }
-
- if (values["p4cl"] != xml_p4cl) {
- FATAL("mismatching p4cl: xml %u vs. json %u\n", xml_p4cl, values["p4cl"]);
- }
-
- VERBOSE("found %lu fuse definitions\n", fuse_ids.size());
- assert(fuse_ids.size() < FUSE_MAX);
-
- if (fuse_ids.size() != 0) {
- // Make sure FW_DEFINED_DATA_EXTRA_BLK6 is still at 125, width 3.
- assert(fuse_ids["FW_DEFINED_DATA_EXTRA_BLK6"] == 125);
- assert(fuse_bits["FW_DEFINED_DATA_EXTRA_BLK6"] == 5);
- }
-
- // Whether we loaded xml or not, hardcode FW_DEFINED_DATA_EXTRA_BLK6
- fuse_ids["FW_DEFINED_DATA_EXTRA_BLK6"] = 125;
- fuse_bits["FW_DEFINED_DATA_EXTRA_BLK6"] = 5;
-
- for (map<string, uint32_t>::const_iterator it = fuse_ids.begin();
- it != fuse_ids.end(); ++it) {
- VERBOSE("fuse '%s' at %u, width %u\n", it->first.c_str(), it->second,
- fuse_bits[it->first]);
- }
-
- // Compute fuse_values array, according to manifest and xml.
- uint32_t fuse_values[FUSE_MAX];
- for (size_t i = 0; i < FUSE_MAX; ++i) fuse_values[i] = FUSE_IGNORE;
-
- for (map<string, uint32_t>::const_iterator x = fuses.begin();
- x != fuses.end(); ++x) {
- map<string, uint32_t>::const_iterator it = fuse_ids.find(x->first);
- if (it == fuse_ids.end()) {
- FATAL("cannot find definition for fuse '%s'\n", x->first.c_str());
- }
- uint32_t idx = it->second;
- assert(idx < FUSE_MAX);
- uint32_t mask = (1ul << fuse_bits[x->first]) - 1;
- if ((x->second & mask) != x->second) {
- FATAL("specified fuse value too large\n");
- }
- uint32_t val = FUSE_PADDING & ~mask;
- val |= x->second;
-
- fuse_values[idx] = val;
- hdr.markFuse(idx);
- }
-
- // Print out fuse hash input.
- VERBOSE("expected fuse state:\n");
- for (size_t i = 0; i < FUSE_MAX; ++i) {
- VERBOSE("%08x ", fuse_values[i]);
- }
- VERBOSE("\n");
-
- // Compute info_values array, according to manifest.
- uint32_t info_values[INFO_MAX];
- for (size_t i = 0; i < INFO_MAX; ++i) info_values[i] = INFO_IGNORE;
-
- for (map<string, uint32_t>::const_iterator x = infos.begin();
- x != infos.end(); ++x) {
- uint32_t index = atoi(x->first.c_str());
- assert(index < INFO_MAX);
-
- info_values[index] ^= x->second;
-
- hdr.markInfo(index);
- }
-
- // TODO: read values from JSON or implement version logic here.
-
- // Print out info hash input.
- VERBOSE("expected info state:\n");
- for (size_t i = 0; i < INFO_MAX; ++i) {
- VERBOSE("%08x ", info_values[i]);
- }
- VERBOSE("\n");
-
- if (!signatureFilename.empty()) {
- int fd = ::open(signatureFilename.c_str(), O_RDONLY);
- if (fd > 0) {
- int n = ::read(fd, hdr.signature, sizeof(hdr.signature));
- ::close(fd);
-
- if (n != sizeof(hdr.signature))
- FATAL("cannot read from '%s'\n", signatureFilename.c_str());
-
- VERBOSE("provided signature\n");
- } else {
- FATAL("cannot open '%s'\n", signatureFilename.c_str());
- }
- }
-
- // Sign image.
- if (image.sign(key, &hdr, fuse_values, info_values, hashesFilename)) {
- image.generate(outputFilename, outputFormat == "hex");
- } else {
- FATAL("failed to sign\n");
- }
-
- return 0;
-}
diff --git a/util/signer/common/aes.h b/util/signer/common/aes.h
deleted file mode 100644
index 08e4eefb50..0000000000
--- a/util/signer/common/aes.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef __EC_UTIL_SIGNER_COMMON_AES_H
-#define __EC_UTIL_SIGNER_COMMON_AES_H
-
-#include <stddef.h>
-#include <inttypes.h>
-
-class AES {
- private:
- unsigned char key_[16];
- public:
- AES();
- ~AES();
-
- void set_key(const void* key);
- void decrypt_block(const void* in, void* out);
- void encrypt_block(const void* in, void* out);
- void cmac(const void* in, size_t in_len, void* out);
-};
-
-#endif // __EC_UTIL_SIGNER_COMMON_AES_H
diff --git a/util/signer/common/ecdh.h b/util/signer/common/ecdh.h
deleted file mode 100644
index 52751491d7..0000000000
--- a/util/signer/common/ecdh.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef __EC_UTIL_SIGNER_COMMON_ECDH_H
-#define __EC_UTIL_SIGNER_COMMON_ECDH_H
-
-#include <openssl/ec.h>
-
-class ECDH {
- private:
- EC_KEY* key_;
- EC_GROUP* group_;
- public:
- ECDH();
- ~ECDH();
-
- void get_point(void* dst);
-
- // Computes SHA256 of x-coordinate.
- void compute_secret(const void* other, void* secret);
-};
-
-#endif // __EC_UTIL_SIGNER_COMMON_ECDH_H
diff --git a/util/signer/common/gnubby.h b/util/signer/common/gnubby.h
deleted file mode 100644
index 9c27303296..0000000000
--- a/util/signer/common/gnubby.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef __EC_UTIL_SIGNER_COMMON_GNUBBY_H
-#define __EC_UTIL_SIGNER_COMMON_GNUBBY_H
-
-#include <stddef.h>
-#include <inttypes.h>
-
-#include <libusb-1.0/libusb.h>
-
-typedef struct env_md_ctx_st EVP_MD_CTX;
-typedef struct evp_pkey_st EVP_PKEY;
-typedef struct rsa_st RSA;
-typedef struct bignum_st BIGNUM;
-
-class Gnubby {
- public:
- Gnubby();
- ~Gnubby();
-
- bool ok() const { return handle_ != NULL; }
-
- int sign(EVP_MD_CTX* ctx, uint8_t* signature, uint32_t* siglen, EVP_PKEY* key);
-
- int write(RSA* rsa);
-
- private:
- int send_to_device(uint8_t instruction,
- const uint8_t* payload,
- size_t length);
-
- int receive_from_device(uint8_t* dest, size_t length);
-
- int write_bn(uint8_t ins, BIGNUM* n, size_t length);
- int doSign(EVP_MD_CTX* ctx, uint8_t* padded_req, uint8_t* signature,
- uint32_t* siglen, EVP_PKEY* key);
- // Open a gnubby, unspecified selection made when multiple plugged in.
- int open();
-
- libusb_context* ctx_;
- libusb_device_handle* handle_;
-};
-
-#endif // __EC_UTIL_SIGNER_COMMON_GNUBBY_H
diff --git a/util/signer/common/image.h b/util/signer/common/image.h
deleted file mode 100644
index c7e04a2753..0000000000
--- a/util/signer/common/image.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef __EC_UTIL_SIGNER_COMMON_IMAGE_H
-#define __EC_UTIL_SIGNER_COMMON_IMAGE_H
-
-#include <stdio.h>
-#include <stddef.h>
-#include <inttypes.h>
-
-#include <string>
-
-class PublicKey;
-struct SignedHeader;
-
-class Image {
- public:
- Image();
- ~Image();
-
- void randomize();
-
- bool fromIntelHex(const std::string& filename, bool withSignature = true);
- bool fromElf(const std::string& filename);
-
- bool sign(PublicKey& key,
- const SignedHeader* hdr,
- const uint32_t fuses[],
- const uint32_t info[],
- const std::string& hashesFilename);
- void generate(const std::string& outputFilename, bool hex_output) const;
-
-
- bool ok() const { return success_; }
- const uint8_t* code() const { return mem_; }
- size_t size() const { return high_ - base_; }
- int base() const { return base_; }
- int ro_base() const { return ro_base_; }
- int rx_base() const { return rx_base_; }
- int ro_max() const { return ro_max_; }
- int rx_max() const { return rx_max_; }
-
- void fillPattern(uint32_t);
- void fillRandom();
-
- private:
- void toIntelHex(FILE *fout) const;
- int nibble(char n);
- int parseByte(char** p);
- int parseWord(char** p);
- void store(int adr, int v);
-
- bool success_;
- uint8_t mem_[8*64*1024];
- int low_, high_, base_;
- size_t ro_base_, rx_base_;
- size_t ro_max_, rx_max_;
-};
-
-#endif // __EC_UTIL_SIGNER_COMMON_IMAGE_H
diff --git a/util/signer/common/publickey.h b/util/signer/common/publickey.h
deleted file mode 100644
index 79c38a94c2..0000000000
--- a/util/signer/common/publickey.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef __EC_UTIL_SIGNER_COMMON_PUBLICKEY_H
-#define __EC_UTIL_SIGNER_COMMON_PUBLICKEY_H
-
-#include <stddef.h>
-#include <inttypes.h>
-
-#include <string>
-
-typedef struct evp_pkey_st EVP_PKEY;
-typedef struct bignum_st BIGNUM;
-
-class PublicKey {
- public:
- explicit PublicKey(const std::string& filename);
- ~PublicKey();
-
- bool ok();
-
- // # of words for R.
- // Currently 96 (enough for upto 3071 moduli).
- size_t rwords() const { return 96; }
-
- // # of significant words in modulus.
- size_t nwords();
-
- uint32_t public_exponent();
-
- // -1 / least significant word of modulus.
- uint32_t n0inv();
-
- // PKCS1.5 SHA256
- // Montgomery factor 2**(32*rwords()) multiplied in.
- int sign(const void* msg, size_t msglen, BIGNUM** output);
-
- // PKCS1_OAEP SHA-1, MGF1
- int encrypt(uint8_t* in, int inlen, uint8_t* out);
-
- // PKCS1_OAEP SHA-1, MGF1
- int decrypt(uint8_t* in, int inlen, uint8_t* out);
-
- int raw(uint8_t* in, int inlen, BIGNUM** out);
-
- void print(const char* tag, size_t nwords, uint8_t* data, size_t len);
- void print(const char* tag, size_t nwords, BIGNUM* n);
-
- static void toArray(uint32_t* dst, size_t nwords, BIGNUM* n);
-
- void modToArray(uint32_t* dst, size_t nwords);
-
- // outputs rwords() words.
- void print(const char* tag);
-
- // outputs rwords() words.
- void toArray(uint32_t* dst);
-
- int writeToGnubby();
-
- private:
- EVP_PKEY* key_;
- bool publicOnly_;
-
- PublicKey& operator=(const PublicKey& other);
- PublicKey(const PublicKey& other);
-};
-
-#endif // __EC_UTIL_SIGNER_COMMON_PUBLICKEY_H
diff --git a/util/signer/common/signed_header.h b/util/signer/common/signed_header.h
deleted file mode 100644
index 2012285f82..0000000000
--- a/util/signer/common/signed_header.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef __EC_UTIL_SIGNER_COMMON_SIGNED_HEADER_H
-#define __EC_UTIL_SIGNER_COMMON_SIGNED_HEADER_H
-
-#include <assert.h>
-#include <string.h>
-#include <inttypes.h>
-
-#define FUSE_PADDING 0x55555555 // baked in hw!
-#define FUSE_IGNORE 0xa3badaac // baked in rom!
-#define FUSE_MAX 128 // baked in rom!
-
-#define INFO_MAX 128 // baked in rom!
-#define INFO_IGNORE 0xaa3c55c3 // baked in rom!
-
-typedef struct SignedHeader {
-#ifdef __cplusplus
- SignedHeader() : magic(-1), image_size(0),
- epoch_(0x1337), major_(0), minor_(0xbabe),
- p4cl_(0), applysec_(0), config1_(0), err_response_(0), expect_response_(0) {
- memset(signature, 'S', sizeof(signature));
- memset(tag, 'T', sizeof(tag));
- memset(fusemap, 0, sizeof(fusemap));
- memset(infomap, 0, sizeof(infomap));
- memset(_pad, '3', sizeof(_pad));
- }
-
- void markFuse(uint32_t n) {
- assert(n < FUSE_MAX);
- fusemap[n / 32] |= 1 << (n & 31);
- }
-
- void markInfo(uint32_t n) {
- assert(n < INFO_MAX);
- infomap[n / 32] |= 1 << (n & 31);
- }
-
- void print() const {
- }
-#endif // __cplusplus
-
- uint32_t magic; // -1 (thanks, boot_sys!)
- uint32_t signature[96];
- uint32_t img_chk_; // top 32 bit of expected img_hash
- // --------------------- everything below is part of img_hash
- uint32_t tag[7]; // words 0-6 of RWR/FWR
- uint32_t keyid; // word 7 of RWR
- uint32_t key[96]; // public key to verify signature with
- uint32_t image_size;
- uint32_t ro_base; // readonly region
- uint32_t ro_max;
- uint32_t rx_base; // executable region
- uint32_t rx_max;
- uint32_t fusemap[FUSE_MAX / (8 * sizeof(uint32_t))];
- uint32_t infomap[INFO_MAX / (8 * sizeof(uint32_t))];
- uint32_t epoch_; // word 7 of FWR
- uint32_t major_; // keyladder count
- uint32_t minor_;
- uint64_t timestamp_; // time of signing
- uint32_t p4cl_;
- uint32_t applysec_; // bits to and with FUSE_FW_DEFINED_BROM_APPLYSEC
- uint32_t config1_; // bits to mesh with FUSE_FW_DEFINED_BROM_CONFIG1
- uint32_t err_response_; // bits to or with FUSE_FW_DEFINED_BROM_ERR_RESPONSE
- uint32_t expect_response_; // action to take when expectation is violated
- uint32_t _pad[256 - 1 - 96 - 1 - 7 - 1 - 96 - 5*1 - 4 - 4 - 9*1 - 2 - 1];
- uint32_t fuses_chk_; // top 32 bit of expected fuses hash
- uint32_t info_chk_; // top 32 bit of expected info hash
-} SignedHeader;
-
-#ifdef __cplusplus
-static_assert(sizeof(SignedHeader) == 1024, "SignedHeader should be 1024 bytes");
-static_assert(offsetof(SignedHeader, info_chk_) == 1020, "SignedHeader should be 1024 bytes");
-#endif // __cplusplus
-
-#endif // __EC_UTIL_SIGNER_COMMON_SIGNED_HEADER_H
diff --git a/util/signer/ecdh.cc b/util/signer/ecdh.cc
deleted file mode 100644
index d5f9cfe25e..0000000000
--- a/util/signer/ecdh.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include <common/ecdh.h>
-
-#include <openssl/obj_mac.h>
-#include <openssl/sha.h>
-
-ECDH::ECDH() {
- key_ = EC_KEY_new();
- group_ = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
- EC_KEY_set_group(key_, group_);
- EC_KEY_generate_key(key_);
-}
-
-ECDH::~ECDH() {
- EC_GROUP_free(group_);
- EC_KEY_free(key_);
-}
-
-void ECDH::get_point(void* dst) {
- EC_POINT_point2oct(group_, EC_KEY_get0_public_key(key_),
- POINT_CONVERSION_UNCOMPRESSED,
- reinterpret_cast<unsigned char*>(dst), 65, 0);
-}
-
-void ECDH::compute_secret(const void* in, void* out) {
- EC_POINT* b = EC_POINT_new(group_);
- EC_POINT* x = EC_POINT_new(group_);
-
- EC_POINT_oct2point(group_, b, reinterpret_cast<const unsigned char*>(in), 65, 0);
- EC_POINT_mul(group_, x, 0, b, EC_KEY_get0_private_key(key_), 0);
-
- unsigned char xbytes[65];
- EC_POINT_point2oct(group_, x,
- POINT_CONVERSION_UNCOMPRESSED,
- xbytes, sizeof(xbytes), 0);
-
- SHA256_CTX sha;
- SHA256_Init(&sha);
- SHA256_Update(&sha, xbytes + 1, 32); // x coordinate only
- SHA256_Final(reinterpret_cast<unsigned char*>(out), &sha);
-
- EC_POINT_free(x);
- EC_POINT_free(b);
-}
diff --git a/util/signer/gnubby.cc b/util/signer/gnubby.cc
deleted file mode 100644
index 77cd5eb2a3..0000000000
--- a/util/signer/gnubby.cc
+++ /dev/null
@@ -1,634 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include <common/gnubby.h>
-
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <pwd.h>
-
-#include <libusb-1.0/libusb.h>
-#include <openssl/bn.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-#include <openssl/sha.h>
-
-#include <common/aes.h>
-#include <common/ecdh.h>
-
-#include <string>
-
-#define MAX_APDU_SIZE 1200
-#define LIBUSB_ERR -1
-
-extern bool FLAGS_verbose;
-
-// Largely from gnubby ifd_driver.c
-// -----
-
-typedef int RESPONSECODE;
-typedef uint8_t UCHAR;
-typedef UCHAR* PUCHAR;
-typedef uint32_t DWORD;
-typedef DWORD* PDWORD;
-
-#define IFD_SUCCESS 0
-#define IFD_COMMUNICATION_ERROR -1
-
-#define DLOG(...) do{if(FLAGS_verbose){fprintf(stderr, __VA_ARGS__);}}while(0)
-
-// usb gnubby commands
-#define CMD_ATR 0x81
-#define CMD_APDU 0x83
-#define CMD_LOCK 0x84
-#define CMD_WINK 0x88
-
-// Helper to dump bits to console.
-static
-void printHex(const char* text, const void* data, int len) {
- int i;
- const uint8_t* d = (const uint8_t*)(data);
- (void)d;
- DLOG("%s: ", text);
- for (i = 0; i < len; ++i) {
- DLOG("%02x", *d++);
- if (i == 3) DLOG(":");
- if (i == 4) DLOG("|");
- }
- DLOG("\n");
-}
-
-// Construct usb framed request.
-// data can be NULL iff len == 0.
-// Returns frame size > 0 on success.
-static
-RESPONSECODE construct_usb_frame(uint8_t cmd,
- const void* data, DWORD len,
- uint8_t* out, PDWORD out_len) {
- const uint8_t* d = (const uint8_t*)(data);
- DWORD i;
-
- if (*out_len < len + 7) return IFD_COMMUNICATION_ERROR;
-
- // use pid as channel id
- out[0] = getpid() >> 0;
- out[1] = getpid() >> 8;
- out[2] = getpid() >> 16;
- out[3] = getpid() >> 24;
- out[4] = cmd;
- out[5] = len >> 8;
- out[6] = len;
-
- // Append the actual payload.
- for (i = 0; i < len; ++i) out[7 + i] = d[i];
-
- // Return total length
- *out_len = 7 + len;
-
- return IFD_SUCCESS;
-}
-
-// Send cmd to gnubby and receive response.
-static
-RESPONSECODE gnubby_exchange(libusb_device_handle* dev_handle,
- void* buf, int res,
- void* rsp, PDWORD rsp_len) {
- int sent_len = 0;
- uint8_t rcv[2048];
- int recv_len = 0;
-
- DLOG("gnubby_exchange(%p, %p, %d, %p, *%u)\n",
- dev_handle, buf, res, rsp, *rsp_len);
-
- printHex(">", buf, res);
-
- // Send to gnubby
- res = libusb_bulk_transfer(dev_handle, (1 | LIBUSB_ENDPOINT_OUT),
- (unsigned char*)(buf), res,
- &sent_len, 0);
- DLOG(">: libusb_bulk_transfer: %d [%d]\n", res, sent_len);
- if (res < 0) return IFD_COMMUNICATION_ERROR;
-
- // Read from gnubby
- memset(rcv, 0, sizeof(rcv)); // start clean.
- res = libusb_bulk_transfer(dev_handle, (1 | LIBUSB_ENDPOINT_IN),
- rcv, sizeof rcv, &recv_len, 0);
- DLOG("<: libusb_bulk_transfer: %d [%d]\n", res, recv_len);
- if (res < 0) return IFD_COMMUNICATION_ERROR;
-
- if (recv_len > 0) {
- printHex("<", rcv, recv_len);
-
- // Check return header.
- // rcv[0..4] should be equal to request.
- // rcv[5..6] is response payload length.
- // rcv[recv_len-2..recv_len-1] is smartcard response code (9000 etc.)
- if (memcmp(buf, rcv, 5)) return IFD_COMMUNICATION_ERROR;
-
- uint16_t plen = rcv[5] * 256 + rcv[6];
- if (plen + 7 < recv_len) return IFD_COMMUNICATION_ERROR;
-
- if (*rsp_len < plen) return IFD_COMMUNICATION_ERROR;
-
- // Copy response payload.
- memcpy(rsp, rcv + 7, plen);
-
- // Return payload length.
- *rsp_len = plen;
-
- return IFD_SUCCESS;
- }
-
- return IFD_COMMUNICATION_ERROR;
-}
-
-#if 0
-static
-RESPONSECODE gnubby_atr(libusb_device_handle* handle, PUCHAR Atr, PDWORD AtrLength) {
- uint8_t cmd[10];
- DWORD cmd_len = sizeof(cmd);
- RESPONSECODE res;
-
- DLOG("gnubby_atr(%p, %p, *%u)\n", handle, Atr, *AtrLength);
-
- memset(Atr, 0, *AtrLength);
-
- res = construct_usb_frame(CMD_ATR, NULL, 0, cmd, &cmd_len);
- if (res != IFD_SUCCESS) return res;
-
- res = gnubby_exchange(handle, cmd, cmd_len, Atr, AtrLength);
-
- if (res == IFD_SUCCESS) {
- // Present an ATR that can do T=1
- // Gnubby ATR appears to not advertise that capability.
- memcpy(Atr, "\x3B\xF0\x13\x00\x00\x81\x31\xFE\x45\xE8", 10);
- *AtrLength = 10;
- }
-
- return res;
-}
-#endif
-
-static
-RESPONSECODE gnubby_apdu(libusb_device_handle* handle,
- PUCHAR tx, DWORD txLen,
- PUCHAR rx, PDWORD rxLen) {
- uint8_t cmd[2048];
- DWORD cmd_len = sizeof(cmd);
- RESPONSECODE res = IFD_SUCCESS;
-
- DLOG("gnubby_apdu(%p, %p, %u, %p, *%u)\n",
- handle, tx, txLen, rx, *rxLen);
-
- res = construct_usb_frame(CMD_APDU, tx, txLen, cmd, &cmd_len);
- if (res != IFD_SUCCESS) return res;
-
- res = gnubby_exchange(handle, cmd, cmd_len, rx, rxLen);
-
- if (res != IFD_SUCCESS) *rxLen = 0;
- return res;
-}
-
-static
-RESPONSECODE gnubby_lock(libusb_device_handle* handle, UCHAR seconds) {
- uint8_t cmd[10];
- DWORD cmd_len = sizeof(cmd);
- uint8_t rsp[10];
- DWORD rsp_len = sizeof(rsp);
-
- RESPONSECODE res = IFD_SUCCESS;
-
- res = construct_usb_frame(CMD_LOCK, &seconds, 1, cmd, &cmd_len);
- if (res != IFD_SUCCESS) return res;
-
- res = gnubby_exchange(handle, cmd, cmd_len, rsp, &rsp_len);
- if (res != IFD_SUCCESS) return res;
-
- if ((rsp_len == 1 && rsp[0] == 0) ||
- rsp_len == 0) {
- return IFD_SUCCESS;
- }
-
- return IFD_COMMUNICATION_ERROR;
-}
-
-static
-RESPONSECODE gnubby_wink(libusb_device_handle* handle) {
- uint8_t cmd[10];
- DWORD cmd_len = sizeof(cmd);
- uint8_t rsp[10];
- DWORD rsp_len = sizeof(rsp);
-
- RESPONSECODE res = IFD_SUCCESS;
-
- res = construct_usb_frame(CMD_WINK, NULL, 0, cmd, &cmd_len);
- if (res != IFD_SUCCESS) return res;
-
- res = gnubby_exchange(handle, cmd, cmd_len, rsp, &rsp_len);
- if (res != IFD_SUCCESS) return res;
-
- return res;
-}
-
-// -----
-// end of ifd_driver cut&paste
-
-
-// Open a usb device and return (handle_, context).
-Gnubby::Gnubby()
- : handle_(NULL) {
- libusb_init(&ctx_);
- libusb_set_debug(ctx_, 3);
-}
-
-// Close a usb device.
-Gnubby::~Gnubby() {
- // Close handle_ if non-zero.
- if (handle_) {
- int rc = libusb_release_interface(handle_, 0);
- DLOG("gnubby release : %d\n", rc);
- libusb_close(handle_);
- (void) rc;
- }
-
- // Close context.
- libusb_exit(ctx_);
-}
-
-
-static
-int getSW12(const uint8_t* buf, size_t buflen) {
- if (buflen < 2) return -1;
- return buf[buflen - 2] * 256 + buf[buflen - 1];
-}
-
-static
-void getPIN(uint8_t* out) {
- srand(time(NULL)); // yuk
- for (int i = 0; i < 16; ++i) out[i] = (uint32_t)rand() >> (i+1);
-
- const char* pin = getpass("Gnubby PIN: ");
- int len = strlen(pin);
-
- if (len == 6) {
- // Exactly 6, copy direct.
- memcpy(out, pin, 6);
- } else {
- // SHA256, take first 6.
- uint8_t digest[SHA256_DIGEST_LENGTH];
- SHA256_CTX sha;
- SHA256_Init(&sha);
- SHA256_Update(&sha, pin, len);
- SHA256_Final(digest, &sha);
- memcpy(out, digest, 6);
- }
-}
-
-static
-std::string tokenFilename(const uint8_t* fp) {
- const char* home = getenv("HOME");
- if (home == NULL)
- home = getpwuid(getuid())->pw_dir;
- std::string s(home);
- s.append("/.tmp/");
- for (int i = 0; i < 32; ++i) {
- s.push_back("0123456789abcdef"[fp[i]>>4]);
- s.push_back("0123456789abcdef"[fp[i]&15]);
- }
- s.append(".token");
- return s;
-}
-
-static
-bool getToken(const uint8_t* fp, uint8_t* out) {
- int fd = open(tokenFilename(fp).c_str(), O_RDONLY);
- if (fd < 0) return false;
- int n = read(fd, out, 16);
- close(fd);
- DLOG("read %d from %s\n", n, tokenFilename(fp).c_str());
- return n == 16;
-}
-
-static
-void saveToken(const uint8_t* fp, const uint8_t* token) {
- int fd = open(tokenFilename(fp).c_str(), O_CREAT|O_TRUNC|O_APPEND|O_NOFOLLOW|O_WRONLY, 0600);
- if (fd >= 0) {
- int n = write(fd, token, 16);
- DLOG("wrote %d to %s\n", n, tokenFilename(fp).c_str());
- close(fd);
- (void) n;
- }
-}
-
-static
-void forgetToken(const uint8_t* fp) {
- DLOG("forgetting token %s\n", tokenFilename(fp).c_str());
- unlink(tokenFilename(fp).c_str());
-}
-
-static
-bool isGnubby(libusb_device *dev) {
- struct libusb_device_descriptor lsb_desc;
- if (!libusb_get_device_descriptor(dev, &lsb_desc)) {
- return lsb_desc.idVendor == 0x1050 && lsb_desc.idProduct == 0x0211;
- }
- return false;
-}
-
-int Gnubby::doSign(EVP_MD_CTX* ctx, uint8_t* padded_req, uint8_t* signature,
- uint32_t* siglen, EVP_PKEY* key) {
- RESPONSECODE result = -1;
-
- uint8_t fp[32];
- ECDH ecdh;
- uint8_t secret[32] = {0};
- AES aes;
- uint8_t pin[16];
- uint8_t token[16];
-
- UCHAR req[1024];
- UCHAR resp[2048];
- DWORD resp_len = 0;
-
- // lock(100)
- result = gnubby_lock(handle_, (UCHAR)100);
- if (result != 0) goto __fail;
- // TODO: handle busy etc.
-
- // select ssh applet
- resp_len = sizeof(resp);
- result = gnubby_apdu(handle_,
- (PUCHAR)"\x00\xa4\x04\x00\x06\x53\x53\x48\x00\x01\x01", 11,
- resp, &resp_len);
- if (result != 0) goto __fail;
- if (getSW12(resp, resp_len) != 0x9000) goto __fail;
-
-__again:
-
- // read slot 0x66 under challenge
- resp_len = sizeof(resp);
- result = gnubby_apdu(handle_,
- (PUCHAR)"\x00\x43\x66\x00\x00\x00\x10\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00", 5 + 2 + 16,
- resp, &resp_len);
- if (result != 0) goto __fail;
- if (getSW12(resp, resp_len) != 0x9000) goto __fail;
-
- // save device fingerprint
- memcpy(fp, resp + 1 + 256 + 65 + 65, 32);
-
- uint8_t pubkey[256];
- if (key->type != EVP_PKEY_RSA
- || EVP_PKEY_size(key) != 256
- || BN_bn2bin(key->pkey.rsa->n, pubkey) != 256) {
- goto __fail;
- }
- if (memcmp(pubkey, resp + 1, 256)) {
- // Key mis-match, wrong gnubby selected?
- DLOG("pubkey mis-match, at device handle: %p", handle_);
- goto __fail;
- }
-
- if (!getToken(fp, token)) {
- // PIN unlock required.
- getPIN(pin);
-
- ecdh.compute_secret(resp + 1 + 256, secret);
- aes.set_key(secret);
-
- memcpy(req, "\x00\x42\x00\x00\x51", 5);
-
- ecdh.get_point(req + 5);
- printHex("req", req, 5 + 65);
- aes.encrypt_block(pin, req + 5 + 65);
- printHex("req", req, 5 + 65 + 16);
-
- resp_len = sizeof(resp);
- result = gnubby_apdu(handle_,
- req, 5 + 65 + 16,
- resp, &resp_len);
- if (result != 0) goto __fail;
-
- if ((getSW12(resp, resp_len) & 0xfff0) == 0x63c0) {
- // Wrong PIN.
- goto __again;
- }
-
- if (getSW12(resp, resp_len) != 0x9000) goto __fail;
-
- aes.set_key(secret + 16);
- aes.decrypt_block(resp, token);
-
- saveToken(fp, token);
- }
-
- // Build sign request using slot 0x66.
- memset(req, 0, sizeof(req));
- memcpy(req, "\x00\x40\x66\x00\x00\x01\x10", 7);
- memcpy(req + 7 + 16, padded_req, 256);
-
- aes.set_key(token);
- aes.cmac(req + 7 + 16, 256, req + 7);
-
- for (;;) {
- resp_len = sizeof(resp);
- result = gnubby_apdu(handle_,
- req, 7 + 256 + 16,
- resp, &resp_len);
- if (result != 0) goto __fail;
-
- if (getSW12(resp, resp_len) == 0x6985) { // touch
- gnubby_wink(handle_);
- fprintf(stderr, "touch..");
- fflush(stderr);
- usleep(200000); // slow down, buddy
- continue;
- }
-
- if (getSW12(resp, resp_len) == 0x63ca) { // pin
- forgetToken(fp);
- goto __again;
- }
-
- break;
- }
-
- if (getSW12(resp, resp_len) != 0x9000) goto __fail;
-
- // Return signature.
- memcpy(signature, resp, 256);
- *siglen = 256;
-
- // profit!
- result = 1;
-
-__fail:
- // (always try to) unlock
- gnubby_lock(handle_, 0);
-
- return result;
-}
-
-int Gnubby::sign(EVP_MD_CTX* ctx, uint8_t* signature, uint32_t* siglen,
- EVP_PKEY* key) {
- // build pkcs1.5 request for ctx hash
- // lock(100)
- // select ssh
- // read slot 0x66
- // compare against key
- // try read token from ~/.tmp/attest-fp
- // loop
- // - send sign request
- // - handle PIN, touch
- // unlock()
- // profit!
- RESPONSECODE result = -1;
- DWORD image_hash_len = SHA256_DIGEST_LENGTH;
- libusb_device **device_list;
- ssize_t num_devices = libusb_get_device_list(ctx_, &device_list);
-
- // Compute pkc15 padded inputs for requested sha256.
- // Brutal hard-coding ftw.
- uint8_t padded_req[256];
- memset(padded_req, 0xff, sizeof(padded_req));
- padded_req[0] = 0x00;
- padded_req[1] = 0x01;
- // Fixed asn1 riddle for sha256
- memcpy(padded_req + 256 - 32 - 20,
- "\x00\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20",
- 20);
- // Append sha256
- EVP_DigestFinal_ex(ctx,
- padded_req + sizeof(padded_req) - SHA256_DIGEST_LENGTH,
- &image_hash_len);
-
- for (int i = 0; i < num_devices; i++) {
- if (!isGnubby(device_list[i])) {
- continue;
- }
- int rc = libusb_open(device_list[i], &handle_);
- if (rc) {
- DLOG("libusb_open() @ device index: %d failed: %d\n", i, rc);
- continue;
- }
- rc = libusb_claim_interface(handle_, 0);
- if (rc) {
- DLOG("libusb_claim_interface() @ device index: %d failed: %d\n", i, rc);
- if (handle_) {
- libusb_close(handle_);
- handle_ = NULL;
- }
- continue;
- }
- rc = doSign(ctx, padded_req, signature, siglen, key);
- libusb_release_interface(handle_, 0);
- libusb_close(handle_);
- handle_ = NULL;
- if (rc == 1) {
- result = 1;
- break;
- }
- // Try next device.
- }
-
- libusb_free_device_list(device_list, 1);
- return result;
-}
-
-// Open a gnubby, unspecified selection made when multiple plugged in.
-int Gnubby::open() {
- RESPONSECODE result = -1;
- handle_ = libusb_open_device_with_vid_pid(
- ctx_,
- 0x1050, // Gnubby Vendor ID (VID)
- 0x0211 // Gnubby Product ID (PID)
- );
- DLOG("gnubby dev_handle_ %p\n", handle_);
- int rc = libusb_claim_interface(handle_, 0);
- DLOG("gnubby claim : %d\n", rc);
-
- if (rc != 0) {
- if (handle_) libusb_close(handle_);
- } else {
- result = 1;
- }
- return result;
-}
-
-int Gnubby::write_bn(uint8_t p1, BIGNUM* n, size_t length) {
- RESPONSECODE result = -1;
-
- UCHAR req[1024];
- UCHAR resp[1024];
- DWORD resp_len = 0;
-
- memcpy(req, "\x00\x66\x00\x00\x00\x00\x00", 7);
- req[2] = p1;
- req[5] = length >> 8;
- req[6] = length;
-
- if (BN_bn2bin(n, req + 7) != int(length)) goto __fail;
-
- resp_len = sizeof(resp);
- result = gnubby_apdu(handle_,
- req, 7 + length,
- resp, &resp_len);
- if (result != 0) goto __fail;
-
- result = 1;
- if (getSW12(resp, resp_len) != 0x9000) goto __fail;
-
- result = 0;
-
-__fail:
- return result;
-}
-
-int Gnubby::write(RSA* rsa) {
- RESPONSECODE result = -1;
-
- UCHAR resp[2048];
- DWORD resp_len = 0;
-
- if (!handle_) {
- result = (open() != 1);
- if (result) goto __fail;
- }
-
- // lock(100)
- result = gnubby_lock(handle_, (UCHAR)100);
- if (result != 0) goto __fail;
- // TODO: handle busy etc.
-
- // select ssh applet
- resp_len = sizeof(resp);
- result = gnubby_apdu(handle_,
- (PUCHAR)"\x00\xa4\x04\x00\x06\x53\x53\x48\x00\x01\x01", 11,
- resp, &resp_len);
- if (result != 0) goto __fail;
-
- result = 1;
- if (getSW12(resp, resp_len) != 0x9000) goto __fail;
-
- result = 0;
-
- result = result || write_bn(0, rsa->p, 128);
- result = result || write_bn(1, rsa->q, 128);
- result = result || write_bn(2, rsa->dmp1, 128);
- result = result || write_bn(3, rsa->dmq1, 128);
- result = result || write_bn(4, rsa->iqmp, 128);
- result = result || write_bn(5, rsa->n, 256);
- result = result || write_bn(6, rsa->e, 1);
-
-__fail:
- // (always try to) unlock
- if (handle_) gnubby_lock(handle_, 0);
-
- return result;
-}
diff --git a/util/signer/image.cc b/util/signer/image.cc
deleted file mode 100644
index a2e4d5c2fc..0000000000
--- a/util/signer/image.cc
+++ /dev/null
@@ -1,517 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include <common/image.h>
-
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <gelf.h>
-#include <libelf.h>
-
-#include <common/publickey.h>
-
-#include <openssl/bn.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/rand.h>
-#include <openssl/rsa.h>
-
-#include <common/signed_header.h>
-
-#include <string>
-
-using namespace std;
-
-extern bool FLAGS_verbose;
-
-#define VERBOSE(...) \
- do { \
- if (FLAGS_verbose) fprintf(stderr, __VA_ARGS__); \
- } while (0)
-#define WARN(...) \
- do { \
- fprintf(stderr, __VA_ARGS__); \
- } while (0)
-#define FATAL(...) \
- do { \
- fprintf(stderr, __VA_ARGS__); \
- abort(); \
- } while (0)
-
-static const int FLASH_START = 0x4000;
-static const int FLASH_END = FLASH_START + 512 * 1024;
-
-Image::Image()
- : success_(true),
- low_(FLASH_END - FLASH_START),
- high_(0),
- base_(0),
- ro_base_(FLASH_END * 16),
- rx_base_(FLASH_END * 16),
- ro_max_(0),
- rx_max_(0) {
- memset(mem_, 0xff, sizeof(mem_)); // default memory content
-}
-
-void Image::randomize() {
- int fd = open("/dev/urandom", O_RDONLY);
- if (fd >= 0) {
- read(fd, mem_, sizeof(mem_));
- close(fd);
- }
-}
-
-bool Image::fromElf(const string& filename) {
- Elf* elf = NULL;
- Elf_Scn* scn = NULL;
- GElf_Shdr shdr;
- GElf_Phdr phdr;
-
- char* base_ptr = NULL;
- struct stat elf_stats;
-
- bool result = false;
-
- int fd;
-
- if ((fd = open(filename.c_str(), O_RDONLY)) < 0) {
- WARN("failed to open '%s'\n", filename.c_str());
- goto fail;
- }
- if ((fstat(fd, &elf_stats)) < 0) {
- WARN("cannot stat '%s'\n", filename.c_str());
- goto fail;
- }
-
- // printf("Elf filesize: %lu\n", elf_stats.st_size);
-
- if ((base_ptr = (char*)malloc(elf_stats.st_size)) == NULL) {
- WARN("cannot malloc %lu\n", elf_stats.st_size);
- goto fail;
- }
-
- if (read(fd, base_ptr, elf_stats.st_size) < elf_stats.st_size) {
- WARN("cannot read from '%s'\n", filename.c_str());
- goto fail;
- }
-
- // Sniff content for sanity
- if (*(uint32_t*)base_ptr != 0x464c457f) {
- // WARN("'%s' is not elf file\n", filename);
- goto fail;
- }
-
- if (elf_version(EV_CURRENT) == EV_NONE) {
- WARN("Warning: elf library is out of date!\n");
- }
-
- elf = elf_begin(fd, ELF_C_READ, NULL);
-
- // Infer minimal rx segment from section headers.
- while ((scn = elf_nextscn(elf, scn)) != 0) {
- gelf_getshdr(scn, &shdr);
-
- VERBOSE("type %08x; flags %08lx ", shdr.sh_type, shdr.sh_flags);
- VERBOSE("%08lx(@%08lx)[%08lx] align %lu\n", shdr.sh_addr, shdr.sh_offset,
- shdr.sh_size, shdr.sh_addralign);
-
- // Ignore sections that are not alloc
- if (!(shdr.sh_flags & SHF_ALLOC)) {
- continue;
- }
-
- // Ignore sections that are not exec
- if (!(shdr.sh_flags & SHF_EXECINSTR)) {
- continue;
- }
-
- // Ignore sections outside our flash range
- if (shdr.sh_addr < FLASH_START * 16 ||
- shdr.sh_addr + shdr.sh_size >= FLASH_END * 16) {
- continue;
- }
-
- // Track rx boundaries
- if (shdr.sh_addr < rx_base_) {
- rx_base_ = shdr.sh_addr;
- }
- if (shdr.sh_addr + shdr.sh_size > rx_max_) {
- rx_max_ = shdr.sh_addr + shdr.sh_size;
- }
- }
-
- // Load image per program headers and track total ro segment
- for (int index = 0; gelf_getphdr(elf, index, &phdr); ++index) {
- VERBOSE("phdr %08lx(@%08lx) [%08lx/%08lx]", phdr.p_vaddr, phdr.p_paddr,
- phdr.p_filesz, phdr.p_memsz);
-
- // Ignore sections outside our flash range
- if (phdr.p_paddr < FLASH_START * 16 ||
- phdr.p_paddr + phdr.p_filesz >= FLASH_END * 16) {
- VERBOSE(" (outside flash, skipped)\n");
- continue;
- }
-
- // Ignore p_offset 0, which ELF hdr; cannot be legit.
- if (phdr.p_offset == 0) {
- VERBOSE(" (offset 0, ignoring)\n");
- continue;
- }
-
- VERBOSE("\n");
-
- // Track ro boundaries
- if (phdr.p_paddr < ro_base_) {
- ro_base_ = phdr.p_paddr;
- }
- if (phdr.p_paddr + phdr.p_filesz > ro_max_) {
- ro_max_ = phdr.p_paddr + phdr.p_filesz;
- }
-
- // Copy data into image
- for (size_t n = 0; n < phdr.p_filesz; ++n) {
- store(phdr.p_paddr + n - FLASH_START * 16, base_ptr[phdr.p_offset + n]);
- }
- }
-
- low_ &= ~2047;
- base_ = low_;
-
- // Set ro_base to start, so app can read its own header.
- ro_base_ = base_ + FLASH_START * 16;
- // Set rx_base to just past header, where interrupt vectors are,
- // since fetching a vector gets done on the I bus.
- rx_base_ = ro_base_ + sizeof(SignedHeader);
-
- high_ = ((high_ + 2047) / 2048) * 2048; // Round image to multiple of 2K.
-
- VERBOSE("Rounded image size %lu\n", size());
- VERBOSE("ro_base %08lx..%08lx\n", ro_base_, ro_max_);
- VERBOSE("rx_base %08lx..%08lx\n", rx_base_, rx_max_);
-
- result = true;
-
-fail:
- if (elf) elf_end(elf);
- if (base_ptr) free(base_ptr);
- if (fd >= 0) close(fd);
-
- return result;
-}
-
-bool Image::fromIntelHex(const string& filename, bool withSignature) {
- bool isRam = false;
- int seg = 0;
-
- FILE* fp = fopen(filename.c_str(), "rt");
- if (fp != NULL) {
- char line[BUFSIZ];
- while (fgets(line, sizeof(line), fp)) {
- if (strchr(line, '\r')) *strchr(line, '\r') = 0;
- if (strchr(line, '\n')) *strchr(line, '\n') = 0;
- if (line[0] != ':') continue; // assume comment line
- if (strlen(line) < 9) {
- WARN("short record %s", line);
- success_ = false;
- continue;
- }
- if (line[7] != '0') {
- WARN("unknown record type %s", line);
- success_ = false;
- } else
- switch (line[8]) {
- case '1': { // 01 eof
- } break;
- case '2': { // 02 segment
- if (!strncmp(line, ":02000002", 9)) {
- char* p = line + 9;
- int s = parseWord(&p);
- if (s != 0x1000) {
- if (s >= FLASH_START && s <= FLASH_END) {
- seg = s - FLASH_START;
- // WARN("at segment %04x\n", seg);
- } else {
- WARN("data should in range %x-%x: %s\n", FLASH_START,
- FLASH_END, line);
- success_ = false;
- }
- }
- }
- isRam = !strcmp(line, ":020000021000EC");
- } break;
- case '0': { // 00 data
- char* p = line + 1;
- int len = parseByte(&p);
- int adr = parseWord(&p);
- parseByte(&p);
- while (len--) {
- if (isRam) {
- int v = parseByte(&p);
- if (v != 0) {
- WARN("WARNING: non-zero RAM byte %02x at %04x\n", v, adr);
- }
- ++adr;
- } else {
- store((seg * 16) + adr++, parseByte(&p));
- }
- }
- } break;
- case '3': { // 03 entry point
- } break;
- default: {
- WARN("unknown record type %s", line);
- success_ = false;
- } break;
- }
- }
- fclose(fp);
- } else {
- WARN("failed to open file '%s'\n", filename.c_str());
- success_ = false;
- }
-
- if (success_) {
- static_assert(sizeof(SignedHeader) == 1024,
- "SignedHeader should be 1024 bytes");
- if (withSignature) {
- // signed images start on 2K boundary.
- if ((low_ & 2047) != 0) {
- WARN("signed images should start on 2K boundary, not %08x\n", low_);
- }
- base_ = low_;
- } else {
- // unsigned images start on odd 1K boundary.
- if ((low_ & 2047) != 1024) {
- WARN("unsigned images should start odd 1K boundary, not %08x\n", low_);
- }
- base_ = low_ - sizeof(SignedHeader);
- }
- }
-
- if (success_) {
- VERBOSE("low %08x, high %08x\n", FLASH_START * 16 + low_,
- FLASH_START * 16 + high_);
- // Round image to multiple of 2K.
- high_ = ((high_ + 2047) / 2048) * 2048;
- ro_base_ = FLASH_START * 16 + base_;
- rx_base_ = FLASH_START * 16 + base_;
- ro_max_ = FLASH_START * 16 + base_ + size();
- rx_max_ = FLASH_START * 16 + base_ + size();
- VERBOSE("base %08lx, size %08lx\n", ro_base_, size());
- }
-
- return success_;
-}
-
-Image::~Image() {}
-
-void Image::toIntelHex(FILE* fout) const {
- for (int i = base_; i < high_; i += 16) {
- // spit out segment record at start of segment.
- if (!((i - base_) & 0xffff)) {
- int s = FLASH_START + (base_ >> 4) + ((i - base_) >> 4);
- fprintf(fout, ":02000002%04X%02X\n", s,
- (~((2 + 2 + (s >> 8)) & 255) + 1) & 255);
- }
- // spit out data records, 16 bytes each.
- fprintf(fout, ":10%04X00", (i - base_) & 0xffff);
- int crc = 16 + (((i - base_) >> 8) & 255) + ((i - base_) & 255);
- for (int n = 0; n < 16; ++n) {
- fprintf(fout, "%02X", mem_[i + n]);
- crc += mem_[i + n];
- }
- fprintf(fout, "%02X", (~(crc & 255) + 1) & 255);
- fprintf(fout, "\n");
- }
-}
-
-void Image::fillPattern(uint32_t pattern) {
- for (int i = high_ - base_; i < 512 * 1024 - 2048; i += 4) {
- *(uint32_t*)(mem_ + i) = pattern;
- }
- high_ = 512 * 1024 - 2048;
-}
-
-void Image::fillRandom() {
- srand(time(NULL));
- for (int i = high_ - base_; i < 512 * 1024 - 2048; i += 4) {
- *(uint32_t*)(mem_ + i) = rand();
- }
- high_ = 512 * 1024 - 2048;
-}
-
-void Image::generate(const std::string& filename, bool hex_output) const {
- FILE* fout = fopen(filename.c_str(), "w");
- if (!fout) return;
-
- if (hex_output)
- toIntelHex(fout);
- else // TODO: we don't expect write to fail, can be made more robust.
- fwrite(mem_ + base_, 1, high_ - base_, fout);
- fclose(fout);
-}
-
-int Image::nibble(char n) {
- switch (n) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return n - '0';
- case 'a':
- case 'A':
- return 10;
- case 'b':
- case 'B':
- return 11;
- case 'c':
- case 'C':
- return 12;
- case 'd':
- case 'D':
- return 13;
- case 'e':
- case 'E':
- return 14;
- case 'f':
- case 'F':
- return 15;
- default:
- WARN("bad hex digit '%c'\n", n);
- success_ = false;
- return 0;
- }
-}
-
-int Image::parseByte(char** p) {
- int result = nibble(**p);
- result *= 16;
- (*p)++;
- result |= nibble(**p);
- (*p)++;
- return result;
-}
-
-int Image::parseWord(char** p) {
- int result = parseByte(p);
- result *= 256;
- result |= parseByte(p);
- return result;
-}
-
-void Image::store(int adr, int v) {
- if (adr < 0 || (size_t)(adr) >= sizeof(mem_)) {
- WARN("illegal adr %04x\n", adr);
- success_ = false;
- return;
- }
- // VERBOSE("mem_[0x%08x]=0x%02x\n", adr, v&255);
- mem_[adr] = v;
- if (adr > high_) high_ = adr;
- if (adr < low_) low_ = adr;
-}
-
-bool Image::sign(PublicKey& key, const SignedHeader* input_hdr,
- const uint32_t fuses[FUSE_MAX], const uint32_t info[INFO_MAX],
- const string& hashesFilename) {
- BIGNUM* sig = NULL;
- SignedHeader* hdr = (SignedHeader*)(&mem_[base_]);
- SHA256_CTX sha256;
- int result;
-
- // List of hashes we actually sign.
- struct {
- uint8_t img_hash[SHA256_DIGEST_LENGTH];
- uint8_t fuses_hash[SHA256_DIGEST_LENGTH];
- uint8_t info_hash[SHA256_DIGEST_LENGTH];
- } hashes;
-
- memcpy(hdr, input_hdr, sizeof(SignedHeader));
-
- hdr->image_size = this->size();
-
- // Fill in key traits
- hdr->keyid = key.n0inv();
- key.modToArray(hdr->key, key.rwords());
-
- // Hash fuses
- SHA256_Init(&sha256);
- SHA256_Update(&sha256, fuses, FUSE_MAX * sizeof(uint32_t));
- SHA256_Final(hashes.fuses_hash, &sha256);
-
- hdr->fuses_chk_ = (hashes.fuses_hash[0] << 0) | (hashes.fuses_hash[1] << 8) |
- (hashes.fuses_hash[2] << 16) | (hashes.fuses_hash[3] << 24);
-
- // Hash info
- SHA256_Init(&sha256);
- SHA256_Update(&sha256, info, INFO_MAX * sizeof(uint32_t));
- SHA256_Final(hashes.info_hash, &sha256);
-
- hdr->info_chk_ = (hashes.info_hash[0] << 0) | (hashes.info_hash[1] << 8) |
- (hashes.info_hash[2] << 16) | (hashes.info_hash[3] << 24);
-
- // Hash img
- int size = this->size() - offsetof(SignedHeader, tag);
- SHA256_Init(&sha256);
- SHA256_Update(&sha256, &hdr->tag, size);
- SHA256_Final(hashes.img_hash, &sha256);
-
- hdr->img_chk_ = (hashes.img_hash[0] << 0) | (hashes.img_hash[1] << 8) |
- (hashes.img_hash[2] << 16) | (hashes.img_hash[3] << 24);
-
- // Dump out values for comparing against boot_rom
- VERBOSE("Himg =");
- for (size_t i = 0; i < sizeof(hashes.img_hash); ++i) {
- VERBOSE("%02x", hashes.img_hash[i]);
- }
- VERBOSE("\n");
-
- VERBOSE("Hfss =");
- for (size_t i = 0; i < sizeof(hashes.fuses_hash); ++i) {
- VERBOSE("%02x", hashes.fuses_hash[i]);
- }
- VERBOSE("\n");
-
- VERBOSE("Hinf =");
- for (size_t i = 0; i < sizeof(hashes.info_hash); ++i) {
- VERBOSE("%02x", hashes.info_hash[i]);
- }
- VERBOSE("\n");
-
- if (!hashesFilename.empty()) {
- // Write hashes to file for subsequent extraneous (re)signing.
- int fd = open(hashesFilename.c_str(), O_CREAT | O_TRUNC | O_RDWR, 0600);
- if (fd >= 0) {
- write(fd, &hashes, sizeof(hashes));
- close(fd);
- }
- }
-
- sig = BN_bin2bn((uint8_t*)(hdr->signature), sizeof(hdr->signature), NULL);
-
- result = key.sign(&hashes, sizeof(hashes), &sig);
-
- if (result != 1) {
- WARN("key.sign: %d\n", result);
- } else {
- key.toArray(hdr->signature, key.rwords(), sig);
- }
-
- if (sig) BN_free(sig);
-
- return result == 1;
-}
diff --git a/util/signer/publickey.cc b/util/signer/publickey.cc
deleted file mode 100644
index 4b977d123e..0000000000
--- a/util/signer/publickey.cc
+++ /dev/null
@@ -1,278 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include <common/publickey.h>
-
-#include <string.h>
-#include <string>
-
-#include <openssl/bn.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-#include <openssl/pem.h>
-#include <openssl/rand.h>
-
-#include <common/gnubby.h>
-
-extern bool FLAGS_verbose;
-
-#define VERBOSE(...) do{if(FLAGS_verbose){fprintf(stderr, __VA_ARGS__);fflush(stderr);}}while(0)
-#define WARN(...) do{fprintf(stderr, __VA_ARGS__);}while(0)
-#define FATAL(...) do{fprintf(stderr, __VA_ARGS__);abort();}while(0)
-
-PublicKey::PublicKey(const std::string& filename) : key_(NULL), publicOnly_(true) {
- EVP_PKEY* pkey = NULL;
- BIO* bio = BIO_new(BIO_s_file());
-
- OpenSSL_add_all_ciphers(); // needed to decrypt PEM.
- if (BIO_read_filename(bio, filename.c_str()) == 1) {
- pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
-
- if (pkey) {
- publicOnly_ = false;
- } else {
- // Try read as public key.
- (void)BIO_reset(bio);
- pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
- if (pkey) {
- VERBOSE("read public key only, assuming gnubby for signing..\n");
- }
- }
- }
-
- if (!pkey) {
- WARN("loadKey: failed to load RSA key from '%s'\n", filename.c_str());
- }
-
- BIO_free_all(bio);
- key_ = pkey;
-}
-
-PublicKey::~PublicKey() {
- if (key_) {
- EVP_PKEY_free(key_);
- key_ = NULL;
- }
-}
-
-bool PublicKey::ok() {
- return key_ != NULL;
-}
-
-size_t PublicKey::nwords() {
- RSA* rsa = EVP_PKEY_get1_RSA(key_);
- size_t result = (BN_num_bytes(rsa->n) + 3) / 4;
- RSA_free(rsa);
- return result;
-}
-
-uint32_t PublicKey::public_exponent() {
- RSA* rsa = EVP_PKEY_get1_RSA(key_);
- uint32_t result = BN_get_word(rsa->e);
- RSA_free(rsa);
- return result;
-}
-
-uint32_t PublicKey::n0inv() {
- RSA* rsa = EVP_PKEY_get1_RSA(key_);
- BN_CTX* ctx = BN_CTX_new();
- BIGNUM* r = BN_new();
- BIGNUM* rem = BN_new();
- BIGNUM* n0inv = BN_new();
- BN_set_bit(r, 32); // 2**32
- BN_div(NULL, rem, rsa->n, r, ctx); // low 32 bit
- BN_mod_inverse(n0inv, rem, r, ctx);
-
- uint32_t result = 0 - BN_get_word(n0inv);
-
- BN_free(n0inv);
- BN_free(rem);
- BN_free(r);
- BN_CTX_free(ctx);
- RSA_free(rsa);
-
- return result;
-}
-
-void PublicKey::print(const char* tag, size_t nwords, BIGNUM* n) {
- BN_CTX* ctx = BN_CTX_new();
- BIGNUM* N = BN_new();
- BIGNUM* r = BN_new();
- BIGNUM* d = BN_new();
- BIGNUM* rem = BN_new();
-
- BN_set_bit(r, 32); // 2^32
- BN_copy(N, n);
-
- printf("const uint32_t %s[%lu + 1] = {", tag, nwords);
- printf("0x%08x, ", n0inv());
- for (size_t i = 0; i < nwords; ++i) {
- if (i) printf(", ");
- BN_div(N, rem, N, r, ctx);
- printf("0x%08lx", BN_get_word(rem));
- }
- printf("};\n");
-
- BN_free(rem);
- BN_free(d);
- BN_free(r);
- BN_free(N);
- BN_CTX_free(ctx);
-}
-
-void PublicKey::print(const char* tag, size_t nwords,
- uint8_t* data, size_t len) {
- BIGNUM* n = BN_bin2bn(data, len, NULL);
- print(tag, nwords, n);
- BN_free(n);
-}
-
-void PublicKey::print(const char* tag) {
- RSA* rsa = EVP_PKEY_get1_RSA(key_);
- print(tag, rwords(), rsa->n);
- RSA_free(rsa);
-}
-
-/*static*/
-void PublicKey::toArray(uint32_t* dst, size_t nwords, BIGNUM* n) {
- BN_CTX* ctx = BN_CTX_new();
- BIGNUM* N = BN_new();
- BIGNUM* r = BN_new();
- BIGNUM* d = BN_new();
- BIGNUM* rem = BN_new();
-
- BN_set_bit(r, 32); // 2^32
- BN_copy(N, n);
-
- for (size_t i = 0; i < nwords; ++i) {
- BN_div(N, rem, N, r, ctx);
- *dst++ = BN_get_word(rem);
- }
-
- BN_free(rem);
- BN_free(d);
- BN_free(r);
- BN_free(N);
- BN_CTX_free(ctx);
-}
-
-void PublicKey::modToArray(uint32_t* dst, size_t nwords) {
- RSA* rsa = EVP_PKEY_get1_RSA(key_);
- toArray(dst, nwords, rsa->n);
- RSA_free(rsa);
-}
-
-int PublicKey::encrypt(uint8_t* msg, int msglen, uint8_t* out) {
- RSA* rsa = EVP_PKEY_get1_RSA(key_);
- int result =
- RSA_public_encrypt(msglen, msg, out, rsa, RSA_PKCS1_OAEP_PADDING);
- RSA_free(rsa);
- return result;
-}
-
-int PublicKey::decrypt(uint8_t* msg, int msglen, uint8_t* out) {
- RSA* rsa = EVP_PKEY_get1_RSA(key_);
- int result =
- RSA_private_decrypt(msglen, msg, out, rsa, RSA_PKCS1_OAEP_PADDING);
- RSA_free(rsa);
- return result;
-}
-
-
-int PublicKey::raw(uint8_t* in, int inlen, BIGNUM** out) {
- RSA* rsa = EVP_PKEY_get1_RSA(key_);
- BN_CTX* ctx = BN_CTX_new();
- BIGNUM* m = BN_new();
- BIGNUM* r = BN_new();
- BN_bin2bn(in, inlen, m);
- int result = BN_mod_exp(r, m, rsa->d, rsa->n, ctx);
- if (result == 1) {
- *out = BN_dup(r);
- }
- BN_free(r);
- BN_free(m);
- BN_CTX_free(ctx);
- RSA_free(rsa);
- return result;
-}
-
-// Sign message.
-// Produces signature * R mod N (Montgomery format).
-// Returns 1 on success.
-int PublicKey::sign(const void* msg, size_t msglen, BIGNUM** output) {
- int result = 0;
- EVP_MD_CTX* ctx = NULL;
- BN_CTX* bnctx = NULL;
- BIGNUM* tmp = NULL;
- RSA* rsa = NULL;
- uint8_t* sig = NULL;
- unsigned int siglen = 0;
-
- unsigned int tmplen = EVP_PKEY_size(key_);
-
- ctx = EVP_MD_CTX_create();
- if (!ctx) goto __fail;
-
- EVP_MD_CTX_init(ctx);
- EVP_DigestInit(ctx, EVP_sha256());
- if (EVP_DigestUpdate(ctx, msg, msglen) != 1) goto __fail;
-
- sig = (uint8_t*)malloc(tmplen);
-
- if (publicOnly_) {
- if (nwords() == 64) {
- // 2048 bit public key : gnubby
- fprintf(stderr, "gnubby signing.."); fflush(stderr);
-
- Gnubby gnubby;
- result = gnubby.sign(ctx, sig, &siglen, key_);
- fprintf(stderr, "Gnubby.sign: %d\n", result);
- } else {
- // other public key : best have signature prefilled
- fprintf(stderr, "WARNING: public key size %lu; assuming preloaded signature\n", nwords());
- fprintf(stderr, " Likely you are trying to use the real rom key, try the -dev flavor\n");
- fflush(stderr);
- siglen = BN_bn2bin(*output, sig);
- result = 1;
- }
- } else {
- VERBOSE("ossl signing..");
- result = EVP_SignFinal(ctx, sig, &siglen, key_);
- VERBOSE("EVP_SignFinal: %d\n", result);
- }
-
- if (result != 1) goto __fail;
-
- tmp = BN_bin2bn(sig, siglen, NULL);
-
- // compute R*sig mod N
- rsa = EVP_PKEY_get1_RSA(key_);
- if (BN_lshift(tmp, tmp, rwords() * 32) != 1) goto __fail;
-
- bnctx = BN_CTX_new();
- if (BN_mod(tmp, tmp, rsa->n, bnctx) != 1) goto __fail;
- *output = BN_dup(tmp);
-
-__fail:
- if (tmp) BN_free(tmp);
- if (rsa) RSA_free(rsa);
- if (sig) free(sig);
- if (ctx) EVP_MD_CTX_destroy(ctx);
- if (bnctx) BN_CTX_free(bnctx);
-
- return result;
-}
-
-int PublicKey::writeToGnubby() {
- if (publicOnly_) return -1;
-
- RSA* rsa = EVP_PKEY_get1_RSA(key_);
-
- Gnubby gnubby;
- int result = gnubby.write(rsa);
-
- RSA_free(rsa);
-
- return result;
-}