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:
parent
38f135e83e
commit
34abb32ed2
83
Makefile
83
Makefile
|
@ -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
|
||||
|
|
27
bdb/LICENSE
27
bdb/LICENSE
|
@ -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.
|
130
bdb/Makefile
130
bdb/Makefile
|
@ -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}
|
30
bdb/README
30
bdb/README
|
@ -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
398
bdb/bdb.c
|
@ -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
181
bdb/bdb.h
|
@ -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_ */
|
232
bdb/bdb_create.c
232
bdb/bdb_create.c
|
@ -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();
|
||||
}
|
268
bdb/bdb_struct.h
268
bdb/bdb_struct.h
|
@ -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_ */
|
||||
|
492
bdb/bdb_test.c
492
bdb/bdb_test.c
|
@ -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;
|
||||
}
|
200
bdb/dump_rsa.c
200
bdb/dump_rsa.c
|
@ -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;
|
||||
}
|
17
bdb/ecdsa.c
17
bdb/ecdsa.c
|
@ -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;
|
||||
}
|
347
bdb/host.c
347
bdb/host.c
|
@ -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;
|
||||
}
|
171
bdb/host.h
171
bdb/host.h
|
@ -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
339
bdb/rsa.c
|
@ -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
210
bdb/sha.c
|
@ -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;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
This is a pretend ap-rw.bin image. Exciting.
|
|
@ -1 +0,0 @@
|
|||
This is some OEM0 data.
|
|
@ -1 +0,0 @@
|
|||
This is some OEM1 data of some sort
|
|
@ -1 +0,0 @@
|
|||
This is a pretend sp-rw.bin image.
|
|
@ -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.
|
@ -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-----
|
|
@ -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.
|
@ -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-----
|
|
@ -1,10 +1,6 @@
|
|||
|
||||
Here's what's what in the firmware/ directory.
|
||||
|
||||
bdb/
|
||||
|
||||
Code for managing Boot Descriptor Blocks (BDB).
|
||||
|
||||
include/
|
||||
lib/
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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
|
|
@ -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
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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(¶ms, 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(¶ms);
|
||||
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");
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
504
tests/bdb_test.c
504
tests/bdb_test.c
|
@ -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.
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
ַ‰VֲN<D6B2>"I<>sv<18>מא}ןkֽ<6B>±b£…
'“Tנ<54><D7A0>
|
|
@ -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.
|
@ -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-----
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue