diff --git a/Makefile b/Makefile index 5e98b234..72478adc 100644 --- a/Makefile +++ b/Makefile @@ -118,6 +118,8 @@ SHELL := /usr/bin/env bash include modules/musl-cross musl_dep := musl-cross +target := $(shell echo $(CROSS) | grep -Eoe '([^/]*?)-linux-musl') +arch := $(subst -linux-musl, , $(target)) heads_cc := $(CROSS)gcc \ -fdebug-prefix-map=$(pwd)=heads \ -gno-record-gcc-switches \ @@ -143,7 +145,9 @@ CROSS_TOOLS := \ CC="$(heads_cc)" \ $(CROSS_TOOLS_NOCC) \ - +# Targets to build payload only +.PHONY: payload +payload: $(build)/$(BOARD)/bzImage $(build)/$(initrd_dir)/initrd.cpio.xz ifeq ($(CONFIG_COREBOOT), y) @@ -158,7 +162,7 @@ else $(error "$(BOARD): neither CONFIG_COREBOOT nor CONFIG_LINUXBOOT is set?") endif -all: +all payload: @sha256sum $< | tee -a "$(HASHES)" # Disable all built in rules @@ -462,7 +466,10 @@ bin_modules-$(CONFIG_FBWHIPTAIL) += fbwhiptail bin_modules-$(CONFIG_HOTPKEY) += hotp-verification bin_modules-$(CONFIG_MSRTOOLS) += msrtools bin_modules-$(CONFIG_NKSTORECLI) += nkstorecli -bin_modules-$(CONFIG_UTIL_LINUX) += util-linux +bin_modules-$(CONFIG_OPENSSL) += openssl +bin_modules-$(CONFIG_TPM2_TOOLS) += tpm2-tools +bin_modules-$(CONFIG_CURL) += curl +bin_modules-$(CONFIG_BASH) += bash $(foreach m, $(bin_modules-y), \ $(call map,initrd_bin_add,$(call bins,$m)) \ diff --git a/boards/qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md b/boards/qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md index c3b5c57b..4217b756 100644 --- a/boards/qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md +++ b/boards/qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md @@ -1,4 +1,4 @@ -qemu-coreboot-(fb)whiptail-tpm1-(hotp) board +qemu-coreboot-(fb)whiptail-tpm[1,2](-hotp) boards === The `qemu-coreboot-fbwhiptail-tpm1-hotp` configuration (and their variants) permits testing of most features of Heads. diff --git a/boards/qemu-coreboot-fbwhiptail-tpm2-hotp/qemu-coreboot-fbwhiptail-tpm2-hotp.config b/boards/qemu-coreboot-fbwhiptail-tpm2-hotp/qemu-coreboot-fbwhiptail-tpm2-hotp.config new file mode 100644 index 00000000..3a79ee1a --- /dev/null +++ b/boards/qemu-coreboot-fbwhiptail-tpm2-hotp/qemu-coreboot-fbwhiptail-tpm2-hotp.config @@ -0,0 +1,159 @@ +# Configuration for building a coreboot ROM that works in +# the qemu emulator in graphical mode thanks to FBWhiptail +# This version requires a supported HOTP Security dongle (Nitrokey Pro/Storage or Librem Key) +# +# TPM can be used with a qemu software TPM (TIS, 2.0). +export CONFIG_COREBOOT=y +export CONFIG_COREBOOT_VERSION=4.13 +export CONFIG_LINUX_VERSION=5.10.5 + +CONFIG_COREBOOT_CONFIG=config/coreboot-qemu-tpm2.config +CONFIG_LINUX_CONFIG=config/linux-qemu.config + +ifeq "$(CONFIG_UROOT)" "y" +CONFIG_BUSYBOX=n +else +CONFIG_KEXEC=y +CONFIG_QRENCODE=y +CONFIG_TPMTOTP=y +CONFIG_POPT=y +CONFIG_FLASHTOOLS=y +CONFIG_FLASHROM=y +CONFIG_PCIUTILS=y +CONFIG_UTIL_LINUX=y +CONFIG_CRYPTSETUP2=y +CONFIG_GPG2=y +CONFIG_LVM2=y +CONFIG_MBEDTLS=y +CONFIG_DROPBEAR=y +CONFIG_MSRTOOLS=y +CONFIG_HOTPKEY=y + +#Uncomment only one of the following block +#Required for graphical gui-init (FBWhiptail) +CONFIG_CAIRO=y +CONFIG_FBWHIPTAIL=y +# +#text-based init (generic-init and gui-init) +#CONFIG_NEWT=y +#CONFIG_SLANG=y + +endif + +export CONFIG_LINUX_USB_COMPANION_CONTROLLER=y +CONFIG_LINUX_USB=y +CONFIG_LINUX_E1000=y + +#Uncomment only one BOOTSCRIPT: +#Whiptail-based init (text-based or FBWhiptail) +export CONFIG_BOOTSCRIPT=/bin/gui-init +# +#text-based original init: +#export CONFIG_BOOTSCRIPT=/bin/generic-init +export CONFIG_BOOT_REQ_HASH=n +export CONFIG_BOOT_REQ_ROLLBACK=n +export CONFIG_BOOT_RECOVERY_SERIAL="/dev/ttyS0" +export CONFIG_BOOT_KERNEL_ADD="console=ttyS0 console=tty systemd.zram=0" +export CONFIG_BOOT_KERNEL_REMOVE="quiet rhgb splash" + +#TPM2 requirements +export CONFIG_TPM2_TOOLS=y +export CONFIG_PRIMARY_KEY_TYPE=ecc +CONFIG_TPM2_TSS=y +CONFIG_OPENSSL=y +CONFIG_CURL=y +CONFIG_BASH=y + +export CONFIG_BOOT_DEV="/dev/vda1" +export CONFIG_BOARD_NAME="qemu-coreboot-fbwhiptail-tpm2-hotp" + +# Use the GPG-injected ROM if a key was given, since we can't reflash a GPG +# keyring in QEMU. Otherwise use the plain ROM, some things can still be tested +# that way without a GPG key. +ifneq "$(PUBKEY_ASC)" "" +QEMU_BOOT_ROM := $(build)/$(BOARD)/$(CB_OUTPUT_FILE_GPG_INJ) +else +QEMU_BOOT_ROM := $(build)/$(BOARD)/$(CB_OUTPUT_FILE) +endif + +#borrowed from https://github.com/orangecms/webboot/blob/boot-via-qemu/run-webboot.sh +TPMDIR=$(build)/$(BOARD)/vtpm +$(TPMDIR)/.manufacture: + mkdir -p "$(TPMDIR)" + swtpm_setup --tpm-state "$(TPMDIR)" --create-platform-cert --lock-nvram + touch "$(TPMDIR)/.manufacture" +ROOT_DISK_IMG=$(build)/$(BOARD)/root.qcow2 +# Default to 20G disk +QEMU_DISK_SIZE?=20G +$(ROOT_DISK_IMG): + qemu-img create -f qcow2 "$(ROOT_DISK_IMG)" $(QEMU_DISK_SIZE) +# Remember the amount of memory so it doesn't have to be specified every time. +# Default to 4G, most bootable OSes are not usable with less. +QEMU_MEMORY_SIZE?=4G +MEMORY_SIZE_FILE=$(build)/$(BOARD)/memory +$(MEMORY_SIZE_FILE): + @echo "$(QEMU_MEMORY_SIZE)" >"$(MEMORY_SIZE_FILE)" +USB_FD_IMG=$(build)/$(BOARD)/usb_fd.raw +$(USB_FD_IMG): + dd if=/dev/zero bs=1M of="$(USB_FD_IMG)" bs=1M count=128 + # Debian obnoxiously does not include /usr/sbin in PATH for non-root, even + # though it is meaningful to use mkfs.vfat (etc.) as non-root + MKFS_VFAT=mkfs.vfat; \ + [ -x /usr/sbin/mkfs.vfat ] && MKFS_VFAT=/usr/sbin/mkfs.vfat; \ + "$$MKFS_VFAT" "$(USB_FD_IMG)" +# Pass INSTALL_IMG= to attach an installer as a USB flash drive instead +# of the temporary flash drive for exporting GPG keys. +ifneq "$(INSTALL_IMG)" "" +QEMU_USB_FD_IMG := $(INSTALL_IMG) +else +QEMU_USB_FD_IMG := $(USB_FD_IMG) +endif +# To forward a USB token, set USB_TOKEN to one of the following: +# - NitrokeyPro - forwards a Nitrokey Pro by VID:PID +# - LibremKey - forwards a Librem Key by VID:PID +# - - Provide the QEMU usb-host parameters, such as +# 'hostbus=<#>,hostport=<#>' or 'vendorid=<#>,productid=<#>' +ifeq "$(USB_TOKEN)" "NitrokeyPro" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=16648 +else ifeq "$(USB_TOKEN)" "NitrokeyStorage" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=16649 +else ifeq "$(USB_TOKEN)" "Nitrokey3NFC" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=17074 +else ifeq "$(USB_TOKEN)" "LibremKey" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=12653,productid=19531 +else ifneq "$(USB_TOKEN)" "" +QEMU_USB_TOKEN_DEV := -device "usb-host,$(USB_TOKEN)" +endif + +run: $(TPMDIR)/.manufacture $(ROOT_DISK_IMG) $(MEMORY_SIZE_FILE) $(USB_FD_IMG) + swtpm socket \ + --tpm2 \ + --tpmstate dir="$(TPMDIR)" \ + --flags "startup-clear" \ + --terminate \ + --ctrl type=unixio,path="$(TPMDIR)/sock" & + sleep 0.5 + + -qemu-system-x86_64 -drive file="$(ROOT_DISK_IMG)",if=virtio \ + --machine q35,accel=kvm:tcg \ + -rtc base=utc \ + -smp "$$(nproc)" \ + -vga virtio \ + -full-screen \ + -m "$$(cat "$(MEMORY_SIZE_FILE)")" \ + -serial stdio \ + --bios "$(QEMU_BOOT_ROM)" \ + -object rng-random,filename=/dev/urandom,id=rng0 \ + -device virtio-rng-pci,rng=rng0 \ + -netdev user,id=u1 -device e1000,netdev=u1 \ + -chardev socket,id=chrtpm,path="$(TPMDIR)/sock" \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 \ + -device qemu-xhci,id=usb \ + -device usb-tablet \ + -drive file="$(QEMU_USB_FD_IMG)",if=none,id=usb-fd-drive,format=raw \ + -device usb-storage,bus=usb.0,drive=usb-fd-drive \ + $(QEMU_USB_TOKEN_DEV) \ + + stty sane + @echo diff --git a/boards/qemu-coreboot-fbwhiptail-tpm2-hotp/qemu-coreboot-fbwhiptail-tpm2-hotp.md b/boards/qemu-coreboot-fbwhiptail-tpm2-hotp/qemu-coreboot-fbwhiptail-tpm2-hotp.md new file mode 120000 index 00000000..a9ee0493 --- /dev/null +++ b/boards/qemu-coreboot-fbwhiptail-tpm2-hotp/qemu-coreboot-fbwhiptail-tpm2-hotp.md @@ -0,0 +1 @@ +../qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md \ No newline at end of file diff --git a/boards/qemu-coreboot-fbwhiptail-tpm2/qemu-coreboot-fbwhiptail-tpm2.config b/boards/qemu-coreboot-fbwhiptail-tpm2/qemu-coreboot-fbwhiptail-tpm2.config new file mode 100644 index 00000000..24bc02f0 --- /dev/null +++ b/boards/qemu-coreboot-fbwhiptail-tpm2/qemu-coreboot-fbwhiptail-tpm2.config @@ -0,0 +1,158 @@ +# Configuration for building a coreboot ROM that works in +# the qemu emulator in graphical mode thanks to FBWhiptail +# +# TPM can be used with a qemu software TPM (TIS, 2.0). +export CONFIG_COREBOOT=y +export CONFIG_COREBOOT_VERSION=4.13 +export CONFIG_LINUX_VERSION=5.10.5 + +CONFIG_COREBOOT_CONFIG=config/coreboot-qemu-tpm2.config +CONFIG_LINUX_CONFIG=config/linux-qemu.config + +ifeq "$(CONFIG_UROOT)" "y" +CONFIG_BUSYBOX=n +else +CONFIG_KEXEC=y +CONFIG_QRENCODE=y +CONFIG_TPMTOTP=y +CONFIG_POPT=y +CONFIG_FLASHTOOLS=y +CONFIG_FLASHROM=y +CONFIG_PCIUTILS=y +CONFIG_UTIL_LINUX=y +CONFIG_CRYPTSETUP2=y +CONFIG_GPG2=y +CONFIG_LVM2=y +CONFIG_MBEDTLS=y +CONFIG_DROPBEAR=y +CONFIG_MSRTOOLS=y +CONFIG_HOTPKEY=n + +#Uncomment only one of the following block +#Required for graphical gui-init (FBWhiptail) +CONFIG_CAIRO=y +CONFIG_FBWHIPTAIL=y +# +#text-based init (generic-init and gui-init) +#CONFIG_NEWT=y +#CONFIG_SLANG=y + +endif + +export CONFIG_LINUX_USB_COMPANION_CONTROLLER=y +CONFIG_LINUX_USB=y +CONFIG_LINUX_E1000=y + +#Uncomment only one BOOTSCRIPT: +#Whiptail-based init (text-based or FBWhiptail) +export CONFIG_BOOTSCRIPT=/bin/gui-init +# +#text-based original init: +#export CONFIG_BOOTSCRIPT=/bin/generic-init +export CONFIG_BOOT_REQ_HASH=n +export CONFIG_BOOT_REQ_ROLLBACK=n +export CONFIG_BOOT_RECOVERY_SERIAL="/dev/ttyS0" +export CONFIG_BOOT_KERNEL_ADD="console=ttyS0 console=tty systemd.zram=0" +export CONFIG_BOOT_KERNEL_REMOVE="quiet rhgb splash" + +#TPM2 requirements +export CONFIG_TPM2_TOOLS=y +export CONFIG_PRIMARY_KEY_TYPE=ecc +CONFIG_TPM2_TSS=y +CONFIG_OPENSSL=y +CONFIG_CURL=y +CONFIG_BASH=y + +export CONFIG_BOOT_DEV="/dev/vda1" +export CONFIG_BOARD_NAME="qemu-coreboot-fbwhiptail-tpm2" + +# Use the GPG-injected ROM if a key was given, since we can't reflash a GPG +# keyring in QEMU. Otherwise use the plain ROM, some things can still be tested +# that way without a GPG key. +ifneq "$(PUBKEY_ASC)" "" +QEMU_BOOT_ROM := $(build)/$(BOARD)/$(CB_OUTPUT_FILE_GPG_INJ) +else +QEMU_BOOT_ROM := $(build)/$(BOARD)/$(CB_OUTPUT_FILE) +endif + +#borrowed from https://github.com/orangecms/webboot/blob/boot-via-qemu/run-webboot.sh +TPMDIR=$(build)/$(BOARD)/vtpm +$(TPMDIR)/.manufacture: + mkdir -p "$(TPMDIR)" + swtpm_setup --tpm-state "$(TPMDIR)" --create-platform-cert --lock-nvram + touch "$(TPMDIR)/.manufacture" +ROOT_DISK_IMG=$(build)/$(BOARD)/root.qcow2 +# Default to 20G disk +QEMU_DISK_SIZE?=20G +$(ROOT_DISK_IMG): + qemu-img create -f qcow2 "$(ROOT_DISK_IMG)" $(QEMU_DISK_SIZE) +# Remember the amount of memory so it doesn't have to be specified every time. +# Default to 4G, most bootable OSes are not usable with less. +QEMU_MEMORY_SIZE?=4G +MEMORY_SIZE_FILE=$(build)/$(BOARD)/memory +$(MEMORY_SIZE_FILE): + @echo "$(QEMU_MEMORY_SIZE)" >"$(MEMORY_SIZE_FILE)" +USB_FD_IMG=$(build)/$(BOARD)/usb_fd.raw +$(USB_FD_IMG): + dd if=/dev/zero bs=1M of="$(USB_FD_IMG)" bs=1M count=128 + # Debian obnoxiously does not include /usr/sbin in PATH for non-root, even + # though it is meaningful to use mkfs.vfat (etc.) as non-root + MKFS_VFAT=mkfs.vfat; \ + [ -x /usr/sbin/mkfs.vfat ] && MKFS_VFAT=/usr/sbin/mkfs.vfat; \ + "$$MKFS_VFAT" "$(USB_FD_IMG)" +# Pass INSTALL_IMG= to attach an installer as a USB flash drive instead +# of the temporary flash drive for exporting GPG keys. +ifneq "$(INSTALL_IMG)" "" +QEMU_USB_FD_IMG := $(INSTALL_IMG) +else +QEMU_USB_FD_IMG := $(USB_FD_IMG) +endif +# To forward a USB token, set USB_TOKEN to one of the following: +# - NitrokeyPro - forwards a Nitrokey Pro by VID:PID +# - LibremKey - forwards a Librem Key by VID:PID +# - - Provide the QEMU usb-host parameters, such as +# 'hostbus=<#>,hostport=<#>' or 'vendorid=<#>,productid=<#>' +ifeq "$(USB_TOKEN)" "NitrokeyPro" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=16648 +else ifeq "$(USB_TOKEN)" "NitrokeyStorage" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=16649 +else ifeq "$(USB_TOKEN)" "Nitrokey3NFC" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=17074 +else ifeq "$(USB_TOKEN)" "LibremKey" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=12653,productid=19531 +else ifneq "$(USB_TOKEN)" "" +QEMU_USB_TOKEN_DEV := -device "usb-host,$(USB_TOKEN)" +endif + +run: $(TPMDIR)/.manufacture $(ROOT_DISK_IMG) $(MEMORY_SIZE_FILE) $(USB_FD_IMG) + swtpm socket \ + --tpm2 \ + --tpmstate dir="$(TPMDIR)" \ + --flags "startup-clear" \ + --terminate \ + --ctrl type=unixio,path="$(TPMDIR)/sock" & + sleep 0.5 + + -qemu-system-x86_64 -drive file="$(ROOT_DISK_IMG)",if=virtio \ + --machine q35,accel=kvm:tcg \ + -rtc base=utc \ + -smp "$$(nproc)" \ + -vga virtio \ + -full-screen \ + -m "$$(cat "$(MEMORY_SIZE_FILE)")" \ + -serial stdio \ + --bios "$(QEMU_BOOT_ROM)" \ + -object rng-random,filename=/dev/urandom,id=rng0 \ + -device virtio-rng-pci,rng=rng0 \ + -netdev user,id=u1 -device e1000,netdev=u1 \ + -chardev socket,id=chrtpm,path="$(TPMDIR)/sock" \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 \ + -device qemu-xhci,id=usb \ + -device usb-tablet \ + -drive file="$(QEMU_USB_FD_IMG)",if=none,id=usb-fd-drive,format=raw \ + -device usb-storage,bus=usb.0,drive=usb-fd-drive \ + $(QEMU_USB_TOKEN_DEV) \ + + stty sane + @echo diff --git a/boards/qemu-coreboot-fbwhiptail-tpm2/qemu-coreboot-fbwhiptail-tpm2.md b/boards/qemu-coreboot-fbwhiptail-tpm2/qemu-coreboot-fbwhiptail-tpm2.md new file mode 120000 index 00000000..a9ee0493 --- /dev/null +++ b/boards/qemu-coreboot-fbwhiptail-tpm2/qemu-coreboot-fbwhiptail-tpm2.md @@ -0,0 +1 @@ +../qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md \ No newline at end of file diff --git a/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.md b/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.md index a9ee0493..42112c58 120000 --- a/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.md +++ b/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.md @@ -1 +1 @@ -../qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md \ No newline at end of file +boards/qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md \ No newline at end of file diff --git a/boards/qemu-coreboot-whiptail-tpm2-hotp/qemu-coreboot-whiptail-tpm2-hotp.config b/boards/qemu-coreboot-whiptail-tpm2-hotp/qemu-coreboot-whiptail-tpm2-hotp.config new file mode 100644 index 00000000..7deca9c4 --- /dev/null +++ b/boards/qemu-coreboot-whiptail-tpm2-hotp/qemu-coreboot-whiptail-tpm2-hotp.config @@ -0,0 +1,159 @@ +# Configuration for building a coreboot ROM that works in +# the qemu emulator in console mode thanks to Whiptail +# This version requires a supported HOTP Security dongle (Nitrokey Pro/Storage or Librem Key) +# +# TPM can be used with a qemu software TPM (TIS, 2.0). +export CONFIG_COREBOOT=y +export CONFIG_COREBOOT_VERSION=4.13 +export CONFIG_LINUX_VERSION=5.10.5 + +CONFIG_COREBOOT_CONFIG=config/coreboot-qemu-tpm2.config +CONFIG_LINUX_CONFIG=config/linux-qemu.config + +ifeq "$(CONFIG_UROOT)" "y" +CONFIG_BUSYBOX=n +else +CONFIG_KEXEC=y +CONFIG_QRENCODE=y +CONFIG_TPMTOTP=y +CONFIG_POPT=y +CONFIG_FLASHTOOLS=y +CONFIG_FLASHROM=y +CONFIG_PCIUTILS=y +CONFIG_UTIL_LINUX=y +CONFIG_CRYPTSETUP2=y +CONFIG_GPG2=y +CONFIG_LVM2=y +CONFIG_MBEDTLS=y +CONFIG_DROPBEAR=y +CONFIG_MSRTOOLS=y +#CONFIG_HOTPKEY=y + +#Uncomment only one of the following block +#Required for graphical gui-init (FBWhiptail) +#CONFIG_CAIRO=y +#CONFIG_FBWHIPTAIL=y +# +#text-based init (generic-init and gui-init) +CONFIG_NEWT=y +CONFIG_SLANG=y + +endif + +export CONFIG_LINUX_USB_COMPANION_CONTROLLER=y +CONFIG_LINUX_USB=y +CONFIG_LINUX_E1000=y + +#Uncomment only one BOOTSCRIPT: +#Whiptail-based init (text-based or FBWhiptail) +export CONFIG_BOOTSCRIPT=/bin/gui-init +# +#text-based original init: +#export CONFIG_BOOTSCRIPT=/bin/generic-init +export CONFIG_BOOT_REQ_HASH=n +export CONFIG_BOOT_REQ_ROLLBACK=n +export CONFIG_BOOT_RECOVERY_SERIAL="/dev/ttyS0" +export CONFIG_BOOT_KERNEL_ADD="console=ttyS0 console=tty systemd.zram=0" +export CONFIG_BOOT_KERNEL_REMOVE="quiet rhgb splash" + +#TPM2 requirements +export CONFIG_TPM2_TOOLS=y +export CONFIG_PRIMARY_KEY_TYPE=ecc +CONFIG_TPM2_TSS=y +CONFIG_OPENSSL=y +CONFIG_CURL=y +CONFIG_BASH=y + +export CONFIG_BOOT_DEV="/dev/vda1" +export CONFIG_BOARD_NAME="qemu-coreboot-whiptail-tpm2-hotp" + +# Use the GPG-injected ROM if a key was given, since we can't reflash a GPG +# keyring in QEMU. Otherwise use the plain ROM, some things can still be tested +# that way without a GPG key. +ifneq "$(PUBKEY_ASC)" "" +QEMU_BOOT_ROM := $(build)/$(BOARD)/$(CB_OUTPUT_FILE_GPG_INJ) +else +QEMU_BOOT_ROM := $(build)/$(BOARD)/$(CB_OUTPUT_FILE) +endif + +#borrowed from https://github.com/orangecms/webboot/blob/boot-via-qemu/run-webboot.sh +TPMDIR=$(build)/$(BOARD)/vtpm +$(TPMDIR)/.manufacture: + mkdir -p "$(TPMDIR)" + swtpm_setup --tpm-state "$(TPMDIR)" --create-platform-cert --lock-nvram + touch "$(TPMDIR)/.manufacture" +ROOT_DISK_IMG=$(build)/$(BOARD)/root.qcow2 +# Default to 20G disk +QEMU_DISK_SIZE?=20G +$(ROOT_DISK_IMG): + qemu-img create -f qcow2 "$(ROOT_DISK_IMG)" $(QEMU_DISK_SIZE) +# Remember the amount of memory so it doesn't have to be specified every time. +# Default to 4G, most bootable OSes are not usable with less. +QEMU_MEMORY_SIZE?=4G +MEMORY_SIZE_FILE=$(build)/$(BOARD)/memory +$(MEMORY_SIZE_FILE): + @echo "$(QEMU_MEMORY_SIZE)" >"$(MEMORY_SIZE_FILE)" +USB_FD_IMG=$(build)/$(BOARD)/usb_fd.raw +$(USB_FD_IMG): + dd if=/dev/zero bs=1M of="$(USB_FD_IMG)" bs=1M count=128 + # Debian obnoxiously does not include /usr/sbin in PATH for non-root, even + # though it is meaningful to use mkfs.vfat (etc.) as non-root + MKFS_VFAT=mkfs.vfat; \ + [ -x /usr/sbin/mkfs.vfat ] && MKFS_VFAT=/usr/sbin/mkfs.vfat; \ + "$$MKFS_VFAT" "$(USB_FD_IMG)" +# Pass INSTALL_IMG= to attach an installer as a USB flash drive instead +# of the temporary flash drive for exporting GPG keys. +ifneq "$(INSTALL_IMG)" "" +QEMU_USB_FD_IMG := $(INSTALL_IMG) +else +QEMU_USB_FD_IMG := $(USB_FD_IMG) +endif +# To forward a USB token, set USB_TOKEN to one of the following: +# - NitrokeyPro - forwards a Nitrokey Pro by VID:PID +# - LibremKey - forwards a Librem Key by VID:PID +# - - Provide the QEMU usb-host parameters, such as +# 'hostbus=<#>,hostport=<#>' or 'vendorid=<#>,productid=<#>' +ifeq "$(USB_TOKEN)" "NitrokeyPro" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=16648 +else ifeq "$(USB_TOKEN)" "NitrokeyStorage" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=16649 +else ifeq "$(USB_TOKEN)" "Nitrokey3NFC" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=17074 +else ifeq "$(USB_TOKEN)" "LibremKey" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=12653,productid=19531 +else ifneq "$(USB_TOKEN)" "" +QEMU_USB_TOKEN_DEV := -device "usb-host,$(USB_TOKEN)" +endif + +run: $(TPMDIR)/.manufacture $(ROOT_DISK_IMG) $(MEMORY_SIZE_FILE) $(USB_FD_IMG) + swtpm socket \ + --tpm2 \ + --tpmstate dir="$(TPMDIR)" \ + --flags "startup-clear" \ + --terminate \ + --ctrl type=unixio,path="$(TPMDIR)/sock" & + sleep 0.5 + + -qemu-system-x86_64 -drive file="$(ROOT_DISK_IMG)",if=virtio \ + --machine q35,accel=kvm:tcg \ + -rtc base=utc \ + -smp "$$(nproc)" \ + -vga virtio \ + -full-screen \ + -m "$$(cat "$(MEMORY_SIZE_FILE)")" \ + -serial stdio \ + --bios "$(QEMU_BOOT_ROM)" \ + -object rng-random,filename=/dev/urandom,id=rng0 \ + -device virtio-rng-pci,rng=rng0 \ + -netdev user,id=u1 -device e1000,netdev=u1 \ + -chardev socket,id=chrtpm,path="$(TPMDIR)/sock" \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 \ + -device qemu-xhci,id=usb \ + -device usb-tablet \ + -drive file="$(QEMU_USB_FD_IMG)",if=none,id=usb-fd-drive,format=raw \ + -device usb-storage,bus=usb.0,drive=usb-fd-drive \ + $(QEMU_USB_TOKEN_DEV) \ + + stty sane + @echo diff --git a/boards/qemu-coreboot-whiptail-tpm2-hotp/qemu-coreboot-whiptail-tpm2-hotp.md b/boards/qemu-coreboot-whiptail-tpm2-hotp/qemu-coreboot-whiptail-tpm2-hotp.md new file mode 120000 index 00000000..a9ee0493 --- /dev/null +++ b/boards/qemu-coreboot-whiptail-tpm2-hotp/qemu-coreboot-whiptail-tpm2-hotp.md @@ -0,0 +1 @@ +../qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md \ No newline at end of file diff --git a/boards/qemu-coreboot-whiptail-tpm2/qemu-coreboot-whiptail-tpm2.config b/boards/qemu-coreboot-whiptail-tpm2/qemu-coreboot-whiptail-tpm2.config new file mode 100644 index 00000000..bac4bbf0 --- /dev/null +++ b/boards/qemu-coreboot-whiptail-tpm2/qemu-coreboot-whiptail-tpm2.config @@ -0,0 +1,158 @@ +# Configuration for building a coreboot ROM that works in +# the qemu emulator in console mode thanks to Whiptail +# +# TPM can be used with a qemu software TPM (TIS, 2.0). +export CONFIG_COREBOOT=y +export CONFIG_COREBOOT_VERSION=4.13 +export CONFIG_LINUX_VERSION=5.10.5 + +CONFIG_COREBOOT_CONFIG=config/coreboot-qemu-tpm2.config +CONFIG_LINUX_CONFIG=config/linux-qemu.config + +ifeq "$(CONFIG_UROOT)" "y" +CONFIG_BUSYBOX=n +else +CONFIG_KEXEC=y +CONFIG_QRENCODE=y +CONFIG_TPMTOTP=y +CONFIG_POPT=y +CONFIG_FLASHTOOLS=y +CONFIG_FLASHROM=y +CONFIG_PCIUTILS=y +CONFIG_UTIL_LINUX=y +CONFIG_CRYPTSETUP2=y +CONFIG_GPG2=y +CONFIG_LVM2=y +CONFIG_MBEDTLS=y +CONFIG_DROPBEAR=y +CONFIG_MSRTOOLS=y +#CONFIG_HOTPKEY=y + +#Uncomment only one of the following block +#Required for graphical gui-init (FBWhiptail) +#CONFIG_CAIRO=y +#CONFIG_FBWHIPTAIL=y +# +#text-based init (generic-init and gui-init) +CONFIG_NEWT=y +CONFIG_SLANG=y + +endif + +export CONFIG_LINUX_USB_COMPANION_CONTROLLER=y +CONFIG_LINUX_USB=y +CONFIG_LINUX_E1000=y + +#Uncomment only one BOOTSCRIPT: +#Whiptail-based init (text-based or FBWhiptail) +export CONFIG_BOOTSCRIPT=/bin/gui-init +# +#text-based original init: +#export CONFIG_BOOTSCRIPT=/bin/generic-init +export CONFIG_BOOT_REQ_HASH=n +export CONFIG_BOOT_REQ_ROLLBACK=n +export CONFIG_BOOT_RECOVERY_SERIAL="/dev/ttyS0" +export CONFIG_BOOT_KERNEL_ADD="console=ttyS0 console=tty systemd.zram=0" +export CONFIG_BOOT_KERNEL_REMOVE="quiet rhgb splash" + +#TPM2 requirements +export CONFIG_TPM2_TOOLS=y +export CONFIG_PRIMARY_KEY_TYPE=ecc +CONFIG_TPM2_TSS=y +CONFIG_OPENSSL=y +CONFIG_CURL=y +CONFIG_BASH=y + +export CONFIG_BOOT_DEV="/dev/vda1" +export CONFIG_BOARD_NAME="qemu-coreboot-whiptail-tpm2" + +# Use the GPG-injected ROM if a key was given, since we can't reflash a GPG +# keyring in QEMU. Otherwise use the plain ROM, some things can still be tested +# that way without a GPG key. +ifneq "$(PUBKEY_ASC)" "" +QEMU_BOOT_ROM := $(build)/$(BOARD)/$(CB_OUTPUT_FILE_GPG_INJ) +else +QEMU_BOOT_ROM := $(build)/$(BOARD)/$(CB_OUTPUT_FILE) +endif + +#borrowed from https://github.com/orangecms/webboot/blob/boot-via-qemu/run-webboot.sh +TPMDIR=$(build)/$(BOARD)/vtpm +$(TPMDIR)/.manufacture: + mkdir -p "$(TPMDIR)" + swtpm_setup --tpm-state "$(TPMDIR)" --create-platform-cert --lock-nvram + touch "$(TPMDIR)/.manufacture" +ROOT_DISK_IMG=$(build)/$(BOARD)/root.qcow2 +# Default to 20G disk +QEMU_DISK_SIZE?=20G +$(ROOT_DISK_IMG): + qemu-img create -f qcow2 "$(ROOT_DISK_IMG)" $(QEMU_DISK_SIZE) +# Remember the amount of memory so it doesn't have to be specified every time. +# Default to 4G, most bootable OSes are not usable with less. +QEMU_MEMORY_SIZE?=4G +MEMORY_SIZE_FILE=$(build)/$(BOARD)/memory +$(MEMORY_SIZE_FILE): + @echo "$(QEMU_MEMORY_SIZE)" >"$(MEMORY_SIZE_FILE)" +USB_FD_IMG=$(build)/$(BOARD)/usb_fd.raw +$(USB_FD_IMG): + dd if=/dev/zero bs=1M of="$(USB_FD_IMG)" bs=1M count=128 + # Debian obnoxiously does not include /usr/sbin in PATH for non-root, even + # though it is meaningful to use mkfs.vfat (etc.) as non-root + MKFS_VFAT=mkfs.vfat; \ + [ -x /usr/sbin/mkfs.vfat ] && MKFS_VFAT=/usr/sbin/mkfs.vfat; \ + "$$MKFS_VFAT" "$(USB_FD_IMG)" +# Pass INSTALL_IMG= to attach an installer as a USB flash drive instead +# of the temporary flash drive for exporting GPG keys. +ifneq "$(INSTALL_IMG)" "" +QEMU_USB_FD_IMG := $(INSTALL_IMG) +else +QEMU_USB_FD_IMG := $(USB_FD_IMG) +endif +# To forward a USB token, set USB_TOKEN to one of the following: +# - NitrokeyPro - forwards a Nitrokey Pro by VID:PID +# - LibremKey - forwards a Librem Key by VID:PID +# - - Provide the QEMU usb-host parameters, such as +# 'hostbus=<#>,hostport=<#>' or 'vendorid=<#>,productid=<#>' +ifeq "$(USB_TOKEN)" "NitrokeyPro" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=16648 +else ifeq "$(USB_TOKEN)" "NitrokeyStorage" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=16649 +else ifeq "$(USB_TOKEN)" "Nitrokey3NFC" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=8352,productid=17074 +else ifeq "$(USB_TOKEN)" "LibremKey" +QEMU_USB_TOKEN_DEV := -device usb-host,vendorid=12653,productid=19531 +else ifneq "$(USB_TOKEN)" "" +QEMU_USB_TOKEN_DEV := -device "usb-host,$(USB_TOKEN)" +endif + +run: $(TPMDIR)/.manufacture $(ROOT_DISK_IMG) $(MEMORY_SIZE_FILE) $(USB_FD_IMG) + swtpm socket \ + --tpm2 \ + --tpmstate dir="$(TPMDIR)" \ + --flags "startup-clear" \ + --terminate \ + --ctrl type=unixio,path="$(TPMDIR)/sock" & + sleep 0.5 + + -qemu-system-x86_64 -drive file="$(ROOT_DISK_IMG)",if=virtio \ + --machine q35,accel=kvm:tcg \ + -rtc base=utc \ + -smp "$$(nproc)" \ + -vga virtio \ + -full-screen \ + -m "$$(cat "$(MEMORY_SIZE_FILE)")" \ + -serial stdio \ + --bios "$(QEMU_BOOT_ROM)" \ + -object rng-random,filename=/dev/urandom,id=rng0 \ + -device virtio-rng-pci,rng=rng0 \ + -netdev user,id=u1 -device e1000,netdev=u1 \ + -chardev socket,id=chrtpm,path="$(TPMDIR)/sock" \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 \ + -device qemu-xhci,id=usb \ + -device usb-tablet \ + -drive file="$(QEMU_USB_FD_IMG)",if=none,id=usb-fd-drive,format=raw \ + -device usb-storage,bus=usb.0,drive=usb-fd-drive \ + $(QEMU_USB_TOKEN_DEV) \ + + stty sane + @echo diff --git a/boards/qemu-coreboot-whiptail-tpm2/qemu-coreboot-whiptail-tpm2.md b/boards/qemu-coreboot-whiptail-tpm2/qemu-coreboot-whiptail-tpm2.md new file mode 120000 index 00000000..a9ee0493 --- /dev/null +++ b/boards/qemu-coreboot-whiptail-tpm2/qemu-coreboot-whiptail-tpm2.md @@ -0,0 +1 @@ +../qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md \ No newline at end of file diff --git a/config/busybox.config b/config/busybox.config index 3df67ef8..00fb49b9 100644 --- a/config/busybox.config +++ b/config/busybox.config @@ -282,9 +282,9 @@ CONFIG_PASTE=y # CONFIG_PRINTENV is not set CONFIG_PRINTF=y CONFIG_PWD=y -# CONFIG_READLINK is not set -# CONFIG_FEATURE_READLINK_FOLLOW is not set -# CONFIG_REALPATH is not set +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y CONFIG_SEQ=y @@ -392,7 +392,7 @@ CONFIG_LOADKMAP=y # CONFIG_START_STOP_DAEMON is not set # CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set # CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set -# CONFIG_WHICH is not set +CONFIG_WHICH=y # # klibc-utils diff --git a/config/coreboot-qemu-tpm2.config b/config/coreboot-qemu-tpm2.config new file mode 100644 index 00000000..9795dee5 --- /dev/null +++ b/config/coreboot-qemu-tpm2.config @@ -0,0 +1,19 @@ +# CONFIG_INCLUDE_CONFIG_FILE is not set +CONFIG_ONBOARD_VGA_IS_PRIMARY=y +CONFIG_CBFS_SIZE=0xfe0000 +# CONFIG_POST_IO is not set +# CONFIG_POST_DEVICE is not set +CONFIG_BOARD_EMULATION_QEMU_X86_Q35=y +# CONFIG_CONSOLE_SERIAL is not set +CONFIG_LINUX_COMMAND_LINE="debug console=ttyS0,115200 console=tty" +CONFIG_COREBOOT_ROMSIZE_KB_16384=y +CONFIG_PCIEXP_ASPM=y +CONFIG_PCIEXP_COMMON_CLOCK=y +CONFIG_UART_PCI_ADDR=0 +CONFIG_DRIVERS_PS2_KEYBOARD=y +CONFIG_USER_TPM2=y +CONFIG_TPM_MEASURED_BOOT=y +CONFIG_DEFAULT_CONSOLE_LOGLEVEL_6=y +CONFIG_PAYLOAD_LINUX=y +CONFIG_PAYLOAD_FILE="@BOARD_BUILD_DIR@/bzImage" +CONFIG_LINUX_INITRD="@BOARD_BUILD_DIR@/initrd.cpio.xz" diff --git a/initrd/bin/cbfs-init b/initrd/bin/cbfs-init index ab143aad..8ab72c71 100755 --- a/initrd/bin/cbfs-init +++ b/initrd/bin/cbfs-init @@ -20,11 +20,11 @@ for cbfsname in `echo $cbfsfiles`; do || die "$filename: mkdir failed" cbfs -t 50 -r $cbfsname > "$filename" \ || die "$filename: cbfs file read failed" - if [ "$CONFIG_TPM" = "y" ]; then + if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ]; then TMPFILE=/tmp/cbfs.$$ echo "$filename" > $TMPFILE cat $filename >> $TMPFILE - tpm extend -ix "$CONFIG_PCR" -if $TMPFILE \ + tpmr extend -ix "$CONFIG_PCR" -if $TMPFILE \ || die "$filename: tpm extend failed" fi fi diff --git a/initrd/bin/config-gui.sh b/initrd/bin/config-gui.sh index e6f0b775..3799b67f 100755 --- a/initrd/bin/config-gui.sh +++ b/initrd/bin/config-gui.sh @@ -128,6 +128,8 @@ while true; do # reset TPM if present if [ "$CONFIG_TPM" = "y" ]; then /bin/tpm-reset + elif [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + tpmr reset fi whiptail --title 'Configuration Reset Updated Successfully' \ --msgbox "Configuration reset and BIOS updated successfully.\n\nPress Enter to reboot" 16 60 diff --git a/initrd/bin/gui-init b/initrd/bin/gui-init index 7ccb2396..9b2a983d 100755 --- a/initrd/bin/gui-init +++ b/initrd/bin/gui-init @@ -182,6 +182,12 @@ update_totp() if [ "$skip_to_menu" = "true" ]; then return 1 # Already asked to skip to menu from a prior error fi + + echo "DEBUG: CONFIG_TPM: $CONFIG_TPM" + echo "DEBUG: CONFIG_TPM2_TOOLS: $CONFIG_TPM2_TOOLS" + echo "DEBUG: Show PCRs" + pcrs + whiptail $BG_COLOR_ERROR --title "ERROR: TOTP Generation Failed!" \ --menu " ERROR: Heads couldn't generate the TOTP code.\n If you have just completed a Factory Reset, or just reflashed @@ -507,7 +513,7 @@ prompt_totp_mismatch() reset_tpm() { TRACE "Under /bin/gui-init:reset_tpm" - if [ "$CONFIG_TPM" = "y" ]; then + if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ]; then if (whiptail $BG_COLOR_WARNING --title 'Reset the TPM' \ --yesno "This will clear the TPM and TPM password, replace them with new ones!\n\nDo you want to proceed?" 0 80) then /bin/tpm-reset diff --git a/initrd/bin/kexec-boot b/initrd/bin/kexec-boot index 9952cf1e..9f85ef7b 100755 --- a/initrd/bin/kexec-boot +++ b/initrd/bin/kexec-boot @@ -134,5 +134,15 @@ echo "$kexeccmd" eval "$kexeccmd" \ || die "Failed to load the new kernel" +if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + # Add a random passphrase to platform hierarchy to prevent TPM2 from + # being cleared in the OS. + # This passphrase is only effective before the next boot. + echo "Locking platform hierarchy..." + randpass=$(dd if=/dev/urandom bs=4 count=1 | xxd -p) + tpm2 changeauth -c platform "$randpass" \ + || warn "Failed to lock platform hierarchy of TPM2!" +fi + echo "Starting the new kernel" exec kexec -e diff --git a/initrd/bin/kexec-insert-key b/initrd/bin/kexec-insert-key index 423dce4c..59e4db60 100755 --- a/initrd/bin/kexec-insert-key +++ b/initrd/bin/kexec-insert-key @@ -49,7 +49,7 @@ if ! kexec-unseal-key "$INITRD_DIR/secret.key" ; then fi # Override PCR 4 so that user can't read the key -tpm extend -ix 4 -ic generic \ +tpmr extend -ix 4 -ic generic \ || die 'Unable to scramble PCR' # Check to continue diff --git a/initrd/bin/kexec-save-default b/initrd/bin/kexec-save-default index 96dfafe0..06a0fc27 100755 --- a/initrd/bin/kexec-save-default +++ b/initrd/bin/kexec-save-default @@ -34,6 +34,7 @@ paramsdir="${paramsdir%%/}" TMP_MENU_FILE="/tmp/kexec/kexec_menu.txt" ENTRY_FILE="$paramsdir/kexec_default.$index.txt" HASH_FILE="$paramsdir/kexec_default_hashes.txt" +PRIMHASH_FILE="$paramsdir/kexec_primhdl_hash.txt" if [ ! -r "$TMP_MENU_FILE" ]; then die "No menu options available, please run kexec-select-boot" @@ -47,7 +48,7 @@ fi KEY_DEVICES="$paramsdir/kexec_key_devices.txt" KEY_LVM="$paramsdir/kexec_key_lvm.txt" save_key="n" -if [[ "$CONFIG_TPM" = "y" && "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ]]; then +if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ]; then if [ ! -r "$KEY_DEVICES" ]; then read \ -n 1 \ @@ -93,14 +94,14 @@ if [[ "$CONFIG_TPM" = "y" && "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ]]; then lvm vgscan || true read \ - -p "Encrypted LVM group? ($lvm_suggest): " \ + -p "LVM group containing Encrypted LVs (retype to keep)? ($lvm_suggest): " \ lvm_volume_group echo "+++ Block devices (blkid): " blkid || true read \ - -p "Encrypted devices? ($devices_suggest): " \ + -p "Encrypted devices (retype to keep)? ($devices_suggest): " \ key_devices save_key_params="-s -p $paramsdev" @@ -122,6 +123,14 @@ if [ ! -d $paramsdir ]; then mkdir -p $paramsdir \ || die "Failed to create params directory" fi + +if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + if [ ! -r "$PRIMHASH_FILE" ]; then + sha256sum /tmp/primary.handle > "$PRIMHASH_FILE" \ + || die "ERROR: Failed to Hash TPM2 primary key handle!" + fi +fi + rm $paramsdir/kexec_default.*.txt 2>/dev/null || true echo "$entry" > $ENTRY_FILE ( cd $bootdir && kexec-boot -b "$bootdir" -e "$entry" -f| \ @@ -179,8 +188,10 @@ fi # sign and auto-roll config counter extparam= -if [ "$CONFIG_TPM" = "y" ]; then - extparam=-r +if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ];then + if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then + extparam=-r + fi fi kexec-sign-config -p $paramsdir $extparam \ || die "Failed to sign default config" diff --git a/initrd/bin/kexec-save-key b/initrd/bin/kexec-save-key index 7a20fafa..4c89f6ce 100755 --- a/initrd/bin/kexec-save-key +++ b/initrd/bin/kexec-save-key @@ -61,8 +61,12 @@ kexec-seal-key $paramsdir \ || die "Failed to save and generate key in TPM" if [ "$skip_sign" != "y" ]; then + extparam= + if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then + extparam=-r + fi # sign and auto-roll config counter - kexec-sign-config -p $paramsdir -r \ + kexec-sign-config -p $paramsdir $extparam \ || die "Failed to sign updated config" fi diff --git a/initrd/bin/kexec-seal-key b/initrd/bin/kexec-seal-key index 96f4d1ce..7789eb61 100755 --- a/initrd/bin/kexec-seal-key +++ b/initrd/bin/kexec-seal-key @@ -36,20 +36,27 @@ if [ -r "$KEY_LVM" ]; then || die "$VOLUME_GROUP: unable to activate volume group" fi -# Key slot 0 is the manual recovery pass phrase -# that they user entered when they installed Qubes, +echo "DEBUG: CONFIG_TPM: $CONFIG_TPM" +echo "DEBUG: CONFIG_TPM2_TOOLS: $CONFIG_TPM2_TOOLS" +echo "DEBUG: Show PCRs" +pcrs + +# LUKS Key slot 0 is the manual recovery pass phrase +# that they user entered when they installed OS, # key slot 1 is the one that we've generated. read -s -p "Enter disk recovery key: " disk_password echo -n "$disk_password" > "$RECOVERY_KEY" echo -read -s -p "New disk unlock password for booting: " key_password -echo -read -s -p "Repeat unlock code: " key_password2 -echo +if [ "$CONFIG_AUTO_UNLOCK" != y ]; then + read -s -p "New disk unlock password for booting: " key_password + echo + read -s -p "Repeat unlock code: " key_password2 + echo -if [ "$key_password" != "$key_password2" ]; then - die "Key passwords do not match" + if [ "$key_password" != "$key_password2" ]; then + die "Key passwords do not match" + fi fi # Generate key file @@ -83,73 +90,138 @@ done # since it should still be zero cat "$KEY_DEVICES" | cut -d\ -f1 | xargs /bin/qubes-measure-luks \ || die "Unable to measure the LUKS headers" -luks_pcr=`tpm calcfuturepcr -ix 16 -if /tmp/luksDump.txt` -# HOTP USB Secrity Dongle loads USB modules which changes PCR5. -# In the event HOTP USB Security Dongle is enabled, skip verification of PCR5 -if [ -x /bin/hotp_verification ]; then - pcr_5="X" -else - pcr_5="0000000000000000000000000000000000000000" -fi - -# Note that PCR 4 needs to be set with the "normal-boot" -# path value, which we do not have right now since we are -# in a recovery shell. -# used to be -ix 4 f8fa3b6e32e7c6fe04c366e74636e505b28f3b0d \ -# now just all zeros in a normal boot -# PCR 5 must be all zero since no kernel modules should have -# been loaded during a normal boot, but might have been -# loaded in the recovery shell. -# Otherwise use the current values of the PCRs, which will be read -# from the TPM as part of the sealing ("X"). -tpm sealfile2 \ - -if "$KEY_FILE" \ - -of "$TPM_SEALED" \ - -pwdd "$key_password" \ - -hk 40000000 \ - -ix 0 X \ - -ix 1 X \ - -ix 2 X \ - -ix 3 X \ - -ix 4 0000000000000000000000000000000000000000 \ - -ix 5 $pcr_5 \ - -ix 6 $luks_pcr \ - -ix 7 X \ -|| die "Unable to seal secret" - -shred -n 10 -z -u "$KEY_FILE" 2> /dev/null \ -|| die "Failed to delete key file" - -# try it without the owner password first -if ! tpm nv_writevalue \ - -in $TPM_INDEX \ - -if "$TPM_SEALED" \ -; then - # to create an nvram space we need the TPM owner password - # and the TPM physical presence must be asserted. +if [ "$CONFIG_TPM" = "y" ];then + luks_pcr=`tpm calcfuturepcr -ix 16 -if /tmp/luksDump.txt` + # HOTP USB Secrity Dongle loads USB modules which changes PCR5. + # In the event HOTP USB Security Dongle is enabled, skip verification of PCR5 + # If modules should be loaded during normal boot, skip verification of PCR5 # - # The permissions are 0 since there is nothing special - # about the sealed file - tpm physicalpresence -s \ - || warn "Warning: Unable to assert physical presence" + #TODO: check condition, no libdata.ko + if [ "$CONFIG_USB_KEYBOARD" = "y" -o -r /lib/modules/libata.ko -o -x /bin/hotp_verification ]; then + pcr_5="X" + else + pcr_5="0000000000000000000000000000000000000000" + fi - read -s -p "TPM Owner password: " tpm_password - echo + # Note that PCR 4 needs to be set with the "normal-boot" + # path value, which we do not have right now since we are + # in a "init" mode + # used to be -ix 4 f8fa3b6e32e7c6fe04c366e74636e505b28f3b0d \ + # now just all zeros in a normal boot + # PCR 5 must be all zero since no kernel modules should have + # been loaded during a normal boot, but might have been + # loaded in the recovery shell. + # Otherwise use the current values of the PCRs, which will be read + # from the TPM as part of the sealing ("X"). + if [ "$CONFIG_AUTO_UNLOCK" != y ]; then + tpm sealfile2 \ + -if "$KEY_FILE" \ + -of "$TPM_SEALED" \ + -pwdd "$key_password" \ + -hk 40000000 \ + -ix 0 X \ + -ix 1 X \ + -ix 2 X \ + -ix 3 X \ + -ix 4 0000000000000000000000000000000000000000 \ + -ix 5 $pcr_5 \ + -ix 6 $luks_pcr \ + -ix 7 X + else + tpm sealfile2 \ + -if "$KEY_FILE" \ + -of "$TPM_SEALED" \ + -hk 40000000 \ + -ix 0 X \ + -ix 1 X \ + -ix 2 X \ + -ix 3 X \ + -ix 4 0000000000000000000000000000000000000000 \ + -ix 5 $pcr_5 \ + -ix 6 $luks_pcr \ + -ix 7 X + fi - tpm nv_definespace \ - -in $TPM_INDEX \ - -sz $TPM_SIZE \ - -pwdo "$tpm_password" \ - -per 0 \ - || warn "Warning: Unable to define NVRAM space; trying anyway" + if [ $? -ne 0 ]; then + die "Unable to seal secret" + fi + shred -n 10 -z -u "$KEY_FILE" 2> /dev/null \ + || die "Failed to delete key file" - tpm nv_writevalue \ + # try it without the owner password first + if ! tpm nv_writevalue \ -in $TPM_INDEX \ -if "$TPM_SEALED" \ - || die "Unable to write sealed secret to NVRAM" + ; then + # to create an nvram space we need the TPM owner password + # and the TPM physical presence must be asserted. + # + # The permissions are 0 since there is nothing special + # about the sealed file + tpm physicalpresence -s \ + || warn "Warning: Unable to assert physical presence" + + read -s -p "TPM Owner password: " tpm_password + echo + + tpm nv_definespace \ + -in $TPM_INDEX \ + -sz $TPM_SIZE \ + -pwdo "$tpm_password" \ + -per 0 \ + || warn "Warning: Unable to define NVRAM space; trying anyway" + + + tpm nv_writevalue \ + -in $TPM_INDEX \ + -if "$TPM_SEALED" \ + || die "Unable to write sealed secret to NVRAM" + fi +elif [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + pcrf="/tmp/secret/pcrf.bin" + #TODO: verify logic below against tpm2 + tpm2 pcrread -o "$pcrf" sha256:0,1,2,3 + # pcr 4 is expected to be zero (init mode) + dd if=/dev/zero bs=32 count=1 >> "$pcrf" + if [ "$CONFIG_USB_KEYBOARD" = "y" -o -r /lib/modules/libata.ko -o -x /bin/hotp_verification ]; then + # Here, we take pcr 5 into consideration if modules are expected to be measured+loaded + # + # binary pcr dump can only go via stderr for redirection + # sadly this busybox has buggy support for "2>>" and "2|" + # so we need workaround... + tpm2 pcrread -o /dev/stderr sha256:5 2>&1 >/dev/console | cat >> "$pcrf" + else + #no kernel modules are expected to be measured+loaded + dd if=/dev/zero bs=32 count=1 >> "$pcrf" + fi + # Use pcr 23 to precompute the value for pcr 6 + tpmr extend -ix 23 -if /tmp/luksDump.txt + tpm2 pcrread -o /dev/stderr sha256:23 2>&1 >/dev/console | cat >> "$pcrf" + #TODO: delete the following pcrs output on screen + # goal is to validate that what is in pcr 23 is at pcr 6 at unseal + pcrs + tpm2 pcrreset 23 + # We take into consideration user files in cbfs + tpm2 pcrread -o /dev/stderr sha256:7 2>&1 >/dev/console | cat >> "$pcrf" + if [ "$CONFIG_AUTO_UNLOCK" = "y" ]; then + #TODO: There is no CONFIG_AUTO_UNLOCK. Should be removed + tpmr seal "$KEY_FILE" "0x8100000$TPM_INDEX" sha256:0,1,2,3,4,5,6,7 "$pcrf" + else + #TODO: wrap TPM disk encryption key passphrase, otherwise prompt to user looks like if we were asking for TPM ownership passphrase + #TODO: everything is supposed to be under $pcrf, why considering them twice? + # TODO: review syntax to not duplicate expending pcr 2 times with pcr0-7: find a way to only use $pcrf? : sha256 "$pcrf" "$key_password" + tpmr seal "$KEY_FILE" "0x8100000$TPM_INDEX" sha256:0,1,2,3,4,5,6,7 "$pcrf" "$key_password" + fi + if [ $? -eq 0 ]; then + # should be okay if this fails + shred -n 10 -z -u "$pcrf".* 2> /dev/null || true + fi fi shred -n 10 -z -u "$TPM_SEALED" 2> /dev/null \ || warn "Failed to delete the sealed secret - continuing" + +cp /tmp/luksDump.txt "$paramsdir/kexec_lukshdr_hash.txt" \ +|| warn "Failed to have hashes of LUKS header - continuing" diff --git a/initrd/bin/kexec-select-boot b/initrd/bin/kexec-select-boot index d0fe1b44..3ddf4fcd 100755 --- a/initrd/bin/kexec-select-boot +++ b/initrd/bin/kexec-select-boot @@ -50,6 +50,22 @@ bootdir="${bootdir%%/}" paramsdev="${paramsdev%%/}" paramsdir="${paramsdir%%/}" +PRIMHASH_FILE="$paramsdir/kexec_primhdl_hash.txt" +if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + if [ -r "$PRIMHASH_FILE" ]; then + sha256sum -c "$PRIMHASH_FILE" \ + || { + echo "FATAL: Hash of TPM2 primary key handle mismatch!"; + echo "If you have not intentionally regenerated TPM2 primary key,"; + warn "your system may have been compromised!"; + } + else + echo "WARNING: Hash of TPM2 primary key handle does not exist!" + echo "Please rebuild the boot hash tree." + default_failed="y" + fi +fi + verify_global_hashes() { echo "+++ Checking verified boot hash file " @@ -299,23 +315,22 @@ do_boot() die "!!! Missing required boot hashes" fi - if [ "$CONFIG_TPM" = "y" \ - -a -r "$TMP_KEY_DEVICES" ]; then + if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ] && [ -r "$TMP_KEY_DEVICES" ]; then INITRD=`kexec-boot -b "$bootdir" -e "$option" -i` \ - || die "!!! Failed to extract the initrd from boot option" + || die "!!! Failed to extract the initrd from boot option" if [ -z "$INITRD" ]; then die "!!! No initrd file found in boot option" fi kexec-insert-key $INITRD \ - || die "!!! Failed to insert disk key into a new initrd" + || die "!!! Failed to insert disk key into a new initrd" kexec-boot -b "$bootdir" -e "$option" \ -a "$add" -r "$remove" -o "/tmp/secret/initrd.cpio" \ - || die "!!! Failed to boot w/ options: $option" + || die "!!! Failed to boot w/ options: $option" else kexec-boot -b "$bootdir" -e "$option" -a "$add" -r "$remove" \ - || die "!!! Failed to boot w/ options: $option" + || die "!!! Failed to boot w/ options: $option" fi } @@ -344,11 +359,12 @@ while true; do user_select fi - if [ "$CONFIG_TPM" = "y" \ - -a ! -r "$TMP_KEY_DEVICES" ]; then - # Extend PCR4 as soon as possible - tpm extend -ix 4 -ic generic \ - || die "Failed to extend PCR 4" + if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ]; then + if [ ! -r "$TMP_KEY_DEVICES" ]; then + # Extend PCR4 as soon as possible + tpmr extend -ix 4 -ic generic \ + || die "Failed to extend PCR 4" + fi fi # if no saved options, scan the boot directory and generate @@ -356,7 +372,7 @@ while true; do scan_options fi - if [ "$CONFIG_TPM" = "y" ]; then + if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ]; then # Optionally enforce device file hashes if [ -r "$TMP_HASH_FILE" ]; then valid_global_hash="n" @@ -368,7 +384,7 @@ while true; do fi fi - if [ -r "$TMP_ROLLBACK_FILE" ]; then + if [ "$CONFIG_IGNORE_ROLLBACK" != "y" -a -r "$TMP_ROLLBACK_FILE" ]; then # in the case of iso boot with a rollback file, do not assume valid valid_rollback="n" diff --git a/initrd/bin/kexec-unseal-key b/initrd/bin/kexec-unseal-key index d35e8b78..7f7ee347 100755 --- a/initrd/bin/kexec-unseal-key +++ b/initrd/bin/kexec-unseal-key @@ -18,26 +18,60 @@ if [ -z "$key_file" ]; then key_file="/tmp/secret/secret.key" fi -tpm nv_readvalue \ - -in "$TPM_INDEX" \ - -sz "$TPM_SIZE" \ - -of "$sealed_file" \ -|| die "Unable to read key from TPM NVRAM" +echo "DEBUG: CONFIG_TPM: $CONFIG_TPM" +echo "DEBUG: CONFIG_TPM2_TOOLS: $CONFIG_TPM2_TOOLS" +echo "DEBUG: Show PCRs" +pcrs -for tries in 1 2 3; do - read -s -p "Enter unlock password (blank to abort): " tpm_password - echo +if [ "$CONFIG_TPM" = "y" ];then + tpm nv_readvalue \ + -in "$TPM_INDEX" \ + -sz "$TPM_SIZE" \ + -of "$sealed_file" \ + || die "Unable to read key from TPM NVRAM" - if [ -z "$tpm_password" ]; then - die "Aborting unseal disk encryption key" + for tries in 1 2 3; do + if [ "$CONFIG_AUTO_UNLOCK" != y ]; then + read -s -p "Enter unlock password (blank to abort): " tpm_password + echo + if [ -z "$tpm_password" ]; then + die "Aborting unseal disk encryption key" + fi + + tpm unsealfile \ + -if "$sealed_file" \ + -of "$key_file" \ + -pwdd "$tpm_password" \ + -hk 40000000 + else + tpm unsealfile \ + -if "$sealed_file" \ + -of "$key_file" \ + -hk 40000000 + fi + + if [ $? -eq 0 ]; then + # should be okay if this fails + shred -n 10 -z -u /tmp/secret/sealed 2> /dev/null || true + exit 0 + fi + + pcrs + warn "Unable to unseal disk encryption key" + done +elif [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + if [ "$CONFIG_ATTEST_TOOLS" = "y" ]; then + echo "Bring up network for remote attestation" + network-init-recovery + fi + for tries in 1 2 3; do + if [ "$CONFIG_AUTO_UNLOCK" = "y" ]; then + tpmr unseal "0x8100000$TPM_INDEX" "sha256:0,1,2,3,4,5,6,7" > "$key_file" + else + tpmr unseal "0x8100000$TPM_INDEX" "sha256:0,1,2,3,4,5,6,7" "file:-" > "$key_file" fi - if tpm unsealfile \ - -if "$sealed_file" \ - -of "$key_file" \ - -pwdd "$tpm_password" \ - -hk 40000000 \ - ; then + if [ $? -eq 0 ]; then # should be okay if this fails shred -n 10 -z -u /tmp/secret/sealed 2> /dev/null || true exit 0 @@ -46,5 +80,6 @@ for tries in 1 2 3; do pcrs warn "Unable to unseal disk encryption key" done +fi die "Retry count exceeded..." diff --git a/initrd/bin/oem-factory-reset b/initrd/bin/oem-factory-reset index dcb121f7..cb162e22 100755 --- a/initrd/bin/oem-factory-reset +++ b/initrd/bin/oem-factory-reset @@ -57,7 +57,7 @@ die() { exit 1 } -whiptail_error() +whiptail_error() { local msg=$1 if [ "$msg" = "" ]; then @@ -66,7 +66,7 @@ whiptail_error() whiptail $BG_COLOR_ERROR --msgbox "${msg}\n\n" $HEIGHT $WIDTH $BG_COLOR_ERROR --title "Error" } -whiptail_error_die() +whiptail_error_die() { whiptail_error "$@" die @@ -131,11 +131,11 @@ gpg_key_reset() echo ${USER_PIN_DEF} echo 0 echo y - echo ${GPG_USER_NAME} + echo ${GPG_USER_NAME} echo ${GPG_USER_MAIL} echo ${GPG_USER_COMMENT} } | gpg --command-fd=0 --status-fd=2 --pinentry-mode=loopback --card-edit \ - > /tmp/gpg_card_edit_output 2>/dev/null + > /tmp/gpg_card_edit_output 2>/dev/null if [ $? -ne 0 ]; then ERROR=`cat /tmp/gpg_card_edit_output` whiptail_error_die "GPG Key automatic keygen failed!\n\n$ERROR" @@ -159,7 +159,7 @@ gpg_key_change_pin() echo q echo q } | gpg --command-fd=0 --status-fd=2 --pinentry-mode=loopback --card-edit \ - > /tmp/gpg_card_edit_output 2>/dev/null + > /tmp/gpg_card_edit_output 2>/dev/null if [ $? -ne 0 ]; then ERROR=`cat /tmp/gpg_card_edit_output | fold -s` whiptail_error_die "GPG Key PIN change failed!\n\n$ERROR" @@ -184,26 +184,28 @@ generate_checksums() rm /boot/kexec* 2>/dev/null # create Heads TPM counter - if [ "$CONFIG_TPM" = "y" ]; then - tpm counter_create \ - -pwdo "$TPM_PASS" \ - -pwdc '' \ - -la -3135106223 \ - | tee /tmp/counter \ - || whiptail_error_die "Unable to create TPM counter" - TPM_COUNTER=`cut -d: -f1 < /tmp/counter` + if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ];then + if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then + tpmr counter_create \ + -pwdo "$TPM_PASS_DEF" \ + -pwdc '' \ + -la -3135106223 \ + | tee /tmp/counter \ + || whiptail_error_die "Unable to create TPM counter" + TPM_COUNTER=`cut -d: -f1 < /tmp/counter` - # increment TPM counter - increment_tpm_counter $TPM_COUNTER >/dev/null 2>&1 \ - || whiptail_error_die "Unable to increment tpm counter" + # increment TPM counter + increment_tpm_counter $TPM_COUNTER >/dev/null 2>&1 \ + || whiptail_error_die "Unable to increment tpm counter" - # create rollback file - sha256sum /tmp/counter-$TPM_COUNTER > /boot/kexec_rollback.txt 2>/dev/null \ - || whiptail_error_die "Unable to create rollback file" - else - ## needs to exist for initial call to unseal-hotp - echo "0" > /boot/kexec_hotp_counter - fi + # create rollback file + sha256sum /tmp/counter-$TPM_COUNTER > /boot/kexec_rollback.txt 2>/dev/null \ + || whiptail_error_die "Unable to create rollback file" + else + ## needs to exist for initial call to unseal-hotp + echo "0" > /boot/kexec_hotp_counter + fi + fi # set default boot option only if no TPM Disk Unlock Key previously set if [ -z "$TPM_DISK_ENCRYPTION_KEY_SET" ]; then @@ -370,7 +372,7 @@ else fi # show warning prompt -if [ "$CONFIG_TPM" = "y" ]; then +if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ]; then TPM_STR=" * ERASE the TPM and own it with a password\n" else TPM_STR="" @@ -612,10 +614,12 @@ if [ "$CONFIG_TPM" = "y" ]; then echo $TPM_PASS echo $TPM_PASS } | /bin/tpm-reset >/dev/null 2>/tmp/error - if [ $? -ne 0 ]; then - ERROR=$(tail -n 1 /tmp/error | fold -s) - whiptail_error_die "Error resetting TPM:\n\n${ERROR}" - fi +elif [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + tpmr reset +fi +if [ $? -ne 0 ]; then + ERROR=$(tail -n 1 /tmp/error | fold -s) + whiptail_error_die "Error resetting TPM:\n\n${ERROR}" fi # clear local keyring diff --git a/initrd/bin/qubes-measure-luks b/initrd/bin/qubes-measure-luks index b277af7e..e40881e4 100755 --- a/initrd/bin/qubes-measure-luks +++ b/initrd/bin/qubes-measure-luks @@ -17,5 +17,5 @@ done sha256sum /tmp/lukshdr-* > /tmp/luksDump.txt || die "Unable to hash luks headers" rm /tmp/lukshdr-* -tpm extend -ix 6 -if /tmp/luksDump.txt \ +tpmr extend -ix 6 -if /tmp/luksDump.txt \ || die "Unable to extend PCR" diff --git a/initrd/bin/seal-hotpkey b/initrd/bin/seal-hotpkey index 6309be68..988f9d47 100755 --- a/initrd/bin/seal-hotpkey +++ b/initrd/bin/seal-hotpkey @@ -27,17 +27,23 @@ else HOTPKEY_BRANDING="HOTP USB Security Dongle" fi -tpm nv_readvalue \ - -in 4d47 \ - -sz 312 \ - -of "$HOTP_SEALED" \ -|| die "Unable to retrieve sealed file from TPM NV" +if [ $CONFIG_TPM = "y" ]; then + tpm nv_readvalue \ + -in 4d47 \ + -sz 312 \ + -of "$HOTP_SEALED" \ + || die "Unable to retrieve sealed file from TPM NV" + + tpm unsealfile \ + -hk 40000000 \ + -if "$HOTP_SEALED" \ + -of "$HOTP_SECRET" \ + || die "Unable to unseal HOTP secret" +elif [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + tpmr unseal 0x81004d47 sha256:0,1,2,3,4,7 > "$HOTP_SECRET" \ + || die "Unable to unseal HOTP secret" +fi -tpm unsealfile \ - -hk 40000000 \ - -if "$HOTP_SEALED" \ - -of "$HOTP_SECRET" \ -|| die "Unable to unseal HOTP secret" shred -n 10 -z -u "$HOTP_SEALED" 2> /dev/null diff --git a/initrd/bin/seal-totp b/initrd/bin/seal-totp index 57388daf..610f8a4a 100755 --- a/initrd/bin/seal-totp +++ b/initrd/bin/seal-totp @@ -28,59 +28,71 @@ dd \ || die "Unable to generate 20 random bytes" secret="`base32 < $TOTP_SECRET`" +if [ "$CONFIG_TPM" = "y" ];then + # Use the current values of the PCRs, which will be read + # from the TPM as part of the sealing ("X"). + # PCR4 == 0 means that we are still in the boot process and + # not a recovery shell. + # should this read the storage root key? + if ! tpm sealfile2 \ + -if "$TOTP_SECRET" \ + -of "$TOTP_SEALED" \ + -hk 40000000 \ + -ix 0 X \ + -ix 1 X \ + -ix 2 X \ + -ix 3 X \ + -ix 4 0000000000000000000000000000000000000000 \ + -ix 7 X \ + ; then + shred -n 10 -z -u "$TOTP_SECRET" 2> /dev/null + die "Unable to seal secret" + fi -# Use the current values of the PCRs, which will be read -# from the TPM as part of the sealing ("X"). -# PCR4 == 0 means that we are still in the boot process and -# not a recovery shell. -# should this read the storage root key? -if ! tpm sealfile2 \ - -if "$TOTP_SECRET" \ - -of "$TOTP_SEALED" \ - -hk 40000000 \ - -ix 0 X \ - -ix 1 X \ - -ix 2 X \ - -ix 3 X \ - -ix 4 0000000000000000000000000000000000000000 \ - -ix 7 X \ -; then shred -n 10 -z -u "$TOTP_SECRET" 2> /dev/null - die "Unable to seal secret" -fi - -shred -n 10 -z -u "$TOTP_SECRET" 2> /dev/null -# to create an nvram space we need the TPM owner password -# and the TPM physical presence must be asserted. -# -# The permissions are 0 since there is nothing special -# about the sealed file -tpm physicalpresence -s \ -|| warn "Warning: Unable to assert physical presence" + # to create an nvram space we need the TPM owner password + # and the TPM physical presence must be asserted. + # + # The permissions are 0 since there is nothing special + # about the sealed file + tpm physicalpresence -s \ + || warn "Warning: Unable to assert physical presence" -# Try to write it without the password first, and then create -# the NVRAM space using the owner password if it fails for some reason. -if ! tpm nv_writevalue \ - -in $TPM_NVRAM_SPACE \ - -if "$TOTP_SEALED" \ -; then - warn 'NVRAM space does not exist? Owner password is required' - read -s -p "TPM Owner password: " tpm_password - echo + # Try to write it without the password first, and then create + # the NVRAM space using the owner password if it fails for some reason. + if ! tpm nv_writevalue \ + -in $TPM_NVRAM_SPACE \ + -if "$TOTP_SEALED" \ + ; then + warn 'NVRAM space does not exist? Owner password is required' + read -s -p "TPM Owner password: " tpm_password + echo - tpm nv_definespace \ - -in $TPM_NVRAM_SPACE \ - -sz 312 \ - -pwdo "$tpm_password" \ - -per 0 \ - || die "Unable to define NVRAM space" + tpm nv_definespace \ + -in $TPM_NVRAM_SPACE \ + -sz 312 \ + -pwdo "$tpm_password" \ + -per 0 \ + || die "Unable to define NVRAM space" - tpm nv_writevalue \ - -in $TPM_NVRAM_SPACE \ - -if "$TOTP_SEALED" \ - || die "Unable to write sealed secret to NVRAM" + tpm nv_writevalue \ + -in $TPM_NVRAM_SPACE \ + -if "$TOTP_SEALED" \ + || die "Unable to write sealed secret to NVRAM" + fi +elif [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + pcrf="/tmp/secret/pcrf.bin" + tpm2 pcrread -o "$pcrf" sha256:0,1,2,3 + # pcr 4 is expected to be zero (boot mode: init) + dd if=/dev/zero bs=32 count=1 >> "$pcrf" + # pcr 5 (kernel modules loaded) is not measured at sealing/unsealing of totp + # pcr 6 (drive luks header) is not measured at sealing/unsealing of totp + # pcr 7 is containing measurements of user injected stuff in cbfs + tpm2 pcrread -o /dev/stderr sha256:7 2>&1 >/dev/console | cat >> "$pcrf" + tpmr seal "$TOTP_SECRET" "0x8100$TPM_NVRAM_SPACE" sha256:0,1,2,3,4,7 "$pcrf" \ + || die "Unable to write sealed secret to NVRAM" fi shred -n 10 -z -u "$TOTP_SEALED" 2> /dev/null diff --git a/initrd/bin/tpm-reset b/initrd/bin/tpm-reset index 8a8b9d1c..d3c33d00 100755 --- a/initrd/bin/tpm-reset +++ b/initrd/bin/tpm-reset @@ -1,34 +1,40 @@ #!/bin/sh . /etc/functions -echo '*****' -echo '***** WARNING: This will erase all keys and secrets from the TPM' -echo '*****' +if [ "$CONFIG_TPM" = "y" ]; then + echo '*****' + echo '***** WARNING: This will erase all keys and secrets from the TPM' + echo '*****' -read -s -p "New TPM owner password: " key_password -echo + read -s -p "New TPM owner password: " key_password + echo -if [ -z "$key_password" ]; then - die "Empty owner password is not allowed" + if [ -z "$key_password" ]; then + die "Empty owner password is not allowed" + fi + + read -s -p "Repeat owner password: " key_password2 + echo + + + if [ "$key_password" != "$key_password2" ]; then + die "Key passwords do not match" + fi + + # Make sure the TPM is ready to be reset + tpm physicalpresence -s + tpm physicalenable + tpm physicalsetdeactivated -c + tpm forceclear + tpm physicalenable + tpm takeown -pwdo "$key_password" + + # And now turn it all back on + tpm physicalpresence -s + tpm physicalenable + tpm physicalsetdeactivated -c fi -read -s -p "Repeat owner password: " key_password2 -echo - - -if [ "$key_password" != "$key_password2" ]; then - die "Key passwords do not match" +if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + tpmr reset fi - -# Make sure the TPM is ready to be reset -tpm physicalpresence -s -tpm physicalenable -tpm physicalsetdeactivated -c -tpm forceclear -tpm physicalenable -tpm takeown -pwdo "$key_password" - -# And now turn it all back on -tpm physicalpresence -s -tpm physicalenable -tpm physicalsetdeactivated -c diff --git a/initrd/bin/tpmr b/initrd/bin/tpmr new file mode 100755 index 00000000..05b46dfb --- /dev/null +++ b/initrd/bin/tpmr @@ -0,0 +1,212 @@ +#!/bin/sh +# TPM Wrapper - to unify tpm and tpm2 subcommands + +. /etc/functions + +SECRET_DIR="/tmp/secret" +PRIMARY_HANDLE="0x81000000" +ENC_SESSION_FILE="enc.ctx" +DEC_SESSION_FILE="dec.ctx" +PRIMARY_HANDLE_FILE="primary.handle" + +set -e -o pipefail +if [ -r "/tmp/config" ]; then + . /tmp/config +else + . /etc/config +fi + +# tpm1 does not need to convert options +if [ "$CONFIG_TPM" = "y" ]; then + exec tpm "$@" +fi + +if [ "$CONFIG_TPM2_TOOLS" != "y" ]; then + echo >&2 "No TPM2!" + exit 1 +fi + +tpm2_extend() { + while true; do + case "$1" in + -ix) + index="$2" + shift 2;; + -ic) + hash="`echo $2|sha256sum|cut -d' ' -f1`" + shift 2;; + -if) + hash="`sha256sum $2|cut -d' ' -f1`" + shift 2;; + *) + break;; + esac + done + tpm2 pcrextend "$index:sha256=$hash" + exec tpm2 pcrread "sha256:$index" +} + +tpm2_counter_read() { + while true; do + case "$1" in + -ix) + index="$2" + shift 2;; + *) + break;; + esac + done + echo "$index: `tpm2 nvread 0x$index | xxd -pc8`" +} + +tpm2_counter_inc() { + while true; do + case "$1" in + -ix) + index="$2" + shift 2;; + -pwdc) + pwd="$2" + shift 2;; + *) + break;; + esac + done + tpm2 nvincrement "0x$index" > /dev/console + echo "$index: `tpm2 nvread 0x$index | xxd -pc8`" +} + +tpm2_counter_cre() { + while true; do + case "$1" in + -pwdo) + pwdo="$2" + shift 2;; + -pwdof) + pwdo="file:$2" + shift 2;; + -pwdc) + pwd="$2" + shift 2;; + -la) + label="$2" + shift 2;; + *) + break;; + esac + done + rand_index="1`dd if=/dev/urandom bs=1 count=3 | xxd -pc3`" + tpm2 nvdefine -C o -s 8 -a "ownerread|authread|authwrite|nt=1" -P "$pwdo" "0x$rand_index" > /dev/console + echo "$rand_index: (valid after an increment)" +} + +tpm2_startsession() { + mkdir -p "$SECRET_DIR" + tpm2 flushcontext \ + --transient-object \ + || die "tpm2_flushcontext: unable to flush transient handles" + + tpm2 flushcontext \ + --loaded-session \ + || die "tpm2_flushcontext: unable to flush sessions" + + tpm2 flushcontext \ + --saved-session \ + || die "tpm2_flushcontext: unable to flush saved session" + tpm2 readpublic -c "$PRIMARY_HANDLE" -t "/tmp/$PRIMARY_HANDLE_FILE" + tpm2 startauthsession -c "/tmp/$PRIMARY_HANDLE_FILE" --hmac-session -S "/tmp/$ENC_SESSION_FILE" + tpm2 startauthsession -c "/tmp/$PRIMARY_HANDLE_FILE" --hmac-session -S "/tmp/$DEC_SESSION_FILE" + tpm2 sessionconfig --disable-encrypt "/tmp/$DEC_SESSION_FILE" +} + +tpm2_sealfile() { + #TODO remove this: tpmr seal "$KEY_FILE" "0x8100000$TPM_INDEX" sha256:0,1,2,3,4,5,6,7 "$pcrf" "$key_password" + file="$1" #$KEY_FILE + handle="$2" # 0x8100000$TPM_INDEX + pcrl="$3" #sha256:0,1,2,3,4,5,6,7 + pcrf="$4" + pass="$5" + mkdir -p "$SECRET_DIR" + bname="`basename $file`" + tpm2 createpolicy --policy-pcr -l "$pcrl" -f "$pcrf" -L "$SECRET_DIR/pcr.policy" + if [ "$pass" ];then + tpm2 create -C "/tmp/$PRIMARY_HANDLE_FILE" -i "$file" -u "$SECRET_DIR/$bname.priv" -r "$SECRET_DIR/$bname.pub" -L "$SECRET_DIR/pcr.policy" -S "/tmp/$DEC_SESSION_FILE" -p "$pass" + else + tpm2 create -C "/tmp/$PRIMARY_HANDLE_FILE" -i "$file" -u "$SECRET_DIR/$bname.priv" -r "$SECRET_DIR/$bname.pub" -L "$SECRET_DIR/pcr.policy" -S "/tmp/$DEC_SESSION_FILE" + fi + tpm2 load -C "/tmp/$PRIMARY_HANDLE_FILE" -u "$SECRET_DIR/$bname.priv" -r "$SECRET_DIR/$bname.pub" -c "$SECRET_DIR/$bname.seal.ctx" + read -s -p "New TPM owner password: " key_password + # remove possible data occupying this handle + tpm2 evictcontrol -C o -P "$key_password" -c "$handle" 2>/dev/null || true + tpm2 evictcontrol -C o -P "$key_password" -c "$SECRET_DIR/$bname.seal.ctx" "$handle" +} + +tpm2_unseal() { + #TODO: remove this: tpmr unseal "0x8100000$TPM_INDEX" "sha256:0,1,2,3,4,5,6,7" "file:-" > "$key_file" + handle="$1" + pcrl="$2" + pass="$3" + echo "debug handle: $handle prcl: $pcrl pass $pass" + if [ "$pass" ];then + tpm2 unseal -c "$handle" -S "/tmp/$ENC_SESSION_FILE" -p "pcr:$pcrl+$pass" + else + tpm2 unseal -c "$handle" -S "/tmp/$ENC_SESSION_FILE" -p "pcr:$pcrl" + fi +} + +tpm2_reset() { + echo '*****' + echo '***** WARNING: This will erase all keys and secrets from the TPM' + echo '*****' + + read -s -p "New TPM owner password: " key_password + echo + + if [ -z "$key_password" ]; then + die "Empty owner password is not allowed" + fi + + read -s -p "Repeat owner password: " key_password2 + echo + + + if [ "$key_password" != "$key_password2" ]; then + die "Key passwords do not match" + fi + mkdir -p "$SECRET_DIR" + tpm2 clear -c platform || warn "Unable to clear TPM on platform hierarchy!" + tpm2 changeauth -c owner "$key_password" + tpm2 createprimary -C owner -g sha256 -G "${CONFIG_PRIMARY_KEY_TYPE:-rsa}" -c "$SECRET_DIR/primary.ctx" -P "$key_password" + tpm2 evictcontrol -C owner -c "$SECRET_DIR/primary.ctx" "$PRIMARY_HANDLE" -P "$key_password" + shred -u "$SECRET_DIR/primary.ctx" + tpm2_startsession +} +subcmd="$1" +shift 1 +case "$subcmd" in + extend) + tpm2_extend "$@";; + counter_read) + tpm2_counter_read "$@";; + counter_increment) + tpm2_counter_inc "$@";; + counter_create) + tpm2_counter_cre "$@";; + nv_definespace) + tpm2_nvdef "$@";; + nv_writevalue) + tpm2_nvw "$@";; + nv_readvalue) + tpm2_nvr "$@";; + seal) + tpm2_sealfile "$@";; + startsession) + tpm2_startsession "$@";; + unseal) + tpm2_unseal "$@";; + reset) + tpm2_reset;; + *) + echo "Command $subcmd not wrapped!" + exit 1 +esac diff --git a/initrd/bin/uefi-init b/initrd/bin/uefi-init index 600d2072..08067ac9 100755 --- a/initrd/bin/uefi-init +++ b/initrd/bin/uefi-init @@ -18,8 +18,8 @@ if [ -n "GUID" ]; then uefi -r $GUID | gunzip -c > $TMPFILE \ || die "Failed to read config GUID from ROM" - if [ "$CONFIG_TPM" = "y" ]; then - tpm extend -ix "$CONFIG_PCR" -if $TMPFILE \ + if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ]; then + tpmr extend -ix "$CONFIG_PCR" -if $TMPFILE \ || die "$filename: tpm extend failed" fi diff --git a/initrd/bin/unseal-hotp b/initrd/bin/unseal-hotp index 3d2f6756..3e20db4c 100755 --- a/initrd/bin/unseal-hotp +++ b/initrd/bin/unseal-hotp @@ -38,19 +38,21 @@ if [ "$counter_value" == "" ]; then fi #counter_value=$(printf "%d" 0x${counter_value}) +if [ "$CONFIG_TPM" = "y" ]; then + tpm nv_readvalue \ + -in 4d47 \ + -sz 312 \ + -of "$HOTP_SEALED" \ + || die "Unable to retrieve sealed file from TPM NV" -tpm nv_readvalue \ - -in 4d47 \ - -sz 312 \ - -of "$HOTP_SEALED" \ -|| die "Unable to retrieve sealed file from TPM NV" - -tpm unsealfile \ - -hk 40000000 \ - -if "$HOTP_SEALED" \ - -of "$HOTP_SECRET" \ -|| die "Unable to unseal HOTP secret" - + tpm unsealfile \ + -hk 40000000 \ + -if "$HOTP_SEALED" \ + -of "$HOTP_SECRET" \ + || die "Unable to unseal HOTP secret" +elif [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + tpmr unseal 0x81004d47 sha256:0,1,2,3,4,7 >> "$HOTP_SECRET" +fi shred -n 10 -z -u "$HOTP_SEALED" 2> /dev/null if ! hotp $counter_value < "$HOTP_SECRET"; then diff --git a/initrd/bin/unseal-totp b/initrd/bin/unseal-totp index 63a36955..e46e32ff 100755 --- a/initrd/bin/unseal-totp +++ b/initrd/bin/unseal-totp @@ -8,17 +8,22 @@ TOTP_SECRET="/tmp/secret/totp.key" TRACE "Under /bin/unseal-totp" -tpm nv_readvalue \ - -in 4d47 \ - -sz 312 \ - -of "$TOTP_SEALED" \ -|| die "Unable to retrieve sealed file from TPM NV" +if [ "$CONFIG_TPM" = "y" ]; then + tpm nv_readvalue \ + -in 4d47 \ + -sz 312 \ + -of "$TOTP_SEALED" \ + || die "Unable to retrieve sealed file from TPM NV" -tpm unsealfile \ - -hk 40000000 \ - -if "$TOTP_SEALED" \ - -of "$TOTP_SECRET" \ -|| die "Unable to unseal totp secret" + tpm unsealfile \ + -hk 40000000 \ + -if "$TOTP_SEALED" \ + -of "$TOTP_SECRET" \ + || die "Unable to unseal totp secret" +elif [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + tpmr unseal 0x81004d47 sha256:0,1,2,3,4,7 > "$TOTP_SECRET" \ + || die "Unable to unseal totp secret" +fi shred -n 10 -z -u "$TOTP_SEALED" 2> /dev/null diff --git a/initrd/bin/usb-init b/initrd/bin/usb-init index 3ab79d10..94eb8b1e 100755 --- a/initrd/bin/usb-init +++ b/initrd/bin/usb-init @@ -6,9 +6,9 @@ TRACE "Under /bin/usb-init" -if [ "$CONFIG_TPM" = "y" ]; then +if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ]; then # Extend PCR4 as soon as possible - tpm extend -ix 4 -ic usb + tpmr extend -ix 4 -ic usb fi media-scan usb diff --git a/initrd/bin/wget-measure.sh b/initrd/bin/wget-measure.sh index e66e48b8..ec05df80 100755 --- a/initrd/bin/wget-measure.sh +++ b/initrd/bin/wget-measure.sh @@ -19,6 +19,6 @@ fi wget "$URL" || die "$URL: failed" FILE="`basename "$URL"`" -tpm extend -ix "$INDEX" -if "$FILE" || die "$FILE: tpm extend failed" +tpmr extend -ix "$INDEX" -if "$FILE" || die "$FILE: tpm extend failed" diff --git a/initrd/bin/x230-flash.init b/initrd/bin/x230-flash.init index 6807dd29..e5ea182b 100755 --- a/initrd/bin/x230-flash.init +++ b/initrd/bin/x230-flash.init @@ -14,7 +14,7 @@ insmod /lib/modules/xhci-pci.ko insmod /lib/modules/e1000e.ko insmod /lib/modules/usb-storage.ko -tpm extend -ix 4 -ic recovery +tpmr extend -ix 4 -ic recovery sleep 2 echo '***** Starting recovery shell' diff --git a/initrd/etc/fstab b/initrd/etc/fstab index 43d34e01..69987bdd 100644 --- a/initrd/etc/fstab +++ b/initrd/etc/fstab @@ -3,3 +3,4 @@ devpts /dev/pts devpts defaults 0 0 sysfs /sys sysfs defaults 0 0 proc /proc proc defaults 0 0 efivarfs /sys/firmware/efi/efivars efivarfs defaults 0 0 +securityfs /sys/kernel/security securityfs defaults 0 0 diff --git a/initrd/etc/functions b/initrd/etc/functions index d956b872..ad0086e4 100755 --- a/initrd/etc/functions +++ b/initrd/etc/functions @@ -41,8 +41,8 @@ recovery() { # ensure /tmp/config exists for recovery scripts that depend on it touch /tmp/config - if [ "$CONFIG_TPM" = y ]; then - tpm extend -ix 4 -ic recovery + if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ]; then + tpmr extend -ix 4 -ic recovery fi while [ true ] @@ -65,7 +65,11 @@ pause_recovery() { } pcrs() { - head -8 /sys/class/tpm/tpm0/pcrs + if [ "$CONFIG_TPM" = "y" ]; then + head -8 /sys/class/tpm/tpm0/pcrs + elif [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + tpm2 pcrread sha256 + fi } confirm_totp() @@ -81,7 +85,7 @@ confirm_totp() date=`date "+%Y-%m-%d %H:%M:%S"` seconds=`date "+%s"` half=`expr \( $seconds % 60 \) / 30` - if [ "$CONFIG_TPM" != y ]; then + if [ "$CONFIG_TPM" != "y" -a "$CONFIG_TPM2_TOOLS" != "y" ]; then TOTP="NO TPM" elif [ "$half" != "$last_half" ]; then last_half=$half; @@ -249,7 +253,7 @@ check_tpm_counter() warn "$1 does not exist; creating new TPM counter" read -s -p "TPM Owner password: " tpm_password echo - tpm counter_create \ + tpmr counter_create \ -pwdo "$tpm_password" \ -pwdc '' \ -la $LABEL \ @@ -266,14 +270,14 @@ check_tpm_counter() read_tpm_counter() { TRACE "Under /etc/functions:read_tpm_counter" - tpm counter_read -ix "$1" | tee "/tmp/counter-$1" \ + tpmr counter_read -ix "$1" | tee "/tmp/counter-$1" \ || die "Counter read failed" } increment_tpm_counter() { TRACE "Under /etc/functions:increment_tpm_counter" - tpm counter_increment -ix "$1" -pwdc '' \ + tpmr counter_increment -ix "$1" -pwdc '' \ | tee /tmp/counter-$1 \ || die "Counter increment failed" } @@ -358,8 +362,10 @@ update_checksums() # sign and auto-roll config counter extparam= - if [ "$CONFIG_TPM" = "y" ]; then - extparam=-r + if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ];then + if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then + extparam=-r + fi fi if ! kexec-sign-config -p /boot -u $extparam ; then rv=1 diff --git a/initrd/init b/initrd/init index 878c84f2..a1145998 100755 --- a/initrd/init +++ b/initrd/init @@ -16,6 +16,8 @@ mkdir /proc /sys /dev /tmp /boot /media 2>&- 1>&- mount /dev 2>/dev/ttyprintk mount /proc 2>/dev/ttyprintk mount /sys 2>/dev/ttyprintk +mount /sys/kernel/security 2>/dev/ttyprintk + if [ "$CONFIG_LINUXBOOT" = "y" ]; then mount /sys/firmware/efi/efivars fi @@ -28,6 +30,13 @@ if [ ! -r /dev/ptmx ]; then ln -s /dev/pts/ptmx /dev/ptmx fi + +[ -a /dev/stdin ] || ln -s /proc/self/fd/0 /dev/stdin +[ -a /dev/stdout ] || ln -s /proc/self/fd/1 /dev/stdout +[ -a /dev/stderr ] || ln -s /proc/self/fd/2 /dev/stderr +# Needed by bash +[ -a /dev/fd ] || ln -s /proc/self/fd /dev/fd + # Recovery shells will erase anything from here mkdir -p /tmp/secret @@ -46,10 +55,10 @@ hwclock -l -s TRACE "Under init" # set CONFIG_TPM dynamically before init -if [ -e /dev/tpm0 ]; then - CONFIG_TPM='y' -else +if [ ! -e /dev/tpm0 ]; then CONFIG_TPM='n' + CONFIG_TPM2_TOOLS='n' + warn 'No TPM found...' fi #Specify whiptail background colors cues under FBWhiptail only @@ -61,6 +70,11 @@ else export BG_COLOR_ERROR="${CONFIG_ERROR_BG_COLOR:-""}" fi +if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then + # Initialize tpm2 encrypted sessions here + tpmr startsession +fi + if [ "$CONFIG_COREBOOT" = "y" ]; then /bin/cbfs-init fi @@ -99,8 +113,8 @@ if [ "$boot_option" = "r" ]; then # Start an interactive shell recovery 'User requested recovery shell' # just in case... - if [ "$CONFIG_TPM" = "y" ]; then - tpm extend -ix 4 -ic recovery + if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = "y" ]; then + tpmr extend -ix 4 -ic recovery fi exec /bin/ash exit @@ -156,7 +170,7 @@ else fi # belts and suspenders, just in case... -if [ "$CONFIG_TPM" = "y" ]; then - tpm extend -ix 4 -ic recovery +if [ "$CONFIG_TPM" = "y" -o "$CONFIG_TPM2_TOOLS" = y ]; then + tpmr extend -ix 4 -ic recovery fi exec /bin/ash diff --git a/initrd/sbin/insmod b/initrd/sbin/insmod index 01a988f9..60f37d0e 100755 --- a/initrd/sbin/insmod +++ b/initrd/sbin/insmod @@ -25,18 +25,20 @@ if [ ! -r "$MODULE" ]; then fi if [ ! -r /sys/class/tpm/tpm0/pcrs -o ! -x /bin/tpm ]; then - tpm_missing=1 + if [ ! -c /dev/tpmrm0 -o ! -x /bin/tpm2 ]; then + tpm_missing=1 + fi fi if [ -z "$tpm_missing" ]; then - tpm extend -ix "$MODULE_PCR" -if "$MODULE" \ + tpmr extend -ix "$MODULE_PCR" -if "$MODULE" \ || die "$MODULE: tpm extend failed" fi if [ ! -z "$*" -a -z "$tpm_missing" ]; then TMPFILE=/tmp/insmod.$$ echo "$@" > $TMPFILE - tpm extend -ix "$MODULE_PCR" -if $TMPFILE \ + tpmr extend -ix "$MODULE_PCR" -if $TMPFILE \ || die "$MODULE: tpm extend on arguments failed" fi diff --git a/modules/bash b/modules/bash new file mode 100644 index 00000000..a43bd1f1 --- /dev/null +++ b/modules/bash @@ -0,0 +1,40 @@ +# GNU bash +modules-$(CONFIG_BASH) += bash + +bash_version := 5.1.16 +bash_dir := bash-$(bash_version) +bash_tar := bash-$(bash_version).tar.gz +bash_url := https://ftpmirror.gnu.org/bash/$(bash_tar) +bash_hash := 5bac17218d3911834520dad13cd1f85ab944e1c09ae1aba55906be1f8192f558 + +bash_configure := ./configure \ + $(CROSS_TOOLS) \ + --host $(target) \ + --prefix="/usr" \ + --enable-largefile \ + --infodir=/usr/share/info \ + --mandir=/usr/share/man \ + --without-bash-malloc \ + --disable-coprocesses \ + --disable-debugger \ + --disable-net-redirections \ + --enable-single-help-strings \ + --disable-nls \ + +bash_target := $(MAKE_JOBS) \ + && $(MAKE) -C $(build)/$(bash_dir) \ + DESTDIR="$(INSTALL)" \ + install \ + +ifeq "$(CONFIG_BASH)" "y" +initrd_bins += $(initrd_tmp_dir)/bin/bash +endif + +$(build)/$(bash_dir)/bash: $(build)/$(bash_dir)/.build + +# Replace /bin/bash linked to busybox +$(initrd_tmp_dir)/bin/bash: $(build)/$(bash_dir)/bash $(initrd_tmp_dir)/bin/busybox + install -Dm 755 "$<" "$@" + $(CROSS)strip --preserve-dates "$@" 2>&- + +bash_depends := $(musl_dep) busybox diff --git a/modules/curl b/modules/curl new file mode 100644 index 00000000..df7e5b7b --- /dev/null +++ b/modules/curl @@ -0,0 +1,71 @@ +# cURL and libcurl +modules-$(CONFIG_CURL) += curl + +curl_depends := openssl zlib $(musl_dep) + +curl_version := 7.83.1 +curl_dir := curl-$(curl_version) +curl_tar := curl-$(curl_version).tar.xz +curl_url := https://curl.se/download/$(curl_tar) +curl_hash := 2cb9c2356e7263a1272fd1435ef7cdebf2cd21400ec287b068396deb705c22c4 + +curl_configure := ./configure \ + $(CROSS_TOOLS) \ + --host $(target) \ + --prefix "/" \ + --with-openssl \ + --enable-optimize \ + --disable-ares \ + --disable-rt \ + --disable-ech \ + --disable-dependency-tracking \ + --enable-shared \ + --disable-static \ + --enable-http \ + --disable-ftp \ + --enable-file \ + --disable-ldap \ + --disable-ldaps \ + --disable-rtsp \ + --enable-proxy \ + --disable-dict \ + --enable-telnet \ + --enable-tftp \ + --disable-pop3 \ + --disable-imap \ + --disable-smb \ + --disable-smtp \ + --disable-gopher \ + --disable-mqtt \ + --enable-manual \ + --disable-libcurl-option \ + --enable-openssl-auto-load-config \ + --enable-versioned-symbols \ + --disable-threaded-resolver \ + --disable-sspi \ + --enable-crypto-auth \ + --disable-ntlm \ + --enable-tls-srp \ + --enable-unix-sockets \ + --enable-cookies \ + --enable-socketpair \ + --enable-http-auth \ + --enable-doh \ + --enable-mime \ + --enable-dateparse \ + --enable-netrc \ + --enable-progress-meter \ + --disable-dnsshuffle \ + --enable-get-easy-options \ + --enable-alt-svc \ + --enable-headers-api \ + --enable-hsts \ + +curl_target := $(MAKE_JOBS) \ + && $(MAKE) -C $(build)/$(curl_dir) \ + DESTDIR="$(INSTALL)" \ + install + +curl_libraries := lib/.libs/libcurl.so.4 + +curl_output := src/.libs/curl diff --git a/modules/linux b/modules/linux index 77fa0e35..19a9c6c6 100644 --- a/modules/linux +++ b/modules/linux @@ -131,6 +131,10 @@ linux_modules-$(CONFIG_LINUX_MEI) += drivers/misc/mei/mei-me.ko EXTRA_FLAGS := -fdebug-prefix-map=$(pwd)=heads -gno-record-gcc-switches +ifeq "$(CONFIG_LINUX_VERSION)" "4.14.62" +EXTRA_FLAGS += -Wno-cast-function-type +endif + linux_target := \ O="$(build)/$(linux_dir)" \ ARCH="$(LINUX_ARCH)" \ diff --git a/modules/openssl b/modules/openssl new file mode 100644 index 00000000..cded4525 --- /dev/null +++ b/modules/openssl @@ -0,0 +1,36 @@ +# OpenSSL library +modules-$(CONFIG_OPENSSL) += openssl + +openssl_version := 1_1_1h +openssl_dir := openssl-$(openssl_version) +openssl_tar := openssl-$(openssl_version).tar.gz +openssl_url := https://github.com/openssl/openssl/archive/OpenSSL_$(openssl_version).tar.gz +openssl_hash := d1f723c1f6b6d1eaf26655caa50d2f60d4d33f4b04977b1da63def878f386fcc + +# hack to provide path to libgcc +LIBGCC_DIR := $(dir $(shell $(heads_cc) -print-libgcc-file-name)) + +openssl_configure := \ + $(CROSS_TOOLS) \ + LDFLAGS="-L$(LIBGCC_DIR)" \ + ./Configure \ + --prefix="/" \ + linux-$(strip $(arch)) \ + +openssl_target := $(MAKE_JOBS) \ + build_programs \ + && \ + $(MAKE) \ + -C "$(build)/$(openssl_dir)" \ + DESTDIR="$(INSTALL)" \ + LIBDIR="lib" \ + install_sw \ + +openssl_libraries := \ + libcrypto.so.1.1 \ + libssl.so.1.1 \ + +openssl_output := \ + apps/openssl \ + +openssl_depends := $(musl_dep) diff --git a/modules/tpm2-tools b/modules/tpm2-tools new file mode 100644 index 00000000..0f8569b5 --- /dev/null +++ b/modules/tpm2-tools @@ -0,0 +1,29 @@ +# TPM2 tools program +modules-$(CONFIG_TPM2_TOOLS) += tpm2-tools + +tpm2-tools_version := 5.2 +#tpm2-tools_version := 78a7681 +#tpm2-tools_repo := https://github.com/tpm2-software/tpm2-tools.git + +tpm2-tools_dir := tpm2-tools-$(tpm2-tools_version) +tpm2-tools_tar := tpm2-tools-$(tpm2-tools_version).tar.gz +tpm2-tools_url := https://github.com/tpm2-software/tpm2-tools/releases/download/$(tpm2-tools_version)/$(tpm2-tools_tar) +tpm2-tools_hash := c0b402f6a7b3456e8eb2445211e2d41c46c7e769e05fe4d8909ff64119f7a630 + +# we have ESYS 3.0, but it doesn't figure that out on its own +tpm2-tools_configure := ./bootstrap && ./configure \ + $(CROSS_TOOLS) \ + --host $(MUSL_ARCH)-elf-linux \ + --prefix "/" \ + --disable-fapi \ + TSS2_ESYS_3_0_CFLAGS="-I$(INSTALL)/include" \ + TSS2_ESYS_3_0_LIBS="-ltss2-esys" \ + +tpm2-tools_target := $(MAKE_JOBS) \ + DESTDIR="$(INSTALL)" \ + $(CROSS_TOOLS) \ + install \ + +tpm2-tools_output := tools/tpm2 + +tpm2-tools_depends := tpm2-tss curl $(musl_dep) diff --git a/modules/tpm2-tss b/modules/tpm2-tss new file mode 100644 index 00000000..53610d1d --- /dev/null +++ b/modules/tpm2-tss @@ -0,0 +1,40 @@ +# TPM2 TSS library +modules-$(CONFIG_TPM2_TSS) += tpm2-tss + +tpm2-tss_version := 3.2.0 +tpm2-tss_dir := tpm2-tss-$(tpm2-tss_version) +tpm2-tss_tar := tpm2-tss-$(tpm2-tss_version).tar.gz +tpm2-tss_url := https://github.com/tpm2-software/tpm2-tss/releases/download/$(tpm2-tss_version)/$(tpm2-tss_tar) +tpm2-tss_hash := 48305e4144dcf6d10f3b25b7bccf0189fd2d1186feafd8cd68c6b17ecf0d7912 + +tpm2-tss_configure := aclocal && automake --add-missing && autoreconf -fi \ + && ./configure \ + $(CROSS_TOOLS) \ + --host $(MUSL_ARCH)-elf-linux \ + --prefix "/" \ + --disable-doxygen-doc \ + --disable-doxygen-man \ + --disable-doxygen-rtf \ + --disable-doxygen-html \ + --disable-fapi \ + +# Run one build to generate the executables with the pre-defined +# exec_prefix and datarootdir, then a second make to install the binaries +# into our actual target location + +tpm2-tss_target := $(MAKE_JOBS) \ + DESTDIR="$(INSTALL)" \ + $(CROSS_TOOLS) \ + install \ + +# tpm2 binary wants to dlopen some libraries, so be sure that +# they are available. It would be nice to statically link these. +tpm2-tss_libraries := \ + src/tss2-rc/.libs/libtss2-rc.so.0 \ + src/tss2-mu/.libs/libtss2-mu.so.0 \ + src/tss2-sys/.libs/libtss2-sys.so.1 \ + src/tss2-esys/.libs/libtss2-esys.so.0 \ + src/tss2-tcti/.libs/libtss2-tctildr.so.0 \ + src/tss2-tcti/.libs/libtss2-tcti-device.so.0 \ + +tpm2-tss_depends := openssl $(musl_dep) diff --git a/patches/tpm2-tools-5.2.patch b/patches/tpm2-tools-5.2.patch new file mode 100644 index 00000000..ed5233d9 --- /dev/null +++ b/patches/tpm2-tools-5.2.patch @@ -0,0 +1,21 @@ +diff --git a/Makefile.am b/Makefile.am +index c58f0f34..a2bade09 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -93,7 +93,7 @@ tss2_tools = \ + + # Bundle all the tools into a single program similar to busybox + bin_PROGRAMS += tools/tpm2 +-tools_tpm2_LDADD = $(LDADD) $(CURL_LIBS) ++tools_tpm2_LDADD = $(LDADD) + tools_tpm2_CFLAGS = $(AM_CFLAGS) -DTPM2_TOOLS_MAX="$(words $(tpm2_tools))" + tools_tpm2_SOURCES = \ + tools/tpm2_tool.c \ +@@ -127,7 +127,6 @@ tpm2_tools = \ + tools/tpm2_encryptdecrypt.c \ + tools/tpm2_evictcontrol.c \ + tools/tpm2_flushcontext.c \ +- tools/tpm2_getekcertificate.c \ + tools/tpm2_getrandom.c \ + tools/tpm2_gettime.c \ + tools/tpm2_hash.c \ diff --git a/patches/tpm2-tss-3.2.0.patch b/patches/tpm2-tss-3.2.0.patch new file mode 100644 index 00000000..c1de8d33 --- /dev/null +++ b/patches/tpm2-tss-3.2.0.patch @@ -0,0 +1,20 @@ +--- a/configure.ac 2022-05-21 14:40:59.686470575 +0800 ++++ b/configure.ac 2022-05-21 14:41:21.406671435 +0800 +@@ -488,17 +488,6 @@ AM_CONDITIONAL(SYSD_SYSUSERS, test "x$sy + AC_CHECK_PROG(systemd_tmpfiles, systemd-tmpfiles, yes) + AM_CONDITIONAL(SYSD_TMPFILES, test "x$systemd_tmpfiles" = "xyes") + +-# Check all tools used by make install +-AS_IF([test "$HOSTOS" = "Linux"], +- [ AC_CHECK_PROG(useradd, useradd, yes) +- AC_CHECK_PROG(groupadd, groupadd, yes) +- AC_CHECK_PROG(adduser, adduser, yes) +- AC_CHECK_PROG(addgroup, addgroup, yes) +- AS_IF([test "x$addgroup" != "xyes" && test "x$groupadd" != "xyes" ], +- [AC_MSG_ERROR([addgroup or groupadd are needed.])]) +- AS_IF([test "x$adduser" != "xyes" && test "x$useradd" != "xyes" ], +- [AC_MSG_ERROR([adduser or useradd are needed.])])]) +- + AC_SUBST([PATH]) + + dnl --------- Doxy Gen -----------------------