You are not logged in.
Hello everyone !
I am currently trying to set up my computer so that it use a tpm module (2.0) to decrypt my root partition.
Here is my current setup :
/dev/sda1 -> EFI partition mounted on /boot
/dev/sda2 -> btrfs encrypted partition mounted on /
|--- -> /dev/mapper/luks container
What I've read on https://wiki.archlinux.org/index.php/Tr … orm_Module is that TPM 2.0 is not officially supported. So I've done a bit of research to find out how/if it is possible to use the module to automagically decrypt the /dev/sda2 partition at boot time so that I don't have to enter 2 different passwords. The goal is that the disk is encrypted so it cannot be read by removing it from the case / using kali / etc but it doesn't need user input, like bitlocker does on windows. The EFI is currently signed and secure boot is active.
I have found how to use the TPM module to seal and unseal a key following these instructions : https://robertou.com/tpm2-sealed-luks-e … -keys.html
I had to slightly alter the bash scripts to make it work. I used the documentation and the latest release of https://sourceforge.net/projects/ibmtpm20tss/ to seal and unseal a password using the TPM module.
The edited scripts I use for sealing and unsealing are:
new-disk-key.sh
#!/bin/sh
TOOLSDIR="./"
DISK="/dev/disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
TPM_SLOT="0"
tmpdir=tmp
umask 0077
# Make a new key
dd if=/dev/urandom of="$tmpdir/newkey.bin" bs=1 count=32
# Kill the existing key
echo "Removing old key..."
sudo cryptsetup luksKillSlot "$DISK" "TPM_SLOT" -d /root/keys/rootkey.bin
# Seal the new key to the TPM
echo "Sealing key to TPM..."
"$TOOLSDIR/seal-to-pcrs.sh" "$tmpdir/newkey.bin" "$TOOLSDIR/sealedkey_priv.bin" "$TOOLSDIR/sealedkey_pub.bin"
# Add the key to LUKS
echo "Adding key..."
sudo cryptsetup luksAddKey "$DISK" "$tmpdir/newkey.bin" -d /root/keys/rootkey.binseal-to-pcrs.sh
#!/bin/sh
# args are: input priv pub
# KEEP IN SYNC!
PCRS="0 2 4 7"
PCR_BITS="95"
TOOLSDIR="./"
tmpdir=tmp
export TPM_INTERFACE_TYPE=dev
export TPM_SESSION_ENCKEY=`./getrandom -by 16 -ns`
# Read PCRs
for pcr in $PCRS
do
"$TOOLSDIR/pcrread" -ns -ha $pcr >>"$tmpdir/pcrs.txt"
done
# Make text policy file
"$TOOLSDIR/policymakerpcr" -bm $PCR_BITS -if "$tmpdir/pcrs.txt" -of "$tmpdir/pcr-policy.txt"
# Make binary policy file
"$TOOLSDIR/policymaker" -if "$tmpdir/pcr-policy.txt" -of "$tmpdir/pcr-policy.bin"
# Seal the actual file
"$TOOLSDIR/create" -hp 81000001 -bl -kt p -kt f -pol "$tmpdir/pcr-policy.bin" -if "$1" -opr "$2" -opu "$3"unseal-disk-key.sh
#!/bin/sh
TOOLSDIR="/opt/tpmdisk"
disk_key=$("$TOOLSDIR/unseal-from-pcrs.sh" "$TOOLSDIR/sealedkey_priv.bin" "$TOOLSDIR/sealedkey_pub.bin" /dev/stdout)
if [ $? -ne 0 ]
then
exec systemd-ask-password "Enter disk recovery key: "
else
echo -n "$disk_key"
fiunseal-from-pcrs.sh
#!/bin/sh
# args are: priv pub output
# KEEP IN SYNC!
PCRS="0 2 4 7"
PCR_BITS="95"
TOOLSDIR="/opt/tpmdisk"
export TPM_INTERFACE_TYPE=dev
export TPM_SESSION_ENCKEY=`./getrandom -by 16 -ns`
# Load the keys
load_key=$("$TOOLSDIR/load" -hp 81000001 -ipr "$1" -ipu "$2")
if [ $? -ne 0 ]
then
>&2 echo "Load command failed!"
>&2 echo "$load_key"
exit 1
fi
key_handle=${load_key#*Handle }
# Start auth session
start_auth=$("$TOOLSDIR/startauthsession" -se p)
if [ $? -ne 0 ]
then
>&2 echo "Start auth session failed!"
>&2 echo "$start_auth"
"$TOOLSDIR/flushcontext" -ha $key_handle
exit 1
fi
sess_handle=${start_auth#*Handle }
# Run policypcr
"$TOOLSDIR/policypcr" -ha $sess_handle -bm $PCR_BITS
# Unseal
"$TOOLSDIR/unseal" -ha $key_handle -se0 $sess_handle 0 -of "$3"
if [ $? -ne 0 ]
then
>&2 echo "Unsealing failed!"
"$TOOLSDIR/flushcontext" -ha $key_handle
"$TOOLSDIR/flushcontext" -ha $sess_handle
exit 1
fi
# Flush temporary
"$TOOLSDIR/flushcontext" -ha $key_handleAll of this work properly, as when I am running unseal-disk-key.sh, I am getting the same key that is inside newkey.bin.
Now, the tough part : I have no idea on how I can use the script unseal-disk-key.sh on boot to automatically decrypt my luks partition.
Here is what I tried :
I've read on https://wiki.archlinux.org/index.php/mkinitcpio#HOOKS on how to create a custom hook and created a hook for mkinitcpio at this location : /etc/initcpio/install/tpm-decrypt
The hook contains this code :
#!/bin/bash
build() {
add_binary "/opt/tpmdisk/flushcontext"
add_binary "/opt/tpmdisk/load"
add_binary "/opt/tpmdisk/getrandom"
add_binary "/opt/tpmdisk/policypcr"
add_binary "/opt/tpmdisk/startauthsession"
add_binary "/opt/tpmdisk/unseal"
add_file "/opt/tpmdisk/unseal-disk-key.sh"
add_file "/opt/tpmdisk/unseal-from-pcrs.sh"
add_file "/opt/tpmdisk/sealedkey_priv.bin"
add_file "/opt/tpmdisk/sealedkey_pub.bin"
}
help() {
cat <<HELPEOF
This hook allows for decrypting /dev/sda2 using the TPM.
HELPEOF
}I also edited mkinitcpio.conf and added the hook like this:
HOOKS=(base systemd autodetect keyboard sd-vconsole tpm-decrypt modconf block sd-encrypt filesystems)I then edited my cmdline used when I boot the system to this:
/etc/default/sbupdate
CMDLINE_DEFAULT="root=/dev/sda2 rw nvidia-drm.modeset=1 luks.uuid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx root=UUID=yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy nowatchdog splash luks.keyscript=/opt/tpmdisk/unseal-disk-key.sh"And.... of course it did nothing. I am requesting your help on how to do this. That would be really appreciated ! Please take notice that I am still a begginer with all of this, 2 weeks ago I had never even touched linux before.
Offline
I think you are on the right track here, but the syntax of your kernel command line seems to be slightly wrong: luks.keyscript is not a valid parameter, see the man page of systemd-cryptsetup-generator, instead it should be
luks.options=keyscript=/opt/tpmdisk/unseal-disk-key.shAs an alternative, consider setting up /etc/crypttab.initramfs as described in the wiki and remove all LUKS-related parameters from the kernel command line.
Offline
How did you generate sealedkey_priv.bin & sealedkey_pub.bin ?
When the seal-to-pcr.sh runs, the create command returns this error:
create: failed, rc 0000018b
TPM_RC_HANDLE - the handle is not correct for the use Handle number 1
Any suggestions?
Last edited by haimiko (2018-09-19 21:07:42)
Offline
That error sounds like you did not create the primary key before running seal-to-pcr.sh, as described in the instructional blog post: "After compiling, I followed James Bottomley's instructions for creating a 81000001 key handle" (link added by me). So you need to do something like
tsscreateprimary -hi o -st -rsa # create a new primary key at the transient handle 80000000
tssevictcontrol -hi o -ho 80000000 -hp 81000001 # save this key to the persistent handle 81000001
tssflushcontext -ha 80000000 # free the transient handleThe transient handle can vary (the first free one is taken, which can be different if you have created other transient objects in this TPM session), so you have to pay attention to the output of tsscreateprimary and adapt the handle if necessary.
Offline
Thank you!
Offline
Got past that error but now encountering a new error during the unseal.
unseal: failed, rc 0000099d
TPM_RC_POLICY_FAIL - a policy check failed Session number 1
This is the test script I'm using to seal and test unsealing.
#!/bin/sh -x
PCRS="0 2 4 7"
PCR_BITS="95"
TOOLSDIR="/root/tools/tpm2tools"
export PATH=$PATH:$TOOLSDIR
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TOOLSDIR
export TPM_INTERFACE_TYPE="dev"
export TPM_SESSION_ENCKEY=`./getrandom -by 16 -ns`
tmpdir=/tmp
umask 0077
## evict old keys
evictcontrol -hi o -ho 81000001 -hp 81000001 > /dev/null 2>&1
##
createprimary -hi o -st -rsa
evictcontrol -hi o -ho 80000000 -hp 81000001
cp hp80000000.bin sealedkey_priv.bin
cp h80000000.bin sealedkey_pub.bin
# Make a new key
echo "SUPER SECRET KEY!!" > "$tmpdir/newkey.bin"
# Read PCRs
for pcr in $PCRS
do
"$TOOLSDIR/pcrread" -ns -ha $pcr >>"$tmpdir/pcrs.txt"
done
# Make text policy file
"$TOOLSDIR/policymakerpcr" -v -bm $PCR_BITS -if "$tmpdir/pcrs.txt" -of "$tmpdir/pcr-policy.txt" >/dev/null 2>&1
# Make binary policy file
"$TOOLSDIR/policymaker" -if "$tmpdir/pcr-policy.txt" -of "$tmpdir/pcr-policy.bin"
# Seal the actual file
"$TOOLSDIR/create" -hp 81000001 -bl -kt p -kt f -pol "$tmpdir/pcr-policy.bin" -if "$tmpdir/newkey.bin" -opr "$TOOLSDIR/sealedkey_priv.bin" -opu "$TOOLSDIR/sealedkey_pub.bin"
flushcontext -ha 80000000
## unsealing
echo "Unsealing key"
load_key=$("$TOOLSDIR/load" -hp 81000001 -ipr "$TOOLSDIR/sealedkey_priv.bin" -ipu "$TOOLSDIR/sealedkey_pub.bin")
if [ $? -ne 0 ]
then
>&2 echo "Load command failed!"
>&2 echo "$load_key"
exit 1
fi
key_handle=${load_key#*Handle }
# Start auth session
start_auth=$("$TOOLSDIR/startauthsession" -se p)
if [ $? -ne 0 ]
then
>&2 echo "Start auth session failed!"
>&2 echo "$start_auth"
"$TOOLSDIR/flushcontext" -ha $key_handle
exit 1
fi
sess_handle=${start_auth#*Handle }
# Run policypcr
"$TOOLSDIR/policypcr" -ha $sess_handle -bm $PCR_BITS
# Unseal
"$TOOLSDIR/unseal" -ha $key_handle -se0 $sess_handle 0 -of "/dev/stdout"
if [ $? -ne 0 ]
then
>&2 echo "Unsealing failed!"
"$TOOLSDIR/flushcontext" -ha $key_handle
"$TOOLSDIR/flushcontext" -ha $sess_handle
exit 1
fi
# Flush temporary
"$TOOLSDIR/flushcontext" -ha $key_handleand here is the verbose output from the script above:
+ PCRS=0 2 4 7
+ PCR_BITS=95
+ TOOLSDIR=/root/tools/tpm2tools
+ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/root/tools/tpm2tools:/root/tools/tpm2tools
+ export LD_LIBRARY_PATH=:/usr/local/lib:/root/tools/tpm2tools:/root/tools/tpm2tools
+ export TPM_INTERFACE_TYPE=dev
+ ./getrandom -by 16 -ns
+ export TPM_SESSION_ENCKEY=a7bba880a2efca56e71b96d4852686f2
+ tmpdir=/tmp
+ umask 0077
+ evictcontrol -hi o -ho 81000001 -hp 81000001
+ createprimary -hi o -st -rsa
Handle 80000000
+ evictcontrol -hi o -ho 80000000 -hp 81000001
+ cp hp80000000.bin sealedkey_priv.bin
+ cp h80000000.bin sealedkey_pub.bin
+ echo SECRET KEY!!
+ /root/tools/tpm2tools/pcrread -ns -ha 0
+ /root/tools/tpm2tools/pcrread -ns -ha 2
+ /root/tools/tpm2tools/pcrread -ns -ha 4
+ /root/tools/tpm2tools/pcrread -ns -ha 7
+ /root/tools/tpm2tools/policymakerpcr -v -bm 95 -if /tmp/pcrs.txt -of /tmp/pcr-policy.txt
+ /root/tools/tpm2tools/policymaker -if /tmp/pcr-policy.txt -of /tmp/pcr-policy.bin
+ /root/tools/tpm2tools/create -hp 81000001 -bl -kt p -kt f -pol /tmp/pcr-policy.bin -if /tmp/newkey.bin -opr /root/tools/tpm2tools/sealedkey_priv.bin -opu /root/tools/tpm2tools/sealedkey_pub.bin
+ flushcontext -ha 80000000
+ echo Unsealing key
Unsealing key
+ /root/tools/tpm2tools/load -hp 81000001 -ipr /root/tools/tpm2tools/sealedkey_priv.bin -ipu /root/tools/tpm2tools/sealedkey_pub.bin
+ load_key=Handle 80000001
+ [ 0 -ne 0 ]
+ key_handle=80000001
+ /root/tools/tpm2tools/startauthsession -se p
+ start_auth=Handle 03000000
+ [ 0 -ne 0 ]
+ sess_handle=03000000
+ /root/tools/tpm2tools/policypcr -ha 03000000 -bm 95
+ /root/tools/tpm2tools/unseal -ha 80000001 -se0 03000000 0 -of /dev/stdout
unseal: failed, rc 0000099d
TPM_RC_POLICY_FAIL - a policy check failed Session number 1
+ [ 1 -ne 0 ]
+ echo Unsealing failed!
Unsealing failed!
+ /root/tools/tpm2tools/flushcontext -ha 80000001
+ /root/tools/tpm2tools/flushcontext -ha 03000000
+ exit 1Last edited by haimiko (2018-09-20 21:41:01)
Offline
Sorry, I somehow did not receive a notification for your last post... The script should be correct and works on my machine. It is however a bit fragile: the first time it is run is successful, while subsequent runs fail with the error message you provided. This is because the file "$tmpdir/pcrs.txt" is only ever appended to in the "Read PCRs" section, but never deleted. This works well the first time when the file does not yet exist. The second and every following time, the file contains the PCR values from the current and all previous runs, which leads to the creation of a policy that does not match the current state of the TPM, which naturally is then unable to unlock the key. I suspect this is what happened during your tests. Please try deleting the file "$tmpdir/pcrs.txt" manually (or adding something like rm "$tmpdir/pcrs.txt" directly before the for loop) and rerunning the script.
BTW, there is an AUR package mkinitcpio-tpm2-encrypt that provides a mkinitcpio hook for unlocking LUKS volumes using a TPM during boot. I have not used it personally, so cannot vouch for its correctness, but the code looks fine. It is based on tpm2-tss and tpm2-tools instead of ibm-tss like the scripts in this thread. Personally, I find these a lot easier to work with because the tools are a bit more "high level" in that they have clearer named and documented arguments and generally do more things automatically instead of explicitly having them to specify as options. Full disclaimer: I am the current maintainer of tpm2-tss and tpm2-tools (but not mkinitcpio-tpm2-encrypt) ![]()
Offline
Thanks diabonas. I ended up giving up on this solution. I could not get it to work. I found that cryptsetup with builtin TPM support (https://github.com/AndreasFuchsSIT/cryp … -incubator) worked after some tweaking, although it was a pain to compile.
Offline
A cool, I didn't know that one
Glad you got it working!
Offline