Harald Hoyer 460d2c
From 37502d4c8974370a38496f44e279d56061fe67c3 Mon Sep 17 00:00:00 2001
Harald Hoyer 460d2c
From: Antz <antzz@protonmail.ch>
Harald Hoyer 460d2c
Date: Sat, 29 Aug 2020 14:54:19 +0200
Harald Hoyer 460d2c
Subject: [PATCH] 90crypt: make `rd.luks.key` usable with encrypted keydev.
Harald Hoyer 460d2c
Harald Hoyer 460d2c
Introduce prefix `keysource:` for the values of `rd.luks.partuuid`,
Harald Hoyer 460d2c
`rd.luks.serial` and `rd.luks.uuid`.
Harald Hoyer 460d2c
If specified, ask for passphrase instead of waiting for keydevs to come
Harald Hoyer 460d2c
online.
Harald Hoyer 460d2c
---
Harald Hoyer 460d2c
 dracut.cmdline.7.asc               | 45 ++++++++++++++++++++++++++++++++++++++
Harald Hoyer 460d2c
 modules.d/90crypt/cryptroot-ask.sh | 18 +++++++++++++--
Harald Hoyer 460d2c
 modules.d/90crypt/parse-crypt.sh   | 43 ++++++++++++++++++++++++++----------
Harald Hoyer 460d2c
 3 files changed, 92 insertions(+), 14 deletions(-)
Harald Hoyer 460d2c
Harald Hoyer 460d2c
diff --git a/dracut.cmdline.7.asc b/dracut.cmdline.7.asc
Harald Hoyer 460d2c
index c37d427e..dbbbfed0 100644
Harald Hoyer 460d2c
--- a/dracut.cmdline.7.asc
Harald Hoyer 460d2c
+++ b/dracut.cmdline.7.asc
Harald Hoyer 460d2c
@@ -302,6 +302,8 @@ crypto LUKS
Harald Hoyer 460d2c
     The comparisons also matches, if _<luks uuid>_ is only the beginning of the
Harald Hoyer 460d2c
     LUKS UUID, so you don't have to specify the full UUID.
Harald Hoyer 460d2c
     This parameter can be specified multiple times.
Harald Hoyer 460d2c
+    _<luks uuid>_ may be prefixed by the keyword `keysource:`, see
Harald Hoyer 460d2c
+    _rd.luks.key_ below.
Harald Hoyer 460d2c
 
Harald Hoyer 460d2c
 **rd.luks.allow-discards=**__<luks uuid>__::
Harald Hoyer 460d2c
     Allow  using  of discards (TRIM) requests for LUKS partitions with the given
Harald Hoyer 460d2c
@@ -397,6 +399,49 @@ head -32c /dev/urandom > rootkey.key
Harald Hoyer 460d2c
 cryptsetup --batch-mode --key-file rootkey.key \
Harald Hoyer 460d2c
            luksFormat /dev/sda47
Harald Hoyer 460d2c
 --
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
+You can also use regular key files on an encrypted _keydev_.
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
+Compared to using GPG encrypted keyfiles on an unencrypted
Harald Hoyer 460d2c
+device this provides the following advantages:
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
+- you can unlock your disk(s) using multiple passphrases
Harald Hoyer 460d2c
+- better security by not loosing the key stretching mechanism
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
+To use an encrypted _keydev_ you *must* ensure that it becomes
Harald Hoyer 460d2c
+available by using the keyword `keysource`, e.g.
Harald Hoyer 460d2c
+`rd.luks.uuid=keysource:aaaa`
Harald Hoyer 460d2c
+_aaaa_ being the uuid of the encrypted _keydev_.
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
+Example:
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
+Lets assume you have three disks _A_, _B_ and _C_ with the uuids
Harald Hoyer 460d2c
+_aaaa_, _bbbb_ and _cccc_. +
Harald Hoyer 460d2c
+You want to unlock _A_ and _B_ using keyfile _keyfile_. +
Harald Hoyer 460d2c
+The unlocked volumes be _A'_, _B'_ and _C'_ with the uuids
Harald Hoyer 460d2c
+_AAAA_, _BBBB_ and _CCCC_. +
Harald Hoyer 460d2c
+_keyfile_ is saved on _C'_ as _/keyfile_.
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
+One luks keyslot of each _A_, _B_ and _C_ is setup with a
Harald Hoyer 460d2c
+passphrase. +
Harald Hoyer 460d2c
+Another luks keyslot of each _A_ and _B_ is setup with _keyfile_.
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
+To boot this configuration you could use:
Harald Hoyer 460d2c
+[listing]
Harald Hoyer 460d2c
+--
Harald Hoyer 460d2c
+rd.luks.uuid=aaaa
Harald Hoyer 460d2c
+rd.luks.uuid=bbbb
Harald Hoyer 460d2c
+rd.luks.uuid=keysource:cccc
Harald Hoyer 460d2c
+rd.luks.key=/keyfile:UUID=CCCC
Harald Hoyer 460d2c
+--
Harald Hoyer 460d2c
+Dracut asks for the passphrase for _C_ and uses the
Harald Hoyer 460d2c
+keyfile to unlock _A_ and _B_. +
Harald Hoyer 460d2c
+If getting the passphrase for _C_ fails it falls back to
Harald Hoyer 460d2c
+asking for the passphrases for _A_ and _B_.
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
+If you want _C'_ to stay unlocked, specify a luks name for
Harald Hoyer 460d2c
+it, e.g. `rd.luks.name=cccc=mykeys`, otherwise it gets closed
Harald Hoyer 460d2c
+when not needed anymore.
Harald Hoyer 460d2c
 ===============================
Harald Hoyer 460d2c
 
Harald Hoyer 460d2c
 MD RAID
Harald Hoyer 460d2c
diff --git a/modules.d/90crypt/cryptroot-ask.sh b/modules.d/90crypt/cryptroot-ask.sh
Harald Hoyer 460d2c
index 97047ae9..19d2bcb4 100755
Harald Hoyer 460d2c
--- a/modules.d/90crypt/cryptroot-ask.sh
Harald Hoyer 460d2c
+++ b/modules.d/90crypt/cryptroot-ask.sh
Harald Hoyer 460d2c
@@ -20,8 +20,11 @@ fi
Harald Hoyer 460d2c
 # default luksname - luks-UUID
Harald Hoyer 460d2c
 luksname=$2
Harald Hoyer 460d2c
 
Harald Hoyer 460d2c
+# is_keysource - ask for passphrase even if a rd.luks.key argument is set
Harald Hoyer 460d2c
+is_keysource=${3:-0}
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
 # number of tries
Harald Hoyer 460d2c
-numtries=${3:-10}
Harald Hoyer 460d2c
+numtries=${4:-10}
Harald Hoyer 460d2c
 
Harald Hoyer 460d2c
 # TODO: improve to support what cmdline does
Harald Hoyer 460d2c
 if [ -f /etc/crypttab ] && getargbool 1 rd.luks.crypttab -d -n rd_NO_CRYPTTAB; then
Harald Hoyer 460d2c
@@ -137,6 +140,8 @@ if [ -n "$luksfile" -a "$luksfile" != "none" -a -e "$luksfile" ]; then
Harald Hoyer 460d2c
     if cryptsetup --key-file "$luksfile" $cryptsetupopts luksOpen "$device" "$luksname"; then
Harald Hoyer 460d2c
         ask_passphrase=0
Harald Hoyer 460d2c
     fi
Harald Hoyer 460d2c
+elif [ "$is_keysource" -ne 0 ]; then
Harald Hoyer 460d2c
+    info "Asking for passphrase because $device is a keysource."
Harald Hoyer 460d2c
 else
Harald Hoyer 460d2c
     while [ -n "$(getarg rd.luks.key)" ]; do
Harald Hoyer 460d2c
         if tmp=$(getkey /tmp/luks.keys $device); then
Harald Hoyer 460d2c
@@ -151,7 +156,7 @@ else
Harald Hoyer 460d2c
             info "No key found for $device.  Will try $numtries time(s) more later."
Harald Hoyer 460d2c
             initqueue --unique --onetime --settled \
Harald Hoyer 460d2c
                 --name cryptroot-ask-$luksname \
Harald Hoyer 460d2c
-                $(command -v cryptroot-ask) "$device" "$luksname" "$(($numtries-1))"
Harald Hoyer 460d2c
+                $(command -v cryptroot-ask) "$device" "$luksname" "$is_keysource" "$(($numtries-1))"
Harald Hoyer 460d2c
             exit 0
Harald Hoyer 460d2c
         fi
Harald Hoyer 460d2c
         unset tmp
Harald Hoyer 460d2c
@@ -178,6 +183,15 @@ if [ $ask_passphrase -ne 0 ]; then
Harald Hoyer 460d2c
     unset _timeout
Harald Hoyer 460d2c
 fi
Harald Hoyer 460d2c
 
Harald Hoyer 460d2c
+if [ "$is_keysource" -ne 0 -a ${luksname##luks-} != "$luksname" ]; then
Harald Hoyer 460d2c
+    luks_close="$(command -v cryptsetup) close"
Harald Hoyer 460d2c
+    {
Harald Hoyer 460d2c
+        printf -- '[ -e /dev/mapper/%s ] && ' "$luksname"
Harald Hoyer 460d2c
+        printf -- '%s "%s"\n' "$luks_close" "$luksname"
Harald Hoyer 460d2c
+    } >> "$hookdir/cleanup/31-crypt-keysource.sh"
Harald Hoyer 460d2c
+    unset luks_close
Harald Hoyer 460d2c
+fi
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
 unset device luksname luksfile
Harald Hoyer 460d2c
 
Harald Hoyer 460d2c
 # mark device as asked
Harald Hoyer 460d2c
diff --git a/modules.d/90crypt/parse-crypt.sh b/modules.d/90crypt/parse-crypt.sh
Harald Hoyer 460d2c
index f6911cc8..4e899fed 100755
Harald Hoyer 460d2c
--- a/modules.d/90crypt/parse-crypt.sh
Harald Hoyer 460d2c
+++ b/modules.d/90crypt/parse-crypt.sh
Harald Hoyer 460d2c
@@ -49,6 +49,12 @@ else
Harald Hoyer 460d2c
     if [ -n "$PARTUUID" ]; then
Harald Hoyer 460d2c
         for uuid in $PARTUUID; do
Harald Hoyer 460d2c
 
Harald Hoyer 460d2c
+            is_keysource=0
Harald Hoyer 460d2c
+            _uuid=$uuid
Harald Hoyer 460d2c
+            uuid=${uuid#keysource:}
Harald Hoyer 460d2c
+            [ $uuid != $_uuid ] && is_keysource=1
Harald Hoyer 460d2c
+            unset _uuid
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
             uuid=${uuid##luks-}
Harald Hoyer 460d2c
             if luksname=$(_cryptgetargsname "rd.luks.name=$uuid="); then
Harald Hoyer 460d2c
                 luksname="${luksname#$uuid=}"
Harald Hoyer 460d2c
@@ -61,7 +67,7 @@ else
Harald Hoyer 460d2c
                     printf -- 'ENV{ID_PART_ENTRY_UUID}=="*%s*", ' "$uuid"
Harald Hoyer 460d2c
                     printf -- 'RUN+="%s --settled --unique --onetime ' "$(command -v initqueue)"
Harald Hoyer 460d2c
                     printf -- '--name cryptroot-ask-%%k %s ' "$(command -v cryptroot-ask)"
Harald Hoyer 460d2c
-                    printf -- '$env{DEVNAME} %s %s"\n' "$luksname" "$tout"
Harald Hoyer 460d2c
+                    printf -- '$env{DEVNAME} %s %s"\n' "$luksname" "$is_keysource" "$tout"
Harald Hoyer 460d2c
                 } >> /etc/udev/rules.d/70-luks.rules.new
Harald Hoyer 460d2c
             else
Harald Hoyer 460d2c
                 luksname=$(dev_unit_name "$luksname")
Harald Hoyer 460d2c
@@ -81,6 +87,12 @@ else
Harald Hoyer 460d2c
     elif [ -n "$SERIAL" ]; then
Harald Hoyer 460d2c
         for serialid in $SERIAL; do
Harald Hoyer 460d2c
 
Harald Hoyer 460d2c
+            is_keysource=0
Harald Hoyer 460d2c
+            _serialid=$serialid
Harald Hoyer 460d2c
+            serialid=${serialid#keysource:}
Harald Hoyer 460d2c
+            [ $serialid != $_serialid ] && is_keysource=1
Harald Hoyer 460d2c
+            unset _serialid
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
             serialid=${serialid##luks-}
Harald Hoyer 460d2c
             if luksname=$(_cryptgetargsname "rd.luks.name=$serialid="); then
Harald Hoyer 460d2c
                 luksname="${luksname#$serialid=}"
Harald Hoyer 460d2c
@@ -93,7 +105,7 @@ else
Harald Hoyer 460d2c
                     printf -- 'ENV{ID_SERIAL_SHORT}=="*%s*", ' "$serialid"
Harald Hoyer 460d2c
                     printf -- 'RUN+="%s --settled --unique --onetime ' "$(command -v initqueue)"
Harald Hoyer 460d2c
                     printf -- '--name cryptroot-ask-%%k %s ' "$(command -v cryptroot-ask)"
Harald Hoyer 460d2c
-                    printf -- '$env{DEVNAME} %s %s"\n' "$luksname" "$tout"
Harald Hoyer 460d2c
+                    printf -- '$env{DEVNAME} %s %s"\n' "$luksname" "$is_keysource" "$tout"
Harald Hoyer 460d2c
                 } >> /etc/udev/rules.d/70-luks.rules.new
Harald Hoyer 460d2c
             else
Harald Hoyer 460d2c
                 luksname=$(dev_unit_name "$luksname")
Harald Hoyer 460d2c
@@ -113,6 +125,12 @@ else
Harald Hoyer 460d2c
     elif [ -n "$LUKS" ]; then
Harald Hoyer 460d2c
         for luksid in $LUKS; do
Harald Hoyer 460d2c
 
Harald Hoyer 460d2c
+            is_keysource=0
Harald Hoyer 460d2c
+            _luksid=$luksid
Harald Hoyer 460d2c
+            luksid=${luksid#keysource:}
Harald Hoyer 460d2c
+            [ $luksid != $_luksid ] && is_keysource=1
Harald Hoyer 460d2c
+            unset _luksid
Harald Hoyer 460d2c
+
Harald Hoyer 460d2c
             luksid=${luksid##luks-}
Harald Hoyer 460d2c
             if luksname=$(_cryptgetargsname "rd.luks.name=$luksid="); then
Harald Hoyer 460d2c
                 luksname="${luksname#$luksid=}"
Harald Hoyer 460d2c
@@ -126,7 +144,7 @@ else
Harald Hoyer 460d2c
                     printf -- 'ENV{ID_FS_UUID}=="*%s*", ' "$luksid"
Harald Hoyer 460d2c
                     printf -- 'RUN+="%s --settled --unique --onetime ' "$(command -v initqueue)"
Harald Hoyer 460d2c
                     printf -- '--name cryptroot-ask-%%k %s ' "$(command -v cryptroot-ask)"
Harald Hoyer 460d2c
-                    printf -- '$env{DEVNAME} %s %s"\n' "$luksname" "$tout"
Harald Hoyer 460d2c
+                    printf -- '$env{DEVNAME} %s %s %s"\n' "$luksname" "$is_keysource" "$tout"
Harald Hoyer 460d2c
                 } >> /etc/udev/rules.d/70-luks.rules.new
Harald Hoyer 460d2c
             else
Harald Hoyer 460d2c
                 luksname=$(dev_unit_name "$luksname")
Harald Hoyer 460d2c
@@ -143,15 +161,16 @@ else
Harald Hoyer 460d2c
                 fi
Harald Hoyer 460d2c
             fi
Harald Hoyer 460d2c
 
Harald Hoyer 460d2c
-            uuid=$luksid
Harald Hoyer 460d2c
-            while [ "$uuid" != "${uuid#*-}" ]; do uuid=${uuid%%-*}${uuid#*-}; done
Harald Hoyer 460d2c
-            printf -- '[ -e /dev/disk/by-id/dm-uuid-CRYPT-LUKS?-*%s*-* ] || exit 1\n' $uuid \
Harald Hoyer 460d2c
-                >> "$hookdir/initqueue/finished/90-crypt.sh"
Harald Hoyer 460d2c
-
Harald Hoyer 460d2c
-            {
Harald Hoyer 460d2c
-                printf -- '[ -e /dev/disk/by-uuid/*%s* ] || ' $luksid
Harald Hoyer 460d2c
-                printf -- 'warn "crypto LUKS UUID "%s" not found"\n' $luksid
Harald Hoyer 460d2c
-            } >> "$hookdir/emergency/90-crypt.sh"
Harald Hoyer 460d2c
+            if [ $is_keysource -eq 0 ]; then
Harald Hoyer 460d2c
+                uuid=$luksid
Harald Hoyer 460d2c
+                while [ "$uuid" != "${uuid#*-}" ]; do uuid=${uuid%%-*}${uuid#*-}; done
Harald Hoyer 460d2c
+                printf -- '[ -e /dev/disk/by-id/dm-uuid-CRYPT-LUKS?-*%s*-* ] || exit 1\n' $uuid \
Harald Hoyer 460d2c
+                    >> "$hookdir/initqueue/finished/90-crypt.sh"
Harald Hoyer 460d2c
+                {
Harald Hoyer 460d2c
+                    printf -- '[ -e /dev/disk/by-uuid/*%s* ] || ' $luksid
Harald Hoyer 460d2c
+                    printf -- 'warn "crypto LUKS UUID "%s" not found"\n' $luksid
Harald Hoyer 460d2c
+                } >> "$hookdir/emergency/90-crypt.sh"
Harald Hoyer 460d2c
+            fi
Harald Hoyer 460d2c
         done
Harald Hoyer 460d2c
     elif getargbool 0 rd.auto; then
Harald Hoyer 460d2c
         if [ -z "$DRACUT_SYSTEMD" ]; then
Harald Hoyer 460d2c