From ef4ae8953cdef17940c8b3b75e28cb919fdf34fa Mon Sep 17 00:00:00 2001 From: Daisuke Nojiri Date: Tue, 3 May 2016 09:29:16 -0700 Subject: bdb: Copy files from bdb to firmware/bdb Test files are copied to tests/ and the rest are copied to firmware/bdb/. BUG=chrome-os-partner:51908 BRANCH=tot TEST=make runtests Change-Id: I19f66c398e69037f00812a789854340a9690fef5 Signed-off-by: Daisuke Nojiri Reviewed-on: https://chromium-review.googlesource.com/342090 Reviewed-by: Randall Spangler --- firmware/bdb/LICENSE | 27 +++ firmware/bdb/README | 30 +++ firmware/bdb/bdb.c | 398 ++++++++++++++++++++++++++++++++++++ firmware/bdb/bdb.h | 181 +++++++++++++++++ firmware/bdb/bdb_struct.h | 268 ++++++++++++++++++++++++ firmware/bdb/dump_rsa.c | 200 ++++++++++++++++++ firmware/bdb/ecdsa.c | 17 ++ firmware/bdb/host.c | 347 ++++++++++++++++++++++++++++++++ firmware/bdb/host.h | 171 ++++++++++++++++ firmware/bdb/rsa.c | 339 +++++++++++++++++++++++++++++++ firmware/bdb/sha.c | 210 +++++++++++++++++++ tests/bdb_test.c | 492 +++++++++++++++++++++++++++++++++++++++++++++ tests/testkeys/bdbkey.crt | 33 +++ tests/testkeys/bdbkey.keyb | Bin 0 -> 1032 bytes tests/testkeys/bdbkey.pem | 51 +++++ tests/testkeys/subkey.crt | 26 +++ tests/testkeys/subkey.keyb | Bin 0 -> 776 bytes tests/testkeys/subkey.pem | 39 ++++ 18 files changed, 2829 insertions(+) create mode 100644 firmware/bdb/LICENSE create mode 100644 firmware/bdb/README create mode 100644 firmware/bdb/bdb.c create mode 100644 firmware/bdb/bdb.h create mode 100644 firmware/bdb/bdb_struct.h create mode 100644 firmware/bdb/dump_rsa.c create mode 100644 firmware/bdb/ecdsa.c create mode 100644 firmware/bdb/host.c create mode 100644 firmware/bdb/host.h create mode 100644 firmware/bdb/rsa.c create mode 100644 firmware/bdb/sha.c create mode 100644 tests/bdb_test.c create mode 100644 tests/testkeys/bdbkey.crt create mode 100644 tests/testkeys/bdbkey.keyb create mode 100644 tests/testkeys/bdbkey.pem create mode 100644 tests/testkeys/subkey.crt create mode 100644 tests/testkeys/subkey.keyb create mode 100644 tests/testkeys/subkey.pem diff --git a/firmware/bdb/LICENSE b/firmware/bdb/LICENSE new file mode 100644 index 00000000..d2514965 --- /dev/null +++ b/firmware/bdb/LICENSE @@ -0,0 +1,27 @@ +// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/firmware/bdb/README b/firmware/bdb/README new file mode 100644 index 00000000..ec34961b --- /dev/null +++ b/firmware/bdb/README @@ -0,0 +1,30 @@ +BDB library and utilities + +Building: +--------- +The host-side library and utilities requires OpenSSL. + +Do 'make runtests' to ensure everything is working. + +Generating a BDB: +----------------- +Edit the options in bdb_create.c. Then 'make bdb'. + +In the next release, this will take a config file rather than +requiring recompilation each time. Also, the BDB header and data will +be signed in two separate steps, so that the private BDB key is not +required each time. + +Revision History: +----------------- +v0.1.2 24-Nov-2015 Add support for RSA-3072B keys and signatures. + Add dump_rsa utility and 'make testkeys' to create + new keys. + Use a RSA-3072B (exponent 3) key for the subkey so + the exponent 3 code gets tested. + +v0.1.1 17-Nov-2015 Add support for ECDSA-521 data types. Note that + only the data types are supported; there is not a + C implementation for ECDSA. + +v0.1.0 15-Sep-2015 Initial version. diff --git a/firmware/bdb/bdb.c b/firmware/bdb/bdb.c new file mode 100644 index 00000000..d3327a51 --- /dev/null +++ b/firmware/bdb/bdb.c @@ -0,0 +1,398 @@ +/* Copyright (c) 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. + * + * Boot descriptor block firmware functions + */ + +#include +#include "bdb.h" + +/*****************************************************************************/ + +/** + * Check if string contains a null terminator. + * + * Bytes after the null terminator do not need to be null. + * + * @param s String to check + * @param size Size of string buffer in characters + * @return 1 if string has a null terminator, 0 if not + */ +int string_has_null(const char *s, size_t size) +{ + for (; size; size--) { + if (*s++ == 0) + return 1; + } + return 0; +} + +int bdb_check_header(const struct bdb_header *p, size_t size) +{ + if (size < sizeof(*p) || size < p->struct_size) + return BDB_ERROR_BUF_SIZE; + + if (p->struct_magic != BDB_HEADER_MAGIC) + return BDB_ERROR_STRUCT_MAGIC; + + if (p->struct_major_version != BDB_HEADER_VERSION_MAJOR) + return BDB_ERROR_STRUCT_VERSION; + + /* Note that minor version doesn't matter yet */ + + if (p->struct_size < sizeof(*p)) + return BDB_ERROR_STRUCT_SIZE; + + if (p->oem_area_0_size & 3) + return BDB_ERROR_OEM_AREA_SIZE; /* Not 32-bit aligned */ + + /* + * Make sure the BDB is at least big enough for us. At this point, all + * the caller may have loaded is this header We'll check if there's + * space for everything else after we load it. + */ + if (p->bdb_size < sizeof(*p)) + return BDB_ERROR_BDB_SIZE; + + /* + * The rest of the fields don't matter yet; we'll check them when we + * check the BDB itself. + */ + return BDB_SUCCESS; +} + +int bdb_check_key(const struct bdb_key *p, size_t size) +{ + size_t expect_key_size = 0; + + if (size < sizeof(*p) || size < p->struct_size) + return BDB_ERROR_BUF_SIZE; + + if (p->struct_magic != BDB_KEY_MAGIC) + return BDB_ERROR_STRUCT_MAGIC; + + if (p->struct_major_version != BDB_KEY_VERSION_MAJOR) + return BDB_ERROR_STRUCT_VERSION; + + /* Note that minor version doesn't matter yet */ + + if (!string_has_null(p->description, sizeof(p->description))) + return BDB_ERROR_DESCRIPTION; + + /* We currently only support SHA-256 */ + if (p->hash_alg != BDB_HASH_ALG_SHA256) + return BDB_ERROR_HASH_ALG; + + /* Make sure signature algorithm and size are correct */ + switch (p->sig_alg) { + case BDB_SIG_ALG_RSA4096: + expect_key_size = BDB_RSA4096_KEY_DATA_SIZE; + break; + case BDB_SIG_ALG_ECSDSA521: + expect_key_size = BDB_ECDSA521_KEY_DATA_SIZE; + break; + case BDB_SIG_ALG_RSA3072B: + expect_key_size = BDB_RSA3072B_KEY_DATA_SIZE; + break; + default: + return BDB_ERROR_SIG_ALG; + } + + if (p->struct_size < sizeof(*p) + expect_key_size) + return BDB_ERROR_STRUCT_SIZE; + + return BDB_SUCCESS; +} + +int bdb_check_sig(const struct bdb_sig *p, size_t size) +{ + size_t expect_sig_size = 0; + + if (size < sizeof(*p) || size < p->struct_size) + return BDB_ERROR_BUF_SIZE; + + if (p->struct_magic != BDB_SIG_MAGIC) + return BDB_ERROR_STRUCT_MAGIC; + + if (p->struct_major_version != BDB_SIG_VERSION_MAJOR) + return BDB_ERROR_STRUCT_VERSION; + + /* Note that minor version doesn't matter yet */ + + if (!string_has_null(p->description, sizeof(p->description))) + return BDB_ERROR_DESCRIPTION; + + /* We currently only support SHA-256 */ + if (p->hash_alg != BDB_HASH_ALG_SHA256) + return BDB_ERROR_HASH_ALG; + + /* Make sure signature algorithm and size are correct */ + switch (p->sig_alg) { + case BDB_SIG_ALG_RSA4096: + expect_sig_size = BDB_RSA4096_SIG_SIZE; + break; + case BDB_SIG_ALG_ECSDSA521: + expect_sig_size = BDB_ECDSA521_SIG_SIZE; + break; + case BDB_SIG_ALG_RSA3072B: + expect_sig_size = BDB_RSA3072B_SIG_SIZE; + break; + default: + return BDB_ERROR_SIG_ALG; + } + + if (p->struct_size < sizeof(*p) + expect_sig_size) + return BDB_ERROR_STRUCT_SIZE; + + return BDB_SUCCESS; +} + +int bdb_check_data(const struct bdb_data *p, size_t size) +{ + size_t need_size; + + if (size < sizeof(*p) || size < p->signed_size) + return BDB_ERROR_BUF_SIZE; + + if (p->struct_magic != BDB_DATA_MAGIC) + return BDB_ERROR_STRUCT_MAGIC; + + if (p->struct_major_version != BDB_DATA_VERSION_MAJOR) + return BDB_ERROR_STRUCT_VERSION; + + /* Note that minor version doesn't matter yet */ + + if (!string_has_null(p->description, sizeof(p->description))) + return BDB_ERROR_DESCRIPTION; + + if (p->struct_size < sizeof(*p)) + return BDB_ERROR_STRUCT_SIZE; + + if (p->hash_entry_size < sizeof(struct bdb_hash)) + return BDB_ERROR_HASH_ENTRY_SIZE; + + /* Calculate expected size */ + need_size = p->struct_size + p->num_hashes * p->hash_entry_size; + + /* Make sure OEM area size doesn't cause wraparound */ + if (need_size + p->oem_area_1_size < need_size) + return BDB_ERROR_OEM_AREA_SIZE; + if (p->oem_area_1_size & 3) + return BDB_ERROR_OEM_AREA_SIZE; /* Not 32-bit aligned */ + need_size += p->oem_area_1_size; + + if (p->signed_size < need_size) + return BDB_ERROR_SIGNED_SIZE; + + return BDB_SUCCESS; +} + +/*****************************************************************************/ + +const struct bdb_header *bdb_get_header(const void *buf) +{ + return buf; +} + +const struct bdb_key *bdb_get_bdbkey(const void *buf) +{ + const struct bdb_header *h = bdb_get_header(buf); + const uint8_t *b8 = buf; + + /* BDB key follows header */ + return (const struct bdb_key *)(b8 + h->struct_size); +} + +const void *bdb_get_oem_area_0(const void *buf) +{ + const struct bdb_key *k = bdb_get_bdbkey(buf); + const uint8_t *b8 = (const uint8_t *)k; + + /* OEM area 0 follows BDB key */ + return b8 + k->struct_size; +} + +const struct bdb_key *bdb_get_subkey(const void *buf) +{ + const struct bdb_header *h = bdb_get_header(buf); + const uint8_t *b8 = bdb_get_oem_area_0(buf); + + /* Subkey follows OEM area 0 */ + return (const struct bdb_key *)(b8 + h->oem_area_0_size); +} + +const struct bdb_sig *bdb_get_header_sig(const void *buf) +{ + const struct bdb_header *h = bdb_get_header(buf); + const uint8_t *b8 = bdb_get_oem_area_0(buf); + + /* Header signature starts after signed data */ + return (const struct bdb_sig *)(b8 + h->signed_size); +} + +const struct bdb_data *bdb_get_data(const void *buf) +{ + const struct bdb_sig *s = bdb_get_header_sig(buf); + const uint8_t *b8 = (const uint8_t *)s; + + /* Data follows header signature */ + return (const struct bdb_data *)(b8 + s->struct_size); +} + +const void *bdb_get_oem_area_1(const void *buf) +{ + const struct bdb_data *p = bdb_get_data(buf); + const uint8_t *b8 = (const uint8_t *)p; + + /* OEM area 1 follows BDB data */ + return b8 + p->struct_size; +} + +const struct bdb_hash *bdb_get_hash(const void *buf, enum bdb_data_type type) +{ + const struct bdb_data *data = bdb_get_data(buf); + const uint8_t *b8 = bdb_get_oem_area_1(buf); + int i; + + /* Hashes follow OEM area 0 */ + b8 += data->oem_area_1_size; + + /* Search for a matching hash */ + for (i = 0; i < data->num_hashes; i++, b8 += data->hash_entry_size) { + const struct bdb_hash *h = (const struct bdb_hash *)b8; + + if (h->type == type) + return h; + } + + return NULL; +} + +const struct bdb_sig *bdb_get_data_sig(const void *buf) +{ + const struct bdb_data *data = bdb_get_data(buf); + const uint8_t *b8 = (const uint8_t *)data; + + /* Data signature starts after signed data */ + return (const struct bdb_sig *)(b8 + data->signed_size); +} + +/*****************************************************************************/ + +int bdb_verify_sig(const struct bdb_key *key, + const struct bdb_sig *sig, + const uint8_t *digest) +{ + /* Key and signature algorithms must match */ + if (key->sig_alg != sig->sig_alg) + return BDB_ERROR_SIG_ALG; + + switch (key->sig_alg) { + case BDB_SIG_ALG_RSA4096: + if (bdb_rsa4096_verify(key->key_data, sig->sig_data, digest)) + return BDB_ERROR_VERIFY_SIG; + break; + case BDB_SIG_ALG_ECSDSA521: + if (bdb_ecdsa521_verify(key->key_data, sig->sig_data, digest)) + return BDB_ERROR_VERIFY_SIG; + break; + case BDB_SIG_ALG_RSA3072B: + if (bdb_rsa3072b_verify(key->key_data, sig->sig_data, digest)) + return BDB_ERROR_VERIFY_SIG; + break; + default: + return BDB_ERROR_VERIFY_SIG; + } + + return BDB_SUCCESS; +} + +int bdb_verify(const void *buf, size_t size, const uint8_t *bdb_key_digest) +{ + const uint8_t *end = (const uint8_t *)buf + size; + const struct bdb_header *h; + const struct bdb_key *bdbkey, *subkey; + const struct bdb_sig *sig; + const struct bdb_data *data; + const void *oem; + uint8_t digest[BDB_SHA256_DIGEST_SIZE]; + int bdb_digest_mismatch; + + /* Make sure buffer doesn't wrap around address space */ + if (end < (const uint8_t *)buf) + return BDB_ERROR_BUF_SIZE; + + /* + * Check header now that we've actually loaded it. We can't guarantee + * this is the same header which was checked before. + */ + h = bdb_get_header(buf); + if (bdb_check_header(h, size)) + return BDB_ERROR_HEADER; + + /* Sanity-check BDB key */ + bdbkey = bdb_get_bdbkey(buf); + if (bdb_check_key(bdbkey, end - (const uint8_t *)bdbkey)) + return BDB_ERROR_BDBKEY; + + /* Calculate BDB key digest and compare with expected */ + if (bdb_sha256(digest, bdbkey, bdbkey->struct_size)) + return BDB_ERROR_DIGEST; + + bdb_digest_mismatch = memcmp(digest, bdb_key_digest, sizeof(digest)); + + /* Make sure OEM area 0 fits */ + oem = bdb_get_oem_area_0(buf); + if (h->oem_area_0_size > end - (const uint8_t *)oem) + return BDB_ERROR_OEM_AREA_0; + + /* Sanity-check subkey */ + subkey = bdb_get_subkey(buf); + if (bdb_check_key(subkey, end - (const uint8_t *)subkey)) + return BDB_ERROR_SUBKEY; + + /* Make sure enough data was signed, and the signed data fits */ + if (h->oem_area_0_size + subkey->struct_size > h->signed_size || + h->signed_size > end - (const uint8_t *)oem) + return BDB_ERROR_BDB_SIGNED_SIZE; + + /* Sanity-check header signature */ + sig = bdb_get_header_sig(buf); + if (bdb_check_sig(sig, end - (const uint8_t *)sig)) + return BDB_ERROR_HEADER_SIG; + + /* Make sure it signed the right amount of data */ + if (sig->signed_size != h->signed_size) + return BDB_ERROR_HEADER_SIG; + + /* Calculate header digest and compare with expected signature */ + if (bdb_sha256(digest, oem, h->signed_size)) + return BDB_ERROR_DIGEST; + if (bdb_verify_sig(bdbkey, sig, digest)) + return BDB_ERROR_HEADER_SIG; + + /* + * Sanity-check data struct. This also checks that OEM area 1 and the + * hashes fit in the remaining buffer. + */ + data = bdb_get_data(buf); + if (bdb_check_data(data, end - (const uint8_t *)data)) + return BDB_ERROR_DATA; + + /* Sanity-check data signature */ + sig = bdb_get_data_sig(buf); + if (bdb_check_sig(sig, end - (const uint8_t *)sig)) + return BDB_ERROR_DATA_SIG; + if (sig->signed_size != data->signed_size) + return BDB_ERROR_DATA_SIG; + + /* Calculate data digest and compare with expected signature */ + if (bdb_sha256(digest, data, data->signed_size)) + return BDB_ERROR_DIGEST; + if (bdb_verify_sig(subkey, sig, digest)) + return BDB_ERROR_DATA_SIG; + + /* Return success or success-other-than-BDB-key-mismatch */ + return bdb_digest_mismatch ? BDB_GOOD_OTHER_THAN_KEY : BDB_SUCCESS; +} diff --git a/firmware/bdb/bdb.h b/firmware/bdb/bdb.h new file mode 100644 index 00000000..177deeae --- /dev/null +++ b/firmware/bdb/bdb.h @@ -0,0 +1,181 @@ +/* Copyright (c) 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. + * + * Boot descriptor block firmware functions + */ + +#ifndef VBOOT_REFERENCE_BDB_H_ +#define VBOOT_REFERENCE_BDB_H_ + +#include +#include "bdb_struct.h" + +/*****************************************************************************/ +/* +Expected calling sequence: + +Load and check just the header +bdb_check_header(buf, size); + +Load and verify the entire BDB +bdb_verify(buf, size, bdb_key_hash, dev_mode_flag); + +Check RW subkey version. If normal boot from primary BDB, roll forward + +Check data version. If normal boot from primary BDB, roll forward +*/ + +/*****************************************************************************/ +/* Codes for functions returning numeric error codes */ + +enum bdb_return_code { + /* Success */ + BDB_SUCCESS = 0, + + /* BDB key did not match hash, but other than that the BDB was + * fully verified. */ + BDB_GOOD_OTHER_THAN_KEY = 1, + + /* Other errors */ + BDB_ERROR_UNKNOWN = 100, + + /* Buffer size too small or wraps around */ + BDB_ERROR_BUF_SIZE, + + /* Bad fields in structures */ + BDB_ERROR_STRUCT_MAGIC, + BDB_ERROR_STRUCT_VERSION, + BDB_ERROR_STRUCT_SIZE, + BDB_ERROR_SIGNED_SIZE, + BDB_ERROR_BDB_SIZE, + BDB_ERROR_OEM_AREA_SIZE, + BDB_ERROR_HASH_ENTRY_SIZE, + BDB_ERROR_HASH_ALG, + BDB_ERROR_SIG_ALG, + BDB_ERROR_DESCRIPTION, + + /* Bad components of BDB in bdb_verify() */ + BDB_ERROR_HEADER, + BDB_ERROR_BDBKEY, + BDB_ERROR_OEM_AREA_0, + BDB_ERROR_SUBKEY, + BDB_ERROR_BDB_SIGNED_SIZE, + BDB_ERROR_HEADER_SIG, + BDB_ERROR_DATA, + BDB_ERROR_DATA_SIG, + + /* Other errors in bdb_verify() */ + BDB_ERROR_DIGEST, /* Error calculating digest */ + BDB_ERROR_VERIFY_SIG, /* Error verifying signature */ +}; + +/*****************************************************************************/ +/* Functions */ + +/** + * Sanity-check BDB structures. + * + * This checks for known version numbers, magic numbers, algorithms, etc. and + * ensures the sizes are consistent with those parameters. + * + * @param p Pointer to structure to check + * @param size Size of structure buffer + * @return 0 if success, non-zero error code if error. + */ +int bdb_check_header(const struct bdb_header *p, size_t size); +int bdb_check_key(const struct bdb_key *p, size_t size); +int bdb_check_sig(const struct bdb_sig *p, size_t size); +int bdb_check_data(const struct bdb_data *p, size_t size); + +/** + * Verify the entire BDB + * + * @param buf Data to hash + * @param size Size of data in bytes + * @param bdb_key_digest Pointer to expected digest for BDB key. + * Must be BDB_SHA256_DIGEST_SIZE bytes long. + * + * @return 0 if success, non-zero error code if error. Note that error code + * BDB_GOOD_OTHER_THAN_KEY may still indicate an acceptable BDB if the Boot + * Verified fuse has not been set, or in developer mode. + */ +int bdb_verify(const void *buf, size_t size, const uint8_t *bdb_key_digest); + +/** + * Functions to extract things from a verified BDB buffer. + * + * Do not call these externally until after bdb_verify()! These methods + * assume data structures have already been verified. + * + * @param buf Pointer to BDB buffer + * @param type Data type, for bdb_get_hash() + * @return A pointer to the requested data, or NULL if error / not present. + */ +const struct bdb_header *bdb_get_header(const void *buf); +const struct bdb_key *bdb_get_bdbkey(const void *buf); +const void *bdb_get_oem_area_0(const void *buf); +const struct bdb_key *bdb_get_subkey(const void *buf); +const struct bdb_sig *bdb_get_header_sig(const void *buf); +const struct bdb_data *bdb_get_data(const void *buf); +const void *bdb_get_oem_area_1(const void *buf); +const struct bdb_hash *bdb_get_hash(const void *buf, enum bdb_data_type type); +const struct bdb_sig *bdb_get_data_sig(const void *buf); + +/*****************************************************************************/ +/* Functions probably provided by the caller */ + +/** + * Calculate a SHA-256 digest of a buffer. + * + * @param digest Pointer to the digest buffer. Must be + * BDB_SHA256_DIGEST_SIZE bytes long. + * @param buf Data to hash + * @param size Size of data in bytes + * @return 0 if success, non-zero error code if error. + */ +__attribute__((weak)) +int bdb_sha256(void *digest, const void *buf, size_t size); + +/** + * Verify a RSA-4096 signed digest + * + * @param key_data Key data to use (BDB_RSA4096_KEY_DATA_SIZE bytes) + * @param sig_data Signature to verify (BDB_RSA4096_SIG_SIZE bytes) + * @param digest Digest of signed data (BDB_SHA256_DIGEST bytes) + * @return 0 if success, non-zero error code if error. + */ +__attribute__((weak)) +int bdb_rsa4096_verify(const uint8_t *key_data, + const uint8_t *sig, + const uint8_t *digest); + +/** + * Verify a RSA-3072B signed digest + * + * @param key_data Key data to use (BDB_RSA3072B_KEY_DATA_SIZE bytes) + * @param sig_data Signature to verify (BDB_RSA3072B_SIG_SIZE bytes) + * @param digest Digest of signed data (BDB_SHA256_DIGEST bytes) + * @return 0 if success, non-zero error code if error. + */ +__attribute__((weak)) +int bdb_rsa3072b_verify(const uint8_t *key_data, + const uint8_t *sig, + const uint8_t *digest); + +/** + * Verify a ECDSA-521 signed digest + * + * @param key_data Key data to use (BDB_ECDSA521_KEY_DATA_SIZE bytes) + * @param sig_data Signature to verify (BDB_ECDSA521_SIG_SIZE bytes) + * @param digest Digest of signed data (BDB_SHA256_DIGEST bytes) + * @return 0 if success, non-zero error code if error. + */ +__attribute__((weak)) +int bdb_ecdsa521_verify(const uint8_t *key_data, + const uint8_t *sig, + const uint8_t *digest); + +/*****************************************************************************/ + +#endif /* VBOOT_REFERENCE_BDB_H_ */ diff --git a/firmware/bdb/bdb_struct.h b/firmware/bdb/bdb_struct.h new file mode 100644 index 00000000..f8d2b321 --- /dev/null +++ b/firmware/bdb/bdb_struct.h @@ -0,0 +1,268 @@ +/* Copyright (c) 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. + * + * Boot descriptor block structures + */ + +#ifndef VBOOT_REFERENCE_BDB_STRUCT_H_ +#define VBOOT_REFERENCE_BDB_STRUCT_H_ + +#include + +/* Size of SHA256 digest in bytes */ +#define BDB_SHA256_DIGEST_SIZE 32 + +/* Size of RSA4096 key data in bytes */ +#define BDB_RSA4096_KEY_DATA_SIZE 1032 + +/* Size of RSA4096 signature in bytes */ +#define BDB_RSA4096_SIG_SIZE 512 + +/* Size of ECDSA521 key data in bytes = ceil(521/8) * 2 */ +#define BDB_ECDSA521_KEY_DATA_SIZE 132 + +/* Size of ECDSA521 signature in bytes = ceil(521/8) * 2 */ +#define BDB_ECDSA521_SIG_SIZE 132 + +/* Size of RSA3072B key data in bytes */ +#define BDB_RSA3072B_KEY_DATA_SIZE 776 + +/* Size of RSA3072B signature in bytes */ +#define BDB_RSA3072B_SIG_SIZE 384 + +/*****************************************************************************/ +/* Header for BDB */ + +/* Magic number for bdb_header.struct_magic */ +#define BDB_HEADER_MAGIC 0x30426442 + +/* Current version of bdb_header struct */ +#define BDB_HEADER_VERSION_MAJOR 1 +#define BDB_HEADER_VERSION_MINOR 0 + +/* Expected size of bdb_header struct in bytes */ +#define BDB_HEADER_EXPECTED_SIZE 32 + +struct bdb_header { + /* Magic number to identify struct = BDB_HEADER_MAGIC. */ + uint32_t struct_magic; + + /* Structure version = BDB_HEADER_VERSION{MAJOR,MINOR} */ + uint8_t struct_major_version; + uint8_t struct_minor_version; + + /* Size of structure in bytes */ + uint16_t struct_size; + + /* Recommended address in SP SRAM to load BDB. Set to -1 to use + * default address. */ + uint64_t bdb_load_address; + + /* Size of the entire BDB in bytes */ + uint32_t bdb_size; + + /* Number of bytes following the BDB key which are signed by the BDB + * header signature. */ + uint32_t signed_size; + + /* Size of OEM area 0 in bytes, or 0 if not present */ + uint32_t oem_area_0_size; + + /* Reserved; set 0 */ + uint8_t reserved0[8]; +} __attribute__((packed)); + +/*****************************************************************************/ +/* Public key structure for BDB */ + +/* Magic number for bdb_key.struct_magic */ +#define BDB_KEY_MAGIC 0x73334256 + +/* Current version of bdb_key struct */ +#define BDB_KEY_VERSION_MAJOR 1 +#define BDB_KEY_VERSION_MINOR 0 + +/* Supported hash algorithms */ +enum bdb_hash_alg { + BDB_HASH_ALG_INVALID = 0, /* Not used; invalid */ + BDB_HASH_ALG_SHA256 = 2, /* SHA-256 */ +}; + +/* Supported signature algorithms */ +enum bdb_sig_alg { + BDB_SIG_ALG_INVALID = 0, /* Not used; invalid */ + BDB_SIG_ALG_RSA4096 = 3, /* RSA-4096, exponent 65537 */ + BDB_SIG_ALG_ECSDSA521 = 5, /* ECDSA-521 */ + BDB_SIG_ALG_RSA3072B = 7, /* RSA_3072, exponent 3 */ +}; + +/* + * Expected size of bdb_key struct in bytes, not counting variable-length key + * data at end. + */ +#define BDB_KEY_EXPECTED_SIZE 80 + +struct bdb_key { + /* Magic number to identify struct = BDB_KEY_MAGIC. */ + uint32_t struct_magic; + + /* Structure version = BDB_KEY_VERSION{MAJOR,MINOR} */ + uint8_t struct_major_version; + uint8_t struct_minor_version; + + /* Size of structure in bytes, including variable-length key data */ + uint16_t struct_size; + + /* Hash algorithm (enum bdb_hash_alg) */ + uint8_t hash_alg; + + /* Signature algorithm (enum bdb_sig_alg) */ + uint8_t sig_alg; + + /* Reserved; set 0 */ + uint8_t reserved0[2]; + + /* Key version */ + uint32_t key_version; + + /* Description; null-terminated ASCII */ + char description[128]; + + /* + * Key data. Variable-length; size is struct_size - + * offset_of(bdb_key, key_data). + */ + uint8_t key_data[0]; +} __attribute__((packed)); + +/*****************************************************************************/ +/* Signature structure for BDB */ + +/* Magic number for bdb_sig.struct_magic */ +#define BDB_SIG_MAGIC 0x6b334256 + +/* Current version of bdb_sig struct */ +#define BDB_SIG_VERSION_MAJOR 1 +#define BDB_SIG_VERSION_MINOR 0 + +struct bdb_sig { + /* Magic number to identify struct = BDB_SIG_MAGIC. */ + uint32_t struct_magic; + + /* Structure version = BDB_SIG_VERSION{MAJOR,MINOR} */ + uint8_t struct_major_version; + uint8_t struct_minor_version; + + /* Size of structure in bytes, including variable-length signature + * data. */ + uint16_t struct_size; + + /* Hash algorithm used for this signature (enum bdb_hash_alg) */ + uint8_t hash_alg; + + /* Signature algorithm (enum bdb_sig_alg) */ + uint8_t sig_alg; + + /* Reserved; set 0 */ + uint8_t reserved0[2]; + + /* Number of bytes of data signed by this signature */ + uint32_t signed_size; + + /* Description; null-terminated ASCII */ + char description[128]; + + /* Signature data. Variable-length; size is struct_size - + * offset_of(bdb_sig, sig_data). */ + uint8_t sig_data[0]; +} __attribute__((packed)); + +/*****************************************************************************/ +/* Data structure for BDB */ + +/* Magic number for bdb_data.struct_magic */ +#define BDB_DATA_MAGIC 0x31426442 + +/* Current version of bdb_sig struct */ +#define BDB_DATA_VERSION_MAJOR 1 +#define BDB_DATA_VERSION_MINOR 0 + +struct bdb_data { + /* Magic number to identify struct = BDB_DATA_MAGIC. */ + uint32_t struct_magic; + + /* Structure version = BDB_DATA_VERSION{MAJOR,MINOR} */ + uint8_t struct_major_version; + uint8_t struct_minor_version; + + /* Size of structure in bytes, NOT including hashes which follow. */ + uint16_t struct_size; + + /* Version of data (RW firmware) contained */ + uint32_t data_version; + + /* Size of OEM area 1 in bytes, or 0 if not present */ + uint32_t oem_area_1_size; + + /* Number of hashes which follow */ + uint8_t num_hashes; + + /* Size of each hash entry in bytes */ + uint8_t hash_entry_size; + + /* Reserved; set 0 */ + uint8_t reserved0[2]; + + /* Number of bytes of data signed by the subkey, including this + * header */ + uint32_t signed_size; + + /* Reserved; set 0 */ + uint8_t reserved1[8]; + + /* Description; null-terminated ASCII */ + char description[128]; +} __attribute__((packed)); + +/* Type of data for bdb_hash.type */ +enum bdb_data_type { + /* Types of data for boot descriptor blocks */ + BDB_DATA_SP_RW = 1, /* SP-RW firmware */ + BDB_DATA_AP_RW = 2, /* AP-RW firmware */ + BDB_DATA_MCU = 3, /* MCU firmware */ + + /* Types of data for kernel descriptor blocks */ + BDB_DATA_KERNEL = 128, /* Kernel */ + BDB_DATA_CMD_LINE = 129, /* Command line */ + BDB_DATA_HEADER16 = 130, /* 16-bit vmlinuz header */ +}; + +/* Hash entries which follow the structure */ +struct bdb_hash { + /* Offset of data from start of partition */ + uint64_t offset; + + /* Size of data in bytes */ + uint32_t size; + + /* Partition number containing data */ + uint8_t partition; + + /* Type of data; enum bdb_data_type */ + uint8_t type; + + /* Reserved; set 0 */ + uint8_t reserved0[2]; + + /* Address in RAM to load data. -1 means use default. */ + uint64_t load_address; + + /* SHA-256 hash digest */ + uint8_t digest[BDB_SHA256_DIGEST_SIZE]; +} __attribute__((packed)); + +/*****************************************************************************/ + +#endif /* VBOOT_REFERENCE_BDB_STRUCT_H_ */ + diff --git a/firmware/bdb/dump_rsa.c b/firmware/bdb/dump_rsa.c new file mode 100644 index 00000000..c40f803a --- /dev/null +++ b/firmware/bdb/dump_rsa.c @@ -0,0 +1,200 @@ +/* Copyright (c) 2010 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. + */ + +/* + * C port of DumpPublicKey.java from the Android Open source project with + * support for additional RSA key sizes. (platform/system/core,git/libmincrypt + * /tools/DumpPublicKey.java). Uses the OpenSSL X509 and BIGNUM library. + */ + +#include + +#include +#include +#include + +/* + * Command line tool to extract RSA public keys from X.509 certificates and + * output a pre-processed version of keys for use by RSA verification routines. + */ + +int check(RSA *key) +{ + int public_exponent = BN_get_word(key->e); + int modulus = BN_num_bits(key->n); + + if (public_exponent != 65537 && public_exponent != 3) { + fprintf(stderr, "WARNING: Non-standard public exponent %d.\n", + public_exponent); + } + + if (modulus != 1024 && modulus != 2048 && modulus != 3072 && + modulus != 4096 && modulus != 8192) { + fprintf(stderr, "WARNING: Non-standard modulus length = %d.\n", + modulus); + } + return 1; +} + +/** + * Pre-processes and outputs RSA public key to standard output. + */ +void output(RSA *key) +{ + BIGNUM *N; + BIGNUM *Big1 = NULL, *Big2 = NULL, *Big32 = NULL, *BigMinus1 = NULL; + BIGNUM *B = NULL; + BIGNUM *N0inv= NULL, *R = NULL, *RR = NULL, *RRTemp = NULL; + BIGNUM *NnumBits = NULL; + BIGNUM *n = NULL, *rr = NULL; + BN_CTX *bn_ctx = BN_CTX_new(); + uint32_t n0invout; + int nwords, i; + + N = key->n; + /* Output size of RSA key in 32-bit words */ + nwords = BN_num_bits(N) / 32; + if (-1 == write(1, &nwords, sizeof(nwords))) + goto failure; + + /* Initialize BIGNUMs */ + Big1 = BN_new(); + Big2 = BN_new(); + Big32 = BN_new(); + BigMinus1 = BN_new(); + N0inv= BN_new(); + R = BN_new(); + RR = BN_new(); + RRTemp = BN_new(); + NnumBits = BN_new(); + n = BN_new(); + rr = BN_new(); + + BN_set_word(Big1, 1L); + BN_set_word(Big2, 2L); + BN_set_word(Big32, 32L); + BN_sub(BigMinus1, Big1, Big2); + + B = BN_new(); + BN_exp(B, Big2, Big32, bn_ctx); /* B = 2^32 */ + + /* Calculate and output N0inv = -1 / N[0] mod 2^32 */ + BN_mod_inverse(N0inv, N, B, bn_ctx); + BN_sub(N0inv, B, N0inv); + n0invout = BN_get_word(N0inv); + if (-1 == write(1, &n0invout, sizeof(n0invout))) + goto failure; + + /* Calculate R = 2^(# of key bits) */ + BN_set_word(NnumBits, BN_num_bits(N)); + BN_exp(R, Big2, NnumBits, bn_ctx); + + /* Calculate RR = R^2 mod N */ + BN_copy(RR, R); + BN_mul(RRTemp, RR, R, bn_ctx); + BN_mod(RR, RRTemp, N, bn_ctx); + + /* Write out modulus as little endian array of integers. */ + for (i = 0; i < nwords; ++i) { + uint32_t nout; + + BN_mod(n, N, B, bn_ctx); /* n = N mod B */ + nout = BN_get_word(n); + if (-1 == write(1, &nout, sizeof(nout))) + goto failure; + + BN_rshift(N, N, 32); /* N = N/B */ + } + + /* Write R^2 as little endian array of integers. */ + for (i = 0; i < nwords; ++i) { + uint32_t rrout; + + BN_mod(rr, RR, B, bn_ctx); /* rr = RR mod B */ + rrout = BN_get_word(rr); + if (-1 == write(1, &rrout, sizeof(rrout))) + goto failure; + + BN_rshift(RR, RR, 32); /* RR = RR/B */ + } + + failure: + /* Free BIGNUMs. */ + BN_free(Big1); + BN_free(Big2); + BN_free(Big32); + BN_free(BigMinus1); + BN_free(N0inv); + BN_free(R); + BN_free(RRTemp); + BN_free(NnumBits); + BN_free(n); + BN_free(rr); + +} + +int main(int argc, char* argv[]) { + int cert_mode = 0; + FILE* fp; + X509* cert = NULL; + RSA* pubkey = NULL; + EVP_PKEY* key; + char *progname; + + if (argc != 3 || + (strcmp(argv[1], "-cert") && strcmp(argv[1], "-pub"))) { + progname = strrchr(argv[0], '/'); + if (progname) + progname++; + else + progname = argv[0]; + fprintf(stderr, "Usage: %s <-cert | -pub> \n", progname); + return -1; + } + + if (!strcmp(argv[1], "-cert")) + cert_mode = 1; + + fp = fopen(argv[2], "r"); + + if (!fp) { + fprintf(stderr, "Couldn't open file %s!\n", argv[2]); + return -1; + } + + if (cert_mode) { + /* Read the certificate */ + if (!PEM_read_X509(fp, &cert, NULL, NULL)) { + fprintf(stderr, "Couldn't read certificate.\n"); + goto fail; + } + + /* Get the public key from the certificate. */ + key = X509_get_pubkey(cert); + + /* Convert to a RSA_style key. */ + if (!(pubkey = EVP_PKEY_get1_RSA(key))) { + fprintf(stderr, "Couldn't convert to RSA style key.\n"); + goto fail; + } + } else { + /* Read the pubkey in .PEM format. */ + if (!(pubkey = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL))) { + fprintf(stderr, "Couldn't read public key file.\n"); + goto fail; + } + } + + if (check(pubkey)) { + output(pubkey); + } + + fail: + X509_free(cert); + RSA_free(pubkey); + fclose(fp); + + return 0; +} diff --git a/firmware/bdb/ecdsa.c b/firmware/bdb/ecdsa.c new file mode 100644 index 00000000..f4d17287 --- /dev/null +++ b/firmware/bdb/ecdsa.c @@ -0,0 +1,17 @@ +/* Copyright (c) 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. + * + * Boot descriptor block firmware ECDSA stub + */ + +#include +#include "bdb.h" + +int bdb_ecdsa521_verify(const uint8_t *key_data, + const uint8_t *sig, + const uint8_t *digest) +{ + /* This is just a stub */ + return BDB_ERROR_DIGEST; +} diff --git a/firmware/bdb/host.c b/firmware/bdb/host.c new file mode 100644 index 00000000..24d94652 --- /dev/null +++ b/firmware/bdb/host.c @@ -0,0 +1,347 @@ +/* Copyright (c) 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. + * + * Host functions for signing + */ + +#include +#include +#include + +#include "bdb.h" +#include "host.h" + +char *strzcpy(char *dest, const char *src, size_t size) +{ + strncpy(dest, src, size); + dest[size - 1] = 0; + return dest; +} + +uint8_t *read_file(const char *filename, uint32_t *size_ptr) +{ + FILE *f; + uint8_t *buf; + long size; + + *size_ptr = 0; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Unable to open file %s\n", filename); + return NULL; + } + + fseek(f, 0, SEEK_END); + size = ftell(f); + rewind(f); + + if (size < 0 || size > UINT32_MAX) { + fclose(f); + return NULL; + } + + buf = malloc(size); + if (!buf) { + fclose(f); + return NULL; + } + + if (1 != fread(buf, size, 1, f)) { + fprintf(stderr, "Unable to read file %s\n", filename); + fclose(f); + free(buf); + return NULL; + } + + fclose(f); + + *size_ptr = size; + return buf; +} + +int write_file(const char *filename, const void *buf, uint32_t size) +{ + FILE *f = fopen(filename, "wb"); + + if (!f) { + fprintf(stderr, "Unable to open file %s\n", filename); + return 1; + } + + if (1 != fwrite(buf, size, 1, f)) { + fprintf(stderr, "Unable to write to file %s\n", filename); + fclose(f); + unlink(filename); /* Delete any partial file */ + return 1; + } + + fclose(f); + return 0; +} + +struct rsa_st *read_pem(const char *filename) +{ + struct rsa_st *pem; + FILE *f; + + /* Read private key */ + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "%s: unable to read key from %s\n", + __func__, filename); + return NULL; + } + + pem = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL); + fclose(f); + + return pem; +} + +struct bdb_key *bdb_create_key(const char *filename, + uint32_t key_version, + const char *desc) +{ + uint32_t sig_alg; + size_t key_size = sizeof(struct bdb_key); + struct bdb_key *k; + uint8_t *kdata; + uint32_t kdata_size = 0; + + /* + * Read key data. Somewhat lame assumption that we can determine the + * signature algorithm from the key size, but it's true right now. + */ + kdata = read_file(filename, &kdata_size); + if (kdata_size == BDB_RSA4096_KEY_DATA_SIZE) { + sig_alg = BDB_SIG_ALG_RSA4096; + } else if (kdata_size == BDB_RSA3072B_KEY_DATA_SIZE) { + sig_alg = BDB_SIG_ALG_RSA3072B; + } else { + fprintf(stderr, "%s: bad key size from %s\n", + __func__, filename); + return NULL; + } + key_size += kdata_size; + + /* Allocate buffer */ + k = (struct bdb_key *)calloc(key_size, 1); + if (!k) { + free(kdata); + return NULL; + } + + k->struct_magic = BDB_KEY_MAGIC; + k->struct_major_version = BDB_KEY_VERSION_MAJOR; + k->struct_minor_version = BDB_KEY_VERSION_MINOR; + k->struct_size = key_size; + k->hash_alg = BDB_HASH_ALG_SHA256; + k->sig_alg = sig_alg; + k->key_version = key_version; + + /* Copy description, if any */ + if (desc) + strzcpy(k->description, desc, sizeof(k->description)); + + /* Copy key data */ + memcpy(k->key_data, kdata, kdata_size); + free(kdata); + + return k; +} + +struct bdb_sig *bdb_create_sig(const void *data, + size_t size, + struct rsa_st *key, + uint32_t sig_alg, + const char *desc) +{ + static const uint8_t info[] = { + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, + 0x00, 0x04, 0x20 + }; + + size_t sig_size = sizeof(struct bdb_sig); + uint8_t digest[sizeof(info) + BDB_SHA256_DIGEST_SIZE]; + struct bdb_sig *sig; + + if (size >= UINT32_MAX) + return NULL; + + switch(sig_alg) { + case BDB_SIG_ALG_RSA4096: + sig_size += BDB_RSA4096_SIG_SIZE; + break; + case BDB_SIG_ALG_RSA3072B: + sig_size += BDB_RSA3072B_SIG_SIZE; + break; + default: + fprintf(stderr, "%s: bad signature algorithm %d\n", + __func__, sig_alg); + return NULL; + } + + /* Allocate buffer */ + sig = (struct bdb_sig *)calloc(sig_size, 1); + if (!sig) + return NULL; + + sig->struct_magic = BDB_SIG_MAGIC; + sig->struct_major_version = BDB_SIG_VERSION_MAJOR; + sig->struct_minor_version = BDB_SIG_VERSION_MINOR; + sig->struct_size = sig_size; + sig->hash_alg = BDB_HASH_ALG_SHA256; + sig->sig_alg = sig_alg; + sig->signed_size = size; + + /* Copy description, if any */ + if (desc) + strzcpy(sig->description, desc, sizeof(sig->description)); + + /* Calculate info-padded digest */ + memcpy(digest, info, sizeof(info)); + if (bdb_sha256(digest + sizeof(info), data, size)) { + free(sig); + return NULL; + } + + /* RSA-encrypt the signature */ + if (RSA_private_encrypt(sizeof(digest), + digest, + sig->sig_data, + key, + RSA_PKCS1_PADDING) == -1) { + free(sig); + return NULL; + } + return sig; +} + +struct bdb_header *bdb_create(struct bdb_create_params *p) +{ + size_t bdb_size = 0; + size_t sig_size = sizeof(struct bdb_sig) + BDB_RSA4096_SIG_SIZE; + size_t hashes_size = sizeof(struct bdb_hash) * p->num_hashes; + uint8_t *buf, *bnext; + struct bdb_header *h; + struct bdb_sig *sig; + struct bdb_data *data; + const void *oem; + + /* We can do some checks before we even allocate the buffer */ + + /* Make sure OEM sizes are aligned */ + if ((p->oem_area_0_size & 3) || (p->oem_area_1_size & 3)) { + fprintf(stderr, "%s: OEM areas not 32-bit aligned\n", + __func__); + return NULL; + } + + /* Hash count must fit in uint8_t */ + if (p->num_hashes > 255) { + fprintf(stderr, "%s: too many hashes\n", __func__); + return NULL; + } + + /* Calculate BDB size */ + bdb_size = sizeof(struct bdb_header); + bdb_size += p->bdbkey->struct_size; + bdb_size += p->oem_area_0_size; + bdb_size += p->subkey->struct_size; + bdb_size += sig_size; + bdb_size += sizeof(struct bdb_data); + bdb_size += p->oem_area_1_size; + bdb_size += sizeof(struct bdb_hash) * p->num_hashes; + bdb_size += sig_size; + + /* Make sure it fits */ + if (bdb_size > UINT32_MAX) { + fprintf(stderr, "%s: BDB size > UINT32_MAX\n", __func__); + return NULL; + } + + /* Allocate a buffer */ + bnext = buf = calloc(bdb_size, 1); + if (!buf) { + fprintf(stderr, "%s: can't allocate buffer\n", __func__); + return NULL; + } + + /* Fill in the header */ + h = (struct bdb_header *)bnext; + h->struct_magic = BDB_HEADER_MAGIC; + h->struct_major_version = BDB_HEADER_VERSION_MAJOR; + h->struct_minor_version = BDB_HEADER_VERSION_MINOR; + h->struct_size = sizeof(*h); + h->bdb_load_address = p->bdb_load_address; + h->bdb_size = bdb_size; + h->signed_size = p->oem_area_0_size + p->subkey->struct_size; + h->oem_area_0_size = p->oem_area_0_size; + bnext += h->struct_size; + + /* Copy BDB key */ + memcpy(bnext, p->bdbkey, p->bdbkey->struct_size); + bnext += p->bdbkey->struct_size; + + /* Copy OEM area 0 */ + oem = bnext; + if (p->oem_area_0_size) { + memcpy(bnext, p->oem_area_0, p->oem_area_0_size); + bnext += p->oem_area_0_size; + } + + /* Copy subkey */ + memcpy(bnext, p->subkey, p->subkey->struct_size); + bnext += p->subkey->struct_size; + + /* + * Create header signature using private BDB key. + * + * TODO: create the header signature in a totally separate step. That + * way, the private BDB key is not required each time a BDB is created. + */ + sig = bdb_create_sig(oem, h->signed_size, p->private_bdbkey, + p->bdbkey->sig_alg, p->header_sig_description); + memcpy(bnext, sig, sig->struct_size); + bnext += sig->struct_size; + + /* Fill in the data */ + data = (struct bdb_data *)bnext; + data->struct_magic = BDB_DATA_MAGIC; + data->struct_major_version = BDB_DATA_VERSION_MAJOR; + data->struct_minor_version = BDB_DATA_VERSION_MINOR; + data->struct_size = sizeof(struct bdb_data); + data->data_version = p->data_version; + data->oem_area_1_size = p->oem_area_1_size; + data->num_hashes = p->num_hashes; + data->hash_entry_size = sizeof(struct bdb_hash); + data->signed_size = data->struct_size + data->oem_area_1_size + + hashes_size; + if (p->data_description) { + strzcpy(data->description, p->data_description, + sizeof(data->description)); + } + bnext += data->struct_size; + + /* Copy OEM area 1 */ + oem = bnext; + if (p->oem_area_1_size) { + memcpy(bnext, p->oem_area_1, p->oem_area_1_size); + bnext += p->oem_area_1_size; + } + + /* Copy hashes */ + memcpy(bnext, p->hash, hashes_size); + bnext += hashes_size; + + /* Create data signature using private subkey */ + sig = bdb_create_sig(data, data->signed_size, p->private_subkey, + p->subkey->sig_alg, p->data_sig_description); + memcpy(bnext, sig, sig->struct_size); + + /* Return the BDB */ + return h; +} diff --git a/firmware/bdb/host.h b/firmware/bdb/host.h new file mode 100644 index 00000000..9334680b --- /dev/null +++ b/firmware/bdb/host.h @@ -0,0 +1,171 @@ +/* Copyright (c) 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. + * + * Boot descriptor block host functions + */ + +#ifndef VBOOT_REFERENCE_BDB_HOST_H_ +#define VBOOT_REFERENCE_BDB_HOST_H_ + +#include +#include +#include "bdb_struct.h" + +/*****************************************************************************/ +/* +Expected calling sequence: + +Load and check just the header +bdb_check_header(buf, size); + +Load and verify the entire BDB +bdb_verify(buf, size, bdb_key_hash, dev_mode_flag); + + bdb_check_header() again - paranoia against bad storage devices + + bdb_check_key() on BDB key + bdb_sha256() on BDB key + Compare with appropriate root key hash + If dev_mode_flag(), mismatch is not fatal + + bdb_check_sig() on BDB header sig + bdb_sha256() on OEM area 1, RW subkey + bdb_rsa_verify() on digest using BDB key + + bdb_check_key() on RW subkey + + bdb_check_data() on RW data + bdb_check_sig() on data sig + bdb_sha256() on data, OEM area 1, hashes + bdb_rsa_verify() on digest using RW subkey + +Check RW subkey version. If normal boot from primary BDB, roll forward +Check data version. If normal boot from primary BDB, roll forward +*/ + +/*****************************************************************************/ +/* Codes for functions returning numeric error codes */ + +enum bdb_host_return_code { + /* All/any of bdb_return_code, and the following... */ + + /* Other errors */ + BDB_ERROR_HOST = 200, +}; + +/*****************************************************************************/ +/* Functions */ + +/** + * Like strncpy, but guaranteeing null termination + */ +char *strzcpy(char *dest, const char *src, size_t size); + +/** + * Read a file. + * + * Caller must free() the returned buffer. + * + * @param filename Path to file + * @param size_ptr Destination for size of buffer + * @return A newly allocated buffer containing the data, or NULL if error. + */ +uint8_t *read_file(const char *filename, uint32_t *size_ptr); + +/** + * Write a file. + * + * @param buf Data to write + * @param size Size of data in bytes + * @return 0 if success, non-zero error code if error. + */ +int write_file(const char *filename, const void *buf, uint32_t size); + +/** + * Read a PEM from a file. + * + * Caller must free the PEM with RSA_free(). + * + * @param filename Path to file + * @return A newly allocated PEM object, or NULL if error. + */ +struct rsa_st *read_pem(const char *filename); + +/** + * Create a BDB public key object. + * + * Caller must free() the returned key. + * + * @param filename Path to file containing public key (.keyb) + * @param key_version Version for key + * @param desc Description. Optional; may be NULL. + * @return A newly allocated public key, or NULL if error. + */ +struct bdb_key *bdb_create_key(const char *filename, + uint32_t key_version, + const char *desc); + +/** + * Create a BDB signature object. + * + * Caller must free() the returned signature. + * + * @param data Data to sign + * @param size Size of data in bytes + * @param key PEM key + * @param sig_alg Signature algorithm + * @param desc Description. Optional; may be NULL. + * @return A newly allocated signature, or NULL if error. + */ +struct bdb_sig *bdb_create_sig(const void *data, + size_t size, + struct rsa_st *key, + uint32_t sig_alg, + const char *desc); + +struct bdb_create_params +{ + /* Load address */ + uint64_t bdb_load_address; + + /* OEM areas. Size may be 0, in which case the buffer is ignored */ + uint8_t *oem_area_0; + uint32_t oem_area_0_size; + uint8_t *oem_area_1; + uint32_t oem_area_1_size; + + /* Public BDB key and subkey */ + struct bdb_key *bdbkey; + struct bdb_key *subkey; + + /* Private BDB key and subkey */ + struct rsa_st *private_bdbkey; + struct rsa_st *private_subkey; + + /* Descriptions for header and data signatures */ + char *header_sig_description; + char *data_sig_description; + + /* Data description and version */ + char *data_description; + uint32_t data_version; + + /* Data hashes and count */ + struct bdb_hash *hash; + uint32_t num_hashes; +}; + +/** + * Create a new BDB + * + * Caller must free() returned object. + * + * @param p Creation parameters + * @return A newly allocated BDB, or NULL if error. + */ +struct bdb_header *bdb_create(struct bdb_create_params *p); + +/*****************************************************************************/ + +#endif /* VBOOT_REFERENCE_BDB_HOST_H_ */ diff --git a/firmware/bdb/rsa.c b/firmware/bdb/rsa.c new file mode 100644 index 00000000..932c9733 --- /dev/null +++ b/firmware/bdb/rsa.c @@ -0,0 +1,339 @@ +/* Copyright (c) 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. + * + * Boot descriptor block firmware RSA + */ + +#include +#include "bdb.h" + +/* Public key structure in RAM */ +struct public_key { + uint32_t arrsize; /* Size of n[] and rr[] arrays in elements */ + uint32_t n0inv; /* -1 / n[0] mod 2^32 */ + const uint32_t *n; /* Modulus as little endian array */ + const uint32_t *rr; /* R^2 as little endian array */ +}; + +/** + * a[] -= mod + */ +static void subM(const struct public_key *key, uint32_t *a) +{ + int64_t A = 0; + uint32_t i; + for (i = 0; i < key->arrsize; ++i) { + A += (uint64_t)a[i] - key->n[i]; + a[i] = (uint32_t)A; + A >>= 32; + } +} + +/** + * Return a[] >= mod + */ +int vb2_mont_ge(const struct public_key *key, uint32_t *a) +{ + uint32_t i; + for (i = key->arrsize; i;) { + --i; + if (a[i] < key->n[i]) + return 0; + if (a[i] > key->n[i]) + return 1; + } + return 1; /* equal */ +} + +/** + * Montgomery c[] += a * b[] / R % mod + */ +static void montMulAdd(const struct public_key *key, + uint32_t *c, + const uint32_t a, + const uint32_t *b) +{ + uint64_t A = (uint64_t)a * b[0] + c[0]; + uint32_t d0 = (uint32_t)A * key->n0inv; + uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A; + uint32_t i; + + for (i = 1; i < key->arrsize; ++i) { + A = (A >> 32) + (uint64_t)a * b[i] + c[i]; + B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A; + c[i - 1] = (uint32_t)B; + } + + A = (A >> 32) + (B >> 32); + + c[i - 1] = (uint32_t)A; + + if (A >> 32) { + subM(key, c); + } +} + +/** + * Montgomery c[] = a[] * b[] / R % mod + */ +static void montMul(const struct public_key *key, + uint32_t *c, + const uint32_t *a, + const uint32_t *b) +{ + uint32_t i; + for (i = 0; i < key->arrsize; ++i) { + c[i] = 0; + } + for (i = 0; i < key->arrsize; ++i) { + montMulAdd(key, c, a[i], b); + } +} + +int vb2_safe_memcmp(const void *s1, const void *s2, size_t size) +{ + const unsigned char *us1 = s1; + const unsigned char *us2 = s2; + int result = 0; + + if (0 == size) + return 0; + + /* + * Code snippet without data-dependent branch due to Nate Lawson + * (nate@root.org) of Root Labs. + */ + while (size--) + result |= *us1++ ^ *us2++; + + return result != 0; +} + +/* + * PKCS 1.5 padding (from the RSA PKCS#1 v2.1 standard) + * + * Depending on the RSA key size and hash function, the padding is calculated + * as follows: + * + * 0x00 || 0x01 || PS || 0x00 || T + * + * T: DER Encoded DigestInfo value which depends on the hash function used. + * + * SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H. + * + * Length(T) = 51 octets for SHA-256 + * + * PS: octet string consisting of {Length(RSA Key) - Length(T) - 3} 0xFF + */ +static const uint8_t sha256_tail[] = { + 0x00,0x30,0x31,0x30,0x0d,0x06,0x09,0x60, + 0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01, + 0x05,0x00,0x04,0x20 +}; + +int vb2_check_padding(const uint8_t *sig, const struct public_key *key, + uint32_t pad_size) +{ + /* Determine padding to use depending on the signature type */ + const uint32_t tail_size = sizeof(sha256_tail); + int result = 0; + int i; + + /* First 2 bytes are always 0x00 0x01 */ + result |= *sig++ ^ 0x00; + result |= *sig++ ^ 0x01; + + /* Then 0xff bytes until the tail */ + for (i = 0; i < pad_size - tail_size - 2; i++) + result |= *sig++ ^ 0xff; + + /* + * Then the tail. Even though there are probably no timing issues + * here, we use vb2_safe_memcmp() just to be on the safe side. + */ + result |= vb2_safe_memcmp(sig, sha256_tail, tail_size); + + return result ? BDB_ERROR_DIGEST : BDB_SUCCESS; +} + +/* Array size for RSA4096 */ +#define ARRSIZE4096 (4096 / 32) + +/** + * In-place public exponentiation. (exponent 65537, key size 4096 bits) + * + * @param key Key to use in signing + * @param inout Input and output big-endian byte array + */ +static void modpowF4(const struct public_key *key, uint8_t *inout) +{ + uint32_t a[ARRSIZE4096]; + uint32_t aR[ARRSIZE4096]; + uint32_t aaR[ARRSIZE4096]; + uint32_t *aaa = aaR; /* Re-use location. */ + int i; + + /* Convert from big endian byte array to little endian word array. */ + for (i = 0; i < ARRSIZE4096; ++i) { + uint32_t tmp = + (inout[((ARRSIZE4096 - 1 - i) * 4) + 0] << 24) | + (inout[((ARRSIZE4096 - 1 - i) * 4) + 1] << 16) | + (inout[((ARRSIZE4096 - 1 - i) * 4) + 2] << 8) | + (inout[((ARRSIZE4096 - 1 - i) * 4) + 3] << 0); + a[i] = tmp; + } + + montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */ + for (i = 0; i < 16; i+=2) { + montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */ + montMul(key, aR, aaR, aaR); /* aR = aaR * aaR / R mod M */ + } + montMul(key, aaa, aR, a); /* aaa = aR * a / R mod M */ + + /* Make sure aaa < mod; aaa is at most 1x mod too large. */ + if (vb2_mont_ge(key, aaa)) { + subM(key, aaa); + } + + /* Convert to bigendian byte array */ + for (i = ARRSIZE4096 - 1; i >= 0; --i) { + uint32_t tmp = aaa[i]; + *inout++ = (uint8_t)(tmp >> 24); + *inout++ = (uint8_t)(tmp >> 16); + *inout++ = (uint8_t)(tmp >> 8); + *inout++ = (uint8_t)(tmp >> 0); + } +} + +int bdb_rsa4096_verify(const uint8_t *key_data, + const uint8_t *sig, + const uint8_t *digest) +{ + const uint32_t *kdata32 = (const uint32_t *)key_data; + struct public_key key; + uint8_t sig_work[BDB_RSA4096_SIG_SIZE]; + uint32_t pad_size; + int rv; + + /* Unpack key */ + if (kdata32[0] != ARRSIZE4096) + return BDB_ERROR_DIGEST; /* Wrong key size */ + + key.arrsize = kdata32[0]; + key.n0inv = kdata32[1]; + key.n = kdata32 + 2; + key.rr = kdata32 + 2 + key.arrsize; + + /* Copy signature to work buffer */ + memcpy(sig_work, sig, sizeof(sig_work)); + + modpowF4(&key, sig_work); + + /* + * Check padding. Continue on to check the digest even if error to + * reduce the risk of timing based attacks. + */ + pad_size = key.arrsize * sizeof(uint32_t) - BDB_SHA256_DIGEST_SIZE; + rv = vb2_check_padding(sig_work, &key, pad_size); + + /* + * Check digest. Even though there are probably no timing issues here, + * use vb2_safe_memcmp() just to be on the safe side. (That's also why + * we don't return before this check if the padding check failed.) + */ + if (vb2_safe_memcmp(sig_work + pad_size, digest, + BDB_SHA256_DIGEST_SIZE)) + rv = BDB_ERROR_DIGEST; + + return rv; +} + +/* Array size for RSA3072B */ +#define ARRSIZE3072B (3072 / 32) + +/** + * In-place public exponentiation. (exponent 3, key size 3072 bits) + * + * @param key Key to use in signing + * @param inout Input and output big-endian byte array + */ +static void modpow3(const struct public_key *key, uint8_t *inout) +{ + uint32_t a[ARRSIZE3072B]; + uint32_t aR[ARRSIZE3072B]; + uint32_t aaR[ARRSIZE3072B]; + uint32_t *aaa = aR; /* Re-use location */ + int i; + + /* Convert from big endian byte array to little endian word array. */ + for (i = 0; i < ARRSIZE3072B; ++i) { + uint32_t tmp = + (inout[((ARRSIZE3072B - 1 - i) * 4) + 0] << 24) | + (inout[((ARRSIZE3072B - 1 - i) * 4) + 1] << 16) | + (inout[((ARRSIZE3072B - 1 - i) * 4) + 2] << 8) | + (inout[((ARRSIZE3072B - 1 - i) * 4) + 3] << 0); + a[i] = tmp; + } + + montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */ + montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */ + montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */ + + /* Make sure aaa < mod; aaa is at most 1x mod too large. */ + if (vb2_mont_ge(key, aaa)) { + subM(key, aaa); + } + + /* Convert to bigendian byte array */ + for (i = ARRSIZE3072B - 1; i >= 0; --i) { + uint32_t tmp = aaa[i]; + *inout++ = (uint8_t)(tmp >> 24); + *inout++ = (uint8_t)(tmp >> 16); + *inout++ = (uint8_t)(tmp >> 8); + *inout++ = (uint8_t)(tmp >> 0); + } +} + +int bdb_rsa3072b_verify(const uint8_t *key_data, + const uint8_t *sig, + const uint8_t *digest) +{ + const uint32_t *kdata32 = (const uint32_t *)key_data; + struct public_key key; + uint8_t sig_work[BDB_RSA3072B_SIG_SIZE]; + uint32_t pad_size; + int rv; + + /* Unpack key */ + if (kdata32[0] != ARRSIZE3072B) + return BDB_ERROR_DIGEST; /* Wrong key size */ + + key.arrsize = kdata32[0]; + key.n0inv = kdata32[1]; + key.n = kdata32 + 2; + key.rr = kdata32 + 2 + key.arrsize; + + /* Copy signature to work buffer */ + memcpy(sig_work, sig, sizeof(sig_work)); + + modpow3(&key, sig_work); + + /* + * Check padding. Continue on to check the digest even if error to + * reduce the risk of timing based attacks. + */ + pad_size = key.arrsize * sizeof(uint32_t) - BDB_SHA256_DIGEST_SIZE; + rv = vb2_check_padding(sig_work, &key, pad_size); + + /* + * Check digest. Even though there are probably no timing issues here, + * use vb2_safe_memcmp() just to be on the safe side. (That's also why + * we don't return before this check if the padding check failed.) + */ + if (vb2_safe_memcmp(sig_work + pad_size, digest, + BDB_SHA256_DIGEST_SIZE)) + rv = BDB_ERROR_DIGEST; + + return rv; +} diff --git a/firmware/bdb/sha.c b/firmware/bdb/sha.c new file mode 100644 index 00000000..1e83662d --- /dev/null +++ b/firmware/bdb/sha.c @@ -0,0 +1,210 @@ +/* SHA-256 and SHA-512 implementation based on code by Oliver Gay + * under a BSD-style license. See below. + */ +/* + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005, 2007 Olivier Gay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "bdb.h" + +#define VB2_SHA256_DIGEST_SIZE 32 +#define VB2_SHA256_BLOCK_SIZE 64 + +struct vb2_sha256_context { + uint32_t h[8]; + uint32_t total_size; + uint32_t size; + uint8_t block[2 * VB2_SHA256_BLOCK_SIZE]; +}; + +#define SHFR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) +#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) +#define CH(x, y, z) ((x & y) ^ (~x & z)) +#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) +#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) +#define UNPACK32(x, str) \ + { \ + *((str) + 3) = (uint8_t) ((x) ); \ + *((str) + 2) = (uint8_t) ((x) >> 8); \ + *((str) + 1) = (uint8_t) ((x) >> 16); \ + *((str) + 0) = (uint8_t) ((x) >> 24); \ + } +#define PACK32(str, x) \ + { \ + *(x) = ((uint32_t) *((str) + 3) ) \ + | ((uint32_t) *((str) + 2) << 8) \ + | ((uint32_t) *((str) + 1) << 16) \ + | ((uint32_t) *((str) + 0) << 24); \ + } +#define SHA256_SCR(i) \ + { \ + w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + + SHA256_F3(w[i - 15]) + w[i - 16]; \ + } + +static const uint32_t sha256_h0[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +static const uint32_t sha256_k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +/* SHA-256 implementation from verified boot library */ +void vb2_sha256_init(struct vb2_sha256_context *ctx) +{ + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha256_h0[i]; + } + ctx->size = 0; + ctx->total_size = 0; +} + +static void vb2_sha256_transform(struct vb2_sha256_context *ctx, + const uint8_t *message, + unsigned int block_nb) +{ + /* Note that these arrays use 72*4=288 bytes of stack */ + uint32_t w[64]; + uint32_t wv[8]; + uint32_t t1, t2; + const unsigned char *sub_block; + int i; + int j; + for (i = 0; i < (int) block_nb; i++) { + sub_block = message + (i << 6); + for (j = 0; j < 16; j++) { + PACK32(&sub_block[j << 2], &w[j]); + } + for (j = 16; j < 64; j++) { + SHA256_SCR(j); + } + for (j = 0; j < 8; j++) { + wv[j] = ctx->h[j]; + } + for (j = 0; j < 64; j++) { + t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + + sha256_k[j] + w[j]; + t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + for (j = 0; j < 8; j++) { + ctx->h[j] += wv[j]; + } + } +} + +void vb2_sha256_update(struct vb2_sha256_context *ctx, + const uint8_t *data, + uint32_t size) +{ + unsigned int block_nb; + unsigned int new_size, rem_size, tmp_size; + const uint8_t *shifted_data; + tmp_size = VB2_SHA256_BLOCK_SIZE - ctx->size; + rem_size = size < tmp_size ? size : tmp_size; + memcpy(&ctx->block[ctx->size], data, rem_size); + if (ctx->size + size < VB2_SHA256_BLOCK_SIZE) { + ctx->size += size; + return; + } + new_size = size - rem_size; + block_nb = new_size / VB2_SHA256_BLOCK_SIZE; + shifted_data = data + rem_size; + vb2_sha256_transform(ctx, ctx->block, 1); + vb2_sha256_transform(ctx, shifted_data, block_nb); + rem_size = new_size % VB2_SHA256_BLOCK_SIZE; + memcpy(ctx->block, &shifted_data[block_nb << 6], + rem_size); + ctx->size = rem_size; + ctx->total_size += (block_nb + 1) << 6; +} + +void vb2_sha256_finalize(struct vb2_sha256_context *ctx, uint8_t *digest) +{ + unsigned int block_nb; + unsigned int pm_size; + unsigned int size_b; + int i; + block_nb = (1 + ((VB2_SHA256_BLOCK_SIZE - 9) + < (ctx->size % VB2_SHA256_BLOCK_SIZE))); + size_b = (ctx->total_size + ctx->size) << 3; + pm_size = block_nb << 6; + memset(ctx->block + ctx->size, 0, pm_size - ctx->size); + ctx->block[ctx->size] = 0x80; + UNPACK32(size_b, ctx->block + pm_size - 4); + vb2_sha256_transform(ctx, ctx->block, block_nb); + for (i = 0 ; i < 8; i++) { + UNPACK32(ctx->h[i], &digest[i << 2]); + } +} + +int bdb_sha256(void *digest, const void *buf, size_t size) +{ + struct vb2_sha256_context ctx; + + vb2_sha256_init(&ctx); + vb2_sha256_update(&ctx, buf, size); + vb2_sha256_finalize(&ctx, digest); + + return BDB_SUCCESS; +} diff --git a/tests/bdb_test.c b/tests/bdb_test.c new file mode 100644 index 00000000..6c9022dc --- /dev/null +++ b/tests/bdb_test.c @@ -0,0 +1,492 @@ +/* Copyright (c) 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. + * + * Unit tests + */ + +#include +#include +#include + +#include "bdb.h" +#include "host.h" + +#define TEST_EQ(got, want) test_eq(got, want, #got, #want, __LINE__) + +void test_eq(int got, int want, const char *gotstr, const char *wantstr, + int line) +{ + if (got == want) + return; + + fprintf(stderr, "Fail(%d): %s != %s\n" + "got: 0x%08x (%d)\n" + "wanted: 0x%08x (%d)\n", + line, gotstr, wantstr, got, got, want, want); + exit(1); +} + +void check_header_tests(void) +{ + struct bdb_header sgood = { + .struct_magic = BDB_HEADER_MAGIC, + .struct_major_version = BDB_HEADER_VERSION_MAJOR, + .struct_minor_version = BDB_HEADER_VERSION_MINOR, + .struct_size = sizeof(struct bdb_header), + .bdb_load_address = -1, + .bdb_size = 1024, + .signed_size = 512, + .oem_area_0_size = 256, + }; + const size_t ssize = sgood.struct_size; + struct bdb_header s; + + s = sgood; + TEST_EQ(bdb_check_header(&s, ssize), BDB_SUCCESS); + TEST_EQ(bdb_check_header(&s, ssize - 1), BDB_ERROR_BUF_SIZE); + + s = sgood; + s.struct_size++; + TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_BUF_SIZE); + + s = sgood; + s.struct_size--; + TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_STRUCT_SIZE); + + s = sgood; + s.struct_magic++; + TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_STRUCT_MAGIC); + + s = sgood; + s.struct_major_version++; + TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_STRUCT_VERSION); + + s = sgood; + s.oem_area_0_size++; + TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_OEM_AREA_SIZE); + + s = sgood; + s.bdb_size = ssize - 1; + TEST_EQ(bdb_check_header(&s, ssize), BDB_ERROR_BDB_SIZE); +} + +void check_key_tests(void) +{ + struct bdb_key sgood = { + .struct_magic = BDB_KEY_MAGIC, + .struct_major_version = BDB_KEY_VERSION_MAJOR, + .struct_minor_version = BDB_KEY_VERSION_MINOR, + .struct_size = (sizeof(struct bdb_key) + + BDB_RSA4096_KEY_DATA_SIZE), + .hash_alg = BDB_HASH_ALG_SHA256, + .sig_alg = BDB_SIG_ALG_RSA4096, + .key_version = 1, + .description = "Test key", + }; + const size_t ssize = sgood.struct_size; + struct bdb_key s; + + s = sgood; + TEST_EQ(bdb_check_key(&s, ssize), BDB_SUCCESS); + TEST_EQ(bdb_check_key(&s, ssize - 1), BDB_ERROR_BUF_SIZE); + + s = sgood; + s.struct_size++; + TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_BUF_SIZE); + + s = sgood; + s.struct_size--; + TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_STRUCT_SIZE); + + s = sgood; + s.struct_magic++; + TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_STRUCT_MAGIC); + + s = sgood; + s.struct_major_version++; + TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_STRUCT_VERSION); + + /* Description must contain a null */ + s = sgood; + memset(s.description, 'x', sizeof(s.description)); + TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_DESCRIPTION); + + /* Data AFTER the null is explicitly allowed, though */ + s = sgood; + s.description[100] = 'x'; + TEST_EQ(bdb_check_key(&s, ssize), BDB_SUCCESS); + + /* Limited algorithm choices at present */ + s = sgood; + s.hash_alg = BDB_HASH_ALG_INVALID; + TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_HASH_ALG); + + /* This works because ECDSA521 signatures are smaller than RSA4096 */ + s = sgood; + s.sig_alg = BDB_SIG_ALG_ECSDSA521; + TEST_EQ(bdb_check_key(&s, ssize), BDB_SUCCESS); + + s = sgood; + s.sig_alg = BDB_SIG_ALG_INVALID; + TEST_EQ(bdb_check_key(&s, ssize), BDB_ERROR_SIG_ALG); +} + +void check_sig_tests(void) +{ + struct bdb_sig sgood = { + .struct_magic = BDB_SIG_MAGIC, + .struct_major_version = BDB_SIG_VERSION_MAJOR, + .struct_minor_version = BDB_SIG_VERSION_MINOR, + .struct_size = sizeof(struct bdb_sig) + BDB_RSA4096_SIG_SIZE, + .hash_alg = BDB_HASH_ALG_SHA256, + .sig_alg = BDB_SIG_ALG_RSA4096, + .signed_size = 123, + .description = "Test sig", + }; + const size_t ssize = sgood.struct_size; + struct bdb_sig s; + + s = sgood; + TEST_EQ(bdb_check_sig(&s, ssize), BDB_SUCCESS); + TEST_EQ(bdb_check_sig(&s, ssize - 1), BDB_ERROR_BUF_SIZE); + + s = sgood; + s.struct_size++; + TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_BUF_SIZE); + + s = sgood; + s.struct_size--; + TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_STRUCT_SIZE); + + s = sgood; + s.struct_magic++; + TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_STRUCT_MAGIC); + + s = sgood; + s.struct_major_version++; + TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_STRUCT_VERSION); + + /* Description must contain a null */ + s = sgood; + memset(s.description, 'x', sizeof(s.description)); + TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_DESCRIPTION); + + /* Data AFTER the null is explicitly allowed, though */ + s = sgood; + s.description[100] = 'x'; + TEST_EQ(bdb_check_sig(&s, ssize), BDB_SUCCESS); + + /* Limited algorithm choices at present */ + s = sgood; + s.hash_alg = BDB_HASH_ALG_INVALID; + TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_HASH_ALG); + + /* This works because ECDSA521 signatures are smaller than RSA4096 */ + s = sgood; + s.sig_alg = BDB_SIG_ALG_ECSDSA521; + TEST_EQ(bdb_check_sig(&s, ssize), BDB_SUCCESS); + + s = sgood; + s.sig_alg = BDB_SIG_ALG_INVALID; + TEST_EQ(bdb_check_sig(&s, ssize), BDB_ERROR_SIG_ALG); +} + +void check_data_tests(void) +{ + struct bdb_data sgood = { + .struct_magic = BDB_DATA_MAGIC, + .struct_major_version = BDB_DATA_VERSION_MAJOR, + .struct_minor_version = BDB_DATA_VERSION_MINOR, + .struct_size = sizeof(struct bdb_data), + .data_version = 1, + .oem_area_1_size = 256, + .num_hashes = 3, + .hash_entry_size = sizeof(struct bdb_hash), + .signed_size = 2048, + .description = "Test data", + }; + const size_t ssize = sgood.signed_size; + struct bdb_data s; + + s = sgood; + TEST_EQ(bdb_check_data(&s, ssize), BDB_SUCCESS); + TEST_EQ(bdb_check_data(&s, ssize - 1), BDB_ERROR_BUF_SIZE); + + s = sgood; + s.struct_size--; + TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_STRUCT_SIZE); + + s = sgood; + s.struct_magic++; + TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_STRUCT_MAGIC); + + s = sgood; + s.struct_major_version++; + TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_STRUCT_VERSION); + + /* Description must contain a null */ + s = sgood; + memset(s.description, 'x', sizeof(s.description)); + TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_DESCRIPTION); + + /* Data AFTER the null is explicitly allowed, though */ + s = sgood; + s.description[100] = 'x'; + TEST_EQ(bdb_check_data(&s, ssize), BDB_SUCCESS); + + s = sgood; + s.hash_entry_size--; + TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_HASH_ENTRY_SIZE); + + s = sgood; + s.oem_area_1_size++; + TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_OEM_AREA_SIZE); + + /* Check exact size needed */ + s = sgood; + s.signed_size = sizeof(s) + s.num_hashes * sizeof(struct bdb_hash) + + s.oem_area_1_size; + TEST_EQ(bdb_check_data(&s, ssize), BDB_SUCCESS); + s.signed_size--; + TEST_EQ(bdb_check_data(&s, ssize), BDB_ERROR_SIGNED_SIZE); + + /* + * TODO: Verify wraparound check works. That can only be tested on a + * platform where size_t is uint32_t, because otherwise a 32-bit + * oem_area_1_size can't cause wraparound. + */ +} + +/** + * Test bdb_verify() and bdb_create() + */ +void check_bdb_verify(void) +{ + uint8_t oem_area_0[32] = "Some OEM area."; + uint8_t oem_area_1[64] = "Some other OEM area."; + + struct bdb_hash hash[2] = { + { + .offset = 0x10000, + .size = 0x18000, + .partition = 1, + .type = BDB_DATA_SP_RW, + .load_address = 0x100000, + .digest = {0x11, 0x11, 0x11, 0x10}, + }, + { + .offset = 0x28000, + .size = 0x20000, + .partition = 1, + .type = BDB_DATA_AP_RW, + .load_address = 0x200000, + .digest = {0x22, 0x22, 0x22, 0x20}, + }, + }; + + struct bdb_create_params p = { + .bdb_load_address = 0x11223344, + .oem_area_0 = oem_area_0, + .oem_area_0_size = sizeof(oem_area_0), + .oem_area_1 = oem_area_1, + .oem_area_1_size = sizeof(oem_area_1), + .header_sig_description = "The header sig", + .data_sig_description = "The data sig", + .data_description = "Test BDB data", + .data_version = 3, + .hash = hash, + .num_hashes = 2, + }; + + uint8_t bdbkey_digest[BDB_SHA256_DIGEST_SIZE]; + struct bdb_header *hgood, *h; + size_t hsize; + + /* Load keys */ + p.bdbkey = bdb_create_key("testkeys/bdbkey.keyb", 100, "BDB key"); + p.subkey = bdb_create_key("testkeys/subkey.keyb", 200, "Subkey"); + p.private_bdbkey = read_pem("testkeys/bdbkey.pem"); + p.private_subkey = read_pem("testkeys/subkey.pem"); + if (!p.bdbkey || !p.subkey || !p.private_bdbkey || !p.private_subkey) { + fprintf(stderr, "Unable to load test keys\n"); + exit(2); + } + + bdb_sha256(bdbkey_digest, p.bdbkey, p.bdbkey->struct_size); + + /* Create the test BDB */ + hgood = bdb_create(&p); + if (!hgood) { + fprintf(stderr, "Unable to create test BDB\n"); + exit(2); + } + hsize = hgood->bdb_size; + + /* Allocate a copy we can mangle */ + h = calloc(hsize, 1); + + /* As created, it should pass */ + memcpy(h, hgood, hsize); + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_SUCCESS); + + /* Mangle each component in turn */ + memcpy(h, hgood, hsize); + h->struct_magic++; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER); + + memcpy(h, hgood, hsize); + ((struct bdb_key *)bdb_get_bdbkey(h))->struct_magic++; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_BDBKEY); + + memcpy(h, hgood, hsize); + ((struct bdb_key *)bdb_get_bdbkey(h))->key_version++; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_GOOD_OTHER_THAN_KEY); + + memcpy(h, hgood, hsize); + h->oem_area_0_size += hsize; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_OEM_AREA_0); + + memcpy(h, hgood, hsize); + ((struct bdb_key *)bdb_get_subkey(h))->struct_magic++; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_SUBKEY); + + memcpy(h, hgood, hsize); + ((struct bdb_key *)bdb_get_subkey(h))->struct_size += 4; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_BDB_SIGNED_SIZE); + + memcpy(h, hgood, hsize); + ((struct bdb_sig *)bdb_get_header_sig(h))->struct_magic++; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG); + + memcpy(h, hgood, hsize); + ((struct bdb_sig *)bdb_get_header_sig(h))->signed_size--; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG); + + memcpy(h, hgood, hsize); + ((struct bdb_sig *)bdb_get_header_sig(h))->sig_data[0] ^= 0x42; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG); + + /* Also make sure the header sig really covers all the fields */ + memcpy(h, hgood, hsize); + ((struct bdb_key *)bdb_get_subkey(h))->key_version++; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG); + + memcpy(h, hgood, hsize); + ((uint8_t *)bdb_get_oem_area_0(h))[0] ^= 0x42; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG); + + memcpy(h, hgood, hsize); + ((uint8_t *)bdb_get_oem_area_0(h))[p.oem_area_0_size - 1] ^= 0x24; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER_SIG); + + /* Check data header */ + memcpy(h, hgood, hsize); + ((struct bdb_data *)bdb_get_data(h))->struct_magic++; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA); + + memcpy(h, hgood, hsize); + ((struct bdb_sig *)bdb_get_data_sig(h))->struct_magic++; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG); + + memcpy(h, hgood, hsize); + ((struct bdb_sig *)bdb_get_data_sig(h))->signed_size--; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG); + + memcpy(h, hgood, hsize); + ((struct bdb_sig *)bdb_get_data_sig(h))->sig_data[0] ^= 0x42; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG); + + /* Also make sure the data sig really covers all the fields */ + memcpy(h, hgood, hsize); + ((struct bdb_data *)bdb_get_data(h))->data_version--; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG); + + memcpy(h, hgood, hsize); + ((uint8_t *)bdb_get_oem_area_1(h))[0] ^= 0x42; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG); + + memcpy(h, hgood, hsize); + ((uint8_t *)bdb_get_oem_area_1(h))[p.oem_area_1_size - 1] ^= 0x24; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG); + + memcpy(h, hgood, hsize); + ((struct bdb_hash *)bdb_get_hash(h, BDB_DATA_SP_RW))->offset++; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG); + + memcpy(h, hgood, hsize); + ((struct bdb_hash *)bdb_get_hash(h, BDB_DATA_AP_RW))->digest[0] ^= 0x96; + TEST_EQ(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG); + + /* + * This is also a convenient place to test that all the parameters we + * fed into bdb_create() also worked. That also tests all the + * bdb_get_*() functions. + */ + memcpy(h, hgood, hsize); + TEST_EQ(h->bdb_load_address, p.bdb_load_address); + + TEST_EQ(strcmp(bdb_get_bdbkey(h)->description, + p.bdbkey->description), 0); + TEST_EQ(bdb_get_bdbkey(h)->key_version, p.bdbkey->key_version); + + TEST_EQ(h->oem_area_0_size, p.oem_area_0_size); + TEST_EQ(memcmp(bdb_get_oem_area_0(h), oem_area_0, sizeof(oem_area_0)), + 0); + + TEST_EQ(strcmp(bdb_get_subkey(h)->description, p.subkey->description), + 0); + TEST_EQ(bdb_get_subkey(h)->key_version, p.subkey->key_version); + + TEST_EQ(strcmp(bdb_get_header_sig(h)->description, + p.header_sig_description), 0); + + TEST_EQ(strcmp(bdb_get_data(h)->description, p.data_description), 0); + TEST_EQ(bdb_get_data(h)->data_version, p.data_version); + TEST_EQ(bdb_get_data(h)->num_hashes, p.num_hashes); + + TEST_EQ(bdb_get_data(h)->oem_area_1_size, p.oem_area_1_size); + TEST_EQ(memcmp(bdb_get_oem_area_1(h), oem_area_1, sizeof(oem_area_1)), + 0); + + TEST_EQ(strcmp(bdb_get_data_sig(h)->description, + p.data_sig_description), 0); + + /* Test getting hash entries */ + memcpy(h, hgood, hsize); + TEST_EQ(bdb_get_hash(h, BDB_DATA_SP_RW)->offset, hash[0].offset); + TEST_EQ(bdb_get_hash(h, BDB_DATA_AP_RW)->offset, hash[1].offset); + /* And a non-existent one */ + TEST_EQ(bdb_get_hash(h, BDB_DATA_MCU)!=NULL, 0); + + /* + * TODO: Verify wraparound checks works. That can only be tested on a + * platform where size_t is uint32_t, because otherwise a 32-bit + * oem_area_1_size can't cause wraparound. + */ + + /* Free keys and buffers */ + free(p.bdbkey); + free(p.subkey); + RSA_free(p.private_bdbkey); + RSA_free(p.private_subkey); + free(hgood); + free(h); +} + +/*****************************************************************************/ + +int main(void) +{ + printf("Running tests...\n"); + + check_header_tests(); + check_key_tests(); + check_sig_tests(); + check_data_tests(); + check_bdb_verify(); + + printf("All tests passed!\n"); + + return 0; +} diff --git a/tests/testkeys/bdbkey.crt b/tests/testkeys/bdbkey.crt new file mode 100644 index 00000000..383216a3 --- /dev/null +++ b/tests/testkeys/bdbkey.crt @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFtTCCA52gAwIBAgIJANitnQKymb5VMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTAwOTI5MTgxNjM4WhcNMTAxMDI5MTgxNjM4WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAm5v71oqFynujT4FVq5lKaYxpmKfXdeBNKDmLzgu7fXLUKaEqTGEDsseE +5qyaaP+dmTnQKfne7G31zgf46//YEl+u5Gt/S4oAgYyvs3rjymzD5kVOLEAzgrIX +AwyhDFARRzAFWos43hypunHGvu4fDBAzZ3zGVulhjgAzD/gNjToVYCP7bj6kTaDx +1u9siCKdYN09vGwSUt9WuV+yort7kns/B8ArVxt3bFSjsAxuWel/dJyLwCMQ9XAx +dgWpg3RBUsK/KgekQybPLrhLYJn1AeOApwzJ4HoJSqU/1jCEaGrKA/KtCRXiurZz +6lBi7sElsigjBvEZH0iCmmRgH3Oi/cbpHIs1C6YHvCCbO90ntwgtDf0+2WJtFtbG +t5Do3CXri0tcsXBWqISSK3VzzjHH691BVwLuoBvF1XICMEjmq9aJ+MdbEe4E+GU8 +TV9NnRnuYyOUoxeisyXiArUUI9+1qL6pIgulTlY2Ch51QZY5n2aYY97PtosNotbS +ylMrLvWXGiiQWxux12eOnB3c/3wNYWey8Km4cmOhEOYz7hLz2r1uIoC/SzM5wLnn +TEQmaiUDNV9R3Gj3E3xkpTq3UNSSPsV7k8lInMtWqzps6aTvBw1k6i6CUvWbEZqm +t/0bimQHOEdg3OrJjQpwTKSp4ouSyVu0IphDwy1yjKCfNWKRzrUCAwEAAaOBpzCB +pDAdBgNVHQ4EFgQUyBKBgFg+vONV1sbup7QtFa7DR78wdQYDVR0jBG4wbIAUyBKB +gFg+vONV1sbup7QtFa7DR7+hSaRHMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpT +b21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGSCCQDY +rZ0Cspm+VTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQA0wtlLEAKR +ctB41x/V10SMFIg5eLbDrUKQQT33BddrhFu0blc7U5jgXjqTYS80xIlOC0hXtN7D +Z478st3NAxjtvBKxNMWB9Ppz6+15UENnXNGLElhRPaeAbxBs7zVB64b8fY69EJRe +JOJNp6+c4WJsHWzxrmfHD0Wx18pJ877ThRi/ZH0QP2TjPc0gZT4szP1taoOJ7SXy +gO10WfPoF1GgI/VXhPLnk2zXpTlFdp+qyKOtDFxOOK/cVKdXAxDDDO9DAw6cvrEn +mPS2Zml9HI25/CrE00y+k4w7bqzNeGNzhSGPBvq5Yqnefc1dJSdDQZ3XLG9Fis4a +nVfuSTvP1MUrFEGEvuxRcA0rWPwQtYSHHs8ZnpT6eayTPcpDvWSihe4xUywirXTT +kbWgeABGQGaoAnFJYhjqBROGdVb4V3vbsjbCi8k2r4IIcqOzp6OIJxha2LvkZ+iu +f+OlMVAO/C1LbRsVQkfJp7NxEt6PVewQV5Kgnwlf+x7Q2tUfZfdpLd/EMtojv3BD +Ewx5X2yHGXcYZG/C1kNzyGTfg97/+55mtNlkTmo8elcPxlpnEuMXEv4JthnRy90x +ZLflcR9q0pOiV+n//KyQvfjH99JmRtVJGG8xlDEtRbJWjFQD/uSEBxeS0T6INrza +0WTaiIOZB1vMPe6CDYDWDzrFdQrD6HoWDQ== +-----END CERTIFICATE----- diff --git a/tests/testkeys/bdbkey.keyb b/tests/testkeys/bdbkey.keyb new file mode 100644 index 00000000..515aaa98 Binary files /dev/null and b/tests/testkeys/bdbkey.keyb differ diff --git a/tests/testkeys/bdbkey.pem b/tests/testkeys/bdbkey.pem new file mode 100644 index 00000000..204b440f --- /dev/null +++ b/tests/testkeys/bdbkey.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +Cbo6jQKCAQBtvmt4e1kz8Ehy92n9NVQ+cyy0HklXEkiiu9BSmA4LRPefuBqNKaN0 +ROaJ+z+GoO4br+ZTL4kwb8FU9Py8CfUib+TGOjPuYhFpVONcTfVuF2yeUTf6cYsZ +sco1Fi8WbPV9ZX8zXvoFjVCnGYP31SbVa6dwJCmTK4JbwMZRUEQlXOd74Dk5A9cC +qWPg0fyRajrhc9dOgzWj17tTIDlKm0fZ2phkLd5inayK2CIXvKZUy6PTu7medJFQ +4v7cqNJPFJ/xdkLR3psqDsXTUlBSNnrr24a5QuVA0QV4j2DZZC6+Acgneqz+0Uu6 +t66vMuSdH620bV2n84wh1xXc7qkjDYMTAoIBAQC6DsTyBGNNI0/DGwAsae5Zri8w +T/SOER7Tc/PCgQyFUNsJJc/OmSy66PPiH2HzqLjl6/jeiJP++oCnfO6pNTq1Fjz4 +Le2iS1szlcuJ9QLdtn2LTqORzdQVpka42X+o+NqJEdzkZb/N6eBA4PPQdTxHIiu1 +WGBpDc5vGkpuzLm9SVCw/4SD84z+Nhs0pqOvwWhmQWCtl28fgqU4LMeOX1Wz5P8E +IledlgbCZh2KwXuv3BJdkawuwrSPsahnZmoJapx2dE+FkNl4equaBwImfLf5Qifj +IhIN5GueO9k/D2/7/XvW2qJ3Vy0z0xMMNiTVYufVpbh77Kn2ebKfROlkzMEU +-----END RSA PRIVATE KEY----- diff --git a/tests/testkeys/subkey.crt b/tests/testkeys/subkey.crt new file mode 100644 index 00000000..fad23f48 --- /dev/null +++ b/tests/testkeys/subkey.crt @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEWzCCAsOgAwIBAgIJAKOPQrNCNRSqMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTUxMTIzMjA1MTI4WhcNMTUxMjIzMjA1MTI4WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBoDANBgkqhkiG9w0BAQEFAAOCAY0AMIIB +iAKCAYEA1/JAfpirBAFZdm+m6AcX5QQt7vWDV6OAN4T5nWxAtedRb0XLeV9ICJJI +4CwxWKhvM4pe8pUwwldjoIHIs7viDjBnFVO6+41Gwdsp54AO9qpd//izjarwrOFq +QcZIn7KVOaYxTlMWlfIDOS3K0rr2adBuR/Yq4Nj61XevNsxRelojDLAQeamRia8t +hB3vR1LHQJlMT7R8VXy3AOHx+YcYKUFCgf5A7J+pdAaOIgkFKuakZZNDC+7D0Ykq +jPHadHKzT1SCJxILD/YkCUCOn5bdh7oQekCnhJgf3bwPRDaGEsJL3nnxhc8hx3tI +7DHwKmz9naz63S41Zqd+VvWam7Jttyb6lQjj7Y8TauXGAL3vEiI/u0iiVyw6b3c3 +77/W4RWuRIiMAn6FAkUY6oxKB+67ZA1PoRLfiIxFGot1KEpTeLzdsyYx7fB1Scj+ +DDzx3EaHQAz12E4anTozljvdAPMoZ6i9Dar3eZvA0KFsM5sdNy0Hp96PBeBNiw1O +XZYUrYgVAgEDo1AwTjAdBgNVHQ4EFgQUiwtVmJWqyIBZWV1xvn7iMbLeE30wHwYD +VR0jBBgwFoAUiwtVmJWqyIBZWV1xvn7iMbLeE30wDAYDVR0TBAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAYEAJXgsYoQ7QDNf1GF0bQQKnSqIKMssecD8x66rrJQr1Yon +biJeUfN9N/pAca7CI/vjeTC1w6BlXEbUDNNwLKQYVfTOBdmbW1qDANMUP05PaiAG +cZHVKMZZrR/5+z+LWG157cP7HzHPGfw78LopVXUDZmd5fRD2d7MnqYCrswp/dORM +brHTwzpPhH75uNQmq6w2RowjrntDnKhGT0tSY57/OI+Gke3ch3XPPg3juhREaVUm +4ZXSCwajKmPBju+7adT46gY/LjAYv/rAEiUN5YHOBVHxHdoMOIqsf6VfPVc8USpg +5fsV7NWGNSuvpiA7xBIBKai3dZl8nztFHvjn7z4x6XrqQ1KTMBvnGONHAHopeUtj +a3WPd3GpBmLMpSfDWtcaSSuwOAgZro6vGqcHN4FybKASbtS0RynPRL42DBbLiarn +nA0hhR1YR03Kqc6hexrsg7zrjcNL6b8dzu6o+VxD30ecj68D7IliORtouJahvk5/ +F8MyzvHvAa+K7Hb/IcJv +-----END CERTIFICATE----- diff --git a/tests/testkeys/subkey.keyb b/tests/testkeys/subkey.keyb new file mode 100644 index 00000000..33ed4ace Binary files /dev/null and b/tests/testkeys/subkey.keyb differ diff --git a/tests/testkeys/subkey.pem b/tests/testkeys/subkey.pem new file mode 100644 index 00000000..2a8885e0 --- /dev/null +++ b/tests/testkeys/subkey.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- -- cgit v1.2.1