diff options
author | Maciej S. Szmigiero <mail@maciej.szmigiero.name> | 2020-11-22 02:06:47 +0100 |
---|---|---|
committer | Maciej S. Szmigiero <mail@maciej.szmigiero.name> | 2022-05-22 20:45:16 +0200 |
commit | 72839de16243fb410d587e18d76d3b637fa3f389 (patch) | |
tree | 895cb2bb1364702ce171dce6e032d8d8f2cffdd5 /defaults | |
parent | arch: Copy s390 config to s390x (it's 64bit anyway!) (diff) | |
download | genkernel-72839de16243fb410d587e18d76d3b637fa3f389.tar.gz genkernel-72839de16243fb410d587e18d76d3b637fa3f389.tar.bz2 genkernel-72839de16243fb410d587e18d76d3b637fa3f389.zip |
genkernel: add keyctl support for loading LUKS passphrase into a keyring
cryptsetup LUKS2 format comes with an ability to automatically unlock
multiple devices (root, swap, etc.) sharing the same passphrase, without
retyping it for each of them, by loading it into the user keyring.
This commit adds such (optional) genkernel support for loading LUKS
passphrase into the user keyring on boot.
In the default mode of operation the newly added key is (possibly) used
only to unlock root and swap devices and is removed soon after that.
By providing appropriate kernel command line parameter the key can be left
in the keyring instead (with an optional timeout) for unlocking other LUKS
devices post-initramfs time.
Because one of the most common use cases of this functionality will be
having an encrypted swap for doing suspend to disk (hibernation) let's also
make sure that we don't unlock the root device when doing so is unnecessary
(when we are resuming the system from hibernation).
Since the security of a FDE passphrase is of paramount importance in this
solution significant care has been taken not to leak it accidentally:
* The passphrase is read directly by keyctl to avoid storing it in the
shell,
* If the passphrase is used only to unlock root and swap devices (which is
the default mode of operation) the init script will check whether its
removal from keyring has actually succeeded and, if not, reboot the system
rather than continue while leaving it exposed,
* keyutils includes a patch (already upstreamed) to wipe the passphrase
from memory when no longer needed.
Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
Diffstat (limited to 'defaults')
-rw-r--r-- | defaults/initrd.scripts | 52 | ||||
-rw-r--r-- | defaults/linuxrc | 34 | ||||
-rw-r--r-- | defaults/software.sh | 7 |
3 files changed, 90 insertions, 3 deletions
diff --git a/defaults/initrd.scripts b/defaults/initrd.scripts index 4932783..eb556d6 100644 --- a/defaults/initrd.scripts +++ b/defaults/initrd.scripts @@ -2108,6 +2108,54 @@ openLUKS() { [ -d "${mntkey}" ] && run rmdir -p "${mntkey}" >/dev/null 2>&1 } +keyctl_keyadd() { + if [ -n "${KEYCTL_KEYDESC}" ] + then + if [ ! -x /bin/keyctl ] + then + bad_msg "keyctl program is missing. Was initramfs built without --keyctl parameter?" + exit 1 + fi + + # not using read to avoid secrets being left in memory + stty -echo + echo -n "Please type the key '${KEYCTL_KEYDESC}' for the user keyring then press Ctrl-D twice: " + KEYCTL_KEYID=`keyctl padd user "${KEYCTL_KEYDESC}" @u` + echo + stty echo + + if [ -n "${KEYCTL_KEYID}" -a -n "${KEYCTL_KEYTIMEOUT}" ] + then + keyctl timeout "${KEYCTL_KEYID}" "${KEYCTL_KEYTIMEOUT}" + fi + fi +} + +keyctl_keyremove() { + if [ -n "${KEYCTL_KEYID}" -a -z "${KEYCTL_KEYKEEP}" ] + then + if [ ! -x /bin/keyctl ] + then + bad_msg "keyctl program is missing. Was initramfs built without --keyctl parameter?" + exit 1 + fi + + keyctl revoke "${KEYCTL_KEYID}" + keyctl unlink "${KEYCTL_KEYID}" >/dev/null + + # trust but verify + if keyctl show "${KEYCTL_KEYID}" >/dev/null 2>&1 + then + # better reboot than leave the user passphrase accidentally exposed + bad_msg "unable to remove the newly added key from keyring, rebooting in 5 seconds for security" + sleep 5 + reboot -f + fi + + KEYCTL_KEYID= + fi +} + iface_name() { local ifname="${1}" @@ -2437,7 +2485,7 @@ ipv6_tentative() { fi } -start_LUKS() { +start_LUKS_root() { # if key is set but neither ssh enabled or key device is given, find # the key device @@ -2461,7 +2509,9 @@ start_LUKS() { REAL_ROOT="/dev/mapper/root" fi fi +} +start_LUKS_swap() { if [ -n "${CRYPT_SWAP_KEY}" ] then # same for swap, but no need to sleep if root was unencrypted diff --git a/defaults/linuxrc b/defaults/linuxrc index 15fbf7c..5ee7804 100644 --- a/defaults/linuxrc +++ b/defaults/linuxrc @@ -272,6 +272,15 @@ do swap_keydev_fstype=*) CRYPT_SWAP_KEYDEV_FSTYPE=${x#*=} ;; + keyctl_keydesc=*) + KEYCTL_KEYDESC=${x#*=} + ;; + keyctl_keytimeout=*) + KEYCTL_KEYTIMEOUT=${x#*=} + ;; + keyctl_keykeep) + KEYCTL_KEYKEEP=1 + ;; real_resume=*|resume=*) REAL_RESUME=${x#*=} ;; @@ -656,10 +665,23 @@ then start_sshd fi +keyctl_keyadd + # Initialize LUKS root device except for livecd's if [ "${CDROOT}" != '1' ] then - start_LUKS + if ( [ -n "${CRYPT_SWAP_KEY}" ] && [ -z "${CRYPT_SWAP_KEYDEV}" ] ) || \ + ( [ -n "${CRYPT_SWAP_HEADER}" ] && [ -z "${CRYPT_SWAP_HEADERDEV}" ] ) + then + # the swap key or header might be on the root fs so start it first in this case + start_LUKS_root + luks_root_started=1 + start_LUKS_swap + else + # we don't need to start the root at all if we are resuming from suspend + start_LUKS_swap + fi + if [ "${NORESUME}" != '1' ] && [ -n "${REAL_RESUME}" ] then case "${REAL_RESUME}" in @@ -691,6 +713,11 @@ then do_resume fi + + if [ -z "${luks_root_started}" ] + then + start_LUKS_root + fi fi run mkdir -p "${NEW_ROOT}" @@ -1060,7 +1087,8 @@ then losetup /dev/loop0 "${CDROOT_PATH}/${LOOPEXT}${LOOP}" test_success 'Preparing loop filesystem' - start_LUKS + start_LUKS_root + start_LUKS_swap case ${LOOPTYPE} in normal) @@ -1302,6 +1330,8 @@ else fi fi # if [ "${CDROOT}" = '1' ] +keyctl_keyremove + # Re-run to ensure $NEWROOT/etc/initramfs.mounts was processed at least once process_initramfs_mounts diff --git a/defaults/software.sh b/defaults/software.sh index ec2bacb..0dce9e1 100644 --- a/defaults/software.sh +++ b/defaults/software.sh @@ -128,6 +128,13 @@ GKPKG_JSON_C_SRCTAR="${GKPKG_JSON_C_SRCTAR:-${DISTDIR}/json-c-${GKPKG_JSON_C_PV} GKPKG_JSON_C_SRCDIR="${GKPKG_JSON_C_SRCDIR:-json-c-${GKPKG_JSON_C_PV}}" GKPKG_JSON_C_BINPKG="${GKPKG_JSON_C_BINPKG:-%%CACHE%%/json-c-${GKPKG_JSON_C_PV}-%%ARCH%%.tar.xz}" +GKPKG_KEYUTILS_PN="keyutils" +GKPKG_KEYUTILS_PV="${GKPKG_KEYUTILS_PV:-1.6.3}" +GKPKG_KEYUTILS_DEPS="" +GKPKG_KEYUTILS_SRCTAR="${GKPKG_KEYUTILS_SRCTAR:-${DISTDIR}/keyutils-${GKPKG_KEYUTILS_PV}.tar.gz}" +GKPKG_KEYUTILS_SRCDIR="${GKPKG_KEYUTILS_SRCDIR:-keyutils-${GKPKG_KEYUTILS_PV}}" +GKPKG_KEYUTILS_BINPKG="${GKPKG_KEYUTILS_BINPKG:-%%CACHE%%/keyutils-${GKPKG_KEYUTILS_PV}-%%ARCH%%.tar.xz}" + GKPKG_KMOD_PN="kmod" GKPKG_KMOD_PV="${GKPKG_KMOD_PV:-VERSION_KMOD}" GKPKG_KMOD_DEPS="zlib xz zstd" |