]> git.pld-linux.org Git - projects/geninitrd.git/blobdiff - mod-luks.sh
luks: initial support for luks2 tokens
[projects/geninitrd.git] / mod-luks.sh
index abd175d9d3aa3a4d8ff5fe7274151caf468674e3..468489afbb3c6d67bcefd941c34200b22b7b3bb2 100644 (file)
@@ -1,5 +1,4 @@
 #!/bin/sh
-#
 # geninitrd mod: cryptsetup luks
 USE_LUKS=${USE_LUKS:-yes}
 
@@ -8,7 +7,7 @@ USE_LUKS=${USE_LUKS:-yes}
 have_luks=no
 
 # device to use for name for cryptsetup luks
-LUKSDEV=""
+LUKSNAME=""
 
 # setup geninitrd module
 # @access      public
@@ -31,19 +30,15 @@ is_luks() {
                return 1
        fi
 
-       if [ ! -e "$node" ]; then
-               warn "is_luks(): node $node doesn't exist!"
-               return 1
-       fi
-
        local dev dm_name=${node#/dev/mapper/}
        if [ "$node" = "$dm_name" ]; then
-               debug "is_luks: $node is not device mapper name"
+               verbose "is_luks: $node is not device mapper name"
                return 1
        fi
 
-       dev=$(/sbin/cryptsetup status $dm_name 2>/dev/null | awk '/device:/{print $2}')
+       dev=$(awk -vdm_name="$dm_name" '$1 == dm_name { print $2 }' /etc/crypttab)
        if [ "$dev" ]; then
+               dev=$(find_devname "$dev")
                /sbin/cryptsetup isLuks $dev
                rc=$?
        else
@@ -51,9 +46,9 @@ is_luks() {
        fi
 
        if [ $rc = 0 ]; then
-               debug "is_luks: $node is cryptsetup luks"
+               verbose "is_luks: $node is cryptsetup luks"
        else
-               debug "is_luks: $node is not cryptsetup luks"
+               verbose "is_luks: $node is not cryptsetup luks"
        fi
        return $rc
 }
@@ -63,24 +58,31 @@ is_luks() {
 # @access      public
 find_modules_luks() {
        local devpath="$1"
-       local dev
+       local dev=""
 
-       local name=${devpath#/dev/mapper/}
-       LUKSDEV=$(/sbin/cryptsetup status $name 2>/dev/null | awk '/device:/{print $2}')
-       if [ -z "$LUKSDEV" ]; then
-               die "Lost cryptsetup device meanwhile?"
-       fi
+       LUKSNAME=${devpath#/dev/mapper/}
 
        find_module "dm-crypt"
 
        # TODO: autodetect
-       find_module "aes"
-       find_module "cbc"
-
-       have_luks=yes
+       find_module "-aes"
+       find_module "-cbc"
+       find_module "-cbc(aes)"
+       find_module "-xts(aes)"
+       find_module "-af-alg"
+       find_module "-algif_hash"
+       find_module "-algif_skcipher"
+       find_module "-loop"
 
        # recurse
-       find_modules_for_devpath $LUKSDEV
+       dev=$(awk -vLUKSNAME="$LUKSNAME" '$1 == LUKSNAME { print $2 }' /etc/crypttab)
+       if [ -n "$dev" ]; then
+               dev=$(find_devname "$dev")
+               find_modules_for_devpath $dev
+               have_luks=yes
+       else
+               die "Cannot find '$LUKSNAME' in /etc/crypttab"
+       fi
 }
 
 
@@ -93,14 +95,15 @@ initrd_gen_luks() {
 
        inst_d /bin
        inst_exec $cryptsetup /bin/cryptsetup
+       inst_d /var/run/cryptsetup
 
        mount_dev
        mount_sys
        initrd_gen_devices
        # TODO: 'udevadm settle' is called by lukssetup, is udev optional?
 
-       debug "luks: process /etc/crypttab $LUKSDEV"
-       luks_crypttab $LUKSDEV
+       verbose "luks: process /etc/crypttab $LUKSNAME"
+       luks_crypttab $LUKSNAME
 }
 
 
@@ -111,48 +114,117 @@ key_is_random() {
 
 # produce cryptsetup from $name from /etc/crypttab
 luks_crypttab() {
-       local LUKSDEV="$1"
+       local LUKSNAME="$1"
 
        # copy from /etc/rc.d/init.d/cryptsetup
-       local dst src key opt mode owner
+       local dst src key opt mode owner failsafe token libdir cryptdir
 
        while read dst src key opt; do
-               [ -z "$dst" -o "${dst#\#}" != "$dst" ] && continue
-               [ "$src" != "$LUKSDEV" ] && continue
-
-               if [ -n "$key" -a "x$key" != "xnone" ]; then
-                       if test -e "$key" ; then
-                               mode=$(LC_ALL=C ls -l "$key" | cut -c 5-10)
-                               owner=$(LC_ALL=C ls -l $key | awk '{ print $3 }')
-                               if [ "$mode" != "------" ] && ! key_is_random "$key"; then
-                                       die "INSECURE MODE FOR $key"
-                               fi
-                               if [ "$owner" != root ]; then
-                                       die "INSECURE OWNER FOR $key"
-                               fi
-                       else
-                               die "Key file for $dst not found"
+               [ "$dst" != "$LUKSNAME" ] && continue
+
+               failsafe=""
+
+               if [ -z "$key" ] || [ "x$key" = "xnone" ] || [ "x$key" = "x-" ]; then
+                       failsafe=1
+                       key="/etc/cryptsetup-keys.d/$LUKSNAME.key"
+               fi
+
+               if test -e "$key" ; then
+                       mode=$(LC_ALL=C ls -l "$key" | cut -c 5-10)
+                       owner=$(LC_ALL=C ls -l $key | awk '{ print $3 }')
+                       if [ "$mode" != "------" ] && ! key_is_random "$key"; then
+                               die "INSECURE MODE FOR $key"
                        fi
-               else
+                       if [ "$owner" != root ]; then
+                               die "INSECURE OWNER FOR $key"
+                       fi
+               elif [ -n "$failsafe" ]; then
                        key=""
+               else
+                       die "Key file for $dst not found"
                fi
 
+               src=$(find_devname "$src")
                if /sbin/cryptsetup isLuks "$src" 2>/dev/null; then
                        if key_is_random "$key"; then
                                die "$dst: LUKS requires non-random key, skipping"
                        fi
-                       if [ -n "$opt" ]; then
-                               warn "$dst: options are invalid for LUKS partitions, ignoring them"
-                       fi
                        if [ "$key" ]; then
                                keyfile=/etc/.$dst.key
                                inst $key $keyfile
                        fi
+                       for libdir in $(get_libdir /usr/LIBDIR); do
+                               if [ -d $libdir/cryptsetup ]; then
+                                       cryptdir=$libdir/cryptsetup
+                                       break
+                               fi
+                       done
+                       if ! is_no "$USE_LUKS_TOKEN" && [ -n "$cryptdir" ]; then
+                               for token in $(/sbin/cryptsetup luksDump $src | sed -n -e '/^Tokens:/,/^[^[:space:]]/ { /^[[:space:]]*[[:digit:]]*:/ { s/^[[:space:]]*[[:digit:]]*:[[:space:]]*// p } }'); do
+                                       verbose "Found cryptsetup token: $token"
+                                       case "$token" in
+                                               systemd-fido2)
+                                                       inst_d $cryptdir
+                                                       inst_exec $cryptdir/libcryptsetup-token-$token.so $cryptdir
+                                                       inst_exec $libdir/libfido2.so.1 $libdir
+                                                       ;;
+                                               systemd-tpm2)
+                                                       inst_d $cryptdir
+                                                       inst_exec $cryptdir/libcryptsetup-token-$token.so $cryptdir
+                                                       inst_exec $libdir/libtss2-esys.so.0 $libdir/libtss2-rc.so.0 $libdir/libtss2-mu.so.0 $libdir
+                                                       ;;
+                                               *)
+                                                       inst_d $cryptdir
+                                                       inst_exec $cryptdir/libcryptsetup-token-$token.so $cryptdir
+                                                       ;;
+                                       esac
+                               done
+                       fi
 
-                       debug "+ cryptsetup ${keyfile:+-d $keyfile} luksOpen '$src' '$dst'"
+                       crypttab_opt=""
+                       old_IFS="$IFS"
+                       IFS=","
+                       for option in $opt; do
+                               case "$option" in
+                                       discard|allow-discards)
+                                               crypttab_opt="$crypttab_opt --allow-discards"
+                                               ;;
+                                       *)
+                                               warn "$dst: option \'$opt\' is invalid for LUKS partitions, ignored"
+                                               ;;
+                               esac
+                       done
+                       IFS="$old_IFS"
+
+                       verbose "+ cryptsetup ${keyfile:+-d $keyfile} open $crypttab_opt '$src' '$dst'"
                        add_linuxrc <<-EOF
-                       if [ -e "$src" ]; then
-                               cryptsetup ${keyfile:+-d $keyfile} luksOpen '$src' '$dst' <&1
+                       debugshell
+
+                       cryptsetup_opt=""
+                       if [ "\$DEBUGINITRD" ]; then
+                               cryptsetup_opt="--debug"
+                       fi
+                       # cryptsetup can be called twice and in case on crypt on lvm only second
+                       # will succeed because there will be no src device in first cryptsetup call
+                       # this can be called multiple times, before lvm and after lvm.
+                       luksdev='$src'
+                       if [ \${luksdev##/dev/disk/by-uuid/} != \${luksdev} ]; then
+                               src_uuid=\${luksdev##/dev/disk/by-uuid/}
+                               while read x y z name; do
+                                       found_uuid=\$(cryptsetup \$cryptsetup_opt luksUUID /dev/\${name} 2>/dev/null)
+                                       if [ "\$found_uuid" = "\$src_uuid" ]; then
+                                               luksdev=/dev/\$name
+                                               break
+                                       fi
+                               done < /proc/partitions
+                       fi
+
+                       if [ -e "\$luksdev" ]; then
+                               crypt_status=\$(cryptsetup \$cryptsetup_opt status '$dst')
+                               if [ "\${crypt_status%%is inactive*}" != "\$crypt_status" ]; then
+                                       # is inactive
+                                       cryptsetup \$cryptsetup_opt ${keyfile:+-d $keyfile} open $crypttab_opt "\$luksdev" '$dst' <&1
+                               fi
                        fi
 
                        debugshell
This page took 0.086761 seconds and 4 git commands to generate.