From 99f7903c26e1cb0103b8d1e5b3f6fbc1574abbf7 Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Sun, 5 Jan 2025 20:04:46 +0300 Subject: [PATCH] initial commit --- 47sshd-tpm/module-setup.sh | 83 ++++++++++++++++++++++++++++++++++++++ 47sshd-tpm/unseal.service | 13 ++++++ 47sshd-tpm/unseal.sh | 16 ++++++++ README.md | 18 +++++++++ config | 13 ++++++ dracut-sshd-tpm.spec | 33 +++++++++++++++ 6 files changed, 176 insertions(+) create mode 100644 47sshd-tpm/module-setup.sh create mode 100644 47sshd-tpm/unseal.service create mode 100755 47sshd-tpm/unseal.sh create mode 100644 README.md create mode 100644 config create mode 100644 dracut-sshd-tpm.spec diff --git a/47sshd-tpm/module-setup.sh b/47sshd-tpm/module-setup.sh new file mode 100644 index 0000000..9c4f6c8 --- /dev/null +++ b/47sshd-tpm/module-setup.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +check() { + require_binaries openssl && + require_binaries tpm2_createprimary && + require_binaries tpm2_pcrread && + require_binaries tpm2_createpolicy && + require_binaries tpm2_create && + require_binaries tpm2_unseal || + return 1 +} + +depends() { + echo tpm2-tss + echo sshd +} + +seal() { + set -e + + cd "$tpm_tempdir" + touch key ; chmod 600 key + + # generate 256-bit key + openssl rand 32 > key + + # create TPM primary context + tpm2_createprimary -Q -c primary.ctx + + # gather PCR state + if [ -n "$tpm_pcr_bin" ]; then + dinfo "copying ${tpm_pcr_bin@Q}" + cp "$tpm_pcr_bin" pcr.bin + else + dinfo "reading current PCRs" + tpm2_pcrread -o pcr.bin "${tpm_pcrs?TPM PCR list is required}" + fi + + # create policy with the PCR information + tpm2_createpolicy -Q --policy-pcr -l "$tpm_pcrs" -f pcr.bin -L pcr.policy + + # seal the encryption key in the TPM + tpm2_create -Q -C primary.ctx -L pcr.policy -i key -c key.ctx + + # copy sealed encryption key and relevant information to the initramfs + /usr/bin/install -Dm 644 key.ctx "${initdir}/etc/ssh/key.ctx" + echo "$tpm_pcrs" > "${initdir}/etc/ssh/pcrs" + + cd "${initdir}/etc/ssh" + + # encrypt keys + for key in ssh_host_*_key; do + openssl aes-256-cbc -e -in "$key" -out "${key}.enc" -kfile "${tpm_tempdir}/key" -iter 1 + done +} + +install() { + local conffile=${dracutsysrootdir}/etc/default/dracut-sshd-tpm + [ -f "$conffile" ] && . "$conffile" + + local tpm_tempdir=$(mktemp -d) + chmod 700 "$tpm_tempdir" + ( seal ) || { + dfatal "Couldn't seal keys!" + rm -rf "$tpm_tempdir" + return 1 + } + rm -rf "$tpm_tempdir" + + # remove unencrypted keys + rm "$initdir"/etc/ssh/ssh_host_*_key + + inst_binary /usr/bin/touch + inst_binary /usr/bin/chmod + inst_binary /usr/bin/openssl + inst_binary /usr/bin/basename + inst_binary /usr/bin/tpm2_unseal + inst_simple "${moddir}/unseal.sh" /usr/sbin/unseal.sh + inst_simple "${moddir}/unseal.service" "${systemdsystemunitdir}/unseal.service" + mkdir -p "${initdir}${systemdsystemconfdir}/sshd.service.requires" + ln -s "${systemdsystemunitdir}/unseal.service" "${initdir}${systemdsystemconfdir}/sshd.service.requires" +} + diff --git a/47sshd-tpm/unseal.service b/47sshd-tpm/unseal.service new file mode 100644 index 0000000..23d50b0 --- /dev/null +++ b/47sshd-tpm/unseal.service @@ -0,0 +1,13 @@ +[Unit] +Description=Unseal OpenSSH host keys +DefaultDependencies=no +Before=sshd.service +After=tpm2.target +Requires=tpm2.target + +[Service] +Type=oneshot +ExecStart=/usr/sbin/unseal.sh + +[Install] +RequiredBy=sshd.service diff --git a/47sshd-tpm/unseal.sh b/47sshd-tpm/unseal.sh new file mode 100755 index 0000000..180570c --- /dev/null +++ b/47sshd-tpm/unseal.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e + +cd /etc/ssh + +touch key +chmod 600 key +tpm2_unseal -c key.ctx -p pcr:"$(cat pcrs)" -o key + +for enc in *.enc; do + base="${enc%.enc}" + touch "$base" + chmod 600 "$base" + openssl aes-256-cbc -d -in "$enc" -out "$base" -kfile key -iter 1 +done diff --git a/README.md b/README.md new file mode 100644 index 0000000..38f1aaf --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# dracut-sshd-tpm + +TPM sealing of [dracut-sshd](https://github.com/gsauthof/dracut-sshd) host keys + +## Configuration + +The default configuration is placed into /etc/default/dracut-sshd-tpm. You will +need to configure, at minimum, which registers to use while sealing the host +keys (the `tpm_pcrs` value). + +## Building + +```sh +dnf install rpkg git +git clone https://git.slonk.ing/slonk/dracut-sshd-tpm +cd dracut-sshd-tpm +rpkg local +``` diff --git a/config b/config new file mode 100644 index 0000000..266eff8 --- /dev/null +++ b/config @@ -0,0 +1,13 @@ +# TPM PCRs (platform control registers) to reference while sealing host keys +# See ArchWiki for a list of registers: +# https://wiki.archlinux.org/title/Trusted_Platform_Module#Accessing_PCR_registers +# Example: `sha256:0,4` +# Required, must be consistent across reboots. +#tpm_pcrs= + +# Path to PCR dump to use while creating TPM policy +# The next boot's registers must match for the keys to be unsealed +# You can dump the current ones with the following command: +# root@fedora:~# tpm2_pcrread -o pcr.bin "$tpm_pcrs" +# Not required, will default to reading current register values. +#tpm_pcr_bin= diff --git a/dracut-sshd-tpm.spec b/dracut-sshd-tpm.spec new file mode 100644 index 0000000..d9dda9c --- /dev/null +++ b/dracut-sshd-tpm.spec @@ -0,0 +1,33 @@ +# vim: syntax=spec +Name: dracut-sshd-tpm +Version: {{{ git_dir_version }}} +Release: 1%{?dist} +Summary: TPM sealing of dracut-sshd host keys +License: MIT +URL: https://git.slonk.ing/slonk/dracut-sshd-tpm +VCS: {{{ git_dir_vcs }}} +Source: {{{ git_dir_pack }}} +BuildArch: noarch +Requires: dracut-sshd tpm2-tools openssl + +%description +Seals the SSH host keys used by dracut-sshd using the TPM, +and unseals them before sshd starts up. + +%prep +{{{ git_dir_setup_macro }}} + +%install +mkdir -p %{buildroot}/usr/lib/dracut/modules.d +cp -r 47sshd-tpm %{buildroot}/usr/lib/dracut/modules.d +install -Dt %{buildroot}/etc/default/dracut-sshd-tpm -m644 config + +%files +%dir /usr/lib/dracut/modules.d/47sshd-tpm +/usr/lib/dracut/modules.d/47sshd-tpm/module-setup.sh +/usr/lib/dracut/modules.d/47sshd-tpm/unseal.service +/usr/lib/dracut/modules.d/47sshd-tpm/unseal.sh +%config /etc/default/dracut-sshd-tpm + +%changelog +{{{ git_dir_changelog }}}