Merge pull request #1292 from tlaurion/tpm2_retry

TPM2/TPM1 support (testing and bug fixes needed through qemu-(fb)whiptail-tpm[1,2](-hotp) testing boards!
This commit is contained in:
tlaurion 2023-03-13 16:22:13 -04:00 committed by GitHub
commit d24def4b59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
76 changed files with 2097 additions and 502 deletions

View File

@ -470,6 +470,13 @@ workflows:
requires:
- x230-hotp-maximized
- build:
name: qemu-coreboot-fbwhiptail-tpm2-hotp
target: qemu-coreboot-fbwhiptail-tpm2-hotp
subcommand: ""
requires:
- x230-hotp-maximized
- build:
name: librem_13v2
target: librem_13v2

View File

@ -52,6 +52,9 @@ include $(CONFIG)
# Unless otherwise specified, we are building for heads
CONFIG_HEADS ?= y
# Unless otherwise specified, we are building bash to have non-interactive shell for scripts (arrays and bashisms)
CONFIG_BASH ?= y
# Determine arch part for a host triplet
ifeq "$(CONFIG_TARGET_ARCH)" "x86"
MUSL_ARCH := x86_64
@ -118,6 +121,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 +148,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 +165,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 +469,9 @@ 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_BASH) += bash
$(foreach m, $(bin_modules-y), \
$(call map,initrd_bin_add,$(call bins,$m)) \

View File

@ -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.

View File

@ -0,0 +1,163 @@
# 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
#Enable DEBUG output
export CONFIG_DEBUG_OUTPUT=y
export CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT=y
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
export CONFIG_TPM2_CAPTURE_PCAP=y
CONFIG_TPM2_TSS=y
CONFIG_OPENSSL=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 --create-config-files skip-if-exist
swtpm_setup --tpm-state "$(TPMDIR)" --create-platform-cert --lock-nvram --tpm2
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=<path_to_img.iso> 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
# - <other> - 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

View File

@ -0,0 +1 @@
../qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md

View File

@ -0,0 +1,162 @@
# 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
#Enable DEBUG output
export CONFIG_DEBUG_OUTPUT=y
export CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT=y
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
export CONFIG_TPM2_CAPTURE_PCAP=y
CONFIG_TPM2_TSS=y
CONFIG_OPENSSL=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 --create-config-files skip-if-exist
swtpm_setup --tpm-state "$(TPMDIR)" --create-platform-cert --lock-nvram --tpm2
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=<path_to_img.iso> 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
# - <other> - 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

View File

@ -0,0 +1 @@
../qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md

View File

@ -1 +1 @@
../qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md
boards/qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md

View File

@ -0,0 +1,163 @@
# 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
#Enable DEBUG output
export CONFIG_DEBUG_OUTPUT=y
export CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT=y
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
export CONFIG_TPM2_CAPTURE_PCAP=y
CONFIG_TPM2_TSS=y
CONFIG_OPENSSL=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 --create-config-files skip-if-exist
swtpm_setup --tpm-state "$(TPMDIR)" --create-platform-cert --lock-nvram --tpm2
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=<path_to_img.iso> 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
# - <other> - 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

View File

@ -0,0 +1 @@
../qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md

View File

@ -0,0 +1,162 @@
# 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
#Enable DEBUG output
export CONFIG_DEBUG_OUTPUT=y
export CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT=y
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
export CONFIG_TPM2_CAPTURE_PCAP=y
CONFIG_TPM2_TSS=y
CONFIG_OPENSSL=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 --create-config-files skip-if-exist
swtpm_setup --tpm-state "$(TPMDIR)" --create-platform-cert --lock-nvram --tpm2
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=<path_to_img.iso> 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
# - <other> - 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

View File

@ -0,0 +1 @@
../qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md

View File

@ -4,6 +4,7 @@ export CONFIG_COREBOOT=y
export CONFIG_COREBOOT_VERSION=4.13
export CONFIG_LINUX_VERSION=4.14.62
CONFIG_BASH=n
CONFIG_FLASHROM=y
#CONFIG_GPG=y
#CONFIG_FLASHTOOLS=y
@ -17,7 +18,7 @@ CONFIG_LINUX_CONFIG=config/linux-x230-flash.config
CONFIG_LINUX_USB=y
#CONFIG_LINUX_E1000E=y
export CONFIG_BOOTSCRIPT=/bin/t430-flash.init
export CONFIG_BOOTSCRIPT=/bin/xx30-flash.init
export CONFIG_BOARD_NAME="ThinkPad T430-legacy-flash"
export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal --ifd --image bios"

View File

@ -4,6 +4,7 @@ export CONFIG_COREBOOT=y
export CONFIG_COREBOOT_VERSION=4.13
export CONFIG_LINUX_VERSION=4.14.62
CONFIG_BASH=n
CONFIG_FLASHROM=y
#CONFIG_GPG=y
#CONFIG_FLASHTOOLS=y
@ -17,7 +18,7 @@ CONFIG_LINUX_CONFIG=config/linux-x230-flash.config
CONFIG_LINUX_USB=y
#CONFIG_LINUX_E1000E=y
export CONFIG_BOOTSCRIPT=/bin/x230-flash.init
export CONFIG_BOOTSCRIPT=/bin/xx30-flash.init
export CONFIG_BOARD_NAME="ThinkPad X230-legacy-flash"
export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal --ifd --image bios"

View File

@ -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
@ -1096,7 +1096,7 @@ CONFIG_SV_DEFAULT_SERVICE_DIR=""
CONFIG_SH_IS_ASH=y
# CONFIG_SH_IS_HUSH is not set
# CONFIG_SH_IS_NONE is not set
CONFIG_BASH_IS_ASH=y
# CONFIG_BASH_IS_ASH is not set
# CONFIG_BASH_IS_HUSH is not set
# CONFIG_BASH_IS_NONE is not set
CONFIG_SHELL_ASH=y

View File

@ -1,3 +1,4 @@
CONFIG_CCACHE=y
# CONFIG_INCLUDE_CONFIG_FILE is not set
CONFIG_ONBOARD_VGA_IS_PRIMARY=y
CONFIG_CBFS_SIZE=0x980000

View File

@ -0,0 +1,20 @@
CONFIG_CCACHE=y
# 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"

View File

@ -1,4 +1,4 @@
#!/bin/ash
#!/bin/bash
set -e -o pipefail
. /etc/functions
@ -24,7 +24,7 @@ for cbfsname in `echo $cbfsfiles`; do
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

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -e -o pipefail
. /etc/functions
. /tmp/config

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
#
set -e -o pipefail
. /etc/functions

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
#
set -e -o pipefail
. /etc/functions

View File

@ -1,9 +1,11 @@
#!/bin/sh
#!/bin/ash
#
# based off of flashrom-x230
#
# NOTE: This script is used on legacy-flash boards and runs with busybox ash,
# not bash
set -e -o pipefail
. /etc/functions
. /etc/ash_functions
. /tmp/config
TRACE "Under /bin/flash.sh"

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
. /etc/functions
TRACE "Under /bin/flashrom-kgpe-d16-openbmc.sh"

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Boot from a local disk installation
. /etc/functions

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
#
set -e -o pipefail
. /etc/functions

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# if we are using the full GPG we need a wrapper for the gpgv executable
. /etc/functions

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Boot from a local disk installation
BOARD_NAME=${CONFIG_BOARD_NAME:-${CONFIG_BOARD}}
@ -148,11 +148,12 @@ prompt_update_checksums()
fi
}
generate_totp_htop()
generate_totp_hotp()
{
TRACE "Under /bin/gui-init:generate_totp_htop"
tpm_password="$1" # May be empty, will prompt if needed and empty
TRACE "Under /bin/gui-init:generate_totp_hotp"
echo "Scan the QR code to add the new TOTP secret"
if /bin/seal-totp "$BOARD_NAME"; then
if /bin/seal-totp "$BOARD_NAME" "$tpm_password"; then
if [ -x /bin/hotp_verification ]; then
echo "Once you have scanned the QR code, hit Enter to configure your HOTP USB Security Dongle (e.g. Librem Key or Nitrokey)"
read
@ -164,7 +165,7 @@ generate_totp_htop()
# clear screen
printf "\033c"
else
warn "Sealing of measurements inside of TPM failed. You might want to take ownership of TPM by resetting it."
warn "Unsealing TOTP/HOTP secret from previous sealed measurements failed. Try "Generate new HOTP/TOTP secret" option if you updated firmware content."
fi
}
@ -173,7 +174,7 @@ update_totp()
TRACE "Under /bin/gui-init:update_totp"
# update the TOTP code
date=`date "+%Y-%m-%d %H:%M:%S %Z"`
if [ "$CONFIG_TPM" = n ]; then
if [ "$CONFIG_TPM" != "y" ]; then
TOTP="NO TPM"
else
TOTP=`unseal-totp`
@ -182,6 +183,12 @@ update_totp()
if [ "$skip_to_menu" = "true" ]; then
return 1 # Already asked to skip to menu from a prior error
fi
DEBUG "CONFIG_TPM: $CONFIG_TPM"
DEBUG "CONFIG_TPM2_TOOLS: $CONFIG_TPM2_TOOLS"
DEBUG "Show PCRs"
DEBUG "$(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
@ -201,7 +208,7 @@ update_totp()
g )
if (whiptail $BG_COLOR_WARNING --title 'Generate new TOTP/HOTP secret' \
--yesno "This will erase your old secret and replace it with a new one!\n\nDo you want to proceed?" 0 80) then
generate_totp_htop && update_totp && BG_COLOR_MAIN_MENU=""
generate_totp_hotp && update_totp && BG_COLOR_MAIN_MENU=""
fi
;;
i )
@ -360,8 +367,7 @@ show_main_menu()
attempt_default_boot
;;
r )
update_totp
update_hotp
update_totp && update_hotp
;;
o )
show_options_menu
@ -474,7 +480,7 @@ show_tpm_totp_hotp_options_menu()
option=$(cat /tmp/whiptail)
case "$option" in
g )
generate_totp_htop
generate_totp_hotp
;;
r )
reset_tpm
@ -510,15 +516,24 @@ reset_tpm()
if [ "$CONFIG_TPM" = "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
if ! prompt_new_owner_password; then
echo "Press Enter to return to the menu..."
read
echo
return 1
fi
tpmr reset "$key_password"
# now that the TPM is reset, remove invalid TPM counter files
mount_boot
mount -o rw,remount /boot
rm -f /boot/kexec_rollback.txt
rm -f /boot/kexec_primhdl_hash.txt
# create Heads TPM counter before any others
check_tpm_counter /boot/kexec_rollback.txt \
check_tpm_counter /boot/kexec_rollback.txt "" "$key_password" \
|| die "Unable to find/create tpm counter"
counter="$TPM_COUNTER"
@ -529,7 +544,7 @@ reset_tpm()
|| die "Unable to create rollback file"
mount -o ro,remount /boot
generate_totp_htop
generate_totp_hotp "$key_password"
else
echo "Returning to the main menu"
fi

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Launches kexec from saved configuration entries
set -e -o pipefail
. /tmp/config
@ -134,5 +134,9 @@ echo "$kexeccmd"
eval "$kexeccmd" \
|| die "Failed to load the new kernel"
if [ "$CONFIG_TPM" = "y" ]; then
tpmr kexec_finalize
fi
echo "Starting the new kernel"
exec kexec -e

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Unseal a disk key from TPM and add to a new initramfs
set -e -o pipefail
. /etc/functions
@ -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
@ -78,8 +78,8 @@ dd if="$INITRD" of="$SECRET_CPIO" bs=512 conv=sync \
if [ "$unseal_failed" = "n" ]; then
# kexec-save-default might have created crypttab overrides to be injected in initramfs through additional cpio
if [ -r "$bootdir/kexec_initrd_crypttab_overrides.txt" ]; then
echo "$bootdir/kexec_initrd_crypttab_overrides.txt found..."
echo "Preparing initramfs crypttab overrides as defined under $bootdir/kexec_initrd_crypttab_overrides.txt to be injected through cpio at next kexec call..."
echo "+++ $bootdir/kexec_initrd_crypttab_overrides.txt found..."
echo "+++ Preparing initramfs crypttab overrides as defined under $bootdir/kexec_initrd_crypttab_overrides.txt to be injected through cpio at next kexec call..."
# kexec-save-default has found crypttab files under initrd and saved them
cat "$bootdir/kexec_initrd_crypttab_overrides.txt" | while read line; do
crypttab_file=$(echo "$line" | awk -F ':' {'print $1'})
@ -87,14 +87,14 @@ if [ "$unseal_failed" = "n" ]; then
# Replace each initrd crypttab file with modified entry containing /secret.key path
mkdir -p "$INITRD_DIR/$(dirname $crypttab_file)"
echo "$crypttab_entry" | tee -a "$INITRD_DIR/$crypttab_file" > /dev/null
echo "initramfs's $crypttab_file will be overriden with $crypttab_entry"
echo "+++ initramfs's $crypttab_file will be overriden with: $crypttab_entry"
done
else
# No crypttab files were found under selected default boot option's initrd file
crypttab_file="etc/crypttab"
mkdir -p "$INITRD_DIR/$(dirname $crypttab_file)"
# overwrite crypttab to mirror behavior of seal-key
echo "The following /etc/crypttab lines will be passed through cpio into kexec call for default boot option:"
echo "+++ The following /etc/crypttab lines will be passed through cpio into kexec call for default boot option:"
for uuid in `cat "$TMP_KEY_DEVICES" | cut -d\ -f2`; do
# NOTE: discard operation (TRIM) is activated by default if no crypptab found in initrd
echo "luks-$uuid UUID=$uuid /secret.key luks,discard" | tee -a "$INITRD_DIR/$crypttab_file"

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Boot from signed ISO
set -e -o pipefail
. /etc/functions

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -e -o pipefail
. /etc/functions
TRACE "Under /bin/kexec-parse-bls"

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -e -o pipefail
. /etc/functions

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Save these options to be the persistent default
set -e -o pipefail
. /tmp/config
@ -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" ] && [ "$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,12 @@ if [ ! -d $paramsdir ]; then
mkdir -p $paramsdir \
|| die "Failed to create params directory"
fi
if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then
sha256sum /tmp/primary.handle > "$PRIMHASH_FILE" \
|| die "ERROR: Failed to Hash TPM2 primary key handle!"
fi
rm $paramsdir/kexec_default.*.txt 2>/dev/null || true
echo "$entry" > $ENTRY_FILE
( cd $bootdir && kexec-boot -b "$bootdir" -e "$entry" -f| \
@ -139,14 +146,14 @@ if [ "$save_key" = "y" ]; then
current_default_initrd=$(cat /boot/kexec_default_hashes.txt | grep initr | awk -F " " {'print $NF'} | sed 's/\.\//\/boot\//g')
# Get crypttab files paths from initrd
echo "Checking current selected default boot's $current_default_initrd for existing crypttab files..."
echo "+++ Checking current selected default boot's $current_default_initrd for existing crypttab files..."
# First either decompress or use the original if it's not compressed
initrd_decompressed="/tmp/initrd_extract/initrd_decompressed.cpio"
zcat < "$current_default_initrd" > "$initrd_decompressed" 2> /dev/null || initrd_decompressed="$current_default_initrd"
crypttab_files=$(cpio --list --quiet < "$initrd_decompressed" | grep crypttab 2> /dev/null) || true
if [ ! -z "$crypttab_files" ]; then
echo "Extracting current selected default boot's $current_default_initrd for found crypttab files analysis..."
echo "+++ Extracting current selected default boot's $current_default_initrd for found crypttab files analysis..."
cpio -id --quiet < $initrd_decompressed $crypttab_files 2> /dev/null
rm -f $bootdir/kexec_initrd_crypttab_overrides.txt || true
@ -165,12 +172,12 @@ if [ "$save_key" = "y" ]; then
cd - > /dev/null
#insert current default boot's initrd crypttab locations into tracking file to be overwritten into initramfs at kexec-inject-key
echo "The following OS crypttab file:entry were modified from default boot's initrd:"
echo "+++ The following OS crypttab file:entry were modified from default boot's initrd:"
cat $bootdir/kexec_initrd_crypttab_overrides.txt
echo "Heads added /secret.key in those entries and saved them under $bootdir/kexec_initrd_crypttab_overrides.txt"
echo "Those overrides will be part of detached signed digests and used to prepare cpio injected at kexec of selected default boot entry."
echo "+++ Heads added /secret.key in those entries and saved them under $bootdir/kexec_initrd_crypttab_overrides.txt"
echo "+++ Those overrides will be part of detached signed digests and used to prepare cpio injected at kexec of selected default boot entry."
else
echo "No crypttab file found in extracted initrd. Removing $bootdir/kexec_initrd_crypttab_overrides.txt"
echo "+++ No crypttab file found in extracted initrd. Removing $bootdir/kexec_initrd_crypttab_overrides.txt"
rm -f "$bootdir/kexec_initrd_crypttab_overrides.txt" || true
fi
# Cleanup
@ -179,8 +186,10 @@ fi
# sign and auto-roll config counter
extparam=
if [ "$CONFIG_TPM" = "y" ]; then
extparam=-r
if [ "$CONFIG_TPM" = "y" ];then
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
extparam=-r
fi
fi
kexec-sign-config -p $paramsdir $extparam \
|| die "Failed to sign default config"

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Generate a TPM key used to unlock LUKS disks
set -e -o pipefail
. /etc/functions
@ -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

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# This will generate a disk encryption key and seal / ecncrypt
# with the current PCRs and then store it in the TPM NVRAM.
# It will then need to be bundled into initrd that is booted.
@ -14,6 +14,8 @@ RECOVERY_KEY="/tmp/secret/recovery.key"
. /etc/functions
. /tmp/config
TRACE "Under kexec-seal-key"
paramsdir=$1
if [ -z "$paramsdir" ]; then
die "Usage $0 /boot"
@ -36,8 +38,10 @@ 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,
DEBUG "$(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"
@ -83,73 +87,37 @@ 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"
pcrf="/tmp/secret/pcrf.bin"
tpmr pcrread 0 "$pcrf"
tpmr pcrread -a 1 "$pcrf"
tpmr pcrread -a 2 "$pcrf"
tpmr pcrread -a 3 "$pcrf"
# Note that PCR 4 needs to be set with the "normal-boot" path value, which is 0.
dd if=/dev/zero bs="$(tpmr pcrsize)" count=1 status=none >> "$pcrf"
if [ "$CONFIG_USB_KEYBOARD" = "y" -o -r /lib/modules/libata.ko -o -x /bin/hotp_verification ]; then
DEBUG "Sealing TPM disk unlock key with PCR5 involvement (additional kernel modules are loaded per board config)..."
# Here, we take pcr 5 into consideration if modules are expected to be measured+loaded
tpmr pcrread -a 5 "$pcrf"
else
pcr_5="0000000000000000000000000000000000000000"
DEBUG "Sealing TPM disk unlock key with PCR5=0 (NO additional kernel modules are loaded per board config)..."
#no kernel modules are expected to be measured+loaded
dd if=/dev/zero bs="$(tpmr pcrsize)" count=1 status=none >> "$pcrf"
fi
# Precompute the value for pcr 6
DEBUG "Precomputing TPM future value for PCR6 sealing/unsealing of TPM disk unlock key..."
tpmr calcfuturepcr -a "/tmp/luksDump.txt" "$pcrf"
# We take into consideration user files in cbfs
tpmr pcrread -a 7 "$pcrf"
# 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"
DO_WITH_DEBUG --mask-position 7 \
tpmr seal "$KEY_FILE" "$TPM_INDEX" 0,1,2,3,4,5,6,7 "$pcrf" \
"$TPM_SIZE" "$key_password"
# should be okay if this fails
shred -n 10 -z -u "$pcrf".* 2> /dev/null || true
shred -n 10 -z -u "$KEY_FILE" 2> /dev/null \
|| die "Failed to delete key file"
|| warn "Failed to delete key file - continuing"
# 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.
#
# 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
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"

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Generic configurable boot script via kexec
set -e -o pipefail
. /tmp/config
@ -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 "
@ -281,8 +297,15 @@ user_select() {
else
echo "+++ Rebooting to start the new default option"
sleep 2
reboot \
|| die "!!! Failed to reboot system"
if [ "$CONFIG_DEBUG_OUTPUT" != "y" ]; then
reboot \
|| die "!!! Failed to reboot system"
else
DEBUG "Rebooting is required prior of booting default boot entry"
# Instead of rebooting, drop to a recovery shell
# for a chance to inspect debug output
recovery "Entering recovery to permit inspection of /tmp/debug.log output, reboot to continue"
fi
fi
fi
@ -299,23 +322,22 @@ do_boot()
die "!!! Missing required boot hashes"
fi
if [ "$CONFIG_TPM" = "y" \
-a -r "$TMP_KEY_DEVICES" ]; then
if [ "$CONFIG_TPM" = "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 +366,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" ]; 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
@ -368,7 +391,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"

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Sign a valid directory of kexec params
set -e -o pipefail
. /tmp/config

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# This will unseal and unecncrypt the drive encryption key from the TPM
# The TOTP secret will be shown to the user on each encryption attempt.
# It will then need to be bundled into initrd that is booted with Qubes.
@ -9,37 +9,34 @@ TPM_INDEX=3
TPM_SIZE=312
. /etc/functions
TRACE "Under kexec-unseal-key"
mkdir -p /tmp/secret
sealed_file="/tmp/secret/sealed.key"
key_file="$1"
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"
DEBUG "CONFIG_TPM: $CONFIG_TPM"
DEBUG "CONFIG_TPM2_TOOLS: $CONFIG_TPM2_TOOLS"
DEBUG "Show PCRs"
DEBUG "$(pcrs)"
for tries in 1 2 3; do
read -s -p "Enter unlock password (blank to abort): " tpm_password
echo
if [ -z "$tpm_password" ]; then
die "Aborting unseal disk encryption key"
fi
if tpm unsealfile \
-if "$sealed_file" \
-of "$key_file" \
-pwdd "$tpm_password" \
-hk 40000000 \
; then
# should be okay if this fails
shred -n 10 -z -u /tmp/secret/sealed 2> /dev/null || true
DO_WITH_DEBUG --mask-position 6 \
tpmr unseal "$TPM_INDEX" "0,1,2,3,4,5,6,7" "$TPM_SIZE" \
"$key_file" "$tpm_password"
if [ "$?" -eq 0 ]; then
exit 0
fi

View File

@ -1,4 +1,4 @@
#!/bin/ash
#!/bin/bash
set -e -o pipefail
. /etc/functions

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Scan for USB installation options
set -e -o pipefail
. /etc/functions

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Mount a USB device
. /etc/functions

View File

@ -1,4 +1,4 @@
#!/bin/ash
#!/bin/bash
. /etc/functions

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Automated setup of TPM, GPG keys, and disk
TRACE "Under /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" ];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
@ -307,7 +309,7 @@ report_integrity_measurements()
date=`date "+%Y-%m-%d %H:%M:%S %Z"`
seconds=`date "+%s"`
half=`expr \( $seconds % 60 \) / 30`
if [ "$CONFIG_TPM" = n ]; then
if [ "$CONFIG_TPM" != "y" ]; then
TOTP="NO TPM"
elif [ "$half" != "$last_half" ]; then
last_half=$half;
@ -608,14 +610,11 @@ fi
## reset TPM and set password
if [ "$CONFIG_TPM" = "y" ]; then
echo -e "\nResetting TPM...\n"
{
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
tpmr reset "$TPM_PASS" >/dev/null 2>/tmp/error
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

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# System Info
BOARD_NAME=${CONFIG_BOARD_NAME:-${CONFIG_BOARD}}

View File

@ -1,8 +1,13 @@
#!/bin/sh
. /etc/functions
#!/bin/ash
. /etc/ash_functions
TRACE "Under /bin/poweroff"
# Shut down TPM
if [ "$CONFIG_TPM" = "y" ]; then
tpmr shutdown
fi
# Sync all mounted filesystems
echo s > /proc/sysrq-trigger

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Measure all of the luks disk encryption headers into
# a PCR so that we can detect disk swap attacks.
. /etc/functions
@ -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"

View File

@ -1,8 +1,13 @@
#!/bin/sh
. /etc/functions
#!/bin/ash
. /etc/ash_functions
TRACE "Under /bin/reboot"
# Shut down TPM
if [ "$CONFIG_TPM" = "y" ]; then
tpmr shutdown
fi
# Sync all mounted filesystems
echo s > /proc/sysrq-trigger

View File

@ -1,9 +1,8 @@
#!/bin/sh
#!/bin/bash
# Retrieve the sealed TOTP secret and initialize a USB Security dongle with it
. /etc/functions
HOTP_SEALED="/tmp/secret/hotp.sealed"
HOTP_SECRET="/tmp/secret/hotp.key"
HOTP_COUNTER="/boot/kexec_hotp_counter"
HOTP_KEY="/boot/kexec_hotp_key"
@ -27,19 +26,11 @@ 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"
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
if [ "$CONFIG_TPM" = "y" ]; then
DEBUG "Sealing HOTP secret reuses TOTP sealed secret..."
tpmr unseal 4d47 0,1,2,3,4,7 312 "$HOTP_SECRET" \
|| die "Unable to unseal HOTP secret"
fi
# Store counter in file instead of TPM for now, as it conflicts with Heads
# config TPM counter as TPM 1.2 can only increment one counter between reboots

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Generate a random secret, seal it with the PCRs
# and write it to the TPM NVRAM.
#
@ -15,6 +15,7 @@ HOST="$1"
if [ -z "$HOST" ]; then
HOST="TPMTOTP"
fi
TPM_PASSWORD="$2"
TOTP_SECRET="/tmp/secret/totp.key"
TOTP_SEALED="/tmp/secret/totp.sealed"
@ -28,61 +29,21 @@ dd \
|| die "Unable to generate 20 random bytes"
secret="`base32 < $TOTP_SECRET`"
# 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"
# 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_writevalue \
-in $TPM_NVRAM_SPACE \
-if "$TOTP_SEALED" \
pcrf="/tmp/secret/pcrf.bin"
tpmr pcrread 0 "$pcrf"
tpmr pcrread -a 1 "$pcrf"
tpmr pcrread -a 2 "$pcrf"
tpmr pcrread -a 3 "$pcrf"
# pcr 4 is expected to be zero (boot mode: init)
dd if=/dev/zero bs="$(tpmr pcrsize)" count=1 status=none >> "$pcrf"
# pcr 5 (kernel modules loaded) is not measured at sealing/unsealing of totp
DEBUG "Sealing TOTP neglecting PCR5 involvement (Dynamically loaded kernel modules are not firmware integrity attestation related)"
# pcr 6 (drive luks header) is not measured at sealing/unsealing of totp
DEBUG "Sealing TOTP without PCR6 involvement (LUKS header consistency is not firmware integrity attestation related)"
# pcr 7 is containing measurements of user injected stuff in cbfs
tpmr pcrread -a 7 "$pcrf"
tpmr seal "$TOTP_SECRET" "$TPM_NVRAM_SPACE" 0,1,2,3,4,7 "$pcrf" 312 "" "$TPM_PASSWORD" \
|| die "Unable to write sealed secret to NVRAM"
fi
shred -n 10 -z -u "$TOTP_SEALED" 2> /dev/null
url="otpauth://totp/$HOST?secret=$secret"

View File

@ -1,26 +0,0 @@
#!/bin/sh
# Initialize the USB and network device drivers,
# invoke a recovery shell and prompt the user for how to proceed
. /etc/functions
. /tmp/config
insmod /lib/modules/ehci-hcd.ko
insmod /lib/modules/ehci-pci.ko
insmod /lib/modules/xhci-hcd.ko
insmod /lib/modules/xhci-pci.ko
insmod /lib/modules/e1000e.ko
insmod /lib/modules/usb-storage.ko
tpm extend -ix 4 -ic recovery
sleep 2
echo '***** Starting recovery shell'
echo ''
echo 'To install from flash drive:'
echo ''
echo ' mount -o ro /dev/sdb1 /media'
echo ' flash.sh /media/t430.rom'
echo ''
exec /bin/ash

View File

@ -1,34 +1,10 @@
#!/bin/sh
#!/bin/bash
. /etc/functions
echo '*****'
echo '***** WARNING: This will erase all keys and secrets from the TPM'
echo '*****'
read -s -p "New TPM owner password: " key_password
echo
prompt_new_owner_password
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
tpmr reset "$key_password"

633
initrd/bin/tpmr Executable file
View File

@ -0,0 +1,633 @@
#!/bin/bash
# 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"
# PCR size in bytes. Set when we determine what TPM version is in use.
# TPM1 PCRs are always 20 bytes. TPM2 is allowed to provide multiple PCR banks
# with different algorithms - we always use SHA-256, so they are 32 bytes.
PCR_SIZE=
# Export CONFIG_TPM2_CAPTURE_PCAP=y from your board config to capture tpm2 pcaps to
# /tmp/tpm0.pcap; Wireshark can inspect these. (This must be enabled at build
# time so the pcap TCTI driver is included.)
if [ -n "$CONFIG_TPM2_CAPTURE_PCAP" ]; then
export TPM2TOOLS_TCTI="pcap:device:/dev/tpmrm0"
export TCTI_PCAP_FILE="/tmp/tpm0.pcap"
fi
set -e -o pipefail
if [ -r "/tmp/config" ]; then
. /tmp/config
else
. /etc/config
fi
TRACE "Under /bin/tpmr"
# Busybox xxd lacks -r, and we get hex dumps from TPM1 commands. This converts
# a hex dump to binary data using sed and printf
hex2bin() {
sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf
}
# Render a password as 'hex:<hexdump>' for use with tpm2-tools. Passwords
# should always be passed this way to avoid ambiguity. (Passing with no prefix
# would choke if the password happened to start with 'file:' or 'hex:'. Passing
# as a file still chokes if the password begins with 'hex:', oddly tpm2-tools
# accepts 'hex:' in the file content.)
tpm2_password_hex() {
echo "hex:$(echo -n "$1" | xxd -p | tr -d ' \n')"
}
# usage: tpmr pcrread [-a] <index> <file>
# Reads PCR binary data and writes to file.
# -a: Append to file. Default is to overwrite.
tpm2_pcrread() {
TRACE "Under /bin/tpmr:tpm2_pcrread"
if [ "$1" = "-a" ]; then
APPEND=y
shift
fi
index="$1"
file="$2"
if [ -z "$APPEND" ]; then
# Don't append - truncate file now so real command always
# appends
true >"$file"
fi
DO_WITH_DEBUG tpm2 pcrread -Q -o >(cat >>"$file") "sha256:$index"
}
tpm1_pcrread() {
TRACE "Under /bin/tpmr:tpm1_pcrread"
if [ "$1" = "-a" ]; then
APPEND=y
shift
fi
index="$1"
file="$2"
if [ -z "$APPEND" ]; then
# Don't append - truncate file now so real command always
# appends
true >"$file"
fi
DO_WITH_DEBUG tpm pcrread -ix "$index" | hex2bin >>"$file"
}
# usage: tpmr calcfuturepcr [-a] <input_file> <output_file>
# Uses the scratch PCR to calculate a future PCR value (TPM2 23, TPM1 16). The
# data in input file are hashed into a PCR, and the PCR value is placed in
# output_file.
# -a: Append to output_file. Default is to overwrite
tpm2_calcfuturepcr() {
TRACE "Under /bin/tpmr:tpm2_calcfuturepcr"
if [ "$1" = "-a" ]; then
APPEND=y
shift
fi
input_file="$1"
output_file="$2"
if [ -z "$APPEND" ]; then
true >"$output_file"
fi
tpm2 pcrreset -Q 23
DO_WITH_DEBUG tpmr extend -ix 23 -if "$input_file"
DO_WITH_DEBUG tpm2 pcrread -Q -o >(cat >>"$output_file") sha256:23
tpm2 pcrreset -Q 23
}
tpm1_calcfuturepcr() {
TRACE "Under /bin/tpmr:tpm1_calcfuturepcr"
if [ "$1" = "-a" ]; then
APPEND=y
shift
fi
input_file="$1"
output_file="$2"
if [ -z "$APPEND" ]; then
true >"$output_file"
fi
DO_WITH_DEBUG tpm calcfuturepcr -ix 16 -if "$input_file" | hex2bin >>"$output_file"
}
tpm2_extend() {
TRACE "Under /bin/tpmr:tpm2_extend"
while true; do
case "$1" in
-ix)
index="$2"
shift 2;;
-ic)
hash="$(echo -n "$2"|sha256sum|cut -d' ' -f1)"
shift 2;;
-if)
hash="$(sha256sum "$2"|cut -d' ' -f1)"
shift 2;;
*)
break;;
esac
done
tpm2 pcrextend "$index:sha256=$hash"
DO_WITH_DEBUG tpm2 pcrread "sha256:$index"
}
tpm2_counter_read() {
TRACE "Under /bin/tpmr: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() {
TRACE "Under /bin/tpmr: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() {
TRACE "Under /bin/tpmr: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 "$(tpm2_password_hex "$pwdo")" "0x$rand_index" > /dev/console
echo "$rand_index: (valid after an increment)"
}
tpm2_startsession() {
TRACE "Under /bin/tpmr:tpm2_startsession"
mkdir -p "$SECRET_DIR"
tpm2 flushcontext -Q \
--transient-object \
|| die "tpm2_flushcontext: unable to flush transient handles"
tpm2 flushcontext -Q \
--loaded-session \
|| die "tpm2_flushcontext: unable to flush sessions"
tpm2 flushcontext -Q \
--saved-session \
|| die "tpm2_flushcontext: unable to flush saved session"
tpm2 readpublic -Q -c "$PRIMARY_HANDLE" -t "/tmp/$PRIMARY_HANDLE_FILE"
tpm2 startauthsession -Q -c "/tmp/$PRIMARY_HANDLE_FILE" --hmac-session -S "/tmp/$ENC_SESSION_FILE"
tpm2 startauthsession -Q -c "/tmp/$PRIMARY_HANDLE_FILE" --hmac-session -S "/tmp/$DEC_SESSION_FILE"
tpm2 sessionconfig -Q --disable-encrypt "/tmp/$DEC_SESSION_FILE"
}
# Use cleanup_session() with at_exit to release a TPM2 session and delete the
# session file. E.g.:
# at_exit cleanup_session "$SESSION_FILE"
cleanup_session() {
TRACE "Under /bin/tpmr:cleanup_session"
session_file="$1"
if [ -f "$session_file" ]; then
DEBUG "Clean up session: $session_file"
# Nothing else we can do if this fails, still remove the file
tpm2 flushcontext -Q "$session_file" || DEBUG "Flush failed for session $session_file"
rm -f "$session_file"
else
DEBUG "No need to clean up session: $session_file"
fi
}
# Clean up a file by shredding it. No-op if the file wasn't created. Use with
# at_exit, e.g.:
# at_exit cleanup_shred "$FILE"
cleanup_shred() {
TRACE "Under /bin/tpmr:cleanup_shred"
shred -n 10 -z -u "$1" 2>/dev/null || true
}
# tpm2_seal: Seal a file against PCR values and, optionally, a password.
# If a password is given, both the PCRs and password are required to unseal the
# file. PCRs are provided as a PCR list and data file. PCR data must be
# provided - TPM2 allows the TPM to fall back to current PCR values, but it is
# not required to support this.
tpm2_seal() {
TRACE "Under /bin/tpmr:tpm2_seal"
file="$1" #$KEY_FILE
index="$2"
pcrl="$3" #0,1,2,3,4,5,6,7 (does not include algorithm prefix)
pcrf="$4"
sealed_size="$5" # Not used for TPM2
pass="$6" # May be empty to seal with no password
tpm_password="$7" # Owner password - will prompt if needed and not empty
# Owner password is always needed for TPM2.
mkdir -p "$SECRET_DIR"
bname="`basename $file`"
# Pad with up to 6 zeros, i.e. '0x81000001', '0x81001234', etc.
handle="$(printf "0x81%6s" "$index" | tr ' ' 0)"
DEBUG "tpm2_seal: file=$file handle=$handle pcrl=$pcrl pcrf=$pcrf pass=$(mask_param "$pass")"
# Create a policy requiring both PCRs and the object's authentication
# value using a trial session.
TRIAL_SESSION=/tmp/sealfile_trial.session
AUTH_POLICY=/tmp/sealfile_auth.policy
rm -f "$TRIAL_SESSION" "$AUTH_POLICY"
tpm2 startauthsession -g sha256 -S "$TRIAL_SESSION"
# We have to clean up the session
at_exit cleanup_session "$TRIAL_SESSION"
# Save the policy hash in case the password policy is not used (we have
# to get this from the last step, whichever it is).
tpm2 policypcr -Q -l "sha256:$pcrl" -f "$pcrf" -S "$TRIAL_SESSION" -L "$AUTH_POLICY"
CREATE_PASS_ARGS=()
if [ "$pass" ]; then
# Add an object authorization policy (the object authorization
# will be the password). Save the digest, this is the resulting
# policy.
tpm2 policypassword -Q -S "$TRIAL_SESSION" -L "$AUTH_POLICY"
# Pass the password to create later. Pass the sha256sum of the
# password to the TPM so the password is not limited to 32 chars
# in length.
CREATE_PASS_ARGS=(-p "$(tpm2_password_hex "$pass")")
fi
# Create the object with this policy and the auth value.
# NOTE: We disable USERWITHAUTH and enable ADMINWITHPOLICY so the
# password cannot be used on its own, the PCRs are also required.
# (The default is to allow either policy auth _or_ password auth. In
# this case the policy includes the password, and we don't want to allow
# the password on its own.)
tpm2 create -Q -C "/tmp/$PRIMARY_HANDLE_FILE" \
-i "$file" \
-u "$SECRET_DIR/$bname.priv" \
-r "$SECRET_DIR/$bname.pub" \
-L "$AUTH_POLICY" \
-S "/tmp/$DEC_SESSION_FILE" \
-a "fixedtpm|fixedparent|adminwithpolicy" \
"${CREATE_PASS_ARGS[@]}"
tpm2 load -Q -C "/tmp/$PRIMARY_HANDLE_FILE" \
-u "$SECRET_DIR/$bname.priv" -r "$SECRET_DIR/$bname.pub" \
-c "$SECRET_DIR/$bname.seal.ctx"
prompt_tpm_password
# remove possible data occupying this handle
tpm2 evictcontrol -Q -C o -P "$(tpm2_password_hex "$tpm_password")" \
-c "$handle" 2>/dev/null || true
DO_WITH_DEBUG --mask-position 6 \
tpm2 evictcontrol -Q -C o -P "$(tpm2_password_hex "$tpm_password")" \
-c "$SECRET_DIR/$bname.seal.ctx" "$handle"
}
tpm1_seal() {
TRACE "Under /bin/tpmr:tpm1_seal"
file="$1"
index="$2"
pcrl="$3" #0,1,2,3,4,5,6,7 (does not include algorithm prefix)
pcrf="$4"
sealed_size="$5"
pass="$6" # May be empty to seal with no password
tpm_password="$7" # Owner password - will prompt if needed and not empty
sealed_file="$SECRET_DIR/tpm1_seal_sealed.bin"
at_exit cleanup_shred "$sealed_file"
POLICY_ARGS=()
# If a password was given, add it to the policy arguments
if [ "$pass" ]; then
POLICY_ARGS+=(-pwdd "$pass")
fi
# Transform the PCR list and PCR file to discrete arguments
IFS=',' read -r -a PCR_LIST <<<"$pcrl"
pcr_file_index=0
for pcr in "${PCR_LIST[@]}"; do
# Read each PCR_SIZE block from the file and pass as hex
POLICY_ARGS+=(-ix "$pcr"
"$(dd if="$pcrf" skip="$pcr_file_index" bs="$PCR_SIZE" count=1 status=none | xxd -p | tr -d ' ')"
)
pcr_file_index=$((pcr_file_index+1))
done
tpm sealfile2 \
-if "$file" \
-of "$sealed_file" \
-hk 40000000 \
"${POLICY_ARGS[@]}"
# try it without the owner password first
if ! tpm nv_writevalue -in "$index" -if "$sealed_file"; 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"
prompt_tpm_password
tpm nv_definespace -in "$index" -sz "$sealed_size" \
-pwdo "$tpm_password" -per 0 \
|| warn "Warning: Unable to define NVRAM space; trying anyway"
tpm nv_writevalue -in "$index" -if "$sealed_file" \
|| die "Unable to write sealed secret to NVRAM"
fi
}
# Unseal a file sealed by tpm2_seal. The PCR list must be provided, the
# password must be provided if one was used to seal (and cannot be provided if
# no password was used to seal).
tpm2_unseal() {
TRACE "Under /bin/tpmr:tpm2_unseal"
index="$1"
pcrl="$2" #0,1,2,3,4,5,6,7 (does not include algorithm prefix)
sealed_size="$3"
file="$4"
pass="$5"
# TPM2 doesn't care about sealed_size, only TPM1 needs that. We don't
# have to separately read the sealed file on TPM2.
# Pad with up to 6 zeros, i.e. '0x81000001', '0x81001234', etc.
handle="$(printf "0x81%6s" "$index" | tr ' ' 0)"
DEBUG "tpm2_unseal: handle=$handle pcrl=$pcrl file=$file pass=$(mask_param "$pass")"
# If we don't have the primary handle (TPM hasn't been reset), tpm2 will
# print nonsense error messages about an unexpected handle value. We
# can't do anything without a primary handle.
if [ ! -f "/tmp/$PRIMARY_HANDLE_FILE" ]; then
DEBUG "tpm2_unseal: No primary handle, cannot attempt to unseal"
exit 1
fi
POLICY_SESSION=/tmp/unsealfile_policy.session
rm -f "$POLICY_SESSION"
tpm2 startauthsession -Q -g sha256 -S "$POLICY_SESSION" --policy-session
at_exit cleanup_session "$POLICY_SESSION"
# Check the PCR policy
tpm2 policypcr -Q -l "sha256:$pcrl" -S "$POLICY_SESSION"
UNSEAL_PASS_SUFFIX=""
if [ "$pass" ]; then
# Add the object authorization policy (the actual password is
# provided later, but we must include this so the policy we
# attempt to use is correct).
tpm2 policypassword -Q -S "$POLICY_SESSION"
# When unsealing, include the password with the auth session
UNSEAL_PASS_SUFFIX="+$(tpm2_password_hex "$pass")"
fi
tpm2 unseal -Q -c "$handle" -p "session:$POLICY_SESSION$UNSEAL_PASS_SUFFIX" \
-S "/tmp/$ENC_SESSION_FILE" > "$file"
}
tpm1_unseal() {
TRACE "Under /bin/tpmr:tpm1_unseal"
index="$1"
pcrl="$2"
sealed_size="$3"
file="$4"
pass="$5"
# pcrl (the PCR list) is unused in TPM1. The TPM itself knows which
# PCRs were used to seal and checks them. We can't verify that it's
# correct either, so just ignore it in TPM1.
sealed_file="$SECRET_DIR/tpm1_unseal_sealed.bin"
at_exit cleanup_shred "$sealed_file"
rm -f "$sealed_file"
tpm nv_readvalue \
-in "$index" \
-sz "$sealed_size" \
-of "$sealed_file" \
|| die "Unable to read sealed file from TPM NVRAM"
PASS_ARGS=()
if [ "$pass" ]; then
PASS_ARGS=(-pwdd "$pass")
fi
tpm unsealfile \
-if "$sealed_file" \
-of "$file" \
"${PASS_ARGS[@]}" \
-hk 40000000
}
tpm2_reset() {
TRACE "Under /bin/tpmr:tpm2_reset"
key_password="$1"
mkdir -p "$SECRET_DIR"
tpm2 clear -c platform || warn "Unable to clear TPM on platform hierarchy!"
tpm2 changeauth -c owner "$(tpm2_password_hex "$key_password")"
tpm2 changeauth -c endorsement "$(tpm2_password_hex "$key_password")"
tpm2 createprimary -C owner -g sha256 -G "${CONFIG_PRIMARY_KEY_TYPE:-rsa}" \
-c "$SECRET_DIR/primary.ctx" -P "$(tpm2_password_hex "$key_password")"
tpm2 evictcontrol -C owner -c "$SECRET_DIR/primary.ctx" "$PRIMARY_HANDLE" \
-P "$(tpm2_password_hex "$key_password")"
shred -u "$SECRET_DIR/primary.ctx"
tpm2_startsession
# Set the dictionary attack parameters. TPM2 defaults vary widely, we
# want consistent behavior on any TPM.
# * --max-tries=10: Allow 10 failures before lockout. This allows the
# user to quickly "burst" 10 failures without significantly impacting
# the rate allowed for a dictionary attacker.
# Most TPM2 flows ask for the owner password 2-4 times, so this allows
# a handful of mistypes and some headroom for an expected unseal
# failure if firmware is updated.
# Remember that an auth failure is also counted any time an unclean
# shutdown occurs (see TPM2 spec part 1, section 19.8.6, "Non-orderly
# Shutdown").
# * --recovery-time=3600: Forget an auth failure every 1 hour.
# * --lockout-recovery-time: After a failed lockout recovery auth, the
# TPM must be reset to try again.
#
# Heads does not offer a way to reset dictionary attack lockout, instead
# the TPM can be reset and new secrets sealed.
tpm2 dictionarylockout -Q --setup-parameters \
--max-tries=10 \
--recovery-time=3600 \
--lockout-recovery-time=0 \
--auth="session:/tmp/$ENC_SESSION_FILE"
# Set a random DA lockout password, so the DA lockout can't be cleared
# with a password. Heads doesn't offer dictionary attach reset, instead
# the TPM can be reset and new secrets sealed.
#
# The default lockout password is empty, so we must set this, and we
# don't need to provide any auth (use the default empty password).
tpm2 changeauth -Q -c lockout \
"hex:$(dd if=/dev/urandom bs=32 count=1 status=none | xxd -p | tr -d ' \n')"
}
tpm1_reset() {
TRACE "Under /bin/tpmr:tpm1_reset"
key_password="$1"
# 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
}
# Perform final cleanup before boot and lock the platform heirarchy.
tpm2_kexec_finalize() {
TRACE "Under /bin/tpmr:tpm2_kexec_finalize"
# Flush sessions and transient objects
tpm2 flushcontext -Q --transient-object \
|| warn "tpm2_flushcontext: unable to flush transient handles"
tpm2 flushcontext -Q --loaded-session \
|| warn "tpm2_flushcontext: unable to flush sessions"
tpm2 flushcontext -Q --saved-session \
|| warn "tpm2_flushcontext: unable to flush saved session"
# 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 TPM2 platform hierarchy..."
randpass=$(dd if=/dev/urandom bs=4 count=1 status=none | xxd -p)
tpm2 changeauth -c platform "$randpass" \
|| warn "Failed to lock platform hierarchy of TPM2!"
}
tpm2_shutdown() {
TRACE "Under /bin/tpmr:tpm2_shutdown"
# Prepare for shutdown.
# This is a "clear" shutdown (do not preserve runtime state) since we
# are not going to resume later, we are powering off (or rebooting).
tpm2 shutdown -Q --clear
}
if [ "$CONFIG_TPM" != "y" ]; then
echo >&2 "No TPM!"
exit 1
fi
# TPM1 - most commands forward directly to tpm, but some are still wrapped for
# consistency with tpm2.
if [ "$CONFIG_TPM2_TOOLS" != "y" ]; then
PCR_SIZE=20 # TPM1 PCRs are always SHA-1
subcmd="$1"
# Don't shift yet, for most commands we will just forward to tpm.
case "$subcmd" in
pcrread)
shift; tpm1_pcrread "$@";;
pcrsize)
echo "$PCR_SIZE";;
calcfuturepcr)
shift; tpm1_calcfuturepcr "$@";;
seal)
shift; tpm1_seal "$@";;
startsession)
;; # Nothing on TPM1.
unseal)
shift; tpm1_unseal "$@";;
reset)
shift; tpm1_reset "$@";;
kexec_finalize)
;; # Nothing on TPM1.
shutdown)
;; # Nothing on TPM1.
*)
DEBUG "Direct translation from tpmr to tpm1 call"
DO_WITH_DEBUG exec tpm "$@"
;;
esac
exit 0
fi
# TPM2 - all commands implemented as wrappers around tpm2
PCR_SIZE=32 # We use the SHA-256 PCRs
subcmd="$1"
shift 1
case "$subcmd" in
pcrread)
tpm2_pcrread "$@";;
pcrsize)
echo "$PCR_SIZE";;
calcfuturepcr)
tpm2_calcfuturepcr "$@";;
extend)
tpm2_extend "$@";;
counter_read)
tpm2_counter_read "$@";;
counter_increment)
tpm2_counter_inc "$@";;
counter_create)
tpm2_counter_cre "$@";;
seal)
tpm2_seal "$@";;
startsession)
tpm2_startsession "$@";;
unseal)
tpm2_unseal "$@";;
reset)
tpm2_reset "$@";;
kexec_finalize)
tpm2_kexec_finalize "$@";;
shutdown)
tpm2_shutdown "$@";;
*)
echo "Command $subcmd not wrapped!"
exit 1
esac

View File

@ -1,4 +1,4 @@
#!/bin/ash
#!/bin/bash
set -e -o pipefail
. /etc/functions
@ -19,7 +19,7 @@ if [ -n "GUID" ]; then
|| die "Failed to read config GUID from ROM"
if [ "$CONFIG_TPM" = "y" ]; then
tpm extend -ix "$CONFIG_PCR" -if $TMPFILE \
tpmr extend -ix "$CONFIG_PCR" -if $TMPFILE \
|| die "$filename: tpm extend failed"
fi

View File

@ -1,9 +1,8 @@
#!/bin/sh
#!/bin/bash
# Retrieve the sealed file and counter from the NVRAM, unseal it and compute the hotp
. /etc/functions
HOTP_SEALED="/tmp/secret/hotp.sealed"
HOTP_SECRET="/tmp/secret/hotp.key"
HOTP_COUNTER="/boot/kexec_hotp_counter"
@ -38,20 +37,10 @@ if [ "$counter_value" == "" ]; then
fi
#counter_value=$(printf "%d" 0x${counter_value})
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"
shred -n 10 -z -u "$HOTP_SEALED" 2> /dev/null
if [ "$CONFIG_TPM" = "y" ]; then
DEBUG "Unsealing HOTP secret reuses TOTP sealed secret..."
tpmr unseal 4d47 0,1,2,3,4,7 312 "$HOTP_SECRET"
fi
if ! hotp $counter_value < "$HOTP_SECRET"; then
shred -n 10 -z -u "$HOTP_SECRET" 2> /dev/null

View File

@ -1,26 +1,16 @@
#!/bin/sh
#!/bin/bash
# Retrieve the sealed file from the NVRAM, unseal it and compute the totp
. /etc/functions
TOTP_SEALED="/tmp/secret/totp.sealed"
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"
tpm unsealfile \
-hk 40000000 \
-if "$TOTP_SEALED" \
-of "$TOTP_SECRET" \
|| die "Unable to unseal totp secret"
shred -n 10 -z -u "$TOTP_SEALED" 2> /dev/null
if [ "$CONFIG_TPM" = "y" ]; then
tpmr unseal 4d47 0,1,2,3,4,7 312 "$TOTP_SECRET" \
|| die "Unable to unseal totp secret"
fi
if ! totp -q < "$TOTP_SECRET"; then
shred -n 10 -z -u "$TOTP_SECRET" 2> /dev/null

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Boot a USB installation
. /etc/functions
@ -8,7 +8,7 @@ TRACE "Under /bin/usb-init"
if [ "$CONFIG_TPM" = "y" ]; then
# Extend PCR4 as soon as possible
tpm extend -ix 4 -ic usb
tpmr extend -ix 4 -ic usb
fi
media-scan usb

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# get a file and extend a TPM PCR
. /etc/functions
@ -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"

View File

@ -1,28 +0,0 @@
#!/bin/sh
# Initialize the USB and network device drivers,
# invoke a recovery shell and prompt the user for how to proceed
. /etc/functions
. /tmp/config
TRACE "Under /bin/x230-flash.init"
insmod /lib/modules/ehci-hcd.ko
insmod /lib/modules/ehci-pci.ko
insmod /lib/modules/xhci-hcd.ko
insmod /lib/modules/xhci-pci.ko
insmod /lib/modules/e1000e.ko
insmod /lib/modules/usb-storage.ko
tpm extend -ix 4 -ic recovery
sleep 2
echo '***** Starting recovery shell'
echo ''
echo 'To install from flash drive:'
echo ''
echo ' mount -o ro /dev/sdb1 /media'
echo ' flash.sh /media/x230.rom'
echo ''
exec /bin/ash

27
initrd/bin/xx30-flash.init Executable file
View File

@ -0,0 +1,27 @@
#!/bin/ash
# Initialize the USB and network device drivers,
# invoke a recovery shell and prompt the user for how to proceed
. /etc/ash_functions
. /tmp/config
TRACE "Under /bin/xx30-flash.init"
busybox insmod /lib/modules/ehci-hcd.ko
busybox insmod /lib/modules/ehci-pci.ko
busybox insmod /lib/modules/xhci-hcd.ko
busybox insmod /lib/modules/xhci-pci.ko
busybox insmod /lib/modules/e1000e.ko
busybox insmod /lib/modules/usb-storage.ko
sleep 2
echo '***** Starting recovery shell'
echo ''
echo 'To install from flash drive:'
echo ''
echo ' mount -o ro /dev/sdb1 /media'
echo ' flash.sh /media/xx30-legacy.rom'
echo ''
exec /bin/sh

87
initrd/etc/ash_functions Normal file
View File

@ -0,0 +1,87 @@
#!/bin/sh
#
# Core shell functions that do not require bash. These functions are used with
# busybox ash on legacy-flash boards, and with bash on all other boards.
die() {
echo >&2 "$*";
sleep 2;
exit 1;
}
warn() {
echo >&2 "$*";
sleep 1;
}
DEBUG() {
if [ "$CONFIG_DEBUG_OUTPUT" = "y" ];then
echo "DEBUG: $*" | tee -a /tmp/debug.log >&2;
fi
}
TRACE() {
if [ "$CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT" = "y" ];then
echo "TRACE: $*" | tee -a /tmp/debug.log >&2;
fi
}
preserve_rom() {
TRACE "Under /etc/functions:preserve_rom"
new_rom="$1"
old_files=`cbfs -t 50 -l 2>/dev/null | grep "^heads/"`
for old_file in `echo $old_files`; do
new_file=`cbfs.sh -o $1 -l | grep -x $old_file`
if [ -z "$new_file" ]; then
echo "+++ Adding $old_file to $1"
cbfs -t 50 -r $old_file >/tmp/rom.$$ \
|| die "Failed to read cbfs file from ROM"
cbfs.sh -o $1 -a $old_file -f /tmp/rom.$$ \
|| die "Failed to write cbfs file to new ROM file"
fi
done
}
recovery() {
TRACE "Under /etc/functions:recovery"
echo >&2 "!!!!! $*"
# Remove any temporary secret files that might be hanging around
# but recreate the directory so that new tools can use it.
#safe to always be true. Otherwise "set -e" would make it exit here
shred -n 10 -z -u /tmp/secret/* 2> /dev/null || true
rm -rf /tmp/secret
mkdir -p /tmp/secret
# ensure /tmp/config exists for recovery scripts that depend on it
touch /tmp/config
if [ "$CONFIG_TPM" = "y" ]; then
tpmr extend -ix 4 -ic recovery
fi
while [ true ]
do
echo >&2 "!!!!! Starting recovery shell"
sleep 1
if [ -x /bin/setsid ]; then
/bin/setsid -c /bin/sh
else
/bin/sh
fi
done
}
pause_recovery() {
TRACE "Under /etc/functions:pause_recovery"
read -p $'!!! Hit enter to proceed to recovery shell !!!\n'
recovery $*
}
combine_configs() {
TRACE "Under /etc/functions:combine_configs"
cat /etc/config* > /tmp/config
}

View File

@ -1,71 +1,44 @@
#!/bin/sh
#!/bin/bash
# Shell functions for most initialization scripts
. /etc/ash_functions
die() {
echo >&2 "$*";
sleep 2;
exit 1;
}
warn() {
echo >&2 "$*";
sleep 1;
}
DEBUG() {
if [ "$CONFIG_DEBUG_OUTPUT" = "y" ];then
echo >&2 "DEBUG: $*";
# Print <hidden> or <empty> depending on whether $1 is empty. Useful to mask an
# optional password parameter.
mask_param() {
if [ -z "$1" ]; then
echo "<empty>"
else
echo "<hidden>"
fi
}
TRACE() {
if [ "$CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT" = "y" ];then
echo >&2 "TRACE: $*";
fi
}
# Trace a command with DEBUG, then execute it.
# A password parameter can be masked by passing --mask-position N before the
# command to execute, the debug trace will just indicate whether the password
# was empty or nonempty (which is important when use of a password is optional).
# N=0 is the name of the command to be executed, N=1 is its first parameter,
# etc.
DO_WITH_DEBUG() {
if [ "$1" == "--mask-position" ]; then
mask_position="$2"
shift
shift
DEBUG_ARGS=("$@")
recovery() {
TRACE "Under /etc/functions:recovery"
echo >&2 "!!!!! $*"
# Remove any temporary secret files that might be hanging around
# but recreate the directory so that new tools can use it.
#safe to always be true. Otherwise "set -e" would make it exit here
shred -n 10 -z -u /tmp/secret/* 2> /dev/null || true
rm -rf /tmp/secret
mkdir -p /tmp/secret
# 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
DEBUG_ARGS[$mask_position]="$(mask_param "${DEBUG_ARGS[$mask_position]}")"
DEBUG "${DEBUG_ARGS[@]}"
else
DEBUG "$@"
fi
while [ true ]
do
echo >&2 "!!!!! Starting recovery shell"
sleep 1
if [ -x /bin/setsid ]; then
/bin/setsid -c /bin/ash
else
/bin/ash
fi
done
}
pause_recovery() {
TRACE "Under /etc/functions:pause_recovery"
read -p 'Hit enter to proceed to recovery shell:'
recovery $*
"$@"
}
pcrs() {
head -8 /sys/class/tpm/tpm0/pcrs
if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then
tpm2 pcrread sha256
elif [ "$CONFIG_TPM" = "y" ]; then
head -8 /sys/class/tpm/tpm0/pcrs
fi
}
confirm_totp()
@ -81,7 +54,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" ]; then
TOTP="NO TPM"
elif [ "$half" != "$last_half" ]; then
last_half=$half;
@ -236,20 +209,52 @@ confirm_gpg_card()
fi
}
# Prompt for an owner password if it is not already set in tpm_password. Sets
# tpm_password. Tools should optionally accept a TPM password on the command
# line, since some flows need it multiple times and only one prompt is ideal.
prompt_tpm_password() {
if [ -n "$tpm_password" ]; then
return 0;
fi
read -s -p "TPM Owner password: " tpm_password
echo # new line after password prompt
}
# Prompt for a new owner password when resetting the TPM. Returned in
# key_password. The password must be 1-32 characters and must be entered twice,
# the script will loop until this is met.
prompt_new_owner_password() {
local key_password2
key_password=1
key_password2=2
while [ "$key_password" != "$key_password2" ] || [ "${#key_password}" -gt 32 ] || [ -z "$key_password" ]; do
read -s -p "New TPM owner passphrase (2 words suggested, 1-32 characters max): " key_password
echo
read -s -p "Repeat chosen TPM owner passphrase: " key_password2
echo
if [ "$key_password" != "$key_password2" ]; then
echo "Passphrases entered do not match. Try again!"
echo
fi
done
}
check_tpm_counter()
{
TRACE "Under /etc/functions:check_tpm_counter"
LABEL=${2:-3135106223}
tpm_password="$3"
# if the /boot.hashes file already exists, read the TPM counter ID
# from it.
if [ -r "$1" ]; then
TPM_COUNTER=`grep counter- "$1" | cut -d- -f2`
else
warn "$1 does not exist; creating new TPM counter"
read -s -p "TPM Owner password: " tpm_password
echo
tpm counter_create \
prompt_tpm_password
tpmr counter_create \
-pwdo "$tpm_password" \
-pwdc '' \
-la $LABEL \
@ -266,14 +271,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"
}
@ -307,22 +312,6 @@ check_config() {
|| die "Failed to copy kexec boot params to tmp"
}
preserve_rom() {
TRACE "Under /etc/functions:preserve_rom"
new_rom="$1"
old_files=`cbfs -t 50 -l 2>/dev/null | grep "^heads/"`
for old_file in `echo $old_files`; do
new_file=`cbfs.sh -o $1 -l | grep -x $old_file`
if [ -z "$new_file" ]; then
echo "+++ Adding $old_file to $1"
cbfs -t 50 -r $old_file >/tmp/rom.$$ \
|| die "Failed to read cbfs file from ROM"
cbfs.sh -o $1 -a $old_file -f /tmp/rom.$$ \
|| die "Failed to write cbfs file to new ROM file"
fi
done
}
replace_config() {
TRACE "Under /etc/functions:replace_config"
CONFIG_FILE=$1
@ -339,10 +328,6 @@ replace_config() {
sort ${CONFIG_FILE}.tmp | uniq > ${CONFIG_FILE}
rm -f ${CONFIG_FILE}.tmp
}
combine_configs() {
TRACE "Under /etc/functions:combine_configs"
cat /etc/config* > /tmp/config
}
update_checksums()
{
@ -358,8 +343,10 @@ update_checksums()
# sign and auto-roll config counter
extparam=
if [ "$CONFIG_TPM" = "y" ]; then
extparam=-r
if [ "$CONFIG_TPM" = "y" ];then
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
extparam=-r
fi
fi
if ! kexec-sign-config -p /boot -u $extparam ; then
rv=1
@ -568,3 +555,37 @@ generate_random_mac_address()
#Borrowed from https://stackoverflow.com/questions/42660218/bash-generate-random-mac-address-unicast
hexdump -n 6 -ve '1/1 "%.2x "' /dev/urandom | awk -v a="2,6,a,e" -v r="$RANDOM" 'BEGIN{srand(r);}NR==1{split(a,b,",");r=int(rand()*4+1);printf "%s%s:%s:%s:%s:%s:%s\n",substr($1,0,1),b[r],$2,$3,$4,$5,$6}'
}
# Add a command to be invoked at exit. (Note that trap EXIT replaces any
# existing handler.) Commands are invoked in reverse order, so they can be used
# to clean up resources, etc.
# The parameters are all executed as-is and do _not_ require additional quoting
# (unlike trap). E.g.:
# at_exit shred "$file" #<-- file is expanded when calling at_exit, no extra quoting needed
at_exit() {
AT_EXIT_HANDLERS+=("$@") # Command and args
AT_EXIT_HANDLERS+=("$#") # Number of elements in this command
}
# Array of all exit handler command arguments with lengths of each command at
# the end. For example:
# at_exit echo hello
# at_exit echo a b c
# results in:
# AT_EXIT_HANDLERS=(echo hello 2 echo a b c 4)
AT_EXIT_HANDLERS=()
# Each handler is an array AT_EXIT_HANDLER_{i}
run_at_exit_handlers() {
local cmd_pos cmd_len
cmd_pos="${#AT_EXIT_HANDLERS[@]}"
# Silence trace if there are no handlers, this is common and occurs a lot
[ "$cmd_pos" -gt 0 ] && DEBUG "Running at_exit handlers"
while [ "$cmd_pos" -gt 0 ]; do
cmd_pos="$((cmd_pos-1))"
cmd_len="${AT_EXIT_HANDLERS[$cmd_pos]}"
cmd_pos="$((cmd_pos-cmd_len))"
"${AT_EXIT_HANDLERS[@]:$cmd_pos:$cmd_len}"
done
}
trap run_at_exit_handlers EXIT

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Shell functions for common operations using fbwhiptail
. /etc/functions

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Reencrypt LUKS container and change Disk Recovery Key associated passphrase (Slot 0: main slot)
. /etc/functions

View File

@ -1 +1 @@
root:x:0:0:root:/:/bin/ash
root:x:0:0:root:/:/bin/sh

View File

@ -1,4 +1,7 @@
#!/bin/ash
#! /bin/ash
# Note this is used on legacy-flash boards that lack bash, it runs with busybox
# ash. Calls to bash scripts must be guarded by checking config.
mknod /dev/ttyprintk c 5 3
echo "hello world" > /dev/ttyprintk
@ -16,6 +19,7 @@ mkdir /proc /sys /dev /tmp /boot /media 2>&- 1>&-
mount /dev 2>/dev/ttyprintk
mount /proc 2>/dev/ttyprintk
mount /sys 2>/dev/ttyprintk
if [ "$CONFIG_LINUXBOOT" = "y" ]; then
mount /sys/firmware/efi/efivars
fi
@ -28,6 +32,12 @@ if [ ! -r /dev/ptmx ]; then
ln -s /dev/pts/ptmx /dev/ptmx
fi
# Needed by bash
[ -e /dev/stdin ] || ln -s /proc/self/fd/0 /dev/stdin
[ -e /dev/stdout ] || ln -s /proc/self/fd/1 /dev/stdout
[ -e /dev/stderr ] || ln -s /proc/self/fd/2 /dev/stderr
[ -e /dev/fd ] || ln -s /proc/self/fd /dev/fd
# Recovery shells will erase anything from here
mkdir -p /tmp/secret
@ -40,16 +50,16 @@ fi
hwclock -l -s
# Read the system configuration parameters
. /etc/functions
. /etc/ash_functions
. /etc/config
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,8 +71,13 @@ else
export BG_COLOR_ERROR="${CONFIG_ERROR_BG_COLOR:-""}"
fi
if [ "$CONFIG_TPM" = "y" ]; then
# Initialize tpm2 encrypted sessions here
tpmr startsession
fi
if [ "$CONFIG_COREBOOT" = "y" ]; then
/bin/cbfs-init
[ -x /bin/bash ] && /bin/cbfs-init
fi
if [ "$CONFIG_LINUXBOOT" = "y" ]; then
/bin/uefi-init
@ -71,7 +86,7 @@ fi
# Set GPG_TTY before calling gpg in key-init
export GPG_TTY=/dev/console
/bin/key-init
[ -x /bin/bash ] && /bin/key-init
# Setup recovery serial shell
if [ ! -z "$CONFIG_BOOT_RECOVERY_SERIAL" ]; then
@ -100,17 +115,19 @@ if [ "$boot_option" = "r" ]; then
recovery 'User requested recovery shell'
# just in case...
if [ "$CONFIG_TPM" = "y" ]; then
tpm extend -ix 4 -ic recovery
tpmr extend -ix 4 -ic recovery
fi
exec /bin/ash
exec /bin/sh
exit
fi
# Override CONFIG_TPM from /etc/config with runtime value determined above.
# Override CONFIG_TPM and CONFIG_TPM2_TOOLS from /etc/config with runtime value
# determined above.
#
# Values in user config have higher priority during combining thus effectively
# changing the value for the rest of the scripts which source /tmp/config.
echo "export CONFIG_TPM=\"$CONFIG_TPM\"" >> /etc/config.user
echo "export CONFIG_TPM2_TOOLS=\"$CONFIG_TPM2_TOOLS\"" >> /etc/config.user
combine_configs
. /tmp/config
@ -157,6 +174,6 @@ fi
# belts and suspenders, just in case...
if [ "$CONFIG_TPM" = "y" ]; then
tpm extend -ix 4 -ic recovery
tpmr extend -ix 4 -ic recovery
fi
exec /bin/ash
exec /bin/sh

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Extract the GPG signed dmsetup configuration from
# the header of the file system, validate it against
# the trusted key database, and execute it to mount

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# udhcpc script

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# extend a TPM PCR with a module and then load it
# any arguments will also be measured.
# The default PCR to be extended is 5, but can be
@ -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

32
modules/bash Normal file
View File

@ -0,0 +1,32 @@
# 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 := CFLAGS=-Os ./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 \
--disable-readline \
bash_target := $(MAKE_JOBS) \
&& $(MAKE) -C $(build)/$(bash_dir) \
DESTDIR="$(INSTALL)" \
install \
bash_output := bash
bash_depends := $(musl_dep)

View File

@ -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)" \

64
modules/openssl Normal file
View File

@ -0,0 +1,64 @@
# OpenSSL library
modules-$(CONFIG_OPENSSL) += openssl
openssl_version := 3.0.8
openssl_dir := openssl-$(openssl_version)
openssl_tar := openssl-$(openssl_version).tar.gz
openssl_url := https://www.openssl.org/source/$(openssl_tar)
openssl_hash := 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
# hack to provide path to libgcc
LIBGCC_DIR := $(dir $(shell $(heads_cc) -print-libgcc-file-name))
# The only optional algorithm that's enabled is SM3. tpm2-tss uses SHA, AES,
# and SM3.
openssl_configure := \
$(CROSS_TOOLS) \
CFLAGS="-Os" \
LDFLAGS="-L$(LIBGCC_DIR)" \
./Configure \
--prefix="/" \
no-tests \
linux-$(strip $(arch)) \
no-aria \
no-bf \
no-blake2 \
no-camellia \
no-cast \
no-chacha \
no-cmac \
no-des \
no-dh \
no-dsa \
no-ecdh \
no-ecdsa \
no-idea \
no-md4 \
no-mdc2 \
no-ocb \
no-poly1305 \
no-rc2 \
no-rc4 \
no-rmd160 \
no-scrypt \
no-seed \
no-siphash \
no-siv \
no-sm2 \
no-sm4 \
no-whirlpool \
openssl_target := $(MAKE_JOBS) \
build_programs \
&& \
$(MAKE) \
-C "$(build)/$(openssl_dir)" \
DESTDIR="$(INSTALL)" \
LIBDIR="lib" \
install_sw \
# Only libcrypto is needed currently, libssl is not included in initrd
openssl_libraries := \
libcrypto.so.3 \
openssl_depends := $(musl_dep)

36
modules/tpm2-tools Normal file
View File

@ -0,0 +1,36 @@
# TPM2 tools program
modules-$(CONFIG_TPM2_TOOLS) += tpm2-tools
# CONFIG_TPM means any TPM version. (CONFIG_TPM2_TOOLS differentiates them when
# they must be handled differently, which should be localized.) Boards setting
# CONFIG_TPM2_TOOLS=y imply CONFIG_TPM=y.
ifeq "$(CONFIG_TPM2_TOOLS)" "y"
export CONFIG_TPM=y
endif
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 := openssl tpm2-tss $(musl_dep)

45
modules/tpm2-tss Normal file
View File

@ -0,0 +1,45 @@
# 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 \
# The pcap TCTI driver is only included if enabled in the board config.
ifeq "$(CONFIG_TPM2_CAPTURE_PCAP)" "y"
tpm2-tss_libraries += src/tss2-tcti/.libs/libtss2-tcti-pcap.so.0
endif
tpm2-tss_depends := openssl $(musl_dep)

View File

@ -2,14 +2,11 @@ modules-$(CONFIG_TPMTOTP) += tpmtotp
tpmtotp_depends := mbedtls qrencode $(musl_dep)
#tpmtotp_version := git
#tpmtotp_repo := https://github.com/osresearch/tpmtotp
tpmtotp_version := 18b860fdcf5a55537c8395b891f2b2a5c24fc00a
tpmtotp_version := 4d63d21c8b7db2e92ddb393057f168aead147f47
tpmtotp_dir := tpmtotp-$(tpmtotp_version)
tpmtotp_tar := tpmtotp-$(tpmtotp_version).tar.gz
tpmtotp_url := https://github.com/osresearch/tpmtotp/archive/$(tpmtotp_version).tar.gz
tpmtotp_hash := 1082f2b0e4af833e04220dddedcc21a39eb39ee4dc5668bb010e7bcc795c606c
tpmtotp_hash := eaac1e8f652f1da7f5a1ed6a8cfefb6511f1e5e1dabf93b44db3b29c18c5ae53
tpmtotp_target := \
$(CROSS_TOOLS) \

View File

@ -0,0 +1,33 @@
diff --git a/Makefile.am b/Makefile.am
index 7132215..32e2193 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/configure.ac b/configure.ac
index f1c1711..7279baa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -59,7 +59,6 @@ PKG_CHECK_MODULES([TSS2_MU], [tss2-mu])
PKG_CHECK_MODULES([TSS2_RC], [tss2-rc])
PKG_CHECK_MODULES([TSS2_SYS], [tss2-sys])
PKG_CHECK_MODULES([CRYPTO], [libcrypto >= 1.1.0])
-PKG_CHECK_MODULES([CURL], [libcurl])
# pretty print of devicepath if efivar library is present
PKG_CHECK_MODULES([EFIVAR], [efivar],,[true])

View File

@ -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 -----------------------