From dacc0f47349b654c80012683492c5e7fd9ae799d Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Wed, 21 Feb 2018 17:55:03 -0500 Subject: [PATCH 01/14] Add support for gpg2.x (Ubuntu 18.04) --- .../ubuntu-secure-boot/keys/gpg-agent.conf | 2 ++ data/usr/sbin/grub-install | 35 ++++++++++++++----- debian/changelog | 6 ++++ 3 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 data/etc/ubuntu-secure-boot/keys/gpg-agent.conf diff --git a/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf b/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf new file mode 100644 index 0000000..89cd128 --- /dev/null +++ b/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf @@ -0,0 +1,2 @@ +pinentry-program /usr/bin/pinetry-curses +allow-loopback-pinentry diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index fffb3c6..644adee 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Here we override the original grub-install with a custom version that does a # secure installation of GRUB. For now, we don't support any of the original @@ -69,6 +69,9 @@ Cleanup () { if [ -n "$PEMPRIVATEKEY" ] ; then rm -f "$PEMPRIVATEKEY" fi + if [ -n "$NULL_FILE" ]; then + rm -f "$NULL_FILE" + fi } # Obtain passphrase from user: @@ -111,25 +114,33 @@ then PEMPRIVATEKEY="$(mktemp)" trap Cleanup EXIT INT TERM - # Extract public key: - KEYID=$(gpg -k --with-colons | grep "Ubuntu secure boot EFI key" \ - | cut -d : -f 5) + export GPG_TTY=$(tty) + + # See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=838153 + # KEYID is not in output. So instead, export and grep it + KEYID=$(gpg -a --export |gpg --list-packets --verbose | \ + awk '/Ubuntu secure boot EFI key/ { printing=1 } /keyid/ { if (printing) { print $NF; printing=0} } {}') + gpg --batch --yes --output "$GPGPUBLICKEY" --export "$KEYID" # Get passphrase: + NULL_FILE=$(mktemp) PASSPHRASEOK=0 + gpg-connect-agent updatestartuptty /bye while [ "$PASSPHRASEOK" -eq 0 ] ; do GetPassphrase + rm -f "$NULL_FILE" # Test signing to make sure passphrase is ok echo "$PASSPHRASE" > "$PASSPHRASEFILE" - if ! : | gpg --batch -u "$KEYID" --passphrase-file "$PASSPHRASEFILE" \ - -o /dev/null -as - + if ! : | gpg --pinentry-mode=loopback --batch -u "$KEYID" --passphrase-file "$PASSPHRASEFILE" \ + -o "$NULL_FILE" -as - then RetryPassphrase else PASSPHRASEOK=1 fi done + rm -f $"NULL_FILE" # We have to sign all GRUB files (e.g. modules) with gpg. Currently, # grub-mkstandalone - while otherwise being the ideal tool to use @@ -298,10 +309,16 @@ EOFPASSPHRASEEOF efibootmgr | grep -i "$BOOTLOADER_ID" | cut -c 5-8 | xargs -n 1 -r \ efibootmgr --quiet --delete-bootnum --bootnum set -e - # Add new bootloader entry: + # Add new bootloader entry. nvme looks like /dev/nvme0n1p1 DEVICE="$(df -T /boot/efi | sed -n 2p | awk '{ print $1}')" - DISK="$(echo "$DEVICE" | sed 's|[0-9]||g')" - PARTNUM="$(echo "$DEVICE" | sed 's|[^0-9]||g')" + if [[ $DEVICE =~ n[0-9]+p[0-9] ]] + then + DISK="$(echo "$DEVICE" | sed 's?p.*??g')" + PARTNUM="$(echo "$DEVICE" | sed 's?.*p??g')" + else + DISK="$(echo "$DEVICE" | sed 's|[0-9]||g')" + PARTNUM="$(echo "$DEVICE" | sed 's|[^0-9]||g')" + fi efibootmgr --quiet --create --disk "$DISK" --part "$PARTNUM" \ --write-signature --label "$BOOTLOADER_ID" \ --loader "\\EFI\\$BOOTLOADER_ID\\$EFI_FILENAME" diff --git a/debian/changelog b/debian/changelog index 488bc73..ae983d8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +ubuntu-secure-boot (0.1.3) unstable; urgency=low + + * Add support for gpg2.x (Ubuntu 18.04) + + -- Don Bowman Wed Feb 21 17:52:07 -0500 +` ubuntu-secure-boot (0.1.2) unstable; urgency=low * Work around upstream no_insmod_on_sb.patch that prevents us from loading From 669941432054e39eb3c6afbd34556f1b2b3a6254 Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Wed, 21 Feb 2018 19:01:03 -0500 Subject: [PATCH 02/14] add sha256/sha512 to grub --- data/usr/sbin/grub-install | 4 +++- debian/changelog | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index 644adee..3b8cc60 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -189,6 +189,8 @@ then verify gcry_rsa gcry_dsa + gcry_sha256 + gcry_sha512 " # The upstream Debian version of GRUB2 applies a special patch called # debian/patches/no_insmod_on_sb.patch: @@ -282,7 +284,7 @@ then # If the user is running an older version of Ubuntu/GRUB2, they might not # have all the modules listed above. Filter out the ones they don't have. WANTED_FILE=$(mktemp) - echo $GRUB_MODULES | tr ' ' '\0' | tr -d '\n' | sort -z > "$WANTED_FILE" + echo $GRUB_MODULES | tr ' ' '\0' | tr -d '\n' | sort -u -z > "$WANTED_FILE" ACTUAL_FILE=$(mktemp) find "$GRUBSTAGE/boot/grub" -type f -name \*.mod -printf '%f\0' | \ sed -z 's/\.mod//g' | sort -z > "$ACTUAL_FILE" diff --git a/debian/changelog b/debian/changelog index ae983d8..132a363 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,8 +2,8 @@ ubuntu-secure-boot (0.1.3) unstable; urgency=low * Add support for gpg2.x (Ubuntu 18.04) - -- Don Bowman Wed Feb 21 17:52:07 -0500 -` + -- Don Bowman Wed, 21 Feb 2018 17:52:07 -0500 + ubuntu-secure-boot (0.1.2) unstable; urgency=low * Work around upstream no_insmod_on_sb.patch that prevents us from loading From 302c5091a6e97413e47733a3649e00251cba9931 Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Wed, 21 Feb 2018 20:59:57 -0500 Subject: [PATCH 03/14] fix typo on pinentry might need to start agent as # gpg-agent --daemon --pinentry-program /usr/bin/pinentry-curses after GNUPGHOME env var is set --- data/etc/ubuntu-secure-boot/keys/gpg-agent.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf b/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf index 89cd128..57e2bec 100644 --- a/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf +++ b/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf @@ -1,2 +1,2 @@ -pinentry-program /usr/bin/pinetry-curses +pinentry-program /usr/bin/pinentry-curses allow-loopback-pinentry From a0ef53ecdc3bbb33a364b5cad1273b245b9ff997 Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Thu, 22 Feb 2018 16:20:54 -0500 Subject: [PATCH 04/14] fix typo on rm --- data/usr/sbin/grub-install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index 3b8cc60..a119560 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -140,7 +140,7 @@ then PASSPHRASEOK=1 fi done - rm -f $"NULL_FILE" + rm -f "$NULL_FILE" # We have to sign all GRUB files (e.g. modules) with gpg. Currently, # grub-mkstandalone - while otherwise being the ideal tool to use From 6fa100c24349da3edaad7d2dd80a5e311dc87499 Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Fri, 23 Feb 2018 12:14:04 -0500 Subject: [PATCH 05/14] Only check .sig if signed kernel is installed (e.g. don't check for custom kernels) --- data/usr/sbin/grub-install | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index a119560..e757d2d 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -344,9 +344,12 @@ EOFPASSPHRASEEOF # (see comments in update-grub). echo "Signing kernel or initrd at $SECURE_BOOT_KERNEL_PATH" if [ -n "$SECURE_BOOT_SIGNED_SOURCE" ] ; then - # Check source signature - gpg --verify "${SECURE_BOOT_SIGNED_SOURCE}.sig" \ - "$SECURE_BOOT_SIGNED_SOURCE" + if [ -f "${SECURE_BOOT_SIGNED_SOURCE}.sig" ] + then + # Check source signature + gpg --verify "${SECURE_BOOT_SIGNED_SOURCE}.sig" \ + "$SECURE_BOOT_SIGNED_SOURCE" + fi # Copy and sign it to destination with sbsign: runsbsign --key "$PEMPRIVATEKEY" --cert "$KEYDIR/db.crt" \ From 077ad131fcebd3596ab50e8366658935b5697680 Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Sat, 24 Feb 2018 12:41:42 -0500 Subject: [PATCH 06/14] Remove custom passphrase entry, let gpg pinentry do it (so it can cache). --- .../ubuntu-secure-boot/keys/gpg-agent.conf | 3 + data/usr/sbin/grub-install | 75 ++++--------------- 2 files changed, 18 insertions(+), 60 deletions(-) diff --git a/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf b/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf index 57e2bec..d9664fc 100644 --- a/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf +++ b/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf @@ -1,2 +1,5 @@ pinentry-program /usr/bin/pinentry-curses allow-loopback-pinentry +default-cache-ttl 1800 +max-cache-ttl 1800 + diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index e757d2d..78334ef 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -63,43 +63,10 @@ Cleanup () { if [ -n "$GRUBSTAGE" ] ; then rm -rf "$GRUBSTAGE" fi - if [ -n "$PASSPHRASEFILE" ] ; then - rm -f "$PASSPHRASEFILE" - fi if [ -n "$PEMPRIVATEKEY" ] ; then rm -f "$PEMPRIVATEKEY" fi - if [ -n "$NULL_FILE" ]; then - rm -f "$NULL_FILE" - fi -} - -# Obtain passphrase from user: -GetPassphrase() { - # Ask user for passphrase: note that we die if return code is 30, - # indicating that the user won't be asked the question: - db_settitle ubuntu-secure-boot/title - db_reset ubuntu-secure-boot/passphrase - db_fset ubuntu-secure-boot/passphrase seen false - db_input critical ubuntu-secure-boot/passphrase - db_go - db_get ubuntu-secure-boot/passphrase - PASSPHRASE="$RET" - # Always reset the password so that it doesn't remain behind: - db_reset ubuntu-secure-boot/passphrase -} - -# Ask if the user wants to retry entering passphrase: -RetryPassphrase() { - db_settitle ubuntu-secure-boot/title - db_reset ubuntu-secure-boot/retrypassphrase - db_fset ubuntu-secure-boot/retrypassphrase seen false - db_input critical ubuntu-secure-boot/retrypassphrase - db_go - db_get ubuntu-secure-boot/retrypassphrase - if [ "$RET" != true ] ; then - exit 1 - fi + [ -n "$NULL" ] && rm -f "$NULL" } # Does key directory exist? @@ -110,8 +77,8 @@ then # Temporary files: GPGPUBLICKEY="$(mktemp)" GRUBSTAGE="$(mktemp -d)" - PASSPHRASEFILE="$(mktemp)" PEMPRIVATEKEY="$(mktemp)" + NULL="$(mktemp)" trap Cleanup EXIT INT TERM export GPG_TTY=$(tty) @@ -123,24 +90,17 @@ then gpg --batch --yes --output "$GPGPUBLICKEY" --export "$KEYID" - # Get passphrase: - NULL_FILE=$(mktemp) - PASSPHRASEOK=0 gpg-connect-agent updatestartuptty /bye - while [ "$PASSPHRASEOK" -eq 0 ] ; do - GetPassphrase - rm -f "$NULL_FILE" - # Test signing to make sure passphrase is ok - echo "$PASSPHRASE" > "$PASSPHRASEFILE" - if ! : | gpg --pinentry-mode=loopback --batch -u "$KEYID" --passphrase-file "$PASSPHRASEFILE" \ - -o "$NULL_FILE" -as - - then - RetryPassphrase - else - PASSPHRASEOK=1 - fi + + # Test signing to make sure passphrase is ok, also to + # fetch it into the gpg-agent cache + # We use a file for the output rather than /dev/null + # since it does a chmod 644 after its done! + until : | gpg --batch -u "$KEYID" -o "$NULL" -as - + do + echo "Incorrect passphrase, retry" done - rm -f "$NULL_FILE" + rm -f "$NULL" # We have to sign all GRUB files (e.g. modules) with gpg. Currently, # grub-mkstandalone - while otherwise being the ideal tool to use @@ -166,8 +126,7 @@ then # Sign GRUB files echo "Signing GRUB modules... (this will take a minute)" find "$GRUBSTAGE"/boot -type f -print0 | xargs -0 -n 1 \ - gpg --batch -u "$KEYID" --detach-sign \ - --passphrase-file "$PASSPHRASEFILE" + gpg --yes --batch -u "$KEYID" --detach-sign # Make memdisk/tar image: echo "Creating memdisk..." @@ -294,10 +253,7 @@ then $USED_MODULES # Save db.key OpenSSL key to an unencrypted file (remove passphrase): - openssl rsa -in "$KEYDIR/db.key" -out "$PEMPRIVATEKEY" -passin stdin \ - << EOFPASSPHRASEEOF -$PASSPHRASE -EOFPASSPHRASEEOF + openssl rsa -in "$KEYDIR/db.key" -out "$PEMPRIVATEKEY" # Sign the EFI image into final output location. echo "Signing GRUB image..." @@ -359,7 +315,7 @@ EOFPASSPHRASEEOF # Now sign the final output with gpg: if [ -e "$SECURE_BOOT_KERNEL_PATH" ] ; then gpg --yes --batch -u "$KEYID" --detach-sign \ - --passphrase-file "$PASSPHRASEFILE" "$SECURE_BOOT_KERNEL_PATH" + "$SECURE_BOOT_KERNEL_PATH" fi elif [ "$SECURE_BOOT_KERNEL_ACTION" = postrm -a \ "$SECURE_BOOT_KERNEL_HOOK" = 1 ] @@ -394,8 +350,7 @@ EOFPASSPHRASEEOF ;; esac # Sign final output with gpg: - gpg --yes --batch -u "$KEYID" --detach-sign \ - --passphrase-file "$PASSPHRASEFILE" "$file" + gpg --yes --batch -u "$KEYID" --detach-sign "$file" done fi From 3babf391cbe20880141f35d5457d4c87581bd8ca Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Sat, 24 Feb 2018 19:10:32 -0500 Subject: [PATCH 07/14] More work-arounds for pinentry vs debconf lack of stdin --- README | 2 +- .../ubuntu-secure-boot/keys/gpg-agent.conf | 1 + data/usr/sbin/grub-install | 110 ++++++++++++++---- debian/control | 2 +- debian/postrm | 2 +- 5 files changed, 90 insertions(+), 27 deletions(-) diff --git a/README b/README index c6832d3..7e1c1c0 100644 --- a/README +++ b/README @@ -25,7 +25,7 @@ Build instructions 2. Build the package: - dpkg-buildpackage + dpkg-buildpackage --no-sign Install instructions -------------------- diff --git a/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf b/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf index d9664fc..2dddf98 100644 --- a/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf +++ b/data/etc/ubuntu-secure-boot/keys/gpg-agent.conf @@ -1,5 +1,6 @@ pinentry-program /usr/bin/pinentry-curses allow-loopback-pinentry +allow-preset-passphrase default-cache-ttl 1800 max-cache-ttl 1800 diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index 78334ef..baafb30 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -20,11 +20,21 @@ # signature files, let GRUB go to a rescue prompt, and then turn off # check_signatures. -set -e # Load debconf: used for prompting for passphrase. . /usr/share/debconf/confmodule +KEYDIR=/etc/ubuntu-secure-boot/keys +export GNUPGHOME="$KEYDIR" +#tty=$(tty) +#if [ $? -eq 0 ] +#then +# export GPG_TTY=$(tty) +# gpg-connect-agent updatestartuptty /bye >/dev/null 2>&1 +#fi + +set -e + runsbsign() { # On Ubuntu 16.04, sbsign crashes randomly; this appears to be a # regression from Ubuntu 15.10: @@ -52,23 +62,42 @@ EFI_FILENAME=securegrubx64.efi # EFI image name BOOTLOADER_ID=ubuntu # EFI directory on EFI partition FORMAT=x86_64-efi # grub --format -KEYDIR=/etc/ubuntu-secure-boot/keys -export GNUPGHOME="$KEYDIR" # Temporary file cleanup Cleanup () { - if [ -n "$GPGPUBLICKEY" ] ; then - rm -f "$GPGPUBLICKEY" - fi - if [ -n "$GRUBSTAGE" ] ; then - rm -rf "$GRUBSTAGE" - fi - if [ -n "$PEMPRIVATEKEY" ] ; then - rm -f "$PEMPRIVATEKEY" - fi + [ -n "$GPGPUBLICKEY" ] && rm -f "$GPGPUBLICKEY" ] + [ -n "$GRUBSTAGE" ] && rm -rf "$GRUBSTAGE" + [ -n "$PEMPRIVATEKEY" ] && rm -f "$PEMPRIVATEKEY" [ -n "$NULL" ] && rm -f "$NULL" } +GetPassphrase() { + # Ask user for passphrase: note that we die if return code is 30, + # indicating that the user won't be asked the question: + db_settitle ubuntu-secure-boot/title + db_reset ubuntu-secure-boot/passphrase + db_fset ubuntu-secure-boot/passphrase seen false + db_input critical ubuntu-secure-boot/passphrase + db_go + db_get ubuntu-secure-boot/passphrase + PASSPHRASE="$RET" + # Always reset the password so that it doesn't remain behind: + db_reset ubuntu-secure-boot/passphrase +} + +# Ask if the user wants to retry entering passphrase: +RetryPassphrase() { + db_settitle ubuntu-secure-boot/title + db_reset ubuntu-secure-boot/retrypassphrase + db_fset ubuntu-secure-boot/retrypassphrase seen false + db_input critical ubuntu-secure-boot/retrypassphrase + db_go + db_get ubuntu-secure-boot/retrypassphrase + if [ "$RET" != true ] ; then + exit 1 + fi +} + # Does key directory exist? if [ -d "$KEYDIR" ] && gpg -K --with-colons | \ grep -q "Ubuntu secure boot EFI key" && \ @@ -81,25 +110,54 @@ then NULL="$(mktemp)" trap Cleanup EXIT INT TERM - export GPG_TTY=$(tty) # See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=838153 # KEYID is not in output. So instead, export and grep it KEYID=$(gpg -a --export |gpg --list-packets --verbose | \ awk '/Ubuntu secure boot EFI key/ { printing=1 } /keyid/ { if (printing) { print $NF; printing=0} } {}') - gpg --batch --yes --output "$GPGPUBLICKEY" --export "$KEYID" + gpg --yes --output "$GPGPUBLICKEY" --export "$KEYID" - gpg-connect-agent updatestartuptty /bye - - # Test signing to make sure passphrase is ok, also to - # fetch it into the gpg-agent cache - # We use a file for the output rather than /dev/null - # since it does a chmod 644 after its done! - until : | gpg --batch -u "$KEYID" -o "$NULL" -as - + set +e + + PASSPHRASEOK=0 + until [ $PASSPHRASEOK -eq 1 ] do - echo "Incorrect passphrase, retry" + : | gpg --pinentry-mode cancel --yes -u "$KEYID" -o "$NULL" -as - 2>/dev/null + if [ $? -eq 0 ] + then + PASSPHRASEOK=1 + else + echo "get the passphrase" + GetPassphrase + echo "$PASSPHRASE" | gpg --batch --passphrase-fd 0 \ + --pinentry-mode loopback --yes \ + -u "$KEYID" -o "$NULL" -as /dev/null 2>/dev/null + if [ $? -eq 0 ] + then + PASSPHRASEOK=1 + else + RetryPassphrase + fi + fi done + if [ $PASSPHRASEOK != 1 ] + then + echo "^C pressed, giving up" + exit 1 + fi + + set -e +# # Test signing to make sure passphrase is ok, also to +# # fetch it into the gpg-agent cache +# # We use a file for the output rather than /dev/null +# # since it does a chmod 644 after its done! +# until : | gpg --pinentry-mode ask --yes -u "$KEYID" -o "$NULL" -as - +# do +# rm -f "$NULL" +# echo "Incorrect passphrase, retry" +# sleep 1 +# done rm -f "$NULL" # We have to sign all GRUB files (e.g. modules) with gpg. Currently, @@ -126,7 +184,7 @@ then # Sign GRUB files echo "Signing GRUB modules... (this will take a minute)" find "$GRUBSTAGE"/boot -type f -print0 | xargs -0 -n 1 \ - gpg --yes --batch -u "$KEYID" --detach-sign + gpg -v --yes -u "$KEYID" --detach-sign # Make memdisk/tar image: echo "Creating memdisk..." @@ -253,7 +311,11 @@ then $USED_MODULES # Save db.key OpenSSL key to an unencrypted file (remove passphrase): - openssl rsa -in "$KEYDIR/db.key" -out "$PEMPRIVATEKEY" + until echo "$PASSPHRASE" | openssl rsa -in "$KEYDIR/db.key" -out "$PEMPRIVATEKEY" -passin stdin + do + echo "Bad passphrase on ssl key" + sleep 1 + done # Sign the EFI image into final output location. echo "Signing GRUB image..." diff --git a/debian/control b/debian/control index a6ccb68..ceeef3d 100644 --- a/debian/control +++ b/debian/control @@ -13,7 +13,7 @@ Package: ubuntu-secure-boot Architecture: amd64 # Currently only tested on very recent versions of GRUB/gnupg: Depends: ${misc:Depends}, grub-efi-amd64 (>= 2.02~beta2-29ubuntu0.3), - gnupg (>= 1.4.18), efibootmgr (>= 0.12), openssl (>= 1.0.2), + gnupg (>= 1.4.18), pinentry-curses (>= 1.0.0), efibootmgr (>= 0.12), openssl (>= 1.0.2), uuid-runtime (>= 2.26.2), efitools (>= 1.4.2), sbsigntool (>= 0.6), patch (>= 2.7.5) # shim should be removed; it is signed by Canonical/Microsoft diff --git a/debian/postrm b/debian/postrm index d262599..b5e95a9 100755 --- a/debian/postrm +++ b/debian/postrm @@ -38,7 +38,7 @@ fi case "$1" in purge) # Clean up files made by this package. - rm -rf /etc/ubuntu-secure-boot/keys + #rm -rf /etc/ubuntu-secure-boot/keys rm -f /etc/ubuntu-secure-boot/grub.cfg rm -f /etc/grub.d/01_grub_secure_boot_password # Avoid wiping original post*.distrib scripts if they were still there: From 6e3df74cc8be60b377080631adb53f2e8313227d Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Sun, 25 Feb 2018 14:02:39 -0500 Subject: [PATCH 08/14] add luks/cryptodisk to list (to allow /boot to be on encrypted) --- data/usr/sbin/grub-install | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index baafb30..64d4c39 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -242,6 +242,7 @@ then cat chain configfile + cryptodisk echo efifwsetup efinet @@ -264,6 +265,7 @@ then lsefimmap lsefisystab lssal + luks memdisk minicmd normal From 891e2bc4a99e33bb441a998b1600acb7f1da1949 Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Mon, 23 Dec 2019 11:57:39 -0500 Subject: [PATCH 09/14] feat: cache to avoid rebuild of all grub modules Add a cache directory. if the grub.cfg and publickey are the same, do not rebuild and resign grub. --- data/usr/sbin/grub-install | 54 ++++++++++++++++++++++++++++++++++++-- debian/changelog | 6 +++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index 64d4c39..b0b3797 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -98,6 +98,47 @@ RetryPassphrase() { fi } +# Cache: if the result will be the same return 0, else 1 +# this prevents rebuilding grub modules many times (once +# per kernel installed) +CheckCache() { + ## is /etc/ubuntu-secure-boot/grub.cfg unchanged? + ## is GPGPUBLICKEY unchanged? + if [ ! -d /etc/ubuntu-secure-boot/cache ] + then + echo "grub-install cache: first run, rebuild" + mkdir -p /etc/ubuntu-secure-boot/cache + return 1 + fi + if [ ! -f /etc/ubuntu-secure-boot/cache/grub.cfg ] + then + echo "grub-install cache: no previous grub.cfg, rebuild" + return 1 + fi + if [ ! -f /etc/ubuntu-secure-boot/cache/grub.pubkey ] + then + echo "grub-install cache: no previous grub.pubkey, rebuild" + return 1 + fi + cmp "$GPGPUBLICKEY" /etc/ubuntu-secure-boot/cache/grub.pubkey + if [ $? != 0 ] + then + echo "grub install cache: GPG key changed, rebuild" + return 1 + fi + if [ -f /etc/ubuntu-secure-boot/grub.cfg ] + then + cmp /etc/ubuntu-secure-boot/grub.cfg /etc/ubuntu-secure-boot/cache/grub.cfg + if [ $? != 0 ] + then + echo "grub install cache: change in grub.cfg, rebuild" + return 1 + fi + fi + echo "grub install cache: no changes found, do not rebuld" + return 0 +} + # Does key directory exist? if [ -d "$KEYDIR" ] && gpg -K --with-colons | \ grep -q "Ubuntu secure boot EFI key" && \ @@ -110,16 +151,20 @@ then NULL="$(mktemp)" trap Cleanup EXIT INT TERM - # See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=838153 # KEYID is not in output. So instead, export and grep it KEYID=$(gpg -a --export |gpg --list-packets --verbose | \ awk '/Ubuntu secure boot EFI key/ { printing=1 } /keyid/ { if (printing) { print $NF; printing=0} } {}') gpg --yes --output "$GPGPUBLICKEY" --export "$KEYID" - set +e + CheckCache "$GPGPUBLICKEY" + if [ $? -eq 0 ] + then + exit 0 + fi + PASSPHRASEOK=0 until [ $PASSPHRASEOK -eq 1 ] do @@ -434,6 +479,11 @@ then rm -rf /boot/grub/unicode.pf2 : > /boot/grub/grub.cfg + # Now update cache + mkdir -p /etc/ubuntu-secure-boot/cache + cp "$GPGPUBLICKEY" /etc/ubuntu-secure-boot/cache/grub.pubkey + cp /etc/ubuntu-secure-boot/grub.cfg /etc/ubuntu-secure-boot/cache/grub.cfg + exit 0 fi diff --git a/debian/changelog b/debian/changelog index 132a363..0f1db8d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +ubuntu-secure-boot (0.1.4) unstable; urgency=low + + * feat: cache to avoid rebuild of all grub modules + + -- Don Bowman Mon, 23 Dec 2019 11:57:39 -0500 + ubuntu-secure-boot (0.1.3) unstable; urgency=low * Add support for gpg2.x (Ubuntu 18.04) From 2e7559ce39ebfb91627401973630511d56f895f8 Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Thu, 9 Jan 2020 16:36:24 -0500 Subject: [PATCH 10/14] feat: invalidate cache if /boot/* changes or --sign-all --- data/usr/sbin/grub-install | 296 +++++++++++++++++++------------------ debian/changelog | 6 + 2 files changed, 157 insertions(+), 145 deletions(-) diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index b0b3797..b33d15b 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -102,6 +102,12 @@ RetryPassphrase() { # this prevents rebuilding grub modules many times (once # per kernel installed) CheckCache() { + if [ "$SECURE_BOOT_SIGN_ALL" = 1 -o "$1" = --sign-all ] + then + echo "grub-install: cache invalidated due to SECURE_BOOT_SIGN_ALL or --sign-all" + return 1 + fi + ## is /etc/ubuntu-secure-boot/grub.cfg unchanged? ## is GPGPUBLICKEY unchanged? if [ ! -d /etc/ubuntu-secure-boot/cache ] @@ -139,60 +145,9 @@ CheckCache() { return 0 } -# Does key directory exist? -if [ -d "$KEYDIR" ] && gpg -K --with-colons | \ - grep -q "Ubuntu secure boot EFI key" && \ - [ -e "$KEYDIR/db.crt" -a -e "$KEYDIR/db.key" ] -then - # Temporary files: - GPGPUBLICKEY="$(mktemp)" - GRUBSTAGE="$(mktemp -d)" - PEMPRIVATEKEY="$(mktemp)" - NULL="$(mktemp)" - trap Cleanup EXIT INT TERM - - # See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=838153 - # KEYID is not in output. So instead, export and grep it - KEYID=$(gpg -a --export |gpg --list-packets --verbose | \ - awk '/Ubuntu secure boot EFI key/ { printing=1 } /keyid/ { if (printing) { print $NF; printing=0} } {}') - - gpg --yes --output "$GPGPUBLICKEY" --export "$KEYID" - set +e - - CheckCache "$GPGPUBLICKEY" - if [ $? -eq 0 ] - then - exit 0 - fi - - PASSPHRASEOK=0 - until [ $PASSPHRASEOK -eq 1 ] - do - : | gpg --pinentry-mode cancel --yes -u "$KEYID" -o "$NULL" -as - 2>/dev/null - if [ $? -eq 0 ] - then - PASSPHRASEOK=1 - else - echo "get the passphrase" - GetPassphrase - echo "$PASSPHRASE" | gpg --batch --passphrase-fd 0 \ - --pinentry-mode loopback --yes \ - -u "$KEYID" -o "$NULL" -as /dev/null 2>/dev/null - if [ $? -eq 0 ] - then - PASSPHRASEOK=1 - else - RetryPassphrase - fi - fi - done - if [ $PASSPHRASEOK != 1 ] - then - echo "^C pressed, giving up" - exit 1 - fi - +BuildGrubRamfs() { set -e + # # Test signing to make sure passphrase is ok, also to # # fetch it into the gpg-agent cache # # We use a file for the output rather than /dev/null @@ -214,7 +169,7 @@ then # Use grub-mknetdir to assemble all the GRUB files (this is the most # simple, least invasive method to call grub_install_copy_files). echo "Gathering GRUB modules... (please disregard any messages" \ - "regarding network configuration..." + "regarding network configuration..." grub-mknetdir --net-directory="$GRUBSTAGE" # We aren't interested in EFI image or grub.cfg from grub-mknetdir: rm -f "$GRUBSTAGE"/boot/grub/*/*.efi @@ -229,12 +184,12 @@ then # Sign GRUB files echo "Signing GRUB modules... (this will take a minute)" find "$GRUBSTAGE"/boot -type f -print0 | xargs -0 -n 1 \ - gpg -v --yes -u "$KEYID" --detach-sign + gpg -v --yes -u "$KEYID" --detach-sign # Make memdisk/tar image: echo "Creating memdisk..." tar --create --directory "$GRUBSTAGE" \ - --file "$GRUBSTAGE/memdisk.tar" boot + --file "$GRUBSTAGE/memdisk.tar" boot # Produce final EFI image: # The --verbose option on grub-mkstandalone is very useful to learn how @@ -246,14 +201,14 @@ then # key algorithm (e.g. gcry_rsa). Look at grub-core/commands/verify.c: # pkalgos variable to see which modules are required. SB_MODULES=" - memdisk - tar - verify - gcry_rsa - gcry_dsa - gcry_sha256 - gcry_sha512 - " + memdisk + tar + verify + gcry_rsa + gcry_dsa + gcry_sha256 + gcry_sha512 + " # The upstream Debian version of GRUB2 applies a special patch called # debian/patches/no_insmod_on_sb.patch: # @@ -281,68 +236,68 @@ then # (Failure to do so would be indicated by a "Secure Boot forbids loading # module from" error.) CD_MODULES=" - all_video - boot - btrfs - cat - chain - configfile - cryptodisk - echo - efifwsetup - efinet - ext2 - fat - font - gettext - gfxmenu - gfxterm - gfxterm_background - gzio - halt - hfsplus - iso9660 - jpeg - keystatus - loadenv - linux - lsefi - lsefimmap - lsefisystab - lssal - luks - memdisk - minicmd - normal - part_apple - part_msdos - part_gpt - password_pbkdf2 - png - reboot - search - search_fs_uuid - search_fs_file - search_label - sleep - test - true - video - zfs - zfscrypt - zfsinfo - " + all_video + boot + btrfs + cat + chain + configfile + cryptodisk + echo + efifwsetup + efinet + ext2 + fat + font + gettext + gfxmenu + gfxterm + gfxterm_background + gzio + halt + hfsplus + iso9660 + jpeg + keystatus + loadenv + linux + lsefi + lsefimmap + lsefisystab + lssal + luks + memdisk + minicmd + normal + part_apple + part_msdos + part_gpt + password_pbkdf2 + png + reboot + search + search_fs_uuid + search_fs_file + search_label + sleep + test + true + video + zfs + zfscrypt + zfsinfo + " # x86_64-efi platform-specific modules: CD_MODULES="$CD_MODULES - linuxefi - " + linuxefi + " GRUB_MODULES="$CD_MODULES - lvm - mdraid09 - mdraid1x - raid5rec - raid6rec - " + lvm + mdraid09 + mdraid1x + raid5rec + raid6rec + " # Now, append our modules to the list: GRUB_MODULES="$GRUB_MODULES $SB_MODULES" # If the user is running an older version of Ubuntu/GRUB2, they might not @@ -351,44 +306,100 @@ then echo $GRUB_MODULES | tr ' ' '\0' | tr -d '\n' | sort -u -z > "$WANTED_FILE" ACTUAL_FILE=$(mktemp) find "$GRUBSTAGE/boot/grub" -type f -name \*.mod -printf '%f\0' | \ - sed -z 's/\.mod//g' | sort -z > "$ACTUAL_FILE" + sed -z 's/\.mod//g' | sort -z > "$ACTUAL_FILE" USED_MODULES=$(comm -12 -z "$WANTED_FILE" "$ACTUAL_FILE" | tr '\0' ' ') grub-mkimage --format $FORMAT --output "$GRUBSTAGE/$EFI_FILENAME" \ - --memdisk "$GRUBSTAGE/memdisk.tar" --pubkey "$GPGPUBLICKEY" \ - $USED_MODULES + --memdisk "$GRUBSTAGE/memdisk.tar" --pubkey "$GPGPUBLICKEY" \ + $USED_MODULES # Save db.key OpenSSL key to an unencrypted file (remove passphrase): until echo "$PASSPHRASE" | openssl rsa -in "$KEYDIR/db.key" -out "$PEMPRIVATEKEY" -passin stdin do - echo "Bad passphrase on ssl key" - sleep 1 + echo "Bad passphrase on ssl key" + sleep 1 done # Sign the EFI image into final output location. echo "Signing GRUB image..." runsbsign --key "$PEMPRIVATEKEY" --cert "$KEYDIR/db.crt" \ - --output /boot/efi/EFI/$BOOTLOADER_ID/$EFI_FILENAME \ - "$GRUBSTAGE/$EFI_FILENAME" + --output /boot/efi/EFI/$BOOTLOADER_ID/$EFI_FILENAME \ + "$GRUBSTAGE/$EFI_FILENAME" # Delete existing bootloader entries from firmware: echo "Adding bootloader to EFI configuration..." set +e efibootmgr | grep -i "$BOOTLOADER_ID" | cut -c 5-8 | xargs -n 1 -r \ - efibootmgr --quiet --delete-bootnum --bootnum + efibootmgr --quiet --delete-bootnum --bootnum set -e # Add new bootloader entry. nvme looks like /dev/nvme0n1p1 DEVICE="$(df -T /boot/efi | sed -n 2p | awk '{ print $1}')" if [[ $DEVICE =~ n[0-9]+p[0-9] ]] then - DISK="$(echo "$DEVICE" | sed 's?p.*??g')" - PARTNUM="$(echo "$DEVICE" | sed 's?.*p??g')" + DISK="$(echo "$DEVICE" | sed 's?p.*??g')" + PARTNUM="$(echo "$DEVICE" | sed 's?.*p??g')" else - DISK="$(echo "$DEVICE" | sed 's|[0-9]||g')" - PARTNUM="$(echo "$DEVICE" | sed 's|[^0-9]||g')" + DISK="$(echo "$DEVICE" | sed 's|[0-9]||g')" + PARTNUM="$(echo "$DEVICE" | sed 's|[^0-9]||g')" fi efibootmgr --quiet --create --disk "$DISK" --part "$PARTNUM" \ - --write-signature --label "$BOOTLOADER_ID" \ - --loader "\\EFI\\$BOOTLOADER_ID\\$EFI_FILENAME" + --write-signature --label "$BOOTLOADER_ID" \ + --loader "\\EFI\\$BOOTLOADER_ID\\$EFI_FILENAME" +} + +# Does key directory exist? +if [ -d "$KEYDIR" ] && gpg -K --with-colons | \ + grep -q "Ubuntu secure boot EFI key" && \ + [ -e "$KEYDIR/db.crt" -a -e "$KEYDIR/db.key" ] +then + # Temporary files: + GPGPUBLICKEY="$(mktemp)" + GRUBSTAGE="$(mktemp -d)" + PEMPRIVATEKEY="$(mktemp)" + NULL="$(mktemp)" + trap Cleanup EXIT INT TERM + + # See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=838153 + # KEYID is not in output. So instead, export and grep it + KEYID=$(gpg -a --export |gpg --list-packets --verbose | \ + awk '/Ubuntu secure boot EFI key/ { printing=1 } /keyid/ { if (printing) { print $NF; printing=0} } {}') + + gpg --yes --output "$GPGPUBLICKEY" --export "$KEYID" + set +e + + PASSPHRASEOK=0 + until [ $PASSPHRASEOK -eq 1 ] + do + : | gpg --pinentry-mode cancel --yes -u "$KEYID" -o "$NULL" -as - 2>/dev/null + if [ $? -eq 0 ] + then + PASSPHRASEOK=1 + else + echo "get the passphrase" + GetPassphrase + echo "$PASSPHRASE" | gpg --batch --passphrase-fd 0 \ + --pinentry-mode loopback --yes \ + -u "$KEYID" -o "$NULL" -as /dev/null 2>/dev/null + if [ $? -eq 0 ] + then + PASSPHRASEOK=1 + else + RetryPassphrase + fi + fi + done + if [ $PASSPHRASEOK != 1 ] + then + echo "^C pressed, giving up" + exit 1 + fi + + # Resigning/Rebuilding grub is slow. If key is same and + # grub.cfg is same, don't. (e.g. on update-initramfs) + CheckCache "$GPGPUBLICKEY" "$1" + if [ $? != 0 ] + then + BuildGrubRamfs + fi # Sign any kernels we were requested to sign: if [ "$SECURE_BOOT_KERNEL_ACTION" = postinst -a \ @@ -442,14 +453,9 @@ then # This assumes that whatever is on /boot is trustworthy. Intended for use # only from make-secure-boot-keys. if [ "$1" = --sign-all ] ; then - for file in /boot/vmlinux-* /boot/vmlinuz-* /boot/initrd* ; do - [ -e "$file" ] || continue # in case no matches - case "$file" in - *.sig) - # Detached signature file; ignore. - continue - ;; - esac + for file in $(ls /boot/vmlinux-* /boot/vmlinuz-* /boot/initrd* |grep -v "\.sig$") ; do + # Skip soft-links (e.g. /boot/vmlinuz) + [ -f "$file" -a ! -h "$file" ] || continue echo "Signing kernel or initrd at $file" case "$file" in *.efi.signed) diff --git a/debian/changelog b/debian/changelog index 0f1db8d..6be54a6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +ubuntu-secure-boot (0.1.5) unstable; urgency=low + + * feat: invalidate cache if /boot/* changes or --sign-all + + -- Don Bowman Thu, 9 Jan 2020 14:41:00 -0500 + ubuntu-secure-boot (0.1.4) unstable; urgency=low * feat: cache to avoid rebuild of all grub modules From 534b86258a27f92821ff60a4a5c3ede2d76da9f7 Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Mon, 13 Jan 2020 10:41:31 -0500 Subject: [PATCH 11/14] feat: check all .sig files for validity, resign if not We now log to syslog all operations. In addition to the --sign-all force-override, we now check, for each file, if: a) .sig is present b) .sig is reasonable size c) .sig is verifiable via gpg if not, force resign --- data/usr/sbin/grub-install | 120 +++++++++++++++++++++++++------------ debian/changelog | 6 ++ 2 files changed, 88 insertions(+), 38 deletions(-) diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index b33d15b..4891908 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -33,8 +33,44 @@ export GNUPGHOME="$KEYDIR" # gpg-connect-agent updatestartuptty /bye >/dev/null 2>&1 #fi +log() { + logger -t grub-install "$*" + >&2 echo "$*" +} + set -e +CheckSig() { + # Called with file (and --sign-all optionall) + if [ "$2" = --sign-all ] + then + log "Force rebuild of sig for $1 due to --sign-all" + return 1 + fi + # Now, we should find $file, ${file}.sig. If .sig is not present, + # or wrong size, rebuild + if [ ! -f ${file}.sig ] + then + log "Force rebuild of sig for $1 due to missing .sig file" + return 1 + fi + size=$(stat -c %s ${file}.sig) + if [ $size -lt 512 -o $size -gt 4096 ] + then + log "Force rebuild of sig for $1 due to incorrect size" + return 1 + fi + + gpg --no-default-keyring --keyring $KEYDIR/pubring.kbx --verify ${file}.sig >/dev/null 2>&1 + if [ $? != 0 ] + then + log "Force rebuild of sig for $1 due to invalid pre-existing signature" + return 1 + fi + + return 0 +} + runsbsign() { # On Ubuntu 16.04, sbsign crashes randomly; this appears to be a # regression from Ubuntu 15.10: @@ -45,15 +81,15 @@ runsbsign() { if sbsign "$@" ; then return 0 fi - echo "Retry..." + log "sbsign failed -- retry" done - echo "Failed!" + echo "sbsign failed -- give up!" return 1 } # We can't probe key directory unless we're root. if ! [ $(id -u) = 0 ]; then - echo "ERROR: grub-install must be run as root." + log "ERROR: grub-install must be run as root." exit 1 fi @@ -104,7 +140,7 @@ RetryPassphrase() { CheckCache() { if [ "$SECURE_BOOT_SIGN_ALL" = 1 -o "$1" = --sign-all ] then - echo "grub-install: cache invalidated due to SECURE_BOOT_SIGN_ALL or --sign-all" + log "grub-install: cache invalidated due to SECURE_BOOT_SIGN_ALL or --sign-all" return 1 fi @@ -112,24 +148,24 @@ CheckCache() { ## is GPGPUBLICKEY unchanged? if [ ! -d /etc/ubuntu-secure-boot/cache ] then - echo "grub-install cache: first run, rebuild" + log "grub-install cache: first run, rebuild" mkdir -p /etc/ubuntu-secure-boot/cache return 1 fi if [ ! -f /etc/ubuntu-secure-boot/cache/grub.cfg ] then - echo "grub-install cache: no previous grub.cfg, rebuild" + log "grub-install cache: no previous grub.cfg, rebuild" return 1 fi if [ ! -f /etc/ubuntu-secure-boot/cache/grub.pubkey ] then - echo "grub-install cache: no previous grub.pubkey, rebuild" + log "grub-install cache: no previous grub.pubkey, rebuild" return 1 fi cmp "$GPGPUBLICKEY" /etc/ubuntu-secure-boot/cache/grub.pubkey if [ $? != 0 ] then - echo "grub install cache: GPG key changed, rebuild" + log "grub install cache: GPG key changed, rebuild" return 1 fi if [ -f /etc/ubuntu-secure-boot/grub.cfg ] @@ -137,11 +173,11 @@ CheckCache() { cmp /etc/ubuntu-secure-boot/grub.cfg /etc/ubuntu-secure-boot/cache/grub.cfg if [ $? != 0 ] then - echo "grub install cache: change in grub.cfg, rebuild" + log "grub install cache: change in grub.cfg, rebuild" return 1 fi fi - echo "grub install cache: no changes found, do not rebuld" + log "grub install cache: no changes found, do not rebuld grub initramfs" return 0 } @@ -168,7 +204,7 @@ BuildGrubRamfs() { # Use grub-mknetdir to assemble all the GRUB files (this is the most # simple, least invasive method to call grub_install_copy_files). - echo "Gathering GRUB modules... (please disregard any messages" \ + log "Gathering GRUB modules... (please disregard any messages" \ "regarding network configuration..." grub-mknetdir --net-directory="$GRUBSTAGE" # We aren't interested in EFI image or grub.cfg from grub-mknetdir: @@ -182,19 +218,19 @@ BuildGrubRamfs() { set -e # Sign GRUB files - echo "Signing GRUB modules... (this will take a minute)" + log "Signing GRUB modules... (this will take a minute)" find "$GRUBSTAGE"/boot -type f -print0 | xargs -0 -n 1 \ gpg -v --yes -u "$KEYID" --detach-sign # Make memdisk/tar image: - echo "Creating memdisk..." + log "Creating memdisk..." tar --create --directory "$GRUBSTAGE" \ --file "$GRUBSTAGE/memdisk.tar" boot # Produce final EFI image: # The --verbose option on grub-mkstandalone is very useful to learn how # this process works. - echo "Building GRUB image..." + log "Building GRUB image..." # NOTE: In order for the public key to take effect, you must build the # verify module into the main image. Furthermore, to avoid an infinite # recursion loop, you also have to build in the module for your public @@ -315,18 +351,18 @@ BuildGrubRamfs() { # Save db.key OpenSSL key to an unencrypted file (remove passphrase): until echo "$PASSPHRASE" | openssl rsa -in "$KEYDIR/db.key" -out "$PEMPRIVATEKEY" -passin stdin do - echo "Bad passphrase on ssl key" + log "Bad passphrase on ssl key" sleep 1 done # Sign the EFI image into final output location. - echo "Signing GRUB image..." + log "Signing GRUB image..." runsbsign --key "$PEMPRIVATEKEY" --cert "$KEYDIR/db.crt" \ --output /boot/efi/EFI/$BOOTLOADER_ID/$EFI_FILENAME \ "$GRUBSTAGE/$EFI_FILENAME" # Delete existing bootloader entries from firmware: - echo "Adding bootloader to EFI configuration..." + log "Adding bootloader to EFI configuration..." set +e efibootmgr | grep -i "$BOOTLOADER_ID" | cut -c 5-8 | xargs -n 1 -r \ efibootmgr --quiet --delete-bootnum --bootnum @@ -374,7 +410,7 @@ then then PASSPHRASEOK=1 else - echo "get the passphrase" + log "get the passphrase" GetPassphrase echo "$PASSPHRASE" | gpg --batch --passphrase-fd 0 \ --pinentry-mode loopback --yes \ @@ -389,7 +425,7 @@ then done if [ $PASSPHRASEOK != 1 ] then - echo "^C pressed, giving up" + log "^C pressed, giving up" exit 1 fi @@ -418,7 +454,7 @@ then # sign the result. The source file must already have a gpg signature # on it. This is intended for use with linux-signed-image packages # (see comments in update-grub). - echo "Signing kernel or initrd at $SECURE_BOOT_KERNEL_PATH" + log "Signing kernel or initrd at $SECURE_BOOT_KERNEL_PATH" if [ -n "$SECURE_BOOT_SIGNED_SOURCE" ] ; then if [ -f "${SECURE_BOOT_SIGNED_SOURCE}.sig" ] then @@ -452,28 +488,36 @@ then # If --sign-all flag is passed, sign all installed kernels and initramfs. # This assumes that whatever is on /boot is trustworthy. Intended for use # only from make-secure-boot-keys. - if [ "$1" = --sign-all ] ; then - for file in $(ls /boot/vmlinux-* /boot/vmlinuz-* /boot/initrd* |grep -v "\.sig$") ; do - # Skip soft-links (e.g. /boot/vmlinuz) - [ -f "$file" -a ! -h "$file" ] || continue - echo "Signing kernel or initrd at $file" - case "$file" in - *.efi.signed) - # This is supposed to be an Authenticode-signed kernel. - runsbsign --key "$PEMPRIVATEKEY" --cert "$KEYDIR/db.crt" \ - --output "$file" "$file" - ;; - esac - # Sign final output with gpg: - gpg --yes --batch -u "$KEYID" --detach-sign "$file" - done - fi + #if [ "$1" = --sign-all ] ; then + + for file in $(ls /boot/vmlinux-* /boot/vmlinuz-* /boot/initrd* 2>/dev/null |grep -v "\.sig$") ; do + # Skip soft-links (e.g. /boot/vmlinuz) + [ -f "$file" -a ! -h "$file" ] || continue + CheckSig "$file" "$1" + if [ $? -eq 1 ] + then + log "Signing kernel or initrd at $file" + case "$file" in + *.efi.signed) + # This is supposed to be an Authenticode-signed kernel. + log "Handle .efi.signed case $file" + runsbsign --key "$PEMPRIVATEKEY" --cert "$KEYDIR/db.crt" \ + --output "$file" "$file" + ;; + esac + # Sign final output with gpg: + log "(re) sign file $file" + gpg --yes --batch -u "$KEYID" --detach-sign "$file" + fi + done + + #fi # Remove junk from /boot from the original GRUB packages. These files are # not secured, so keeping them around is not helpful. If this package is # uninstalled, our postrm will rerun original GRUB commands to restore # them. - echo "Removing non-secure GRUB boot files..." + log "Removing non-secure GRUB boot files..." rm -f "/boot/efi/EFI/$BOOTLOADER_ID/grub.cfg" rm -f "/boot/efi/EFI/$BOOTLOADER_ID/grubx64.efi" rm -f "/boot/efi/EFI/$BOOTLOADER_ID/MokManager.efi" @@ -493,6 +537,6 @@ then exit 0 fi -echo "WARNING: No signing keys found. Running original grub-install..." +log "WARNING: No signing keys found. Running original grub-install..." grub-install.distrib "$@" diff --git a/debian/changelog b/debian/changelog index 6be54a6..ecfa179 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +ubuntu-secure-boot (0.1.6) unstable; urgency=low + + * feat: check all .sig files for validity, resign if not + + -- Don Bowman Mon, 13 Jan 2020 10:41:00 -0500 + ubuntu-secure-boot (0.1.5) unstable; urgency=low * feat: invalidate cache if /boot/* changes or --sign-all From 25901bc7f33ecd784daa920a21011442ef151fd8 Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Mon, 13 Jan 2020 11:29:40 -0500 Subject: [PATCH 12/14] fix: remove .sig from SECURE_BOOT_KERNEL_PATH if present it appears update-initramfs can be called w/ /boot/vmlinu...sig which causes a .sig.sig to appear. Remove if present --- data/etc/initramfs/dive.log | 0 data/etc/initramfs/post-update.d/zz-ubuntu-secure-boot | 9 ++++++++- data/usr/sbin/grub-install | 3 ++- debian/changelog | 6 ++++++ 4 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 data/etc/initramfs/dive.log diff --git a/data/etc/initramfs/dive.log b/data/etc/initramfs/dive.log new file mode 100644 index 0000000..e69de29 diff --git a/data/etc/initramfs/post-update.d/zz-ubuntu-secure-boot b/data/etc/initramfs/post-update.d/zz-ubuntu-secure-boot index b293f88..067a90d 100755 --- a/data/etc/initramfs/post-update.d/zz-ubuntu-secure-boot +++ b/data/etc/initramfs/post-update.d/zz-ubuntu-secure-boot @@ -2,9 +2,16 @@ set -e +log() { + logger -t zz-ubuntu-secure-boot "$*" + >&2 echo "$*" +} + +log "update initramfs hook: $*" + if [ -z "$2" ] ; then # Required parameter (path to initramfs file) is missing. - echo "Required parameter to zz-ubuntu-secure-boot initramfs " \ + log "Required parameter to zz-ubuntu-secure-boot initramfs " \ "hook was missing." exit 1 fi diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index 4891908..09a74c5 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -448,6 +448,7 @@ then SECURE_BOOT_KERNEL_PATH="/boot/vmlinux-$SECURE_BOOT_KERNEL_ABI" fi fi + SECURE_BOOT_KERNEL_PATH=${SECURE_BOOT_KERNEL_PATH%.sig} # If SECURE_BOOT_SIGNED_SOURCE is set, then that is a kernel that we # already signed with a detached signature. We will copy it to the # destination location, using sbsign to sign it with that, and then @@ -490,7 +491,7 @@ then # only from make-secure-boot-keys. #if [ "$1" = --sign-all ] ; then - for file in $(ls /boot/vmlinux-* /boot/vmlinuz-* /boot/initrd* 2>/dev/null |grep -v "\.sig$") ; do + for file in $(ls /boot/vmlinux-* /boot/vmlinuz-* /boot/initrd* 2>/dev/null |egrep -v "\.sig$|\.sig.dpkg-bak$") ; do # Skip soft-links (e.g. /boot/vmlinuz) [ -f "$file" -a ! -h "$file" ] || continue CheckSig "$file" "$1" diff --git a/debian/changelog b/debian/changelog index ecfa179..fd8906d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +ubuntu-secure-boot (0.1.7) unstable; urgency=low + + * fix: remove .sig from SECURE_BOOT_KERNEL_PATH if present + + -- Don Bowman Mon, 13 Jan 2020 11:29:00 -0500 + ubuntu-secure-boot (0.1.6) unstable; urgency=low * feat: check all .sig files for validity, resign if not From 0420ce9ba926a28eeef05ae95ffc430f6de78dfa Mon Sep 17 00:00:00 2001 From: Kyle Larose Date: Mon, 3 Feb 2020 15:11:40 -0500 Subject: [PATCH 13/14] fix: swap -e and +e in helper function In a helper function we turned off exiting on error, then enabled it after calling an external utility. This had the behavior of forcing later calls in the script to immediately exit whenever a non-zero error code was returned by anything. Unfortunatly, we were testing the result of a helper function (`CheckSig`) by testing `$?`. If it was non-zero, we'd immediately exit the program, leading to a failure to actually generate signatures, and a failure to finish installation. Change the code to set the flags in the correct order. --- data/usr/sbin/grub-install | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/usr/sbin/grub-install b/data/usr/sbin/grub-install index 09a74c5..e348c6d 100755 --- a/data/usr/sbin/grub-install +++ b/data/usr/sbin/grub-install @@ -363,10 +363,10 @@ BuildGrubRamfs() { # Delete existing bootloader entries from firmware: log "Adding bootloader to EFI configuration..." - set +e + set -e efibootmgr | grep -i "$BOOTLOADER_ID" | cut -c 5-8 | xargs -n 1 -r \ efibootmgr --quiet --delete-bootnum --bootnum - set -e + set +e # Add new bootloader entry. nvme looks like /dev/nvme0n1p1 DEVICE="$(df -T /boot/efi | sed -n 2p | awk '{ print $1}')" if [[ $DEVICE =~ n[0-9]+p[0-9] ]] From 640ac90b9978a3305a5168afdb08691d8668e339 Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Mon, 3 Feb 2020 17:04:30 -0500 Subject: [PATCH 14/14] fix: incorporate changelog for pull request #2 --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index fd8906d..636fa99 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +ubuntu-secure-boot (0.1.7ubuntu1) unstable; urgency=medium + + [ Kyle Larose ] + * fix: swap -e and +e in helper function + + -- don Mon, 03 Feb 2020 17:02:41 -0500 + ubuntu-secure-boot (0.1.7) unstable; urgency=low * fix: remove .sig from SECURE_BOOT_KERNEL_PATH if present