You are not logged in.

#1 2018-06-02 17:47:11

Mog
Member
Registered: 2018-06-02
Posts: 2

Problem setting up automatic partition decryption using TPM 2.0

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

seal-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"
fi

unseal-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_handle

All 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

#2 2018-07-21 09:54:27

diabonas
Package Maintainer (PM)
Registered: 2018-07-21
Posts: 7

Re: Problem setting up automatic partition decryption using TPM 2.0

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

As 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

#3 2018-09-19 20:53:47

haimiko
Member
Registered: 2018-09-19
Posts: 4

Re: Problem setting up automatic partition decryption using TPM 2.0

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

#4 2018-09-19 21:25:36

diabonas
Package Maintainer (PM)
Registered: 2018-07-21
Posts: 7

Re: Problem setting up automatic partition decryption using TPM 2.0

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 handle

The 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

#5 2018-09-19 22:33:09

haimiko
Member
Registered: 2018-09-19
Posts: 4

Re: Problem setting up automatic partition decryption using TPM 2.0

Thank you!

Offline

#6 2018-09-20 21:22:31

haimiko
Member
Registered: 2018-09-19
Posts: 4

Re: Problem setting up automatic partition decryption using TPM 2.0

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_handle

and 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 1

Last edited by haimiko (2018-09-20 21:41:01)

Offline

#7 2018-10-31 11:12:39

diabonas
Package Maintainer (PM)
Registered: 2018-07-21
Posts: 7

Re: Problem setting up automatic partition decryption using TPM 2.0

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) wink

Offline

#8 2018-10-31 13:29:33

haimiko
Member
Registered: 2018-09-19
Posts: 4

Re: Problem setting up automatic partition decryption using TPM 2.0

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

#9 2018-10-31 14:54:14

diabonas
Package Maintainer (PM)
Registered: 2018-07-21
Posts: 7

Re: Problem setting up automatic partition decryption using TPM 2.0

A cool, I didn't know that one smile Glad you got it working!

Offline

Board footer

Powered by FluxBB