From b44e13e0029592934b3b690d736c073c08739bd6 Mon Sep 17 00:00:00 2001 From: Christoph Biedl Date: Sat, 28 Jan 2023 17:30:49 +0100 Subject: [PATCH] Implement a pin to store the key in a single file This is a very simple pin, and possibly rather for educational purposes: Store the jwk at a given place in the file system. --- src/pins/file/clevis-decrypt-file | 59 +++++++++++++++++++++ src/pins/file/clevis-encrypt-file | 65 ++++++++++++++++++++++++ src/pins/file/clevis-encrypt-file.1.adoc | 44 ++++++++++++++++ src/pins/file/dracut.module-setup.sh.in | 27 ++++++++++ src/pins/file/initramfs.in | 35 +++++++++++++ src/pins/file/meson.build | 46 +++++++++++++++++ src/pins/file/pin-file | 30 +++++++++++ src/pins/meson.build | 1 + 8 files changed, 307 insertions(+) create mode 100755 src/pins/file/clevis-decrypt-file create mode 100755 src/pins/file/clevis-encrypt-file create mode 100644 src/pins/file/clevis-encrypt-file.1.adoc create mode 100755 src/pins/file/dracut.module-setup.sh.in create mode 100755 src/pins/file/initramfs.in create mode 100644 src/pins/file/meson.build create mode 100755 src/pins/file/pin-file diff --git a/src/pins/file/clevis-decrypt-file b/src/pins/file/clevis-decrypt-file new file mode 100755 index 00000000..d1a06b08 --- /dev/null +++ b/src/pins/file/clevis-decrypt-file @@ -0,0 +1,59 @@ +#!/bin/bash + +set -eu + +# Copyright (c) 2020 Christoph Biedl +# Author: Christoph Biedl +# +# 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 . +# + +[ $# -eq 1 ] && [ "${1:-}" = "--summary" ] && exit 2 + +if [ -t 0 ] ; then + echo >&2 + echo 'Usage: clevis decrypt file < JWE > PLAINTEXT' >&2 + echo >&2 + exit 1 +fi + +read -d . hdr64 +if ! hdr="$(jose fmt --quote="$hdr64" --string --b64load --object --output=-)" ; then + echo 'JWE header corrupt' >&2 + exit 1 +fi + +if [ "$(jose fmt --json="$hdr" --get clevis --get pin --unquote=-)" != 'file' ] ; then + echo 'JWE pin mismatch!' >&2 + exit 1 +fi + +if ! name="$(jose fmt --json="$hdr" --get clevis --get file --get name --unquote=-)" ; then + echo 'JWE missing 'clevis.file.name' header parameter!' >&2 + exit 1 +fi + +if [ ! -f "$name" ] ; then + echo "Key file $name not found" >&2 + exit 1 +fi + +jwk="$(cat "$name")" + +if ! jose fmt --json="$jwk" --object --output=/dev/null 2>/dev/null ; then + echo "Key file $name is malformed" >&2 + exit 1 +fi + +( printf '%s' "$jwk$hdr64." ; cat ) | exec jose jwe dec --key=- --input=- diff --git a/src/pins/file/clevis-encrypt-file b/src/pins/file/clevis-encrypt-file new file mode 100755 index 00000000..b1bfac4e --- /dev/null +++ b/src/pins/file/clevis-encrypt-file @@ -0,0 +1,65 @@ +#!/bin/sh + +set -eu + +# Copyright (c) 2020 Christoph Biedl +# Author: Christoph Biedl +# +# 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 . +# + +SUMMARY='Encrypts using a jwk stored in a file policy' + +if [ "${1:-}" = '--summary' ] ; then + echo "$SUMMARY" + exit 0 +fi + +if [ -t 0 ] ; then + exec >&2 + echo + echo 'Usage: clevis encrypt file CONFIG < PLAINTEXT > JWE' + echo + echo "$SUMMARY" + echo + echo 'his command uses the following configuration properties:' + echo + echo ' name: The file that holds the encryption key (REQUIRED)' + echo + exit 2 +fi + +if ! cfg="$(jose fmt --json="$1" --object --output=- 2>/dev/null)" ; then + echo 'Configuration is malformed!' >&2 + exit 1 +fi + +if ! name="$(jose fmt --json="$cfg" --object --get name --unquote=-)" ; then + echo 'Missing the required name property!' >&2 + exit 1 +fi + +if [ -e "$name" ] ; then + echo "File $name already exists" >&2 + exit 1 +fi + +jwk="$(jose jwk gen --input='{"alg":"A256GCM"}')" + +( umask 0377 ; echo "$jwk" >"$name" ) + +jwe='{"protected":{"clevis":{"pin":"file","file":{}}}}' +jwe="$(jose fmt --json="$jwe" --get protected --get clevis --get file --quote "$name" --set name -UUUU --output=-)" + +( printf '%s' "$jwe$jwk" ; cat ) | exec jose jwe enc --input=- --key=- --detached=- --compact diff --git a/src/pins/file/clevis-encrypt-file.1.adoc b/src/pins/file/clevis-encrypt-file.1.adoc new file mode 100644 index 00000000..bc898689 --- /dev/null +++ b/src/pins/file/clevis-encrypt-file.1.adoc @@ -0,0 +1,44 @@ +CLEVIS-ENCRYPT-FILE(1) +====================== +:doctype: manpage + + +== NAME + +clevis-encrypt-file - Encrypts using a file policy + +== SYNOPSIS + +*clevis encrypt file* CONFIG < PT > JWE + +== OVERVIEW + +The *clevis encrypt file* command encrypts using a file policy. +Its only argument is the JSON configuration object. + +Encrypting data using the file pin works like this: + + $ clevis encrypt file '{"name":"/path/to/file"}' < PT > JWE + +The given file must not exist yet. + +To decrypt the data, just pass it to the *clevis decrypt* command: + + $ clevis decrypt < JWE > PT + +== CONFIG + +This command uses the following configuration properties: + +* *name* (string) : + The name to the file where the jwk is stored (REQUIRED) + +== BUGS + +Requires that directories for that file already exist. + +Rather for educational purposes. + +== SEE ALSO + +link:clevis-decrypt.1.adoc[*clevis-decrypt*(1)] diff --git a/src/pins/file/dracut.module-setup.sh.in b/src/pins/file/dracut.module-setup.sh.in new file mode 100755 index 00000000..765bfb0f --- /dev/null +++ b/src/pins/file/dracut.module-setup.sh.in @@ -0,0 +1,27 @@ +#!/bin/sh +# +# Copyright (c) 2020 Christoph Biedl +# Author: Christoph Biedl +# +# 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 . +# + +depends() { + echo clevis + return 0 +} + +install() { + inst clevis-decrypt-file +} diff --git a/src/pins/file/initramfs.in b/src/pins/file/initramfs.in new file mode 100755 index 00000000..77f9afd1 --- /dev/null +++ b/src/pins/file/initramfs.in @@ -0,0 +1,35 @@ +#!/bin/sh +# +# Copyright (c) 2020 Christoph Biedl +# Author: Christoph Biedl +# +# 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 . +# + +case $1 in +prereqs) + exit 0 + ;; +esac + +. @initramfstoolsdir@/hook-functions + +die() { + code="$1" + msg="$2" + echo " (ERROR): $msg" >&2 + exit "$code" +} + +copy_exec @bindir@/clevis-decrypt-file || die 1 "@bindir@/clevis-decrypt-file not found" diff --git a/src/pins/file/meson.build b/src/pins/file/meson.build new file mode 100644 index 00000000..ff16acbf --- /dev/null +++ b/src/pins/file/meson.build @@ -0,0 +1,46 @@ + +dracut = dependency('dracut', required: false) +initramfs_tools = find_program('update-initramfs', required: false) + +bins += join_paths(meson.current_source_dir(), 'clevis-decrypt-file') +bins += join_paths(meson.current_source_dir(), 'clevis-encrypt-file') +mans += join_paths(meson.current_source_dir(), 'clevis-encrypt-file.1') + +env = environment() +env.append('PATH', + join_paths(meson.source_root(), 'src'), + meson.current_source_dir(), + '/usr/libexec', + libexecdir, + separator: ':' +) + +test('pin-file', find_program('./pin-file'), env: env) + +if dracut.found() + dracutdir = dracut.get_pkgconfig_variable('dracutmodulesdir') + '/60' + meson.project_name() + '-pin-file' + configure_file( + input: 'dracut.module-setup.sh.in', + output: 'module-setup.sh', + install_dir: dracutdir, + configuration: data, + ) +else + warning('Will not install dracut module clevis-pin-file due to missing dependencies!') +endif + +if initramfs_tools.found() + initramfstools_dir = '/usr/share/initramfs-tools' + initramfs_hooks_dir = '/usr/share/initramfs-tools/hooks' + initramfs_data = configuration_data() + initramfs_data.merge_from(data) + initramfs_data.set('initramfstoolsdir', initramfstools_dir) + configure_file( + input: 'initramfs.in', + output: 'clevis-pin-file', + install_dir: initramfs_hooks_dir, + configuration: initramfs_data, + ) +else + warning('Will not install initramfs module clevis-pin-file due to missing dependencies!') +endif diff --git a/src/pins/file/pin-file b/src/pins/file/pin-file new file mode 100755 index 00000000..887b946e --- /dev/null +++ b/src/pins/file/pin-file @@ -0,0 +1,30 @@ +#!/bin/sh + +set -e + +# Copyright (c) 2020 Christoph Biedl +# Author: Christoph Biedl +# +# 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 . +# + +TMP="$(mktemp -d)" +# shellcheck disable=SC2064 # Expanding TMP right now is intended +trap "rm -rf \"$TMP\"" EXIT + +cfg="$(printf '{"name":"%s"}' "$TMP/key")" +inp='hi' +enc="$(printf '%s' "$inp" | clevis encrypt file "$cfg")" +dec="$(printf '%s' "$enc" | clevis decrypt)" +test "$dec" = "$inp" diff --git a/src/pins/meson.build b/src/pins/meson.build index 12670ae8..20edfa72 100644 --- a/src/pins/meson.build +++ b/src/pins/meson.build @@ -1,3 +1,4 @@ +subdir('file') subdir('sss') subdir('tang') subdir('tpm2')