Skip to content

Commit

Permalink
Support for different NV perms; support for reading authless indexes
Browse files Browse the repository at this point in the history
Updated tpm-luks to allow any combination of NV perms and passing the
well known password. Also updated Fedora 17's dract scripts to allow
reading authless indexes.

Signed-off-by: Kent Yoder <key@linux.vnet.ibm.com>
  • Loading branch information
Kent Yoder committed Apr 15, 2013
1 parent a12cd82 commit d2527ca
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 25 deletions.
3 changes: 2 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ dist_plymouth_SCRIPTS=dracut/Fedora17/crypt-tpm/cryptroot-ask.sh \
dracut/Fedora17/crypt-tpm/module-setup.sh \
dracut/Fedora17/crypt-tpm/parse-crypt.sh \
dracut/Fedora17/crypt-tpm/parse-keydev.sh \
dracut/Fedora17/crypt-tpm/probe-keydev.sh
dracut/Fedora17/crypt-tpm/probe-keydev.sh \
dracut/Fedora17/crypt-tpm/tpm-try-authless-indexes.sh
endif

if RHEL6
Expand Down
17 changes: 5 additions & 12 deletions dracut/Fedora17/crypt-tpm/cryptroot-ask-tpm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ DEVICE=${1}
NAME=${2}
TPM_LUKS_MAX_NV_INDEX=128

#set -x
set -x

VIABLE_INDEXES=""

#
# An index is viable if its composite hash matches current PCR state, or if
# it doesn't require PCR state at all
#
#ALL_INDEXES=$($GETCAP -cap 0xd | ${AWK} -F "= " '$1 ~ /Index/ {print $2 }' | ${AWK} -F "." '{ print $1 }')
ALL_INDEXES=$($GETCAP -cap 0xd | ${AWK} -F: '$1 ~ /Index/ {print $2 }' | ${AWK} -F= '{ print $1 }')
for i in $ALL_INDEXES; do
MATCH1=$($GETCAP -cap 0x11 -scap $i | ${AWK} -F ": " '$1 ~ /Matches/ { print $2 }')
Expand Down Expand Up @@ -59,7 +58,6 @@ if [ ! -n "${NVPASS}" ]; then
fi

KEYFILE=${TMPFS_MNT}/key
SUCCESS=0

for NVINDEX in $VIABLE_INDEXES; do
NVSIZE=$($GETCAP -cap 0x11 -scap ${NVINDEX} | ${AWK} -F= '$1 ~ /dataSize/ { print $2 }')
Expand Down Expand Up @@ -93,15 +91,10 @@ for NVINDEX in $VIABLE_INDEXES; do
echo "Success."
${UMOUNT} ${TMPFS_MNT}

SUCCESS=1
break
exit 0
done

# NVRAM cannot be accessed. Fall back to LUKS passphrase
if [ ${SUCCESS} -eq 0 ]; then
echo "Unable to unlock an NVRAM area."
${UMOUNT} ${TMPFS_MNT}
exit 255
fi

exit 0
echo "Unable to unlock an NVRAM area."
${UMOUNT} ${TMPFS_MNT}
exit 255
9 changes: 6 additions & 3 deletions dracut/Fedora17/crypt-tpm/cryptroot-ask.sh
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,12 @@ else
fi

if [ $ask_passphrase -ne 0 ]; then
ask_for_password --tries 3 \
--cmd "cryptroot-ask-tpm $device $luksname" \
--prompt "TPM NVRAM Password ($device)"
tpm-try-authless-indexes $device $luksname
if [ $? -ne 0 ]; then
ask_for_password --tries 3 \
--cmd "cryptroot-ask-tpm $device $luksname" \
--prompt "TPM NVRAM Password ($device)"
fi

if [ $? -ne 0 ]; then
luks_open="$(command -v cryptsetup) luksOpen"
Expand Down
1 change: 1 addition & 0 deletions dracut/Fedora17/crypt-tpm/module-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ install() {
inst "$moddir/crypt-lib.sh" "/lib/dracut-crypt-lib.sh"
# tpm-luks dependencies
inst "$moddir"/cryptroot-ask-tpm.sh /sbin/cryptroot-ask-tpm
inst "$moddir"/tpm-try-authless-indexes.sh /sbin/tpm-try-authless-indexes
inst_binary getcapability
inst_binary awk
inst_binary od
Expand Down
93 changes: 93 additions & 0 deletions dracut/Fedora17/crypt-tpm/tpm-try-authless-indexes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/bin/sh
#
# package reqs: od, getcapability, nv_readvalue, dd
#
# Author: Kent Yoder <key@linux.vnet.ibm.com>
#
CRYPTSETUP=/sbin/cryptsetup
MOUNT=/bin/mount
UMOUNT=/bin/umount
TPM_NVREAD=/usr/bin/nv_readvalue
GETCAP=/usr/bin/getcapability
AWK=/bin/awk
DEVICE=${1}
NAME=${2}
TPM_LUKS_MAX_NV_INDEX=128
TPM_NV_PER_AUTHREAD=0x00040000
TPM_NV_PER_OWNERREAD=0x00020000
NOAUTH_INDEXES=""

#set -x

#
# An index is viable if its composite hash matches current PCR state, or if
# it doesn't require PCR state at all
#
#ALL_INDEXES=$($GETCAP -cap 0xd | ${AWK} -F "= " '$1 ~ /Index/ {print $2 }' | ${AWK} -F "." '{ print $1 }')
ALL_INDEXES=$($GETCAP -cap 0xd | ${AWK} -F: '$1 ~ /Index/ {print $2 }' | ${AWK} -F= '{ print $1 }')
for i in $ALL_INDEXES; do
MATCH1=$($GETCAP -cap 0x11 -scap $i | ${AWK} -F ": " '$1 ~ /Matches/ { print $2 }')
SIZE=$($GETCAP -cap 0x11 -scap $i | ${AWK} -F= '$1 ~ /dataSize/ { print $2 }')
AUTH_BITS=0x$($GETCAP -cap 0x11 -scap $i | ${AWK} '$1 ~ /Result/ { print $11 }')
if [ $i -gt ${TPM_LUKS_MAX_NV_INDEX} ]; then
continue
else
AUTHREAD=$(( ${AUTH_BITS} & ${TPM_NV_PER_AUTHREAD} ))
OWNERREAD=$(( ${AUTH_BITS} & ${TPM_NV_PER_OWNERREAD} ))

if [ ${AUTHREAD} -eq 0 -a ${OWNERREAD} -eq 0 ];then
NOAUTH_INDEXES="$i $NOAUTH_INDEXES"
echo "No auth index: $i"
continue
fi
fi
done

if [ -z "${NOAUTH_INDEXES}" ]; then
echo "No TPM authless indexes found"
exit 255
fi

TMPFS_MNT=/tmp/cryptroot-mnt
if [ ! -d ${TMPFS_MNT} ]; then
mkdir ${TMPFS_MNT} || exit -1
fi

$MOUNT -t tmpfs -o size=16K tmpfs ${TMPFS_MNT}
if [ $? -ne 0 ]; then
echo "Unable to mount tmpfs area to securely use TPM NVRAM data."
exit 255
fi

KEYFILE=${TMPFS_MNT}/key

for NVINDEX in $NOAUTH_INDEXES; do
NVSIZE=$($GETCAP -cap 0x11 -scap ${NVINDEX} | ${AWK} -F= '$1 ~ /dataSize/ { print $2 }')

$TPM_NVREAD -ix ${NVINDEX} -sz ${NVSIZE} -of ${KEYFILE} >/dev/null 2>&1
RC=$?
if [ ${RC} -ne 0 ]; then
echo "No auth TPM NV index ${NVINDEX}: error (${RC})"
continue
fi

echo "Trying data read from NV index $NVINDEX"
$CRYPTSETUP luksOpen ${DEVICE} ${NAME} --key-file ${KEYFILE} --keyfile-size ${NVSIZE}
RC=$?
# Zeroize keyfile regardless of success/fail
dd if=/dev/zero of=${KEYFILE} bs=1c count=${NVSIZE} >/dev/null 2>&1
if [ ${RC} -ne 0 ]; then
echo "Cryptsetup failed, trying next index..."
continue
fi
echo "Success."
${UMOUNT} ${TMPFS_MNT}

exit 0
done

# NVRAM cannot be accessed. Fall back to LUKS passphrase
echo "Unable to unlock an NVRAM area."
${UMOUNT} ${TMPFS_MNT}
exit 255

82 changes: 73 additions & 9 deletions tpm-luks/tpm-luks
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#!/bin/bash -e
#!/bin/bash
#
# package reqs: tpm-tools, trousers
#
# Author: Kent Yoder <key@linux.vnet.ibm.com>
#
set -x

AWK=/bin/awk
CRYPTSETUP=/sbin/cryptsetup
TPM_LUKS_NV_INDEX_LIMIT=128
Expand All @@ -16,9 +18,26 @@ OWNERPASS=
NVPASS=
KEY_SLOT=
RAND_SOURCE="/dev/urandom"
RW_PERMS="AUTHREAD|AUTHWRITE"
#
# Do we need a password at tpm_nvdefine time (other than owner)? 1=false, 0=true
#
DEFINE_PASS=1
#
# Do we need a password at tpm_nvwrite time? 1=false, 0=true
#
WRITE_PASS=1
#
# Do we have an owner authorized write? 1=false, 0=true
#
OWNER_WRITE=1

function prompt_for_new_nvpass
{
if [ ${DEFINE_PASS} -eq 1 -a ${WRITE_PASS} -eq 1 ]; then
return
fi

if [ ! -n "${NVPASS}" ]; then
read -s -p "Enter a new TPM NV area password: " NVPASS1
echo
Expand All @@ -44,6 +63,7 @@ function get_nv_password

function get_owner_password
{
# XXX this is the same as -z? TEST
if [ ! -n "${OWNERPASS}" ]; then
read -s -p "Enter your TPM owner password: " OWNERPASS || exit 3
echo
Expand Down Expand Up @@ -171,28 +191,51 @@ function nv_define_and_write
{
PERMSFILE=${1}
DATAFILE=${TMPFS_KEYFILE}
NVPASS_OPTION=
OWNERPASS_OPTION="-y"
WRITEPASS_OPTION=

get_owner_password

if [ ! -n "${NVINDEX}" ]; then
NVINDEX=$(find_free_nv_index)
fi

if [ ! -z "${NVPASS}" ]; then
NVPASS_OPTION="-a ${NVPASS}"
fi

if [ "${OWNERPASS}" != "-y" ]; then
OWNERPASS_OPTION="-o ${OWNERPASS}"
fi

if [ -n "${PERMSFILE}" ]; then
tpm_nvdefine -i ${NVINDEX} -s ${KEYFILE_SIZE} -p 'AUTHREAD|AUTHWRITE' -o ${OWNERPASS} \
-a ${NVPASS} -f ${PERMSFILE} >/dev/null
tpm_nvdefine -i ${NVINDEX} -s ${KEYFILE_SIZE} -p ${RW_PERMS} \
${OWNERPASS_OPTION} ${NVPASS_OPTION} -f ${PERMSFILE} >/dev/null
else
tpm_nvdefine -i ${NVINDEX} -s ${KEYFILE_SIZE} -p 'AUTHREAD|AUTHWRITE' -o ${OWNERPASS} \
-a ${NVPASS} >/dev/null
tpm_nvdefine -i ${NVINDEX} -s ${KEYFILE_SIZE} -p ${RW_PERMS} \
${OWNERPASS_OPTION} ${NVPASS_OPTION} >/dev/null
fi

if [ $? -ne 0 ]; then
return 15
fi

tpm_nvwrite -i ${NVINDEX} -s ${KEYFILE_SIZE} -f ${DATAFILE} --password=${NVPASS}
# if there's a password required for writing the NV area, determine if its the
# owner password, or the NV area password
if [ ${OWNER_WRITE} -eq 0 ]; then
if [ "${OWNERPASS}" == "-y" ]; then
WRITEPASS_OPTION="-z"
else
WRITEPASS_OPTION="--password=${OWNERPASS}"
fi
elif [ ${WRITE_PASS} -eq 0 ]; then
WRITEPASS_OPTION="--password=${NVPASS}"
fi

tpm_nvwrite -i ${NVINDEX} -s ${KEYFILE_SIZE} -f ${DATAFILE} ${WRITEPASS_OPTION}
if [ $? -ne 0 ]; then
tpm_nvrelease -i ${NVINDEX} --pwdo=${OWNERPASS}
tpm_nvrelease -i ${NVINDEX} ${OWNERPASS_OPTION}
return 16
fi

Expand Down Expand Up @@ -302,9 +345,16 @@ function usage
echo -e " indexes with tpm_nvinfo)"
echo -e " -d <device> use the specified LUKS device (view with "
echo -e " 'blkid -t TYPE=crypto_LUKS')"
echo -e " -p <nvpermsfile> use the specified NV permissions file for the new area"
echo -e " -p <nvpermsfile> use the specified NV permissions file for the new area. This"
echo -e " is the same file you'd pass to tpm_nvdefine -f"
echo -e " -P <r/w perms> use the specified NV read/write permissions for the new area."
echo -e " Pass the same set of options as you'd pass to tpm_nvdefine -p"
echo -e " default is AUTHREAD|AUTHWRITE"
echo -e " -q <file> use the specified file for the key material source, default"
echo -e " is /dev/urandom"
echo -e " -y use the well known secret (all zeroes) as the owner password."
echo -e " This will apply both to the NV define and NV write operations"
echo -e " if they apply."
echo -e " -h help"
}

Expand All @@ -315,7 +365,7 @@ KEYFILE_SIZE=32
NVINDEX=
ACTION="x"

while getopts "kco:mrw:l:s:i:d:p:q:h" opt; do
while getopts "kco:mrw:l:s:i:d:p:P:q:yh" opt; do
case $opt in
k)
[[ "${ACTION}" == "x" ]] && ACTION="kill" || (usage && exit 255)
Expand Down Expand Up @@ -357,9 +407,15 @@ while getopts "kco:mrw:l:s:i:d:p:q:h" opt; do
exit 21
fi
;;
P)
RW_PERMS=${OPTARG}
;;
q)
RAND_SOURCE=${OPTARG}
;;
y)
OWNERPASS="-y"
;;
*)
usage
exit 255
Expand All @@ -371,6 +427,14 @@ done
tpm_enabled
tpm_owned

# handle the passwords we need to gather
echo ${RW_PERMS} | grep -qi AUTH
DEFINE_PASS=$?
echo ${RW_PERMS} | grep -qi AUTHWRITE
WRITE_PASS=$?
echo ${RW_PERMS} | grep -qi OWNER
OWNER_WRITE=$?

if [ "${ACTION}" == "create" ]; then
device_get
prompt_for_new_nvpass
Expand Down

0 comments on commit d2527ca

Please sign in to comment.