mirror of
https://github.com/Dasharo/coreboot.git
synced 2026-03-06 14:43:26 -08:00
build.sh uses _ instead of - to separate components. Change-Id: I06d11509c130eb1556b907e0d8393cd995d118c1 Upstream-Status: Inappropriate [Dasharo downstream] Signed-off-by: Wiktor Mowinski <wiktor.mowinski@3mdeb.com> Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
364 lines
9.9 KiB
Bash
Executable File
364 lines
9.9 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -e
|
|
|
|
edk_workspace=payloads/external/edk2/workspace
|
|
edk_basetools=${edk_workspace}/Dasharo/BaseTools
|
|
edk_tools=${edk_basetools}/BinWrappers/PosixLike
|
|
edk_scripts=${edk_basetools}/Scripts
|
|
|
|
function die() {
|
|
echo error: "$@" 1>&2
|
|
exit 1
|
|
}
|
|
|
|
function confirm() {
|
|
local msg=$1
|
|
read -r -n1 -p "$msg [y/N] "
|
|
echo
|
|
if [ "$REPLY" != y ]; then
|
|
die "operation cancelled by the user"
|
|
fi
|
|
}
|
|
|
|
function print_banner() {
|
|
local msg=$1
|
|
|
|
echo
|
|
echo ========== "${msg^^*}" ==========
|
|
echo
|
|
}
|
|
|
|
function info() {
|
|
echo info: "$@"
|
|
}
|
|
|
|
function print_usage() {
|
|
echo "Usage: $(basename "$0") subcommand [subcommand-args...]"
|
|
echo
|
|
echo 'Subcommands:'
|
|
echo ' box export standalone GenerateCapsule out of EDK2'
|
|
echo ' help print this message'
|
|
echo ' keygen use OpenSSL to auto-generate test keys suitable for signing'
|
|
echo ' positional argument: directory-path'
|
|
echo ' make build a capsule, options:'
|
|
echo ' -t root-certificate-file'
|
|
echo ' -o subroot-certificate-file'
|
|
echo ' -s signing-certificate-file'
|
|
echo ' -b (the flag adds battery check DXE into the capsule)'
|
|
}
|
|
|
|
function help_subcommand() {
|
|
print_usage
|
|
}
|
|
|
|
function keygen_subcommand() {
|
|
local dir=$1
|
|
|
|
if [ $# -ne 1 ]; then
|
|
echo "Usage: $(basename "$0") keygen keys-dir"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -e "$dir" ]; then
|
|
confirm "OK to remove '$dir'?"
|
|
rm -r "$dir"
|
|
fi
|
|
|
|
mkdir "$dir"
|
|
cd "$dir"
|
|
|
|
# this is needed to make `openssl req` work non-interactively
|
|
cat > "openssl.cnf" << 'EOF'
|
|
.include /etc/ssl/openssl.cnf
|
|
|
|
[ CA_default ]
|
|
dir = ./test-ca
|
|
certs = $dir/certs
|
|
crl_dir = $dir/crl
|
|
database = $dir/index.txt
|
|
new_certs_dir = $dir/newcerts
|
|
certificate = $dir/cacert.pem
|
|
serial = $dir/serial
|
|
crlnumber = $dir/crlnumber
|
|
crl = $dir/crl.pem
|
|
private_key = $dir/private/cakey.pem
|
|
|
|
[ req_root ]
|
|
prompt = no
|
|
distinguished_name = req_root_dn
|
|
x509_extensions = v3_ca
|
|
string_mask = utf8only
|
|
[ req_root_dn ]
|
|
countryName = XX
|
|
stateOrProvinceName = Province
|
|
organizationName = Org
|
|
commonName = root
|
|
|
|
[ req_sub ]
|
|
prompt = no
|
|
distinguished_name = req_sub_dn
|
|
x509_extensions = v3_ca
|
|
string_mask = utf8only
|
|
[ req_sub_dn ]
|
|
countryName = XX
|
|
stateOrProvinceName = Province
|
|
organizationName = Org
|
|
commonName = sub
|
|
|
|
[ req_sign ]
|
|
prompt = no
|
|
distinguished_name = req_sign_dn
|
|
x509_extensions = v3_ca
|
|
string_mask = utf8only
|
|
[ req_sign_dn ]
|
|
countryName = XX
|
|
stateOrProvinceName = Province
|
|
organizationName = Org
|
|
commonName = sign
|
|
EOF
|
|
|
|
print_banner 'Making root certificate'
|
|
|
|
# make root certificate
|
|
openssl genrsa -out root.p8e 2048
|
|
openssl req -config openssl.cnf -section req_root -new -x509 -days 3650 -key root.p8e -out root.pub.pem
|
|
|
|
# dump certificate information like `openssl ca` does for completeness
|
|
openssl x509 -in root.pub.pem -text -certopt no_sigdump,no_pubkey -nocert
|
|
|
|
# create a CA
|
|
mkdir -p test-ca/newcerts
|
|
touch test-ca/index.txt
|
|
echo 01 > test-ca/serial
|
|
|
|
openssl x509 -in root.pub.pem -out root.cer -outform DER
|
|
python "${OLDPWD}/${edk_scripts}/BinToPcd.py" \
|
|
-p gFmpDevicePkgTokenSpaceGuid.PcdFmpDevicePkcs7CertBufferXdr \
|
|
-i root.cer -x -o CapsuleRootKey.inc
|
|
|
|
print_banner 'Making subroot certificate'
|
|
|
|
# make subroot certificate
|
|
openssl genrsa -out sub.p8e 2048
|
|
openssl req -config openssl.cnf -section req_sub -new -key sub.p8e -out sub.csr
|
|
yes | openssl ca -config openssl.cnf -extensions v3_ca -in sub.csr -days 3650 -cert root.pub.pem -keyfile root.p8e -notext -out sub.pub.pem
|
|
|
|
print_banner 'Making signing certificate'
|
|
|
|
# make signing certificate
|
|
openssl genrsa -out sign.p8e 2048
|
|
openssl req -config openssl.cnf -section req_sign -new -key sign.p8e -out sign.csr
|
|
yes | openssl ca -config openssl.cnf -in sign.csr -days 3650 -cert sub.pub.pem -keyfile sub.p8e -notext -out sign.crt
|
|
|
|
# create binary PKCS12 (certificate + private key) from signing certificate
|
|
openssl pkcs12 -export -passout pass: -inkey sign.p8e -in sign.crt -out sign.pfx
|
|
# now convert binary PKCS12 into PEM PKCS12 with no password
|
|
openssl pkcs12 -in sign.pfx -passin pass: -nodes -out sign.p12
|
|
|
|
print_banner 'Usage examples'
|
|
|
|
echo "Installing root certificate (before build):"
|
|
echo " cp $dir/CapsuleRootKey.inc ${edk_workspace}/Dasharo/DasharoPayloadPkg/"
|
|
echo
|
|
echo "Signing a capsule (after build):"
|
|
echo " $0 make -t $dir/root.pub.pem -o $dir/sub.pub.pem -s $dir/sign.p12"
|
|
}
|
|
|
|
function check_cert() {
|
|
local name=$1
|
|
local path=$2
|
|
|
|
if [ -z "$path" ]; then
|
|
die "$name certificate wasn't provided"
|
|
fi
|
|
|
|
if [ ! -f "$path" ]; then
|
|
die "can't read $name certificate at '$path'"
|
|
fi
|
|
}
|
|
|
|
function make_subcommand() {
|
|
if [ ! -f .config ]; then
|
|
die "no '.config' file in current directory"
|
|
fi
|
|
if [ ! -f build/coreboot.rom ]; then
|
|
die "no 'build/coreboot.rom'; the firmware wasn't built?"
|
|
fi
|
|
if [ ! build/coreboot.rom -nt .config ]; then
|
|
die "'build/coreboot.rom' is not newer than .config'; need a re-build?"
|
|
fi
|
|
if [ ! -x "${edk_tools}/GenerateCapsule" ]; then
|
|
die "'${edk_tools}/GenerateCapsule' can't be executed"
|
|
fi
|
|
|
|
# import coreboot's config file replacing $(...) with ${...}
|
|
while read -r line; do
|
|
if ! eval "$line"; then
|
|
die "failed to source '.config'"
|
|
fi
|
|
done <<< "$(sed 's/\$(\([^)]\+\))/${\1}/g' .config)"
|
|
|
|
if [ "$CONFIG_DRIVERS_EFI_UPDATE_CAPSULES" != y ]; then
|
|
die "current board configuration lacks support of update capsules"
|
|
fi
|
|
|
|
# Option names match terminology of GenerateCapsule which conveniently start
|
|
# with different letters:
|
|
# * t - trusted
|
|
# * o - other
|
|
# * s - signer
|
|
local root_cert sub_cert sign_cert include_battery_check
|
|
while getopts "t:o:s:b" OPTION; do
|
|
case $OPTION in
|
|
t) root_cert="$OPTARG" ;;
|
|
o) sub_cert="$OPTARG" ;;
|
|
s) sign_cert="$OPTARG" ;;
|
|
b) include_battery_check=1 ;;
|
|
*) exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
check_cert root "$root_cert"
|
|
check_cert sub "$sub_cert"
|
|
check_cert sign "$sign_cert"
|
|
|
|
local cap_file=${CONFIG_MAINBOARD_DIR//[\/-]/_}
|
|
if [[ ${CONFIG_MAINBOARD_PART_NUMBER} =~ DDR4 ]]; then
|
|
cap_file+=_ddr4
|
|
fi
|
|
cap_file+=_${CONFIG_LOCALVERSION}
|
|
cap_file+=.cap
|
|
|
|
if [ -e "$cap_file" ]; then
|
|
confirm "Overwrite already existing '$cap_file'?"
|
|
fi
|
|
|
|
local build_type
|
|
if [ "$CONFIG_EDK2_RELEASE" = y ]; then
|
|
build_type=RELEASE
|
|
else
|
|
build_type=DEBUG
|
|
fi
|
|
|
|
local json_file
|
|
json_file=$(mktemp --tmpdir --suffix -cap.json XXXXXXXX)
|
|
trap "$(printf 'rm -f %q' "$json_file")" EXIT
|
|
|
|
cat > "$json_file" << EOF
|
|
{
|
|
"EmbeddedDrivers": [
|
|
EOF
|
|
|
|
# Ensure the charger check driver module is first
|
|
if [ "$include_battery_check" = 1 ]; then
|
|
cat >> "$json_file" << EOF
|
|
{
|
|
"Driver": "${edk_workspace}/Build/DasharoPayloadPkgX64/${build_type}_COREBOOT/X64/CapsuleChargerCheckDxe.efi"
|
|
},
|
|
EOF
|
|
fi
|
|
|
|
cat >> "$json_file" << EOF
|
|
{
|
|
"Driver": "${edk_workspace}/Build/DasharoPayloadPkgX64/${build_type}_COREBOOT/X64/CapsuleSplashDxe.efi"
|
|
},
|
|
{
|
|
"Driver": "${edk_workspace}/Build/DasharoPayloadPkgX64/${build_type}_COREBOOT/X64/FmpDxe.efi"
|
|
}
|
|
],
|
|
"Payloads": [
|
|
{
|
|
"Payload": "build/coreboot.rom",
|
|
"Guid": "${CONFIG_DRIVERS_EFI_MAIN_FW_GUID}",
|
|
"FwVersion": "${CONFIG_DRIVERS_EFI_MAIN_FW_VERSION}",
|
|
"LowestSupportedVersion": "${CONFIG_DRIVERS_EFI_MAIN_FW_LSV}",
|
|
|
|
"OpenSslSignerPrivateCertFile": "${sign_cert}",
|
|
"OpenSslOtherPublicCertFile": "${sub_cert}",
|
|
"OpenSslTrustedPublicCertFile": "${root_cert}"
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
|
|
# Linux doesn't support InitiateReset flag, omitting it to rely on manual
|
|
# warm reset
|
|
if ! "${edk_tools}/GenerateCapsule" --encode \
|
|
--capflag PersistAcrossReset \
|
|
--json-file "$json_file" \
|
|
--output "$cap_file"; then
|
|
die "GenerateCapsule failed"
|
|
fi
|
|
|
|
echo "Created the capsule at '$cap_file'"
|
|
}
|
|
|
|
function box_subcommand() {
|
|
local src=${edk_basetools}/Source/Python
|
|
local dst=gencap
|
|
|
|
local keys=${src}/Pkcs7Sign
|
|
|
|
if [ -e "$dst" ]; then
|
|
confirm "Overwrite already existing '$dst'?"
|
|
rm -r "${dst}"
|
|
fi
|
|
|
|
info "using '${src}'"
|
|
info "constructing a standalone version in '${dst}'"
|
|
|
|
mkdir -p "${dst}"/{Common,keys}
|
|
|
|
cp "${src}/Capsule/GenerateCapsule.py" "${dst}"
|
|
cp -r "${src}/Common/Edk2" "${dst}/Common"
|
|
cp -r "${src}/Common/Uefi" "${dst}/Common"
|
|
|
|
info "using keys from '${keys}'"
|
|
cp "$keys"/TestRoot.pub.pem "${dst}/keys/root.pub.pem"
|
|
cp "$keys"/TestSub.pub.pem "${dst}/keys/sub.pub.pem"
|
|
cp "$keys"/TestCert.pem "${dst}/keys/sign.crt"
|
|
|
|
cat > "${dst}/GenerateCapsule" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
|
|
python=python
|
|
if command -v python3 >/dev/null; then
|
|
python=python3
|
|
elif command -v python2 >/dev/null; then
|
|
python=python2
|
|
fi
|
|
|
|
dir=$(dirname "${BASH_SOURCE:-$0}")
|
|
exec "${python}" "${dir}/GenerateCapsule.py" "$@"
|
|
EOF
|
|
chmod +x "${dst}/GenerateCapsule"
|
|
|
|
print_banner 'Help'
|
|
echo "Location of capsule signing keys:"
|
|
echo " ${dst}/keys/"
|
|
echo
|
|
echo "Usage examples:"
|
|
echo " ${dst}/GenerateCapsule --help"
|
|
echo " ${dst}/GenerateCapsule --output decoded --decode coreboot.cap"
|
|
}
|
|
|
|
if [ $# -eq 0 ]; then
|
|
print_usage
|
|
exit 1
|
|
fi
|
|
|
|
subcommand=$1
|
|
shift
|
|
|
|
case "$subcommand" in
|
|
box|help|keygen|make)
|
|
"$subcommand"_subcommand "$@" ;;
|
|
|
|
*)
|
|
echo "Unexpected subcommand: $subcommand"
|
|
echo
|
|
print_usage
|
|
exit 1 ;;
|
|
esac
|