vboot: remove Boot Descriptor Block (BDB) library and utilities

Remove unused BDB code, previously created for a cancelled SoC
project.

BUG=b:124141368, chromium:986177
TEST=make clean && make runtests
BRANCH=none

Change-Id: I91faf97d9850f8afb816fa324ad9a4d9f3842888
Signed-off-by: Joel Kitching <kitching@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/1710336
Tested-by: Joel Kitching <kitching@chromium.org>
Reviewed-by: Joel Kitching <kitching@chromium.org>
Commit-Queue: Joel Kitching <kitching@chromium.org>
This commit is contained in:
Joel Kitching 2019-07-22 10:23:06 +08:00 committed by Commit Bot
parent 38f135e83e
commit 34abb32ed2
62 changed files with 7 additions and 9222 deletions

View File

@ -325,9 +325,6 @@ FWLIB20 = ${BUILD}/vboot_fw20.a
# Vboot 2.1 (not yet ready - see firmware/README)
FWLIB21 = ${BUILD}/vboot_fw21.a
# Static library containing firmware APIs for common boot flow
BDBLIB = ${BUILD}/bdb.a
# Firmware library sources needed by VbInit() call
VBINIT_SRCS = \
firmware/lib/vboot_common_init.c \
@ -386,16 +383,6 @@ FWLIB21_SRCS = \
firmware/lib21/misc.c \
firmware/lib21/packed_key.c
BDBLIB_SRCS = \
firmware/bdb/bdb.c \
firmware/bdb/ecdsa.c \
firmware/bdb/misc.c \
firmware/bdb/rsa.c \
firmware/bdb/secrets.c \
firmware/bdb/sha.c \
firmware/bdb/stub.c \
firmware/bdb/nvm.c
# TPM lightweight command library
ifeq (${TPM2_MODE},)
TLCL_SRCS = \
@ -453,16 +440,11 @@ FWLIB_OBJS = ${FWLIB_SRCS:%.c=${BUILD}/%.o}
FWLIB2X_OBJS = ${FWLIB2X_SRCS:%.c=${BUILD}/%.o}
FWLIB20_OBJS = ${FWLIB20_SRCS:%.c=${BUILD}/%.o}
FWLIB21_OBJS = ${FWLIB21_SRCS:%.c=${BUILD}/%.o}
BDBLIB_OBJS = ${BDBLIB_SRCS:%.c=${BUILD}/%.o}
ALL_OBJS += ${FWLIB_OBJS} ${FWLIB2X_OBJS} ${FWLIB20_OBJS} ${FWLIB21_OBJS} \
$(BDBLIB_OBJS}
ALL_OBJS += ${FWLIB_OBJS} ${FWLIB2X_OBJS} ${FWLIB20_OBJS} ${FWLIB21_OBJS}
# Intermediate library for the vboot_reference utilities to link against.
UTILLIB = ${BUILD}/libvboot_util.a
# Static library containing both host and firmware APIs
UTILBDB = ${BUILD}/libvboot_utilbdb.a
UTILLIB_SRCS = \
cgpt/cgpt_create.c \
cgpt/cgpt_add.c \
@ -495,13 +477,6 @@ UTILLIB_SRCS = \
UTILLIB_OBJS = ${UTILLIB_SRCS:%.c=${BUILD}/%.o}
ALL_OBJS += ${UTILLIB_OBJS}
# Source files containing host side APIs for common boot flow
UTILBDB_SRCS += \
firmware/bdb/host.c
UTILBDB_OBJS = ${UTILBDB_SRCS:%.c=${BUILD}/%.o}
ALL_OBJS += ${UTILBDB_OBJS}
# Externally exported library for some target userspace apps to link with
# (cryptohome, updater, etc.)
HOSTLIB = ${BUILD}/libvboot_host.a
@ -614,7 +589,6 @@ endif
ifeq (${MINIMAL},)
UTIL_NAMES += \
utility/bdb_extend \
utility/load_kernel_test \
utility/pad_digest_utility \
utility/signature_digest_utility \
@ -663,8 +637,6 @@ FUTIL_SYMLINKS = \
FUTIL_SRCS = \
futility/futility.c \
futility/bdb_helper.c \
futility/cmd_bdb.c \
futility/cmd_create.c \
futility/cmd_dump_fmap.c \
futility/cmd_dump_kernel_config.c \
@ -698,8 +670,7 @@ FUTIL_CMD_LIST = ${BUILD}/gen/futility_cmds.c
FUTIL_OBJS = ${FUTIL_SRCS:%.c=${BUILD}/%.o} ${FUTIL_CMD_LIST:%.c=%.o}
${FUTIL_OBJS}: INCLUDES += -Ihost/lib21/include -Ifirmware/lib21/include \
-Ifirmware/bdb
${FUTIL_OBJS}: INCLUDES += -Ihost/lib21/include -Ifirmware/lib21/include
ALL_OBJS += ${FUTIL_OBJS}
@ -784,12 +755,7 @@ TEST21_NAMES = \
tests/vb21_host_misc_tests \
tests/vb21_host_sig_tests
TESTBDB_NAMES = \
tests/bdb_test \
tests/bdb_nvm_test \
tests/bdb_sprw_test
TEST_NAMES += ${TEST2X_NAMES} ${TEST20_NAMES} ${TEST21_NAMES} ${TESTBDB_NAMES}
TEST_NAMES += ${TEST2X_NAMES} ${TEST20_NAMES} ${TEST21_NAMES}
# And a few more...
ifeq (${TPM2_MODE},)
@ -820,7 +786,6 @@ TEST_FUTIL_BINS = $(addprefix ${BUILD}/,${TEST_FUTIL_NAMES})
TEST2X_BINS = $(addprefix ${BUILD}/,${TEST2X_NAMES})
TEST20_BINS = $(addprefix ${BUILD}/,${TEST20_NAMES})
TEST21_BINS = $(addprefix ${BUILD}/,${TEST21_NAMES})
TESTBDB_BINS = $(addprefix ${BUILD}/,${TESTBDB_NAMES})
# Directory containing test keys
TEST_KEYS = ${SRC_RUN}/tests/testkeys
@ -893,7 +858,6 @@ ${FWLIB_OBJS}: CFLAGS += -DUNROLL_LOOPS
${FWLIB2X_OBJS}: CFLAGS += -DUNROLL_LOOPS
${FWLIB20_OBJS}: CFLAGS += -DUNROLL_LOOPS
${FWLIB21_OBJS}: CFLAGS += -DUNROLL_LOOPS
${BDBLIB_OBJS}: CFLAGS += -DUNROLL_LOOPS
# Workaround for coreboot on x86, which will power off asynchronously
# without giving us a chance to react. This is not an example of the Right
@ -914,7 +878,6 @@ ${FWLIB_OBJS}: CFLAGS += -DDISABLE_ROLLBACK_TPM
endif
${FWLIB21_OBJS}: INCLUDES += -Ifirmware/lib21/include
${BDBLIB_OBJS}: INCLUDES += -Ifirmware/bdb
# Linktest ensures firmware lib doesn't rely on outside libraries
${BUILD}/firmware/linktest/main: ${FWLIB}
@ -960,15 +923,6 @@ ${FWLIB21}: ${FWLIB2X_OBJS} ${FWLIB21_OBJS}
@${PRINTF} " AR $(subst ${BUILD}/,,$@)\n"
${Q}ar qc $@ $^
.PHONY: bdblib
bdblib: ${BDBLIB}
${BDBLIB}: ${FWLIB2X_OBJS} ${BDBLIB_OBJS}
@${PRINTF} " RM $(subst ${BUILD}/,,$@)\n"
${Q}rm -f $@
@${PRINTF} " AR $(subst ${BUILD}/,,$@)\n"
${Q}ar qc $@ $^
# ----------------------------------------------------------------------------
# Host library(s)
@ -989,12 +943,6 @@ ${UTILLIB}: ${UTILLIB_OBJS} ${FWLIB_OBJS} ${FWLIB2X_OBJS} ${FWLIB20_OBJS} \
@${PRINTF} " AR $(subst ${BUILD}/,,$@)\n"
${Q}ar qc $@ $^
${UTILBDB}: ${UTILBDB_OBJS} ${BDBLIB_OBJS}
@${PRINTF} " RM $(subst ${BUILD}/,,$@)\n"
${Q}rm -f $@
@${PRINTF} " AR $(subst ${BUILD}/,,$@)\n"
${Q}ar qc $@ $^
# Link tests for external repos
${BUILD}/host/linktest/extern: ${HOSTLIB}
${BUILD}/host/linktest/extern: LIBS = ${HOSTLIB}
@ -1113,7 +1061,7 @@ futil: ${FUTIL_BIN}
FUTIL_LIBS = ${CRYPTO_LIBS} ${LIBZIP_LIBS}
${FUTIL_BIN}: LDLIBS += ${FUTIL_LIBS}
${FUTIL_BIN}: ${FUTIL_OBJS} ${UTILLIB} ${FWLIB20} ${UTILBDB}
${FUTIL_BIN}: ${FUTIL_OBJS} ${UTILLIB} ${FWLIB20}
@${PRINTF} " LD $(subst ${BUILD}/,,$@)\n"
${Q}${LD} -o $@ ${CFLAGS} ${LDFLAGS} $^ ${LDLIBS}
@ -1152,9 +1100,9 @@ ${TEST_BINS}: INCLUDES += -Itests
${TEST_BINS}: LIBS = ${TESTLIB} ${UTILLIB}
# Futility tests need almost everything that futility needs.
${TEST_FUTIL_BINS}: ${FUTIL_OBJS} ${UTILLIB} ${UTILBDB}
${TEST_FUTIL_BINS}: ${FUTIL_OBJS} ${UTILLIB}
${TEST_FUTIL_BINS}: INCLUDES += -Ifutility
${TEST_FUTIL_BINS}: OBJS += ${FUTIL_OBJS} ${UTILLIB} ${UTILBDB}
${TEST_FUTIL_BINS}: OBJS += ${FUTIL_OBJS} ${UTILLIB}
${TEST_FUTIL_BINS}: LDLIBS += ${FUTIL_LIBS}
${TEST2X_BINS}: ${FWLIB2X}
@ -1164,10 +1112,6 @@ ${TEST20_BINS}: ${FWLIB20}
${TEST20_BINS}: LIBS += ${FWLIB20}
${TEST20_BINS}: LDLIBS += ${CRYPTO_LIBS}
${TESTBDB_BINS}: ${FWLIB2X} ${UTILBDB}
${TESTBDB_BINS}: INCLUDES += -Ifirmware/bdb
${TESTBDB_BINS}: LIBS += ${UTILBDB} ${FWLIB2X}
${TESTLIB}: ${TESTLIB_OBJS}
@${PRINTF} " RM $(subst ${BUILD}/,,$@)\n"
${Q}rm -f $@
@ -1234,18 +1178,10 @@ ${BUILD}/utility/pad_digest_utility: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/signature_digest_utility: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/verify_data: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/bdb_extend: ${FWLIB2X} ${UTILBDB}
${BUILD}/utility/bdb_extend.o: INCLUDES += -Ifirmware/bdb
${BUILD}/utility/bdb_extend: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/bdb_extend: LIBS += ${UTILBDB} ${FWLIB2X}
${BUILD}/host/linktest/main: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/vb20_common2_tests: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/vb20_common3_tests: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/verify_kernel: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/bdb_test: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/bdb_nvm_test: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/bdb_sprw_test: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/hmac_test: LDLIBS += ${CRYPTO_LIBS}
${TEST21_BINS}: LDLIBS += ${CRYPTO_LIBS}
@ -1302,7 +1238,7 @@ ${FUTIL_CMD_LIST}: ${FUTIL_SRCS}
# Frequently-run tests
.PHONY: test_targets
test_targets:: runcgpttests runmisctests run2tests runbdbtests
test_targets:: runcgpttests runmisctests run2tests
ifeq (${MINIMAL},)
# Bitmap utility isn't compiled for minimal variant
@ -1414,11 +1350,6 @@ run2tests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/vb21_host_sig_tests ${TEST_KEYS}
${RUNTEST} ${BUILD_RUN}/tests/hmac_test
.PHONY: runbdbtests
runbdbtests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/bdb_test ${TEST_KEYS}
${RUNTEST} ${BUILD_RUN}/tests/bdb_sprw_test ${TEST_KEYS}
.PHONY: runfutiltests
runfutiltests: test_setup
tests/futility/run_test_scripts.sh ${TEST_INSTALL_DIR}/bin

View File

@ -1,27 +0,0 @@
// 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.

View File

@ -1,130 +0,0 @@
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# 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}

View File

@ -1,30 +0,0 @@
Boot Descriptor Block (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
View File

@ -1,398 +0,0 @@
/* 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
View File

@ -1,181 +0,0 @@
/* 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_ */

View File

@ -1,232 +0,0 @@
/* 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();
}

View File

@ -1,268 +0,0 @@
/* 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_ */

View File

@ -1,492 +0,0 @@
/* 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;
}

View File

@ -1,200 +0,0 @@
/* 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;
}

View File

@ -1,17 +0,0 @@
/* 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;
}

View File

@ -1,347 +0,0 @@
/* 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;
}

View File

@ -1,171 +0,0 @@
/* 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
View File

@ -1,339 +0,0 @@
/* 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
View File

@ -1,210 +0,0 @@
/* 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;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,33 +0,0 @@
-----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-----

Binary file not shown.

View File

@ -1,51 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAm5v71oqFynujT4FVq5lKaYxpmKfXdeBNKDmLzgu7fXLUKaEq
TGEDsseE5qyaaP+dmTnQKfne7G31zgf46//YEl+u5Gt/S4oAgYyvs3rjymzD5kVO
LEAzgrIXAwyhDFARRzAFWos43hypunHGvu4fDBAzZ3zGVulhjgAzD/gNjToVYCP7
bj6kTaDx1u9siCKdYN09vGwSUt9WuV+yort7kns/B8ArVxt3bFSjsAxuWel/dJyL
wCMQ9XAxdgWpg3RBUsK/KgekQybPLrhLYJn1AeOApwzJ4HoJSqU/1jCEaGrKA/Kt
CRXiurZz6lBi7sElsigjBvEZH0iCmmRgH3Oi/cbpHIs1C6YHvCCbO90ntwgtDf0+
2WJtFtbGt5Do3CXri0tcsXBWqISSK3VzzjHH691BVwLuoBvF1XICMEjmq9aJ+Mdb
Ee4E+GU8TV9NnRnuYyOUoxeisyXiArUUI9+1qL6pIgulTlY2Ch51QZY5n2aYY97P
tosNotbSylMrLvWXGiiQWxux12eOnB3c/3wNYWey8Km4cmOhEOYz7hLz2r1uIoC/
SzM5wLnnTEQmaiUDNV9R3Gj3E3xkpTq3UNSSPsV7k8lInMtWqzps6aTvBw1k6i6C
UvWbEZqmt/0bimQHOEdg3OrJjQpwTKSp4ouSyVu0IphDwy1yjKCfNWKRzrUCAwEA
AQKCAgEAlbfvBu0g7UEoUEbQdtp2jjdbIlXbKL83fYxgx07ihkEFgUhfuj1doZX2
eTt5Fa1bpSHK95hCtJjX9/QTvH3dF1CYpY4IXFXbRspmAvoqUYl0swnbvRfId+eB
3J06Fu6ysRuzCvsJLCvH4mu2Hd5eYOz1iIy1CMpj4oyulJ7F6ywHhQkZ0WjUDRzd
kz+p3RHw+lHkJHaW6sWYW6OH7KsWqkmKy5pKGPWEYebN14UeZ8QRrdExZRxYJM5d
yICKKMCiWU6nP3k6wqGElh8b50Y6RibukcvsMN86MWftk9f6jbyxwjqr4iH8lEkY
HkpZ5f5QlqmnifZPhZnujz4kfh50oteC2QPQ0hrNYCDG75wuiNX/vINVfrKG0ddg
iQDFqyQyQirxCGQgy7Wto08KAzKt146ST28N+kdF/kY14ou5f5+GlWQJcnqdHd2p
R25MueXUsY3I63dULR6k02Y6M7Tzo39lYe0LV82+G0A3iGpI+eM7xw/sQDNb2sQs
jCcz7XPrfTomrVJaW1FkM8vM6eWhuhAyDFP+unz0aMnKrkUrarh4t9QpriiCjm3E
HV2Hc7t/Do/w+B3rywKy3PE2yO49eGz20um0JqWcAbGDZY2vDnyV+/xibxqaIZUo
saI/btlyvCv00812momkX/qWwS+1GHvyYYcpIg0XQbZY1TvEi8ECggEBAM6LTfVu
MKNwW/QdZ6pxKl/Oy8zlb1o8HET5hKCdhoMvpwlvpO2qSvlCxH3VZTmcXIXd+Mkd
e4OZrzeMLVxMd64xP10k2ui/O2/8G38xmpMGqZihc+LnY6JgajujfAQHljOgrAJL
xzO2Gk4oWX72oA6jqP8LZkRp/9acTWqBTKs6MOdrfn6I3k0urBB29+jcbqFAfgMx
hfcTKAOHYmg/SeEZDvKP6fRDJGMGXqJ4TaBXjsnhNGCjGmuCqJhxxIGCI/AVK10B
CjEboo9vACzNE1/JMxH8aT5up7e+7R/WoiJ5e3jlvSKmcO7KiR27JVsAlZeIddKd
LzG9KKZ8Yla0U3MCggEBAMDefKVTqSPaG7cmAQGtXrbBDLdCWIaT08v+kMw/drlq
NqLD+1ct098iFwRtKaYPERPKqNtxfJdkUMqWELBWV2Sq4Fi+JVXjGOUctP7Atd2x
6NJ9xHqQKQwKUv0/9jN5Oie9sFvsLwPAJNOJej1BrmvPZvc0CoMyOjkmxEhYu3qG
i26ZTSZSCTrbE8eAL0EJdH0gB7Ryuks8O+jEF7eXuZLZyN3AromISJtmLVlMFZ7m
+0sQnZQqwNF+BIrOgO+3R61jjNzCJbFo7frvRIlDSnrbmWp6sYns1cjhZiKCnO78
RgDiaJcuceqsalgBZi8/Fmam2IPeqhvTNg+5alCuWzcCggEAXFjglFmeGZVFJ9J1
5TkPzyJw8L2smdXCdfxyFjYYTFNkBc4LGdBIEUaPAAwHZEjK/XePoqwx61cthlKA
fYIbCKEwSX8O+X13H8zCpo4RJKeX8IxPeiYm4BTnqp6f9lVGDPNLtQMYn8BN5qAX
07KFQcZe6xm3seMK5nOgEXyaQPyVnQLs3bpoWm4BtKLcmRrlw+dH8DmWQjAoddt0
XlPdvm0rx7wcyH+0pynT6iSL4KMFTrIIbyS9zU/v/ajwSU9crh1o8/5hBi/q8OKa
W22dufgFg4ctryJejsMo1lFq0KssT5O4iuOMHtgjkk14mEWcnNIAjBiHX1/J6xY2
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-----

View File

@ -1,26 +0,0 @@
-----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-----

Binary file not shown.

View File

@ -1,39 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIG4wIBAAKCAYEA1/JAfpirBAFZdm+m6AcX5QQt7vWDV6OAN4T5nWxAtedRb0XL
eV9ICJJI4CwxWKhvM4pe8pUwwldjoIHIs7viDjBnFVO6+41Gwdsp54AO9qpd//iz
jarwrOFqQcZIn7KVOaYxTlMWlfIDOS3K0rr2adBuR/Yq4Nj61XevNsxRelojDLAQ
eamRia8thB3vR1LHQJlMT7R8VXy3AOHx+YcYKUFCgf5A7J+pdAaOIgkFKuakZZND
C+7D0YkqjPHadHKzT1SCJxILD/YkCUCOn5bdh7oQekCnhJgf3bwPRDaGEsJL3nnx
hc8hx3tI7DHwKmz9naz63S41Zqd+VvWam7Jttyb6lQjj7Y8TauXGAL3vEiI/u0ii
Vyw6b3c377/W4RWuRIiMAn6FAkUY6oxKB+67ZA1PoRLfiIxFGot1KEpTeLzdsyYx
7fB1Scj+DDzx3EaHQAz12E4anTozljvdAPMoZ6i9Dar3eZvA0KFsM5sdNy0Hp96P
BeBNiw1OXZYUrYgVAgEDAoIBgQCP9tWpuxytVjukSm9FWg/uAslJ+QI6bQAlA1ET
nYB5ROD02TJQ6jAFtttAHXY7GvTNBun3DiCBj5fAVoXNJ+wJdZoON9H9CNnWkhvv
qrSkcZP/+yJecfXIlkbWhDBqdw4mbsuJjLm5TAImHoc3J07xNZ7apByV5fyOT8ok
iDZRkWyzIAr7xmEGdMkCvp+E4dorEN2KeFLjqHoAlqFRBLrGK4Gr/tXzFRuirwls
BgNx7xhDt4IH9IKLsMcIoTxNocul86msFzeUDFXM/ruLFa34DBtT935WhGn+18+/
bYA+qM4GoC8N/4sSQtENQ8bX21aUHRs1MIOa82rJEmkCWW+Tgw8kYSSi8gVmd7Ly
QFp4XN17ReaIZZKBYJt/3XamcV2tcapxwqBNiGOLPQM4wnnuinkiZD7rXf1u/NFV
rHiVFu1+ORZaTX34+Vq9/wdj18E3cm1ghQsN3BQNzCE1qtulDcs5w2O1iZlP29wq
mtgeU7YHK7CzqNuUiPJWJardCWsCgcEA8VAXoPMSAJByCk3l92eDTOe8n5IMZ307
qXpGMlSUT+SctpgVdoN9iV+7bUQE636Hn37E5czANNpERIoVjFJRm0ioYW/9jOEN
B8zPnvwtLN1vVD1u5XNlumDGWGU1bQCdjgA07DtCM0S5xfhWOACCUJ4l4TDE3DAz
eNfnaXXP8UNfpL6gaWb/xZZwwTesS+hcX8zw14Gzn/GHkyGEtSMA+lezI5C37bzk
ao2pWr+W26HeDPwdG/38gBQceUujidJ9AoHBAOUW7AP8JbFTMUt0j1eO1UbAKty7
XZtURTX+EXK9sWTgeh3xlXpMU6K3U+sIQPsldCACjSeYr8lgGeTP54vZ9L6Zu30H
L2xC/kllafZhOjC5hC4iWaUgePMFiFeOb3prBDJd12ufUlqzydO4bvrKgi2fdAxL
vEtPFXs4U75RzqfXGdER7/0VOI68hS4GunqaiQ0UYPAE1mh+je5oJntP3fW8WRN1
KfuQdm5J+JjzQi4NmJAg6NxlB6wrxmMR8NgneQKBwQCg4A/AogwAYEwG3plPmleI
mn2/trLvqNJw/C7MOGLf7b3PEA5PAlOw6nzzgq3yVFpqVIND3dV4kYLYXA5djDZn
hcWWSqkIlgiv3d+/UsjIk5+NfknuTO58QIQ67iOeAGkJVXidfNbM2HvZUDl6qwGL
FBlAyy3oICJQj++bo9/2LOpt1Grw71UuZEsrenLdRZLqiKCPq80VS6+3a63OF1X8
OndtCyVJKJhHCRuR1Q89FpQIqBNn/qhVYr2mMm0GjFMCgcEAmLnyrVLDy4zLh6MK
Ol842dVx6HzpEjguI/62TH52Q0BRaUu4/DLibHo38gWAp25NaqxeGmXKhkARQzVF
B+ajKbvSU1ofnYH+25jxTut8IHutdBbmbhWl91kFj7RKUZytduk6R7+MPHfb4nr0
pzGsHmpNXYfS3N9jp3rifuE0b+S74Laf/g4ltH2uHq8m/GcGCLhAoAM5mv8JSZrE
UjU+o9LmDPjGp7WkSYalu0zWyV5ltWtF6ENacsfZl2FLOsT7AoHARP9ZNA7JMYMs
dbx2l7eLaTtdOeeSE9AxssmzXBsNHWklEx8DTI3MAFcIXPNesqnm++D/T5sXsIy6
kd3srldHGYHoh1IT5mOO7S8SlKLdYTIlsVIg+I4jpqmHTgk7DWDDpjYzkmJz3A29
q4HHmNx92SXNZD+mX0GnDdP9XDbT3tbt3ANuR1LoTcI3wAUMTN/NQiF8qj2NHzb1
CFOpBOJ9cuUgkWcntjqLJ6mUAMcQ8kF7Pyuhn46qDhY5ceVhrPt9
-----END RSA PRIVATE KEY-----

View File

@ -1,10 +1,6 @@
Here's what's what in the firmware/ directory.
bdb/
Code for managing Boot Descriptor Blocks (BDB).
include/
lib/

View File

@ -1,27 +0,0 @@
// 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.

View File

@ -1,30 +0,0 @@
Boot Descriptor Block (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.

View File

@ -1,450 +0,0 @@
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Boot descriptor block firmware functions
*/
#include "2sysincludes.h"
#include "2common.h"
#include "2sha.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
*/
static 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;
}
uint32_t bdb_size_of(const void *buf)
{
return bdb_get_header(buf)->bdb_size;
}
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_datakey(const void *buf)
{
const struct bdb_header *h = bdb_get_header(buf);
const uint8_t *b8 = bdb_get_oem_area_0(buf);
/* datakey follows OEM area 0 */
return (const struct bdb_key *)(b8 + h->oem_area_0_size);
}
ptrdiff_t bdb_offset_of_datakey(const void *buf)
{
return vb2_offset_of(buf, bdb_get_datakey(buf));
}
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);
}
ptrdiff_t bdb_offset_of_header_sig(const void *buf)
{
return vb2_offset_of(buf, bdb_get_header_sig(buf));
}
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);
}
ptrdiff_t bdb_offset_of_data(const void *buf)
{
return vb2_offset_of(buf, bdb_get_data(buf));
}
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;
}
static const void *bdb_get_hash(const void *buf)
{
const struct bdb_data *data = bdb_get_data(buf);
const uint8_t *b8 = bdb_get_oem_area_1(buf);
/* Hashes follow OEM area 0 */
return b8 + data->oem_area_1_size;
}
const struct bdb_hash *bdb_get_hash_by_type(const void *buf,
enum bdb_data_type type)
{
const struct bdb_data *data = bdb_get_data(buf);
const uint8_t *b8 = bdb_get_hash(buf);
int i;
/* 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_hash *bdb_get_hash_by_index(const void *buf, int index)
{
const struct bdb_data *data = bdb_get_data(buf);
const uint8_t *p = bdb_get_hash(buf);
const struct bdb_hash *h = NULL;
int i;
/* Search for a matching hash */
for (i = 0; i < data->num_hashes; i++, p += data->hash_entry_size) {
if (i == index) {
h = (const struct bdb_hash *)p;
break;
}
}
return h;
}
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);
}
/*****************************************************************************/
static 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, *datakey;
const struct bdb_sig *sig;
const struct bdb_data *data;
const void *oem;
uint8_t digest[BDB_SHA256_DIGEST_SIZE];
int bdb_digest_mismatch = -1;
/* 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 (vb2_digest_buffer((uint8_t *)bdbkey, bdbkey->struct_size,
VB2_HASH_SHA256, digest, BDB_SHA256_DIGEST_SIZE))
return BDB_ERROR_DIGEST;
if (bdb_key_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 datakey */
datakey = bdb_get_datakey(buf);
if (bdb_check_key(datakey, end - (const uint8_t *)datakey))
return BDB_ERROR_DATAKEY;
/* Make sure enough data was signed, and the signed data fits */
if (h->oem_area_0_size + datakey->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 (vb2_digest_buffer((uint8_t *)oem, h->signed_size,
VB2_HASH_SHA256, digest, BDB_SHA256_DIGEST_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_CHECK_SIG;
if (sig->signed_size != data->signed_size)
return BDB_ERROR_DATA_SIGNED_SIZE;
/* Calculate data digest and compare with expected signature */
if (vb2_digest_buffer((uint8_t *)data, data->signed_size,
VB2_HASH_SHA256, digest, BDB_SHA256_DIGEST_SIZE))
return BDB_ERROR_DIGEST;
if (bdb_verify_sig(datakey, 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;
}

View File

@ -1,232 +0,0 @@
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Boot descriptor block firmware functions
*/
#ifndef VBOOT_REFERENCE_BDB_H_
#define VBOOT_REFERENCE_BDB_H_
#include <stdlib.h>
#include <stddef.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 datakey 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,
/* Function is not implemented, thus supposed to be not called */
BDB_ERROR_NOT_IMPLEMENTED,
/* 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_DATAKEY,
BDB_ERROR_BDB_SIGNED_SIZE,
BDB_ERROR_HEADER_SIG,
BDB_ERROR_DATA,
BDB_ERROR_DATA_SIG,
BDB_ERROR_DATA_CHECK_SIG,
BDB_ERROR_DATA_SIGNED_SIZE,
/* Other errors in bdb_verify() */
BDB_ERROR_DIGEST, /* Error calculating digest */
BDB_ERROR_VERIFY_SIG, /* Error verifying signature */
/* Errors in vba_bdb_init */
BDB_ERROR_TRY_OTHER_SLOT,
BDB_ERROR_RECOVERY_REQUEST,
BDB_ERROR_NVM_INIT,
BDB_ERROR_NVM_WRITE,
BDB_ERROR_NVM_RW_HMAC,
BDB_ERROR_NVM_RW_INVALID_HMAC,
BDB_ERROR_NVM_INVALID_PARAMETER,
BDB_ERROR_NVM_INVALID_SECRET,
BDB_ERROR_NVM_RW_MAGIC,
BDB_ERROR_NVM_STRUCT_SIZE,
BDB_ERROR_NVM_WRITE_VERIFY,
BDB_ERROR_NVM_STRUCT_VERSION,
BDB_ERROR_NVM_VBE_READ,
BDB_ERROR_NVM_RW_BUFFER_SMALL,
BDB_ERROR_DECRYPT_BUC,
BDB_ERROR_ENCRYPT_BUC,
BDB_ERROR_WRITE_BUC,
BDB_ERROR_SECRET_TYPE,
BDB_ERROR_SECRET_BUC,
BDB_ERROR_SECRET_BOOT_VERIFIED,
BDB_ERROR_SECRET_BOOT_PATH,
BDB_ERROR_SECRET_BDB,
};
/*****************************************************************************/
/* 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.
* If it's NULL, digest match will be skipped
* (and it'll be treated as 'mismatch').
*
* @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_datakey(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_by_type(const void *buf,
enum bdb_data_type type);
const struct bdb_hash *bdb_get_hash_by_index(const void *buf, int index);
const struct bdb_sig *bdb_get_data_sig(const void *buf);
/**
* Functions to calculate size of BDB components
*
* @param buf Pointer to BDB buffer
* @return Size of the component
*/
uint32_t bdb_size_of(const void *buf);
/**
* Functions to calculate offset of BDB components
*
* @param buf Pointer to BDB buffer
* @return Offset of the component
*/
ptrdiff_t bdb_offset_of_datakey(const void *buf);
ptrdiff_t bdb_offset_of_header_sig(const void *buf);
ptrdiff_t bdb_offset_of_data(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.
*/
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.
*/
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.
*/
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.
*/
int bdb_ecdsa521_verify(const uint8_t *key_data,
const uint8_t *sig,
const uint8_t *digest);
/*****************************************************************************/
#endif /* VBOOT_REFERENCE_BDB_H_ */

View File

@ -1,194 +0,0 @@
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef VBOOT_REFERENCE_FIRMWARE_BDB_BDB_API_H
#define VBOOT_REFERENCE_FIRMWARE_BDB_BDB_API_H
#include <stdint.h>
#include "vboot_register.h"
#include "nvm.h"
#include "secrets.h"
#include "bdb_flag.h"
struct vba_context {
/* Indicate which slot is being tried: 0 - primary, 1 - secondary */
uint8_t slot;
/* Defined by VBA_CONTEXT_FLAG_* in bdb_flag.h */
uint32_t flags;
/* BDB */
uint8_t *bdb;
/* Secrets */
struct bdb_secrets *secrets;
/* NVM-RW buffer */
struct nvmrw nvmrw;
};
/**
* Initialize vboot process
*
* @param ctx
* @return enum bdb_return_code
*/
int vba_bdb_init(struct vba_context *ctx);
/**
* Finalize vboot process
*
* @param ctx
* @return enum bdb_return_code
*/
int vba_bdb_finalize(struct vba_context *ctx);
/**
* Log failed boot attempt and reset the chip
*
* @param ctx
*/
void vba_bdb_fail(struct vba_context *ctx);
/**
* Update kernel and its data key version in NVM
*
* This is the function called from SP-RW, which receives a kernel version
* from an AP-RW after successful verification of a kernel.
*
* It checks whether the version in NVM-RW is older than the reported version
* or not. If so, it updates the version in NVM-RW.
*
* @param ctx
* @param kernel_data_key_version
* @param kernel_version
* @return BDB_SUCCESS or BDB_ERROR_*
*/
int vba_update_kernel_version(struct vba_context *ctx,
uint32_t kernel_data_key_version,
uint32_t kernel_version);
/**
* Write new boot unlock code to NVM-RW
*
* @param ctx
* @param new_buc New BUC to be written
* @return BDB_SUCCESS or BDB_ERROR_*
*/
int vba_update_buc(struct vba_context *ctx, uint8_t *new_buc);
/**
* Derive a secret
*
* This derives a new secret from a secret passed from SP-RO.
*
* @param ctx
* @param type Type of secret to derive
* @param buf Buffer containing data to derive secret from
* @param buf_size Size of <buf>
* @return BDB_SUCCESS or BDB_ERROR_*
*/
int vba_derive_secret(struct vba_context *ctx, enum bdb_secret_type type,
uint8_t *wsr, const uint8_t *buf, uint32_t buf_size);
/**
* Clear a secret
*
* @param ctx
* @param type Type of secret to clear
* @return BDB_SUCCESS or BDB_ERROR_*
*/
int vba_clear_secret(struct vba_context *ctx, enum bdb_secret_type type);
/**
* Extend secrets for SP-RO
*
* @param ctx struct vba_context
* @param bdb BDB
* @param wsr Pointer to working secret register contents
* @param extend Function to be called for extending a secret
* @return BDB_SUCCESS or BDB_ERROR_*
*/
typedef void (*f_extend)(const uint8_t *from, const uint8_t *by, uint8_t *to);
int vba_extend_secrets_ro(struct vba_context *ctx, const uint8_t *bdb,
uint8_t *wsr, f_extend extend);
/**
* Get vboot register value
*
* Implemented by each chip
*
* @param type Type of register to get
* @return Register value
*/
uint32_t vbe_get_vboot_register(enum vboot_register type);
/**
* Set vboot register value
*
* Implemented by each chip
*
* @param type Type of register to set
* @param val Value to set
*/
void vbe_set_vboot_register(enum vboot_register type, uint32_t val);
/**
* Reset the SoC
*
* Implemented by each chip. This is different from reboot (a.k.a. board reset,
* cold reset).
*/
void vbe_reset(void);
/**
* Read contents from Non-Volatile Memory
*
* Implemented by each chip.
*
* @param type Type of NVM
* @param buf Buffer where the data will be read to
* @param size Size of data to read
* @return Zero if success or non-zero otherwise
*/
int vbe_read_nvm(enum nvm_type type, uint8_t *buf, uint32_t size);
/**
* Write contents to Non-Volatile Memory
*
* Implemented by each chip.
*
* @param type Type of NVM
* @param buf Buffer where the data will be written from
* @param size Size of data to write
* @return Zero if success or non-zero otherwise
*/
int vbe_write_nvm(enum nvm_type type, void *buf, uint32_t size);
/**
* Encrypt data by AES-256
*
* @param msg Message to be encrypted
* @param len Length of <msg> in bytes
* @param key Key used for encryption
* @param out Buffer where encrypted message is stored
* @return BDB_SUCCESS or BDB_ERROR_*
*/
int vbe_aes256_encrypt(const uint8_t *msg, uint32_t len, const uint8_t *key,
uint8_t *out);
/**
* Decrypt data by AES-256
*
* @param msg Message to be decrypted
* @param len Length of <msg> in bytes
* @param key Key used for decryption
* @param out Buffer where decrypted message is stored
* @return BDB_SUCCESS or BDB_ERROR_*
*/
int vbe_aes256_decrypt(const uint8_t *msg, uint32_t len, const uint8_t *key,
uint8_t *out);
#endif

View File

@ -1,15 +0,0 @@
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef VBOOT_REFERENCE_FIRMWARE_BDB_BDB_FLAG_H
#define VBOOT_REFERENCE_FIRMWARE_BDB_BDB_FLAG_H
/* Indicate whether BDB key is verified */
#define VBA_CONTEXT_FLAG_BDB_KEY_EFUSED (1 << 0)
/* Indicate whether kernel data key is verified */
#define VBA_CONTEXT_FLAG_KERNEL_DATA_KEY_VERIFIED (1 << 1)
#endif

View File

@ -1,268 +0,0 @@
/* 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 datakey, 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_ */

View File

@ -1,200 +0,0 @@
/* 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;
}

View File

@ -1,17 +0,0 @@
/* 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;
}

View File

@ -1,419 +0,0 @@
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Host functions for signing
*/
#include <unistd.h>
#include "2sysincludes.h"
#include "2common.h"
#include "2sha.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);
free(kdata);
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 (vb2_digest_buffer((uint8_t *)data, size,
VB2_HASH_SHA256,
digest + sizeof(info), BDB_SHA256_DIGEST_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;
}
int bdb_sign_datakey(uint8_t **bdb, struct rsa_st *key)
{
const struct bdb_header *header = bdb_get_header(*bdb);
const struct bdb_key *bdbkey = bdb_get_bdbkey(*bdb);
const void *oem = bdb_get_oem_area_0(*bdb);
const struct bdb_sig *sig = bdb_get_header_sig(*bdb);
struct bdb_sig *new_sig;
uint8_t *new_bdb, *src, *dst;
size_t len;
new_sig = bdb_create_sig(oem, header->signed_size,
key, bdbkey->sig_alg, NULL);
new_bdb = calloc(1, header->bdb_size
+ (new_sig->struct_size - sig->struct_size));
if (!new_bdb)
return BDB_ERROR_UNKNOWN;
/* copy up to sig */
src = *bdb;
dst = new_bdb;
len = bdb_offset_of_header_sig(*bdb);
memcpy(dst, src, len);
/* copy new sig */
src += len;
dst += len;
memcpy(dst, new_sig, new_sig->struct_size);
/* copy the rest */
src += sig->struct_size;
dst += new_sig->struct_size;
len = bdb_size_of(*bdb) - vb2_offset_of(*bdb, src);
memcpy(dst, src, len);
free(*bdb);
free(new_sig);
*bdb = new_bdb;
return BDB_SUCCESS;
}
int bdb_sign_data(uint8_t **bdb, struct rsa_st *key)
{
const struct bdb_key *datakey = bdb_get_datakey(*bdb);
const struct bdb_data *data = bdb_get_data(*bdb);
const uint64_t sig_offset = vb2_offset_of(*bdb, bdb_get_data_sig(*bdb));
struct bdb_sig *new_sig;
uint8_t *new_bdb;
new_sig = bdb_create_sig(data, data->signed_size,
key, datakey->sig_alg, NULL);
new_bdb = calloc(1, sig_offset + new_sig->struct_size);
if (!new_bdb)
return BDB_ERROR_UNKNOWN;
/* copy all data up to the data sig */
memcpy(new_bdb, *bdb, sig_offset);
/* copy the new signature */
memcpy(new_bdb + sig_offset, new_sig, new_sig->struct_size);
free(*bdb);
free(new_sig);
*bdb = new_bdb;
return BDB_SUCCESS;
}
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->datakey->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->datakey->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 datakey */
memcpy(bnext, p->datakey, p->datakey->struct_size);
bnext += p->datakey->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 datakey */
sig = bdb_create_sig(data, data->signed_size, p->private_datakey,
p->datakey->sig_alg, p->data_sig_description);
memcpy(bnext, sig, sig->struct_size);
/* Return the BDB */
return h;
}

View File

@ -1,191 +0,0 @@
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* 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 datakey
bdb_rsa_verify() on digest using BDB key
bdb_check_key() on RW datakey
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 datakey
Check RW datakey 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 datakey */
struct bdb_key *bdbkey;
struct bdb_key *datakey;
/* Private BDB key and datakey */
struct rsa_st *private_bdbkey;
struct rsa_st *private_datakey;
/* 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;
};
/**
* Sign data key in BDB
*
* @param bdb (IN/OUT) Buffer is freed upon successful call. Caller is
* responsible for freeing the newly allocated buffer.
* @param key Private BDB key to be signed with
* @return BDB_SUCCESS on success or BDB_ERROR_* otherwise.
*/
int bdb_sign_datakey(uint8_t **bdb, struct rsa_st *key);
/**
* Sign data section of BDB
*
* @param bdb (IN/OUT) Buffer is freed upon successful call. Caller is
* responsible for freeing the newly allocated buffer.
* @param key Private data key to be signed with
* @return BDB_SUCCESS on success or BDB_ERROR_* otherwise.
*/
int bdb_sign_data(uint8_t **bdb, struct rsa_st *key);
/**
* 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_ */

View File

@ -1,124 +0,0 @@
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <stdint.h>
#include "bdb.h"
#include "bdb_api.h"
#include "vboot_register.h"
static int did_current_slot_fail(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
if (ctx->slot)
return val & VBOOT_REGISTER_FAILED_RW_SECONDARY;
else
return val & VBOOT_REGISTER_FAILED_RW_PRIMARY;
}
static int did_other_slot_fail(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
if (ctx->slot)
return val & VBOOT_REGISTER_FAILED_RW_PRIMARY;
else
return val & VBOOT_REGISTER_FAILED_RW_SECONDARY;
}
static void set_try_other_slot(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
if (ctx->slot)
val &= ~VBOOT_REGISTER_TRY_SECONDARY_BDB;
else
val |= VBOOT_REGISTER_TRY_SECONDARY_BDB;
vbe_set_vboot_register(VBOOT_REGISTER_PERSIST, val);
}
static void set_recovery_request(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
val |= VBOOT_REGISTER_RECOVERY_REQUEST;
vbe_set_vboot_register(VBOOT_REGISTER_PERSIST, val);
}
static void get_current_slot(struct vba_context *ctx)
{
/* Assume SP-RO selects slot this way */
ctx->slot = (vbe_get_vboot_register(VBOOT_REGISTER_PERSIST)
& VBOOT_REGISTER_TRY_SECONDARY_BDB) ? 1 : 0;
}
static void set_current_slot_failed(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
if (ctx->slot)
val |= VBOOT_REGISTER_FAILED_RW_SECONDARY;
else
val |= VBOOT_REGISTER_FAILED_RW_PRIMARY;
vbe_set_vboot_register(VBOOT_REGISTER_PERSIST, val);
}
static void unset_current_slot_failed(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
if (ctx->slot)
val &= ~VBOOT_REGISTER_FAILED_RW_SECONDARY;
else
val &= ~VBOOT_REGISTER_FAILED_RW_PRIMARY;
vbe_set_vboot_register(VBOOT_REGISTER_PERSIST, val);
}
int vba_bdb_init(struct vba_context *ctx)
{
/* Get current slot */
get_current_slot(ctx);
/* Check current slot failed or not at the last boot */
if (!did_current_slot_fail(ctx)) {
/* If not, we try this slot. Prepare for any accidents */
set_current_slot_failed(ctx);
return BDB_SUCCESS;
}
/* Check other slot failed or not at the previous boot */
if (!did_other_slot_fail(ctx)) {
/* If not, we try the other slot after reboot. */
set_try_other_slot(ctx);
return BDB_ERROR_TRY_OTHER_SLOT;
} else {
/* Otherwise, both slots are bad. Reboot to recovery */
set_recovery_request(ctx);
return BDB_ERROR_RECOVERY_REQUEST;
}
}
int vba_bdb_finalize(struct vba_context *ctx)
{
/* Mark the current slot good */
unset_current_slot_failed(ctx);
/* Disable NVM bus */
return BDB_SUCCESS;
}
void vba_bdb_fail(struct vba_context *ctx)
{
/* We can do some logging here if we want */
/* Unconditionally reboot. FailedRW flag is already set.
* At the next boot, bdb_init will decide what to do. */
vbe_reset();
}

View File

@ -1,346 +0,0 @@
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "2sysincludes.h"
#include "2hmac.h"
#include "2sha.h"
#include "bdb_api.h"
#include "bdb_struct.h"
#include "bdb.h"
#include "nvm.h"
#include "secrets.h"
static int nvmrw_validate(const void *buf, uint32_t size)
{
const struct nvmrw *nvm = buf;
if (nvm->struct_magic != NVM_RW_MAGIC)
return BDB_ERROR_NVM_RW_MAGIC;
if (nvm->struct_major_version != NVM_HEADER_VERSION_MAJOR)
return BDB_ERROR_NVM_STRUCT_VERSION;
if (size < nvm->struct_size)
return BDB_ERROR_NVM_STRUCT_SIZE;
/*
* We allow any sizes between min and max so that we can handle minor
* version mismatches. Reader can be older than data or the other way
* around. FW in slot B can upgrade NVM-RW but fails to qualify as a
* stable boot path. Then, FW in slot A is invoked which is older than
* the NVM-RW written by FW in slot B.
*/
if (nvm->struct_size < NVM_RW_MIN_STRUCT_SIZE ||
NVM_RW_MAX_STRUCT_SIZE < nvm->struct_size)
return BDB_ERROR_NVM_STRUCT_SIZE;
return BDB_SUCCESS;
}
static int nvmrw_verify(const struct bdb_secrets *secrets,
const struct nvmrw *nvm, uint32_t size)
{
uint8_t mac[NVM_HMAC_SIZE];
int rv;
if (!secrets || !nvm)
return BDB_ERROR_NVM_INVALID_PARAMETER;
rv = nvmrw_validate(nvm, size);
if (rv)
return rv;
/* Compute and verify HMAC */
if (hmac(VB2_HASH_SHA256, secrets->nvm_rw, BDB_SECRET_SIZE,
nvm, nvm->struct_size - sizeof(mac), mac, sizeof(mac)))
return BDB_ERROR_NVM_RW_HMAC;
/* TODO: Use safe_memcmp */
if (memcmp(mac, nvm->hmac, sizeof(mac)))
return BDB_ERROR_NVM_RW_INVALID_HMAC;
return BDB_SUCCESS;
}
int nvmrw_write(struct vba_context *ctx, enum nvm_type type)
{
struct nvmrw *nvm = &ctx->nvmrw;
int retry = NVM_MAX_WRITE_RETRY;
int rv;
if (!ctx)
return BDB_ERROR_NVM_INVALID_PARAMETER;
if (!ctx->secrets)
return BDB_ERROR_NVM_INVALID_SECRET;
rv = nvmrw_validate(nvm, sizeof(*nvm));
if (rv)
return rv;
/* Update HMAC */
hmac(VB2_HASH_SHA256, ctx->secrets->nvm_rw, BDB_SECRET_SIZE,
nvm, nvm->struct_size - sizeof(nvm->hmac),
nvm->hmac, sizeof(nvm->hmac));
while (retry--) {
uint8_t buf[sizeof(struct nvmrw)];
if (vbe_write_nvm(type, nvm, nvm->struct_size))
continue;
if (vbe_read_nvm(type, buf, sizeof(buf)))
continue;
if (memcmp(buf, nvm, sizeof(buf)))
continue;
/* Write success */
return BDB_SUCCESS;
}
/* NVM seems corrupted. Go to chip recovery mode */
return BDB_ERROR_NVM_WRITE;
}
static int read_verify_nvmrw(enum nvm_type type,
const struct bdb_secrets *secrets,
uint8_t *buf, uint32_t buf_size)
{
struct nvmrw *nvm = (struct nvmrw *)buf;
int rv;
/* Read minimum amount */
if (vbe_read_nvm(type, buf, NVM_MIN_STRUCT_SIZE))
return BDB_ERROR_NVM_VBE_READ;
/* Validate the content */
rv = nvmrw_validate(buf, buf_size);
if (rv)
return rv;
/* Read full body */
if (vbe_read_nvm(type, buf, nvm->struct_size))
return BDB_ERROR_NVM_VBE_READ;
/* Verify the content */
rv = nvmrw_verify(secrets, nvm, sizeof(*nvm));
return rv;
return BDB_SUCCESS;
}
int nvmrw_read(struct vba_context *ctx)
{
uint8_t buf1[NVM_RW_MAX_STRUCT_SIZE];
uint8_t buf2[NVM_RW_MAX_STRUCT_SIZE];
struct nvmrw *nvm1 = (struct nvmrw *)buf1;
struct nvmrw *nvm2 = (struct nvmrw *)buf2;
int rv1, rv2;
/* Read and verify the 1st copy */
rv1 = read_verify_nvmrw(NVM_TYPE_RW_PRIMARY, ctx->secrets,
buf1, sizeof(buf1));
/* Read and verify the 2nd copy */
rv2 = read_verify_nvmrw(NVM_TYPE_RW_SECONDARY, ctx->secrets,
buf2, sizeof(buf2));
if (rv1 == BDB_SUCCESS && rv2 == BDB_SUCCESS) {
/* Sync primary and secondary based on update_count. */
if (nvm1->update_count > nvm2->update_count)
rv2 = !BDB_SUCCESS;
else if (nvm1->update_count < nvm2->update_count)
rv1 = !BDB_SUCCESS;
} else if (rv1 != BDB_SUCCESS && rv2 != BDB_SUCCESS){
/* Abort. Neither was successful. */
return rv1;
}
if (rv1 == BDB_SUCCESS)
/* both copies are good. use primary copy */
memcpy(&ctx->nvmrw, buf1, sizeof(ctx->nvmrw));
else
/* primary is bad but secondary is good. */
memcpy(&ctx->nvmrw, buf2, sizeof(ctx->nvmrw));
if (ctx->nvmrw.struct_minor_version != NVM_HEADER_VERSION_MINOR) {
/*
* Upgrade or downgrade is required. So, we need to write both.
* When upgrading, this is the place where new fields should be
* initialized. We don't increment update_count.
*/
ctx->nvmrw.struct_minor_version = NVM_HEADER_VERSION_MINOR;
ctx->nvmrw.struct_size = sizeof(ctx->nvmrw);
/* We don't worry about calculating hmac twice because
* this is a corner case. */
rv1 = nvmrw_write(ctx, NVM_TYPE_RW_PRIMARY);
rv2 = nvmrw_write(ctx, NVM_TYPE_RW_SECONDARY);
} else if (rv1 != BDB_SUCCESS) {
/* primary copy is bad. sync it with secondary copy */
rv1 = nvmrw_write(ctx, NVM_TYPE_RW_PRIMARY);
} else if (rv2 != BDB_SUCCESS){
/* secondary copy is bad. sync it with primary copy */
rv2 = nvmrw_write(ctx, NVM_TYPE_RW_SECONDARY);
} else {
/* Both copies are good and versions are same as the reader.
* Skip writing. This should be the common case. */
}
if (rv1 || rv2)
return rv1 ? rv1 : rv2;
return BDB_SUCCESS;
}
static int nvmrw_init(struct vba_context *ctx)
{
if (nvmrw_read(ctx))
return BDB_ERROR_NVM_INIT;
return BDB_SUCCESS;
}
int vba_update_kernel_version(struct vba_context *ctx,
uint32_t kernel_data_key_version,
uint32_t kernel_version)
{
struct nvmrw *nvm = &ctx->nvmrw;
if (nvmrw_verify(ctx->secrets, nvm, sizeof(*nvm))) {
if (nvmrw_init(ctx))
return BDB_ERROR_NVM_INIT;
}
if (nvm->min_kernel_data_key_version < kernel_data_key_version ||
nvm->min_kernel_version < kernel_version) {
int rv1, rv2;
/* Roll forward versions */
nvm->min_kernel_data_key_version = kernel_data_key_version;
nvm->min_kernel_version = kernel_version;
/* Increment update counter */
nvm->update_count++;
/* Update both copies */
rv1 = nvmrw_write(ctx, NVM_TYPE_RW_PRIMARY);
rv2 = nvmrw_write(ctx, NVM_TYPE_RW_SECONDARY);
if (rv1 || rv2)
return BDB_ERROR_RECOVERY_REQUEST;
}
return BDB_SUCCESS;
}
int vba_update_buc(struct vba_context *ctx, uint8_t *new_buc)
{
struct nvmrw *nvm = &ctx->nvmrw;
uint8_t buc[BUC_ENC_DIGEST_SIZE];
int rv1, rv2;
if (nvmrw_verify(ctx->secrets, nvm, sizeof(*nvm))) {
if (nvmrw_init(ctx))
return BDB_ERROR_NVM_INIT;
}
/* Encrypt new BUC
* Note that we do not need to decide whether we should use hardware
* crypto or not because this is supposed to be running in RW code. */
if (vbe_aes256_encrypt(new_buc, BUC_ENC_DIGEST_SIZE,
ctx->secrets->buc, buc))
return BDB_ERROR_ENCRYPT_BUC;
/* Return if new BUC is same as current one. */
if (!memcmp(buc, nvm->buc_enc_digest, sizeof(buc)))
return BDB_SUCCESS;
memcpy(nvm->buc_enc_digest, buc, sizeof(buc));
/* Increment update counter */
nvm->update_count++;
/* Write new BUC */
rv1 = nvmrw_write(ctx, NVM_TYPE_RW_PRIMARY);
rv2 = nvmrw_write(ctx, NVM_TYPE_RW_SECONDARY);
if (rv1 || rv2)
return BDB_ERROR_WRITE_BUC;
return BDB_SUCCESS;
}
int nvmrw_get(struct vba_context *ctx, enum nvmrw_var var, uint32_t *val)
{
struct nvmrw *nvm = &ctx->nvmrw;
/* No init or verify so that this can be called from futility.
* Callers are responsible for init and verify. */
switch (var) {
case NVMRW_VAR_UPDATE_COUNT:
*val = nvm->update_count;
break;
case NVMRW_VAR_MIN_KERNEL_DATA_KEY_VERSION:
*val = nvm->min_kernel_data_key_version;
break;
case NVMRW_VAR_MIN_KERNEL_VERSION:
*val = nvm->min_kernel_version;
break;
case NVMRW_VAR_BUC_TYPE:
*val = nvm->buc_type;
break;
case NVMRW_VAR_FLAG_BUC_PRESENT:
*val = nvm->flags & NVM_RW_FLAG_BUC_PRESENT;
break;
case NVMRW_VAR_FLAG_DFM_DISABLE:
*val = nvm->flags & NVM_RW_FLAG_DFM_DISABLE;
break;
case NVMRW_VAR_FLAG_DOSM:
*val = nvm->flags & NVM_RW_FLAG_DOSM;
break;
default:
return BDB_ERROR_NVM_INVALID_PARAMETER;
}
return BDB_SUCCESS;
}
#define MAX_8BIT_UINT ((((uint64_t)1) << 8) - 1)
int nvmrw_set(struct vba_context *ctx, enum nvmrw_var var, uint32_t val)
{
struct nvmrw *nvm = &ctx->nvmrw;
/* No init or verify so that this can be called from futility.
* Callers are responsible for init and verify. */
switch (var) {
case NVMRW_VAR_UPDATE_COUNT:
nvm->update_count = val;
break;
case NVMRW_VAR_MIN_KERNEL_DATA_KEY_VERSION:
nvm->min_kernel_data_key_version = val;
break;
case NVMRW_VAR_MIN_KERNEL_VERSION:
nvm->min_kernel_version = val;
break;
case NVMRW_VAR_BUC_TYPE:
if (val > MAX_8BIT_UINT)
return BDB_ERROR_NVM_INVALID_PARAMETER;
nvm->buc_type = val;
break;
case NVMRW_VAR_FLAG_BUC_PRESENT:
nvm->flags &= ~NVM_RW_FLAG_BUC_PRESENT;
nvm->flags |= val ? NVM_RW_FLAG_BUC_PRESENT : 0;
break;
case NVMRW_VAR_FLAG_DFM_DISABLE:
nvm->flags &= ~NVM_RW_FLAG_DFM_DISABLE;
nvm->flags |= val ? NVM_RW_FLAG_DFM_DISABLE : 0;
break;
case NVMRW_VAR_FLAG_DOSM:
nvm->flags &= ~NVM_RW_FLAG_DOSM;
nvm->flags |= val ? NVM_RW_FLAG_DOSM : 0;
break;
default:
return BDB_ERROR_NVM_INVALID_PARAMETER;
}
return BDB_SUCCESS;
}

View File

@ -1,139 +0,0 @@
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef VBOOT_REFERENCE_BDB_NVM_H_
#define VBOOT_REFERENCE_BDB_NVM_H_
#include <stdint.h>
#include "bdb_struct.h"
#include "bdb_api.h"
enum nvm_type {
NVM_TYPE_WP_PRIMARY,
NVM_TYPE_WP_SECONDARY,
NVM_TYPE_RW_PRIMARY,
NVM_TYPE_RW_SECONDARY,
};
#define NVM_RW_MAGIC 0x3052766e
/* Size in bytes of encrypted BUC (Boot Unlock Code) */
#define BUC_ENC_DIGEST_SIZE 32
/* Size in bytes of HMAC of struct NVM-RW */
#define NVM_HMAC_SIZE BDB_SHA256_DIGEST_SIZE
#define NVM_RW_FLAG_BUC_PRESENT (1 << 0)
#define NVM_RW_FLAG_DFM_DISABLE (1 << 1)
#define NVM_RW_FLAG_DOSM (1 << 2)
/* This is the minimum size of the data needed to learn the actual size */
#define NVM_MIN_STRUCT_SIZE 8
#define NVM_HEADER_VERSION_MAJOR 1
#define NVM_HEADER_VERSION_MINOR 1
/* Maximum number of retries for writing NVM */
#define NVM_MAX_WRITE_RETRY 2
struct nvmrw {
/* Magic number to identify struct */
uint32_t struct_magic;
/* Structure version */
uint8_t struct_major_version;
uint8_t struct_minor_version;
/* Size of struct in bytes. 96 for version 1.0 */
uint16_t struct_size;
/* Number of updates to structure contents */
uint32_t update_count;
/* Flags: NVM_RW_FLAG_* */
uint32_t flags;
/* Minimum valid kernel data key version */
uint32_t min_kernel_data_key_version;
/* Minimum valid kernel version */
uint32_t min_kernel_version;
/* Type of BUC */
uint8_t buc_type;
uint8_t reserved0[7];
/* Encrypted BUC */
uint8_t buc_enc_digest[BUC_ENC_DIGEST_SIZE];
/* SHA-256 HMAC of the struct contents. Add new fields before this. */
uint8_t hmac[NVM_HMAC_SIZE];
} __attribute__((packed));
/*
* List of variables stored in NVM-RW. This should be exported and used by
* firmware and futility to access data in NVM-RW.
*/
enum nvmrw_var {
NVMRW_VAR_UPDATE_COUNT,
NVMRW_VAR_FLAGS,
NVMRW_VAR_MIN_KERNEL_DATA_KEY_VERSION,
NVMRW_VAR_MIN_KERNEL_VERSION,
NVMRW_VAR_BUC_TYPE,
NVMRW_VAR_FLAG_BUC_PRESENT,
NVMRW_VAR_FLAG_DFM_DISABLE,
NVMRW_VAR_FLAG_DOSM,
};
/* Size of the version 1.0 */
#define NVM_RW_MIN_STRUCT_SIZE 96
/* 4 Kbit EEPROM divided by 4 regions (RO,RW) x (1st,2nd) = 128 KB */
#define NVM_RW_MAX_STRUCT_SIZE 128
/* For nvm_rw_read and nvm_write */
struct vba_context;
/**
* Read NVM-RW contents into the context
*
* @param ctx struct vba_context
* @return BDB_SUCCESS or BDB_ERROR_NVM_*
*/
int nvmrw_read(struct vba_context *ctx);
/**
* Write to NVM-RW from the context
*
* @param ctx struct vba_context
* @param type NVM_TYPE_RW_*
* @return BDB_SUCCESS or BDB_ERROR_NVM_*
*/
int nvmrw_write(struct vba_context *ctx, enum nvm_type type);
/**
* Get a value of NVM-RW variable
*
* Callers are responsible for init and verify of ctx->nvmrw.
*
* @param ctx struct vba_context
* @param var Index of the variable
* @param val Destination where the value is stored
* @return BDB_SUCCESS or BDB_ERROR_NVM_*
*/
int nvmrw_get(struct vba_context *ctx, enum nvmrw_var var, uint32_t *val);
/**
* Set a value in NVM-RW variable
*
* Callers are responsible for init and verify of ctx->nvmrw.
*
* @param ctx struct vba_context
* @param var Index of the variable
* @param val Value to be set
* @return BDB_SUCCESS or BDB_ERROR_NVM_*
*/
int nvmrw_set(struct vba_context *ctx, enum nvmrw_var var, uint32_t val);
#endif

View File

@ -1,337 +0,0 @@
/* Copyright 2016 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
*/
static int 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);
}
}
static int 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
};
static int 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 safe_memcmp() just to be on the safe side.
*/
result |= 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 (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 = check_padding(sig_work, &key, pad_size);
/*
* Check digest. Even though there are probably no timing issues here,
* use 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 (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 (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 = check_padding(sig_work, &key, pad_size);
/*
* Check digest. Even though there are probably no timing issues here,
* use 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 (safe_memcmp(sig_work + pad_size, digest, BDB_SHA256_DIGEST_SIZE))
rv = BDB_ERROR_DIGEST;
return rv;
}

View File

@ -1,330 +0,0 @@
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "2sysincludes.h"
#include "2hmac.h"
#include "2sha.h"
#include "bdb_api.h"
#include "bdb_struct.h"
#include "bdb.h"
#include "secrets.h"
const uint8_t secret_constant_a[] = {
0xad, 0xf8, 0xd1, 0xd9, 0x48, 0xe6, 0xb3, 0xe4, 0xe0, 0xc4,
0xd8, 0x66, 0x97, 0x95, 0x71, 0xa8, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x01};
const uint8_t secret_constant_b[] = {
0xba, 0x9d, 0x1d, 0x8b, 0x12, 0xbd, 0x8d, 0xcd, 0x4c, 0x89,
0xd8, 0x18, 0x72, 0x98, 0xb5, 0x18, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x02};
const uint8_t secret_constant_x[] = {
0xfd, 0xc1, 0xe5, 0x57, 0x34, 0xf4, 0xf6, 0x89, 0x6d, 0x1b,
0x6f, 0xf2, 0xd0, 0x36, 0xdb, 0xf4, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x09};
const uint8_t secret_constant_y[] = {
0x18, 0xef, 0x01, 0x8e, 0xcd, 0x62, 0xf1, 0xb0, 0x2d, 0xd4,
0x11, 0xa4, 0xb5, 0x6e, 0x38, 0xf6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x0a};
const uint8_t secret_constant_c[] = {
0x46, 0xda, 0x52, 0x8d, 0x08, 0x56, 0x14, 0xde, 0x75, 0x9c,
0x9a, 0xeb, 0x08, 0x93, 0x3d, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x0b};
const uint8_t secret_constant_fv0[] = {
0x93, 0x32, 0xf7, 0x8d, 0xec, 0x4b, 0x26, 0x2e, 0xb3, 0x5c,
0x39, 0xd7, 0xfc, 0xc6, 0x9f, 0x09, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x05};
const uint8_t secret_constant_fv1[] = {
0x60, 0x8d, 0x96, 0x35, 0xdf, 0xf6, 0x31, 0x67, 0xab, 0xb8,
0x9f, 0x50, 0x81, 0x28, 0x82, 0xec, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x06};
const uint8_t secret_constant_kv0[] = {
0x46, 0x6d, 0xef, 0x2c, 0x05, 0xc9, 0xbf, 0xa9, 0x6b, 0xee,
0xaa, 0x6c, 0xb9, 0xb4, 0x6d, 0x37, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x07};
const uint8_t secret_constant_kv1[] = {
0x0a, 0x9e, 0xc9, 0x20, 0x29, 0xa3, 0x5d, 0xd7, 0x27, 0x55,
0xb6, 0xa6, 0xb4, 0x80, 0x7c, 0x73, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x08};
const uint8_t secret_constant_k[] = {
/*
* Digest of kernel data key struct fills first 32 bytes
*/
0x1e, 0x1d, 0xec, 0xf2, 0x6d, 0x27, 0xa6, 0xd9,
0x67, 0x0f, 0x34, 0xc5, 0xfa, 0x01, 0x68, 0xf6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x03};
const uint8_t secret_constant_l[] = {
/*
* Digest of kernel data key struct fills first 32 bytes
*/
0x9b, 0xc0, 0x29, 0xd3, 0xc3, 0x90, 0x7f, 0x82,
0x56, 0xe2, 0x67, 0x79, 0x11, 0x74, 0xbe, 0xd0, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x04};
const uint8_t secret_constant_p[] = {
/*
* Digest of KDB key struct fills first 32 bytes
*/
0xfe, 0x31, 0xed, 0xed, 0x45, 0xfd, 0x8a, 0x5d,
0x87, 0x90, 0xac, 0x17, 0x02, 0x89, 0x2c, 0xba, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x0c};
const uint8_t secret_constant_q[] = {
/*
* Digest of KDB key struct fills first 32 bytes
*/
0xc7, 0x60, 0x83, 0x0f, 0x20, 0x44, 0x5d, 0x9c,
0x70, 0x96, 0x05, 0x2d, 0x51, 0x4b, 0x15, 0x99, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0x0d};
/**
* Get constant with digest
*
* This function computes a digest of the given buffer and concatenates it
* to the given constant.
*
* @param buf Data from which a digest is computed
* @param buf_size Size of <buf>
* @param constant Buffer containing constant
* @param out Buffer where the result is stored
* @return BDB_SUCCESS on success or !BDB_SUCCESS otherwise
*/
static int get_constant_with_digest(const uint8_t *buf, uint32_t buf_size,
const uint8_t *constant, uint8_t *out)
{
int digest_size = vb2_digest_size(VB2_HASH_SHA256);
const struct bdb_key *key = (const struct bdb_key *)buf;
if (!buf)
return !BDB_SUCCESS;
if (bdb_check_key(key, buf_size))
return !BDB_SUCCESS;
if (vb2_digest_buffer(buf, buf_size, VB2_HASH_SHA256, out, digest_size))
return !BDB_SUCCESS;
memcpy(out + digest_size, constant,
BDB_CONSTANT_BLOCK_SIZE - digest_size);
return BDB_SUCCESS;
}
/**
* Derive secrets for SP-RO
*
* This function extends a BDS to derive secrets as done by SP-RO (a.k.a. mask
* rom).
*
* @param ctx VBoot context
* @param type Type of secret to derive
* @param wsr Work secret register
* @param buf Data from which a digest is computed
* @param buf_size Size of <buf>
* @param extend sha256 extension function to be used
* @return BDB_SUCCESS on success or BDB_ERROR_* otherwise
*/
static int derive_secret_ro(struct vba_context *ctx, enum bdb_secret_type type,
uint8_t *wsr, const uint8_t *buf, uint32_t buf_size,
f_extend extend)
{
uint8_t c[BDB_CONSTANT_BLOCK_SIZE];
uint8_t *from;
const uint8_t *by = (const uint8_t *)c;
uint8_t *to;
switch (type) {
case BDB_SECRET_TYPE_WSR:
from = to = wsr;
by = secret_constant_x;
break;
case BDB_SECRET_TYPE_BDB:
from = wsr;
to = ctx->secrets->bdb;
if (get_constant_with_digest(buf, buf_size,
secret_constant_p, c))
return BDB_ERROR_SECRET_BDB;
break;
case BDB_SECRET_TYPE_BOOT_PATH:
from = wsr;
to = ctx->secrets->boot_path;
if (get_constant_with_digest(buf, buf_size,
secret_constant_k, c))
return BDB_ERROR_SECRET_BOOT_PATH;
break;
case BDB_SECRET_TYPE_BOOT_VERIFIED:
from = wsr;
to = ctx->secrets->boot_verified;
if (ctx->flags & VBA_CONTEXT_FLAG_BDB_KEY_EFUSED)
by = secret_constant_fv0;
else
by = secret_constant_fv1;
break;
case BDB_SECRET_TYPE_NVM_WP:
from = wsr;
by = secret_constant_a;
to = ctx->secrets->nvm_wp;
break;
case BDB_SECRET_TYPE_NVM_RW:
from = ctx->secrets->nvm_wp;
by = secret_constant_b;
to = ctx->secrets->nvm_rw;
break;
default:
return BDB_ERROR_SECRET_TYPE;
}
if (extend)
extend(from, by, to);
else
vb2_sha256_extend(from, by, to);
return BDB_SUCCESS;
}
int vba_derive_secret(struct vba_context *ctx, enum bdb_secret_type type,
uint8_t *wsr, const uint8_t *buf, uint32_t buf_size)
{
uint8_t c[BDB_CONSTANT_BLOCK_SIZE];
uint8_t *from;
const uint8_t *by = (const uint8_t *)c;
uint8_t *to;
switch (type) {
case BDB_SECRET_TYPE_WSR:
from = to = wsr;
by = secret_constant_y;
break;
case BDB_SECRET_TYPE_BDB:
from = to = ctx->secrets->bdb;
if (get_constant_with_digest(buf, buf_size,
secret_constant_q, c))
return BDB_ERROR_SECRET_BDB;
break;
case BDB_SECRET_TYPE_BOOT_PATH:
from = to = ctx->secrets->boot_path;
if (get_constant_with_digest(buf, buf_size,
secret_constant_l, c))
return BDB_ERROR_SECRET_BOOT_PATH;
break;
case BDB_SECRET_TYPE_BOOT_VERIFIED:
from = to = ctx->secrets->boot_verified;
if (ctx->flags & VBA_CONTEXT_FLAG_KERNEL_DATA_KEY_VERIFIED)
by = secret_constant_kv1;
else
by = secret_constant_kv0;
break;
case BDB_SECRET_TYPE_BUC:
from = ctx->secrets->boot_verified;
by = secret_constant_c;
to = ctx->secrets->buc;
break;
default:
return BDB_ERROR_SECRET_TYPE;
}
vb2_sha256_extend(from, by, to);
return BDB_SUCCESS;
}
int vba_clear_secret(struct vba_context *ctx, enum bdb_secret_type type)
{
uint8_t *s;
switch (type) {
case BDB_SECRET_TYPE_NVM_RW:
s = ctx->secrets->nvm_rw;
break;
case BDB_SECRET_TYPE_BDB:
s = ctx->secrets->bdb;
break;
case BDB_SECRET_TYPE_BOOT_PATH:
s = ctx->secrets->boot_path;
break;
case BDB_SECRET_TYPE_BOOT_VERIFIED:
s = ctx->secrets->boot_verified;
break;
case BDB_SECRET_TYPE_BUC:
s = ctx->secrets->buc;
break;
default:
return BDB_ERROR_SECRET_TYPE;
}
memset(s, 0, BDB_SECRET_SIZE);
return BDB_SUCCESS;
}
int vba_extend_secrets_ro(struct vba_context *ctx, const uint8_t *bdb,
uint8_t *wsr, f_extend extend)
{
const struct bdb_key *bdbkey = bdb_get_bdbkey(bdb);
const struct bdb_key *datakey = bdb_get_datakey(bdb);
derive_secret_ro(ctx, BDB_SECRET_TYPE_BDB, wsr, (const uint8_t *)bdbkey,
bdbkey->struct_size, extend);
derive_secret_ro(ctx, BDB_SECRET_TYPE_BOOT_PATH, wsr,
(const uint8_t *)datakey, datakey->struct_size,
extend);
derive_secret_ro(ctx, BDB_SECRET_TYPE_BOOT_VERIFIED, wsr, NULL, 0,
extend);
derive_secret_ro(ctx, BDB_SECRET_TYPE_NVM_WP, wsr, NULL, 0, extend);
/* Deriving NVM-RW has to be done after NVM-WP */
derive_secret_ro(ctx, BDB_SECRET_TYPE_NVM_RW, wsr, NULL, 0, extend);
/* Extending WSR has to be done last. */
derive_secret_ro(ctx, BDB_SECRET_TYPE_WSR, wsr, NULL, 0, extend);
return BDB_SUCCESS;
}

View File

@ -1,35 +0,0 @@
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef VBOOT_REFERENCE_FIRMWARE_BDB_SECRETS_H_
#define VBOOT_REFERENCE_FIRMWARE_BDB_SECRETS_H_
#define BDB_SECRET_SIZE 32
#define BDB_CONSTANT_BLOCK_SIZE 64
enum bdb_secret_type {
BDB_SECRET_TYPE_WSR,
BDB_SECRET_TYPE_NVM_WP,
BDB_SECRET_TYPE_NVM_RW,
BDB_SECRET_TYPE_BDB,
BDB_SECRET_TYPE_BOOT_VERIFIED,
BDB_SECRET_TYPE_BOOT_PATH,
BDB_SECRET_TYPE_BUC,
BDB_SECRET_TYPE_COUNT, /* Last entry. Add new secrets before this. */
};
/*
* Struct storing BDB secrets passed between SP-RO and SP-RW.
*/
struct bdb_secrets {
uint8_t nvm_rw[BDB_SECRET_SIZE];
uint8_t bdb[BDB_SECRET_SIZE];
uint8_t boot_verified[BDB_SECRET_SIZE];
uint8_t boot_path[BDB_SECRET_SIZE];
uint8_t nvm_wp[BDB_SECRET_SIZE];
uint8_t buc[BDB_SECRET_SIZE];
};
#endif

View File

@ -1,20 +0,0 @@
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <string.h>
#include "2sha.h"
#include "bdb.h"
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;
}

View File

@ -1,51 +0,0 @@
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "bdb_api.h"
#include "bdb.h"
__attribute__((weak))
uint32_t vbe_get_vboot_register(enum vboot_register type)
{
return 0;
}
__attribute__((weak))
void vbe_set_vboot_register(enum vboot_register type, uint32_t val)
{
return;
}
__attribute__((weak))
void vbe_reset(void)
{
return;
}
__attribute__((weak))
int vbe_read_nvm(enum nvm_type type, uint8_t *buf, uint32_t size)
{
return BDB_ERROR_NOT_IMPLEMENTED;
}
__attribute__((weak))
int vbe_write_nvm(enum nvm_type type, void *buf, uint32_t size)
{
return BDB_ERROR_NOT_IMPLEMENTED;
}
__attribute__((weak))
int vbe_aes256_encrypt(const uint8_t *msg, uint32_t len, const uint8_t *key,
uint8_t *out)
{
return BDB_ERROR_NOT_IMPLEMENTED;
}
__attribute__((weak))
int vbe_aes256_decrypt(const uint8_t *msg, uint32_t len, const uint8_t *key,
uint8_t *out)
{
return BDB_ERROR_NOT_IMPLEMENTED;
}

View File

@ -1,22 +0,0 @@
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef VBOOT_REFERENCE_FIRMWARE_BDB_VBOOT_REGISTER_H
#define VBOOT_REFERENCE_FIRMWARE_BDB_VBOOT_REGISTER_H
enum vboot_register {
/* Register cleared after every reset */
VBOOT_REGISTER,
/* Register cleared after cold reset (persists after warm reset) */
VBOOT_REGISTER_PERSIST,
};
/* Bit fields for VBOOT_REGISTER_PERSISTENT */
#define VBOOT_REGISTER_RECOVERY_REQUEST (1 << 0)
#define VBOOT_REGISTER_TRY_SECONDARY_BDB (1 << 1)
#define VBOOT_REGISTER_FAILED_RW_PRIMARY (1 << 2)
#define VBOOT_REGISTER_FAILED_RW_SECONDARY (1 << 3)
#endif

View File

@ -1,160 +0,0 @@
/* Copyright 2016 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 helper functions
*/
#include <inttypes.h>
#include <stdio.h>
#include "2sha.h"
#include "bdb.h"
#include "bdb_struct.h"
#include "file_type.h"
enum futil_file_type ft_recognize_bdb(uint8_t *buf, uint32_t len)
{
const struct bdb_header *header = bdb_get_header(buf);
if (bdb_check_header(header, len))
return FILE_TYPE_UNKNOWN;
return FILE_TYPE_BDB;
}
static void print_digest(const char *label, const uint8_t *digest, size_t size)
{
int i;
if (label)
printf("%s", label);
for (i = 0; i < size; i++)
printf("%02x", digest[i]);
printf("\n");
}
static void print_hash_entry(const char *label, const struct bdb_hash *hash)
{
if (label)
printf("%s", label);
printf(" Offset: 0x%" PRIx64 "\n", hash->offset);
printf(" Size: %d\n", hash->size);
printf(" Partition: %d\n", hash->partition);
printf(" Type: %d\n", hash->type);
printf(" Load Address: 0x%" PRIx64 "\n", hash->load_address);
print_digest(" Digest: ", hash->digest, sizeof(hash->digest));
}
static void print_key_info(const char *label, const struct bdb_key *key)
{
uint8_t digest[BDB_SHA256_DIGEST_SIZE];
if (label)
printf("%s", label);
printf(" Struct Version: 0x%x:0x%x\n",
key->struct_major_version, key->struct_minor_version);
printf(" Size: %d\n", key->struct_size);
printf(" Hash Algorithm: %d\n", key->hash_alg);
printf(" Sign Algorithm: %d\n", key->sig_alg);
printf(" Version: %d\n", key->key_version);
printf(" Description: %s\n", key->description);
bdb_sha256(digest, key, key->struct_size);
print_digest(" Digest: ", digest, sizeof(digest));
}
static void print_sig_info(const char *label, const struct bdb_sig *sig)
{
if (label)
printf("%s", label);
printf(" Struct Version: 0x%x:0x%x\n",
sig->struct_major_version, sig->struct_minor_version);
printf(" Hash Algorithm: %d\n", sig->hash_alg);
printf(" Sign Algorithm: %d\n", sig->sig_alg);
printf(" Signed Size: %d\n", sig->signed_size);
printf(" Description: %s\n", sig->description);
}
static void show_bdb_header(const uint8_t *bdb)
{
const struct bdb_header *header = bdb_get_header(bdb);
printf("BDB Header:\n");
printf(" Struct Version: 0x%x:0x%x\n",
header->struct_major_version, header->struct_minor_version);
printf(" Struct Size: %d\n", header->struct_size);
printf(" Load Address: 0x%" PRIx64 "\n", header->bdb_load_address);
printf(" Size: %d\n", header->bdb_size);
printf(" Signed Size: %d\n", header->signed_size);
printf(" OEM0 Size: %d\n", header->oem_area_0_size);
}
static void show_bdbkey_info(const uint8_t *bdb)
{
print_key_info("BDB key:\n", bdb_get_bdbkey(bdb));
}
static void show_datakey_info(const uint8_t *bdb)
{
print_key_info("Data key:\n", bdb_get_datakey(bdb));
}
static void show_header_signature(const uint8_t *bdb)
{
print_sig_info("Header Signature:\n" , bdb_get_header_sig(bdb));
}
static void show_data_header(const uint8_t *bdb)
{
const struct bdb_data *data = bdb_get_data(bdb);
printf("Data Header:\n");
printf(" Struct Version: 0x%x:0x%x\n",
data->struct_major_version, data->struct_minor_version);
printf(" Data Version: %d\n", data->data_version);
printf(" # of Hashes: %d\n", data->num_hashes);
printf(" Hash Entry Size: %d\n", data->hash_entry_size);
printf(" Signed Size: %d\n", data->signed_size);
printf(" Description: %s\n", data->description);
}
static void show_hashes(const uint8_t *bdb)
{
const struct bdb_data *data = bdb_get_data(bdb);
int i;
for (i = 0; i < data->num_hashes; i++) {
const struct bdb_hash *hash = bdb_get_hash_by_index(bdb, i);
printf("Hash #%d:\n", i);
print_hash_entry(NULL, hash);
}
}
static void show_data_signature(const uint8_t *bdb)
{
print_sig_info("Data Signature:\n" , bdb_get_data_sig(bdb));
}
int ft_show_bdb(const char *name, uint8_t *buf, uint32_t len, void *data)
{
const struct bdb_header *header = bdb_get_header(buf);
int rv;
/* We can get here because of '--type' option */
rv = bdb_check_header(header, len);
if (rv) {
fprintf(stderr, "ERROR: Invalid BDB blob: %d\n", rv);
return 1;
}
printf("Boot Descriptor Block: %s\n", name);
show_bdb_header(buf);
show_bdbkey_info(buf);
show_datakey_info(buf);
show_header_signature(buf);
show_data_header(buf);
show_hashes(buf);
show_data_signature(buf);
return 0;
}

View File

@ -1,711 +0,0 @@
/* Copyright 2016 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.
*
* Common boot flow utility
*/
#include <getopt.h>
#include <stdio.h>
#include <unistd.h>
#include "2sysincludes.h"
#include "2common.h"
#include "bdb.h"
#include "bdb_struct.h"
#include "futility.h"
#include "host.h"
static long int version;
/* Command line options */
enum {
/* mode options */
OPT_MODE_NONE,
OPT_MODE_ADD,
OPT_MODE_CREATE,
OPT_MODE_RESIGN,
OPT_MODE_VERIFY,
/* file options */
OPT_BDBKEY_PRI,
OPT_BDBKEY_PUB,
OPT_DATAKEY_PRI,
OPT_DATAKEY_PUB,
OPT_DATA,
OPT_KEY_DIGEST,
/* versions */
OPT_BDBKEY_VERSION,
OPT_DATAKEY_VERSION,
OPT_DATA_VERSION,
/* integer options */
OPT_OFFSET,
OPT_PARTITION,
OPT_TYPE,
OPT_LOAD_ADDRESS,
/* Misc. options */
OPT_IGNORE_KEY_DIGEST,
OPT_VERSION,
OPT_HELP,
};
static const struct option long_opts[] = {
{"add", 1, 0, OPT_MODE_ADD},
{"create", 1, 0, OPT_MODE_CREATE},
{"resign", 1, 0, OPT_MODE_RESIGN},
{"verify", 1, 0, OPT_MODE_VERIFY},
{"bdbkey_pri", 1, 0, OPT_BDBKEY_PRI},
{"bdbkey_pub", 1, 0, OPT_BDBKEY_PUB},
{"datakey_pri", 1, 0, OPT_DATAKEY_PRI},
{"datakey_pub", 1, 0, OPT_DATAKEY_PUB},
{"bdbkey_version", 1, 0, OPT_BDBKEY_VERSION},
{"datakey_version", 1, 0, OPT_DATAKEY_VERSION},
{"data_version", 1, 0, OPT_DATA_VERSION},
{"data", 1, 0, OPT_DATA},
{"key_digest", 1, 0, OPT_KEY_DIGEST},
{"offset", 1, 0, OPT_OFFSET},
{"partition", 1, 0, OPT_PARTITION},
{"type", 1, 0, OPT_TYPE},
{"load_address", 1, 0, OPT_LOAD_ADDRESS},
{"ignore_key_digest", 0, 0, OPT_IGNORE_KEY_DIGEST},
{"version", 1, 0, OPT_VERSION},
{"help", 0, 0, OPT_HELP},
{NULL, 0, 0, 0}
};
/**
* Add hash entry to BDB
*
* This adds a hash entry to a BDB. It does not change the signature. Hence,
* the produced BDB needs to be resigned using the resign sub-command.
*/
static int do_add(const char *bdb_filename, const char *data_filename,
uint64_t offset, uint8_t partition,
uint8_t type, uint64_t load_address)
{
uint8_t *bdb, *data, *new_bdb = NULL;
uint32_t bdb_size, data_size;
struct bdb_header *bdb_header;
struct bdb_data *data_header;
struct bdb_hash *new_hash;
int rv = -1;
bdb = read_file(bdb_filename, &bdb_size);
data = read_file(data_filename, &data_size);
if (!bdb || !data) {
fprintf(stderr, "Unable to load BDB or data\n");
goto exit;
}
/* Create a copy of BDB */
new_bdb = calloc(1, bdb_size + sizeof(*new_hash));
if (!new_bdb) {
fprintf(stderr, "Unable to allocate memory\n");
goto exit;
}
/* Copy up to the end of hashes. This implicitly clears the data
* sig because it's not copied. */
memcpy(new_bdb, bdb, vb2_offset_of(bdb, bdb_get_data_sig(bdb)));
/* Update new BDB header */
bdb_header = (struct bdb_header *)bdb_get_header(new_bdb);
bdb_header->bdb_size += sizeof(*new_hash);
data_header = (struct bdb_data *)bdb_get_data(new_bdb);
/* Update new hash. We're overwriting the data signature, which
* is already invalid anyway. */
new_hash = (struct bdb_hash *)((uint8_t *)data_header
+ data_header->signed_size);
new_hash->size = data_size;
new_hash->type = type;
new_hash->load_address = load_address;
new_hash->partition = partition;
new_hash->offset = offset;
if (bdb_sha256(new_hash->digest, data, data_size)) {
fprintf(stderr, "Unable to calculate hash\n");
goto exit;
}
/* Update data header */
data_header->num_hashes++;
data_header->signed_size += sizeof(*new_hash);
rv = write_file(bdb_filename, bdb_header, bdb_header->bdb_size);
if (rv) {
fprintf(stderr, "Unable to write BDB\n");
goto exit;
}
fprintf(stderr, "Hash is added to BDB successfully. Resign required\n");
exit:
free(bdb);
free(data);
free(new_bdb);
return rv;
}
/**
* Create a new BDB
*
* This creates a new BDB using a pair of BDB keys and a pair of data keys.
* A private data key is needed even with no hash entries.
*/
static int do_create(const char *bdb_filename,
const char *bdbkey_pri_filename,
const char *bdbkey_pub_filename,
uint32_t bdbkey_version,
const char *datakey_pri_filename,
const char *datakey_pub_filename,
uint32_t datakey_version,
uint64_t load_address)
{
struct bdb_key *bdbkey;
struct bdb_key *datakey;
struct rsa_st *bdbkey_pri;
struct rsa_st *datakey_pri;
struct bdb_create_params params;
struct bdb_header *header;
int rv = -1;
/* Check arguments */
if (!bdb_filename || !bdbkey_pri_filename || !bdbkey_pub_filename
|| !datakey_pri_filename || !datakey_pub_filename) {
fprintf(stderr, "Missing filenames\n");
return rv;
}
/* Load keys */
bdbkey = bdb_create_key(bdbkey_pub_filename, bdbkey_version, NULL);
bdbkey_pri = read_pem(bdbkey_pri_filename);
datakey = bdb_create_key(datakey_pub_filename, datakey_version, NULL);
datakey_pri = read_pem(datakey_pri_filename);
if (!bdbkey || !bdbkey_pri || !datakey || !datakey_pri) {
fprintf(stderr, "Unable to load keys\n");
goto exit;
}
memset(&params, 0, sizeof(params));
params.bdb_load_address = load_address;
params.bdbkey = bdbkey;
params.datakey = datakey;
params.private_bdbkey = bdbkey_pri;
params.private_datakey = datakey_pri;
params.num_hashes = 0;
header = bdb_create(&params);
if (!header) {
fprintf(stderr, "Unable to create BDB\n");
goto exit;
}
rv = write_file(bdb_filename, header, header->bdb_size);
if (rv) {
fprintf(stderr, "Unable to write BDB\n");
goto exit;
}
fprintf(stderr, "BDB is created successfully\n");
exit:
/* Free keys and buffers */
free(bdbkey);
free(datakey);
RSA_free(bdbkey_pri);
RSA_free(datakey_pri);
return rv;
}
static int install_bdbkey(uint8_t **bdb, const struct bdb_key *new_key)
{
struct bdb_header *header;
const struct bdb_key *key;
uint8_t *p, *q;
uint8_t *new_bdb;
size_t new_size;
size_t l;
header = (struct bdb_header *)bdb_get_header(*bdb);
key = bdb_get_bdbkey(*bdb);
new_size = bdb_size_of(*bdb) + new_key->struct_size - key->struct_size;
new_bdb = calloc(1, new_size);
if (!new_bdb) {
fprintf(stderr, "Unable to allocate memory\n");
return -1;
}
/* copy BDB header */
p = *bdb;
q = new_bdb;
l = header->struct_size;
memcpy(q, p, l);
/* copy new BDB key */
p += l;
q += l;
memcpy(q, new_key, new_key->struct_size);
/* copy the rest */
p += key->struct_size;
q += new_key->struct_size;
l = bdb_size_of(*bdb) - vb2_offset_of(*bdb, p);
memcpy(q, p, l);
/* update size */
header = (struct bdb_header *)bdb_get_header(new_bdb);
header->bdb_size = new_size;
free(*bdb);
*bdb = new_bdb;
return 0;
}
static int install_datakey(uint8_t **bdb, const struct bdb_key *new_key)
{
struct bdb_header *header;
struct bdb_key *key;
uint8_t *p, *q;
uint8_t *new_bdb;
size_t new_size;
uint32_t l;
key = (struct bdb_key *)bdb_get_datakey(*bdb);
new_size = bdb_size_of(*bdb) + new_key->struct_size - key->struct_size;
new_bdb = calloc(1, new_size);
if (!new_bdb) {
fprintf(stderr, "Unable to allocate memory\n");
return -1;
}
/* copy the stuff up to datakey */
p = *bdb;
q = new_bdb;
l = bdb_offset_of_datakey(*bdb);
memcpy(q, p, l);
/* copy new data key */
p += l;
q += l;
memcpy(q, new_key, new_key->struct_size);
/* copy the rest */
p += key->struct_size;
q += new_key->struct_size;
l = bdb_size_of(*bdb) - vb2_offset_of(*bdb, p);
memcpy(q, p, l);
/* update size */
header = (struct bdb_header *)bdb_get_header(new_bdb);
header->bdb_size = new_size;
header->signed_size = header->oem_area_0_size + new_key->struct_size;
free(*bdb);
*bdb = new_bdb;
return 0;
}
/**
* Resign a BDB using new keys
*
* It first installs given public keys to the BDB, then, runs verification.
* If verification fails due to an invalid signature, it tries to 'fix' it
* by resigning it using a given private key, then runs verification again.
* Whether a key is required or not depends on which signature is invalid.
* If a private key is required but not provided, it returns an error.
*/
static int do_resign(const char *bdb_filename,
const char *bdbkey_pri_filename,
const char *bdbkey_pub_filename,
uint32_t bdbkey_version,
const char *datakey_pri_filename,
const char *datakey_pub_filename,
uint32_t datakey_version,
uint32_t data_version)
{
uint8_t *bdb = NULL;
struct rsa_st *bdbkey_pri = NULL;
struct rsa_st *datakey_pri = NULL;
uint32_t bdb_size;
int resigned = 0;
int rv = -1;
if (!bdb_filename) {
fprintf(stderr, "BDB file must be specified\n");
goto exit;
}
bdb = read_file(bdb_filename, &bdb_size);
if (!bdb) {
fprintf(stderr, "Unable to read %s\n", bdb_filename);
goto exit;
}
if (data_version != -1) {
struct bdb_data *data = (struct bdb_data *)bdb_get_data(bdb);
data->data_version = data_version;
}
if (bdbkey_pub_filename) {
struct bdb_key *key = bdb_create_key(bdbkey_pub_filename,
bdbkey_version, NULL);
if (!key) {
fprintf(stderr, "Unable to read BDB key\n");
goto exit;
}
if (install_bdbkey(&bdb, key)) {
fprintf(stderr, "Unable to install new BDB key\n");
goto exit;
}
}
if (datakey_pub_filename) {
struct bdb_key *key = bdb_create_key(datakey_pub_filename,
datakey_version, NULL);
if (!key) {
fprintf(stderr, "Unable to read data key\n");
goto exit;
}
if (install_datakey(&bdb, key)) {
fprintf(stderr, "Unable to install new data key\n");
goto exit;
}
}
/* Check validity for the new bdb key */
rv = bdb_verify(bdb, bdb_size_of(bdb), NULL);
if (rv == BDB_ERROR_HEADER_SIG) {
/* This is expected failure if we installed a new BDB key.
* Let's resign to fix it. */
resigned = 1;
fprintf(stderr, "Data key signature is invalid. Need to resign "
"the key.\n");
if (!bdbkey_pri_filename) {
fprintf(stderr, "Private BDB key is required but not "
"provided.\n");
goto exit;
}
bdbkey_pri = read_pem(bdbkey_pri_filename);
rv = bdb_sign_datakey(&bdb, bdbkey_pri);
if (rv) {
fprintf(stderr, "Failed to resign data key: %d\n", rv);
goto exit;
}
fprintf(stderr, "Data key is resigned.\n");
} else {
fprintf(stderr, "Resigning data key is not required.\n");
}
/* Check validity for the new data key */
rv = bdb_verify(bdb, bdb_size_of(bdb), NULL);
switch (rv) {
case BDB_ERROR_DATA_SIG:
case BDB_ERROR_DATA_CHECK_SIG:
/* This is expected failure if we installed a new data key
* or sig is corrupted, which happens when a new hash is added
* by 'add' sub-command. Let's resign the data */
resigned = 1;
fprintf(stderr,
"Data signature is invalid. Need to resign data.\n");
if (!datakey_pri_filename) {
fprintf(stderr, "Private data key is required but not "
"provided.\n");
goto exit;
}
datakey_pri = read_pem(datakey_pri_filename);
rv = bdb_sign_data(&bdb, datakey_pri);
if (rv) {
fprintf(stderr, "Failed to resign hashes: %d\n", rv);
goto exit;
}
fprintf(stderr, "Data is resigned.\n");
break;
case BDB_GOOD_OTHER_THAN_KEY:
case BDB_SUCCESS:
fprintf(stderr, "Resigning the data is not required.\n");
break;
default:
fprintf(stderr, "Verifying BDB failed unexpectedly: %d\n", rv);
goto exit;
}
if (!resigned)
goto exit;
/* Check validity one last time */
rv = bdb_verify(bdb, bdb_size_of(bdb), NULL);
if (rv && rv != BDB_GOOD_OTHER_THAN_KEY) {
/* This is not expected. We installed new keys and resigned
* BDB but it's still invalid. */
fprintf(stderr, "BDB is resigned but it's invalid: %d\n", rv);
goto exit;
}
rv = write_file(bdb_filename, bdb, bdb_size_of(bdb));
if (rv) {
fprintf(stderr, "Unable to write BDB.\n");
goto exit;
}
fprintf(stderr, "Successfully resigned BDB.\n");
exit:
free(bdb);
RSA_free(bdbkey_pri);
RSA_free(datakey_pri);
return rv;
}
static int do_verify(const char *bdb_filename, const char *key_digest_filename,
int ignore_key_digest)
{
uint8_t *bdb = NULL;
uint8_t *key_digest = NULL;
uint32_t bdb_size, key_digest_size;
int rv = -1;
bdb = read_file(bdb_filename, &bdb_size);
if (!bdb) {
fprintf(stderr, "Unable to load BDB\n");
goto exit;
}
if (key_digest_filename) {
key_digest = read_file(key_digest_filename, &key_digest_size);
if (!key_digest) {
fprintf(stderr, "Unable to read key digest\n");
goto exit;
}
if (key_digest_size != BDB_SHA256_DIGEST_SIZE) {
fprintf(stderr,
"Invalid digest size: %d\n", key_digest_size);
goto exit;
}
}
rv = bdb_verify(bdb, bdb_size, key_digest);
switch (rv) {
case BDB_SUCCESS:
fprintf(stderr, "BDB is successfully verified.\n");
break;
case BDB_GOOD_OTHER_THAN_KEY:
fprintf(stderr, "BDB is valid.");
if (ignore_key_digest) {
rv = BDB_SUCCESS;
fprintf(stderr,
" Key digest doesn't match but ignored.\n");
} else {
fprintf(stderr,
" Key digest doesn't match.\n");
}
break;
default:
/* TODO: Probably nice to print translation of the error code */
fprintf(stderr, "BDB is invalid: %d.\n", rv);
}
exit:
free(bdb);
free(key_digest);
return rv;
}
/* Print help and return error */
static void print_help(int argc, char *argv[])
{
printf("\nUsage: " MYNAME " %s <--create|--add|--resign|--verify>\n"
"\n"
"Utility for managing boot descriptor blocks (BDBs).\n"
"\n"
"For '--add <bdb_file> [OPTIONS]', required OPTIONS are:\n"
" --data <file> Data to be added\n"
" --offset <offset> Offset\n"
" --partition <number> Partition number\n"
" --type <number> Data type\n"
" --load_address <number> Data load address\n"
"\n"
"For '--create <bdb_file> [OPTIONS]', required OPTIONS are:\n"
" --bdbkey_pri <file> BDB key in .pem format\n"
" --bdbkey_pub <file> BDB key in .keyb format\n"
" --datakey_pri <file> Data key in .pem format\n"
" --datakey_pub <file> Data key in .keyb format\n"
" --load_address <number> BDB load address\n"
"\n"
"For '--resign <bdb_file> [OPTIONS]', optional OPTIONS are:\n"
" --bdbkey_pri <file> New BDB key in .pem format\n"
" --bdbkey_pub <file> New BDB key in .keyb format\n"
" --datakey_pri <file> New data key in .pem format\n"
" --datakey_pub <file> New data key in .keyb format\n"
" --data_version <number> Data version\n"
"\n"
"For '--verify <bdb_file> [OPTIONS]', optional OPTIONS are:\n"
" --key_digest <file> BDB key digest\n"
" --ignore_key_digest Ignore key digest mismatch\n"
"\n",
argv[0]);
}
static int do_bdb(int argc, char *argv[])
{
int mode = 0;
const char *bdb_filename = NULL;
const char *bdbkey_pri_filename = NULL;
const char *bdbkey_pub_filename = NULL;
const char *datakey_pri_filename = NULL;
const char *datakey_pub_filename = NULL;
const char *data_filename = NULL;
const char *key_digest_filename = NULL;
uint32_t bdbkey_version = 0;
uint32_t datakey_version = 0;
uint32_t data_version = -1;
uint64_t offset = 0;
uint8_t partition = 0;
uint8_t type = 0;
uint64_t load_address = -1;
int ignore_key_digest = 0;
int parse_error = 0;
char *e;
int i;
while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
switch (i) {
case '?':
/* Unhandled option */
fprintf(stderr, "Unknown option or missing value\n");
parse_error = 1;
break;
case OPT_HELP:
print_help(argc, argv);
return !!parse_error;
case OPT_MODE_CREATE:
mode = i;
bdb_filename = optarg;
break;
case OPT_MODE_ADD:
mode = i;
bdb_filename = optarg;
break;
case OPT_MODE_RESIGN:
mode = i;
bdb_filename = optarg;
break;
case OPT_MODE_VERIFY:
mode = i;
bdb_filename = optarg;
break;
case OPT_BDBKEY_PRI:
bdbkey_pri_filename = optarg;
break;
case OPT_BDBKEY_PUB:
bdbkey_pub_filename = optarg;
break;
case OPT_DATAKEY_PRI:
datakey_pri_filename = optarg;
break;
case OPT_DATAKEY_PUB:
datakey_pub_filename = optarg;
break;
case OPT_DATA:
data_filename = optarg;
break;
case OPT_KEY_DIGEST:
key_digest_filename = optarg;
break;
case OPT_BDBKEY_VERSION:
bdbkey_version = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --bdbkey_version\n");
parse_error = 1;
}
break;
case OPT_DATAKEY_VERSION:
datakey_version = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --datakey_version\n");
parse_error = 1;
}
break;
case OPT_DATA_VERSION:
data_version = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --data_version\n");
parse_error = 1;
}
break;
case OPT_OFFSET:
offset = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --offset\n");
parse_error = 1;
}
break;
case OPT_PARTITION:
partition = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --partition\n");
parse_error = 1;
}
break;
case OPT_TYPE:
type = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --type\n");
parse_error = 1;
}
break;
case OPT_LOAD_ADDRESS:
load_address = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --load_address\n");
parse_error = 1;
}
break;
case OPT_IGNORE_KEY_DIGEST:
ignore_key_digest = 1;
break;
case OPT_VERSION:
version = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --version\n");
parse_error = 1;
}
break;
}
}
if (parse_error) {
print_help(argc, argv);
return 1;
}
switch (mode) {
case OPT_MODE_ADD:
return do_add(bdb_filename, data_filename,
offset, partition, type, load_address);
case OPT_MODE_CREATE:
return do_create(bdb_filename, bdbkey_pri_filename,
bdbkey_pub_filename, bdbkey_version,
datakey_pri_filename, datakey_pub_filename,
datakey_version, load_address);
case OPT_MODE_RESIGN:
return do_resign(bdb_filename, bdbkey_pri_filename,
bdbkey_pub_filename, bdbkey_version,
datakey_pri_filename, datakey_pub_filename,
datakey_version, data_version);
case OPT_MODE_VERIFY:
return do_verify(bdb_filename,
key_digest_filename, ignore_key_digest);
case OPT_MODE_NONE:
default:
fprintf(stderr, "Must specify a mode.\n");
print_help(argc, argv);
return 1;
}
}
DECLARE_FUTIL_COMMAND(bdb, do_bdb, VBOOT_VERSION_1_0,
"Common boot flow utility");

View File

@ -80,7 +80,3 @@ FILE_TYPE(USBPD1, "usbpd1", "USB-PD charger image (v1.0)",
R_(ft_recognize_usbpd1),
S_(ft_show_usbpd1),
S_(ft_sign_usbpd1))
FILE_TYPE(BDB, "bdb", "Common Boot Flow Boot Descriptor Block",
R_(ft_recognize_bdb),
S_(ft_show_bdb),
NONE)

View File

@ -1,60 +0,0 @@
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Unit tests NVM
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bdb_api.h"
#include "test_common.h"
static void test_nvmrw(void)
{
struct vba_context ctx;
uint32_t val;
memset(&ctx.nvmrw, 0, sizeof(ctx.nvmrw));
TEST_SUCC(nvmrw_set(&ctx, NVMRW_VAR_UPDATE_COUNT, 1), NULL);
TEST_SUCC(nvmrw_get(&ctx, NVMRW_VAR_UPDATE_COUNT, &val), NULL);
TEST_EQ(val, 1, NULL);
TEST_SUCC(nvmrw_set(&ctx, NVMRW_VAR_MIN_KERNEL_DATA_KEY_VERSION, 1),
NULL);
TEST_SUCC(nvmrw_get(&ctx, NVMRW_VAR_MIN_KERNEL_DATA_KEY_VERSION, &val),
NULL);
TEST_EQ(val, 1, NULL);
TEST_SUCC(nvmrw_set(&ctx, NVMRW_VAR_MIN_KERNEL_VERSION, 1), NULL);
TEST_SUCC(nvmrw_get(&ctx, NVMRW_VAR_MIN_KERNEL_VERSION, &val), NULL);
TEST_EQ(val, 1, NULL);
TEST_SUCC(nvmrw_set(&ctx, NVMRW_VAR_BUC_TYPE, 1), NULL);
TEST_SUCC(nvmrw_get(&ctx, NVMRW_VAR_BUC_TYPE, &val), NULL);
TEST_EQ(val, 1, NULL);
TEST_SUCC(nvmrw_set(&ctx, NVMRW_VAR_FLAG_BUC_PRESENT, 1), NULL);
TEST_SUCC(nvmrw_get(&ctx, NVMRW_VAR_FLAG_BUC_PRESENT, &val), NULL);
TEST_TRUE(val, NULL);
TEST_SUCC(nvmrw_set(&ctx, NVMRW_VAR_FLAG_DFM_DISABLE, 1), NULL);
TEST_SUCC(nvmrw_get(&ctx, NVMRW_VAR_FLAG_DFM_DISABLE, &val), NULL);
TEST_TRUE(val, NULL);
TEST_SUCC(nvmrw_set(&ctx, NVMRW_VAR_FLAG_DOSM, 1), NULL);
TEST_SUCC(nvmrw_get(&ctx, NVMRW_VAR_FLAG_DOSM, &val), NULL);
TEST_TRUE(val, NULL);
}
int main(int argc, char *argv[])
{
printf("Running BDB NVM tests...\n");
test_nvmrw();
return gTestSuccess ? 0 : 255;
}

View File

@ -1,684 +0,0 @@
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Unit tests
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include "2sha.h"
#include "2hmac.h"
#include "bdb.h"
#include "bdb_api.h"
#include "bdb_struct.h"
#include "host.h"
#include "test_common.h"
#include "vboot_register.h"
#include "secrets.h"
static struct bdb_header *bdb, *bdb0, *bdb1;
static uint32_t vboot_register;
static uint32_t vboot_register_persist;
static char slot_selected;
static uint8_t aprw_digest[BDB_SHA256_DIGEST_SIZE];
static uint8_t reset_count;
/* NVM-RW image in storage (e.g. EEPROM) */
static uint8_t nvmrw1[NVM_RW_MAX_STRUCT_SIZE];
static uint8_t nvmrw2[NVM_RW_MAX_STRUCT_SIZE];
static struct bdb_secrets secrets = {
.nvm_wp = {0x00, },
.nvm_rw = {0x00, },
.bdb = {0x00, },
.boot_verified = {0x00, },
.boot_path = {0x00, },
.buc = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff},
};
static int vbe_write_nvm_failure = 0;
static struct bdb_header *create_bdb(const char *key_dir,
struct bdb_hash *hash, int num_hashes)
{
struct bdb_header *b;
uint8_t oem_area_0[32] = "Some OEM area.";
uint8_t oem_area_1[64] = "Some other OEM area.";
char filename[1024];
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 = (char *)"The header sig",
.data_sig_description = (char *)"The data sig",
.data_description = (char *)"Test BDB data",
.data_version = 3,
.hash = hash,
.num_hashes = num_hashes,
};
uint8_t bdbkey_digest[BDB_SHA256_DIGEST_SIZE];
/* Load keys */
snprintf(filename, sizeof(filename), "%s/bdbkey.keyb", key_dir);
p.bdbkey = bdb_create_key(filename, 100, "BDB key");
snprintf(filename, sizeof(filename), "%s/datakey.keyb", key_dir);
p.datakey = bdb_create_key(filename, 200, "datakey");
snprintf(filename, sizeof(filename), "%s/bdbkey.pem", key_dir);
p.private_bdbkey = read_pem(filename);
snprintf(filename, sizeof(filename), "%s/datakey.pem", key_dir);
p.private_datakey = read_pem(filename);
if (!p.bdbkey || !p.datakey || !p.private_bdbkey || !p.private_datakey) {
fprintf(stderr, "Unable to load test keys\n");
exit(2);
}
vb2_digest_buffer((uint8_t *)p.bdbkey, p.bdbkey->struct_size,
VB2_HASH_SHA256,
bdbkey_digest, BDB_SHA256_DIGEST_SIZE);
b = bdb_create(&p);
if (!b) {
fprintf(stderr, "Unable to create test BDB\n");
exit(2);
}
/* Free keys and buffers */
free(p.bdbkey);
free(p.datakey);
RSA_free(p.private_bdbkey);
RSA_free(p.private_datakey);
return b;
}
static void calculate_aprw_digest(const struct bdb_hash *hash, uint8_t *digest)
{
/* Locate AP-RW */
/* Calculate digest as loading AP-RW */
memcpy(digest, aprw_digest, sizeof(aprw_digest));
}
static void verstage_main(void)
{
struct vba_context ctx;
const struct bdb_hash *hash;
uint8_t digest[BDB_SHA256_DIGEST_SIZE];
int rv;
rv = vba_bdb_init(&ctx);
if (rv) {
fprintf(stderr, "Initializing context failed for (%d)\n", rv);
vba_bdb_fail(&ctx);
/* This return is needed for unit test. vba_bdb_fail calls
* vbe_reset, which calls verstage_main. If verstage_main
* successfully returns, we return here as well. */
return;
}
fprintf(stderr, "Initialized context. Trying slot %c\n",
ctx.slot ? 'B' : 'A');
/* 1. Locate BDB */
/* 2. Get bdb_hash structure for AP-RW */
hash = bdb_get_hash_by_type(bdb, BDB_DATA_AP_RW);
fprintf(stderr, "Got hash of AP-RW\n");
/* 3. Load & calculate digest of AP-RW */
calculate_aprw_digest(hash, digest);
fprintf(stderr, "Calculated digest\n");
/* 4. Compare digests */
if (memcmp(hash->digest, digest, BDB_SHA256_DIGEST_SIZE)) {
fprintf(stderr, "Digests do not match\n");
vba_bdb_fail(&ctx);
/* This return is needed for unit test. vba_bdb_fail calls
* vbe_reset, which calls verstage_main. If verstage_main
* successfully returns, we return here as well. */
return;
}
/* 5. Record selected slot. This depends on the firmware */
slot_selected = ctx.slot ? 'B' : 'A';
fprintf(stderr, "Selected AP-RW in slot %c\n", slot_selected);
/* X. This should be done upon AP-RW's request after everything is
* successful. We do it here for the unit test. */
vba_bdb_finalize(&ctx);
}
uint32_t vbe_get_vboot_register(enum vboot_register type)
{
switch (type) {
case VBOOT_REGISTER:
return vboot_register;
case VBOOT_REGISTER_PERSIST:
return vboot_register_persist;
default:
fprintf(stderr, "Invalid vboot register type (%d)\n", type);
exit(2);
}
}
void vbe_set_vboot_register(enum vboot_register type, uint32_t val)
{
switch (type) {
case VBOOT_REGISTER:
vboot_register = val;
break;
case VBOOT_REGISTER_PERSIST:
vboot_register_persist = val;
break;
default:
fprintf(stderr, "Invalid vboot register type (%d)\n", type);
exit(2);
}
}
void vbe_reset(void)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
fprintf(stderr, "Booting ...\n");
if (++reset_count > 5) {
fprintf(stderr, "Reset counter exceeded maximum value\n");
exit(2);
}
/* Emulate warm reset */
vboot_register = 0;
if (val & VBOOT_REGISTER_RECOVERY_REQUEST) {
fprintf(stderr, "Recovery requested\n");
return;
}
/* Selected by SP-RO */
bdb = (val & VBOOT_REGISTER_TRY_SECONDARY_BDB) ? bdb1 : bdb0;
verstage_main();
}
static void test_verify_aprw(const char *key_dir)
{
struct bdb_hash hash0 = {
.offset = 0x28000,
.size = 0x20000,
.partition = 1,
.type = BDB_DATA_AP_RW,
.load_address = 0x200000,
.digest = {0x11, 0x11, 0x11, 0x11},
};
struct bdb_hash hash1 = {
.offset = 0x28000,
.size = 0x20000,
.partition = 1,
.type = BDB_DATA_AP_RW,
.load_address = 0x200000,
.digest = {0x22, 0x22, 0x22, 0x22},
};
bdb0 = create_bdb(key_dir, &hash0, 1);
bdb1 = create_bdb(key_dir, &hash1, 1);
memset(aprw_digest, 0, BDB_SHA256_DIGEST_SIZE);
/* (slotA, slotB) = (good, bad) */
reset_count = 0;
vboot_register_persist = 0;
slot_selected = 'X';
memcpy(aprw_digest, hash0.digest, 4);
vbe_reset();
TEST_EQ(reset_count, 1, NULL);
TEST_EQ(slot_selected, 'A', NULL);
TEST_FALSE(vboot_register_persist & VBOOT_REGISTER_FAILED_RW_PRIMARY,
NULL);
TEST_FALSE(vboot_register_persist & VBOOT_REGISTER_FAILED_RW_SECONDARY,
NULL);
/* (slotA, slotB) = (bad, good) */
reset_count = 0;
vboot_register_persist = 0;
slot_selected = 'X';
memcpy(aprw_digest, hash1.digest, 4);
vbe_reset();
TEST_EQ(reset_count, 3, NULL);
TEST_EQ(slot_selected, 'B', NULL);
TEST_TRUE(vboot_register_persist & VBOOT_REGISTER_FAILED_RW_PRIMARY,
NULL);
TEST_FALSE(vboot_register_persist & VBOOT_REGISTER_FAILED_RW_SECONDARY,
NULL);
/* (slotA, slotB) = (bad, bad) */
reset_count = 0;
vboot_register_persist = 0;
slot_selected = 'X';
memset(aprw_digest, 0, BDB_SHA256_DIGEST_SIZE);
vbe_reset();
TEST_EQ(reset_count, 5, NULL);
TEST_EQ(slot_selected, 'X', NULL);
TEST_TRUE(vboot_register_persist & VBOOT_REGISTER_FAILED_RW_PRIMARY,
NULL);
TEST_TRUE(vboot_register_persist & VBOOT_REGISTER_FAILED_RW_SECONDARY,
NULL);
TEST_TRUE(vboot_register_persist & VBOOT_REGISTER_RECOVERY_REQUEST,
NULL);
/* Clean up */
free(bdb0);
free(bdb1);
}
int vbe_read_nvm(enum nvm_type type, uint8_t *buf, uint32_t size)
{
/* Read NVM-RW contents (from EEPROM for example) */
switch (type) {
case NVM_TYPE_RW_PRIMARY:
if (sizeof(nvmrw1) < size)
return -1;
memcpy(buf, nvmrw1, size);
break;
case NVM_TYPE_RW_SECONDARY:
if (sizeof(nvmrw2) < size)
return -1;
memcpy(buf, nvmrw2, size);
break;
default:
return -1;
}
return 0;
}
int vbe_write_nvm(enum nvm_type type, void *buf, uint32_t size)
{
if (vbe_write_nvm_failure > 0) {
fprintf(stderr, "Failed to write NVM (type=%d failure=%d)\n",
type, vbe_write_nvm_failure);
vbe_write_nvm_failure--;
return -1;
}
/* Write NVM-RW contents (to EEPROM for example) */
switch (type) {
case NVM_TYPE_RW_PRIMARY:
memcpy(nvmrw1, buf, size);
break;
case NVM_TYPE_RW_SECONDARY:
memcpy(nvmrw2, buf, size);
break;
default:
return -1;
}
return 0;
}
static void install_nvm(enum nvm_type type,
uint32_t min_kernel_data_key_version,
uint32_t min_kernel_version,
uint32_t update_count)
{
struct nvmrw nvm = {
.struct_magic = NVM_RW_MAGIC,
.struct_major_version = NVM_HEADER_VERSION_MAJOR,
.struct_minor_version = NVM_HEADER_VERSION_MINOR,
.struct_size = sizeof(struct nvmrw),
.min_kernel_data_key_version = min_kernel_data_key_version,
.min_kernel_version = min_kernel_version,
.update_count = update_count,
};
/* Compute HMAC */
hmac(VB2_HASH_SHA256, secrets.nvm_rw, BDB_SECRET_SIZE,
&nvm, nvm.struct_size - sizeof(nvm.hmac),
nvm.hmac, sizeof(nvm.hmac));
/* Install NVM-RWs (in EEPROM for example) */
switch (type) {
case NVM_TYPE_RW_PRIMARY:
memset(nvmrw1, 0, sizeof(nvmrw1));
memcpy(nvmrw1, &nvm, sizeof(nvm));
break;
case NVM_TYPE_RW_SECONDARY:
memset(nvmrw2, 0, sizeof(nvmrw2));
memcpy(nvmrw2, &nvm, sizeof(nvm));
break;
default:
fprintf(stderr, "Unsupported NVM type (%d)\n", type);
exit(2);
return;
}
}
static void test_nvm_read(void)
{
struct vba_context ctx = {
.bdb = NULL,
.secrets = &secrets,
};
struct nvmrw *nvm;
uint8_t nvmrw1_copy[NVM_RW_MAX_STRUCT_SIZE];
uint8_t nvmrw2_copy[NVM_RW_MAX_STRUCT_SIZE];
install_nvm(NVM_TYPE_RW_PRIMARY, 0, 1, 0);
install_nvm(NVM_TYPE_RW_SECONDARY, 1, 0, 0);
memcpy(nvmrw1_copy, nvmrw1, sizeof(nvmrw1));
memcpy(nvmrw2_copy, nvmrw2, sizeof(nvmrw2));
/* Test nvm_read: both good -> pick primary, no sync */
memset(&ctx.nvmrw, 0, sizeof(ctx.nvmrw));
TEST_SUCC(nvmrw_read(&ctx), NULL);
TEST_SUCC(memcmp(&ctx.nvmrw, nvmrw1, sizeof(*nvm)), NULL);
TEST_SUCC(memcmp(nvmrw1, nvmrw1_copy, sizeof(nvmrw1)), NULL);
TEST_SUCC(memcmp(nvmrw2, nvmrw2_copy, sizeof(nvmrw2)), NULL);
/* Test nvm_read: primary bad -> pick secondary */
install_nvm(NVM_TYPE_RW_PRIMARY, 0, 1, 0);
install_nvm(NVM_TYPE_RW_SECONDARY, 1, 0, 0);
memcpy(nvmrw2_copy, nvmrw2, sizeof(*nvm));
nvm = (struct nvmrw *)nvmrw1;
nvm->hmac[0] ^= 0xff;
memset(&ctx.nvmrw, 0, sizeof(ctx.nvmrw));
TEST_SUCC(nvmrw_read(&ctx), NULL);
TEST_SUCC(memcmp(&ctx.nvmrw, nvmrw2, sizeof(*nvm)), NULL);
TEST_SUCC(memcmp(nvmrw1, nvmrw2_copy, sizeof(nvmrw2)), NULL);
TEST_SUCC(memcmp(nvmrw2, nvmrw2_copy, sizeof(nvmrw2)), NULL);
/* Test nvm_read: secondary bad -> pick primary */
install_nvm(NVM_TYPE_RW_PRIMARY, 0, 1, 0);
install_nvm(NVM_TYPE_RW_SECONDARY, 1, 0, 0);
memcpy(nvmrw1_copy, nvmrw1, sizeof(*nvm));
nvm = (struct nvmrw *)nvmrw2;
nvm->hmac[0] ^= 0xff;
memset(&ctx.nvmrw, 0, sizeof(ctx.nvmrw));
TEST_SUCC(nvmrw_read(&ctx), NULL);
TEST_SUCC(memcmp(&ctx.nvmrw, nvmrw1, sizeof(*nvm)), NULL);
TEST_SUCC(memcmp(nvmrw1, nvmrw1_copy, sizeof(nvmrw1)), NULL);
TEST_SUCC(memcmp(nvmrw2, nvmrw1_copy, sizeof(nvmrw1)), NULL);
/* Test nvm_read: both bad */
nvm = (struct nvmrw *)nvmrw1;
nvm->hmac[0] ^= 0xff;
nvm = (struct nvmrw *)nvmrw2;
nvm->hmac[0] ^= 0xff;
memset(&ctx.nvmrw, 0, sizeof(ctx.nvmrw));
TEST_EQ(nvmrw_read(&ctx), BDB_ERROR_NVM_RW_INVALID_HMAC, NULL);
/* Test update count: secondary new -> pick secondary */
install_nvm(NVM_TYPE_RW_PRIMARY, 0, 1, 0);
install_nvm(NVM_TYPE_RW_SECONDARY, 1, 0, 1);
memcpy(nvmrw2_copy, nvmrw2, sizeof(*nvm));
memset(&ctx.nvmrw, 0, sizeof(ctx.nvmrw));
TEST_SUCC(nvmrw_read(&ctx), NULL);
TEST_SUCC(memcmp(&ctx.nvmrw, nvmrw2, sizeof(*nvm)), NULL);
TEST_SUCC(memcmp(nvmrw1, nvmrw2_copy, sizeof(nvmrw1)), NULL);
TEST_SUCC(memcmp(nvmrw2, nvmrw2_copy, sizeof(nvmrw2)), NULL);
/* Test old reader -> minor version downgrade */
install_nvm(NVM_TYPE_RW_PRIMARY, 0, 1, 0);
install_nvm(NVM_TYPE_RW_SECONDARY, 1, 0, 1);
memset(&ctx.nvmrw, 0, sizeof(ctx.nvmrw));
nvm = (struct nvmrw *)nvmrw1;
nvm->struct_minor_version++;
nvm->struct_size++;
TEST_SUCC(nvmrw_read(&ctx), NULL);
TEST_EQ(ctx.nvmrw.struct_minor_version, NVM_HEADER_VERSION_MINOR, NULL);
TEST_EQ(ctx.nvmrw.struct_size, sizeof(*nvm), NULL);
}
static void verify_nvm_write(struct vba_context *ctx,
int expected_result)
{
struct nvmrw *nvmrw;
struct nvmrw *nvm = &ctx->nvmrw;
TEST_EQ(nvmrw_write(ctx, NVM_TYPE_RW_PRIMARY), expected_result, NULL);
if (expected_result != BDB_SUCCESS)
return;
nvmrw = (struct nvmrw *)nvmrw1;
TEST_EQ(nvmrw->min_kernel_data_key_version,
nvm->min_kernel_data_key_version, NULL);
TEST_EQ(nvmrw->min_kernel_version, nvm->min_kernel_version, NULL);
TEST_EQ(nvmrw->update_count, nvm->update_count, NULL);
}
static void test_nvm_write(void)
{
struct vba_context ctx = {
.bdb = NULL,
.secrets = &secrets,
};
struct nvmrw nvm = {
.struct_magic = NVM_RW_MAGIC,
.struct_major_version = NVM_HEADER_VERSION_MAJOR,
.struct_minor_version = NVM_HEADER_VERSION_MINOR,
.struct_size = sizeof(struct nvmrw),
.min_kernel_data_key_version = 1,
.min_kernel_version = 2,
.update_count = 3,
};
/* Test normal case */
memcpy(&ctx.nvmrw, &nvm, sizeof(nvm));
vbe_write_nvm_failure = 0;
verify_nvm_write(&ctx, BDB_SUCCESS);
/* Test write failure: once */
memcpy(&ctx.nvmrw, &nvm, sizeof(nvm));
vbe_write_nvm_failure = 1;
verify_nvm_write(&ctx, BDB_SUCCESS);
/* Test write failure: twice */
memcpy(&ctx.nvmrw, &nvm, sizeof(nvm));
vbe_write_nvm_failure = 2;
verify_nvm_write(&ctx, BDB_ERROR_NVM_WRITE);
/* Test invalid struct magic */
memcpy(&ctx.nvmrw, &nvm, sizeof(nvm));
ctx.nvmrw.struct_magic ^= 0xff;
verify_nvm_write(&ctx, BDB_ERROR_NVM_RW_MAGIC);
/* Test struct size too small */
memcpy(&ctx.nvmrw, &nvm, sizeof(nvm));
ctx.nvmrw.struct_size = NVM_RW_MIN_STRUCT_SIZE - 1;
verify_nvm_write(&ctx, BDB_ERROR_NVM_STRUCT_SIZE);
/* Test struct size too large */
memcpy(&ctx.nvmrw, &nvm, sizeof(nvm));
ctx.nvmrw.struct_size = NVM_RW_MAX_STRUCT_SIZE + 1;
verify_nvm_write(&ctx, BDB_ERROR_NVM_STRUCT_SIZE);
/* Test invalid struct version */
memcpy(&ctx.nvmrw, &nvm, sizeof(nvm));
ctx.nvmrw.struct_major_version = NVM_HEADER_VERSION_MAJOR - 1;
verify_nvm_write(&ctx, BDB_ERROR_NVM_STRUCT_VERSION);
vbe_write_nvm_failure = 0;
}
static void verify_kernel_version(uint32_t min_kernel_data_key_version,
uint32_t new_kernel_data_key_version,
uint32_t min_kernel_version,
uint32_t new_kernel_version,
int expected_result)
{
struct vba_context ctx = {
.bdb = NULL,
.secrets = &secrets,
};
struct nvmrw *nvm = (struct nvmrw *)nvmrw1;
uint32_t expected_kernel_data_key_version = min_kernel_data_key_version;
uint32_t expected_kernel_version = min_kernel_version;
int should_update = 0;
if (min_kernel_data_key_version < new_kernel_data_key_version) {
expected_kernel_data_key_version = new_kernel_data_key_version;
should_update = 1;
}
if (min_kernel_version < new_kernel_version) {
expected_kernel_version = new_kernel_version;
should_update = 1;
}
install_nvm(NVM_TYPE_RW_PRIMARY, min_kernel_data_key_version,
min_kernel_version, 0);
install_nvm(NVM_TYPE_RW_SECONDARY, 0, 0, 0);
TEST_EQ(vba_update_kernel_version(&ctx, new_kernel_data_key_version,
new_kernel_version),
expected_result, NULL);
if (expected_result != BDB_SUCCESS)
return;
/* Check data key version */
TEST_EQ(nvm->min_kernel_data_key_version,
expected_kernel_data_key_version, NULL);
/* Check kernel version */
TEST_EQ(nvm->min_kernel_version, expected_kernel_version, NULL);
/* Check update_count */
TEST_EQ(nvm->update_count, 0 + should_update, NULL);
/* Check sync if update is expected */
if (should_update)
TEST_SUCC(memcmp(nvmrw2, nvmrw1, sizeof(nvmrw1)), NULL);
}
static void test_update_kernel_version(void)
{
/* Test update: data key version */
verify_kernel_version(0, 1, 0, 0, BDB_SUCCESS);
/* Test update: kernel version */
verify_kernel_version(0, 0, 0, 1, BDB_SUCCESS);
/* Test no update: data key version */
verify_kernel_version(1, 0, 0, 0, BDB_SUCCESS);
/* Test no update: kernel version */
verify_kernel_version(0, 0, 1, 0, BDB_SUCCESS);
}
int vbe_aes256_encrypt(const uint8_t *msg, uint32_t len, const uint8_t *key,
uint8_t *out)
{
int i;
for (i = 0; i < len; i++)
out[i] = msg[i] ^ key[i % 256/8];
return BDB_SUCCESS;
}
int vbe_aes256_decrypt(const uint8_t *msg, uint32_t len, const uint8_t *key,
uint8_t *out)
{
int i;
for (i = 0; i < len; i++)
out[i] = msg[i] ^ key[i % 256/8];
return BDB_SUCCESS;
}
static void test_update_buc(void)
{
uint8_t new_buc[BUC_ENC_DIGEST_SIZE];
uint8_t enc_buc[BUC_ENC_DIGEST_SIZE];
struct nvmrw *nvm = (struct nvmrw *)nvmrw1;
struct vba_context ctx = {
.bdb = NULL,
.secrets = &secrets,
};
install_nvm(NVM_TYPE_RW_PRIMARY, 0, 1, 0);
install_nvm(NVM_TYPE_RW_SECONDARY, 1, 0, 0);
TEST_SUCC(vba_update_buc(&ctx, new_buc), NULL);
vbe_aes256_encrypt(new_buc, sizeof(new_buc), ctx.secrets->buc,
enc_buc);
TEST_SUCC(memcmp(nvm->buc_enc_digest, enc_buc, sizeof(new_buc)), NULL);
}
static void test_derive_secrets(void)
{
uint8_t test_key[sizeof(struct bdb_key) + BDB_RSA4096_KEY_DATA_SIZE];
struct bdb_key *key = (struct bdb_key *)test_key;
struct vba_context ctx = {
.bdb = NULL,
.secrets = &secrets,
};
const struct bdb_secrets expected = {
.bdb = {
0x75, 0xb6, 0x24, 0xaa, 0x72, 0x50, 0xf9, 0x33,
0x59, 0x45, 0x8d, 0xbf, 0xfa, 0x42, 0xc4, 0xb7,
0x1b, 0xff, 0xc6, 0x02, 0x02, 0x35, 0xc5, 0x1a,
0x6c, 0xdc, 0x3a, 0x63, 0xfb, 0x8b, 0xac, 0x53},
.boot_verified = {
0x40, 0xf3, 0x9b, 0xdc, 0xf6, 0xb4, 0xe8, 0xdf,
0x48, 0xc4, 0xfe, 0x02, 0xdd, 0x34, 0x06, 0xd9,
0xed, 0xd9, 0x55, 0x79, 0xf4, 0x48, 0x58, 0xbf,
0x32, 0x55, 0xba, 0x21, 0xca, 0xcc, 0x8c, 0xd1},
.boot_path = {
0xfb, 0x58, 0x89, 0x58, 0x2f, 0x54, 0xa2, 0xf7,
0x96, 0x5b, 0x69, 0x77, 0x9b, 0x67, 0x80, 0x39,
0x7a, 0xd4, 0xc5, 0x3b, 0xcf, 0x95, 0x3f, 0xec,
0x28, 0x49, 0x55, 0x49, 0x38, 0x27, 0x5d, 0x3c},
.buc = {
0x63, 0xa5, 0x30, 0xd7, 0xca, 0xe1, 0x3e, 0x2e,
0x72, 0x7e, 0x29, 0xc9, 0x37, 0x66, 0x6a, 0x63,
0x91, 0xd4, 0x8e, 0x8b, 0xbc, 0x1a, 0x7a, 0xcf,
0xc3, 0x19, 0xa0, 0x87, 0xfc, 0x4d, 0xe1, 0xe8},
};
memset(test_key, 0, sizeof(test_key));
key->struct_magic = BDB_KEY_MAGIC;
key->struct_major_version = BDB_KEY_VERSION_MAJOR;
key->struct_minor_version = BDB_KEY_VERSION_MINOR;
key->struct_size = sizeof(test_key);
key->hash_alg = BDB_HASH_ALG_SHA256;
key->sig_alg = BDB_SIG_ALG_RSA4096;
key->key_version = 1;
TEST_SUCC(vba_derive_secret(&ctx, BDB_SECRET_TYPE_BDB, NULL,
test_key, sizeof(test_key)), NULL);
TEST_SUCC(memcmp(ctx.secrets->bdb, expected.bdb, BDB_SECRET_SIZE),
NULL);
TEST_SUCC(vba_derive_secret(&ctx, BDB_SECRET_TYPE_BOOT_VERIFIED, NULL,
NULL, 0), NULL);
TEST_SUCC(memcmp(ctx.secrets->boot_verified, expected.boot_verified,
BDB_SECRET_SIZE), NULL);
TEST_SUCC(vba_derive_secret(&ctx, BDB_SECRET_TYPE_BOOT_PATH, NULL,
test_key, sizeof(test_key)), NULL);
TEST_SUCC(memcmp(ctx.secrets->boot_path, expected.boot_path,
BDB_SECRET_SIZE), NULL);
TEST_SUCC(vba_derive_secret(&ctx, BDB_SECRET_TYPE_BUC, NULL, NULL, 0),
NULL);
TEST_SUCC(memcmp(ctx.secrets->buc, expected.buc,
BDB_SECRET_SIZE), NULL);
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <keys_dir>", argv[0]);
return -1;
}
printf("Running BDB SP-RW tests...\n");
test_verify_aprw(argv[1]);
test_nvm_read();
test_nvm_write();
test_update_kernel_version();
test_update_buc();
test_derive_secrets();
return gTestSuccess ? 0 : 255;
}

View File

@ -1,504 +0,0 @@
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Unit tests
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "2sha.h"
#include "bdb.h"
#include "host.h"
#include "test_common.h"
static 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_S(bdb_check_header(&s, ssize), BDB_SUCCESS);
TEST_EQ_S(bdb_check_header(&s, ssize - 1), BDB_ERROR_BUF_SIZE);
s = sgood;
s.struct_size++;
TEST_EQ_S(bdb_check_header(&s, ssize), BDB_ERROR_BUF_SIZE);
s = sgood;
s.struct_size--;
TEST_EQ_S(bdb_check_header(&s, ssize), BDB_ERROR_STRUCT_SIZE);
s = sgood;
s.struct_magic++;
TEST_EQ_S(bdb_check_header(&s, ssize), BDB_ERROR_STRUCT_MAGIC);
s = sgood;
s.struct_major_version++;
TEST_EQ_S(bdb_check_header(&s, ssize), BDB_ERROR_STRUCT_VERSION);
s = sgood;
s.oem_area_0_size++;
TEST_EQ_S(bdb_check_header(&s, ssize), BDB_ERROR_OEM_AREA_SIZE);
s = sgood;
s.bdb_size = ssize - 1;
TEST_EQ_S(bdb_check_header(&s, ssize), BDB_ERROR_BDB_SIZE);
}
static 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_S(bdb_check_key(&s, ssize), BDB_SUCCESS);
TEST_EQ_S(bdb_check_key(&s, ssize - 1), BDB_ERROR_BUF_SIZE);
s = sgood;
s.struct_size++;
TEST_EQ_S(bdb_check_key(&s, ssize), BDB_ERROR_BUF_SIZE);
s = sgood;
s.struct_size--;
TEST_EQ_S(bdb_check_key(&s, ssize), BDB_ERROR_STRUCT_SIZE);
s = sgood;
s.struct_magic++;
TEST_EQ_S(bdb_check_key(&s, ssize), BDB_ERROR_STRUCT_MAGIC);
s = sgood;
s.struct_major_version++;
TEST_EQ_S(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_S(bdb_check_key(&s, ssize), BDB_ERROR_DESCRIPTION);
/* Data AFTER the null is explicitly allowed, though */
s = sgood;
s.description[100] = 'x';
TEST_EQ_S(bdb_check_key(&s, ssize), BDB_SUCCESS);
/* Limited algorithm choices at present */
s = sgood;
s.hash_alg = BDB_HASH_ALG_INVALID;
TEST_EQ_S(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_S(bdb_check_key(&s, ssize), BDB_SUCCESS);
s = sgood;
s.sig_alg = BDB_SIG_ALG_INVALID;
TEST_EQ_S(bdb_check_key(&s, ssize), BDB_ERROR_SIG_ALG);
}
static 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_S(bdb_check_sig(&s, ssize), BDB_SUCCESS);
TEST_EQ_S(bdb_check_sig(&s, ssize - 1), BDB_ERROR_BUF_SIZE);
s = sgood;
s.struct_size++;
TEST_EQ_S(bdb_check_sig(&s, ssize), BDB_ERROR_BUF_SIZE);
s = sgood;
s.struct_size--;
TEST_EQ_S(bdb_check_sig(&s, ssize), BDB_ERROR_STRUCT_SIZE);
s = sgood;
s.struct_magic++;
TEST_EQ_S(bdb_check_sig(&s, ssize), BDB_ERROR_STRUCT_MAGIC);
s = sgood;
s.struct_major_version++;
TEST_EQ_S(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_S(bdb_check_sig(&s, ssize), BDB_ERROR_DESCRIPTION);
/* Data AFTER the null is explicitly allowed, though */
s = sgood;
s.description[100] = 'x';
TEST_EQ_S(bdb_check_sig(&s, ssize), BDB_SUCCESS);
/* Limited algorithm choices at present */
s = sgood;
s.hash_alg = BDB_HASH_ALG_INVALID;
TEST_EQ_S(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_S(bdb_check_sig(&s, ssize), BDB_SUCCESS);
s = sgood;
s.sig_alg = BDB_SIG_ALG_INVALID;
TEST_EQ_S(bdb_check_sig(&s, ssize), BDB_ERROR_SIG_ALG);
}
static 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_S(bdb_check_data(&s, ssize), BDB_SUCCESS);
TEST_EQ_S(bdb_check_data(&s, ssize - 1), BDB_ERROR_BUF_SIZE);
s = sgood;
s.struct_size--;
TEST_EQ_S(bdb_check_data(&s, ssize), BDB_ERROR_STRUCT_SIZE);
s = sgood;
s.struct_magic++;
TEST_EQ_S(bdb_check_data(&s, ssize), BDB_ERROR_STRUCT_MAGIC);
s = sgood;
s.struct_major_version++;
TEST_EQ_S(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_S(bdb_check_data(&s, ssize), BDB_ERROR_DESCRIPTION);
/* Data AFTER the null is explicitly allowed, though */
s = sgood;
s.description[100] = 'x';
TEST_EQ_S(bdb_check_data(&s, ssize), BDB_SUCCESS);
s = sgood;
s.hash_entry_size--;
TEST_EQ_S(bdb_check_data(&s, ssize), BDB_ERROR_HASH_ENTRY_SIZE);
s = sgood;
s.oem_area_1_size++;
TEST_EQ_S(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_S(bdb_check_data(&s, ssize), BDB_SUCCESS);
s.signed_size--;
TEST_EQ_S(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()
*/
static void check_bdb_verify(const char *key_dir)
{
uint8_t oem_area_0[32] = "Some OEM area.";
uint8_t oem_area_1[64] = "Some other OEM area.";
char filename[1024];
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 = (char *)"The header sig",
.data_sig_description = (char *)"The data sig",
.data_description = (char *)"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 */
snprintf(filename, sizeof(filename), "%s/bdbkey.keyb", key_dir);
p.bdbkey = bdb_create_key(filename, 100, "BDB key");
snprintf(filename, sizeof(filename), "%s/datakey.keyb", key_dir);
p.datakey = bdb_create_key(filename, 200, "datakey");
snprintf(filename, sizeof(filename), "%s/bdbkey.pem", key_dir);
p.private_bdbkey = read_pem(filename);
snprintf(filename, sizeof(filename), "%s/datakey.pem", key_dir);
p.private_datakey = read_pem(filename);
if (!p.bdbkey || !p.datakey || !p.private_bdbkey || !p.private_datakey) {
fprintf(stderr, "Unable to load test keys\n");
exit(2);
}
vb2_digest_buffer((uint8_t *)p.bdbkey, p.bdbkey->struct_size,
VB2_HASH_SHA256,
bdbkey_digest, BDB_SHA256_DIGEST_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_S(bdb_verify(h, hsize, bdbkey_digest), BDB_SUCCESS);
/* It can accept a NULL pointer as bdb_key_digest */
memcpy(h, hgood, hsize);
TEST_EQ_S(bdb_verify(h, hsize, NULL), BDB_GOOD_OTHER_THAN_KEY);
/* Mangle each component in turn */
memcpy(h, hgood, hsize);
h->struct_magic++;
TEST_EQ_S(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_HEADER);
memcpy(h, hgood, hsize);
((struct bdb_key *)bdb_get_bdbkey(h))->struct_magic++;
TEST_EQ_S(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_BDBKEY);
memcpy(h, hgood, hsize);
((struct bdb_key *)bdb_get_bdbkey(h))->key_version++;
TEST_EQ_S(bdb_verify(h, hsize, bdbkey_digest), BDB_GOOD_OTHER_THAN_KEY);
memcpy(h, hgood, hsize);
h->oem_area_0_size += hsize;
TEST_EQ_S(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_OEM_AREA_0);
memcpy(h, hgood, hsize);
((struct bdb_key *)bdb_get_datakey(h))->struct_magic++;
TEST_EQ_S(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATAKEY);
memcpy(h, hgood, hsize);
((struct bdb_key *)bdb_get_datakey(h))->struct_size += 4;
TEST_EQ_S(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_S(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_S(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_S(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_datakey(h))->key_version++;
TEST_EQ_S(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_S(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_S(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_S(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_S(bdb_verify(h, hsize, bdbkey_digest),
BDB_ERROR_DATA_CHECK_SIG);
memcpy(h, hgood, hsize);
((struct bdb_sig *)bdb_get_data_sig(h))->signed_size--;
TEST_EQ_S(bdb_verify(h, hsize, bdbkey_digest),
BDB_ERROR_DATA_SIGNED_SIZE);
memcpy(h, hgood, hsize);
((struct bdb_sig *)bdb_get_data_sig(h))->sig_data[0] ^= 0x42;
TEST_EQ_S(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_S(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_S(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_S(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG);
memcpy(h, hgood, hsize);
((struct bdb_hash *)bdb_get_hash_by_type(h, BDB_DATA_SP_RW))->offset++;
TEST_EQ_S(bdb_verify(h, hsize, bdbkey_digest), BDB_ERROR_DATA_SIG);
memcpy(h, hgood, hsize);
((struct bdb_hash *)bdb_get_hash_by_type(h, BDB_DATA_AP_RW))
->digest[0] ^= 0x96;
TEST_EQ_S(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_S(h->bdb_load_address, p.bdb_load_address);
TEST_EQ_S(strcmp(bdb_get_bdbkey(h)->description, p.bdbkey->description),
0);
TEST_EQ_S(bdb_get_bdbkey(h)->key_version, p.bdbkey->key_version);
TEST_EQ_S(h->oem_area_0_size, p.oem_area_0_size);
TEST_EQ_S(memcmp(bdb_get_oem_area_0(h), oem_area_0, sizeof(oem_area_0)),
0);
TEST_EQ_S(strcmp(bdb_get_datakey(h)->description, p.datakey->description),
0);
TEST_EQ_S(bdb_get_datakey(h)->key_version, p.datakey->key_version);
TEST_EQ_S(strcmp(bdb_get_header_sig(h)->description,
p.header_sig_description), 0);
TEST_EQ_S(strcmp(bdb_get_data(h)->description, p.data_description), 0);
TEST_EQ_S(bdb_get_data(h)->data_version, p.data_version);
TEST_EQ_S(bdb_get_data(h)->num_hashes, p.num_hashes);
TEST_EQ_S(bdb_get_data(h)->oem_area_1_size, p.oem_area_1_size);
TEST_EQ_S(memcmp(bdb_get_oem_area_1(h), oem_area_1, sizeof(oem_area_1)),
0);
TEST_EQ_S(strcmp(bdb_get_data_sig(h)->description,
p.data_sig_description), 0);
/* Test getting hash entries */
memcpy(h, hgood, hsize);
TEST_EQ_S(bdb_get_hash_by_type(h, BDB_DATA_SP_RW)
->offset, hash[0].offset);
TEST_EQ_S(bdb_get_hash_by_index(h, 0)
->offset, hash[0].offset);
TEST_EQ_S(bdb_get_hash_by_type(h, BDB_DATA_AP_RW)
->offset, hash[1].offset);
TEST_EQ_S(bdb_get_hash_by_index(h, 1)
->offset, hash[1].offset);
/* And a non-existent one */
TEST_PTR_EQ(bdb_get_hash_by_type(h, BDB_DATA_MCU), NULL, NULL);
TEST_PTR_EQ(bdb_get_hash_by_index(h, 2), NULL, NULL);
/*
* 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.datakey);
RSA_free(p.private_bdbkey);
RSA_free(p.private_datakey);
free(hgood);
free(h);
}
/*****************************************************************************/
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <keys_dir>", argv[0]);
return -1;
}
printf("Running BDB tests...\n");
check_header_tests();
check_key_tests();
check_sig_tests();
check_data_tests();
check_bdb_verify(argv[1]);
printf("All tests passed!\n");
return gTestSuccess ? 0 : 255;
}

Binary file not shown.

View File

@ -40,7 +40,6 @@ export OUTDIR
# These are the scripts to run. Binaries are invoked directly by the Makefile.
TESTS="
${SCRIPTDIR}/test_bdb.sh
${SCRIPTDIR}/test_create.sh
${SCRIPTDIR}/test_dump_fmap.sh
${SCRIPTDIR}/test_gbb_utility.sh

View File

@ -1,100 +0,0 @@
#!/bin/bash -eux
# 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.
me=${0##*/}
TMP="$me.tmp"
# Work in scratch directory
cd "$OUTDIR"
BDB_FILE=bdb.bin
TESTKEY_DIR=${SRCDIR}/tests/testkeys
TESTDATA_DIR=${SRCDIR}/tests/testdata
BDBKEY_PUB=${TESTKEY_DIR}/bdbkey.keyb
BDBKEY_PRI=${TESTKEY_DIR}/bdbkey.pem
DATAKEY_PUB=${TESTKEY_DIR}/datakey.keyb
DATAKEY_PRI=${TESTKEY_DIR}/datakey.pem
BDBKEY_DIGEST=${TESTDATA_DIR}/bdbkey_digest.bin
DATAKEY_DIGEST=${TESTDATA_DIR}/datakey_digest.bin
DATA_FILE=${TESTDATA_DIR}/sp-rw.bin
declare -i num_hash
# Verify a BDB
#
# $1: Key digest file
# $2: Any remaining option passed to futility bdb --verify
verify() {
local key_digest=${1:-${BDBKEY_DIGEST}}
local extra_option=${2:-}
${FUTILITY} bdb --verify ${BDB_FILE} --key_digest ${key_digest} \
${extra_option}
}
get_num_hash() {
printf "%d" \
$(${FUTILITY} show ${BDB_FILE} \
| grep '# of Hashes' | cut -d':' -f 2)
}
# Tests field matches a specified value in a BDB
# e.g. check_field 'Data Version:' 2 returns error if the data version isn't 2.
check_field() {
# Find the field
x=$(${FUTILITY} show ${BDB_FILE} | grep "${1}")
[ "${x}" ] || return 1
# Remove the field name
x=${x##*:}
[ "${x}" ] || return 1
# Remove the leading and trailing spaces
x=${x//[[:blank:]]/}
[ "${x}" == "${2}" ] || return 1
}
# Demonstrate bdb --create can create a valid BDB
load_address=0x60061ec0de
${FUTILITY} bdb --create ${BDB_FILE} \
--bdbkey_pri ${BDBKEY_PRI} --bdbkey_pub ${BDBKEY_PUB} \
--datakey_pub ${DATAKEY_PUB} --datakey_pri ${DATAKEY_PRI} \
--load_address ${load_address}
verify
check_field "Load Address:" ${load_address}
# Demonstrate bdb --add can add a new hash
num_hash=$(get_num_hash)
${FUTILITY} bdb --add ${BDB_FILE} \
--data ${DATA_FILE} --partition 1 --type 2 --offset 3 --load_address 4
# Use futility show command to verify the hash is added
num_hash+=1
[ $(get_num_hash) -eq $num_hash ]
# TODO: verify partition, type, offset, and load_address
# Demonstrate futility bdb --resign can resign the BDB
data_version=2
${FUTILITY} bdb --resign ${BDB_FILE} --datakey_pri ${DATAKEY_PRI} \
--data_version $data_version
verify
check_field "Data Version:" $data_version
# Demonstrate futility bdb --resign can resign with a new data key
# Note resigning with a new data key requires a private BDB key as well
${FUTILITY} bdb --resign ${BDB_FILE} \
--bdbkey_pri ${BDBKEY_PRI} \
--datakey_pri ${BDBKEY_PRI} --datakey_pub ${BDBKEY_PUB}
verify
# Demonstrate futility bdb --resign can resign with a new BDB key
${FUTILITY} bdb --resign ${BDB_FILE} \
--bdbkey_pri ${DATAKEY_PRI} --bdbkey_pub ${DATAKEY_PUB}
verify ${DATAKEY_DIGEST}
# Demonstrate futility bdb --verify can return success when key digest doesn't
# match but --ignore_key_digest is specified.
verify ${BDBKEY_DIGEST} --ignore_key_digest
# cleanup
rm -rf ${TMP}*
exit 0

View File

@ -37,7 +37,6 @@ static struct {
{FILE_TYPE_VB2_PRIVKEY, "tests/futility/data/sample.vbprik2"},
{FILE_TYPE_PEM, "tests/testkeys/key_rsa2048.pem"},
{FILE_TYPE_USBPD1, "tests/futility/data/zinger_mp_image.bin"},
{FILE_TYPE_BDB, "tests/futility/data/bdb.bin"},
{FILE_TYPE_RWSIG, }, /* need a test for this */
};
BUILD_ASSERT(ARRAY_SIZE(test_case) == NUM_FILE_TYPES);

View File

@ -44,7 +44,6 @@ test_case "pubkey21" "tests/futility/data/sample.vbpubk2"
test_case "prikey21" "tests/futility/data/sample.vbprik2"
test_case "pem" "tests/testkeys/key_rsa2048.pem"
test_case "pem" "tests/testkeys/key_rsa8192.pub.pem"
test_case "bdb" "tests/futility/data/bdb.bin"
# Expect failure here.
fail_case "/Sir/Not/Appearing/In/This/Film"

View File

@ -1 +0,0 @@
ַ‰VֲN<D6B2>"I<>sv<18>מא}ן<6B>±b£… '“Tנ<54><D7A0>

View File

@ -1,33 +0,0 @@
-----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-----

Binary file not shown.

View File

@ -1,51 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAm5v71oqFynujT4FVq5lKaYxpmKfXdeBNKDmLzgu7fXLUKaEq
TGEDsseE5qyaaP+dmTnQKfne7G31zgf46//YEl+u5Gt/S4oAgYyvs3rjymzD5kVO
LEAzgrIXAwyhDFARRzAFWos43hypunHGvu4fDBAzZ3zGVulhjgAzD/gNjToVYCP7
bj6kTaDx1u9siCKdYN09vGwSUt9WuV+yort7kns/B8ArVxt3bFSjsAxuWel/dJyL
wCMQ9XAxdgWpg3RBUsK/KgekQybPLrhLYJn1AeOApwzJ4HoJSqU/1jCEaGrKA/Kt
CRXiurZz6lBi7sElsigjBvEZH0iCmmRgH3Oi/cbpHIs1C6YHvCCbO90ntwgtDf0+
2WJtFtbGt5Do3CXri0tcsXBWqISSK3VzzjHH691BVwLuoBvF1XICMEjmq9aJ+Mdb
Ee4E+GU8TV9NnRnuYyOUoxeisyXiArUUI9+1qL6pIgulTlY2Ch51QZY5n2aYY97P
tosNotbSylMrLvWXGiiQWxux12eOnB3c/3wNYWey8Km4cmOhEOYz7hLz2r1uIoC/
SzM5wLnnTEQmaiUDNV9R3Gj3E3xkpTq3UNSSPsV7k8lInMtWqzps6aTvBw1k6i6C
UvWbEZqmt/0bimQHOEdg3OrJjQpwTKSp4ouSyVu0IphDwy1yjKCfNWKRzrUCAwEA
AQKCAgEAlbfvBu0g7UEoUEbQdtp2jjdbIlXbKL83fYxgx07ihkEFgUhfuj1doZX2
eTt5Fa1bpSHK95hCtJjX9/QTvH3dF1CYpY4IXFXbRspmAvoqUYl0swnbvRfId+eB
3J06Fu6ysRuzCvsJLCvH4mu2Hd5eYOz1iIy1CMpj4oyulJ7F6ywHhQkZ0WjUDRzd
kz+p3RHw+lHkJHaW6sWYW6OH7KsWqkmKy5pKGPWEYebN14UeZ8QRrdExZRxYJM5d
yICKKMCiWU6nP3k6wqGElh8b50Y6RibukcvsMN86MWftk9f6jbyxwjqr4iH8lEkY
HkpZ5f5QlqmnifZPhZnujz4kfh50oteC2QPQ0hrNYCDG75wuiNX/vINVfrKG0ddg
iQDFqyQyQirxCGQgy7Wto08KAzKt146ST28N+kdF/kY14ou5f5+GlWQJcnqdHd2p
R25MueXUsY3I63dULR6k02Y6M7Tzo39lYe0LV82+G0A3iGpI+eM7xw/sQDNb2sQs
jCcz7XPrfTomrVJaW1FkM8vM6eWhuhAyDFP+unz0aMnKrkUrarh4t9QpriiCjm3E
HV2Hc7t/Do/w+B3rywKy3PE2yO49eGz20um0JqWcAbGDZY2vDnyV+/xibxqaIZUo
saI/btlyvCv00812momkX/qWwS+1GHvyYYcpIg0XQbZY1TvEi8ECggEBAM6LTfVu
MKNwW/QdZ6pxKl/Oy8zlb1o8HET5hKCdhoMvpwlvpO2qSvlCxH3VZTmcXIXd+Mkd
e4OZrzeMLVxMd64xP10k2ui/O2/8G38xmpMGqZihc+LnY6JgajujfAQHljOgrAJL
xzO2Gk4oWX72oA6jqP8LZkRp/9acTWqBTKs6MOdrfn6I3k0urBB29+jcbqFAfgMx
hfcTKAOHYmg/SeEZDvKP6fRDJGMGXqJ4TaBXjsnhNGCjGmuCqJhxxIGCI/AVK10B
CjEboo9vACzNE1/JMxH8aT5up7e+7R/WoiJ5e3jlvSKmcO7KiR27JVsAlZeIddKd
LzG9KKZ8Yla0U3MCggEBAMDefKVTqSPaG7cmAQGtXrbBDLdCWIaT08v+kMw/drlq
NqLD+1ct098iFwRtKaYPERPKqNtxfJdkUMqWELBWV2Sq4Fi+JVXjGOUctP7Atd2x
6NJ9xHqQKQwKUv0/9jN5Oie9sFvsLwPAJNOJej1BrmvPZvc0CoMyOjkmxEhYu3qG
i26ZTSZSCTrbE8eAL0EJdH0gB7Ryuks8O+jEF7eXuZLZyN3AromISJtmLVlMFZ7m
+0sQnZQqwNF+BIrOgO+3R61jjNzCJbFo7frvRIlDSnrbmWp6sYns1cjhZiKCnO78
RgDiaJcuceqsalgBZi8/Fmam2IPeqhvTNg+5alCuWzcCggEAXFjglFmeGZVFJ9J1
5TkPzyJw8L2smdXCdfxyFjYYTFNkBc4LGdBIEUaPAAwHZEjK/XePoqwx61cthlKA
fYIbCKEwSX8O+X13H8zCpo4RJKeX8IxPeiYm4BTnqp6f9lVGDPNLtQMYn8BN5qAX
07KFQcZe6xm3seMK5nOgEXyaQPyVnQLs3bpoWm4BtKLcmRrlw+dH8DmWQjAoddt0
XlPdvm0rx7wcyH+0pynT6iSL4KMFTrIIbyS9zU/v/ajwSU9crh1o8/5hBi/q8OKa
W22dufgFg4ctryJejsMo1lFq0KssT5O4iuOMHtgjkk14mEWcnNIAjBiHX1/J6xY2
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-----

View File

@ -1,189 +0,0 @@
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "2sha.h"
#include "bdb.h"
#include "bdb_api.h"
#include "host.h"
static f_extend extend = vb2_sha256_extend;
static void help(void)
{
fprintf(stderr,
"Usage: bdb_extend -b bdb_file -s bds_file "
"[-d digest_file] [-m]\n"
"\n"
"Extends BDS based on a given BDB. When '-m' is given, a "
"MVMAP2315's sha256_extend algorithm will be used. When "
"digest_file is specified, the validity of the BDB key is "
"checked and the secrets will be derived differently.\n");
}
#define PACK32(str, x) \
{ \
*(x) = ((uint32_t) *((str) + 3) ) \
| ((uint32_t) *((str) + 2) << 8) \
| ((uint32_t) *((str) + 1) << 16) \
| ((uint32_t) *((str) + 0) << 24); \
}
/**
* MVMAP2315's implementation of sha256 extend
*
* This performs incorrect but still cryptographically secure sha256 extension.
* This is provided for test purpose only.
*
* See vb2_sha256_extend for details on arguments.
*/
static void mvmap2315_sha256_extend(const uint8_t *from, const uint8_t *by,
uint8_t *to)
{
struct vb2_sha256_context dc;
int i;
vb2_sha256_init(&dc);
for (i = 0; i < 8; i++) {
PACK32(from, &dc.h[i]);
from += 4;
}
vb2_sha256_update(&dc, by, VB2_SHA256_BLOCK_SIZE);
vb2_sha256_finalize(&dc, to);
}
static void dump_secret(const uint8_t *secret, const char *label)
{
int i;
printf("%s = {", label);
for (i = 0; i < BDB_SECRET_SIZE; i++) {
if (i % 8 == 0)
printf("\n\t");
else
printf(" ");
printf("0x%02x,", secret[i]);
}
printf("\n}\n");
}
static void dump_secrets(struct vba_context *ctx, const uint8_t *wsr)
{
dump_secret(ctx->secrets->bdb, "bdb");
dump_secret(ctx->secrets->boot_path, "boot_path");
dump_secret(ctx->secrets->boot_verified, "boot_verified");
dump_secret(ctx->secrets->nvm_wp, "nvm_wp");
dump_secret(ctx->secrets->nvm_rw, "nvm_rw");
dump_secret(wsr, "wsr");
}
static int derive_secrets(struct vba_context *ctx,
const uint8_t *bdb, uint8_t *wsr)
{
struct bdb_secrets secrets;
memset(&secrets, 0, sizeof(secrets));
ctx->secrets = &secrets;
if (vba_extend_secrets_ro(ctx, bdb, wsr, extend)) {
fprintf(stderr, "ERROR: Failed to derive secrets\n");
return -1;
}
fprintf(stderr, "LOG: Secrets are derived as follows\n");
dump_secrets(ctx, wsr);
return 0;
}
int main(int argc, char *argv[])
{
struct vba_context ctx;
uint8_t *bdb, *bds;
uint8_t *key_digest = NULL;
uint32_t bdb_size, bds_size, digest_size;
const char *bdb_file = NULL;
const char *digest_file = NULL;
const char *bds_file = NULL;
int rv;
int opt;
while ((opt = getopt(argc, argv, "b:d:hms:")) != -1) {
switch(opt) {
case 'b':
bdb_file = optarg;
break;
case 'd':
digest_file = optarg;
break;
case 'h':
help();
return 0;
case 'm':
extend = mvmap2315_sha256_extend;
break;
case 's':
bds_file = optarg;
break;
default:
help();
return -1;
}
}
if (!bdb_file || !bds_file) {
fprintf(stderr, "ERROR: BDB and BDS aren't specified\n\n");
help();
return -1;
}
/* Read BDB */
bdb = read_file(bdb_file, &bdb_size);
if (!bdb) {
fprintf(stderr, "ERROR: Unable to read %s\n", bdb_file);
return -1;
}
/* Read BDS */
bds = read_file(bds_file, &bds_size);
if (!bds) {
fprintf(stderr, "ERROR: Unable to read %s\n", bds_file);
return -1;
}
if (bds_size != BDB_SECRET_SIZE) {
fprintf(stderr, "ERROR: Invalid BDS size: %d\n", bds_size);
return -1;
}
/* Read key digest if provided */
if (digest_file) {
key_digest = read_file(digest_file, &digest_size);
if (!key_digest) {
fprintf(stderr,
"ERROR: Unable to read %s\n", digest_file);
return -1;
}
}
/* Verify BDB and set a flag based on the result */
memset(&ctx, 0, sizeof(ctx));
rv = bdb_verify(bdb, bdb_size, key_digest);
if (rv) {
if (rv != BDB_GOOD_OTHER_THAN_KEY) {
fprintf(stderr, "ERROR: BDB is invalid: %d\n", rv);
return -1;
}
fprintf(stderr,
"WARNING: BDB is valid but key digest doesn't match\n");
} else {
ctx.flags |= VBA_CONTEXT_FLAG_BDB_KEY_EFUSED;
fprintf(stderr, "BDB is successfully verified by eFused key\n");
}
/* Derive secrets and dump the values */
return derive_secrets(&ctx, bdb, bds);
}