From a13d42613d7a2112e27262fc1471ccfdbd77cc7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Old=C5=99ich=20Jedli=C4=8Dka?= Date: Sun, 16 Jun 2024 21:57:37 +0200 Subject: [PATCH] Dracut TPM1 integration --- .../dracut/clevis-pin-tpm1/clevis-hook.sh.in | 25 +++++ .../dracut/clevis-pin-tpm1/clevis-tcsd.conf | 6 ++ src/luks/dracut/clevis-pin-tpm1/meson.build | 23 +++++ .../dracut/clevis-pin-tpm1/module-setup.sh.in | 97 +++++++++++++++++++ src/luks/dracut/clevis/clevis-hook.sh.in | 1 - ...-luks-unlocker => clevis-luks-unlocker.in} | 59 +++++++++-- src/luks/dracut/clevis/meson.build | 7 +- src/luks/dracut/clevis/module-setup.sh.in | 2 +- src/luks/dracut/meson.build | 1 + 9 files changed, 212 insertions(+), 9 deletions(-) create mode 100755 src/luks/dracut/clevis-pin-tpm1/clevis-hook.sh.in create mode 100644 src/luks/dracut/clevis-pin-tpm1/clevis-tcsd.conf create mode 100644 src/luks/dracut/clevis-pin-tpm1/meson.build create mode 100755 src/luks/dracut/clevis-pin-tpm1/module-setup.sh.in rename src/luks/dracut/clevis/{clevis-luks-unlocker => clevis-luks-unlocker.in} (63%) diff --git a/src/luks/dracut/clevis-pin-tpm1/clevis-hook.sh.in b/src/luks/dracut/clevis-pin-tpm1/clevis-hook.sh.in new file mode 100755 index 00000000..89248a6d --- /dev/null +++ b/src/luks/dracut/clevis-pin-tpm1/clevis-hook.sh.in @@ -0,0 +1,25 @@ +#!/bin/sh +# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2024 Red Hat, Inc. +# Author: Oldřich Jedlička +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +( + set -eu + . @libexecdir@/clevis-luks-tpm1-functions + stop_tcsd +) diff --git a/src/luks/dracut/clevis-pin-tpm1/clevis-tcsd.conf b/src/luks/dracut/clevis-pin-tpm1/clevis-tcsd.conf new file mode 100644 index 00000000..0adb8147 --- /dev/null +++ b/src/luks/dracut/clevis-pin-tpm1/clevis-tcsd.conf @@ -0,0 +1,6 @@ +[Unit] +DefaultDependencies=no + +[Install] +# Use the default +WantedBy= diff --git a/src/luks/dracut/clevis-pin-tpm1/meson.build b/src/luks/dracut/clevis-pin-tpm1/meson.build new file mode 100644 index 00000000..d9fa6e23 --- /dev/null +++ b/src/luks/dracut/clevis-pin-tpm1/meson.build @@ -0,0 +1,23 @@ +dracut = dependency('dracut', required: false) + +if dracut.found() + dracutdir = dracut.get_pkgconfig_variable('dracutmodulesdir') + '/60' + meson.project_name() + '-pin-tpm1' + + configure_file( + input: 'module-setup.sh.in', + output: 'module-setup.sh', + install_dir: dracutdir, + configuration: data, + ) + + configure_file( + input: 'clevis-hook.sh.in', + output: 'clevis-hook.sh', + install_dir: dracutdir, + configuration: data, + ) + + install_data('clevis-tcsd.conf', install_dir: dracutdir) +else + warning('Will not install dracut module clevis-pin-tpm2 due to missing dependencies!') +endif diff --git a/src/luks/dracut/clevis-pin-tpm1/module-setup.sh.in b/src/luks/dracut/clevis-pin-tpm1/module-setup.sh.in new file mode 100755 index 00000000..bda105fd --- /dev/null +++ b/src/luks/dracut/clevis-pin-tpm1/module-setup.sh.in @@ -0,0 +1,97 @@ +#!/bin/bash +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2024 Red Hat, Inc. +# Author: Oldřich Jedlička +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +check() { + require_binaries clevis-decrypt-tpm1 tpm_version tpm_unsealdata tcsd stdbuf || return 1 + if [[ $hostonly ]]; then + [ -d /var/lib/tpm ] || return 1 + else + [ -f /usr/share/trousers/system.data.auth ] || \ + [ -f /var/lib/tpm/system.data.auth ] || \ + return 1 + fi + return 0 +} + +depends() { + echo clevis network + return 0 +} + +install() { + if dracut_module_included "systemd"; then + inst "$systemdsystemunitdir/tcsd.service" + inst "$moddir/clevis-tcsd.conf" "$systemdsystemunitdir/tcsd.service.d/clevis-tcsd.conf" + else + inst_hook cleanup 60 "$moddir/clevis-hook.sh" + inst_multiple \ + awk chmod chown mkfifo mktemp ip ps stdbuf \ + @libexecdir@/clevis-luks-tpm1-functions + if [ -f /usr/libexec/coreutils/libstdbuf.so ]; then + inst_multiple /usr/libexec/coreutils/libstdbuf.so* + else + inst_libdir_file 'coreutils/libstdbuf.so*' + fi + fi + + inst_multiple \ + clevis-decrypt-tpm1 \ + tcsd \ + tpm_version \ + tpm_unsealdata + + inst_rules 60-tpm-udev.rules + + if ! [[ $hostonly ]] || ! dracut_module_included "systemd"; then + # /etc/hosts is installed only in host-only mode with systemd, so + # we need to create our own in order to get tpm tools working. + # The localhost entry is required by tpm tools. + if [ ! -f "$initdir/etc/hosts" ]; then + echo "127.0.0.1 localhost" >> "$initdir/etc/hosts" + echo "::1 localhost ip6-localhost ip6-loopback" >> "$initdir/etc/hosts" + echo "ff02::1 ip6-allnodes" >> "$initdir/etc/hosts" + echo "ff02::2 ip6-allrouters" >> "$initdir/etc/hosts" + fi + fi + + if [[ $hostonly ]]; then + inst /etc/tcsd.conf + inst_multiple /var/lib/tpm/* + else + inst_dir /etc + touch "$initdir/etc/tcsd.conf" + chmod 0640 "$initdir/etc/tcsd.conf" + chown root:tss "$initdir/etc/tcsd.conf" + + inst_dir /var/lib/tpm + if [ -f /usr/share/trousers/system.data.auth ]; then + inst /usr/share/trousers/system.data.auth /var/lib/tpm/system.data + else + inst /var/lib/tpm/system.data.auth /var/lib/tpm/system.data + fi + fi + + chown -R tss:tss "$initdir/var/lib/tpm" + chmod -R u=rwX,go= "$initdir/var/lib/tpm" +} + +installkernel() { + hostonly='' instmods '=drivers/char/tpm' +} diff --git a/src/luks/dracut/clevis/clevis-hook.sh.in b/src/luks/dracut/clevis/clevis-hook.sh.in index 78921a5d..79128625 100755 --- a/src/luks/dracut/clevis/clevis-hook.sh.in +++ b/src/luks/dracut/clevis/clevis-hook.sh.in @@ -1,5 +1,4 @@ #!/bin/sh -set -eu # vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: # # Copyright (c) 2020-2024 Red Hat, Inc. diff --git a/src/luks/dracut/clevis/clevis-luks-unlocker b/src/luks/dracut/clevis/clevis-luks-unlocker.in similarity index 63% rename from src/luks/dracut/clevis/clevis-luks-unlocker rename to src/luks/dracut/clevis/clevis-luks-unlocker.in index 83063206..6fe42d40 100755 --- a/src/luks/dracut/clevis/clevis-luks-unlocker +++ b/src/luks/dracut/clevis/clevis-luks-unlocker.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash set -eu # vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: # @@ -37,7 +37,9 @@ while getopts ":l" o; do done to_unlock() { + _skip=$@ _devices='' + for _d in $(blkid -t TYPE=crypto_LUKS -o device); do if ! bindings="$(clevis luks list -d "${_d}" 2>/dev/null)" \ || [ -z "${bindings}" ]; then @@ -49,11 +51,56 @@ to_unlock() { fi _devices="$(printf '%s\n%s' "${_devices}" "${_d}")" done - echo "${_devices}" | sed -e 's/^\n$//' + for _d in $(echo "${_devices}" | sed -e 's/^\n$//'); do + case " ${_skip} " in + *" ${_d} "* ) ;; + * ) echo -n "${_d} " ;; + esac + done | sed -e 's/ $/\n/' } +has_tpm1_pin() { + local dev="$1" + + clevis luks list -d "${dev}" | grep -q tpm1 +} + +do_configure_tpm1() { + local tcsd_output= + local tcsd_result + + if ! [ -x @bindir@/clevis-decrypt-tpm1 ] || ! [ -f @libexecdir@/clevis-luks-tpm1-functions ]; then + return + fi + + . @libexecdir@/clevis-luks-tpm1-functions + + set +e + tcsd_output=$(start_tcsd) + tcsd_result=$? + set -e + + if [ $tcsd_result -ne 0 ]; then + if [ -n "$tcsd_output" ]; then + echo "Unable to start TCSD: $tcsd_output" >&2 + else + echo "Unable to start TCSD" >&2 + fi + fi +} + +tpm1cfg_attempted=0 + +tried= while true; do - for d in $(to_unlock); do + for d in $(to_unlock $tried); do + tried="${tried} ${d}" + + if [ $tpm1cfg_attempted -eq 0 ] && has_tpm1_pin "${d}"; then + tpm1cfg_attempted=1 + do_configure_tpm1 + fi + uuid="$(cryptsetup luksUUID "${d}")" if ! clevis luks unlock -d "${d}"; then echo "Unable to unlock ${d} (UUID=${uuid})" >&2 @@ -63,10 +110,10 @@ while true; do done [ "${loop}" != true ] && break + # Checking for pending devices to be unlocked. - if remaining=$(to_unlock) && [ -z "${remaining}" ]; then - break; - fi + remaining=$(to_unlock $tried) + [ -z "${remaining}" ] && break sleep 0.5 done diff --git a/src/luks/dracut/clevis/meson.build b/src/luks/dracut/clevis/meson.build index b05bc101..ba745ec3 100644 --- a/src/luks/dracut/clevis/meson.build +++ b/src/luks/dracut/clevis/meson.build @@ -17,7 +17,12 @@ if dracut.found() configuration: data, ) - install_data('clevis-luks-unlocker', install_dir: libexecdir) + configure_file( + input: 'clevis-luks-unlocker.in', + output: 'clevis-luks-unlocker', + install_dir: libexecdir, + configuration: data, + ) else warning('Will not install dracut module due to missing dependencies!') endif diff --git a/src/luks/dracut/clevis/module-setup.sh.in b/src/luks/dracut/clevis/module-setup.sh.in index 50547a52..71b1d3ff 100755 --- a/src/luks/dracut/clevis/module-setup.sh.in +++ b/src/luks/dracut/clevis/module-setup.sh.in @@ -19,7 +19,7 @@ # depends() { - local __depends=crypt + local __depends="crypt bash" if dracut_module_included "systemd"; then __depends=$(printf '%s systemd' "${__depends}") fi diff --git a/src/luks/dracut/meson.build b/src/luks/dracut/meson.build index 7ad5b14c..21aee0bc 100644 --- a/src/luks/dracut/meson.build +++ b/src/luks/dracut/meson.build @@ -1,5 +1,6 @@ subdir('clevis') subdir('clevis-pin-tang') +subdir('clevis-pin-tpm1') subdir('clevis-pin-tpm2') subdir('clevis-pin-sss') subdir('clevis-pin-null')