[PATCH] Enable partman-crypto to work with keys on removable devices
Hi all,
after a long hiatus I decided to do some d-i hacking again.
The attached path allows setting up a crypto device with a keyfile
stored on another partition (mainly useful when that partition is on a
usbkey).
In the "setup encrypted volumes" stage of partman, the user will be
given a list of partitions known to partman and after selecting one, a
path must be entered. If that file already exists on the device, it will
be used as the keyfile, otherwise a new keyfile will be created.
I've done a test install using qemu (with a secondary qemu harddisk as
the removable device) and a SVN version of cryptsetup (which has the
necessary "mountdev" keyscript). Also, due to a bug in klibc, only ext3
is supported for now (bug reported, will be fixed before the next upload
of cryptsetup which will allow any common fs to be used).
My d-i knowledge is rusty so a review of the patch would be much
appreciated. (I've also been out of the loop wrt. d-i development,
deadlines for the next release, etc...so I have no idea how suitable
this patch is right now in the bigger picture)
I'm also planning to use some of the infrastructure of the patch to add
support for two-factor keys (ask a passphrase, hash it, get a keyfile
from usb stick, xor the two together, use that as the key) and
smartcards (I've already ordered the hardware, dunno when I'll get it).
Cheers :)
--
David Härdeman
Index: debian/partman-crypto.templates
===================================================================
--- debian/partman-crypto.templates (revision 53290)
+++ debian/partman-crypto.templates (working copy)
@@ -269,8 +269,8 @@
Type: text
# :sl3:
# This is a key type for encrypted file systems
-# It can be either protected by a passphrase, a keyfile
-# of a random key
+# It can be either protected by a passphrase, a keyfile,
+# a random key or a file stored on a removable device
# This text is one of these choices, so keep it short
_Description: Passphrase
@@ -278,8 +278,8 @@
Type: text
# :sl3:
# This is a key type for encrypted file systems
-# It can be either protected by a passphrase, a keyfile
-# of a random key
+# It can be either protected by a passphrase, a keyfile,
+# a random key or a file stored on a removable device
# This text is one of these choices, so keep it short
_Description: Keyfile (GnuPG)
@@ -287,11 +287,20 @@
Type: text
# :sl3:
# This is a key type for encrypted file systems
-# It can be either protected by a passphrase, a keyfile
-# of a random key
+# It can be either protected by a passphrase, a keyfile,
+# a random key or a file stored on a removable device
# This text is one of these choices, so keep it short
_Description: Random key
+Template: partman-crypto/text/keytype/removabledev
+Type: text
+# :sl3:
+# This is a key type for encrypted file systems
+# It can be either protected by a passphrase, a keyfile,
+# a random key or a file stored on a removable device
+# This text is one of these choices, so keep it short
+_Description: File on a removable device
+
Template: partman-crypto/unsafe_swap
Type: error
# :sl3:
@@ -369,6 +378,37 @@
_Description: Keyfile creation failure
An error occurred while creating the keyfile.
+Template: partman-crypto/removable-source-partition
+Type: select
+Choices: ${CHOICES}
+# :sl3:
+_Description: Crypto key partition:
+ Please choose the partition which contains the key you wish to use or where
+ a key should be created.
+
+Template: partman-crypto/removable-source-path
+Type: string
+# :sl3:
+_Description: Path to crypto key:
+ Please enter the path (relative to the root of ${DEVICE}) where the key you
+ wish to use is stored or where a key should be created.
+
+Template: partman-crypto/removable-confirm-create
+Type: boolean
+Default: false
+# :sl3:
+_Description: Create new key?
+ No key was found on ${DEVICE} at path ${PATH}, do you wish to create
+ a new key?
+
+Template: partman-crypto/removable-bad-keyfile
+Type: error
+# :sl3:
+_Description: Invalid encryption key
+ You have selected a pre-existing key file which is not suitable as a
+ crypto key as it is not large enough. Please try using a different
+ key file.
+
Template: partman-crypto/crypto_root_needs_boot
Type: error
# :sl3:
Index: ciphers/dm-crypt/keytype
===================================================================
--- ciphers/dm-crypt/keytype (revision 53290)
+++ ciphers/dm-crypt/keytype (working copy)
@@ -1 +1 @@
-passphrase random
+passphrase random removabledev
Index: finish.d/crypto_config
===================================================================
--- finish.d/crypto_config (revision 53290)
+++ finish.d/crypto_config (working copy)
@@ -96,6 +96,27 @@
keyfile="/dev/urandom"
elif [ $keytype = passphrase ]; then
keyfile="none"
+ elif [ $keytype = removabledev ]; then
+ local keydev keypath udevlinks tmp
+ keypath=$(cat $realdevdir/keypath)
+ keydev=$(cat $realdevdir/keydev)
+
+ # We need to use stable device names as using e.g. /dev/hda2
+ # will break the boot if a second USB key is present.
+ udevlinks=""
+ for tmp in by-id by-uuid by-label by-path; do
+ if [ -d "/dev/disk/$tmp" ]; then
+ udevlinks="$udevlinks /dev/disk/$tmp/*"
+ fi
+ done
+ for tmp in $udevlinks; do
+ if [ "$(readlink -f "$tmp")" = "$keydev" ]; then
+ keydev="$tmp"
+ break;
+ fi
+ done
+ keyfile="$keydev:$keypath"
+ opts="$opts,keyscript=mountdev"
elif [ -f $realdevdir/keyfile ]; then
keyfile=$(cat $realdevdir/keyfile)
else
Index: lib/crypto-base.sh
===================================================================
--- lib/crypto-base.sh (revision 53290)
+++ lib/crypto-base.sh (working copy)
@@ -219,6 +219,8 @@
setup_luks $cryptdev $realdev $cipher $ivalgorithm $keysize $keyfile || return 1
elif [ $keytype = random ]; then
setup_dmcrypt $cryptdev $realdev $cipher $ivalgorithm plain $keysize /dev/urandom || return 1
+ elif [ $keytype = removabledev ]; then
+ setup_dmcrypt $cryptdev $realdev $cipher $ivalgorithm plain $keysize $keyfile || return 1
else
setup_dmcrypt $cryptdev $realdev $cipher $ivalgorithm $keyhash $keysize $keyfile || return 1
fi
@@ -548,6 +550,8 @@
[ -d $part ] || return 1
+ rm -f $part/keydev
+ rm -f $part/keypath
case $type in
dm-crypt)
echo aes > $part/cipher
@@ -795,8 +799,12 @@
type=$(cat $id/crypto_type)
keytype=$(cat $id/keytype)
cipher=$(cat $id/cipher)
+ keysize=""
+ [ -f $id/keysize ] && keysize=$(cat $id/keysize)
- if [ $keytype = keyfile ] || [ $keytype = passphrase ]; then
+ if [ $keytype = keyfile ] || \
+ [ $keytype = passphrase ] || \
+ [ $keytype = removabledev ]; then
keyfile=$(mapdevfs $path | tr / _)
keyfile="$dev/$id/${keyfile#_dev_}"
if [ $type = loop-AES ]; then
@@ -804,7 +812,7 @@
fi
if [ ! -f $keyfile ]; then
- if ! /bin/blockdev-keygen "$(humandev $path)" "$keytype" "$keyfile"; then
+ if ! /bin/blockdev-keygen "$(humandev $path)" "$keytype" "$keyfile" "$keysize"; then
db_fset partman-crypto/commit_failed seen false
db_input critical partman-crypto/commit_failed
db_go || true
Index: blockdev-keygen
===================================================================
--- blockdev-keygen (revision 53290)
+++ blockdev-keygen (working copy)
@@ -192,6 +192,110 @@
return 0
}
+# Create or load an already created keyfile on a user-specified device
+create_removable_keyfile() {
+ local keyfile keybytes noninteractive source_dev source_id path mountpoint
+ keyfile=$1
+ keybytes=$2
+ noninteractive=true
+
+ . /lib/partman/lib/base.sh
+
+ while true; do
+ source_dev=''
+ source_id=''
+ while [ ! "$source_id" ]; do
+ choices=$(partition_tree_choices)
+ debconf_select critical partman-crypto/removable-source-partition "$choices" blah
+
+ case $? in
+ 1)
+ $noninteractive
+ ;;
+ 255)
+ return 1
+ ;;
+ esac
+ noninteractive='return 1'
+ source_dev=${RET%//*}
+ source_id=${RET#*//}
+ done
+ source_dev=${source_dev##*/}
+
+ cd "$DEVICES/$source_dev" || return 1
+
+ local x1 x2 x3 x4 x5 device x6
+ open_dialog PARTITION_INFO "$source_id"
+ read_line x1 x2 x3 x4 x5 device x6
+ close_dialog
+
+ if [ -z "$device" ]; then
+ return 1
+ fi
+
+ defpath="/keys/$(cat /etc/hostname)$(echo "$device" | sed 's/\//_/g')"
+ db_set partman-crypto/removable-source-path "$defpath"
+ db_subst partman-crypto/removable-source-path DEVICE "$(humandev $device)"
+ db_input critical partman-crypto/removable-source-path || true
+ db_go || return 1
+ db_get partman-crypto/removable-source-path
+ path="$RET"
+
+ if [ -z "$path" ]; then
+ continue;
+ fi
+
+ mountpoint="/tmp/blockdev-keygen-tmpmount"
+ if [ ! -e "/tmp/blockdev-keygen-tmpmount" ]; then
+ mkdir "$mountpoint" || return 1
+ fi
+
+ if ! log-output -t blockdev-keygen \
+ mount "$device" "$mountpoint" > /dev/null 2>&1; then
+ return 1
+ fi
+
+ local target filesize
+ target="${mountpoint}/${path}"
+ if [ -e "$target" ]; then
+ # Check that the keyfile is suitable
+ filesize="$(ls -l1 "$target" | sed s'/[[:space:]]\+/ /g' | cut -d' ' -f3)"
+ if [ "$filesize" -lt "$keybytes" ]; then
+ db_fset partman-crypto/removable-bad-keyfile seen false
+ db_input critical partman-crypto/removable-bad-keyfile
+ db_go || true
+ continue
+ fi
+ else
+ # We need to create a new keyfile
+ db_subst partman-crypto/removable-confirm-create DEVICE "$(humandev $device)"
+ db_subst partman-crypto/removable-confirm-create PATH "$path"
+ db_input critical partman-crypto/removable-confirm-create || true
+ db_go || return 1
+ db_get partman-crypto/removable-confirm-create
+ if [ "$RET" != true ]; then
+ umount "$mountpoint" > /dev/null 2>&1 || return 1
+ continue
+ fi
+ db_reset partman-crypto/removable-confirm-create
+
+ if ! mkdir -p "$(dirname "$target")" || \
+ ! create_random_keyfile "$target" "$keybytes"; then
+ umount "$mountpoint" > /dev/null 2>&1 || return 1
+ return 1
+ fi
+ fi
+
+ cp "$target" "$keyfile"
+ echo "$device" > "$(dirname "$keyfile")/keydev"
+ echo "$path" > "$(dirname "$keyfile")/keypath"
+ echo "plain" > "$(dirname "$keyfile")/keyhash"
+ umount "$mountpoint" > /dev/null 2>&1 || return 1
+ break
+ done
+ return 0
+}
+
problem_dialog () {
db_fset partman-crypto/keyfile-problem seen false
db_input critical partman-crypto/keyfile-problem
@@ -212,7 +316,7 @@
# Log available entropy
logger -t partman-crypto "kernel entropy_avail: $(cat /proc/sys/kernel/random/entropy_avail) bits"
-if [ "$keytype" = random ] || [ "$keytype" = keyfile ]; then
+if [ "$keytype" = random ] || [ "$keytype" = keyfile ] || [ "$keytype" = removabledev ]; then
if ! have_entropy_plugin; then
db_fset partman-crypto/tools_missing seen false
db_input critical partman-crypto/tools_missing
@@ -261,6 +365,24 @@
fi
;;
+ removabledev)
+ if [ -z "$keybits" ]; then
+ problem_dialog
+ exit 1
+ fi
+ # Round keybits up to closest byte
+ keybytes=$(( (keybits + 7)/8 ))
+ if [ $keybytes -lt 1 ]; then
+ # key size invalid
+ problem_dialog
+ exit 1
+ fi
+ if ! create_removable_keyfile $keyfile $keybytes; then
+ problem_dialog
+ exit 1
+ fi
+ ;;
+
*)
problem_dialog
exit 1
Reply to: