summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorey Hinshaw2018-10-03 22:33:32 -0400
committerCorey Hinshaw2018-10-03 22:33:32 -0400
commit34646d61c9a0ea7335429f48bc42f18db0025849 (patch)
tree727067ef2ccf3d7e0a888e33074e302f3b1cae32
downloadaur-34646d61c9a0ea7335429f48bc42f18db0025849.tar.gz
Initial commit
-rw-r--r--.SRCINFO18
-rw-r--r--.editorconfig13
-rw-r--r--.gitignore4
-rw-r--r--PKGBUILD22
-rw-r--r--README.md64
-rw-r--r--hook_tpm2145
-rw-r--r--install_tpm247
7 files changed, 313 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..8da3d73e1558
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,18 @@
+pkgbase = mkinitcpio-tpm2-encrypt
+ pkgdesc = mkinitcpio hook that decrypts a TPM2-sealed LUKS keyfile
+ pkgver = 1.0
+ pkgrel = 1
+ url = https://aur.archlinux.org/packages/mkinitcpio-tpm2-encrypt/
+ arch = any
+ license = GPL3
+ depends = mkinitcpio
+ depends = tpm2-tools
+ source = install_tpm2
+ source = hook_tpm2
+ source = README.md
+ sha256sums = 43139f076c03ca147d8bf368b98bdd6b237ab927e53194feb944f58e38914901
+ sha256sums = f1cd4ec3197ec4843265e0d61518f641a0dbd650c42cf0399cace0076163fc7c
+ sha256sums = 11585844eb33ce997e55087dbec0610693bd79e3b1ffb02c9818214ce401a9fb
+
+pkgname = mkinitcpio-tpm2-encrypt
+
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000000..26ae5ad881ee
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,13 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+indent_size = 2
+trim_trailing_whitespace = false
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000000..19681f384f40
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.tar.gz
+*.tar.xz
+/pkg
+/src
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..d535ab895fd4
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,22 @@
+# Maintainer: Corey Hinshaw <coreyhinshaw(at)gmail(dot)com>
+
+pkgname=mkinitcpio-tpm2-encrypt
+pkgver=1.0
+pkgrel=1
+pkgdesc="mkinitcpio hook that decrypts a TPM2-sealed LUKS keyfile"
+url="https://aur.archlinux.org/packages/mkinitcpio-tpm2-encrypt/"
+arch=(any)
+license=('GPL3')
+depends=('mkinitcpio' 'tpm2-tools')
+source=('install_tpm2'
+ 'hook_tpm2'
+ 'README.md')
+sha256sums=('43139f076c03ca147d8bf368b98bdd6b237ab927e53194feb944f58e38914901'
+ 'f1cd4ec3197ec4843265e0d61518f641a0dbd650c42cf0399cace0076163fc7c'
+ '11585844eb33ce997e55087dbec0610693bd79e3b1ffb02c9818214ce401a9fb')
+
+package() {
+ install -Dm644 install_tpm2 "${pkgdir}/usr/lib/initcpio/install/tpm2"
+ install -Dm644 hook_tpm2 "${pkgdir}/usr/lib/initcpio/hooks/tpm2"
+ install -Dm644 README.md "${pkgdir}/usr/share/doc/${pkgname}/README"
+}
diff --git a/README.md b/README.md
new file mode 100644
index 000000000000..5ad0e35d54e4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,64 @@
+mkinitcpio TPM2 hook
+====================
+
+This mkinitcpio hook allows for an encrypted root device to use a key sealed by
+a TPM 2.0. It should be placed immediately before the `encrypt` hook in
+`/etc/mkinitcpio.conf`.
+
+ HOOKS="base udev ... block tpm2 encrypt filesystems
+
+The `tpm2` hook attempts to "unseal" a LUKS keyfile previously sealed by the
+TPM. The sealed files must reside on an unencrypted filesystem available to the
+kernel at boot or may be stored in TPM non-volatile memory (NVRAM). For example,
+assuming your unencrypted keyfile is at `/root/mykey` and a primary TPM key has
+been persisted to `0x81000001`:
+
+ # tpm2_createpolicy -P -L sha1:0,2,4,7 -f pcr.pol -T device:/dev/tpmrm0
+ # tpm2_create -H 0x81000001 -g sha256 -G keyedhash -A 0x492 -I /root/mykey \
+ -L pcr.pol -r /boot/mykey.priv -u /boot/mykey.pub -T device:/dev/tpmrm0
+
+After generating a TPM-sealed key, both `tpmkey` and `tpmpcr` should be specified
+on the kernel command line.
+
+The `tpmkey` parameter has several formats:
+
+ tpmkey=[device]:[path]:[handle]
+ tpmkey=[device]:[publicpath]:[privatepath]:[handle]
+ tpmkey=nvram:[index]
+ tpmkey=nvram:[index]:[offset]:[size]
+
+Where `[device]` represents the raw block device on which the key exists,
+`[path]` is the absolute base path of the sealed files within the device, and
+`[handle]` is the TPM handle of the key's parent object. If only `[path]` is
+specified, '.pub' and '.priv' will be appended to the path to locate the public
+and private files, respectively. The absolute `[publicpath]` and `[privatepath]`
+can be specified separately if needed. For example, if `/dev/sda1` is an EFI
+partition mounted at `/boot`:
+
+ tpmkey=/dev/sda1:/mykey:0x81000001
+
+Setting `[device]` to 'nvram' indicates that the key is stored in TPM NVRAM. In
+this case `[index]` is the NVRAM area index, `[offset]` is the offset of the key
+in bytes and `[size]` is the size of the key in bytes.
+
+The `tpmpcr` parameter should hold the TPM2 PCR bank specification that will
+unlock the sealed key. Multiple specs can be separated by a '|' and key
+decryption will be attempted with each set of banks.
+
+You may also need to add the `vfat` file system driver to the `MODULES` array:
+
+ MODULES=(vfat)
+
+Finally, rebuild the initramfs:
+
+ # mkinitcpio -p linux
+
+During boot, the hook will initialize the TPM and attempt to unseal the key. If
+the key is successfully unsealed, it will be passed to the `encrypt` hook to
+perform the actual decryption of the root file system.
+
+Depending on the PCR banks to which the sealed key is bound, system changes such
+as kernel updates or firmware adjustments may prevent the key from being
+unsealed. If this happens, the disk must be manually unlocked with a passphrase
+and a new sealed key file needs to be generated. For this reason, it is CRUCIAL
+to add a separate "recovery" passphrase to the LUKS keys.
diff --git a/hook_tpm2 b/hook_tpm2
new file mode 100644
index 000000000000..a4c6b8f1d3a1
--- /dev/null
+++ b/hook_tpm2
@@ -0,0 +1,145 @@
+#!/usr/bin/ash
+
+run_hook() {
+ local ckeyfile tpmkeypub tpmkeypriv tpmkeyparent tpmkeyindex tpmkeyoffset tpmkeysize
+ local tkdev tkarg1 tkarg2 tkarg3 resolved
+ local tpmload pcrbank unseal unsealout tpmok
+
+ # This file will be loaded by the encrypt hook
+ ckeyfile="/crypto_keyfile.bin"
+
+ # Rootfs location for sealed key files
+ tpmkeypub="/tpm_keyfile.pub"
+ tpmkeypriv="/tpm_keyfile.priv"
+
+ # Default TPM device
+ [ -z $tpmdev ] && tpmdev="/dev/tpmrm0"
+
+ # Parse tpmkey command line argument
+ if [ -n "$tpmkey" ]; then
+ IFS=: read tkdev tkarg1 tkarg2 tkarg3 <<EOF
+$tpmkey
+EOF
+ unset IFS
+
+ case "$tkdev" in
+ rootfs)
+ # Key is in initcpio root filesystem. Use files in place
+ if [ -z "$tkarg3" ]; then
+ tpmkeypub="${tkarg1}.pub"
+ tpmkeypriv="${tkarg1}.priv"
+ tpmkeyparent="$tkarg2"
+ else
+ tpmkeypub="$tkarg1"
+ tpmkeypriv="$tkarg2"
+ tpmkeyparent="$tkarg3"
+ fi
+ ;;
+ nvram)
+ # Key is in NVRAM. Populate NVRAM variables
+ tpmkeyindex="$tkarg1"
+ tpmkeyoffset="$tkarg2"
+ tpmkeysize="$tkarg3"
+ ;;
+ *)
+ # Key is on block device
+ # Locate, mount, and copy the key files
+ if resolved=$(resolve_device "${tkdev}" ${rootdelay}); then
+ mkdir /tpmkey
+ mount -r -t auto "$resolved" /tpmkey
+
+ if [ -z "$tkarg3" ]; then
+ dd if="/tpmkey/${tkarg1}.pub" of="$tpmkeypub" >/dev/null 2>&1
+ dd if="/tpmkey/${tkarg1}.priv" of="$tpmkeypriv" >/dev/null 2>&1
+ tpmkeyparent="$tkarg2"
+ else
+ dd if="/tpmkey/${tkarg1}" of="$tpmkeypub" >/dev/null 2>&1
+ dd if="/tpmkey/${tkarg2}" of="$tpmkeypriv" >/dev/null 2>&1
+ tpmkeyparent="$tkarg3"
+ fi
+
+ umount /tpmkey
+ rmdir /tpmkey
+ fi
+ ;;
+ esac
+
+ # If there is no NVRAM index and no sealed files, print an error
+ if [ -z "$tpmkeyindex" ] && [ ! -f "$tpmkeypub" -o ! -f "$tpmkeypriv" ]; then
+ err "TPM keyfiles could not be opened"
+ fi
+ fi
+
+ # We must have a PCR list to retrieve a key
+ [ -n "$tpmkey" ] && [ -z "$tpmpcr" ] && err "TPM PCR bank not specified"
+
+
+ # If we have a key and PCR list, decrypt it
+ if [ -n "$tpmpcr" -a -n "$tpmkeyindex" ] || [ -n "$tpmpcr" -a -f "$tpmkeypub" -a -f "$tpmkeypriv" ]; then
+ # Load key object if stored on disk
+ tpmload=0
+ if [ -z "$tpmkeyindex" ]; then
+ tpm2_load -Q -H "$tpmkeyparent" -r "$tpmkeypriv" -u "$tpmkeypub" -C /tpmobject.ctx -T "device:${tpmdev}" 2>&1 >/dev/null
+ tpmload=$?
+ fi
+
+ # Format nvram arguments
+ [ -n "$tpmkeyoffset" ] && tpmkeyoffset="-o ${tpmkeyoffset}"
+ [ -n "$tpmkeysize" ] && tpmkeysize="-s ${tpmkeysize}"
+
+ # Attempt to decrypt key with each PCR bank specified
+ unseal=1
+ if [ $tpmload -eq 0 ]; then
+ IFS="|"
+ for pcrbank in $tpmpcr; do
+ if [ -n "$tpmkeyindex" ]; then
+ unsealout=$(tpm2_nvread -Q -x "$tpmkeyindex" -a "$tpmkeyindex" $tpmkeyoffset $tpmkeysize -L "$pcrbank" -f $ckeyfile -T "device:${tpmdev}" 2>&1)
+ unseal=$?
+ else
+ unsealout=$(tpm2_unseal -Q -c /tpmobject.ctx -L "$pcrbank" -o "$ckeyfile" -T "device:${tpmdev}" 2>&1)
+ unseal=$?
+ fi
+ if [ $unseal -eq 0 ]; then break; fi
+ done
+ unset IFS
+ fi
+
+ # Check decryption resuts and report
+ tpmok=0
+ if [ $unseal -eq 0 ]; then
+ tpmok=1
+ elif echo "$unsealout" | grep -sqiE 'Could not load tcti'; then
+ err "TPM communication error"
+ elif echo "$unsealout" | grep -sqiE 'Error.*0x99d'; then
+ echo
+ echo "!!! TPM WARNING: PCR VALUES HAVE CHANGED !!!"
+ echo "This is an indication that the boot configuration has been altered since"
+ echo "the TPM key was generated. This is normal after kernel updates or firmware"
+ echo "changes, however this could also indicate a malicious change to your system."
+ echo
+ elif [ -n "$tpmkeyindex" ]; then
+ err "Could not read key from TPM NVRAM"
+ elif [ $tpmload -ne 0 ]; then
+ err "Could not load TPM keyfile"
+ else
+ err "Could not unseal TPM keyfile"
+ fi
+
+ if [ $tpmok -gt 0 ]; then
+ msg ":: LUKS key successfully decrypted by TPM"
+ else
+ rm -f "$ckeyfile"
+ msg ":: TPM Could not decrypt LUKS key"
+ fi
+ fi
+
+ # Cleanup
+ rm -f /tpmobject.ctx "$tpmkeypub" "$tpmkeypriv"
+}
+
+run_cleanuphook() {
+ # Remove key if still present
+ rm -f "$ckeyfile"
+}
+
+# vim: set ft=sh ts=4 sw=4 et:
diff --git a/install_tpm2 b/install_tpm2
new file mode 100644
index 000000000000..5a153515d252
--- /dev/null
+++ b/install_tpm2
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+build() {
+ add_module "tpm_tis"
+ add_module "tpm_crb"
+
+ add_binary "/usr/bin/tpm2_unseal" "/usr/bin/tpm2_unseal"
+ add_binary "/usr/bin/tpm2_load" "/usr/bin/tpm2_load"
+ add_binary "/usr/bin/tpm2_nvread" "/usr/bin/tpm2_nvread"
+ add_binary "/usr/lib/libtss2-tcti-device.so.0"
+
+ add_runscript
+}
+
+
+help() {
+ cat <<HELPEOF
+This hook allows for an encrypted root device to use a key sealed by a
+TPM 2.0. It should be placed immediately before the 'encrypt' hook. After
+generating a TPM-sealed key, both 'tpmkey' and 'tpmpcr' should be
+specified on the kernel command line.
+
+'tpmkey' has several formats:
+
+ tpmkey=[device]:[path]:[handle]
+ tpmkey=[device]:[publicpath]:[privatepath]:[handle]
+ tpmkey=nvram:[index]
+ tpmkey=nvram:[index]:[offset]:[size]
+
+Where [device] represents the raw block device on which the key exists,
+[path] is the absolute base path of the keyfiles within the device, and
+[handle] is the TPM handle of the key's parent object. If only [path] is
+specified, '.pub' and '.priv' will be appended to the path to locate the
+public and private files, respectively. The absolute [publicpath] and
+[privatepath] can be specified separately if needed.
+
+Setting [device] to 'nvram' indicates that the key is stored in TPM NVRAM.
+In this case [index] is the NVRAM area index, [offset] is the offset of
+the key in bytes and [size] is the size of the key in bytes.
+
+'tpmpcr' should hold the TPM2 PCR bank specification that will unlock the
+sealed key. Multiple specs can be separated by a '|' and key decryption
+will be attempted with each set of banks.
+HELPEOF
+}
+
+# vim: set ft=sh ts=4 sw=4 et: