Skip to content

Instantly share code, notes, and snippets.

@daxtens
Created March 30, 2021 13:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daxtens/cfc0a7e15614b0383e0c57f308cacdd1 to your computer and use it in GitHub Desktop.
Save daxtens/cfc0a7e15614b0383e0c57f308cacdd1 to your computer and use it in GitHub Desktop.
Testing appended signature-based secure boot
You can experiement with this using entirely free software.
You need the following trees:
https://github.com/daxtens/qemu branch pseries-secboot
https://github.com/daxtens/SLOF branch ibm,secure-boot
https://github.com/daxtens/grub branch appendedsig-2.06
You also need:
- a key to sign grub, and accompanying DER certificate
- a key to sign linux, and accompanying DER certificate
Both should have keyUsage=digitalSignature and not be CAs.
Lastly you will need a working a ppc64(le) vm.
Then:
- build qemu. You need qemu-system-ppc64.
- use xxd to convert the certificate for verifying grub into a header
file, and copy it in to SLOF/lib/libcrypto/certificate.h. It must
create variables certificate_der and certificate_der_len.
- build SLOF for qemu (make qemu)
- verify that you can boot your VM with new SLOF and stock grub.
To boot with new SLOF, pass -bios ./SLOF/boot_rom.bin . It should
boot with new slof in non-secure (default) mode.
To enable secure boot, add ",secure-boot" to your machine
parameter, e.g. "-M pseries,secure-boot". This should now refuse to
boot with an error in SLOF.
(Note that the SLOF verfication is a bit lackadaisical, it doesn't
stop you dropping to the all-powerful OF prompt, and it only
requires signatures on 32-bit binaries. -kernel vmlinux should
still work even in SB mode, for example. I haven't tested
netbooting.)
- Build grub in your VM.
- create a file called config. Use something like this, adapted to your
paths/boot partition setup etc. This helps grub find itself, as
unfortunately we can't use the regular prefix stuff.
search.file /grub2/grub.cfg root
set prefix=($root)'/grub2'
configfile $prefix/grub.cfg
- Use the attached sign-grub.sh script -- appropriately modified to use your
paths -- to build a signed grub image.
- Install your grub image with dd, e.g.:
dd if=core.elf.signed of=/dev/sda1
- Sign your kernel, e.g.:
sign-file SHA256 linux-signing.key linux-signing-certificate.der \
/boot/vmlinux /boot/vmlinux.signed
- You should now be able to boot with new SLOF and qemu in
secure-boot mode.
#!/bin/bash
set -euo pipefail
set -x
cd $(dirname $0)
cur="`pwd`"
# sign-grub [--double] [--reserve-space]
function sign_single {
file="$1"
out="$2"
cp "$file" "$out.unsigned"
truncate -s -$SIG_SIZE "$out.unsigned"
# this is the base case, we split it out here just to show how simple it could be!
if [ $reserve_space == 'n' ]; then
../utils/sign-file SHA256 "../slof-to-grub/grub.key" \
"../slof-to-grub/certificate.der.1" \
"$out.unsigned" "$out.signed"
else
openssl cms -sign -binary -in "$out.unsigned" \
-signer ../slof-to-grub/certificate.pem.1 -inkey ../slof-to-grub/grub.key \
-out "$out.p7s" -outform DER -noattr -md sha256 -nocerts
# extend the size
truncate -s $EXTEND_SIZE "$out.p7s"
../utils/sign-file -s "$out.p7s" sha265 /dev/null \
"$out.unsigned" "$out.signed"
fi
}
function sign_double {
file="$1"
out="$2"
cp "$file" "$out.unsigned"
truncate -s -$SIG_SIZE "$out.unsigned"
openssl cms -sign -binary -in "$out.unsigned" \
-signer ../slof-to-grub/certificate.pem.1 -inkey ../slof-to-grub/grub.key \
-signer ../slof-to-grub/certificate.pem.2 -inkey ../slof-to-grub/grub2.key \
-out "$out.p7s" -outform DER -noattr -md sha256 -nocerts
if [ $reserve_space == 'y' ]; then
truncate -s $EXTEND_SIZE "$out.p7s"
fi
../utils/sign-file -s "$out.p7s" sha265 /dev/null \
"$out.unsigned" "$out.signed"
}
if [ $# -gt 0 ] && [ "$1" == "--double" ]; then
shift;
sign=sign_double;
else
sign=sign_single;
fi
if [ $# -gt 0 ] && [ "$1" == "--reserve-space" ]; then
shift;
reserve_space=y;
else
reserve_space=n;
fi
if [ $reserve_space == 'n' ]; then
# We need to first figure out how much space the signature takes,
if [ -f empty ] || [ -f empty.signed ] || [ -f empty.unsigned ]; then
echo "please delete or move aside 'empty' and 'empty.{un,}signed' first"
exit 1
fi
touch empty
SIG_SIZE=0
$sign empty empty
SIG_SIZE=`stat -c '%s' empty.signed`
echo "Detected signature size: $SIG_SIZE bytes"
rm empty empty.signed empty.unsigned
else
# reserve 32k for this and future signatures. This will probably
# become the default upstream
EXTEND_SIZE=32768
SIG_SIZE=$(( 32768 + 40 ))
fi
# build a grub image with that much space reserved
pushd ../grub
GRUB_MODULES="appendedsig gcry_sha256 all_video boot btrfs cat configfile echo ext2 fat font gfxmenu gfxterm gzio halt hfsplus http iso9660 jpeg loadenv loopback linux lvm mdraid09 mdraid1x minicmd net normal part_apple part_msdos part_gpt password_pbkdf2 png reboot regexp search search_fs_uuid search_fs_file search_label serial sleep syslinuxcfg test tftp video xfs"
./grub-mkimage -O powerpc-ieee1275 -o "$cur/core.elf" --appended-signature-size $SIG_SIZE -d ./grub-core/ -x ../keys/imprint-keys/kernel.der -p '' -c "$cur/config" $GRUB_MODULES
$sign "$cur/core.elf" "$cur/core.elf"
popd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment