diff options
-rw-r--r-- | Makefile.rules | 11 | ||||
-rw-r--r-- | util/signer/aes.cc | 51 | ||||
-rw-r--r-- | util/signer/build.mk | 12 | ||||
-rw-r--r-- | util/signer/codesigner.cc | 454 | ||||
-rw-r--r-- | util/signer/common/aes.h | 24 | ||||
-rw-r--r-- | util/signer/common/ecdh.h | 24 | ||||
-rw-r--r-- | util/signer/common/gnubby.h | 41 | ||||
-rw-r--r-- | util/signer/common/image.h | 52 | ||||
-rw-r--r-- | util/signer/common/publickey.h | 66 | ||||
-rw-r--r-- | util/signer/common/signed_header.h | 48 | ||||
-rw-r--r-- | util/signer/ecdh.cc | 47 | ||||
-rw-r--r-- | util/signer/gnubby.cc | 491 | ||||
-rw-r--r-- | util/signer/image.cc | 414 | ||||
-rw-r--r-- | util/signer/publickey.cc | 115 | ||||
-rw-r--r-- | util/signer/publickey.h | 52 | ||||
-rw-r--r-- | util/signer/rom-testkey-A.pem | 364 | ||||
-rw-r--r-- | util/signer/rom-testkey.pem | 45 | ||||
-rw-r--r-- | util/signer/signed_header.h | 29 |
18 files changed, 2074 insertions, 266 deletions
diff --git a/Makefile.rules b/Makefile.rules index e2951d095a..cdd75caa33 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -40,8 +40,9 @@ cmd_flat_to_obj = $(CC) -T $(out)/firmware_image.lds -nostdlib $(CPPFLAGS) \ # Allow the .roshared section to overlap other sections (itself) cmd_ec_elf_to_flat ?= $(OBJCOPY) --set-section-flags .roshared=share \ -O binary $< $@ -cmd_raw_to_flat ?= $(out)/util/signer util/signer/rom-testkey.pem $< \ - && mv $<.signed $@ +cmd_elf_to_signed ?= $(out)/util/signer --key=util/signer/rom-testkey-A.pem \ + --input=$< --format=bin --output=$@.signed \ + && mv $@.signed $@ cmd_elf_to_dis = $(OBJDUMP) -D $< > $@ cmd_elf_to_hex = $(OBJCOPY) -O ihex $< $@ cmd_bin_to_hex = $(OBJCOPY) -I binary -O ihex \ @@ -57,7 +58,7 @@ cmd_c_to_build = $(BUILDCC) $(BUILD_CFLAGS) \ -MMD -MF $@.d -o $@ cmd_c_to_host = $(HOSTCC) $(HOST_CFLAGS) -MMD -MF $@.d -o $@ \ $(sort $(foreach c,$($(*F)-objs),util/$(c:%.o=%.c)) $*.c) -cmd_cxx_to_host = $(HOSTCXX) -std=c++0x $(COMMON_WARN) \ +cmd_cxx_to_host = $(HOSTCXX) -std=c++0x $(COMMON_WARN) $(HOST_CXXFLAGS)\ -I ./$($(notdir $@)_ROOT) -o $@ $(filter %.cc,$^) $($(notdir $@)_LIBS) cmd_host_test = ./util/run_host_test $* $(silent) cmd_version = ./util/getversion.sh > $@ @@ -201,8 +202,8 @@ $(out)/RW/ec.RW.flat: $(out)/RW/ec.RW.elf $(out)/RO/ec.RO.flat.raw: $(out)/RO/ec.RO.elf $(out)/RO/ec.RO.smap $(call quiet,ec_elf_to_flat,OBJCOPY) -$(out)/RO/ec.RO.flat: $(out)/RO/ec.RO.flat.raw - $(call quiet,raw_to_flat,RO_SIGN) +$(out)/RO/ec.RO.flat: $(out)/RO/ec.RO.elf $(out)/RO/ec.RO.smap + $(call quiet,elf_to_signed,RO_SIGN) $(out)/RO/%.hex: $(out)/RO/%.flat $(call quiet,bin_to_hex,OBJCOPY) diff --git a/util/signer/aes.cc b/util/signer/aes.cc new file mode 100644 index 0000000000..4d120a102a --- /dev/null +++ b/util/signer/aes.cc @@ -0,0 +1,51 @@ +/* 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/build.mk b/util/signer/build.mk index 7e7db38997..07db0ea7ea 100644 --- a/util/signer/build.mk +++ b/util/signer/build.mk @@ -2,15 +2,15 @@ # 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. -# -# Lock library -# -signer_LIBS := -lcrypto +signer_LIBS := -lcrypto -lelf -lusb-1.0 -lxml2 signer_ROOT := util/signer -SIGNER_DEPS := $(addprefix $(signer_ROOT)/, codesigner.cc \ - publickey.cc publickey.h signed_header.h) +signer_INC := $(addprefix common/, aes.h ecdh.h gnubby.h \ + image.h publickey.h signed_header.h) +signer_SRC := codesigner.cc publickey.cc image.cc gnubby.cc aes.cc ecdh.cc +SIGNER_DEPS := $(addprefix $(signer_ROOT)/, $(signer_SRC) $(signer_INC)) +HOST_CXXFLAGS += -I/usr/include/libxml2 $(out)/util/signer: $(SIGNER_DEPS) $(call quiet,cxx_to_host,HOSTCXX) diff --git a/util/signer/codesigner.cc b/util/signer/codesigner.cc index 989e87b3c5..cf3513d773 100644 --- a/util/signer/codesigner.cc +++ b/util/signer/codesigner.cc @@ -1,122 +1,430 @@ -// -// 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. -// +/* 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 <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <getopt.h> + +#include <common/image.h> +#include <common/publickey.h> +#include <common/signed_header.h> +//#include <rapidjson/document.h> + +#include <string> +#include <map> +#include <vector> #include <iostream> #include <fstream> #include <sstream> -#include <ios> -#include <string> +#include <libxml/parser.h> +#include <libxml/tree.h> -#include <openssl/pem.h> +using namespace std; +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; -#include <signed_header.h> -#include <publickey.h> + 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); -using namespace std; -static uint8_t *mem; // this is where the file to sign is loaded -// Size of the file to be signed (including 1Kb signature). -static size_t flat_size; + if (!strcmp(key, (const char*)keyName)) { + // Found our key, save val and done. + xmlFree(keyName); + val = valData; + break; + } + xmlFree(valData); + xmlFree(keyName); + } -int LoadFlatFile(const char *name, size_t header_size) -{ - ifstream::pos_type fileSize; - ifstream FlatFile (name, ios::in | ios::binary | ios::ate); + val = get_val(cur_node, key); + if (val) { + // Found our key somewhere deeper down; done. + break; + } + } - if(!FlatFile.is_open()) { - fprintf(stderr, "failed to open %s\n", name); - return -1; + return val; +} + +static +bool print_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; } - flat_size = FlatFile.tellg(); + // 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"); - mem = new uint8_t[flat_size]; - FlatFile.seekg(0, ios::beg); - if(!FlatFile.read((char *)mem, flat_size)) { - fprintf(stderr, "failed to read file %s\n", name); - return -1; + // 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; } - FlatFile.close(); - // verify that there is enough room at the bottom - for (size_t i = 0; i < header_size; i++) - if (mem[i]) { - fprintf(stderr, "nonzero value at offset %zd\n", i); - return -1; + 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 = print_fuse(a_node->parent->parent->parent, ids, bits); + } } - return 0; + if (content) xmlFree(content); + + if (!done && cur_node->children) { + done = find_fuses(cur_node->children, ids, bits); + } + } + + return done; } -int SaveSignedFile(const char *name) -{ - FILE* fp = fopen(name, "wb"); +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 (!fp) { - fprintf(stderr, "failed to open file '%s': %s\n", name, strerror(errno)); - return -1; + 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); + } } - if (fwrite(mem, 1, flat_size, fp) != flat_size) { - fprintf(stderr, "failed to write %zd bytes to '%s': %s\n", - flat_size, name, strerror(errno)); - return -1; + + 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); } - fclose(fp); - return 0; + xmlCleanupParser(); + xmlMemoryDump(); + + return result; } -// Sing the previously read file. Return zero on success, nonzero on failure. -static int sign(PublicKey& key, const SignedHeader* input_hdr) { - BIGNUM* sig = NULL; - SignedHeader* hdr = (SignedHeader*)(&mem[0]); - int result; - memcpy(hdr, input_hdr, sizeof(SignedHeader)); +// Read JSON, populate map, name -> val +bool readJSON(const string& filename, + string* tag, + uint32_t* keyId, + uint32_t* p4cl, + map<string, uint32_t>* fusemap) { + bool result = false; +#if 0 + ifstream ifs(filename.c_str()); + if (ifs) { + + // Touch up a bit to allow for comments. + string s; + while (ifs) { + string line; + getline(ifs, line); + size_t nonspace = line.find_first_not_of(" \t"); + if (nonspace != string::npos && + line.find("//", nonspace) == nonspace) { + continue; + } + s.append(line); + } - result = key.sign(&hdr->tag, flat_size - offsetof(SignedHeader, tag), &sig); + // Try parse. + rapidjson::Document d; + if (d.Parse(s.c_str()).HasParseError()) { + fprintf(stderr, "JSON %s[%lu]: parse error\n", + filename.c_str(), d.GetErrorOffset()); + } else { + const rapidjson::Document::ValueType& fuses = d["fuses"]; + for (auto it = fuses.MemberBegin(); it != fuses.MemberEnd(); ++it) { + fusemap->insert(make_pair(it->name.GetString(), it->value.GetInt())); + } - if (result == 1) { - hdr->image_size = flat_size; - size_t nwords = key.nwords(); - key.toArray(hdr->signature, nwords, sig); - } else { - fprintf(stderr, "ossl_sign:%d\n", result); + const rapidjson::Document::ValueType& keyid = d["keyId"]; + *keyId = keyid.GetInt(); + + const rapidjson::Document::ValueType& P4cl = d["p4cl"]; + *p4cl = P4cl.GetInt(); + + const rapidjson::Document::ValueType& Tag = d["tag"]; + tag->assign(Tag.GetString()); + + result = true; + } } +#endif + return result; +} - if (sig) - BN_free(sig); +string inputFilename; +string outputFilename; +string keyFilename; +string xmlFilename; +string jsonFilename; +string outputFormat; - return result != 1; +void usage(int argc, char* argv[]) { + fprintf(stderr, "Usage: %s options\n" + "--input=$elf-filename\n" + "--output=output-filename\n" + "--key=$pem-filename\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", + argv[0]); +} + +int getOptions(int argc, char* argv[]) { + static struct option long_options[] = { + // name, has_arg + {"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'}, + {"xml", required_argument, NULL, 'x'}, + {0, 0, 0, 0} + }; + int c, option_index = 0; + outputFormat.assign("hex"); + while ((c = getopt_long(argc, argv, "i:o:k:x:j:f:h", + 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 'i': + inputFilename.assign(optarg); + break; + case 'o': + outputFilename.assign(optarg); + break; + case 'k': + keyFilename.assign(optarg); + break; + case 'x': + xmlFilename.assign(optarg); + break; + case 'j': + jsonFilename.assign(optarg); + break; + case 'f': + outputFormat.assign(optarg); + break; + case 'h': + usage(argc, argv); + return 1; + 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 (argc < 3) { - fprintf(stderr, "Usage: %s pem-file [hexfile|flatfile]\n", argv[0]); + if (getOptions(argc, argv)) { exit(1); } - const char* arg = argv[2]; - PublicKey key(argv[1]); + PublicKey key(keyFilename); if (!key.ok()) return -1; + // Load elf. + Image image; + if (!image.fromElf(inputFilename)) return -2; + SignedHeader hdr; - // Load input file - if (LoadFlatFile(arg, sizeof(hdr))) - return -2; + 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(); + + // Parse signing manifest. + map<string, uint32_t> fuses; + uint32_t keyId = key.n0inv(); // default, in case no JSON. + uint32_t json_p4cl = 0; + string tag; + + if (!jsonFilename.empty() && + !readJSON(jsonFilename, &tag, &keyId, &json_p4cl, &fuses)) { + fprintf(stderr, "Failed to read JSON from '%s'\n", jsonFilename.c_str()); + abort(); + } + + // Check keyId. + fprintf(stderr, "keyId: %08x\n", keyId); + if (keyId != hdr.keyid) { + fprintf(stderr, "mismatched keyid\n"); + abort(); + } + + // Fill in tag. + fprintf(stderr, "tag: \"%s\"\n", tag.c_str()); + strncpy((char*)(&hdr.tag), tag.c_str(), sizeof(hdr.tag)); + + // List the specific fuses and values. + fprintf(stderr, "care about %lu fuses:\n", fuses.size()); + for (auto it : fuses) { + fprintf(stderr, "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)) { + fprintf(stderr, "Failed to read XML from '%s'\n", xmlFilename.c_str()); + abort(); + } + + if (json_p4cl != xml_p4cl) { + fprintf(stderr, "mismatching p4cl: xml %u vs. json %u\n", + xml_p4cl, json_p4cl); + abort(); + } + + fprintf(stderr, "found %lu fuse definitions\n", fuse_ids.size()); + assert(fuse_ids.size() < FUSE_MAX); + for (auto it : fuse_ids) { + fprintf(stderr, "fuse '%s' at %u, width %u\n", + it.first.c_str(), it.second, fuse_bits[it.first]); + } - if (sign(key, &hdr)) - return -3; + // Compute fuse_values array, according to manifest and xml. + uint32_t fuse_values[FUSE_MAX]; + memset(fuse_values, FUSE_IGNORE, sizeof(fuse_values)); - if (SaveSignedFile((std::string(arg) + std::string(".signed")).c_str())) - return -4; + for (auto x : fuses) { + map<string, uint32_t>::const_iterator it = fuse_ids.find(x.first); + if (it == fuse_ids.end()) { + fprintf(stderr, "cannot find definition for fuse '%s'\n", x.first.c_str()); + abort(); + } + uint32_t idx = it->second; + assert(idx < FUSE_MAX); + uint32_t mask = (1 << fuse_bits[x.first]) - 1; + if ((x.second & mask) != x.second) { + fprintf(stderr, "specified fuse value too large\n"); + abort(); + } + uint32_t val = FUSE_PADDING & ~mask; + val |= x.second; + + fuse_values[idx] = val; + hdr.markFuse(idx); + } + + // Print out fuse hash input. + fprintf(stderr, "expected fuse state:\n"); + for (size_t i = 0; i < FUSE_MAX; ++i) { + fprintf(stderr, "%08x ", fuse_values[i]); + } + fprintf(stderr, "\n"); + + // Sign image. + if (image.sign(key, &hdr, fuse_values)) { + image.generate(outputFilename, outputFormat == "hex"); + } else { + fprintf(stderr, "failed to sign\n"); + } return 0; } diff --git a/util/signer/common/aes.h b/util/signer/common/aes.h new file mode 100644 index 0000000000..08e4eefb50 --- /dev/null +++ b/util/signer/common/aes.h @@ -0,0 +1,24 @@ +/* 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 new file mode 100644 index 0000000000..52751491d7 --- /dev/null +++ b/util/signer/common/ecdh.h @@ -0,0 +1,24 @@ +/* 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 new file mode 100644 index 0000000000..8829862268 --- /dev/null +++ b/util/signer/common/gnubby.h @@ -0,0 +1,41 @@ +/* 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; + +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); + + 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); + + libusb_context* ctx_; + libusb_device_handle* handle_; +}; + +#define MAX_APDU_SIZE 1200 +#define LIBUSB_ERR -1 + +#define VERBOSE + +#endif // __EC_UTIL_SIGNER_COMMON_GNUBBY_H diff --git a/util/signer/common/image.h b/util/signer/common/image.h new file mode 100644 index 0000000000..c1468bb079 --- /dev/null +++ b/util/signer/common/image.h @@ -0,0 +1,52 @@ +/* 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(); + + 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[]); + 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_; } + + 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 new file mode 100644 index 0000000000..6a899be9ac --- /dev/null +++ b/util/signer/common/publickey.h @@ -0,0 +1,66 @@ +/* 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 set at 3104 bits (97*32). + size_t rwords() const { return 96 + 1; } + + // # of significant words in modulus. + size_t nwords(); + + uint32_t public_exponent(); + + // -1 / least significant word of modulus. + uint32_t n0inv(); + + // PKCS1.5 SHA256 + // Mongomery 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); + + // outputs rwords() words. + void print(const char* tag); + + // outputs rwords() words. + void toArray(uint32_t* dst); + + 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 new file mode 100644 index 0000000000..d04f1ac088 --- /dev/null +++ b/util/signer/common/signed_header.h @@ -0,0 +1,48 @@ +/* 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 +#define FUSE_IGNORE 0xaaaaaaaa +#define FUSE_MAX 160 + +typedef struct SignedHeader { +#ifdef __cplusplus + SignedHeader() : magic(-1), image_size(0) { + memset(signature, 'S', sizeof(signature)); + memset(tag, 'T', sizeof(tag)); + memset(fusemap, 0, sizeof(fusemap)); + memset(_pad, 0xdd, sizeof(_pad)); + } + + void markFuse(uint32_t n) { + assert(n < FUSE_MAX); + fusemap[n / 32] |= 1 << (n & 31); + } +#endif // __cplusplus + + uint32_t magic; // -1 + uint32_t signature[96 + 1]; + uint32_t tag[7]; + uint32_t keyid; + uint32_t image_size; + uint32_t ro_base; + uint32_t ro_max; + uint32_t rx_base; + uint32_t rx_max; + uint32_t fusemap[FUSE_MAX / (8 * sizeof(uint32_t))]; + uint32_t _pad[256 - 1 - 97 - 7 - 6*1 - 5]; +} SignedHeader; + +#ifdef __cplusplus +static_assert(sizeof(SignedHeader) == 1024, "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 new file mode 100644 index 0000000000..d5f9cfe25e --- /dev/null +++ b/util/signer/ecdh.cc @@ -0,0 +1,47 @@ +/* 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 new file mode 100644 index 0000000000..8e10181ea0 --- /dev/null +++ b/util/signer/gnubby.cc @@ -0,0 +1,491 @@ +/* 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/evp.h> +#include <openssl/sha.h> + +#include <common/aes.h> +#include <common/ecdh.h> + +#include <string> + +// 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(...) fprintf(stderr, __VA_ARGS__) +#define DLOG(...) + +// 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() { + libusb_init(&ctx_); + libusb_set_debug(ctx_, 3); + + 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_); + handle_ = NULL; + } +} + +// 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) 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()); +} + +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; + + 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; + + DWORD image_hash_len = SHA256_DIGEST_LENGTH; + + // 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); + + // 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); + + // TODO: compare against key + + 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; +} diff --git a/util/signer/image.cc b/util/signer/image.cc new file mode 100644 index 0000000000..4b9db30608 --- /dev/null +++ b/util/signer/image.cc @@ -0,0 +1,414 @@ +/* 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 <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <libelf.h> +#include <gelf.h> + +#include <common/publickey.h> + +#include <openssl/bn.h> +#include <openssl/evp.h> +#include <openssl/rsa.h> +#include <openssl/pem.h> +#include <openssl/rand.h> + +#include <common/signed_header.h> + +#include <string> + +using namespace std; + +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 +} + +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) { + fprintf(stderr, "failed to open '%s'\n", filename.c_str()); + goto fail; + } + if ((fstat(fd, &elf_stats)) < 0) { + fprintf(stderr, "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) { + fprintf(stderr, "cannot malloc %lu\n", elf_stats.st_size); + goto fail; + } + + if (read(fd, base_ptr, elf_stats.st_size) < elf_stats.st_size) { + fprintf(stderr, "cannot read from '%s'\n", filename.c_str()); + goto fail; + } + + // Sniff content for sanity + if (*(uint32_t*) base_ptr != 0x464c457f) { +// fprintf(stderr, "'%s' is not elf file\n", filename); + goto fail; + } + + if (elf_version(EV_CURRENT) == EV_NONE) { + fprintf(stderr, "Warning: elf library is out of data!\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); + + printf("type %08x; flags %08lx ", shdr.sh_type, shdr.sh_flags); + printf("%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) { + printf("phdr %08lx(@%08lx) [%08lx/%08lx]", + phdr.p_vaddr, phdr.p_paddr, phdr.p_filesz, phdr.p_memsz); + + if (phdr.p_filesz != phdr.p_memsz) { + printf(" (not loading)\n"); + continue; + } + + // Ignore sections outside our flash range + if (phdr.p_paddr < FLASH_START * 16 || + phdr.p_paddr + phdr.p_memsz >= FLASH_END * 16) { + continue; + } + + printf("\n"); + + // Track ro boundaries + if (phdr.p_paddr < ro_base_) { + ro_base_ = phdr.p_paddr; + } + if (phdr.p_paddr + phdr.p_memsz > ro_max_) { + ro_max_ = phdr.p_paddr + phdr.p_memsz; + } + + // 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_; + + if (rx_base_ < base_ + FLASH_START * 16 + sizeof(SignedHeader)) { + // Fix-up 1K header that is part of rx in EC builds + rx_base_ = base_ + FLASH_START * 16 + sizeof(SignedHeader); + } + + high_ = ((high_ + 2047) / 2048) * 2048; // Round image to multiple of 2K. + + printf("Rounded image size %lu\n", size()); + printf("ro_base %08lx..%08lx\n", ro_base_, ro_max_); + printf("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) { + fprintf(stderr, "short record %s", line); + success_ = false; + continue; + } + if (line[7] != '0') { + fprintf(stderr, "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; + //fprintf(stderr, "at segment %04x\n", seg); + } else { + fprintf(stderr, "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) { + fprintf(stderr, "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: { + fprintf(stderr, "unknown record type %s", line); + success_ = false; + } break; + } + } + fclose(fp); + } else { + fprintf(stderr, "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) { + fprintf(stderr, "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) { + fprintf(stderr, "unsigned images should start odd 1K boundary, not %08x\n", low_); + } + base_ = low_ - sizeof(SignedHeader); + } + } + + if (success_) { + fprintf(stderr, "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(); + fprintf(stderr, "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::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_, 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: + fprintf(stderr, "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_)) { + fprintf(stderr, "illegal adr %04x\n", adr); + success_ = false; + return; + } + 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]) { + 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]; + // TODO: flash_fuses_hash + } hashes; + + memcpy(hdr, input_hdr, sizeof(SignedHeader)); + hdr->image_size = this->size(); + + // Hash img + int size = this->size() - offsetof(SignedHeader, tag); + SHA256_Init(&sha256); + SHA256_Update(&sha256, &hdr->tag, size); + SHA256_Final(hashes.img_hash, &sha256); + + fprintf(stderr, "img hash :"); + for (size_t i = 0; i < sizeof(hashes.img_hash); ++i) { + fprintf(stderr, "%02x", hashes.img_hash[i]); + } + fprintf(stderr, "\n"); + + // Hash fuses + SHA256_Init(&sha256); + SHA256_Update(&sha256, fuses, FUSE_MAX * sizeof(uint32_t)); + SHA256_Final(hashes.fuses_hash, &sha256); + + fprintf(stderr, "fuses hash:"); + for (size_t i = 0; i < sizeof(hashes.fuses_hash); ++i) { + fprintf(stderr, "%02x", hashes.fuses_hash[i]); + } + fprintf(stderr, "\n"); + + result = key.sign(&hashes, sizeof(hashes), &sig); + + if (result != 1) { + fprintf(stderr, "key.sign:%d\n", result); + } else { + size_t rwords = key.rwords(); + key.toArray(hdr->signature, rwords, sig); + } + + if (sig) BN_free(sig); + + return result == 1; +} diff --git a/util/signer/publickey.cc b/util/signer/publickey.cc index 6dd99dd146..51499ab52f 100644 --- a/util/signer/publickey.cc +++ b/util/signer/publickey.cc @@ -1,11 +1,10 @@ -// -// 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 "publickey.h" +/* 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> @@ -14,50 +13,64 @@ #include <openssl/pem.h> #include <openssl/rand.h> -PublicKey::PublicKey(const char* filename) { +#include <common/gnubby.h> + +PublicKey::PublicKey(const std::string& filename) : key_(NULL), publicOnly_(true) { EVP_PKEY* pkey = NULL; BIO* bio = BIO_new(BIO_s_file()); - if (BIO_read_filename(bio, filename) == 1) { + 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) { + fprintf(stderr, "read public key only, assuming gnubby for signing..\n"); + } + } } - if (NULL == pkey) { - fprintf(stderr, "loadKey: failed to load RSA key from '%s'", - filename); + if (!pkey) { + fprintf(stderr, "loadKey: failed to load RSA key from '%s'\n", + filename.c_str()); } BIO_free_all(bio); - key = pkey; + key_ = pkey; } PublicKey::~PublicKey() { - if (key) { - EVP_PKEY_free(key); - key = NULL; + if (key_) { + EVP_PKEY_free(key_); + key_ = NULL; } } bool PublicKey::ok() { - return key != NULL; + return key_ != NULL; } size_t PublicKey::nwords() { - RSA* rsa = EVP_PKEY_get1_RSA(key); + 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); + 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); + RSA* rsa = EVP_PKEY_get1_RSA(key_); BN_CTX* ctx = BN_CTX_new(); BIGNUM* r = BN_new(); BIGNUM* rem = BN_new(); @@ -77,7 +90,6 @@ uint32_t PublicKey::n0inv() { return result; } -/*static*/ void PublicKey::print(const char* tag, size_t nwords, BIGNUM* n) { BN_CTX* ctx = BN_CTX_new(); BIGNUM* N = BN_new(); @@ -88,7 +100,8 @@ void PublicKey::print(const char* tag, size_t nwords, BIGNUM* n) { BN_set_bit(r, 32); // 2^32 BN_copy(N, n); - printf("const uint32_t %s[%lu] = {", tag, nwords); + 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); @@ -103,7 +116,6 @@ void PublicKey::print(const char* tag, size_t nwords, BIGNUM* n) { BN_CTX_free(ctx); } -/*static*/ void PublicKey::print(const char* tag, size_t nwords, uint8_t* data, size_t len) { BIGNUM* n = BN_bin2bn(data, len, NULL); @@ -112,32 +124,8 @@ void PublicKey::print(const char* tag, size_t nwords, } void PublicKey::print(const char* tag) { - RSA* rsa = EVP_PKEY_get1_RSA(key); - print(tag, nwords(), rsa->n); - RSA_free(rsa); -} - -void PublicKey::printAll(const char* tag) { - std::string t(tag); - printf("#define %s_EXP %u\n", tag, public_exponent()); - printf("#define %s_INV 0x%08x\n", tag, n0inv()); - RSA* rsa = EVP_PKEY_get1_RSA(key); - print((t + "_MOD").c_str(), nwords(), rsa->n); - - BN_CTX* ctx = BN_CTX_new(); - BIGNUM* RR = BN_new(); - BIGNUM* rem = BN_new(); - BIGNUM* quot = BN_new(); - BN_set_bit(RR, nwords() * 32 * 2); - BN_div(quot, rem, RR, rsa->n, ctx); - - print((t + "_RR").c_str(), nwords(), rem); - - BN_free(quot); - BN_free(rem); - BN_free(RR); - BN_CTX_free(ctx); - + RSA* rsa = EVP_PKEY_get1_RSA(key_); + print(tag, rwords(), rsa->n); RSA_free(rsa); } @@ -165,7 +153,7 @@ void PublicKey::toArray(uint32_t* dst, size_t nwords, BIGNUM* n) { } int PublicKey::encrypt(uint8_t* msg, int msglen, uint8_t* out) { - RSA* rsa = EVP_PKEY_get1_RSA(key); + RSA* rsa = EVP_PKEY_get1_RSA(key_); int result = RSA_public_encrypt(msglen, msg, out, rsa, RSA_PKCS1_OAEP_PADDING); RSA_free(rsa); @@ -173,7 +161,7 @@ int PublicKey::encrypt(uint8_t* msg, int msglen, uint8_t* out) { } int PublicKey::decrypt(uint8_t* msg, int msglen, uint8_t* out) { - RSA* rsa = EVP_PKEY_get1_RSA(key); + RSA* rsa = EVP_PKEY_get1_RSA(key_); int result = RSA_private_decrypt(msglen, msg, out, rsa, RSA_PKCS1_OAEP_PADDING); RSA_free(rsa); @@ -182,7 +170,7 @@ int PublicKey::decrypt(uint8_t* msg, int msglen, uint8_t* out) { int PublicKey::raw(uint8_t* in, int inlen, BIGNUM** out) { - RSA* rsa = EVP_PKEY_get1_RSA(key); + RSA* rsa = EVP_PKEY_get1_RSA(key_); BN_CTX* ctx = BN_CTX_new(); BIGNUM* m = BN_new(); BIGNUM* r = BN_new(); @@ -210,7 +198,7 @@ int PublicKey::sign(const void* msg, size_t msglen, BIGNUM** output) { uint8_t* sig = NULL; unsigned int siglen = 0; - unsigned int tmplen = EVP_PKEY_size(key); + unsigned int tmplen = EVP_PKEY_size(key_); ctx = EVP_MD_CTX_create(); if (!ctx) goto __fail; @@ -220,14 +208,29 @@ int PublicKey::sign(const void* msg, size_t msglen, BIGNUM** output) { if (EVP_DigestUpdate(ctx, msg, msglen) != 1) goto __fail; sig = (uint8_t*)malloc(tmplen); - result = EVP_SignFinal(ctx, sig, &siglen, key); + + if (publicOnly_) { + fprintf(stderr, "gnubby signing.."); + fflush(stderr); + // TODO: 2k -> gnubby, 3k -> HSM? + + Gnubby gnubby; + result = gnubby.Sign(ctx, sig, &siglen, key_); + fprintf(stderr, "gnubby.Sign: %d\n", result); + } else { + fprintf(stderr, "ossl signing.."); + fflush(stderr); + result = EVP_SignFinal(ctx, sig, &siglen, key_); + fprintf(stderr, "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, nwords() * 32) != 1) goto __fail; + 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; diff --git a/util/signer/publickey.h b/util/signer/publickey.h deleted file mode 100644 index 0a33460433..0000000000 --- a/util/signer/publickey.h +++ /dev/null @@ -1,52 +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_PUBLICKEY_H -#define __EC_UTIL_SIGNER_PUBLICKEY_H - -#include <stddef.h> -#include <inttypes.h> - -typedef struct evp_pkey_st EVP_PKEY; -typedef struct bignum_st BIGNUM; - -class PublicKey { - public: - explicit PublicKey(const char* filename); - ~PublicKey(); - - bool ok(); - size_t nwords(); - uint32_t public_exponent(); - uint32_t n0inv(); - - // PKCS1.5 SHA256 - 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); - - static void print(const char* tag, size_t nwords, uint8_t* data, size_t len); - static void print(const char* tag, size_t nwords, BIGNUM* n); - static void toArray(uint32_t* dst, size_t nwords, BIGNUM* n); - - void print(const char* tag); - void printAll(const char* tag); - void toArray(uint32_t* dst); - - private: - EVP_PKEY* key; - - PublicKey& operator=(const PublicKey& other); - PublicKey(const PublicKey& other); -}; - -#endif // __EC_UTIL_SIGNER_PUBLICKEY_H diff --git a/util/signer/rom-testkey-A.pem b/util/signer/rom-testkey-A.pem new file mode 100644 index 0000000000..926b6b0497 --- /dev/null +++ b/util/signer/rom-testkey-A.pem @@ -0,0 +1,364 @@ +# output of: openssl genrsa -f4 3072 +#-----BEGIN RSA PRIVATE KEY----- +MIIG4wIBAAKCAYEAslAOYh0KsW6B3a1slmQLiKvnLaLwO21yVM/l1MG0jzrdepPZ +o134FrFI/dHscPSRlN1M/MzpfDdn+q6FIupprYdHYahbvDb+YpVfrQNYFiYhq1zL +a3QKHRtlD0GEugPuBTIJZcl3zSgGpD3Nh4658f02KhDHnKNJYa9eY1GM5Ij3sW9y +DH8lCV80X8BZjN8mmkmlMjBHCbOgPgxvK8M1e/gsPYgfcmC0EYsiWnohXQBhGY31 +lEaKeub3fQylj5HrT0pck21lmVVYpL9oWaa2ib3p+jJCruddQI6TNvZtY4FQQbiE +hJ1XXSPECuv532pE5tYlB3FHuVUfKio1p/FG8RIerlqAsBI9QTayJePkm/H1GItX +qFsXdT7OhMDYJhUjtlX43pDcoufGzwXYxn9J3po5hbpHfGoGPJJedd/aiybaJywN +D+KmWBn8upMvEmdCsyE9IWb8WJbaH7Yq4yz5ZJm4hrHPqKBaW1BPbqGOEdPiU0PQ +K3XpToiqhU7fXHmDAgMBAAECggGAYTuobDX7878Xz+LWuLd7Vp6upEMajr1iv/7S +DA9Iv2XRCht/bUc7llw8OjRzozCqBiwa5Ct1EohACgGKlfyPfdGrygP9agfu9aEQ +mA6fxQwsBf7G6iRPs4mRtRz8HFcyPuEHINsYmeW+oWcWIVph6SQzmgKmZrLfvAXe +CXiZxLEvqDDmVwwqDQ8+RwxjiJ7StQV9sH2E7zRlKBCtuoZrLtuofDEzPLKg3oQp +Sn8YnFctm7q+dIl20AgMYsM3sK9XYLIVBpT6JqGXnjoXS6lSO5zDw24kbqlip9N9 +KrYO2+VXrppmR9hOKm23BvHIcs9AdhYK6+msGqq95mMkiTEphrh+myQr6kNN9Vx3 +qxRvwfpxejZCSivM+S43Ow25rUF7RYRTHQ/k7ihpHrFzNIyYGtDWK6L6ac9V/YLc +ld7nog+EdxjV0JRAjBvxbjohv2q87SmR1LgD2ORkTtbPFGVY3vBKhfWxTGJh57o0 +5p/UqeIRAMCvRhmKsba55+K7vLbRAoHBAOYMVkIskxk0hVz/hPmqXOoStnH0Nx/B +AI0oZ65Eiii7sTWubepn4l6vE8olCdRp1vNoBgP5B+ByT84Ur1LK3tdhA/LdjcGE ++vAbXL7mKz+SpqQReRN8UByD+UPvhFtZ1cctyCRFHYzWwG/oTkx2afC3JvmNLG2o +ZMopdnCBaSITsld27hUcRftSU+b5B0naqnhXzDE0enyyoFhrC7RHFf1IImTWdiCr +dQFJaHeV9rnJCQC6q7x70aIbHJ5jaDZLKwKBwQDGbaC00zdhAUEVNNW3Tb/CtIaB +RePeMU46pqt1EpU2fJ1Og/1MobX9Y6o1o6l8aIbXaQrOSLhGz2Sb8E+qfYQhuqL5 +/aAgYQ8blevhf+RlVRLktvv/q1vEIUZE2AbtpSiQAgMHgrYq1opg9aB/Q/JsHU3f +L2P2Jtgpkqz5gLPAWJKbU4UMbNbxiFECOZl6RyZWuIOVKH7xsCriUCiF2hwUJmM4 +SLZRkR8S6/wR2lGnHx9NqrPu44Hy1Zz73ke8/wkCgcEAzS93yHIlibe0s+wcWOtB +EG48WItwl1v39+9v+pmbeRVfy/eWhhq+Z6FUz1oV2GXGmTfRFb4K7oBG+hKtBfV4 +qTYY5YgDJfZMM9jT8lktffh5taD4Ew8wDR8RNyztKuWHra4B84fKAZKR9b6IB98e +Qtu5YaAvXmdx7nbo8xQaB5D14tlrJV0gdjdKKps3iwIERm5Y7BJYpdxU9EgWGmfF +DzJFqxc2KZGEPO+SxAb4F2FeLE5TWzw9EI+KCSO1EagdAoHANanYWI723ykzrMSJ +N/Wy8rlX1wZLxf+XpI0Guba42+9/q4hOrLbfPRQDKFaGs7qhHQivf3JzQ9M65mFr +ajRf069h/DH3aEpXh6JYFLg90JndbjV+mXqCatyE4IF7/jE4cxnYL+PN2HAFJIvJ +SCHcIhkawk1Sv3Np6nRci22fL1nE7HT9+opE5zVykyN4unUbjUCBdYlqK3r1XhdH +nkuKZHitRL+FbzHMMZXYqgtdIdFs6dhMqUKmFkJnHkbTJ+3hAoHAdURnZVl1gduI +ISCleulBmSuCXVv3CNQ1tfBsc6J5KZcve/sbkk9eJrea0P5gcVI4lHkK8neW4I3q +tmImgTPNzAzjOf38KdV3pNFuYVN4bFOoguV7I0yZGqE7Tzr+TEz/6GmCYA/QVWSr +tp9Cg9xcGpsHZ6AdhTeFJHWCRhTS2FAgM8Q/lFLF78ng3Mc3tTMv66Sy+N+809d3 +f/NiifJqEqXpTGGSfC9sLqBDG58+tLahkd/4bPzDsXYIORJ6eRIp +-----END RSA PRIVATE KEY----- +# output of: openssl genrsa -f4 2048 +#-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAxkF2U+bC+B6BCfzfM9p3g6J4HbMvdhV3xS1HJSpCdsqhQMkO +6l08LV1R4U7hjF1Nk/7C546XKDJegf9hhHuSZkYtXZOOBdYP8DV8ckrB3Lz6WF+N +54WJTPUaFFRN6ynedl6oRa7vdDW5cjOYGwIqkZg24uPAJKzmKYPkX8BV7d1rNF7+ +LkuDGCt9SzJON7459JMC/mAy1pFS99SPmkmH31OG+WQGq8puqdUdnzT50AUznHOS +5QJiMY1kTXp2iOkII+pzuPhpwjxtqIH4riJ/Rs8lHBNSL/MrK8jsGj0njWPLi0D5 +lSIFmznYn29WayUCnEvjTOAJaUBYwlQrh8eDbwIDAQABAoIBAGdyON/GhO0aXZJs +k7pmv/27hJlaqeUfhoMoAPtvdYaubD11q4a2Z3P0QYkis6Wd+aDDScexK0YaIh4K +t0N9hwI+k+VD3NNGwsI/5lNsloMrSCVclpq7nsy9B4KcCpwuGJoDAiJ6CQ/GCKGC +MlfFZZjap6jz1YpNfTskSsF7hlq6RceOXas4bx8YhZl4V+EkDez3nT6hHT9PUal9 +IN+wGV0xYShSUhRSp9qdm/a8WiyETxjPkh8p+5jVpJTb61XbkIzzSnsl+Xmukapk +fJO6Rcbp/V/78zV5YuR0hbENexPEf/R8iEuNxtVAz7G09U+8t1fTIuCFYy2oLh43 +rAwjHaECgYEA+Ba+UkzoNP0oFnMj4hJgE31NmnPWBMnjyGgchoPYQZVf+tjyCOj9 +bc0D1LQzG8UrkAxMnm4VWUniJ6CzaLHNPKiUvPeS+z1ofvsMup8ly23yL4q3QKOy +nfHQREW5wHHldvwc2uZ53bUInOEPUpQMA9UPFgbighx6WQVXyszAP4MCgYEAzJPo +zL+Ix1s/fwZOjfkFCnWsKcJ1m8t7vEObke4ovWaHP6JpHAumys1ih2F3qg0jKCa5 +yItv/l+Hj9fssYlR09zOmzAR0g8GGFqVgDxFyX0NrXmxcqYexVwNmd0scQKFwj2J +iazYOs1AMuQZ1MqYaw4wS2eG28/Y/F3OooVu3KUCgYEAqyr9+0imudCk9QBSFKu6 +8Bd3EIa1di5ZY685ZzHWZkGKrEc8jxs5p6VY7Eu8K3/Zc5SY1IJ9ZlKMn+zHfAeY +5C4oGUzzczbGPz41ZRli+T2NaHHbx9Rp64GowUIeTAIJYRPHUNzN3kMGgz7g1Ifi +1k4ND5SGeWDupTcDgJ/OUMMCgYBCK71rLLDDOuKI5bNW/KsCvRkY0MtVvzWgqYWS +aCRJTvaEQLYa2jHy+wfZnk8kc+dhP1VsZp2s+51Pi5oFutL64jr5u0yoUy+3hOVC +ezxfddGMwQYCfXUKhUHo+L89NoGpWFo6a+vs6SLQ0zL/vyAZ0JcSbMQUKWCYEIeb +zekT+QKBgCrI1XeYP0+PtKVVsE+0CmKSNhi2jKtCgyFCzHQJb2NHz25fZhlo7aM0 +oLgdsQFqK1+oALk8fT0Bg1jddsggbG7iZlieBTC5tPkNTMjpTcBBgnI5BkbZYuNi +qqbFnV0S2cP86BWzHXrtXWvmdesvMBRGxO7wG/ELXI10rHZG7DvH +-----END RSA PRIVATE KEY----- +# output of: openssl genrsa -3 2048 +#-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0/22CLHy3W8TJcHX/yMQOFIyARFxmlsz9wxilz9oCjEpDpld +GIsS0vXmv3U3hqgD0+ocFwKeYKe86JBTp0KsD6rmLvRwMfF1/n8eLsvXSWU7Z3hF +d6KFUvZ1t4G9WxFq5V2k7pumRhN2g2J0oVPrJpBlJKbOG7f0L6+IZT+V00CQrqUJ +kVxHBCxXosxkJPmoU8NBG+Nlv0OncIj2HrfnzAxmbPs/6uM/yeiTM462M/zqXu44 +l16K17uSGJ5/s6CCVK0AuDcO7nZ+T8gZRXrZw6Ib2t3VgqA38fyJLOZJ2Vc3t7KO +05fM5hNP18JzMpmpd1avhzHgDEer45qsAt1jaQIBAwKCAQEAjVPOsHah6PS3boE6 +qhdgJYwhVguhEZIipLLsZNTwBstwtGY+EFy3N06Z1PjPrxqtN/FoD1cUQG/TRbWN +GixytRyZdKL1dqD5VFS+yd06MO4nmlAuT8GuN075JQEo52Dx7j5t9GfELrekV5b4 +a41HbwruGG80EnqiynUFmNUOjNR/ETxMy4pzd8XH9RPEh9UfRQcrDsU7KOsQVygB +KaU4OhuJMeaU7K+75thaAIFTM5Cp7SUu54Ri8wXcnuvW3qAI4BM/KMnbPWktNHAg +6WkASh3oaY/J03wlfW0J3RBEpefW4dJ8sMq4qAXZ3ycgfJE5lTI8oJH3nX94cOla +FJ0bqwKBgQDvOOwWTw2xtoOYohKYw/vvIMMf8vx4AaG68Hc4cBsGJiFxuWJTT4nV +c67RuVUArObDMe/KgGMy5wqglyDgojXMVhRtOTMBP5tSaUsNViWKJJ/u+QyTFvu4 +q+o2/OuQkYy1WZ/U9rJvb6LcvOuNaffV0JShXJ4HnRLuO5irD60kWQKBgQDi296A +EP7oGgATERwklT4KS3Vgkr8VAEFT/VW78CUNTsGm6L8NOFHQe/U6eXe4ub0oSUan +u7TDhCgmkxvcw3qornu0wdVE0r1oF9TakTfPL9VQQ3mTrmpHCe7DZGJSTu7AC1b+ +07VIemesTBw1Dcf9RvazObjlAvWI/qP51ESVkQKBgQCfe0gO3152ea0QbAxl1/1K +Fddqof2lVmvR9aTQSryuxBZL0Ow3ilvjonSL0ONVyJnXdp/cVZd3RLHAZMCVwXky +5A2eJiIA1RI28NyzjsOxbb/0pghiD1J7HUbPU0e1tl3OO7/jTyGfn8HoffJeRqU5 +NbhrkxQFE2H0J7sctR4YOwKBgQCXPT8AC1SavAAMthLDDilcMk5AYdS4qtY3/jkn +9W4I3yvEmyoI0DaK/U4m+6Ul0SjFhi8afSMtAsVvDL0916cbHv0jK+ODNyjwD+M8 +YM/fdTjgLPu3yZwvW/SCQuw230nVXOSp4nja/EUdiBLOCS/+L08iJntDV05bVG1R +OC25CwKBgESVOTLIZfSkAP8GtolQt5meiQNZAM1fkbTZmydzPU8RcxYSjH4S7xzZ +wqMvedczh7eJ+CjUbYN+n3jj6Dual/36WHsPntV2avejb6UaInYd61t0murRuUsQ +jZ6CAlsBSbhfOru6N3NQ6tQC5+9hPELCTIPgMU3vLFq1cP2G0fTT +-----END RSA PRIVATE KEY----- +# output of: openssl genrsa -3 3072 +-----BEGIN RSA PRIVATE KEY----- +MIIG5AIBAAKCAYEAx96yZwMRZLE+n+aYXqtacPjhpsDAz2IYqbTTKMsYz6Ojvdjw +UWLd6OF0QuEuDrF6J8OK5c/RWRkltlIZgYv8FF8PznKSmz9frPCIKxm4mAu6nnw4 +FFbNBH5RnkKdctVfr8++RzOHjdD6b0WD80cAKxMknXfBCxw36+BNfArdU5ZIgHhh +db3dfL8HPBsrndUOhUWI1OcAY4UTmY6W2nW+tgE0T3nf8kcnUr+qGsw9nAU95Ulm +3Gir8EqL+cepnKDIR0TqIeE9eUeVOZGpNX098FJNpYM4NPAVIiTlexQyYMst+z4x +/WLYxTHfqtRl/BtvGgLqw81jqrhEXZuKL/4ZXawy2VCE5VqckTGd1s7froXI1F4L +wT42eNwL3LO3sBl/BqTk5Ib0azRQADr5Q35AiMUPHMZ/iPdkfHAuFWCAxE3VvQAg +QxqohLKTFjTIDjotHcEDaNCEonhtsz662wJALHALfWxPwAt3Fy8j+b24snpw8Hh+ +T19P1s4mdHnk3GcxAgEDAoIBgQCFPyGaAguYdim/7xA/HOb1+0EZ1dXflrsbzeIb +MhCKbRfT5fWLlz6bQPgslh60dlFv17HuiouQu255jBEBB/1i6gqJobcSKj/IoFrH +ZnsQB9G+/Xq4Od4C/uEULGj3OOp1NSmEzQUJNfxKLlf3hKrHYhho+oCyEs/ylYj9 +XJONDtsAUED5KT5TKgTSvMe+jgmuLls4mgBCWLe7tGSRo9R5ViLfppVML2+Mf8a8 +iCkSrilDhkSS8HKgMbKmhRu9wIRW5YC5ipbuOAxRfyLi0jAgyAxmh9s6P1xj014d +yyQqRASH5M+SaoOXjW3lLm7g40GEkSPP7rpuscU4kKZPEv5c6CKKS5rdkRdYYpGC +hbu4vuQ+WAc/1WadzBouNapr51KpFubLD4HHXw/hrhoxoLVmABzG5f3bbI5oE8PL +cRgGAEM/XTcQ7kMXWBgkzkUNN9UzV+zTegVsGp/gfjdC+mCK3QepqEoMvJYKOSgg +aUgKO9e2lQja8ryW3ypukJZQQqMCgcEA7VhsMaDhAq1nlhX5RaZrddeCcrQv9jR5 +VJruGCp/rQZaezFpwV1tU0Eqir6ZzaUQSdS5t4BCCuoTMZUtQjl1mG8GWwTIF3Pp +hdx0W81ISE5UUYO+mNnvJ0GeEJc9j8+782nxbhH5/W9zd8ixav9AgYOch5v5SUvQ +lohHo+E0FVu8PtMdN+oblWfqSgIBvfLVxZPAKMWreFhE5YCe5a19EC1bKhA/YgU8 +JRlS5bT2ZvlWCng3DenY3GZqpY3dLcaLAoHBANeUPNnwehFGGyk8+5ubiklOuJkD +P2dckTfM6jY4/HRezLQ1kOBlpg6ckEhQJd0hfIlUe1RnCfnDiVctY3coJjng+K7a +VIGNEAbBTzc4/dEZHiVWQkikLWToRobL+n5uxxWYmUXdt8K2RLXtII4N7+5BR2rR +iXaIvknKQMBVqKXxtJ8hMHHLKExGhJT9Xrxzl4spYALT0Qf4OP0AyRDdMkv3JNTf +oUrrWeLAFONq1jwnV1QgufkJXBgY/CkTJjY8swKBwQCeOvLLwJYByO+5Y/uDxEej +5QGhzXVOzaY4Z0llcapzWZGndkaA6POM1hxcfxEzw2AxOHvPqtax8WIhDh4sJk5l +n1mSAzAPopuukvg9M4WFiY2LrSm7O/TE1mlgZNO1NSf3m/ZJYVFTn6JP2yDx/4BW +V72vvVDbh+BkWtptQM1jkn1/N2jP8We47/GGrAEpTI6Dt9Vwg8elkC3uVb9DyP4K +yOdxYCpBWNLDZjdDzfmZ+46xpXoJRpCS7vHDs+jJLwcCgcEAj7gokUr8C4QSG339 +EmexhjR7EKzU75MLeoicJCX9oundzXkLQEPECb21hYrD6MD9sOL84u9b+9ew5Mjs ++hrEJpX7Hzw4Vl4KryuKJNCpNhC+w47W2xgeQ0WEWd1RqZ8vY7sQ2T56gc7YeUjA +XrP1SYDaRzZbpFsphobV1Y5wbqEjFMDK9odwMtmtuKjp0ve6XMZAAeKLWqV7U1Xb +YJN23U9t4z/A3Jzmlyq4l5yO0sTk4sB7+1uSurtSxgzEJCh3AoHBAJxAc/3qetap +JdjBT6CbS2Jh08aCwT4ld1jVToPx3ulUKn/7tVozyjb6I2FipAUrTLnGtQ8+vCQe +F4TWdjYDAy0Dq8HSQ9GTDyk13OwoKou6qr/IyDUE9AFfjyQeo7iUYbpKnUmJAawO +KhlwR6B8x3lFrtwPkbNuWgvOeq++8tamxb1Q56m9DPYNzECrGybe2o/+qDiZCG5n +P/L5lDq30HHN2pyUQacVoXYzrYITzNIVZFg2h28Wti0JKjlX0j64YQ== +-----END RSA PRIVATE KEY----- +# output of: openssl genrsa -f4 3071 +#-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- +# output of: openssl genrsa -3 2047 +#-----BEGIN RSA PRIVATE KEY----- +MIIEoAIBAAKCAQBd5Az6u/daXYeCv3aHYGJ01Aw8NUu8YLoT9ynBDvm7hT5yWLbY +ugLSIN44gLSsgVjJ7g6n0LddheDaOC0YRPgyYcipg8/Lo8Doe8x8qerRz+PwewuP +k9mDmTPvHANJJJ7d7crlwv/OhklPEmDaSUrAVh5AmlUYNxRwbOC/Di3SLzJc/X7m +7ItclQouinH+dOiQGUZwyLGzE+TBB7io3NyV74yxHnmpwyxussNqKcfiN8C1dcIb +uqs/IEoR/TZ5EAcJI8XbSTe8SOVwWIEUcBBohzQWUWJbzwcc2CCijITrnsrO+/Cc +FD34krjss2nDtA2mZsq5b/IqmofziTyf+B9DAgEDAoIBAD6YCKcn+jw+WlcqTwTq +7E3istLOMn2V0WKkxoC0pn0DfvblzzsmrIwV6XsAeHMA5dv0CcU1z5OulebQHhAt ++sxBMHECiofCgJr9Mv3GnIvf7Ur8sl+35le7d/S9V4YYaelJMe6B/98EMN9hlebb +hyrkFCsRjhAkuErzQH9eyTbJRB/7Fqi5pU5WWz7nuhIrrYVMeTEqbEdvCNiLjfrv +ooH7Eq2tQEVDcf49bCRhzOSpaykRsw9UkcLjWFn2OSnWrDlVSB9mbdGNJpBHLThf +WMuac2OxxbCl89bAFQ/oVjAqxLFzn46C7JZvLe/p8cHsYqbsRC21abbVDuAhBYX7 +nQsCgYEA4amkQZxDK1JCEZ7CcvFiV7SgkWqOesjDObpDd9te7M6cjDDVQQf560NR +6Mp4nLe8yBc00maPpLeL+FvovYtDRbDb2yIhyH9WgRWC30vtCMY/GpgS4jOcr3e0 +K9TkTbZTIINvem56rPOVJpJX5yXoG8lQdg/61TdZYISjSE123ykCgYBqg2CbTZLo +FNFvsWxn8dEMk4X/PHqUfyodwfLr1RZ8BFpke8VYOeQWLgS4aR5303zX4KZjHiwr +4z9NLyMjLwq/Akf+ig3Kgp6qgmrd8/QCcOBsaLPXnzlp4wPVNcu17QuDQV8G19Uu +I1bNcnyX+uld4rPuZOT+YQGRHrRsCYfUiwKBgQCWcRgrvYIc4YFhFIGh9kGPzcBg +8bRR2yzRJtelPOnzNGhddeOAr/vyLOFF3FBoen3auiM27wptz7KlkpspB4Iudefn +bBaFqjmrY6yU3UiwhCoRurdBd73KT81yje2JJDdrAkpRnvxzTQ4ZtuVEw/AShjWk +Cqc4z5DrAxeFiPnqGwKBgEcCQGeJDJq4i5/LnZqhNghiWVTS/GL/cWkr90fjZFKt +kZhSg5AmmA7JWHrwvvqM/eVAbuy+yB1CKjN0whd0sdSsL/8Gs9xXFHGsRz6ioqxL +QEhFzTpqJkaXV+N5MnlIsleA6gSP43QXjzOhqGVR8OlBzUmYmKmWAQtpzZ1br+MH +AoGBAJAgNpv0p3hZly5oecTzIan03/nJ7HlhS9XsR6zyI3n/HPxEd4MW7nAMlend +FtuJ8u033ZtWDW8E9qn6jrIMzgZgWMyh4Az+xYdq+ZMT6c3q/Ujh50FSeFc8y1we +onrGgK3d/IXnGIUpUUIexw6mEx4eux1GHusgMA/bWRG/DQeQ +-----END RSA PRIVATE KEY----- +# output of: openssl genrsa -3 3056 +#-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- +# openssl genrsa -3 3071 +#-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- +#openssl genrsa -3 1023 +#-----BEGIN RSA PRIVATE KEY----- +MIICWQIBAAKBgGgVIcckiflOrlrsuagONesnm4qhEf8TvWvwZzTUj6IvtFIsXgFF +Ql/eY3u+By1xFlA3riLMwxXtCvYM2qzXmgu8GH8Mru9Ikon5xapXgR4JNdUDqhgS +nMTfO/7/6qBOGqyMVjJSBSPftKUGa9QGOxQnG0G/FVHQ1mKx299FW707AgEDAoGA +RWNr2hhb+4nJkfMmcAl5R2+9BxYL/2J+R/WaIzhfwXUi4XLpVi4sP+mXp9QEyPYO +4CUewd3XY/NcpAiRyI+8BukbhUdeGdQKf3a6VN5V2r2PlUy9lbOIfa4EfQM64QWF +/BvIq+tVFg3lvAylpxJurmEi7Y7c4uC6ksseSG9YSusCQQDu50smOMGfr5jxccfq +R9nYEqnfWI7nquwyA4eiHnbWVEDGNREY39G1zh+lYRqiQSk1whpsslU68VoyElwO +3VVxAkBvh+v7aQbq0zHWPGMfuHwUy8sxNSidpRwoMbvY89fvfXGcdB9YJbEVDetO +Ej7IU+VfpML8F6hEzSxPHBaPefdrAkEAn0TcxCXWanUQoPaFRtqROrcb6jsJ78dI +IVevwWmkjuLV2Xi2EJU2eTQVGOtnFtYbeSwRncw40fY8IWGStJOOSwJASlqdUkYE +nIzL5ChCFSWoDd0yIM4bE8NoGsvSkKKP9P5LvaK/kBkguLPyNAwp2uKY6m3XUrpw +Ld4dihK5tPv6RwJBALFMpNtx+z1qo5ViOA083dV4HvBUnsaOObmm+fF5di0mNO50 +tHepBmEvmMmbhbGtj4AuWYMgzitlQFRG13plpYc= +-----END RSA PRIVATE KEY----- +#openssl genrsa -f4 1023 +#-----BEGIN RSA PRIVATE KEY----- +MIICWgIBAAKBgF30c14/57rbnRAHchaeO5PW9ub2bzKzoNYsaU50wegI8yFmITTh +nzGahCNtipdmiD2Rh2By+Kknqtc7Rdpqsl63DY2qkTqab3nnyZlGvl1/alz59l8S +JgBlrQYeOkjuixYusUtIedUiBMDffRnJFTfISUTOeoVjqd1R6XapitcxAgMBAAEC +gYAm8JuoImBOh5rO++cDDM2wdlWaX+SyZNRyL7HtfGKpYpwx6Xw1yJUMH/hIHqxk +F3C748bx6HS61t/tmHlZDwOhy+c3kjKtjLuYoJZXfHlduPprRkGFlzD/tTLqOPIO +Ml+hfpIUIo2pKoz0KiD9N7izNnUX280V5v7woOAj0u5gyQJBAM6a1I36rigZoxHi +EZgzyYvJCR6Fq0FBpoTwfHXtXc0LQKNz761Q9AyPU3tt0HDHu67M18eKDzSgCGeD +4M6lV2sCQHRq7JieKpVsRs1Rj07tQU+Fnaq5hVgnLymHXiJoQkUNRBPeFX9bqdU3 +nKMjq1uG2t2ihLtXqt5L522MA36f3tMCQQC08lmyt5iMOlfds7dhLAoayUmZV8yz +bIIg8FaxGeELUg2cmk+R5dK4pVaiRX1HKUcxQurBMiM7HeX+czwTADBdAkBhKBMI +U4eqaFC2bUiyT+LfoN0ya93S8fC0Mdrn0CbuReH4yrEaNr+Hx/+bTttlaSgjK8ym +JMXe+23KyLzp4jYtAkBpLWQxiVQndB3eG1yur8fPku4KjsBcnTy2qz3b7OCwX51q +CWgGl6TiZiSp69UV1wwZS6tSGwyQBdDcer2aNeoZ +-----END RSA PRIVATE KEY----- +#openssl genrsa -f4 1008 +#-----BEGIN RSA PRIVATE KEY----- +MIICUQIBAAJ/ALIt6Zuh8xmqJEG1Xcyfjf5hYdrH4G37zqHKnPqFBA8wCqyURBrV +qG9ykJh02ebbODHTcp8fG/uDOFtuIuQB9wdxD66Q6UpfJMsn+nYWUyIyFeDFLwZY +WGeisDo5Xr6768KlFPbFbqsXSjZobpmq0Z1V05RNfwGH/byWLZu+FQIDAQABAn4Y +Y9aFek63paWe5P+5AeJC/vuRIikjhQOM/Bou5MRge9gKNaV48uRClTEb3WrygfGY +SHR5OZ3v+M9fHJ1kDqySd5sIblrIXwTPor9Pc9ktluSdqJqoe040HtK/T9/ZMMfR +l5/zj6WMrYOn+/FQ9WoGMk0Lvl2xa/GH2PKPJ+UCQADbMqF5o4dZvIhzalZuTv4y +FanJgH6j5njD0ubBMNm2VcCek/mdzyLjcbCAS8zHSOPjwB3K71D8URbDbinsmH8C +QADQGENYErO7rWRr189mZpqcf1LSCGHvgFJt/cNOGMfkSFkESwx5iJlVIOWMAOoq +FSM95hcYLHT3yMDMK1dvf2sCP3+MQ6fbPyw5Z5D5RJflgUa1klm9WnOW7ZjNRRcP +jO/rkCz2YB6y5FNC2XieIueng2wIY42tmgtoR/2qQdz5kwI/HqDTmKz4A1GcDDtx +bVMAwrQCzqMpNwUeHM5S5rXDBhiX8YfSSDkQyHTVFGw2CwedbkjlcUtp0+aaafKf +JewNAkAAlwvn0zsJWKNuuyaj5s+m+C5uMtVLUsI2HLshiNPCSPo6HAMB5K2JR2L7 +VKzrB1eum6WOioA8BPDfZ7kN/A68 +-----END RSA PRIVATE KEY----- +#openssl genrsa -f4 1010 +#-----BEGIN RSA PRIVATE KEY----- +MIICUwIBAAJ/Ax7mPNavitMKXqMYarOJG+6kkCYYuafedhjJ09cmnjm0djTiHWbD +em6nOesz4hWOR4/aSrxTCYYV6A7MtmzmkRotLf9zqs8gjktkkKdPDgKk4Rf+mNCG +xjIjZVKvdHzS+ak+/vO5r43hYOtA9o+iNrDUgbR3vyi6W2RRRFnFXQIDAQABAn4C +Sq7J/t7rFBCJbzx/H1mRKa+wLEn8DUtRbuLIrzes+rOMG0nyTYVAZAJqhk+TuEDE +TOACAkr4s39i63tqfI7TZ/hBdPmHWNo6C84yaxb4/2rK+TwXoP1dyhCPY/p3BmYe +TmnUVCvWuf0ozwTarWhFByDn7iLucawEaj4dHAECQAHPm57vVXHOzNmt6NfuwpMW +2xrp2EDHsz5OI9jBqEVPUXQAgB1lRDtYfvEhQOfTZSREikbkc3BX/FOFdkFG0J0C +QAG5JRVKW4TRgpVvJD3c7KDt+xSgfsPLcCIQWPITBKhdWdZmqOi3TxkdG8iTSgxs +51tcxN9/nl5diahu15GSy8ECQAGJa3eZhLn6k45abdDotcfayn7xWOnITkyeRP9J +gAGpSOcXEaFgcWGnPLplzM2ucBMx8uIsNeZtVByQkoTckmUCQAFetfKVKOkQvyYa +M8/SwXS3ffNKHT1/kOgj4vKg2AUaIf/nocVRZlrq31m4bxgtxEjIGeQtSzRuXLBB +XrPm5oECQAHJfnVFzFGpwHfuWkd+zC86m35d1WIuETVkb0TzoR3+rFELpPzQdoSC +bsu7Mgb1HSqoU852iHPqi421I7jWcP0= +-----END RSA PRIVATE KEY----- +#openssl genrsa -f4 1022 +#-----BEGIN RSA PRIVATE KEY----- +MIICWAIBAAKBgC5hrCpkwMOAyUpUWgrDFRP0r4tjSoU5jGieHYWxMGrlhVo2VPU2 +2Vddq0rKDgKrRMUv8h02DKhy/4iyZV/vS5sOFDx2DhvzBxuKWajL24xQ4kC64aFi +qysHuCgBy6kmU1Fq6IZGQpaoNP2QEggYNyrLnm952us8hUr9wimriyXlAgMBAAEC +gYAKARdZrZHGmajRV5B0cc/CFi0nK6uPQPKAPlqv06BV7lvtMXrxyXrn1VR1NVAA +U2DqB4V5t4bTbrqfiZtELiFoiYGgZZ4xBcEkR53pJ8Hp7qO3OlUcxgrtg3emz4JT +QKgBrKoOsPW62hEJwaZVVvvnsODNh0AilRLOginlVZVpAQJAcD7HeWBESfGAwcvC +8mCpCuCzKC+4bW5M7+WmDzhlvkYhhXgr2ttAylY2uTw7h/Lu36C2Q5xm4c/PFUDr +eEE/iQJAaciHQWCAhGQXgonTyC8V+InsEay151W44218dRcNdS0pug18RDTZRmbk +oq1ldXEGhR5Zl1rhRZqd3VeG8E4gfQJAOERwUHseoIatCfkwJ7qm4uoTRYDujgTu +EpBnt1eJQWH8qeC880BX8VZYpnD4UsVIU9hHpgsAVBCNedUKdUUYKQJAPlLa/XWx +wk6GW26AzCyRsUDxSOiMs6MZr0TOUt4mG6dkMi3HzRel+4ibpAys/ih9QujCuB3f +I3cZE1OCOQqOsQJABRFxEd8gZGVWAYiOPiMmHi3o9WxPye9+fGtX6n+KJivxj4vv +F0oe4mpW6N88VEMOlrtLN2/6mHhmk2ddXJSJzg== +-----END RSA PRIVATE KEY----- diff --git a/util/signer/rom-testkey.pem b/util/signer/rom-testkey.pem deleted file mode 100644 index 9cd8662c64..0000000000 --- a/util/signer/rom-testkey.pem +++ /dev/null @@ -1,45 +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. -# -# openssl genrsa -3 3071 ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/util/signer/signed_header.h b/util/signer/signed_header.h deleted file mode 100644 index 2207a08d11..0000000000 --- a/util/signer/signed_header.h +++ /dev/null @@ -1,29 +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_SIGNED_HEADER_H -#define __EC_UTIL_SIGNER_SIGNED_HEADER_H - -#include <string.h> -#include <inttypes.h> - -typedef struct SignedHeader { - SignedHeader() : magic(-1), image_size(0) { - memset(signature, 'S', sizeof(signature)); - memset(tag, 'T', sizeof(tag)); - memset(fusemap, 0, sizeof(fusemap)); - memset(_pad, -1, sizeof(_pad)); - } - - uint32_t magic; // -1 - uint32_t image_size; // != -1 - uint32_t signature[96]; - uint32_t tag[8]; - uint32_t fusemap[32]; // 1024 bits - uint32_t _pad[256 - 1 - 1 - 96 - 8 - 32]; -} SignedHeader; -static_assert(sizeof(SignedHeader) == 1024, "SignedHeader should be 1024 bytes"); - -#endif // __EC_UTIL_SIGNER_SIGNED_HEADER_H |