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