Add BDB library

This is a standalone library for verifying the BDB structures in the
common boot flow document, and a bdb_create utility to create test BDB
structures.  Eventually, creating these structures will be rolled into
futility.

BUG=chrome-os-partner:48448
BRANCH=none
TEST=cd bdb && make runtests

Change-Id: Ic57c26ca84137205da3b6c7d532f5324c93b4285
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/317275
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
This commit is contained in:
Randall Spangler
2015-12-10 15:03:22 -08:00
committed by chrome-bot
parent 758360b12a
commit b37e6672eb
24 changed files with 3195 additions and 0 deletions

27
bdb/LICENSE Normal file
View File

@@ -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.

130
bdb/Makefile Normal file
View File

@@ -0,0 +1,130 @@
# 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.
# This Makefile normally builds in a 'build' subdir, but use
#
# make BUILD=<dir>
#
# to put the output somewhere else.
##############################################################################
# Configuration variables come first.
# Verbose? Use V=1
ifeq (${V},)
Q := @
endif
# Quiet? Use QUIET=1
ifeq (${QUIET},)
PRINTF := printf
else
PRINTF := :
endif
CC ?= gcc
LD = ${CC}
PKG_CONFIG ?= pkg-config
SRCDIR := $(shell pwd)
export SRCDIR
BUILD = ${SRCDIR}/build
export BUILD
KEYDIR = ${SRCDIR}/testkeys
CFLAGS = -Wall -Werror
# Create / use dependency files
CFLAGS += -MMD -MF $@.d
##############################################################################
# Create output directories if necessary. Do this via explicit shell commands
# so it happens before trying to generate/include dependencies.
_dir_create := $(shell [ -d ${BUILD} ] || mkdir -p ${BUILD}))
_keydir_create := $(shell [ -d ${KEYDIR} ] || mkdir -p ${KEYDIR}))
INC_PATH := $(shell ${PKG_CONFIG} --cflags libcrypto)
CFLAGS += ${INC_PATH}
CRYPTO_LIBS := $(shell ${PKG_CONFIG} --libs libcrypto)
LDLIBS += ${CRYPTO_LIBS}
##############################################################################
# Sources
LIBSRC = bdb.c host.c sha.c rsa.c
LIBOBJ = ${LIBSRC:%.c=${BUILD}/%.o}
BDBTESTSRC = bdb_test.c
BDBTESTOBJ = ${BDBTESTSRC:%.c=${BUILD}/%.o}
BDBTEST = ${BUILD}/bdb_test
BDBCREATESRC = bdb_create.c
BDBCREATEOBJ = ${BDBCREATESRC:%.c=${BUILD}/%.o}
BDBCREATE = ${BUILD}/bdb_create
DUMPRSASRC = dump_rsa.c
DUMPRSAOBJ = ${DUMPRSASRC:%.c=${BUILD}/%.o}
DUMPRSA = ${BUILD}/dump_rsa
ALL_OBJS = ${LIBOBJ} ${BDBTESTOBJ} ${BDBCREATEOBJ}
ALL_EXES = ${BDBTEST} ${BDBCREATE} ${DUMPRSA}
##############################################################################
# Targets
.PHONY: all
all: ${ALL_EXES}
.PHONY: clean
clean:
${Q}/bin/rm -rf ${BUILD}
.PHONY: bdb
bdb: ${BDBCREATE}
${Q}${BDBCREATE}
.PHONY: runtests
runtests: ${BDBTEST}
${Q}${BDBTEST}
.PHONY: testkeys
testkeys: ${DUMPRSA}
${Q}openssl genrsa -F4 -out ${KEYDIR}/bdbkey.pem 4096
${Q}openssl req -batch -new -x509 -key ${KEYDIR}/bdbkey.pem \
-out ${KEYDIR}/bdbkey.crt
${Q}${DUMPRSA} -cert ${KEYDIR}/bdbkey.crt > ${KEYDIR}/bdbkey.keyb
${Q}openssl genrsa -3 -out ${KEYDIR}/subkey.pem 3072
${Q}openssl req -batch -new -x509 -key ${KEYDIR}/subkey.pem \
-out ${KEYDIR}/subkey.crt
${Q}${DUMPRSA} -cert ${KEYDIR}/subkey.crt > ${KEYDIR}/subkey.keyb
${BDBTEST}: ${BDBTESTOBJ} ${LIBOBJ}
@$(PRINTF) " LD $(subst ${BUILD}/,,$@)\n"
${Q}${LD} -o ${BDBTEST} ${CFLAGS} $^ ${LIBS} ${LDLIBS}
${BDBCREATE}: ${BDBCREATEOBJ} ${LIBOBJ}
@$(PRINTF) " LD $(subst ${BUILD}/,,$@)\n"
${Q}${LD} -o ${BDBCREATE} ${CFLAGS} $^ ${LIBS} ${LDLIBS}
${DUMPRSA}: ${DUMPRSAOBJ} ${LIBOBJ}
@$(PRINTF) " LD $(subst ${BUILD}/,,$@)\n"
${Q}${LD} -o ${DUMPRSA} ${CFLAGS} $^ ${LIBS} ${LDLIBS}
##############################################################################
# Generic build rules. LIBS and OBJS can be overridden to tweak the generic
# rules for specific targets.
${BUILD}/%: ${BUILD}/%.o ${OBJS} ${LIBS}
@${PRINTF} " LD $(subst ${BUILD}/,,$@)\n"
${Q}${LD} -o $@ ${CFLAGS} ${LDFLAGS} $< ${OBJS} ${LIBS} ${LDLIBS}
${BUILD}/%.o: %.c
@${PRINTF} " CC $(subst ${BUILD}/,,$@)\n"
${Q}${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $<
# Include generated dependencies
ALL_DEPS += ${ALL_OBJS:%.o=%.o.d}
-include ${ALL_DEPS}

30
bdb/README Normal file
View File

@@ -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.

398
bdb/bdb.c Normal file
View File

@@ -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 <string.h>
#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;
}

181
bdb/bdb.h Normal file
View File

@@ -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 <stdlib.h>
#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_ */

232
bdb/bdb_create.c Normal file
View File

@@ -0,0 +1,232 @@
/* 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.
*
* Create a BDB
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bdb.h"
#include "host.h"
/* Parameters for creating a BDB hash entry */
struct create_hash {
/* File containing data */
const char *filename;
/* Type of data; enum bdb_data_type */
uint8_t type;
/* Address in RAM to load data. -1 means use default. */
uint64_t load_address;
/* Partition number containing data, or -1 to use the same partition as
* the BDB. */
uint8_t partition;
/*
* Offset of data from start of partition.
*
* TODO: if -1, append after BDB. But need to know how big the BDB
* is, and need to round up offset to 32-bit boundary.
*/
uint64_t offset;
};
/* Parameters for a key */
struct create_key {
/* Description */
const char *description;
/* Key version (not meaningful for BDB key) */
uint32_t key_version;
/* Public key filename (.keyb) */
const char *public_filename;
/* Private key filename (.pem) */
const char *private_filename;
};
struct create_params_2 {
/* Destination filename */
const char *filename;
/* Partition to contain the BDB */
uint8_t partition;
/* OEM area files. NULL means there is no data for that area. */
const char *oem_area_0_filename;
const char *oem_area_1_filename;
/* BDB key and subkey */
struct create_key bdbkey;
struct create_key subkey;
};
/*****************************************************************************/
/* FILL THIS IN WITH YOUR SOURCE DATA */
/*
* Creation parameters. Hash and num_hashes will be filled in automatically
* by create().
*/
struct bdb_create_params p = {
.bdb_load_address = 0x11223344,
.header_sig_description = "The header sig",
.data_sig_description = "The data sig",
.data_description = "Test BDB data",
.data_version = 3,
};
/* Additional parameters */
struct create_params_2 p2 = {
.filename = "build/bdb.bin",
.partition = 1,
.oem_area_0_filename = "testdata/oem0.bin",
.oem_area_1_filename = "testdata/oem1.bin",
.bdbkey = {
.description = "Test BDB key",
.key_version = 3,
.public_filename = "testkeys/bdbkey.keyb",
.private_filename = "testkeys/bdbkey.pem",
},
.subkey = {
.description = "Test Subkey",
.key_version = 4,
.public_filename = "testkeys/subkey.keyb",
.private_filename = "testkeys/subkey.pem",
},
};
/* List of hash entries, terminated by one with a NULL filename */
struct create_hash hash_entries[] = {
{
.filename = "testdata/sp-rw.bin",
.type = BDB_DATA_SP_RW,
.load_address = -1,
.partition = -1,
.offset = 0x10000,
},
{
.filename = "testdata/ap-rw.bin",
.type = BDB_DATA_AP_RW,
.load_address = 0x200000,
.partition = -1,
.offset = 0x28000,
},
{
.filename = NULL
},
};
/*****************************************************************************/
int create(void)
{
struct bdb_hash *hash;
struct bdb_header *h;
int i;
/* Count the number of hash entries */
for (p.num_hashes = 0; hash_entries[p.num_hashes].filename;
p.num_hashes++)
;
printf("Found %d hash entries\n", p.num_hashes);
/* Calculate hashes */
p.hash = hash = calloc(sizeof(struct bdb_hash), p.num_hashes);
for (i = 0; i < p.num_hashes; i++, hash++) {
const struct create_hash *he = hash_entries + i;
/* Read file and calculate size and hash */
uint8_t *buf = read_file(he->filename, &hash->size);
if (!buf)
return 1;
if (bdb_sha256(hash->digest, buf, hash->size)) {
fprintf(stderr, "Unable to calculate hash\n");
return 1;
}
free(buf);
hash->type = he->type;
hash->load_address = he->load_address;
hash->partition = he->partition == -1 ? p2.partition :
he->partition;
hash->offset = he->offset;
}
/* Read OEM data */
if (p2.oem_area_0_filename) {
p.oem_area_0 = read_file(p2.oem_area_0_filename,
&p.oem_area_0_size);
if (!p.oem_area_0)
return 1;
if (p.oem_area_0_size & 3) {
fprintf(stderr,
"OEM area 0 size isn't 32-bit aligned\n");
return 1;
}
}
if (p2.oem_area_1_filename) {
p.oem_area_1 = read_file(p2.oem_area_1_filename,
&p.oem_area_1_size);
if (!p.oem_area_1)
return 1;
if (p.oem_area_1_size & 3) {
fprintf(stderr,
"OEM area 1 size isn't 32-bit aligned\n");
return 1;
}
}
/* Load keys */
p.bdbkey = bdb_create_key(p2.bdbkey.public_filename,
p2.bdbkey.key_version,
p2.bdbkey.description);
p.subkey = bdb_create_key(p2.subkey.public_filename,
p2.subkey.key_version,
p2.subkey.description);
p.private_bdbkey = read_pem(p2.bdbkey.private_filename);
p.private_subkey = read_pem(p2.subkey.private_filename);
if (!p.bdbkey || !p.subkey || !p.private_bdbkey || !p.private_subkey) {
fprintf(stderr, "Unable to load keys\n");
return 1;
}
/* Create the BDB */
h = bdb_create(&p);
if (!h) {
fprintf(stderr, "Unable to create BDB\n");
return 1;
}
/* Write it */
if (write_file(p2.filename, h, h->bdb_size))
return 1;
/* Free keys and buffers */
free(p.bdbkey);
free(p.subkey);
RSA_free(p.private_bdbkey);
RSA_free(p.private_subkey);
free(h);
free(p.hash);
return 0;
}
/*****************************************************************************/
int main(void)
{
return create();
}

268
bdb/bdb_struct.h Normal file
View File

@@ -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 <stdint.h>
/* 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_ */

492
bdb/bdb_test.c Normal file
View File

@@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

200
bdb/dump_rsa.c Normal file
View File

@@ -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 <openssl/pem.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
/*
* 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> <file>\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;
}

17
bdb/ecdsa.c Normal file
View File

@@ -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 <string.h>
#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;
}

347
bdb/host.c Normal file
View File

@@ -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 <stdio.h>
#include <string.h>
#include <unistd.h>
#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;
}

171
bdb/host.h Normal file
View File

@@ -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 <stdlib.h>
#include <openssl/pem.h>
#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_ */

339
bdb/rsa.c Normal file
View File

@@ -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 <string.h>
#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;
}

210
bdb/sha.c Normal file
View File

@@ -0,0 +1,210 @@
/* SHA-256 and SHA-512 implementation based on code by Oliver Gay
* <olivier.gay@a3.epfl.ch> 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 <olivier.gay@a3.epfl.ch>
* 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 <string.h>
#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;
}

1
bdb/testdata/ap-rw.bin vendored Normal file
View File

@@ -0,0 +1 @@
This is a pretend ap-rw.bin image. Exciting.

1
bdb/testdata/oem0.bin vendored Normal file
View File

@@ -0,0 +1 @@
This is some OEM0 data.

1
bdb/testdata/oem1.bin vendored Normal file
View File

@@ -0,0 +1 @@
This is some OEM1 data of some sort

1
bdb/testdata/sp-rw.bin vendored Normal file
View File

@@ -0,0 +1 @@
This is a pretend sp-rw.bin image.

33
bdb/testkeys/bdbkey.crt Normal file
View File

@@ -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-----

BIN
bdb/testkeys/bdbkey.keyb Normal file

Binary file not shown.

51
bdb/testkeys/bdbkey.pem Normal file
View File

@@ -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-----

26
bdb/testkeys/subkey.crt Normal file
View File

@@ -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-----

BIN
bdb/testkeys/subkey.keyb Normal file

Binary file not shown.

39
bdb/testkeys/subkey.pem Normal file
View File

@@ -0,0 +1,39 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----