├── debian ├── compat ├── sicherboot.docs ├── source │ └── format ├── sicherboot.manpages ├── rules ├── sicherboot.triggers ├── sicherboot.install ├── gbp.conf ├── sicherboot.postrm ├── sicherboot.postinst ├── sicherboot.preinst ├── copyright ├── control └── changelog ├── kernel ├── postrm.d │ └── sicherboot └── postinst.d │ ├── sicherboot │ └── dracut ├── initramfs └── post-update.d │ └── zz-sicherboot ├── .gitignore ├── shippable.yml ├── tests ├── sicherboot.conf └── test-setup ├── Makefile ├── sicherboot.conf.in ├── README.md ├── sicherboot.8.md └── sicherboot /debian/compat: -------------------------------------------------------------------------------- 1 | 11 2 | -------------------------------------------------------------------------------- /debian/sicherboot.docs: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /debian/sicherboot.manpages: -------------------------------------------------------------------------------- 1 | sicherboot.8 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | %: 3 | dh $@ 4 | -------------------------------------------------------------------------------- /debian/sicherboot.triggers: -------------------------------------------------------------------------------- 1 | interest-noawait /usr/lib/systemd/boot/efi 2 | -------------------------------------------------------------------------------- /kernel/postrm.d/sicherboot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sicherboot help > /dev/null 2>&1 || exit 0 4 | sicherboot remove-kernel "$1" 5 | -------------------------------------------------------------------------------- /debian/sicherboot.install: -------------------------------------------------------------------------------- 1 | kernel/postinst.d/dracut etc/kernel/postinst.d 2 | kernel/postrm.d/* etc/kernel/postrm.d/ 3 | initramfs/post-update.d/* etc/initramfs/post-update.d 4 | -------------------------------------------------------------------------------- /debian/gbp.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | debian-branch = master 3 | debian-tag = v%(version)s 4 | debian-tag-msg = %(pkg)s release %(version)s 5 | export-dir = ../build-area 6 | sign-tags = True 7 | -------------------------------------------------------------------------------- /initramfs/post-update.d/zz-sicherboot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sicherboot help > /dev/null 2>&1 || exit 0 4 | 5 | echo "sicherboot: Installing $1 to ESP" 6 | sicherboot install-kernel "$1" 7 | -------------------------------------------------------------------------------- /kernel/postinst.d/sicherboot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | sicherboot help > /dev/null 2>&1 || exit 0 5 | 6 | echo "sicherboot: Installing $1 to ESP" 7 | 8 | sicherboot install-kernel "$1" 9 | -------------------------------------------------------------------------------- /debian/sicherboot.postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "$1" = "purge" ]; then 5 | dpkg-divert --package sicherboot --rename --remove /etc/kernel/postinst.d/dracut 6 | fi 7 | 8 | #DEBHELPER# 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /sicherboot.conf 2 | /sicherboot.*.tmp 3 | /sicherboot.1 4 | /debian/sicherboot 5 | /debian/sicherboot.substvars 6 | /debian/sicherboot.debhelper.log 7 | /debian/debhelper-* 8 | /debian/files 9 | -------------------------------------------------------------------------------- /debian/sicherboot.postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postinst script for sicherboot 3 | 4 | set -e 5 | 6 | if [ "$1" = "triggered" ] ; then 7 | sicherboot bootctl update || : 8 | fi 9 | 10 | 11 | #DEBHELPER# 12 | -------------------------------------------------------------------------------- /debian/sicherboot.preinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | if [ "$1" = "install" ]; then 6 | dpkg-divert --package sicherboot --divert /etc/kernel/postinst.d/dracut.SecureBoot --rename /etc/kernel/postinst.d/dracut 7 | fi 8 | 9 | #DEBHELPER# 10 | -------------------------------------------------------------------------------- /shippable.yml: -------------------------------------------------------------------------------- 1 | language: none 2 | 3 | build: 4 | pre_ci_boot: 5 | image_name: ubuntu 6 | image_tag: xenial 7 | pull: true 8 | ci: 9 | - touch /etc/kernel/cmdline 10 | - apt-get install -y -qq efitools binutils systemd fakeroot uuid-runtime 11 | - run-parts -v tests 12 | -------------------------------------------------------------------------------- /tests/sicherboot.conf: -------------------------------------------------------------------------------- 1 | # Test configuration file 2 | BOOT_DIR=$PWD/tmp/ 3 | BOOT_EFI_DIR=$PWD/tmp/efi 4 | KEY_HOME=$PWD/tmp/keys 5 | 6 | # Hack: Specify a temporary machine-id (overrides os-release, as included later) 7 | MACHINE_ID=machine-id 8 | 9 | # Hack: We need to export EFI_ARCH for use in the tests 10 | echo "EFI_ARCH=$EFI_ARCH" > $PWD/tmp/config 11 | -------------------------------------------------------------------------------- /kernel/postinst.d/dracut: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # sicherboot file. Installed as dracut to work around missing 4 | # hook support in dracut... 5 | 6 | set -e 7 | 8 | sicherboot_kernel_version="$1" 9 | 10 | # Run the real dracut first if it exists 11 | [ -e /etc/kernel/postinst.d/dracut.SecureBoot ] || exit 0 12 | 13 | . /etc/kernel/postinst.d/dracut.SecureBoot 14 | 15 | sicherboot help > /dev/null 2>&1 || exit 0 16 | 17 | echo "sicherboot: Installing $sicherboot_kernel_version to ESP" 18 | 19 | sicherboot install-kernel "$sicherboot_kernel_version" 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr 2 | 3 | all: sicherboot.conf sicherboot.8 4 | 5 | sicherboot.conf: sicherboot.conf.in sicherboot 6 | cp sicherboot.conf.in sicherboot.conf.tmp 7 | set -e; for var in `grep -o "^[A-Z][A-Z_]*=$$" sicherboot.conf.in | sort -u`; do \ 8 | sed -i "s@^$$var@#`grep ^$$var sicherboot`@g" sicherboot.conf.tmp; \ 9 | done 10 | mv sicherboot.conf.tmp sicherboot.conf 11 | 12 | sicherboot.8: sicherboot.8.md 13 | pandoc -s -t man sicherboot.8.md -o sicherboot.8 14 | 15 | clean: 16 | $(RM) -f sicherboot.conf sicherboot.conf.tmp sicherboot.8 17 | 18 | install: all 19 | install -D -o root -g root -m644 sicherboot.conf $(DESTDIR)/etc/sicherboot/sicherboot.conf 20 | install -d -o root -g root -m700 $(DESTDIR)/etc/sicherboot/keys 21 | install -D -o root -g root -m755 sicherboot $(DESTDIR)$(PREFIX)/sbin/sicherboot 22 | -------------------------------------------------------------------------------- /sicherboot.conf.in: -------------------------------------------------------------------------------- 1 | # Sicherboot configuration file 2 | # 3 | # You can override values here. 4 | # 5 | # Related files: 6 | # 7 | # /etc/kernel/cmdline 8 | # Place to store the kernel commandline 9 | 10 | # Classical boot directory where vmlinuz and initrd.img files can be found 11 | BOOT_DIR= 12 | 13 | # The mount point of the EFI system partition 14 | BOOT_EFI_DIR= 15 | 16 | # EFI Architecture name (automatically detected at run-time) 17 | #EFI_ARCH= 18 | 19 | # Key Common Name 20 | KEY_CN= 21 | 22 | # The location where keys should be stored in 23 | KEY_HOME= 24 | 25 | # OpenSSL arguments for key generations. Here you can specify custom settings. 26 | # 27 | # By default, -nodes is specified, so the key is not encrypted, and is thus 28 | # only safe is KEY_HOME above is located on an encrypted file system. If you 29 | # want to encrypt your keys, you can do so, but it might cause some trouble 30 | # when sicherboot is run automatically during package upgrades, in case there 31 | # is no terminal. 32 | OPENSSL_ARGS= 33 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | 3 | Files: * 4 | Copyright: Copyright (C) 2016 Julian Andres Klode 5 | License: Expat 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | . 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | . 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: sicherboot 2 | Section: utils 3 | Priority: optional 4 | Maintainer: Julian Andres Klode 5 | Build-Depends: debhelper (>= 11), pandoc 6 | Standards-Version: 4.1.3 7 | Homepage: https://github.com/julian-klode/sicherboot 8 | Vcs-Git: https://github.com/julian-klode/sicherboot 9 | Vcs-Browser: https://github.com/julian-klode/sicherboot 10 | 11 | Package: sicherboot 12 | Architecture: all 13 | Depends: ${misc:Depends}, ${shlibs:Depends}, efitools, binutils, systemd, uuid-runtime 14 | Enhances: dracut, systemd, initramfs-tools 15 | Description: systemd-boot integration with UEFI secure boot support 16 | sicher*boot manages kernels and systemd-boot on a secure boot 17 | machine. It installs kernels and systemd-boot, generates signing keys to 18 | enroll in the machine, and signs the kernels and the bootloader with it. 19 | . 20 | Keys are generated in /etc/sicherboot/keys, readable only to root. The private 21 | keys are unencrypted in the default configuration, but that can be changed, 22 | see /etc/sicherboot/sicherboot.conf after installing. 23 | . 24 | This package diverts the /etc/kernel/postinst.d/dracut file and replace it 25 | with its own file that calls the diverted one before running sicherboot, 26 | as dracut does not support any form of hooks. dpkg is not entirely happy 27 | with that and asks you if you want to replace a "deleted" dracut conffile - 28 | answer yes. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | systemd Secure boot integration 2 | =============================== 3 | sicher*boot automatically installs systemd-boot and kernels for it into the 4 | [ESP][], signed with keys generated by it. 5 | 6 | [ESP]: https://en.wikipedia.org/wiki/EFI_System_partition 7 | 8 | [![Run Status](https://api.shippable.com/projects/57d313eea0e0fc1000037262/badge?branch=master)](https://app.shippable.com/projects/57d313eea0e0fc1000037262) 9 | 10 | 11 | SECURITY 12 | -------- 13 | The signing keys are stored unencrypted and only protected by the file system 14 | permissions. Thus, you should make sure that the file system they are 15 | stored (usually `/etc`) in is encrypted. 16 | 17 | Setup 18 | ------------ 19 | After installing sicherboot, you can adjust a number of settings in 20 | `/etc/sicherboot.conf` and should set a kernel commandline in 21 | `/etc/kernel/cmdline`. 22 | 23 | Then run 24 | 25 | sicherboot setup 26 | 27 | to get started. 28 | 29 | Limitations 30 | ----------- 31 | * Kernels and initramfs images must be named `/boot/vmlinuz-` and 32 | `/boot/initrd.img-` 33 | * Only a single ESP is supported. 34 | 35 | 36 | Integrating with your package management 37 | ---------------------------------------- 38 | You want to run: 39 | 40 | * `sicherboot bootctl update` 41 | - whenever systemd is upgraded or installed 42 | * `sicherboot install-kernel ` 43 | - when the kernel is installed and the initramfs was built 44 | * `sicherboot remove-kernel ` 45 | - when the kernel shall be removed 46 | 47 | As an example, kernel and initramfs contain integration with `/etc/kernel` 48 | and initramfs-tools. Install one of the kernel postinst`.d` scripts - the dracut 49 | one exists for dracut systems as a work around for dracut not supporting hooks. 50 | -------------------------------------------------------------------------------- /sicherboot.8.md: -------------------------------------------------------------------------------- 1 | % sicherboot(8) Sicherboot User Manuals 2 | % Julian Andres Klode 3 | % September 6, 2016 4 | 5 | # NAME 6 | 7 | sicherboot - systemd-boot integration with UEFI secure boot support 8 | 9 | # SYNOPSIS 10 | 11 | sicherboot [command] [arg...] 12 | 13 | # DESCRIPTION 14 | 15 | sicherboot manages the systemd-boot bootloader and kernels in an EFI 16 | System Partition (ESP). It stores a set of keys in `/etc/sicherboot/keys` 17 | to sign the binaries for use with secure boot. 18 | 19 | # INITIAL SETUP 20 | 21 | After installation of sicherboot, setup `/etc/kernel/cmdline` and perhaps 22 | change some options in `/etc/sicherboot/sicherboot.conf` to your liking. 23 | 24 | Once you have configured sicherboot as you want, run `sicherboot setup` 25 | to perform the initial installation. 26 | 27 | sicherboot setup 28 | : Performs the initial installation of sicherboot to the ESP. 29 | This basically runs `enroll-keys`, `install-kernel`, `bootctl install`, 30 | asking before each step. 31 | 32 | # KEY MANAGEMENT 33 | 34 | sicherboot generate-keys 35 | : Generates keys in the directory configured in the `KEY_HOME` option. 36 | 37 | sicherboot enroll-keys 38 | : Copies the public keys into the ESP, first running `generate-keys` if no 39 | keys exist yet. 40 | 41 | # KERNEL MANAGEMENT 42 | 43 | sicherboot install-kernel [*VERSION*] 44 | : Install the specified kernel version to the ESP, with initramfs and signed 45 | 46 | sicherboot remove-kernel [*VERSION*] 47 | : Remove the specified kernel version from the ESP 48 | 49 | # OTHER TOOLS 50 | 51 | sicherboot bootctl [*ARGUMENT*...] 52 | : Run the `bootctl` program with the specified arguments, and sign the 53 | bootloader afterwards. 54 | 55 | sicherboot sign-image *EXECUTABLE* 56 | : Sign the given executable using the `db` key. 57 | 58 | # FILES 59 | 60 | `/etc/sicherboot/sicherboot.conf` 61 | : The sicherboot configuration file 62 | 63 | `/etc/sicherboot/keys` 64 | : The default key storage location 65 | 66 | `/etc/kernel/cmdline` 67 | : Kernel command line configuration file 68 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | sicherboot (0.1.5) unstable; urgency=medium 2 | 3 | [ Edward Betts ] 4 | * correct spelling mistake 5 | 6 | [ Julian Andres Klode ] 7 | * Only run hooks if sicherboot is still installed 8 | * kernel/postinst.d/dracut: Only run if diverted dracut postinst exists 9 | * initramfs/post-update.d: Run sicherboot for linux-image-* 10 | * Fixup check for installed sicherboot 11 | * initramfs/post-update.d: Add a message 12 | * d/control: Bump Standards-Version to 4.1.3 13 | * d: Bump debhelper compat to 11 14 | 15 | -- Julian Andres Klode Fri, 16 Mar 2018 11:42:59 +0100 16 | 17 | sicherboot (0.1.4) unstable; urgency=medium 18 | 19 | [ Julian Andres Klode ] 20 | * Make the dracut script do nothing on non-dracut systems (Closes: #868890) 21 | 22 | [ RjY ] 23 | * Handle non-enrolled keys 24 | 25 | -- Julian Andres Klode Wed, 19 Jul 2017 17:42:03 +0200 26 | 27 | sicherboot (0.1.3) unstable; urgency=medium 28 | 29 | * debian: Enhances initramfs-tools, not initramfs-tool (Closes: #840772) 30 | * Ignore failure to remove kernel/loader entry (LP: #1696054) 31 | 32 | -- Julian Andres Klode Tue, 04 Jul 2017 11:52:58 +0200 33 | 34 | sicherboot (0.1.2) unstable; urgency=medium 35 | 36 | * Rename sicherboot.1 to sicherboot.8 37 | * Fix registration of KeyTool in the bootloader 38 | * Add support for SICHERBOOT_CONFIGURATION_FILE_INTERNAL variable 39 | * Create directories before copying or writing files 40 | * debian: Add dependency on uuid-runtime 41 | * Find KeyTool.efi on Ubuntu systems 42 | * Add continuous integration via shippable 43 | 44 | -- Julian Andres Klode Mon, 17 Oct 2016 23:13:23 +0200 45 | 46 | sicherboot (0.1.1) unstable; urgency=low 47 | 48 | * kernel/postinst.d/dracut: Pass arguments to dracut 49 | 50 | -- Julian Andres Klode Tue, 06 Sep 2016 22:31:29 +0200 51 | 52 | sicherboot (0.1.0) unstable; urgency=low 53 | 54 | * Initial upload (Closes: #836867) 55 | 56 | -- Julian Andres Klode Tue, 06 Sep 2016 22:24:52 +0200 57 | -------------------------------------------------------------------------------- /tests/test-setup: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | set -e 3 | 4 | cd "$(dirname "$(readlink -f "$0")")" 5 | 6 | testsuccess() { 7 | printf "%-90s" "Testing $*..." 8 | printf "=====================================================\n" >> $PWD/tmp/out.log 9 | printf " Output of command $*\n" >> $PWD/tmp/out.log 10 | printf "=====================================================\n" >> $PWD/tmp/out.log 11 | if ! "$@" >>$PWD/tmp/out.log 2>&1; then 12 | printf "FAIL\n" 13 | printf "Output so far:\n" >&2 14 | cat $PWD/tmp/out.log 15 | exit 1 16 | else 17 | printf "PASS\n" 18 | fi 19 | } 20 | 21 | export SICHERBOOT_CONFIGURATION_FILE_INTERNAL=$PWD/sicherboot.conf 22 | export PATH="$PWD/tmp:$PATH" 23 | 24 | if test -e tmp; then 25 | rm -rf tmp 26 | fi 27 | 28 | 29 | mkdir tmp 30 | 31 | ######################### TEST KEY GENERATION ############################## 32 | testsuccess fakeroot ../sicherboot generate-keys 33 | 34 | . tmp/config 35 | 36 | testsuccess test -e tmp/keys/PK.auth 37 | testsuccess test -e tmp/keys/db.auth 38 | testsuccess test -e tmp/keys/KEK.auth 39 | 40 | ######################### TEST KEY ENROLLMENT ############################### 41 | 42 | testsuccess fakeroot ../sicherboot enroll-keys 43 | 44 | testsuccess sbverify --cert tmp/keys/db.crt tmp/efi/machine-id/KeyTool.efi 45 | testsuccess test -e tmp/efi/loader/entries/machine-id-keytool.conf 46 | 47 | ############################# TEST BOOTLOADER INSTALLATION ################## 48 | 49 | # Mock bootctl 50 | cat >> $PWD/tmp/bootctl << EOF 51 | #!/bin/sh 52 | install -D /usr/lib/systemd/boot/efi/systemd-boot${EFI_ARCH}.efi $PWD/tmp/efi/EFI/systemd/systemd-boot${EFI_ARCH}.efi 53 | EOF 54 | 55 | chmod +x $PWD/tmp/bootctl 56 | 57 | testsuccess fakeroot ../sicherboot bootctl install 58 | testsuccess test -e tmp/efi/EFI/systemd/systemd-boot${EFI_ARCH}.efi 59 | testsuccess sbverify --cert tmp/keys/db.crt tmp/efi/EFI/systemd/systemd-boot${EFI_ARCH}.efi 60 | 61 | 62 | ############################## TEST KERNEL INSTALLATION ###################### 63 | cp /usr/lib/systemd/boot/efi/linux${EFI_ARCH}.efi.stub tmp/vmlinuz-kernel-version 64 | touch tmp/initrd.img-kernel-version 65 | 66 | testsuccess fakeroot ../sicherboot install-kernel kernel-version 67 | testsuccess test -e tmp/efi/machine-id/kernel-version/linux.efi 68 | testsuccess test -e tmp/efi/loader/entries/machine-id-kernel-version.conf 69 | 70 | 71 | testsuccess sbverify --cert tmp/keys/db.crt tmp/efi/machine-id/kernel-version/linux.efi 72 | 73 | 74 | ############################# TEST THE REAL SETUP COMMAND ###################### 75 | 76 | # Mock uname 77 | cat >> $PWD/tmp/uname << EOF 78 | #!/bin/sh 79 | echo kernel-version 80 | EOF 81 | 82 | chmod +x $PWD/tmp/uname 83 | 84 | 85 | rm -r tmp/efi 86 | rm -r tmp/keys 87 | 88 | testsuccess test ! -e tmp/efi 89 | testsuccess test ! -e tmp/keys 90 | 91 | testsuccess sh -c 'yes | fakeroot ../sicherboot setup' 92 | 93 | testsuccess sbverify --cert tmp/keys/db.crt tmp/efi/EFI/systemd/systemd-boot${EFI_ARCH}.efi 94 | testsuccess sbverify --cert tmp/keys/db.crt tmp/efi/machine-id/kernel-version/linux.efi 95 | testsuccess test -e tmp/efi/loader/entries/machine-id-kernel-version.conf 96 | -------------------------------------------------------------------------------- /sicherboot: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # 3 | # Copyright (C) 2016 Julian Andres Klode 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | . /etc/os-release 24 | 25 | KEY_HOME="/etc/sicherboot/keys" 26 | BOOT_DIR="/boot/" 27 | BOOT_EFI_DIR="/boot/efi" 28 | MACHINE_ID="$(cat /etc/machine-id)" 29 | KEY_CN="${MACHINE_ID}" 30 | OPENSSL_ARGS="-newkey rsa:2048 -nodes -sha256" 31 | 32 | if [ -e /usr/lib/efitools/*/KeyTool.efi ]; then 33 | KEYTOOL=$(echo /usr/lib/efitools/*/KeyTool.efi) 34 | elif [ -e /usr/share/efitools/efi/KeyTool.efi ]; then 35 | KEYTOOL=/usr/share/efitools/efi/KeyTool.efi 36 | fi 37 | 38 | # Discover EFI architecture 39 | for EFI_ARCH in "x64" "aa64" "aarch64" "ia32"; do 40 | if [ -e /usr/lib/systemd/boot/efi/linux${EFI_ARCH}.efi.stub ]; then 41 | break 42 | fi 43 | done 44 | 45 | if [ -n "$SICHERBOOT_CONFIGURATION_FILE_INTERNAL" ]; then 46 | . $SICHERBOOT_CONFIGURATION_FILE_INTERNAL 47 | elif [ -e /etc/sicherboot/sicherboot.conf ]; then 48 | . /etc/sicherboot/sicherboot.conf 49 | fi 50 | 51 | set -e 52 | 53 | _read_yes_no() { 54 | printf "%b [y/n]:" "$*" >&2 55 | while true; do 56 | read answer 57 | case "$answer" in 58 | "y"|"Y"|"yes") 59 | return 0;; 60 | "n"|"N"|"no") 61 | return 1;; 62 | esac 63 | done 64 | return 99 65 | } 66 | 67 | BUILD_IMAGE_HELP="Usage: sicherboot build-image [] 68 | 69 | Combine the kernel image, the initramfs image, and an optional cmdline 70 | file into a UEFI executable. 71 | " 72 | build_image() { 73 | if [ $# -ne 3 -a $# -ne 4 ]; then 74 | printf "%b\n" "$BUILD_IMAGE_HELP" >&2 75 | exit 1 76 | fi 77 | 78 | local kernel_image="$1" 79 | local initramfs_image="$2" 80 | local combined_image="$3" 81 | local cmdline="${4:-/etc/kernel/cmdline}" 82 | local efistub="/usr/lib/systemd/boot/efi/linux${EFI_ARCH}.efi.stub" 83 | 84 | 85 | objcopy \ 86 | --add-section .osrel=/etc/os-release --change-section-vma .osrel=0x20000 \ 87 | --add-section .cmdline="$cmdline" --change-section-vma .cmdline=0x30000 \ 88 | --add-section .linux="$kernel_image" --change-section-vma .linux=0x40000 \ 89 | --add-section .initrd="$initramfs_image" --change-section-vma .initrd=0x3000000 \ 90 | "$efistub" "$combined_image" 91 | } 92 | 93 | SIGN_IMAGE_HELP="Usage: sicherboot sign-image 94 | 95 | Sign the given executable using the db key. 96 | " 97 | sign_image() { 98 | if [ $# -ne 1 ]; then 99 | printf "%b\n" "$SIGN_IMAGE_HELP" >&2 100 | exit 1 101 | fi 102 | 103 | if [ ! \( -e "${KEY_HOME}/db.key" -a -e "${KEY_HOME}/db.crt" \) ]; then 104 | echo "No db.key, skipping sign_image." 105 | return 0 106 | fi 107 | 108 | local image="$1" 109 | local out="$2" 110 | 111 | cp $image $image.jak-bak 112 | sbsign --key $KEY_HOME/db.key \ 113 | --cert $KEY_HOME/db.crt \ 114 | --output "$image" "$image.jak-bak" 115 | rm "$image.jak-bak" 116 | } 117 | 118 | _create_loader_entry() { 119 | local conf="$1" 120 | local image="$2" 121 | local version="$3" 122 | local cmdline="$(cat /etc/kernel/cmdline)" 123 | 124 | echo "title $PRETTY_NAME" > "$conf" 125 | echo "machine-id $MACHINE_ID" >> "$conf" 126 | echo "version $version" >> "$conf" 127 | echo "options $cmdline" >> "$conf" 128 | echo "linux /$image" >> "$conf" 129 | } 130 | 131 | INSTALL_KERNEL_HELP="Usage: sicherboot install-kernel [] 132 | 133 | Install the given kernel version to the ESP(s). If no kernel is given, the 134 | currently running one is installed. 135 | " 136 | install_kernel() { 137 | local version="${1:-$(uname -r)}" 138 | local relative_image_dir="$MACHINE_ID/$version" 139 | local image_dir="$BOOT_EFI_DIR/$relative_image_dir" 140 | local relative_image="$relative_image_dir/linux.efi" 141 | local image="$image_dir/linux.efi" 142 | local conf_dir="$BOOT_EFI_DIR/loader/entries" 143 | local conf="$conf_dir/$MACHINE_ID-$version.conf" 144 | 145 | mkdir -p "$conf_dir" 146 | mkdir -p "$image_dir" 147 | _create_loader_entry "$conf" "$relative_image" "$version" 148 | build_image "$BOOT_DIR/vmlinuz-$version" \ 149 | "$BOOT_DIR/initrd.img-$version" \ 150 | "$image" 151 | sign_image "$image" 152 | } 153 | 154 | REMOVE_KERNEL_HELP="Usage: sicherboot remove-kernel [] 155 | 156 | Removes a kernel from the ESP. 157 | """ 158 | remove_kernel() { 159 | local version="${1:-$(uname -r)}" 160 | local image_dir="$BOOT_EFI_DIR/$MACHINE_ID/$version" 161 | local image="$image_dir/linux.efi" 162 | local conf="$BOOT_EFI_DIR/loader/entries/$MACHINE_ID-$version.conf" 163 | 164 | rm "$conf" || true 165 | rm "$image" || true 166 | rmdir "$image_dir" || true 167 | } 168 | 169 | BOOTCTL_HELP="Usage: sicherboot bootctl [ ...] 170 | 171 | Run bootctl with the given arguments and afterwards sign the 172 | systemd-boot${EFI_ARCH}.efi 173 | " 174 | bootctl() { 175 | command bootctl --path="$BOOT_EFI_DIR" "$@" 176 | sign_image "$BOOT_EFI_DIR/EFI/systemd/systemd-boot${EFI_ARCH}.efi" 177 | } 178 | 179 | 180 | GENERATE_KEYS_HELP="Usage: sicherboot generate-keys 181 | 182 | Generate the keys in ${KEY_HOME}. This has no effect in case a db.key and 183 | a db.crt already exists in there. 184 | " 185 | _generate_key() { 186 | local key_fun="$1" 187 | local signer="$2" 188 | openssl req -new -x509 $OPENSSL_ARGS \ 189 | -keyout "${key_fun}.key" \ 190 | -out "${key_fun}.crt" \ 191 | -subj "/CN=${KEY_CN} ${key_fun}/" 192 | openssl x509 -in "${key_fun}.crt" \ 193 | -out "${key_fun}.cer" -outform DER 194 | 195 | cert-to-efi-sig-list -g $(cat "uuid") ${key_fun}.crt ${key_fun}.esl 196 | sign-efi-sig-list -k "${signer}.key" -c "${signer}.crt" "${key_fun}" "${key_fun}.esl" "${key_fun}.auth" 197 | } 198 | 199 | generate_keys() { 200 | if [ -e "${KEY_HOME}/db.key" -a -e "${KEY_HOME}/db.crt" -a -z "$SICHERBOOT_FORCE_KEYGEN" ]; then 201 | echo "Found db.key, skipping key generation." 202 | return 0 203 | fi 204 | [ -e "${KEY_HOME}" ] || mkdir "${KEY_HOME}" 205 | chown root:root "${KEY_HOME}" 206 | chmod 700 "${KEY_HOME}" 207 | cd "${KEY_HOME}" 208 | uuidgen > "${KEY_HOME}/uuid" 209 | _generate_key PK PK 210 | _generate_key KEK PK 211 | _generate_key db KEK 212 | } 213 | 214 | _copy_keys() { 215 | local key_dir="$1" 216 | mkdir -p "$key_dir" 217 | cp "$KEY_HOME/db.auth" "$key_dir" 218 | cp "$KEY_HOME/KEK.auth" "$key_dir" 219 | cp "$KEY_HOME/PK.auth" "$key_dir" 220 | cp "$KEY_HOME/db.cer" "$key_dir" 221 | cp "$KEY_HOME/KEK.cer" "$key_dir" 222 | cp "$KEY_HOME/db.esl" "$key_dir" 223 | cp "$KEY_HOME/KEK.esl" "$key_dir" 224 | 225 | echo "Installed signed key files into the $key_dir_rel directory in the ESP." 226 | } 227 | 228 | ENROLL_KEYS_HELP="Usage: sicherboot enroll-keys 229 | 230 | Install signed db, KEK, and PK (self-signed) keys into your ESP, together 231 | with KeyTool, so you can easily flash the new key. 232 | " 233 | enroll_keys() { 234 | local relative_image="$MACHINE_ID/KeyTool.efi" 235 | local image_dir="$BOOT_EFI_DIR/$MACHINE_ID" 236 | local image="$BOOT_EFI_DIR/$relative_image" 237 | local conf_dir="$BOOT_EFI_DIR/loader/entries" 238 | local conf="$conf_dir/$MACHINE_ID-keytool.conf" 239 | local key_dir_rel="Keys/$MACHINE_ID" 240 | local key_dir="$BOOT_EFI_DIR/$key_dir_rel" 241 | 242 | if [ ! -e "$KEYTOOL" ]; then 243 | echo "ERROR: Cannot find KeyTool in /usr/{lib,share}/efitools" >&2 244 | exit 1 245 | fi 246 | 247 | if [ -e "$KEY_HOME/db.auth" -a -e "$KEY_HOME/KEK.auth" -a -e "$KEY_HOME/PK.auth" ]; then 248 | _copy_keys "$key_dir" 249 | else 250 | echo "Error: Cannot find signed key files. " >&2 251 | echo "The key storage directory ${KEY_HOME} contains:" >&2 252 | ls -l ${KEY_HOME}/ >&2 || true 253 | if _read_yes_no "Do you want to run generate-keys?"; then 254 | SICHERBOOT_FORCE_KEYGEN=true generate_keys 255 | _copy_keys "$key_dir" 256 | else 257 | if ! _read_yes_no "Do you want to continue installing KeyTool?"; then 258 | return 0 259 | fi 260 | fi 261 | fi 262 | 263 | mkdir -p "$image_dir" 264 | mkdir -p "$conf_dir" 265 | 266 | cp "$KEYTOOL" "$image" 267 | sign_image "$image" 268 | 269 | echo "title UEFI Key Setup Tool" > "$conf" 270 | echo "efi $relative_image" >> "$conf" 271 | 272 | echo "Installed KeyTool into the ESP." 273 | echo 274 | echo "To finish enrolling the keys, reboot the machine, make sure it" 275 | echo "is in setup mode, launch KeyTool, save the old keys, and then" 276 | echo "replace them, in the following order:" 277 | echo " (1) db (signed by KEK)" 278 | echo " (2) KEK (key exchange key, signed by PK)" 279 | echo " (3) PK (platform key, self signed)" 280 | echo 281 | echo "Prefer .auth over .esl over .cer" 282 | echo 283 | echo "Once your PK key has been replaced, your system is put into user" 284 | echo "mode (you might need to reboot for it to take effect). From then" 285 | echo "on, all key changes and binaries need to be signed by the parent" 286 | echo "key. Binaries with db, db with KEK, KEK and PK with PK." 287 | echo 288 | echo "If you want to put your system into setup mode again, you can do" 289 | echo "so by placing $KEY_HOME/rm_PK.auth into your ESP's Keys folder and" 290 | echo "replacing the PK with it. This is a signed empty file which will" 291 | echo "thus remove the existing PK which means the device is in setup" 292 | echo "mode again." 293 | echo "Do not reuse the same keys again after re-entering setup mode this" 294 | echo "way, as anyone could just remove the key again by flashing rm_PK.auth" 295 | } 296 | 297 | SETUP_HELP="setup 298 | 299 | Perform initial setup. 300 | This generates keys, enrolls them (or rather prepares enrollment), and 301 | installs the running kernel and systemd-boot to ${BOOT_EFI_DIR}. 302 | " 303 | setup() { 304 | if _read_yes_no "Enroll keys to ${BOOT_EFI_DIR}?"; then 305 | enroll_keys 306 | fi 307 | if _read_yes_no "Install running kernel to ${BOOT_EFI_DIR}?"; then 308 | install_kernel 309 | fi 310 | if _read_yes_no "Install systemd-boot to ${BOOT_EFI_DIR}?"; then 311 | bootctl install 312 | fi 313 | } 314 | 315 | help() { 316 | [ -n "$1" -a "$1" != "build-image" ] || printf "%b\n" "$BUILD_IMAGE_HELP" 317 | [ -n "$1" -a "$1" != "sign-image" ] || printf "%b\n" "$SIGN_IMAGE_HELP" 318 | [ -n "$1" -a "$1" != "install-kernel" ] || printf "%b\n" "$INSTALL_KERNEL_HELP" 319 | [ -n "$1" -a "$1" != "remove-kernel" ] || printf "%b\n" "$REMOVE_KERNEL_HELP" 320 | [ -n "$1" -a "$1" != "bootctl" ] || printf "%b\n" "$BOOTCTL_HELP" 321 | [ -n "$1" -a "$1" != "generate-keys" ] || printf "%b\n" "$GENERATE_KEYS_HELP" 322 | [ -n "$1" -a "$1" != "enroll-keys" ] || printf "%b\n" "$ENROLL_KEYS_HELP" 323 | [ -n "$1" -a "$1" != "setup" ] || printf "%b" "$SETUP_HELP" 324 | } 325 | 326 | 327 | # Main part of script 328 | if [ $# -lt 1 ]; then 329 | echo "E: No command specified" >&2 330 | help >&2 331 | exit 1 332 | fi 333 | 334 | command="$1" 335 | shift 336 | case "$command" in 337 | "build-image") 338 | build_image "$@";; 339 | "sign-image") 340 | sign_image "$@";; 341 | "install-kernel") 342 | install_kernel "$@";; 343 | "remove-kernel") 344 | remove_kernel "$@";; 345 | "bootctl") 346 | bootctl "$@";; 347 | "--help"|"help"|"-h") 348 | echo "sicherboot - Secure boot and bootloader management stuff" 349 | echo 350 | help "$@" 351 | ;; 352 | "generate-keys") 353 | generate_keys "$@" ;; 354 | "enroll-keys") 355 | enroll_keys "$@" ;; 356 | "setup") 357 | setup "$@";; 358 | *) 359 | echo "sicherboot - Secure boot and bootloader management stuff" >&2 360 | echo >&2 361 | help >&2 362 | exit 1 363 | ;; 364 | esac 365 | --------------------------------------------------------------------------------