import clevis-13-3.el8

This commit is contained in:
CentOS Sources 2020-11-03 06:59:47 -05:00 committed by Andrew Lukoshko
parent f52f3d98ab
commit b2e84aface
24 changed files with 3293 additions and 2475 deletions

View File

@ -1 +1 @@
086374814a4d71db8625d27a1719e03244a7cff0 SOURCES/clevis-11.tar.xz 83aebcbe5792b43bf281b442f379cea08d7c43b0 SOURCES/clevis-13.tar.xz

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/clevis-11.tar.xz SOURCES/clevis-13.tar.xz

View File

@ -0,0 +1,84 @@
From 27a27befed2257c2156ed8b94d679951b9b1a4d5 Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Wed, 13 May 2020 23:51:04 -0300
Subject: [PATCH 1/8] Adjust pin-tang test to account for newer tang without
tangd-update
---
src/luks/tests/unbind-unbound-slot-luks2 | 1 +
src/pins/tang/meson.build | 8 +-------
src/pins/tang/pin-tang | 11 ++++++++---
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/luks/tests/unbind-unbound-slot-luks2 b/src/luks/tests/unbind-unbound-slot-luks2
index 6a2aca5..6d814ad 100755
--- a/src/luks/tests/unbind-unbound-slot-luks2
+++ b/src/luks/tests/unbind-unbound-slot-luks2
@@ -36,6 +36,7 @@ TMP="$(mktemp -d)"
DEV="${TMP}/luks2-device"
new_device "luks2" "${DEV}"
+SLT=2
if clevis luks unbind -d "${DEV}" -s "${SLT}"; then
error "${TEST}: Unbind is expected to fail for device ${DEV} and slot ${SLT}" >&2
fi
diff --git a/src/pins/tang/meson.build b/src/pins/tang/meson.build
index 74a3442..9b9a3db 100644
--- a/src/pins/tang/meson.build
+++ b/src/pins/tang/meson.build
@@ -9,12 +9,6 @@ kgen = find_program(
'/usr/lib/x86_64-linux-gnu/tangd-keygen',
required: false
)
-updt = find_program(
- join_paths(libexecdir, 'tangd-update'),
- '/usr/libexec/tangd-update',
- '/usr/lib/x86_64-linux-gnu/tangd-update',
- required: false
-)
tang = find_program(
join_paths(libexecdir, 'tangd'),
'/usr/libexec/tangd',
@@ -28,7 +22,7 @@ if curl.found()
bins += join_paths(meson.current_source_dir(), 'clevis-encrypt-tang')
mans += join_paths(meson.current_source_dir(), 'clevis-encrypt-tang.1')
- if actv.found() and kgen.found() and updt.found() and tang.found()
+ if actv.found() and kgen.found() and tang.found()
env = environment()
env.set('SD_ACTIVATE', actv.path())
env.append('PATH',
diff --git a/src/pins/tang/pin-tang b/src/pins/tang/pin-tang
index 1720d3d..8190f3d 100755
--- a/src/pins/tang/pin-tang
+++ b/src/pins/tang/pin-tang
@@ -31,18 +31,23 @@ mkdir -p "$TMP"/db
mkdir -p "$TMP"/cache
# Generate the server keys
+KEYS="$TMP"/db
tangd-keygen "$TMP"/db sig exc
-tangd-update "$TMP"/db "$TMP"/cache
+if which tangd-update; then
+ tangd-update "$TMP"/db "$TMP"/cache
+ KEYS=$TMP/cache
+fi
# Start the server
port="$(shuf -i 1024-65536 -n 1)"
-$SD_ACTIVATE --inetd -l 127.0.0.1:$port -a tangd "$TMP"/cache &
+$SD_ACTIVATE --inetd -l 127.0.0.1:$port -a tangd "$KEYS" &
PID=$!
sleep 0.25
thp="$(jose jwk thp -i "$TMP/db/sig.jwk")"
-adv="$TMP/cache/default.jws"
url="http://localhost:${port}"
+adv="$TMP/adv"
+curl "$url/adv" -o $adv
cfg="$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv")"
enc="$(echo -n "hi" | clevis encrypt tang "$cfg")"
--
2.18.4

View File

@ -0,0 +1,732 @@
From e5f6d87d5c71f3faf0c0dbe38534fd3eab30f43e Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Wed, 13 May 2020 23:51:04 -0300
Subject: [PATCH 2/8] Fix clevis luks unlock and add related tests
---
src/luks/clevis-luks-common-functions | 35 ++++++
src/luks/clevis-luks-unlock | 68 ++++++++++++
src/luks/clevis-luks-unlock.in | 130 ----------------------
src/luks/meson.build | 10 +-
src/luks/tests/meson.build | 40 +++++++
src/luks/tests/tests-common-functions.in | 134 +++++++++++++++++++++--
src/luks/tests/unlock-tang-luks1 | 83 ++++++++++++++
src/luks/tests/unlock-tang-luks2 | 83 ++++++++++++++
8 files changed, 439 insertions(+), 144 deletions(-)
create mode 100755 src/luks/clevis-luks-unlock
delete mode 100755 src/luks/clevis-luks-unlock.in
create mode 100755 src/luks/tests/unlock-tang-luks1
create mode 100755 src/luks/tests/unlock-tang-luks2
diff --git a/src/luks/clevis-luks-common-functions b/src/luks/clevis-luks-common-functions
index e27c444..d04fdb5 100644
--- a/src/luks/clevis-luks-common-functions
+++ b/src/luks/clevis-luks-common-functions
@@ -281,3 +281,38 @@ clevis_luks_read_pins_from_slot() {
fi
printf "%s: %s\n" "${SLOT}" "${cfg}"
}
+
+# clevis_luks_unlock_device() does the unlock of the device passed as
+# parameter and returns the decoded passphrase.
+clevis_luks_unlock_device() {
+ local DEV="${1}"
+ [ -z "${DEV}" ] && return 1
+
+ local used_slots
+ if ! used_slots=$(clevis_luks_used_slots "${DEV}") \
+ || [ -z "${used_slots}" ]; then
+ return 1
+ fi
+
+ local slt jwe passphrase
+ for slt in ${used_slots}; do
+ if ! jwe="$(clevis_luks_read_slot "${DEV}" "${slt}" 2>/dev/null)" \
+ || [ -z "${jwe}" ]; then
+ continue
+ fi
+
+ if ! passphrase="$(clevis decrypt < <(echo -n "${jwe}"))" \
+ || [ -z "${passphrase}" ]; then
+ continue
+ fi
+
+ if ! cryptsetup luksOpen --test-passphrase "${DEV}" \
+ --key-file <(echo -n "${passphrase}"); then
+ continue
+ fi
+ echo -n "${passphrase}"
+ return 0
+ done
+
+ return 1
+}
diff --git a/src/luks/clevis-luks-unlock b/src/luks/clevis-luks-unlock
new file mode 100755
index 0000000..580fde8
--- /dev/null
+++ b/src/luks/clevis-luks-unlock
@@ -0,0 +1,68 @@
+#!/bin/bash -e
+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2016 Red Hat, Inc.
+# Author: Nathaniel McCallum <npmccallum@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+. clevis-luks-common-functions
+
+SUMMARY="Unlocks a LUKS volume"
+
+function usage() {
+ exec >&2
+ echo
+ echo "Usage: clevis luks unlock -d DEV [-n NAME]"
+ echo
+ echo "$SUMMARY":
+ echo
+ echo " -d DEV The LUKS device on which to perform unlocking"
+ echo
+ echo " -n NAME The name of the unlocked device node"
+ echo
+ exit 2
+}
+
+if [ $# -eq 1 ] && [ "$1" == "--summary" ]; then
+ echo "$SUMMARY"
+ exit 0
+fi
+
+while getopts ":d:n:" o; do
+ case "$o" in
+ d) DEV="$OPTARG";;
+ n) NAME="$OPTARG";;
+ *) usage;;
+ esac
+done
+
+if [ -z "$DEV" ]; then
+ echo "Did not specify a device!" >&2
+ usage
+fi
+
+if ! cryptsetup isLuks "$DEV"; then
+ echo "$DEV is not a LUKS device!" >&2
+ exit 1
+fi
+
+NAME="${NAME:-luks-"$(cryptsetup luksUUID "$DEV")"}"
+
+if ! pt=$(clevis_luks_unlock_device "${DEV}"); then
+ echo "${DEV} could not be opened." >&2
+ exit 1
+fi
+
+cryptsetup open -d- "${DEV}" "${NAME}" < <(echo -n "${pt}")
diff --git a/src/luks/clevis-luks-unlock.in b/src/luks/clevis-luks-unlock.in
deleted file mode 100755
index aa3134b..0000000
--- a/src/luks/clevis-luks-unlock.in
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/bin/bash -e
-# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
-#
-# Copyright (c) 2016 Red Hat, Inc.
-# Author: Nathaniel McCallum <npmccallum@redhat.com>
-#
-# 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 <http://www.gnu.org/licenses/>.
-#
-
-SUMMARY="Unlocks a LUKS volume"
-UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
-
-# We require cryptsetup >= 2.0.4 to fully support LUKSv2.
-# Support is determined at build time.
-function luks2_supported() {
- return @OLD_CRYPTSETUP@
-}
-
-function usage() {
- exec >&2
- echo
- echo "Usage: clevis luks unlock -d DEV [-n NAME]"
- echo
- echo "$SUMMARY":
- echo
- echo " -d DEV The LUKS device on which to perform unlocking"
- echo
- echo " -n NAME The name of the unlocked device node"
- echo
- exit 2
-}
-
-if [ $# -eq 1 ] && [ "$1" == "--summary" ]; then
- echo "$SUMMARY"
- exit 0
-fi
-
-while getopts ":d:n:" o; do
- case "$o" in
- d) DEV="$OPTARG";;
- n) NAME="$OPTARG";;
- *) usage;;
- esac
-done
-
-if [ -z "$DEV" ]; then
- echo "Did not specify a device!" >&2
- usage
-fi
-
-if ! cryptsetup isLuks "$DEV"; then
- echo "$DEV is not a LUKS device!" >&2
- exit 1
-fi
-
-if luks2_supported; then
- if cryptsetup isLuks --type luks1 "$DEV"; then
- luks_type="luks1"
- elif cryptsetup isLuks --type luks2 "$DEV";then
- luks_type="luks2"
- else
- echo "$DEV is not a supported LUKS device!" >&2
- exit 1
- fi
-else
- luks_type="luks1"
-fi
-NAME="${NAME:-luks-"$(cryptsetup luksUUID "$DEV")"}"
-
-luks1_decrypt() {
- luksmeta load "$@" \
- | clevis decrypt
-
- local rc
- for rc in "${PIPESTATUS[@]}"; do
- [ $rc -eq 0 ] || return $rc
- done
- return 0
-}
-
-luks2_decrypt() {
- # jose jwe fmt -c outputs extra \n, so clean it up
- cryptsetup token export "$@" \
- | jose fmt -j- -Og jwe -o- \
- | jose jwe fmt -i- -c \
- | tr -d '\n' \
- | clevis decrypt
-
- local rc
- for rc in "${PIPESTATUS[@]}"; do
- [ $rc -eq 0 ] || return $rc
- done
- return 0
-}
-
-if [ "$luks_type" == "luks1" ]; then
- while read -r slot state uuid; do
- [ "$state" == "active" ] || continue
- [ "$uuid" == "$UUID" ] || continue
-
- pt="$(luks1_decrypt -d $DEV -s $slot -u $UUID)" \
- || continue
- exec cryptsetup open -d- "$DEV" "$NAME" < <(
- echo -n "$pt"
- )
- done < <(luksmeta show -d "$DEV")
-
-elif [ "$luks_type" == "luks2" ]; then
- while read -r id; do
- pt="$(luks2_decrypt --token-id "$id" "$DEV")" \
- || continue
- exec cryptsetup open -d- "$DEV" "$NAME" < <(
- echo -n "$pt"
- )
- done < <(cryptsetup luksDump "$DEV" | sed -rn 's|^\s+([0-9]+): clevis|\1|p')
-fi
-
-echo "$DEV could not be opened." >&2
-exit 1
diff --git a/src/luks/meson.build b/src/luks/meson.build
index bbba63f..0d24f8d 100644
--- a/src/luks/meson.build
+++ b/src/luks/meson.build
@@ -21,9 +21,7 @@ clevis_luks_bind = configure_file(input: 'clevis-luks-bind.in',
clevis_luks_unbind = configure_file(input: 'clevis-luks-unbind.in',
output: 'clevis-luks-unbind',
configuration: luksmeta_data)
-clevis_luks_unlock = configure_file(input: 'clevis-luks-unlock.in',
- output: 'clevis-luks-unlock',
- configuration: luksmeta_data)
+
if libcryptsetup.found() and luksmeta.found() and pwmake.found()
subdir('systemd')
subdir('udisks2')
@@ -31,18 +29,18 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found()
bins += clevis_luks_unbind
mans += join_paths(meson.current_source_dir(), 'clevis-luks-unbind.1')
- bins += clevis_luks_unlock
- mans += join_paths(meson.current_source_dir(), 'clevis-luks-unlock.1')
-
bins += clevis_luks_bind
mans += join_paths(meson.current_source_dir(), 'clevis-luks-bind.1')
mans += join_paths(meson.current_source_dir(), 'clevis-luks-unlockers.7')
bins += join_paths(meson.current_source_dir(), 'clevis-luks-common-functions')
+
bins += join_paths(meson.current_source_dir(), 'clevis-luks-list')
mans += join_paths(meson.current_source_dir(), 'clevis-luks-list.1')
+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-unlock')
+ mans += join_paths(meson.current_source_dir(), 'clevis-luks-unlock.1')
else
warning('Will not install LUKS support due to missing dependencies!')
endif
diff --git a/src/luks/tests/meson.build b/src/luks/tests/meson.build
index 2e0fb92..9a16b42 100644
--- a/src/luks/tests/meson.build
+++ b/src/luks/tests/meson.build
@@ -1,6 +1,30 @@
# We use jq for comparing the pin config in the clevis luks list tests.
jq = find_program('jq', required: false)
+# we use systemd-socket-activate for running test tang servers.
+actv = find_program(
+ 'systemd-socket-activate',
+ 'systemd-activate',
+ required: false
+)
+
+kgen = find_program(
+ join_paths(libexecdir, 'tangd-keygen'),
+ join_paths(get_option('prefix'), get_option('libdir'), 'tangd-keygen'),
+ join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd-keygen'),
+ join_paths('/', 'usr', get_option('libdir'), 'tangd-keygen'),
+ join_paths('/', 'usr', get_option('libexecdir'), 'tangd-keygen'),
+ required: false
+)
+tang = find_program(
+ join_paths(libexecdir, 'tangd'),
+ join_paths(get_option('prefix'), get_option('libdir'), 'tangd'),
+ join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd'),
+ join_paths('/', 'usr', get_option('libdir'), 'tangd'),
+ join_paths('/', 'usr', get_option('libexecdir'), 'tangd'),
+ required: false
+)
+
common_functions = configure_file(input: 'tests-common-functions.in',
output: 'tests-common-functions',
configuration: luksmeta_data,
@@ -24,6 +48,14 @@ env.prepend('PATH',
separator: ':'
)
+has_tang = false
+if actv.found() and kgen.found() and tang.found()
+ has_tang = true
+ env.set('SD_ACTIVATE', actv.path())
+ env.set('TANGD_KEYGEN', kgen.path())
+ env.set('TANGD', tang.path())
+endif
+
test('bind-wrong-pass-luks1', find_program('bind-wrong-pass-luks1'), env: env)
test('bind-luks1', find_program('bind-luks1'), env: env)
test('unbind-unbound-slot-luks1', find_program('unbind-unbound-slot-luks1'), env: env)
@@ -42,6 +74,10 @@ else
warning('Will not run "clevis luks list" tests due to missing jq dependency')
endif
+if has_tang
+ test('unlock-tang-luks1', find_program('unlock-tang-luks1'), env: env, timeout: 90)
+endif
+
# LUKS2 tests go here, and they get included if we get support for it, based
# on the cryptsetup version.
# Binding LUKS2 takes longer, so timeout is increased for a few tests.
@@ -56,4 +92,8 @@ if luksmeta_data.get('OLD_CRYPTSETUP') == '0'
test('list-tang-luks2', find_program('list-tang-luks2'), env: env, timeout: 60)
test('list-sss-tang-luks2', find_program('list-sss-tang-luks2'), env: env, timeout: 60)
endif
+
+ if has_tang
+ test('unlock-tang-luks2', find_program('unlock-tang-luks2'), env: env, timeout: 120)
+ endif
endif
diff --git a/src/luks/tests/tests-common-functions.in b/src/luks/tests/tests-common-functions.in
index 90420d1..7b3fdad 100755
--- a/src/luks/tests/tests-common-functions.in
+++ b/src/luks/tests/tests-common-functions.in
@@ -56,7 +56,7 @@ new_device() {
# Some builders fail if the cryptsetup steps are not ran as root, so let's
# skip the test now if not running as root.
- if [ $(id -u) != 0 ]; then
+ if [ "$(id -u)" != 0 ]; then
skip_test "WARNING: You must be root to run this test; test skipped."
fi
@@ -74,9 +74,9 @@ new_device() {
return 0
fi
- fallocate -l16M "${DEV}"
- local extra_options='--pbkdf pbkdf2 --pbkdf-force-iterations 1000'
- cryptsetup luksFormat --type "${LUKS}" ${extra_options} --batch-mode \
+ fallocate -l64M "${DEV}"
+ cryptsetup luksFormat --type "${LUKS}" --pbkdf pbkdf2 \
+ --pbkdf-force-iterations 1000 --batch-mode \
--force-password "${DEV}" <<< "${PASS}"
# Caching the just-formatted device for possible reuse.
cp -f "${DEV}" "${DEV_CACHED}"
@@ -90,7 +90,7 @@ new_device_keyfile() {
# Some builders fail if the cryptsetup steps are not ran as root, so let's
# skip the test now if not running as root.
- if [ $(id -u) != 0 ]; then
+ if [ "$(id -u)" != 0 ]; then
skip_test "WARNING: You must be root to run this test; test skipped."
fi
@@ -98,9 +98,9 @@ new_device_keyfile() {
error "Invalid keyfile (${KEYFILE})."
fi
- fallocate -l16M "${DEV}"
- local extra_options='--pbkdf pbkdf2 --pbkdf-force-iterations 1000'
- cryptsetup luksFormat --type "${LUKS}" ${extra_options} --batch-mode \
+ fallocate -l64M "${DEV}"
+ cryptsetup luksFormat --type "${LUKS}" --pbkdf pbkdf2 \
+ --pbkdf-force-iterations 1000 --batch-mode \
"${DEV}" "${KEYFILE}"
}
@@ -112,4 +112,122 @@ pin_cfg_equal() {
<(jq -S . < <(echo -n "${cfg2}"))
}
+# Get a random port to be used with a test tang server.
+get_random_port() {
+ shuf -i 1024-65535 -n 1
+}
+
+# Removes tang rotated keys from the test server.
+tang_remove_rotated_keys() {
+ local basedir="${1}"
+
+ if [ -z "${basedir}" ]; then
+ echo "Please pass a valid base directory for tang"
+ return 1
+ fi
+
+ local db="${basedir}/db"
+ mkdir -p "${db}"
+
+ pushd "${db}"
+ find . -name ".*.jwk" -exec rm -f {} \;
+ popd
+}
+
+# Creates new keys for the test tang server.
+tang_new_keys() {
+ local basedir="${1}"
+ local rotate="${2}"
+
+ if [ -z "${basedir}" ]; then
+ echo "Please pass a valid base directory for tang"
+ return 1
+ fi
+
+ [ -z "${TANGD_KEYGEN}" ] && skip_test "WARNING: TANGD_KEYGEN is not defined."
+
+ local db="${basedir}/db"
+ mkdir -p "${db}"
+
+ if [ -n "${rotate}" ]; then
+ pushd "${db}"
+ local k
+ k=$(find . -name "*.jwk" | wc -l)
+ if [ "${k}" -gt 0 ]; then
+ for k in *.jwk; do
+ mv -f -- "${k}" ".${k}"
+ done
+ fi
+ popd
+ fi
+
+ "${TANGD_KEYGEN}" "${db}"
+
+ return 0
+}
+
+# Start a test tang server.
+tang_run() {
+ local basedir="${1}"
+ local port="${2}"
+
+ if [ -z "${basedir}" ]; then
+ echo "Please pass a valid base directory for tang" >&2
+ return 1
+ fi
+
+ if [ -z "${port}" ]; then
+ echo "Please pass a valid port for tang" >&2
+ return 1
+ fi
+
+ if ! tang_new_keys "${basedir}"; then
+ echo "Error creating new keys for tang server" >&2
+ return 1
+ fi
+
+ local KEYS="${basedir}/db"
+
+ local inetd='--inetd'
+ [ "${SD_ACTIVATE##*/}" = "systemd-activate" ] && inetd=
+
+ local pid pidfile
+ pidfile="${basedir}/tang.pid"
+
+ "${SD_ACTIVATE}" ${inetd} -l "${TANG_HOST}":"${port}" \
+ -a "${TANGD}" "${KEYS}" &
+ pid=$!
+ echo "${pid}" > "${pidfile}"
+}
+
+# Stop tang server.
+tang_stop() {
+ local basedir="${1}"
+ local pidfile="${basedir}/tang.pid"
+ [ -f "${pidfile}" ] || return 0
+
+ local pid
+ pid=$(<"${pidfile}")
+ kill "${pid}"
+}
+
+# Wait for the tang server to be operational.
+tang_wait_until_ready() {
+ local port="${1}"
+ while ! curl --output /dev/null --silent --fail \
+ http://"${TANG_HOST}":"${port}"/adv; do
+ sleep 0.1
+ echo -n . >&2
+ done
+}
+
+# Get tang advertisement.
+tang_get_adv() {
+ local port="${1}"
+ local adv="${2}"
+
+ curl -o "${adv}" http://"${TANG_HOST}":"${port}"/adv
+}
+
+export TANG_HOST=127.0.0.1
export DEFAULT_PASS='just-some-test-password-here'
diff --git a/src/luks/tests/unlock-tang-luks1 b/src/luks/tests/unlock-tang-luks1
new file mode 100755
index 0000000..841ba01
--- /dev/null
+++ b/src/luks/tests/unlock-tang-luks1
@@ -0,0 +1,83 @@
+#!/bin/bash -ex
+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2020 Red Hat, Inc.
+# Author: Sergio Correia <scorreia@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+TEST=$(basename "${0}")
+. tests-common-functions
+
+. clevis-luks-common-functions
+
+on_exit() {
+ [ ! -d "${TMP}" ] && return 0
+ tang_stop "${TMP}"
+ rm -rf "${TMP}"
+}
+
+trap 'on_exit' EXIT
+trap 'on_exit' ERR
+
+TMP="$(mktemp -d)"
+
+port=$(get_random_port)
+tang_run "${TMP}" "${port}" &
+tang_wait_until_ready "${port}"
+
+url="http://${TANG_HOST}:${port}"
+adv="${TMP}/adv"
+tang_get_adv "${port}" "${adv}"
+
+cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv")
+
+# LUKS1.
+DEV="${TMP}/luks1-device"
+new_device "luks1" "${DEV}"
+
+if ! clevis luks bind -f -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then
+ error "${TEST}: Bind should have succeeded."
+fi
+
+if ! clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we were unable to unlock ${DEV}."
+fi
+
+# Let's rotate the tang keys and add another binding with the new key.
+tang_new_keys "${TMP}" "rotate-keys"
+
+# Unlock should still work now.
+if ! clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we should still be able to unlock ${DEV}"
+fi
+
+# Now let's remove the rotated keys.
+tang_remove_rotated_keys "${TMP}"
+
+# Unlock should not work anymore.
+if clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we should not be able to unlock ${DEV}"
+fi
+
+# Now let's add another binding with the new keys.
+tang_get_adv "${port}" "${adv}" # Updating the advertisement.
+if ! clevis luks bind -f -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then
+ error "${TEST}: Bind should have succeeded."
+fi
+
+# Unlock should work again, using the new keys.
+if ! clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we should be able to unlock ${DEV} with the new keys"
+fi
diff --git a/src/luks/tests/unlock-tang-luks2 b/src/luks/tests/unlock-tang-luks2
new file mode 100755
index 0000000..81822fb
--- /dev/null
+++ b/src/luks/tests/unlock-tang-luks2
@@ -0,0 +1,83 @@
+#!/bin/bash -ex
+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2020 Red Hat, Inc.
+# Author: Sergio Correia <scorreia@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+TEST=$(basename "${0}")
+. tests-common-functions
+
+. clevis-luks-common-functions
+
+on_exit() {
+ [ ! -d "${TMP}" ] && return 0
+ tang_stop "${TMP}"
+ rm -rf "${TMP}"
+}
+
+trap 'on_exit' EXIT
+trap 'on_exit' ERR
+
+TMP="$(mktemp -d)"
+
+port=$(get_random_port)
+tang_run "${TMP}" "${port}" &
+tang_wait_until_ready "${port}"
+
+url="http://${TANG_HOST}:${port}"
+adv="${TMP}/adv"
+tang_get_adv "${port}" "${adv}"
+
+cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv")
+
+# LUKS2.
+DEV="${TMP}/luks2-device"
+new_device "luks2" "${DEV}"
+
+if ! clevis luks bind -f -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then
+ error "${TEST}: Bind should have succeeded."
+fi
+
+if ! clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we were unable to unlock ${DEV}."
+fi
+
+# Let's rotate the tang keys and add another binding with the new key.
+tang_new_keys "${TMP}" "rotate-keys"
+
+# Unlock should still work now.
+if ! clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we should still be able to unlock ${DEV}"
+fi
+
+# Now let's remove the rotated keys.
+tang_remove_rotated_keys "${TMP}"
+
+# Unlock should not work anymore.
+if clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we should not be able to unlock ${DEV}"
+fi
+
+# Now let's add another binding with the new keys.
+tang_get_adv "${port}" "${adv}" # Updating the advertisement.
+if ! clevis luks bind -f -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then
+ error "${TEST}: Bind should have succeeded."
+fi
+
+# Unlock should work again, using the new keys.
+if ! clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we should be able to unlock ${DEV} with the new keys"
+fi
--
2.18.4

View File

@ -0,0 +1,57 @@
From d393fbc256e22cc8019d18214e4d140d58f3302a Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Wed, 13 May 2020 23:51:04 -0300
Subject: [PATCH 3/8] Improve error message when bind is given an invalid PIN
---
src/luks/clevis-luks-bind.in | 6 ++++++
src/luks/clevis-luks-common-functions | 9 +++++++++
2 files changed, 15 insertions(+)
diff --git a/src/luks/clevis-luks-bind.in b/src/luks/clevis-luks-bind.in
index a5d3c5f..89a5e22 100755
--- a/src/luks/clevis-luks-bind.in
+++ b/src/luks/clevis-luks-bind.in
@@ -19,6 +19,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+. clevis-luks-common-functions
+
SUMMARY="Binds a LUKS device using the specified policy"
UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
@@ -76,6 +78,10 @@ fi
if ! PIN="${@:$((OPTIND++)):1}" || [ -z "$PIN" ]; then
echo "Did not specify a pin!" >&2
usage
+elif ! EXE=$(findexe clevis-encrypt-"${PIN}") \
+ || [ -z "${EXE}" ]; then
+ echo "'$PIN' is not a valid pin!" >&2
+ usage
fi
if ! CFG="${@:$((OPTIND++)):1}" || [ -z "$CFG" ]; then
diff --git a/src/luks/clevis-luks-common-functions b/src/luks/clevis-luks-common-functions
index d04fdb5..36f0bfd 100644
--- a/src/luks/clevis-luks-common-functions
+++ b/src/luks/clevis-luks-common-functions
@@ -108,6 +108,15 @@ clevis_luks_read_slot() {
echo "${DATA_CODED}"
}
+# findexe() finds an executable.
+findexe() {
+ while read -r -d: path; do
+ [ -f "${path}/${1}" ] && [ -x "${path}/${1}" ] && \
+ echo "${path}/${1}" && return 0
+ done <<< "${PATH}:"
+ return 1
+}
+
# clevis_luks_used_slots() will return the list of used slots for a given LUKS
# device.
clevis_luks_used_slots() {
--
2.18.4

View File

@ -0,0 +1,53 @@
From fc0cc6f159857e463aacababdc0735b0972d103c Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Wed, 13 May 2020 23:51:04 -0300
Subject: [PATCH 4/8] Add rd.neednet=1 to cmdline only if there are devices
bound to tang
---
.../dracut/clevis-pin-tang/module-setup.sh.in | 21 +++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/src/luks/systemd/dracut/clevis-pin-tang/module-setup.sh.in b/src/luks/systemd/dracut/clevis-pin-tang/module-setup.sh.in
index 1bb2ead..a4984dc 100755
--- a/src/luks/systemd/dracut/clevis-pin-tang/module-setup.sh.in
+++ b/src/luks/systemd/dracut/clevis-pin-tang/module-setup.sh.in
@@ -18,8 +18,23 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+has_devices_bound_to_tang() {
+ local dev
+ for dev in $(lsblk -p -n -s -r \
+ | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
+ if clevis luks list -d "${dev}" 2>/dev/null | grep -q tang; then
+ return 0
+ fi
+ done
+ return 1
+}
+
depends() {
- echo clevis network
+ local deps="clevis"
+ if has_devices_bound_to_tang; then
+ deps=$(printf "%s network" "${deps}")
+ fi
+ echo "${deps}"
return 0
}
@@ -28,7 +43,9 @@ cmdline() {
}
install() {
- cmdline > "${initdir}/etc/cmdline.d/99clevis-pin-tang.conf"
+ if has_devices_bound_to_tang; then
+ cmdline > "${initdir}/etc/cmdline.d/99clevis-pin-tang.conf"
+ fi
inst_multiple \
clevis-decrypt-tang \
--
2.18.4

View File

@ -1,7 +1,8 @@
From 69556d143544a72f84e9daf25924e3ae5132ce1a Mon Sep 17 00:00:00 2001 From e3641a7193adac1cea525c093f39679c2cfa22c9 Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com> From: Sergio Correia <scorreia@redhat.com>
Date: Sat, 30 Nov 2019 14:58:43 -0500 Date: Wed, 13 May 2020 23:53:38 -0300
Subject: [PATCH] Add the option to extract luks passphrase used for binding Subject: [PATCH 5/8] Add the option to extract luks passphrase used for
binding
Usage: Usage:
@ -145,21 +146,21 @@ index 0000000..fa9526a
+ +
+link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)], +link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)],
diff --git a/src/luks/meson.build b/src/luks/meson.build diff --git a/src/luks/meson.build b/src/luks/meson.build
index 51d82fb..b2dd724 100644 index 0d24f8d..fda2ca8 100644
--- a/src/luks/meson.build --- a/src/luks/meson.build
+++ b/src/luks/meson.build +++ b/src/luks/meson.build
@@ -23,6 +23,9 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found() @@ -41,6 +41,9 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found()
bins += join_paths(meson.current_source_dir(), 'clevis-luks-list')
mans += join_paths(meson.current_source_dir(), 'clevis-luks-list.1')
bins += join_paths(meson.current_source_dir(), 'clevis-luks-unlock')
mans += join_paths(meson.current_source_dir(), 'clevis-luks-unlock.1')
+
+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-pass') + bins += join_paths(meson.current_source_dir(), 'clevis-luks-pass')
+ mans += join_paths(meson.current_source_dir(), 'clevis-luks-pass.1') + mans += join_paths(meson.current_source_dir(), 'clevis-luks-pass.1')
+ else
bins += join_paths(meson.current_source_dir(), 'clevis-luks-report') warning('Will not install LUKS support due to missing dependencies!')
bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-compare') endif
bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-decode')
diff --git a/src/luks/tests/meson.build b/src/luks/tests/meson.build diff --git a/src/luks/tests/meson.build b/src/luks/tests/meson.build
index 6513eaa..248d2ea 100644 index 9a16b42..4757c4b 100644
--- a/src/luks/tests/meson.build --- a/src/luks/tests/meson.build
+++ b/src/luks/tests/meson.build +++ b/src/luks/tests/meson.build
@@ -1,3 +1,9 @@ @@ -1,3 +1,9 @@
@ -172,7 +173,7 @@ index 6513eaa..248d2ea 100644
# We use jq for comparing the pin config in the clevis luks list tests. # We use jq for comparing the pin config in the clevis luks list tests.
jq = find_program('jq', required: false) jq = find_program('jq', required: false)
@@ -15,8 +21,11 @@ env.prepend('PATH', @@ -45,8 +51,11 @@ env.prepend('PATH',
join_paths(meson.build_root(), 'src', 'pins', 'sss'), join_paths(meson.build_root(), 'src', 'pins', 'sss'),
join_paths(meson.build_root(), 'src', 'pins', 'tang'), join_paths(meson.build_root(), 'src', 'pins', 'tang'),
join_paths(meson.build_root(), 'src', 'pins', 'tpm2'), join_paths(meson.build_root(), 'src', 'pins', 'tpm2'),
@ -182,21 +183,22 @@ index 6513eaa..248d2ea 100644
) )
+env.set('SD_ACTIVATE', actv.path()) +env.set('SD_ACTIVATE', actv.path())
if jq.found() has_tang = false
test('list-recursive-luks1', find_program('list-recursive-luks1'), env: env) if actv.found() and kgen.found() and tang.found()
@@ -25,6 +34,7 @@ if jq.found() @@ -77,6 +86,7 @@ endif
else if has_tang
warning('Will not run "clevis luks list" tests due to missing jq dependency') test('unlock-tang-luks1', find_program('unlock-tang-luks1'), env: env, timeout: 90)
endif endif
+test('pass-tang-luks1', find_program('pass-tang-luks1'), env: env) +test('pass-tang-luks1', find_program('pass-tang-luks1'), env: env)
# LUKS2 tests go here, and they get included if we get support for it, based # LUKS2 tests go here, and they get included if we get support for it, based
# on the cryptsetup version. # on the cryptsetup version.
@@ -34,3 +44,4 @@ if jq.found() @@ -96,4 +106,5 @@ if luksmeta_data.get('OLD_CRYPTSETUP') == '0'
test('list-tang-luks2', find_program('list-tang-luks2'), env: env, timeout: 60) if has_tang
test('list-sss-tang-luks2', find_program('list-sss-tang-luks2'), env: env, timeout: 60) test('unlock-tang-luks2', find_program('unlock-tang-luks2'), env: env, timeout: 120)
endif
+ test('pass-tang-luks2', find_program('pass-tang-luks2'), env: env, timeout: 60)
endif endif
+test('pass-tang-luks2', find_program('pass-tang-luks2'), env: env, timeout: 60)
diff --git a/src/luks/tests/pass-tang-luks1 b/src/luks/tests/pass-tang-luks1 diff --git a/src/luks/tests/pass-tang-luks1 b/src/luks/tests/pass-tang-luks1
new file mode 100755 new file mode 100755
index 0000000..05cdb3e index 0000000..05cdb3e
@ -360,5 +362,5 @@ index 0000000..9123aa0
+! wait "${PID}" +! wait "${PID}"
+unset PID +unset PID
-- --
2.18.1 2.18.4

View File

@ -1,50 +1,83 @@
From 5536f15b9235cb6ae1b79a5ad1d96a8ea97b3113 Mon Sep 17 00:00:00 2001 From 158bdeda3ca961b0e615c8adfc58b61e1a1ba5c7 Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com> From: Sergio Correia <scorreia@redhat.com>
Date: Wed, 29 Jan 2020 06:29:32 -0500 Date: Wed, 13 May 2020 23:55:41 -0300
Subject: [PATCH] Improve clevis luks regen; no unbind in every case Subject: [PATCH 6/8] Add clevis luks regen command
When updating the metadata -- likely due to a tang key rotation --, The clevis luks regen command regenerates the LUKS binding for a given
clevis will not do unbind + bind in every case. device/slot, using the same configuration of the existing binding.
Now we have 2 cases to be handled: Example:
1) we have the key for the slot being rotated; in this case, the
rotation happens in-place
2) we don't have the key for the slot being rotated; in this case, clevis luks list -d /dev/sda1
we have to re-add the keyslot with updated info. 1: tang '{"url":"http://tang.server"}'
2: tpm2 '{"hash":"sha256","key":"ecc"}'
Added also mechanisms for backup + restore of the LUKS header/slots, To rotate the binding in slot 1, we can use the following:
so that we can revert back to the original state if clevis luks regen clevis luks regen -d /dev/sda1 -s 1
fails.
The new binding will use the existing configuration, namely:
'{"url":"http://tang.server"}', with the `tang' pin.
--- ---
src/luks/clevis-luks-common-functions | 202 ++++++++++++++++++++++ src/luks/clevis-luks-common-functions | 230 +++++++++++++++++++++++
src/luks/clevis-luks-pass | 5 +- src/luks/clevis-luks-pass | 5 +-
src/luks/clevis-luks-regen | 223 ++++++++++++------------- src/luks/clevis-luks-regen | 185 ++++++++++++++++++
src/luks/tests/backup-restore-luks1 | 114 +++++++++++++ src/luks/clevis-luks-regen.1.adoc | 48 +++++
src/luks/tests/backup-restore-luks2 | 115 +++++++++++++ src/luks/meson.build | 3 +
src/luks/tests/meson.build | 7 + src/luks/tests/backup-restore-luks1 | 114 +++++++++++
src/luks/tests/regen-inplace-luks1 | 98 +++++++++++ src/luks/tests/backup-restore-luks2 | 115 ++++++++++++
src/luks/tests/regen-inplace-luks2 | 99 +++++++++++ src/luks/tests/meson.build | 6 +
src/luks/tests/regen-not-inplace-luks1 | 95 +++++++++++ src/luks/tests/meson.build.orig | 110 +++++++++++
src/luks/tests/regen-not-inplace-luks2 | 96 +++++++++++ src/luks/tests/regen-inplace-luks1 | 98 ++++++++++
src/luks/tests/tests-common-functions | 27 ++- src/luks/tests/regen-inplace-luks2 | 99 ++++++++++
11 files changed, 966 insertions(+), 115 deletions(-) src/luks/tests/regen-not-inplace-luks1 | 95 ++++++++++
src/luks/tests/regen-not-inplace-luks2 | 96 ++++++++++
src/luks/tests/tests-common-functions.in | 26 +++
14 files changed, 1228 insertions(+), 2 deletions(-)
create mode 100755 src/luks/clevis-luks-regen
create mode 100644 src/luks/clevis-luks-regen.1.adoc
create mode 100755 src/luks/tests/backup-restore-luks1 create mode 100755 src/luks/tests/backup-restore-luks1
create mode 100755 src/luks/tests/backup-restore-luks2 create mode 100755 src/luks/tests/backup-restore-luks2
create mode 100644 src/luks/tests/meson.build.orig
create mode 100755 src/luks/tests/regen-inplace-luks1 create mode 100755 src/luks/tests/regen-inplace-luks1
create mode 100755 src/luks/tests/regen-inplace-luks2 create mode 100755 src/luks/tests/regen-inplace-luks2
create mode 100755 src/luks/tests/regen-not-inplace-luks1 create mode 100755 src/luks/tests/regen-not-inplace-luks1
create mode 100755 src/luks/tests/regen-not-inplace-luks2 create mode 100755 src/luks/tests/regen-not-inplace-luks2
diff --git a/src/luks/clevis-luks-common-functions b/src/luks/clevis-luks-common-functions diff --git a/src/luks/clevis-luks-common-functions b/src/luks/clevis-luks-common-functions
index 9ba1812..2a1af26 100644 index 36f0bfd..5b515ad 100644
--- a/src/luks/clevis-luks-common-functions --- a/src/luks/clevis-luks-common-functions
+++ b/src/luks/clevis-luks-common-functions +++ b/src/luks/clevis-luks-common-functions
@@ -314,3 +314,205 @@ clevis_luks_read_pins_from_slot() { @@ -325,3 +325,233 @@ clevis_luks_unlock_device() {
fi
printf "%s: %s\n" "${SLOT}" "${cfg}" return 1
} }
+ +
+# Generate a key with the same entropy as the LUKS master key of a given
+# device.
+generate_key() {
+ local DEV="${1}"
+
+ if [ -z "${DEV}" ]; then
+ echo "Please, specify a device." >&2
+ return 1
+ fi
+
+ local dump
+ local filter
+ dump=$(cryptsetup luksDump "${DEV}")
+ if cryptsetup isLuks --type luks1 "${DEV}"; then
+ filter=$(sed -rn 's|MK bits:[ \t]*([0-9]+)|\1|p' <<< "${dump}")
+ elif cryptsetup isLuks --type luks2 "${DEV}"; then
+ filter=$(sed -rn 's|^\s+Key:\s+([0-9]+) bits\s*$|\1|p' <<< "${dump}")
+ else
+ echo "${DEV} is not a supported LUKS device!" >&2
+ return 1
+ fi
+ local bits
+ bits=$(sort -n <<< "${filter}" | tail -n 1)
+ pwmake "${bits}"
+}
+
+# clevis_luks1_save_slot() works with LUKS1 devices and it saves a given JWE +# clevis_luks1_save_slot() works with LUKS1 devices and it saves a given JWE
+# to a specific device and slot. The last parameter indicates whether we +# to a specific device and slot. The last parameter indicates whether we
+# should overwrite existing metadata. +# should overwrite existing metadata.
@ -197,7 +230,8 @@ index 9ba1812..2a1af26 100644
+ [ -z "${DEV}" ] && return 1 + [ -z "${DEV}" ] && return 1
+ [ -z "${TMP}" ] && return 1 + [ -z "${TMP}" ] && return 1
+ +
+ local HDR="${TMP}/$(basename "${DEV}").header" + local HDR
+ HDR="${TMP}/$(basename "${DEV}").header"
+ if ! cryptsetup luksHeaderBackup "${DEV}" --batch-mode \ + if ! cryptsetup luksHeaderBackup "${DEV}" --batch-mode \
+ --header-backup-file "${HDR}"; then + --header-backup-file "${HDR}"; then
+ echo "Error backing up LUKS header from ${DEV}" >&2 + echo "Error backing up LUKS header from ${DEV}" >&2
@ -224,7 +258,8 @@ index 9ba1812..2a1af26 100644
+ [ -z "${DEV}" ] && return 1 + [ -z "${DEV}" ] && return 1
+ [ -z "${TMP}" ] && return 1 + [ -z "${TMP}" ] && return 1
+ +
+ local HDR="${TMP}/$(basename "${DEV}").header" + local HDR
+ HDR="${TMP}/$(basename "${DEV}").header"
+ if [ ! -e "${HDR}" ]; then + if [ ! -e "${HDR}" ]; then
+ echo "LUKS header backup does not exist" >&2 + echo "LUKS header backup does not exist" >&2
+ return 1 + return 1
@ -262,30 +297,42 @@ index 1ce8c4c..d31bc17 100755
fi fi
+echo -n "${passphrase}" +echo -n "${passphrase}"
diff --git a/src/luks/clevis-luks-regen b/src/luks/clevis-luks-regen diff --git a/src/luks/clevis-luks-regen b/src/luks/clevis-luks-regen
index 9535ba3..44fd673 100755 new file mode 100755
--- a/src/luks/clevis-luks-regen index 0000000..44fd673
--- /dev/null
+++ b/src/luks/clevis-luks-regen +++ b/src/luks/clevis-luks-regen
@@ -1,8 +1,9 @@ @@ -0,0 +1,185 @@
-#!/usr/bin/env bash
+#!/usr/bin/bash +#!/usr/bin/bash
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
# +#
# Copyright (c) 2018 Red Hat, Inc. +# Copyright (c) 2018 Red Hat, Inc.
# Author: Radovan Sroka <rsroka@redhat.com> +# Author: Radovan Sroka <rsroka@redhat.com>
+# Author: Sergio Correia <scorreia@redhat.com> +# Author: Sergio Correia <scorreia@redhat.com>
# +#
# This program is free software: you can redistribute it and/or modify +# 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 +# it under the terms of the GNU General Public License as published by
@@ -28,19 +29,27 @@ if [ "$1" == "--summary" ]; then +# the Free Software Foundation, either version 3 of the License, or
fi +# (at your option) any later version.
+#
function usage_and_exit () { +# This program is distributed in the hope that it will be useful,
- echo >&2 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
- echo "Usage: clevis luks regen -d DEV -s SLOT" >&2 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- echo >&2 +# GNU General Public License for more details.
- echo "$SUMMARY" >&2 +#
- echo >&2 +# You should have received a copy of the GNU General Public License
- exit "$1" +# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+. clevis-luks-common-functions
+
+SUMMARY="Regenerate LUKS metadata"
+
+if [ "$1" == "--summary" ]; then
+ echo "$SUMMARY"
+ exit 0
+fi
+
+function usage_and_exit () {
+ exec >&2 + exec >&2
+ echo "Usage: clevis luks regen -d DEV -s SLOT" + echo "Usage: clevis luks regen -d DEV -s SLOT"
+ echo + echo
@ -296,11 +343,8 @@ index 9535ba3..44fd673 100755
+ echo " -s SLT The LUKS slot to use" + echo " -s SLT The LUKS slot to use"
+ echo + echo
+ exit "${1}" + exit "${1}"
} +}
+
-if [ "$#" -ne "4" ]; then
- usage_and_exit 1
-fi
+on_exit() { +on_exit() {
+ if [ ! -d "${TMP}" ] || ! rm -rf "${TMP}"; then + if [ ! -d "${TMP}" ] || ! rm -rf "${TMP}"; then
+ echo "Delete temporary files failed!" >&2 + echo "Delete temporary files failed!" >&2
@ -308,142 +352,49 @@ index 9535ba3..44fd673 100755
+ exit 1 + exit 1
+ fi + fi
+} +}
+
-while getopts "hd:s:" o; do
+while getopts ":hfd:s:" o; do +while getopts ":hfd:s:" o; do
case "$o" in + case "$o" in
d) DEV="$OPTARG";; + d) DEV="$OPTARG";;
h) usage_and_exit 0;; + h) usage_and_exit 0;;
@@ -49,88 +58,6 @@ while getopts "hd:s:" o; do + s) SLT="$OPTARG";;
esac + *) usage_and_exit 1;;
done + esac
+done
-function decode_luks_header () { +
- if DATA_CODED="$(jose jwe fmt -i- <<< "$1")"; then +if [ -z "$DEV" ]; then
- DATA_CODED="$(jose fmt -j- -g protected -u- <<< "$DATA_CODED")" + echo "Did not specify a device!" >&2
- DATA_DECODED="$(jose b64 dec -i- <<< "$DATA_CODED")" + exit 1
- else +fi
- echo "Error decoding JWE protected header!" >&2 +
- exit 1 +if [ -z "$SLT" ]; then
- fi + echo "Did not specify a slot!" >&2
- + exit 1
- echo "$DATA_DECODED" +fi
-} +
- +### ----------------------------------------------------------------------
-function generate_cfg () {
- echo -n "{"
- DATA="$(decode_luks_header "$1")"
-
- if ! P="$(jose fmt -j- -g clevis -g pin -u- <<< "$DATA")" || [ -z "$P" ]; then
- echo "Pin wasn't found in LUKS metadata!" >&2
- exit 1
- fi
-
- if ! CONTENT="$(jose fmt -j- -g clevis -g "$P" -o- <<< "$DATA")" || [ -z "$CONTENT" ]; then
- echo "Content was not found!" >&2
- fi
-
- # echo -n "\"$P\": ["
-
- if [ "$P" = "tang" ] || [ "$P" = "http" ]; then
- URL="$(jose fmt -j- -g url -u- <<< "$CONTENT")"
- echo -n "\"url\":\"$URL\""
- elif [ "$P" = "sss" ]; then
- THRESHOLD="$(jose fmt -j- -g t -o- <<< "$CONTENT")"
- if [ -n "$THRESHOLD" ]; then
- echo -n "\"t\":$THRESHOLD,"
- fi
-
- echo -n "\"pins\":{"
-
- CNT=0
- PREV=""
- while ITEM="$(jose fmt -j- -g jwe -g"$CNT" -u- <<< "$CONTENT")"; do
- if [ -z "$ITEM" ]; then
- CNT=$(( CNT + 1 ))
- continue # in some cases it can be empty string
- fi
-
- DD="$(decode_luks_header "$ITEM")"
-
- if ! PP="$(jose fmt -j- -g clevis -g pin -u- <<< "$DD")" || [ -z "$PP" ]; then
- echo "Pin wasn't found in LUKS metadata!" >&2
- exit 1
- fi
-
- if [ "$CNT" -eq 0 ]; then
- PREV="$PP"
- echo -n "\"$PP\":["
- echo -n "$(generate_cfg "$ITEM")"
- else
- if ! [ "$PREV" = "$PP" ]; then
- echo -n "],\"$PP\":["
- echo -n "$(generate_cfg "$ITEM")"
- else
- echo -n ",$(generate_cfg "$ITEM")"
- fi
- fi
-
- PREV="$PP"
- CNT=$(( CNT + 1 ))
- done
-
- echo -n "]}"
-
- else
- echo "Unknown pin $P!" >&2
- exit 1
- fi
-
- echo -n "}"
-}
-
-### get luks metadata
-
if [ -z "$DEV" ]; then
echo "Did not specify a device!" >&2
exit 1
@@ -141,23 +68,14 @@ if [ -z "$SLT" ]; then
exit 1
fi
-if ! OLD_LUKS_CODED="$(clevis_luks_read_slot "$DEV" "$SLT")"; then
- echo "Error reading metadata from LUKS device!" >&2
- exit 1
-fi
-
### ----------------------------------------------------------------------
-
-DECODED="$(decode_luks_header "$OLD_LUKS_CODED")"
-
-if ! PIN="$(jose fmt -j- -g clevis -g pin -u- <<< "$DECODED")" || [ -z "$PIN" ]; then
- echo "Pin wasn't found in LUKS metadata!" >&2
+if ! pin_cfg=$(clevis luks list -d "${DEV}" -s "${SLT}" 2>/dev/null); then +if ! pin_cfg=$(clevis luks list -d "${DEV}" -s "${SLT}" 2>/dev/null); then
+ echo "Error obtaining current configuration of device ${DEV}:${SLT}" >&2 + echo "Error obtaining current configuration of device ${DEV}:${SLT}" >&2
exit 1 + exit 1
fi +fi
+
-CFG="$(generate_cfg "$OLD_LUKS_CODED")"
-
-### ----------------------------------------------------------------------
+PIN=$(echo "${pin_cfg}" | awk '{ print $2 }') +PIN=$(echo "${pin_cfg}" | awk '{ print $2 }')
+CFG=$(echo "${pin_cfg}" | awk '{ print $3 }' | tr -d "'") +CFG=$(echo "${pin_cfg}" | awk '{ print $3 }' | tr -d "'")
+
echo "Regenerating with:" +echo "Regenerating with:"
echo "PIN: $PIN" +echo "PIN: $PIN"
@@ -166,20 +84,101 @@ echo "CONFIG: $CFG" +echo "CONFIG: $CFG"
trap 'echo "Ignoring CONTROL-C!"' INT TERM +
+trap 'echo "Ignoring CONTROL-C!"' INT TERM
# Get the existing key. +
-read -r -s -p "Enter existing LUKS password: " existing_key; echo +# Get the existing key.
+if ! existing_key=$(clevis luks pass -d "${DEV}" -s "${SLT}" 2>/dev/null); then +if ! existing_key=$(clevis luks pass -d "${DEV}" -s "${SLT}" 2>/dev/null); then
+ # We failed to obtain the passphrase for the slot -- perhaps + # We failed to obtain the passphrase for the slot -- perhaps
+ # it was rotated? --, so let's request user input. + # it was rotated? --, so let's request user input.
+ read -r -s -p "Enter existing LUKS password: " existing_key; echo + read -r -s -p "Enter existing LUKS password: " existing_key; echo
+fi +fi
+
# Check if the key is valid. +# Check if the key is valid.
-if ! cryptsetup luksOpen --test-passphrase "${DEV}" <<< "${existing_key}"; then
+if ! cryptsetup open --test-passphrase "${DEV}" <<< "${existing_key}"; then +if ! cryptsetup open --test-passphrase "${DEV}" <<< "${existing_key}"; then
+ exit 1 + exit 1
+fi +fi
@ -480,11 +431,9 @@ index 9535ba3..44fd673 100755
+# Backup LUKS header. +# Backup LUKS header.
+if ! clevis_luks_backup_dev "${DEV}" "${TMP}"; then +if ! clevis_luks_backup_dev "${DEV}" "${TMP}"; then
+ echo "Error while trying to back up LUKS header from ${DEV}" >&2 + echo "Error while trying to back up LUKS header from ${DEV}" >&2
exit 1 + exit 1
fi +fi
+
-if ! clevis luks unbind -d "${DEV}" -s "${SLT}" -f; then
- echo "Error during unbind of rotated key from slot:$SLT in $DEV" >&2
+restore_device() { +restore_device() {
+ local DEV="${1}" + local DEV="${1}"
+ local TMP="${2}" + local TMP="${2}"
@ -525,20 +474,87 @@ index 9535ba3..44fd673 100755
+if ! clevis_luks_save_slot "${DEV}" "${SLT}" "${jwe}" "overwrite"; then +if ! clevis_luks_save_slot "${DEV}" "${SLT}" "${jwe}" "overwrite"; then
+ echo "Error updating metadata in ${DEV}:${SLT}" >&2 + echo "Error updating metadata in ${DEV}:${SLT}" >&2
+ restore_device "${DEV}" "${TMP}" + restore_device "${DEV}" "${TMP}"
exit 1 + exit 1
fi +fi
+
-if ! clevis luks bind -d "${DEV}" -s "${SLT}" "${PIN}" "${CFG}" -k - <<< "${existing_key}"; then
- echo "Error during bind of new key from slot:$SLT in $DEV" >&2
+# Now make sure that we can unlock this device after the change. +# Now make sure that we can unlock this device after the change.
+# If we can't, undo the changes. +# If we can't, undo the changes.
+if ! cryptsetup open --test-passphrase --key-slot "${SLT}" "${DEV}" 2>/dev/null \ +if ! cryptsetup open --test-passphrase --key-slot "${SLT}" "${DEV}" 2>/dev/null \
+ <<< $(clevis luks pass -d "${DEV}" -s "${SLT}" 2>/dev/null); then + <<< $(clevis luks pass -d "${DEV}" -s "${SLT}" 2>/dev/null); then
+ echo "Invalid configuration detected after rebinding. Reverting changes." + echo "Invalid configuration detected after rebinding. Reverting changes."
+ restore_device "${DEV}" "${TMP}" + restore_device "${DEV}" "${TMP}"
exit 1 + exit 1
fi +fi
+
+echo "Keys were succesfully rotated."
diff --git a/src/luks/clevis-luks-regen.1.adoc b/src/luks/clevis-luks-regen.1.adoc
new file mode 100644
index 0000000..763fa1e
--- /dev/null
+++ b/src/luks/clevis-luks-regen.1.adoc
@@ -0,0 +1,48 @@
+CLEVIS-LUKS-REGEN(1)
+=====================
+:doctype: manpage
+
+
+== NAME
+
+clevis-luks-regen - Regenerates LUKS binding
+
+== SYNOPSIS
+
+*clevis luks regen* -d DEV -s SLT
+
+== OVERVIEW
+
+The *clevis luks regen* command regenerates the LUKS binding for a given slot in a LUKS device, using the same configuration of the
+existing binding. Its operation can be compared to performing *clevis luks unbind* and *clevis luks bind* for rebinding said slot and device.
+This is useful when rotating keys.
+
+== OPTIONS
+
+* *-d* _DEV_ :
+ The bound LUKS device
+
+* *-s* _SLT_ :
+ The slot or key slot number for rebinding. Note that it requires that such slot is currently bound by clevis.
+
+== EXAMPLE
+
+ Let's start by using clevis luks list to see the current binding configuration in /dev/sda1:
+
+ # clevis luks list -d /dev/sda1
+ 1: tang '{"url":"http://tang.server"}'
+ 2: tpm2 '{"hash":"sha256","key":"ecc"}'
+
+ We see that slot 1 in /dev/sda1 has a tang binding with the following configuration:
+ '{"url":"http://tang.server"}'
+
+ Now let's do the rebinding of slot 1:
+ # clevis luks regen -d /dev/sda1 -s 1
+
+ After a successful operation, we will have the new binding using the same configuration that was already in place.
+
+== SEE ALSO
+
+link:clevis-luks-list.1.adoc[*clevis-luks-list*(1)]
+link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)]
+link:clevis-luks-unbind.1.adoc[*clevis-luks-unbind*(1)]
diff --git a/src/luks/meson.build b/src/luks/meson.build
index fda2ca8..f21388d 100644
--- a/src/luks/meson.build
+++ b/src/luks/meson.build
@@ -44,6 +44,9 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found()
bins += join_paths(meson.current_source_dir(), 'clevis-luks-pass')
mans += join_paths(meson.current_source_dir(), 'clevis-luks-pass.1')
+
+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-regen')
+ mans += join_paths(meson.current_source_dir(), 'clevis-luks-regen.1')
else
warning('Will not install LUKS support due to missing dependencies!')
endif
diff --git a/src/luks/tests/backup-restore-luks1 b/src/luks/tests/backup-restore-luks1 diff --git a/src/luks/tests/backup-restore-luks1 b/src/luks/tests/backup-restore-luks1
new file mode 100755 new file mode 100755
index 0000000..733a4b6 index 0000000..733a4b6
@ -781,11 +797,11 @@ index 0000000..a3b8608
+! wait "${PID}" +! wait "${PID}"
+unset PID +unset PID
diff --git a/src/luks/tests/meson.build b/src/luks/tests/meson.build diff --git a/src/luks/tests/meson.build b/src/luks/tests/meson.build
index 248d2ea..4e0a6cb 100644 index 4757c4b..dbef9bf 100644
--- a/src/luks/tests/meson.build --- a/src/luks/tests/meson.build
+++ b/src/luks/tests/meson.build +++ b/src/luks/tests/meson.build
@@ -35,6 +35,9 @@ else @@ -87,6 +87,9 @@ if has_tang
warning('Will not run "clevis luks list" tests due to missing jq dependency') test('unlock-tang-luks1', find_program('unlock-tang-luks1'), env: env, timeout: 90)
endif endif
test('pass-tang-luks1', find_program('pass-tang-luks1'), env: env) test('pass-tang-luks1', find_program('pass-tang-luks1'), env: env)
+test('backup-restore-luks1', find_program('backup-restore-luks1'), env: env) +test('backup-restore-luks1', find_program('backup-restore-luks1'), env: env)
@ -794,14 +810,130 @@ index 248d2ea..4e0a6cb 100644
# LUKS2 tests go here, and they get included if we get support for it, based # LUKS2 tests go here, and they get included if we get support for it, based
# on the cryptsetup version. # on the cryptsetup version.
@@ -45,3 +48,7 @@ if jq.found() @@ -107,4 +110,7 @@ if luksmeta_data.get('OLD_CRYPTSETUP') == '0'
test('list-sss-tang-luks2', find_program('list-sss-tang-luks2'), env: env, timeout: 60) test('unlock-tang-luks2', find_program('unlock-tang-luks2'), env: env, timeout: 120)
endif endif
test('pass-tang-luks2', find_program('pass-tang-luks2'), env: env, timeout: 60) test('pass-tang-luks2', find_program('pass-tang-luks2'), env: env, timeout: 60)
+test('backup-restore-luks2', find_program('backup-restore-luks2'), env:env, timeout: 90) + test('backup-restore-luks2', find_program('backup-restore-luks2'), env:env, timeout: 90)
+test('regen-inplace-luks2', find_program('regen-inplace-luks2'), env: env, timeout: 90) + test('regen-inplace-luks2', find_program('regen-inplace-luks2'), env: env, timeout: 90)
+test('regen-not-inplace-luks2', find_program('regen-not-inplace-luks2'), env: env, timeout: 90) + test('regen-not-inplace-luks2', find_program('regen-not-inplace-luks2'), env: env, timeout: 90)
endif
diff --git a/src/luks/tests/meson.build.orig b/src/luks/tests/meson.build.orig
new file mode 100644
index 0000000..4757c4b
--- /dev/null
+++ b/src/luks/tests/meson.build.orig
@@ -0,0 +1,110 @@
+actv = find_program(
+ 'systemd-socket-activate',
+ 'systemd-activate',
+ required: false
+)
+ +
+# We use jq for comparing the pin config in the clevis luks list tests.
+jq = find_program('jq', required: false)
+
+# we use systemd-socket-activate for running test tang servers.
+actv = find_program(
+ 'systemd-socket-activate',
+ 'systemd-activate',
+ required: false
+)
+
+kgen = find_program(
+ join_paths(libexecdir, 'tangd-keygen'),
+ join_paths(get_option('prefix'), get_option('libdir'), 'tangd-keygen'),
+ join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd-keygen'),
+ join_paths('/', 'usr', get_option('libdir'), 'tangd-keygen'),
+ join_paths('/', 'usr', get_option('libexecdir'), 'tangd-keygen'),
+ required: false
+)
+tang = find_program(
+ join_paths(libexecdir, 'tangd'),
+ join_paths(get_option('prefix'), get_option('libdir'), 'tangd'),
+ join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd'),
+ join_paths('/', 'usr', get_option('libdir'), 'tangd'),
+ join_paths('/', 'usr', get_option('libexecdir'), 'tangd'),
+ required: false
+)
+
+common_functions = configure_file(input: 'tests-common-functions.in',
+ output: 'tests-common-functions',
+ configuration: luksmeta_data,
+ install: false
+)
+
+env = environment()
+env.prepend('PATH',
+ join_paths(meson.source_root(), 'src'),
+ join_paths(meson.source_root(), 'src', 'luks'),
+ join_paths(meson.source_root(), 'src', 'pins', 'sss'),
+ join_paths(meson.source_root(), 'src', 'pins', 'tang'),
+ join_paths(meson.source_root(), 'src', 'pins', 'tpm2'),
+ meson.current_source_dir(),
+ meson.current_build_dir(),
+ join_paths(meson.build_root(), 'src'),
+ join_paths(meson.build_root(), 'src', 'luks'),
+ join_paths(meson.build_root(), 'src', 'pins', 'sss'),
+ join_paths(meson.build_root(), 'src', 'pins', 'tang'),
+ join_paths(meson.build_root(), 'src', 'pins', 'tpm2'),
+ libexecdir,
+ '/usr/libexec',
+ separator: ':'
+)
+env.set('SD_ACTIVATE', actv.path())
+
+has_tang = false
+if actv.found() and kgen.found() and tang.found()
+ has_tang = true
+ env.set('SD_ACTIVATE', actv.path())
+ env.set('TANGD_KEYGEN', kgen.path())
+ env.set('TANGD', tang.path())
+endif
+
+test('bind-wrong-pass-luks1', find_program('bind-wrong-pass-luks1'), env: env)
+test('bind-luks1', find_program('bind-luks1'), env: env)
+test('unbind-unbound-slot-luks1', find_program('unbind-unbound-slot-luks1'), env: env)
+test('unbind-luks1', find_program('unbind-luks1'), env: env)
+test('bind-key-file-non-interactive', find_program('bind-key-file-non-interactive-luks1'), env: env)
+test('bind-pass-with-newline', find_program('bind-pass-with-newline-luks1'), env: env)
+test('bind-pass-with-newline-keyfile', find_program('bind-pass-with-newline-keyfile-luks1'), env: env)
+# Bug #70.
+test('bind-already-used-luksmeta-slot', find_program('bind-already-used-luksmeta-slot'), env: env, timeout: 60)
+
+if jq.found()
+ test('list-recursive-luks1', find_program('list-recursive-luks1'), env: env)
+ test('list-tang-luks1', find_program('list-tang-luks1'), env: env)
+ test('list-sss-tang-luks1', find_program('list-sss-tang-luks1'), env: env)
+else
+ warning('Will not run "clevis luks list" tests due to missing jq dependency')
+endif
+
+if has_tang
+ test('unlock-tang-luks1', find_program('unlock-tang-luks1'), env: env, timeout: 90)
+endif
+test('pass-tang-luks1', find_program('pass-tang-luks1'), env: env)
+
+# LUKS2 tests go here, and they get included if we get support for it, based
+# on the cryptsetup version.
+# Binding LUKS2 takes longer, so timeout is increased for a few tests.
+if luksmeta_data.get('OLD_CRYPTSETUP') == '0'
+ test('bind-wrong-pass-luks2', find_program('bind-wrong-pass-luks2'), env: env)
+ test('bind-luks2', find_program('bind-luks2'), env: env, timeout: 60)
+ test('unbind-unbound-slot-luks2', find_program('unbind-unbound-slot-luks2'), env: env)
+ test('unbind-luks2', find_program('unbind-luks2'), env: env, timeout: 60)
+
+ if jq.found()
+ test('list-recursive-luks2', find_program('list-recursive-luks2'), env: env, timeout: 60)
+ test('list-tang-luks2', find_program('list-tang-luks2'), env: env, timeout: 60)
+ test('list-sss-tang-luks2', find_program('list-sss-tang-luks2'), env: env, timeout: 60)
+ endif
+
+ if has_tang
+ test('unlock-tang-luks2', find_program('unlock-tang-luks2'), env: env, timeout: 120)
+ endif
+ test('pass-tang-luks2', find_program('pass-tang-luks2'), env: env, timeout: 60)
+endif
diff --git a/src/luks/tests/regen-inplace-luks1 b/src/luks/tests/regen-inplace-luks1 diff --git a/src/luks/tests/regen-inplace-luks1 b/src/luks/tests/regen-inplace-luks1
new file mode 100755 new file mode 100755
index 0000000..3a42ced index 0000000..3a42ced
@ -1214,23 +1346,15 @@ index 0000000..dc91449
+kill -9 "${PID}" +kill -9 "${PID}"
+! wait "${PID}" +! wait "${PID}"
+unset PID +unset PID
diff --git a/src/luks/tests/tests-common-functions b/src/luks/tests/tests-common-functions diff --git a/src/luks/tests/tests-common-functions.in b/src/luks/tests/tests-common-functions.in
index 7758876..1139f09 100644 index 7b3fdad..6101f28 100755
--- a/src/luks/tests/tests-common-functions --- a/src/luks/tests/tests-common-functions.in
+++ b/src/luks/tests/tests-common-functions +++ b/src/luks/tests/tests-common-functions.in
@@ -63,7 +63,7 @@ new_device() { @@ -229,5 +229,31 @@ tang_get_adv() {
return 0 curl -o "${adv}" http://"${TANG_HOST}":"${port}"/adv
fi
- fallocate -l16M "${DEV}"
+ fallocate -l64M "${DEV}"
local extra_options='--pbkdf pbkdf2 --pbkdf-force-iterations 1000'
cryptsetup luksFormat --type "${LUKS}" ${extra_options} --batch-mode --force-password "${DEV}" <<< "${DEFAULT_PASS}"
# Caching the just-formatted device for possible reuse.
@@ -83,4 +83,29 @@ pin_cfg_equal() {
<(jq -S . < <(echo -n "${cfg2}"))
} }
+# Regenerate binding.
+clevis_regen() { +clevis_regen() {
+ local DEV="${1}" + local DEV="${1}"
+ local SLT="${2}" + local SLT="${2}"
@ -1256,7 +1380,8 @@ index 7758876..1139f09 100644
+ return "${ret}" + return "${ret}"
+} +}
+ +
export TANG_HOST=127.0.0.1
export DEFAULT_PASS='just-some-test-password-here' export DEFAULT_PASS='just-some-test-password-here'
-- --
2.18.2 2.18.4

View File

@ -1,23 +1,17 @@
From 70d3da5ce8d68e8ff258122592670eb70da0c839 Mon Sep 17 00:00:00 2001 From a85f50f789d69d9ca0a4096a64ac912f5967f97f Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com> From: Sergio Correia <scorreia@redhat.com>
Date: Wed, 16 Oct 2019 09:14:58 -0300 Date: Sun, 10 May 2020 15:32:50 -0300
Subject: [PATCH 2/2] Add clevis luks report/regen Subject: [PATCH 7/8] Add clevis luks report
--- ---
src/luks/clevis-luks-common-functions | 143 ++++++++++++++++++++ src/luks/clevis-luks-report | 95 +++++++++++++++++++++++++++++
src/luks/clevis-luks-regen | 186 ++++++++++++++++++++++++++ src/luks/clevis-luks-report-compare | 71 +++++++++++++++++++++
src/luks/clevis-luks-regen.1.adoc | 36 +++++ src/luks/clevis-luks-report-decode | 59 ++++++++++++++++++
src/luks/clevis-luks-report | 95 +++++++++++++ src/luks/clevis-luks-report-sss | 53 ++++++++++++++++
src/luks/clevis-luks-report-compare | 71 ++++++++++ src/luks/clevis-luks-report-tang | 67 ++++++++++++++++++++
src/luks/clevis-luks-report-decode | 59 ++++++++ src/luks/clevis-luks-report.1.adoc | 41 +++++++++++++
src/luks/clevis-luks-report-sss | 53 ++++++++ src/luks/meson.build | 7 +++
src/luks/clevis-luks-report-tang | 67 ++++++++++ 7 files changed, 393 insertions(+)
src/luks/clevis-luks-report.1.adoc | 41 ++++++
src/luks/meson.build | 12 ++
10 files changed, 763 insertions(+)
create mode 100644 src/luks/clevis-luks-common-functions
create mode 100755 src/luks/clevis-luks-regen
create mode 100644 src/luks/clevis-luks-regen.1.adoc
create mode 100755 src/luks/clevis-luks-report create mode 100755 src/luks/clevis-luks-report
create mode 100755 src/luks/clevis-luks-report-compare create mode 100755 src/luks/clevis-luks-report-compare
create mode 100755 src/luks/clevis-luks-report-decode create mode 100755 src/luks/clevis-luks-report-decode
@ -25,389 +19,6 @@ Subject: [PATCH 2/2] Add clevis luks report/regen
create mode 100755 src/luks/clevis-luks-report-tang create mode 100755 src/luks/clevis-luks-report-tang
create mode 100644 src/luks/clevis-luks-report.1.adoc create mode 100644 src/luks/clevis-luks-report.1.adoc
diff --git a/src/luks/clevis-luks-common-functions b/src/luks/clevis-luks-common-functions
new file mode 100644
index 0000000..d676253
--- /dev/null
+++ b/src/luks/clevis-luks-common-functions
@@ -0,0 +1,143 @@
+#!/bin/bash -e
+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2019 Red Hat, Inc.
+# Author: Sergio Correia <scorreia@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+# valid_slot() will check whether a given slot is possibly valid, i.e., if it
+# is a numeric value within the specified range.
+valid_slot() {
+ local SLT="${1}"
+ local MAX_SLOTS="${2}"
+ case "${SLT}" in
+ ''|*[!0-9]*)
+ return 1
+ ;;
+ *)
+ # We got an integer, now let's make sure it is within the
+ # supported range.
+ if [ "${SLT}" -ge "${MAX_SLOTS}" ]; then
+ return 1
+ fi
+ ;;
+ esac
+}
+
+# clevis_luks_read_slot() will read a particular slot of a given device, which
+# should be either LUKS1 or LUKS2. Returns 1 in case of failure; 0 in case of
+# success.
+clevis_luks_read_slot() {
+ local DEV="${1}"
+ local SLT="${2}"
+
+ if [ -z "${DEV}" ] || [ -z "${SLT}" ]; then
+ echo "Need both a device and a slot as arguments." >&2
+ return 1
+ fi
+
+ local DATA_CODED=''
+ local MAX_LUKS1_SLOTS=8
+ local MAX_LUKS2_SLOTS=32
+ if cryptsetup isLuks --type luks1 "${DEV}"; then
+ if ! valid_slot "${SLT}" "${MAX_LUKS1_SLOTS}"; then
+ echo "Please, provide a valid key slot number; 0-7 for LUKS1" >&2
+ return 1
+ fi
+
+ if ! luksmeta test -d "${DEV}"; then
+ echo "The ${DEV} device is not valid!" >&2
+ return 1
+ fi
+
+ local uuid
+ # Pattern from luksmeta: active slot uuid.
+ read -r _ _ uuid <<< "$(luksmeta show -d "${DEV}" | grep "^${SLT} *")"
+
+ if [ "${uuid}" = "empty" ]; then
+ echo "The LUKSMeta slot ${SLT} on device ${DEV} is already empty." >&2
+ return 1
+ fi
+
+ if ! DATA_CODED="$(luksmeta load -d "${DEV}" -s "${SLT}")"; then
+ echo "Cannot load data from ${DEV} slot:${SLT}!" >&2
+ return 1
+ fi
+ elif cryptsetup isLuks --type luks2 "${DEV}"; then
+ if ! valid_slot "${SLT}" "${MAX_LUKS2_SLOTS}"; then
+ echo "Please, provide a valid key slot number; 0-31 for LUKS2" >&2
+ return 1
+ fi
+
+ local token_id
+ token_id=$(cryptsetup luksDump "${DEV}" \
+ | grep -E -B1 "^\s+Keyslot:\s+${SLT}$" \
+ | head -n 1 | sed -rn 's|^\s+([0-9]+): clevis|\1|p')
+ if [ -z "${token_id}" ]; then
+ echo "Cannot load data from ${DEV} slot:${SLT}. No token found!" >&2
+ return 1
+ fi
+
+ local token
+ token=$(cryptsetup token export --token-id "${token_id}" "${DEV}")
+ DATA_CODED=$(jose fmt -j- -Og jwe -o- <<< "${token}" \
+ | jose jwe fmt -i- -c)
+
+ if [ -z "${DATA_CODED}" ]; then
+ echo "Cannot load data from ${DEV} slot:${SLT}!" >&2
+ return 1
+ fi
+ else
+ echo "${DEV} is not a supported LUKS device!" >&2
+ return 1
+ fi
+ echo "${DATA_CODED}"
+}
+
+# Generate a key with the same entropy as the LUKS Master key of a given
+# device.
+generate_key() {
+ local DEV="${1}"
+
+ if [ -z "${DEV}" ]; then
+ echo "Please, specify a device." >&2
+ return 1
+ fi
+
+ local dump
+ local filter
+ dump=$(cryptsetup luksDump "${DEV}")
+ if cryptsetup isLuks --type luks1 "${DEV}"; then
+ filter=$(sed -rn 's|MK bits:[ \t]*([0-9]+)|\1|p' <<< "${dump}")
+ elif cryptsetup isLuks --type luks2 "${DEV}"; then
+ filter=$(sed -rn 's|^\s+Key:\s+([0-9]+) bits\s*$|\1|p' <<< "${dump}")
+ else
+ echo "${DEV} is not a supported LUKS device!" >&2
+ return 1
+ fi
+ local bits
+ bits=$(sort -n <<< "${filter}" | tail -n 1)
+ pwmake "${bits}"
+}
+
+findexe() {
+ while read -r -d: path; do
+ [ -f "${path}/${1}" ] && [ -x "${path}/${1}" ] && \
+ echo "${path}/${1}" && return 0
+ done <<< "${PATH}:"
+ return 1
+}
+
diff --git a/src/luks/clevis-luks-regen b/src/luks/clevis-luks-regen
new file mode 100755
index 0000000..9535ba3
--- /dev/null
+++ b/src/luks/clevis-luks-regen
@@ -0,0 +1,186 @@
+#!/usr/bin/env bash
+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2018 Red Hat, Inc.
+# Author: Radovan Sroka <rsroka@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+. clevis-luks-common-functions
+
+SUMMARY="Regenerate LUKS metadata"
+
+if [ "$1" == "--summary" ]; then
+ echo "$SUMMARY"
+ exit 0
+fi
+
+function usage_and_exit () {
+ echo >&2
+ echo "Usage: clevis luks regen -d DEV -s SLOT" >&2
+ echo >&2
+ echo "$SUMMARY" >&2
+ echo >&2
+ exit "$1"
+}
+
+if [ "$#" -ne "4" ]; then
+ usage_and_exit 1
+fi
+
+while getopts "hd:s:" o; do
+ case "$o" in
+ d) DEV="$OPTARG";;
+ h) usage_and_exit 0;;
+ s) SLT="$OPTARG";;
+ *) usage_and_exit 1;;
+ esac
+done
+
+function decode_luks_header () {
+ if DATA_CODED="$(jose jwe fmt -i- <<< "$1")"; then
+ DATA_CODED="$(jose fmt -j- -g protected -u- <<< "$DATA_CODED")"
+ DATA_DECODED="$(jose b64 dec -i- <<< "$DATA_CODED")"
+ else
+ echo "Error decoding JWE protected header!" >&2
+ exit 1
+ fi
+
+ echo "$DATA_DECODED"
+}
+
+function generate_cfg () {
+ echo -n "{"
+ DATA="$(decode_luks_header "$1")"
+
+ if ! P="$(jose fmt -j- -g clevis -g pin -u- <<< "$DATA")" || [ -z "$P" ]; then
+ echo "Pin wasn't found in LUKS metadata!" >&2
+ exit 1
+ fi
+
+ if ! CONTENT="$(jose fmt -j- -g clevis -g "$P" -o- <<< "$DATA")" || [ -z "$CONTENT" ]; then
+ echo "Content was not found!" >&2
+ fi
+
+ # echo -n "\"$P\": ["
+
+ if [ "$P" = "tang" ] || [ "$P" = "http" ]; then
+ URL="$(jose fmt -j- -g url -u- <<< "$CONTENT")"
+ echo -n "\"url\":\"$URL\""
+ elif [ "$P" = "sss" ]; then
+ THRESHOLD="$(jose fmt -j- -g t -o- <<< "$CONTENT")"
+ if [ -n "$THRESHOLD" ]; then
+ echo -n "\"t\":$THRESHOLD,"
+ fi
+
+ echo -n "\"pins\":{"
+
+ CNT=0
+ PREV=""
+ while ITEM="$(jose fmt -j- -g jwe -g"$CNT" -u- <<< "$CONTENT")"; do
+ if [ -z "$ITEM" ]; then
+ CNT=$(( CNT + 1 ))
+ continue # in some cases it can be empty string
+ fi
+
+ DD="$(decode_luks_header "$ITEM")"
+
+ if ! PP="$(jose fmt -j- -g clevis -g pin -u- <<< "$DD")" || [ -z "$PP" ]; then
+ echo "Pin wasn't found in LUKS metadata!" >&2
+ exit 1
+ fi
+
+ if [ "$CNT" -eq 0 ]; then
+ PREV="$PP"
+ echo -n "\"$PP\":["
+ echo -n "$(generate_cfg "$ITEM")"
+ else
+ if ! [ "$PREV" = "$PP" ]; then
+ echo -n "],\"$PP\":["
+ echo -n "$(generate_cfg "$ITEM")"
+ else
+ echo -n ",$(generate_cfg "$ITEM")"
+ fi
+ fi
+
+ PREV="$PP"
+ CNT=$(( CNT + 1 ))
+ done
+
+ echo -n "]}"
+
+ else
+ echo "Unknown pin $P!" >&2
+ exit 1
+ fi
+
+ echo -n "}"
+}
+
+### get luks metadata
+
+if [ -z "$DEV" ]; then
+ echo "Did not specify a device!" >&2
+ exit 1
+fi
+
+if [ -z "$SLT" ]; then
+ echo "Did not specify a slot!" >&2
+ exit 1
+fi
+
+if ! OLD_LUKS_CODED="$(clevis_luks_read_slot "$DEV" "$SLT")"; then
+ echo "Error reading metadata from LUKS device!" >&2
+ exit 1
+fi
+
+### ----------------------------------------------------------------------
+
+DECODED="$(decode_luks_header "$OLD_LUKS_CODED")"
+
+if ! PIN="$(jose fmt -j- -g clevis -g pin -u- <<< "$DECODED")" || [ -z "$PIN" ]; then
+ echo "Pin wasn't found in LUKS metadata!" >&2
+ exit 1
+fi
+
+CFG="$(generate_cfg "$OLD_LUKS_CODED")"
+
+### ----------------------------------------------------------------------
+
+echo "Regenerating with:"
+echo "PIN: $PIN"
+echo "CONFIG: $CFG"
+
+trap 'echo "Ignoring CONTROL-C!"' INT TERM
+
+# Get the existing key.
+read -r -s -p "Enter existing LUKS password: " existing_key; echo
+
+# Check if the key is valid.
+if ! cryptsetup luksOpen --test-passphrase "${DEV}" <<< "${existing_key}"; then
+ exit 1
+fi
+
+if ! clevis luks unbind -d "${DEV}" -s "${SLT}" -f; then
+ echo "Error during unbind of rotated key from slot:$SLT in $DEV" >&2
+ exit 1
+fi
+
+if ! clevis luks bind -d "${DEV}" -s "${SLT}" "${PIN}" "${CFG}" -k - <<< "${existing_key}"; then
+ echo "Error during bind of new key from slot:$SLT in $DEV" >&2
+ exit 1
+fi
+
+echo "Keys were succesfully rotated."
diff --git a/src/luks/clevis-luks-regen.1.adoc b/src/luks/clevis-luks-regen.1.adoc
new file mode 100644
index 0000000..3cd6b7c
--- /dev/null
+++ b/src/luks/clevis-luks-regen.1.adoc
@@ -0,0 +1,36 @@
+CLEVIS-LUKS-REGEN(1)
+=====================
+:doctype: manpage
+
+
+== NAME
+
+clevis-luks-regen - Regenerates LUKS metadata
+
+== SYNOPSIS
+
+*clevis luks regen* -d DEV -s SLT
+
+== OVERVIEW
+
+The *clevis luks regen* command regenerates the LUKS metadata for a given slot in a LUKS device. It effectively
+performs an operation equivalent to *clevis luks unbind* and *clevis luks bind* for rebinding said slot and device.
+
+== OPTIONS
+
+* *-d* _DEV_ :
+ The bound LUKS device
+
+* *-s* _SLT_ :
+ The slot or key slot number for rebinding. Note that it requires that such slot is currently bound by clevis.
+
+== EXAMPLE
+
+ Regenerate the binding of slot 1 from /dev/sda1:
+
+ # clevis luks regen -d /dev/sda1 -s 1
+
+== SEE ALSO
+
+link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)]
+link:clevis-luks-unbind.1.adoc[*clevis-luks-unbind*(1)]
diff --git a/src/luks/clevis-luks-report b/src/luks/clevis-luks-report diff --git a/src/luks/clevis-luks-report b/src/luks/clevis-luks-report
new file mode 100755 new file mode 100755
index 0000000..f047256 index 0000000..f047256
@ -831,17 +442,13 @@ index 0000000..cf42afe
+ +
+link:clevis-luks-regen.1.adoc[*clevis-luks-regen*(1)] +link:clevis-luks-regen.1.adoc[*clevis-luks-regen*(1)]
diff --git a/src/luks/meson.build b/src/luks/meson.build diff --git a/src/luks/meson.build b/src/luks/meson.build
index 1f64ab0..7c045c4 100644 index f21388d..ee588c3 100644
--- a/src/luks/meson.build --- a/src/luks/meson.build
+++ b/src/luks/meson.build +++ b/src/luks/meson.build
@@ -15,6 +15,18 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found() @@ -47,6 +47,13 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found()
bins += join_paths(meson.current_source_dir(), 'clevis-luks-bind')
mans += join_paths(meson.current_source_dir(), 'clevis-luks-bind.1')
+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-common-functions') bins += join_paths(meson.current_source_dir(), 'clevis-luks-regen')
+ mans += join_paths(meson.current_source_dir(), 'clevis-luks-regen.1')
+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-regen')
+ mans += join_paths(meson.current_source_dir(), 'clevis-luks-regen.1')
+ +
+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-report') + bins += join_paths(meson.current_source_dir(), 'clevis-luks-report')
+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-compare') + bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-compare')
@ -849,10 +456,9 @@ index 1f64ab0..7c045c4 100644
+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-sss') + bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-sss')
+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-tang') + bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-tang')
+ mans += join_paths(meson.current_source_dir(), 'clevis-luks-report.1') + mans += join_paths(meson.current_source_dir(), 'clevis-luks-report.1')
+
mans += join_paths(meson.current_source_dir(), 'clevis-luks-unlockers.7')
else else
warning('Will not install LUKS support due to missing dependencies!') warning('Will not install LUKS support due to missing dependencies!')
endif
-- --
2.21.0 2.18.4

View File

@ -0,0 +1,339 @@
From 3250784e99016d9f920892dbb1438b9e76fb210b Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Sun, 10 May 2020 15:57:23 -0300
Subject: [PATCH 8/8] Use one clevis-luks-askpass per device
This should improve the reliability of the boot unlocking, especially
when unlocking multiple devices upon boot.
It also greatly simplifies the configuration, as there is no need to
enable any systemd units manually nor add _netdev to either fstab or
crypttab.
---
src/luks/clevis-luks-common-functions | 8 ++
src/luks/clevis-luks-unlockers.7.adoc | 16 +---
src/luks/systemd/clevis-luks-askpass | 81 ++++++-------------
src/luks/systemd/clevis-luks-askpass.path | 10 ---
.../systemd/clevis-luks-askpass.service.in | 8 --
src/luks/systemd/clevis-luks-askpass@.path | 12 +++
.../systemd/clevis-luks-askpass@.service.in | 8 ++
.../systemd/dracut/clevis/module-setup.sh.in | 23 ++++++
src/luks/systemd/meson.build | 6 +-
9 files changed, 80 insertions(+), 92 deletions(-)
delete mode 100644 src/luks/systemd/clevis-luks-askpass.path
delete mode 100644 src/luks/systemd/clevis-luks-askpass.service.in
create mode 100644 src/luks/systemd/clevis-luks-askpass@.path
create mode 100644 src/luks/systemd/clevis-luks-askpass@.service.in
diff --git a/src/luks/clevis-luks-common-functions b/src/luks/clevis-luks-common-functions
index 5b515ad..c9d712a 100644
--- a/src/luks/clevis-luks-common-functions
+++ b/src/luks/clevis-luks-common-functions
@@ -555,3 +555,11 @@ clevis_luks_restore_dev() {
fi
return 0
}
+
+# clevis_is_luks_device_by_uuid_open() checks whether the LUKS device with
+# given UUID is open.
+clevis_is_luks_device_by_uuid_open() {
+ local LUKS_UUID="${1}"
+ [ -z "${LUKS_UUID}" ] && return 1
+ test -b /dev/disk/by-id/dm-uuid-*"${LUKS_UUID//-/}"*
+}
diff --git a/src/luks/clevis-luks-unlockers.7.adoc b/src/luks/clevis-luks-unlockers.7.adoc
index 161b73a..e8d47ba 100644
--- a/src/luks/clevis-luks-unlockers.7.adoc
+++ b/src/luks/clevis-luks-unlockers.7.adoc
@@ -26,7 +26,7 @@ You can unlock a LUKS volume manually using the following command:
For more information, see link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)].
-== EARLY BOOT UNLOCKING
+== BOOT UNLOCKING
If Clevis integration does not already ship in your initramfs, you may need to
rebuild your initramfs with this command:
@@ -34,23 +34,13 @@ rebuild your initramfs with this command:
$ sudo dracut -f
Once Clevis is integrated into your initramfs, a simple reboot should unlock
-your root volume. Note, however, that early boot integration only works for the
-root volume. Non-root volumes should use the late boot unlocker.
+your clevis-bound volumes. Root volumes will be unlocked in early-boot, while the
+remaining volumes will be unlocked after dracut switch-root.
Dracut will bring up your network using DHCP by default. If you need to specify
additional network parameters, such as static IP configuration, please consult
the dracut documentation.
-== LATE BOOT UNLOCKING
-
-You can enable late boot unlocking by executing the following command:
-
- $ sudo systemctl enable clevis-luks-askpass.path
-
-After a reboot, Clevis will attempt to unlock all *_netdev* devices listed in
-*/etc/crypttab* when systemd prompts for their passwords. This implies that
-systemd support for *_netdev* is required.
-
== DESKTOP UNLOCKING
When the udisks2 unlocker is installed, your GNOME desktop session should
diff --git a/src/luks/systemd/clevis-luks-askpass b/src/luks/systemd/clevis-luks-askpass
index 9fea6aa..20294e5 100755
--- a/src/luks/systemd/clevis-luks-askpass
+++ b/src/luks/systemd/clevis-luks-askpass
@@ -19,96 +19,61 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
+. clevis-luks-common-functions
shopt -s nullglob
path=/run/systemd/ask-password
-while getopts ":lp:" o; do
+while getopts ":lp:u:" o; do
case "$o" in
l) loop=true;;
p) path="$OPTARG";;
+ u) device_uuid=$OPTARG;;
+ *) ;;
esac
done
-luks1_decrypt() {
- luksmeta load "$@" \
- | clevis decrypt
-
- local rc
- for rc in "${PIPESTATUS[@]}"; do
- [ $rc -eq 0 ] || return $rc
- done
- return 0
-}
-
-luks2_jwe() {
- # jose jwe fmt -c outputs extra \n, so clean it up
- cryptsetup token export "$@" \
- | jose fmt -j- -Og jwe -o- \
- | jose jwe fmt -i- -c \
- | tr -d '\n'
-
- local rc
- for rc in "${PIPESTATUS[@]}"; do
- [ $rc -eq 0 ] || return $rc
- done
- return 0
-}
-
while true; do
todo=0
for question in "$path"/ask.*; do
- metadata=false
unlocked=false
d=
s=
- while read line; do
+ while read -r line; do
case "$line" in
Id=cryptsetup:*) d="${line##Id=cryptsetup:}";;
Socket=*) s="${line##Socket=}";;
esac
done < "$question"
- [ "$d" ] && [ "$s" ] || continue
+ [ -b "${d}" ] || continue
+ [ -S "${s}" ] || continue
- if cryptsetup isLuks --type luks1 "$d"; then
- # If the device is not initialized, sliently skip it.
- luksmeta test -d "$d" || continue
-
- while read -r slot state uuid; do
- [ "$state" == "active" ] || continue
- [ "$uuid" == "$UUID" ] || continue
- metadata=true
-
- if pt="$(luks1_decrypt -d "$d" -s "$slot" -u "$UUID")"; then
- echo -n "+$pt" | ncat -U -u --send-only "$s"
- unlocked=true
- break
- fi
- done < <(luksmeta show -d "$d")
- elif cryptsetup isLuks --type luks2 "$d"; then
- while read -r id; do
- jwe="$(luks2_jwe --token-id "$id" "$d")" \
- || continue
- metadata=true
+ if [ -n "${device_uuid}" ]; then
+ uuid="$(cryptsetup luksUUID "${d}")"
+ [ "${uuid}" != "${device_uuid}" ] && todo=1 && continue
+ fi
- if pt="$(echo -n "$jwe" | clevis decrypt)"; then
- echo -n "+$pt" | ncat -U -u --send-only "$s"
- unlocked=true
- break
- fi
- done < <(cryptsetup luksDump "$d" | sed -rn 's|^\s+([0-9]+): clevis|\1|p')
+ if pt="$(clevis_luks_unlock_device "${d}")"; then
+ echo -n "+$pt" | ncat -U -u --send-only "$s"
+ unlocked=true
fi
- [ "$metadata" == true ] || continue
+ [ -n "${device_uuid}" ] && [ "${unlocked}" == true ] && break
[ "$unlocked" == true ] && continue
((todo++))
done
- if [ $todo -eq 0 ] || [ "$loop" != true ]; then
+ if [ -n "${device_uuid}" ]; then
+ [ ! -b /dev/disk/by-uuid/"${device_uuid}" ] && break
+ if clevis_is_luks_device_by_uuid_open "${device_uuid}"; then
+ break
+ fi
+ fi
+
+ if [ "$todo" -eq 0 ] || [ "$loop" != true ]; then
break;
fi
diff --git a/src/luks/systemd/clevis-luks-askpass.path b/src/luks/systemd/clevis-luks-askpass.path
deleted file mode 100644
index a4d01ba..0000000
--- a/src/luks/systemd/clevis-luks-askpass.path
+++ /dev/null
@@ -1,10 +0,0 @@
-[Unit]
-Description=Clevis systemd-ask-password Watcher
-Before=remote-fs-pre.target
-Wants=remote-fs-pre.target
-
-[Path]
-PathChanged=/run/systemd/ask-password
-
-[Install]
-WantedBy=remote-fs.target
diff --git a/src/luks/systemd/clevis-luks-askpass.service.in b/src/luks/systemd/clevis-luks-askpass.service.in
deleted file mode 100644
index 2c6bbed..0000000
--- a/src/luks/systemd/clevis-luks-askpass.service.in
+++ /dev/null
@@ -1,8 +0,0 @@
-[Unit]
-Description=Clevis LUKS systemd-ask-password Responder
-Requires=network-online.target
-After=network-online.target
-
-[Service]
-Type=oneshot
-ExecStart=@libexecdir@/clevis-luks-askpass -l
diff --git a/src/luks/systemd/clevis-luks-askpass@.path b/src/luks/systemd/clevis-luks-askpass@.path
new file mode 100644
index 0000000..3f23665
--- /dev/null
+++ b/src/luks/systemd/clevis-luks-askpass@.path
@@ -0,0 +1,12 @@
+[Unit]
+Description=Clevis systemd-ask-password Watcher for %i
+DefaultDependencies=no
+Conflicts=shutdown.target
+Before=basic.target shutdown.target
+
+[Path]
+DirectoryNotEmpty=/run/systemd/ask-password
+MakeDirectory=yes
+
+[Install]
+WantedBy=basic.target
diff --git a/src/luks/systemd/clevis-luks-askpass@.service.in b/src/luks/systemd/clevis-luks-askpass@.service.in
new file mode 100644
index 0000000..4165ec5
--- /dev/null
+++ b/src/luks/systemd/clevis-luks-askpass@.service.in
@@ -0,0 +1,8 @@
+[Unit]
+Description=Clevis LUKS systemd-ask-password Responder for luks-%i
+DefaultDependencies=no
+Conflicts=shutdown.target
+Before=shutdown.target
+
+[Service]
+ExecStart=@libexecdir@/clevis-luks-askpass -u %i
diff --git a/src/luks/systemd/dracut/clevis/module-setup.sh.in b/src/luks/systemd/dracut/clevis/module-setup.sh.in
index abc79b3..1a0d6f7 100755
--- a/src/luks/systemd/dracut/clevis/module-setup.sh.in
+++ b/src/luks/systemd/dracut/clevis/module-setup.sh.in
@@ -23,6 +23,24 @@ depends() {
return 255
}
+configure_passwd_watchers() {
+ if ! command -v systemctl >/dev/null; then
+ return 1
+ fi
+
+ find /etc/systemd/system/ -name "clevis-luks-askpass*" -exec rm -f {} \;
+
+ local uuid
+ for dev in $(lsblk -p -n -s -r \
+ | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
+ uuid=$(cryptsetup luksUUID "${dev}")
+
+ if clevis luks list -d "${dev}" >/dev/null 2>/dev/null; then
+ systemctl enable "clevis-luks-askpass@${uuid}.path" 2>/dev/null
+ fi
+ done
+}
+
install() {
inst_hook initqueue/online 60 "$moddir/clevis-hook.sh"
inst_hook initqueue/settled 60 "$moddir/clevis-hook.sh"
@@ -30,6 +48,10 @@ install() {
inst_multiple \
/etc/services \
@libexecdir@/clevis-luks-askpass \
+ clevis-luks-common-functions \
+ head \
+ grep \
+ sed \
clevis-decrypt \
cryptsetup \
luksmeta \
@@ -38,5 +60,6 @@ install() {
jose \
ncat
+ configure_passwd_watchers
dracut_need_initqueue
}
diff --git a/src/luks/systemd/meson.build b/src/luks/systemd/meson.build
index 369e7f7..334e84c 100644
--- a/src/luks/systemd/meson.build
+++ b/src/luks/systemd/meson.build
@@ -6,13 +6,13 @@ if systemd.found()
unitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
configure_file(
- input: 'clevis-luks-askpass.service.in',
- output: 'clevis-luks-askpass.service',
+ input: 'clevis-luks-askpass@.service.in',
+ output: 'clevis-luks-askpass@.service',
install_dir: unitdir,
configuration: data,
)
- install_data('clevis-luks-askpass.path', install_dir: unitdir)
+ install_data('clevis-luks-askpass@.path', install_dir: unitdir)
install_data('clevis-luks-askpass', install_dir: libexecdir)
else
warning('Will not install systemd support due to missing dependencies!')
--
2.18.4

View File

@ -0,0 +1,555 @@
From 7b1639b2194a8bfbb0daedf1cbdfc4ebef5f6b31 Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Mon, 18 May 2020 08:36:17 -0300
Subject: [PATCH] Introduce -y (assume yes) argument to clevis luks bind
In order to simplify automated operations with e.g. ansible,
it would be helpful to have a way to automate the creation of
bindings with clevis.
In simple scenarios, it's possible to download the advertisement
from a tang server and pass it in the binding configuration, to
do the binding offline, in the following way:
curl -sfg http://tang.server/adv -o adv.jws
clevis luks bind -d /dev/sda2 tang '{"url":"http://tang.server", "adv":"adv.jws}'
However, for more complex scenarios using multiple servers with
the sss pin, it becomes a lot more complicated to do the same
thing and do the binding in an automated fashion. An alternative
would be to use expect (tcl), but it can also be complicated.
In this commit we introduce -y as a parameter to clevis luks bind,
meanining _assume yes_. Essentially, this would make it so that
the user would not have to manually trust tang key(s) by typing
y/yes.
Security-wise, it would be similar to downloading the advertisement
manually and passing it to tang as the "adv" configuration option,
something already supported.
We already have a -f parameter, so we picked something different,
not to change existing behavior and possibly break existing scripts.
---
src/luks/clevis-luks-bind.1.adoc | 7 +-
src/luks/clevis-luks-bind.in | 11 +++-
src/luks/clevis-luks-regen | 4 +-
src/luks/tests/assume-yes-luks1 | 81 ++++++++++++++++++++++++
src/luks/tests/assume-yes-luks2 | 81 ++++++++++++++++++++++++
src/luks/tests/meson.build | 2 +
src/pins/sss/clevis-encrypt-sss.1.adoc | 14 +++-
src/pins/sss/clevis-encrypt-sss.c | 30 ++++++---
src/pins/tang/clevis-encrypt-tang | 35 ++++++----
src/pins/tang/clevis-encrypt-tang.1.adoc | 11 +++-
10 files changed, 246 insertions(+), 30 deletions(-)
create mode 100755 src/luks/tests/assume-yes-luks1
create mode 100755 src/luks/tests/assume-yes-luks2
diff --git a/src/luks/clevis-luks-bind.1.adoc b/src/luks/clevis-luks-bind.1.adoc
index 336c0f4..438e517 100644
--- a/src/luks/clevis-luks-bind.1.adoc
+++ b/src/luks/clevis-luks-bind.1.adoc
@@ -9,7 +9,7 @@ clevis-luks-bind - Bind a LUKS device using the specified policy
== SYNOPSIS
-*clevis luks bind* [-f] -d DEV [-s SLT] [-k KEY] PIN CFG
+*clevis luks bind* [-f] [-y] -d DEV [-s SLT] [-k KEY] PIN CFG
== OVERVIEW
@@ -34,6 +34,11 @@ Clevis LUKS unlockers. See link:clevis-luks-unlockers.7.adoc[*clevis-luks-unlock
* *-f* :
Do not prompt for LUKSMeta initialization
+* *-y* :
+ Automatically answer yes for all questions. When using _tang_, it
+ causes the advertisement trust check to be skipped, which can be
+ useful in automated deployments
+
* *-d* _DEV_ :
The LUKS device on which to perform binding
diff --git a/src/luks/clevis-luks-bind.in b/src/luks/clevis-luks-bind.in
index 89a5e22..8b8b5ee 100755
--- a/src/luks/clevis-luks-bind.in
+++ b/src/luks/clevis-luks-bind.in
@@ -33,12 +33,14 @@ function luks2_supported() {
function usage() {
exec >&2
echo
- echo "Usage: clevis luks bind [-f] [-s SLT] [-k KEY] -d DEV PIN CFG"
+ echo "Usage: clevis luks bind [-f] [-y] [-s SLT] [-k KEY] -d DEV PIN CFG"
echo
echo "$SUMMARY":
echo
echo " -f Do not prompt for LUKSMeta initialization"
echo
+ echo " -y Automatically answer yes for all questions"
+ echo
echo " -d DEV The LUKS device on which to perform binding"
echo
echo " -s SLT The LUKS slot to use"
@@ -55,12 +57,15 @@ if [ $# -eq 1 ] && [ "$1" == "--summary" ]; then
fi
FRC=()
-while getopts ":hfd:s:k:" o; do
+YES=()
+while getopts ":fyd:s:k:" o; do
case "$o" in
f) FRC+=(-f);;
d) DEV="$OPTARG";;
s) SLT="$OPTARG";;
k) KEY="$OPTARG";;
+ y) FRC+=(-f)
+ YES+=(-y);;
*) usage;;
esac
done
@@ -139,7 +144,7 @@ cryptsetup luksDump "$DEV" \
)")"
# Encrypt the new key
-jwe="$(echo -n "$key" | clevis encrypt "$PIN" "$CFG")"
+jwe="$(echo -n "$key" | clevis encrypt "$PIN" "$CFG" "${YES}")"
# If necessary, initialize the LUKS volume
if [ "$luks_type" == "luks1" ] && ! luksmeta test -d "$DEV"; then
diff --git a/src/luks/clevis-luks-regen b/src/luks/clevis-luks-regen
index 44fd673..6071d85 100755
--- a/src/luks/clevis-luks-regen
+++ b/src/luks/clevis-luks-regen
@@ -110,7 +110,7 @@ if ! new_passphrase=$(generate_key "${DEV}"); then
fi
# Reencrypt the new password.
-if ! jwe=$(clevis encrypt "${PIN}" "${CFG}" <<< "${new_passphrase}"); then
+if ! jwe="$(clevis encrypt "${PIN}" "${CFG}" <<< "${new_passphrase}")"; then
echo "Error using pin '${PIN}' with config '${CFG}'" >&2
exit 1
fi
@@ -176,7 +176,7 @@ fi
# Now make sure that we can unlock this device after the change.
# If we can't, undo the changes.
if ! cryptsetup open --test-passphrase --key-slot "${SLT}" "${DEV}" 2>/dev/null \
- <<< $(clevis luks pass -d "${DEV}" -s "${SLT}" 2>/dev/null); then
+ <<< "$(clevis luks pass -d "${DEV}" -s "${SLT}" 2>/dev/null)"; then
echo "Invalid configuration detected after rebinding. Reverting changes."
restore_device "${DEV}" "${TMP}"
exit 1
diff --git a/src/luks/tests/assume-yes-luks1 b/src/luks/tests/assume-yes-luks1
new file mode 100755
index 0000000..ad9dea4
--- /dev/null
+++ b/src/luks/tests/assume-yes-luks1
@@ -0,0 +1,81 @@
+#!/bin/bash -ex
+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2020 Red Hat, Inc.
+# Author: Sergio Correia <scorreia@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+TEST=$(basename "${0}")
+. tests-common-functions
+
+. clevis-luks-common-functions
+
+on_exit() {
+ local d
+ for d in "${TMP}" "${TMP2}"; do
+ [ ! -d "${d}" ] && continue
+ tang_stop "${d}"
+ rm -rf "${d}"
+ done
+}
+
+trap 'on_exit' EXIT
+trap 'on_exit' ERR
+
+TMP="$(mktemp -d)"
+
+port=$(get_random_port)
+tang_run "${TMP}" "${port}" &
+tang_wait_until_ready "${port}"
+
+url="http://${TANG_HOST}:${port}"
+
+cfg=$(printf '{"url":"%s"}' "$url")
+
+# LUKS1.
+DEV="${TMP}/luks1-device"
+new_device "luks1" "${DEV}"
+
+if ! clevis luks bind -y -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then
+ error "${TEST}: Bind should have succeeded."
+fi
+
+if ! clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we were unable to unlock ${DEV}."
+fi
+
+# Let's use a second tang server to test the sss pin.
+TMP2="$(mktemp -d)"
+
+port2=$(get_random_port)
+tang_run "${TMP2}" "${port2}" &
+tang_wait_until_ready "${port2}"
+
+url2="http://${TANG_HOST}:${port2}"
+
+cfg2=$(printf '{"t":1,"pins":{"tang":[{"url":"%s"},{"url":"%s"}]}}' \
+ "${url1}" "${url2}")
+
+# LUKS1.
+new_device "luks1" "${DEV}"
+# Now let's test the sss pin with the two test tang servers we deployed.
+if ! clevis luks bind -y -d "${DEV}" sss "${cfg2}" <<< "${DEFAULT_PASS}"; then
+ error "${TEST}: Bind should have succeeded."
+fi
+
+# Unlock should still work now.
+if ! clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we should still be able to unlock ${DEV}"
+fi
diff --git a/src/luks/tests/assume-yes-luks2 b/src/luks/tests/assume-yes-luks2
new file mode 100755
index 0000000..5c0edc3
--- /dev/null
+++ b/src/luks/tests/assume-yes-luks2
@@ -0,0 +1,81 @@
+#!/bin/bash -ex
+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2020 Red Hat, Inc.
+# Author: Sergio Correia <scorreia@redhat.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+TEST=$(basename "${0}")
+. tests-common-functions
+
+. clevis-luks-common-functions
+
+on_exit() {
+ local d
+ for d in "${TMP}" "${TMP2}"; do
+ [ ! -d "${d}" ] && continue
+ tang_stop "${d}"
+ rm -rf "${d}"
+ done
+}
+
+trap 'on_exit' EXIT
+trap 'on_exit' ERR
+
+TMP="$(mktemp -d)"
+
+port=$(get_random_port)
+tang_run "${TMP}" "${port}" &
+tang_wait_until_ready "${port}"
+
+url="http://${TANG_HOST}:${port}"
+
+cfg=$(printf '{"url":"%s"}' "$url")
+
+# LUKS2.
+DEV="${TMP}/luks2-device"
+new_device "luks2" "${DEV}"
+
+if ! clevis luks bind -y -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then
+ error "${TEST}: Bind should have succeeded."
+fi
+
+if ! clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we were unable to unlock ${DEV}."
+fi
+
+# Let's use a second tang server to test the sss pin.
+TMP2="$(mktemp -d)"
+
+port2=$(get_random_port)
+tang_run "${TMP2}" "${port2}" &
+tang_wait_until_ready "${port2}"
+
+url2="http://${TANG_HOST}:${port2}"
+
+cfg2=$(printf '{"t":1,"pins":{"tang":[{"url":"%s"},{"url":"%s"}]}}' \
+ "${url1}" "${url2}")
+
+# LUKS2.
+new_device "luks2" "${DEV}"
+# Now let's test the sss pin with the two test tang servers we deployed.
+if ! clevis luks bind -y -d "${DEV}" sss "${cfg2}" <<< "${DEFAULT_PASS}"; then
+ error "${TEST}: Bind should have succeeded."
+fi
+
+# Unlock should still work now.
+if ! clevis_luks_unlock_device "${DEV}"; then
+ error "${TEST}: we should still be able to unlock ${DEV}"
+fi
diff --git a/src/luks/tests/meson.build b/src/luks/tests/meson.build
index dbef9bf..4795488 100644
--- a/src/luks/tests/meson.build
+++ b/src/luks/tests/meson.build
@@ -85,6 +85,7 @@ endif
if has_tang
test('unlock-tang-luks1', find_program('unlock-tang-luks1'), env: env, timeout: 90)
+ test('assume-yes-luks1', find_program('assume-yes-luks1'), env: env)
endif
test('pass-tang-luks1', find_program('pass-tang-luks1'), env: env)
test('backup-restore-luks1', find_program('backup-restore-luks1'), env: env)
@@ -108,6 +109,7 @@ if luksmeta_data.get('OLD_CRYPTSETUP') == '0'
if has_tang
test('unlock-tang-luks2', find_program('unlock-tang-luks2'), env: env, timeout: 120)
+ test('assume-yes-luks2', find_program('assume-yes-luks2'), env: env, timeout: 60)
endif
test('pass-tang-luks2', find_program('pass-tang-luks2'), env: env, timeout: 60)
test('backup-restore-luks2', find_program('backup-restore-luks2'), env:env, timeout: 90)
diff --git a/src/pins/sss/clevis-encrypt-sss.1.adoc b/src/pins/sss/clevis-encrypt-sss.1.adoc
index 7144e7e..7152144 100644
--- a/src/pins/sss/clevis-encrypt-sss.1.adoc
+++ b/src/pins/sss/clevis-encrypt-sss.1.adoc
@@ -5,11 +5,11 @@ CLEVIS-ENCRYPT-SSS(1)
== NAME
-clevis-encrypt-sss - Encrypts using a Shamir's Secret Sharing policy
+clevis-encrypt-sss - Encrypts using a Shamir's Secret Sharing policy
== SYNOPSIS
-*clevis encrypt sss* CONFIG < PT > JWE
+*clevis encrypt sss* CONFIG [-y] < PT > JWE
== OVERVIEW
@@ -52,6 +52,16 @@ The format of the *pins* property is as follows:
When the list version of the format is used, multiple pins of that type will
receive key fragments.
+== OPTIONS
+
+* *-y* :
+ Automatically answer yes for all questions. For the _tang_ pin, it will
+ skip the advertisement trust check, which can be useful in automated
+ deployments:
+
+ $ cfg='{"t":1,"pins":{"tang":[{"url":...},{"url":...}]}}'
+ $ clevis encrypt sss "$cfg" -y < PT > JWE
+
== SEE ALSO
link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)],
diff --git a/src/pins/sss/clevis-encrypt-sss.c b/src/pins/sss/clevis-encrypt-sss.c
index d6f2c2c..531e918 100644
--- a/src/pins/sss/clevis-encrypt-sss.c
+++ b/src/pins/sss/clevis-encrypt-sss.c
@@ -86,9 +86,9 @@ npins(json_t *pins)
}
static json_t *
-encrypt_frag(json_t *sss, const char *pin, const json_t *cfg)
+encrypt_frag(json_t *sss, const char *pin, const json_t *cfg, int assume_yes)
{
- char *args[] = { "clevis", "encrypt", (char *) pin, NULL, NULL };
+ char *args[] = { "clevis", "encrypt", (char *) pin, NULL, NULL, NULL };
json_auto_t *jwe = json_string("");
str_auto_t *str = NULL;
uint8_t *pnt = NULL;
@@ -100,6 +100,10 @@ encrypt_frag(json_t *sss, const char *pin, const json_t *cfg)
if (!str)
return NULL;
+ if (assume_yes) {
+ args[4] = "-y";
+ }
+
pnt = sss_point(sss, &pntl);
if (!pnt)
return NULL;
@@ -137,7 +141,7 @@ encrypt_frag(json_t *sss, const char *pin, const json_t *cfg)
}
static json_t *
-encrypt_frags(json_int_t t, json_t *pins)
+encrypt_frags(json_int_t t, json_t *pins, int assume_yes)
{
const char *pname = NULL;
json_auto_t *sss = NULL;
@@ -172,7 +176,7 @@ encrypt_frags(json_int_t t, json_t *pins)
json_array_foreach(pcfgs, i, pcfg) {
json_auto_t *jwe = NULL;
- jwe = encrypt_frag(sss, pname, pcfg);
+ jwe = encrypt_frag(sss, pname, pcfg, assume_yes);
if (!jwe)
return NULL;
@@ -201,14 +205,24 @@ main(int argc, char *argv[])
const char *iv = NULL;
json_t *pins = NULL;
json_int_t t = 1;
+ int assume_yes = 0;
if (argc == 2 && strcmp(argv[1], "--summary") == 0) {
fprintf(stdout, "%s\n", SUMMARY);
return EXIT_SUCCESS;
}
- if (isatty(STDIN_FILENO) || argc != 2)
- goto usage;
+ if (isatty(STDIN_FILENO) || argc != 2) {
+ if (argc != 3) {
+ goto usage;
+ }
+
+ if (strcmp(argv[2], "-y") == 0) {
+ assume_yes = 1;
+ } else if (strlen(argv[2]) > 0) {
+ goto usage;
+ }
+ }
/* Parse configuration. */
cfg = json_loads(argv[1], 0, NULL);
@@ -228,7 +242,7 @@ main(int argc, char *argv[])
return EXIT_FAILURE;
}
- sss = encrypt_frags(t, pins);
+ sss = encrypt_frags(t, pins, assume_yes);
if (!sss)
return EXIT_FAILURE;
@@ -287,7 +301,7 @@ main(int argc, char *argv[])
usage:
fprintf(stderr, "\n");
- fprintf(stderr, "Usage: clevis encrypt sss CONFIG < PLAINTEXT > JWE\n");
+ fprintf(stderr, "Usage: clevis encrypt sss CONFIG [-y] < PLAINTEXT > JWE\n");
fprintf(stderr, "\n");
fprintf(stderr, "%s\n", SUMMARY);
fprintf(stderr, "\n");
diff --git a/src/pins/tang/clevis-encrypt-tang b/src/pins/tang/clevis-encrypt-tang
index 378b25d..4a43f1f 100755
--- a/src/pins/tang/clevis-encrypt-tang
+++ b/src/pins/tang/clevis-encrypt-tang
@@ -28,10 +28,14 @@ fi
if [ -t 0 ]; then
exec >&2
echo
- echo "Usage: clevis encrypt tang CONFIG < PLAINTEXT > JWE"
+ echo "Usage: clevis encrypt tang CONFIG [-y] < PLAINTEXT > JWE"
echo
echo "$SUMMARY"
echo
+ echo " -y Use this option for skipping the advertisement"
+ echo " trust check. This can be useful in automated"
+ echo " deployments"
+ echo
echo "This command uses the following configuration properties:"
echo
echo " url: <string> The base URL of the Tang server (REQUIRED)"
@@ -60,6 +64,9 @@ if ! cfg="$(jose fmt -j- -Oo- <<< "$1" 2>/dev/null)"; then
exit 1
fi
+trust=
+[ -n "${2}" ] && [ "${2}" == "-y" ] && trust=yes
+
if ! url="$(jose fmt -j- -Og url -u- <<< "$cfg")"; then
echo "Missing the required 'url' property!" >&2
exit 1
@@ -100,18 +107,20 @@ if ! jose jws ver -i "$jws" -k- -a <<< "$ver"; then
fi
### Check advertisement trust
-if [ -z "$thp" ]; then
- echo "The advertisement contains the following signing keys:" >&2
- echo >&2
- jose jwk thp -i- <<< "$ver" >&2
- echo >&2
- read -r -p "Do you wish to trust these keys? [ynYN] " ans < /dev/tty
- [[ "$ans" =~ ^[yY]$ ]] || exit 1
-
-elif [ "$thp" != "any" ] && \
- ! jose jwk thp -i- -f "$thp" -o /dev/null <<< "$ver"; then
- echo "Trusted JWK '$thp' did not sign the advertisement!" >&2
- exit 1
+if [ -z "${trust}" ]; then
+ if [ -z "$thp" ]; then
+ echo "The advertisement contains the following signing keys:" >&2
+ echo >&2
+ jose jwk thp -i- <<< "$ver" >&2
+ echo >&2
+ read -r -p "Do you wish to trust these keys? [ynYN] " ans < /dev/tty
+ [[ "$ans" =~ ^[yY]$ ]] || exit 1
+
+ elif [ "$thp" != "any" ] && \
+ ! jose jwk thp -i- -f "$thp" -o /dev/null <<< "$ver"; then
+ echo "Trusted JWK '$thp' did not sign the advertisement!" >&2
+ exit 1
+ fi
fi
### Perform encryption
diff --git a/src/pins/tang/clevis-encrypt-tang.1.adoc b/src/pins/tang/clevis-encrypt-tang.1.adoc
index 276575f..c34d109 100644
--- a/src/pins/tang/clevis-encrypt-tang.1.adoc
+++ b/src/pins/tang/clevis-encrypt-tang.1.adoc
@@ -9,7 +9,7 @@ clevis-encrypt-tang - Encrypts using a Tang binding server policy
== SYNOPSIS
-*clevis encrypt tang* CONFIG < PT > JWE
+*clevis encrypt tang* CONFIG [-y] < PT > JWE
== OVERVIEW
@@ -76,6 +76,15 @@ This command uses the following configuration properties:
* *adv* (object) :
A trusted advertisement (raw JSON)
+== OPTIONS
+
+* *-y* :
+ Automatically answer yes for all questions. Use this option for skipping
+ the advertisement trust check. This can be useful in automated deployments:
+
+ $ clevis encrypt tang '{"url":...}' -y < PT > JWE
+
+
== SEE ALSO
link:clevis-decrypt.1.adoc[*clevis-decrypt*(1)]
--
2.18.4

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +0,0 @@
From 6826e5d31d6323eac5137404f0194bf2183b561c Mon Sep 17 00:00:00 2001
From: Javier Martinez Canillas <javierm@redhat.com>
Date: Wed, 7 Nov 2018 16:48:47 +0100
Subject: [PATCH 3/3] Add device TCTI library to the initramfs
The tpm2-tools don't dynamically link against the TCTI libraries anymore,
but instead dlopen() the correct library depending on the TCTI used.
So dracut isn't able anymore to figure out automatically using ldd what
libraries are needed by the tpm2-tools. Since clevis uses the device TCTI
to access the TPM directly, add the libtss2-tcti-device.so to the initrd.
Suggested-by: Federico Chiacchiaretta <federico.chia@gmail.com>
Fixes: ##74
---
src/luks/systemd/dracut/module-setup.sh.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/luks/systemd/dracut/module-setup.sh.in b/src/luks/systemd/dracut/module-setup.sh.in
index 41e7d6c9b002..990bf4aeed56 100755
--- a/src/luks/systemd/dracut/module-setup.sh.in
+++ b/src/luks/systemd/dracut/module-setup.sh.in
@@ -65,6 +65,7 @@ install() {
tpm2_pcrlist \
tpm2_unseal \
tpm2_load
+ inst_libdir_file "libtss2-tcti-device.so*"
fi
dracut_need_initqueue
--
2.19.1

View File

@ -1,57 +0,0 @@
From 25009adea66d3bf9b73f128273de28e532b03281 Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Sat, 30 Nov 2019 18:23:09 -0500
Subject: [PATCH] Add rd.neednet=1 to cmdline only if there are devices bound
to tang
---
src/luks/systemd/dracut/module-setup.sh.in | 24 ++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/src/luks/systemd/dracut/module-setup.sh.in b/src/luks/systemd/dracut/module-setup.sh.in
index 990bf4a..841f7a8 100755
--- a/src/luks/systemd/dracut/module-setup.sh.in
+++ b/src/luks/systemd/dracut/module-setup.sh.in
@@ -18,19 +18,35 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+is_bound_to_tang() {
+ local dev
+ for dev in $(lsblk -p -n -s -r \
+ | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
+ if clevis luks list -d "${dev}" 2>/dev/null | grep -q tang; then
+ return 0
+ fi
+ done
+ return 1
+}
+
depends() {
- echo crypt systemd network
- return 0
+ local depends="crypt systemd"
+ if is_bound_to_tang; then
+ depends=$(printf "%s network" "${depends}")
+ fi
+ echo "${depends}"
}
-cmdline() {
+tang_cmdline() {
echo "rd.neednet=1"
}
install() {
local ret=0
- cmdline > "${initdir}/etc/cmdline.d/99clevis.conf"
+ if is_bound_to_tang; then
+ tang_cmdline > "${initdir}/etc/cmdline.d/99clevis.conf"
+ fi
inst_hook initqueue/online 60 "$moddir/clevis-hook.sh"
inst_hook initqueue/settled 60 "$moddir/clevis-hook.sh"
--
2.18.1

View File

@ -1,77 +0,0 @@
From 53ecfcf6d934206e3daef4ed3515a0d6f098e276 Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Wed, 16 Oct 2019 11:40:33 -0300
Subject: [PATCH 1/2] Adjust pin-tang test to account for newer tang without
tangd-update
---
src/pins/tang/meson.build | 9 ++-------
src/pins/tang/pin-tang | 11 ++++++++---
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/pins/tang/meson.build b/src/pins/tang/meson.build
index 110d72d..061a79f 100644
--- a/src/pins/tang/meson.build
+++ b/src/pins/tang/meson.build
@@ -8,11 +8,6 @@ kgen = find_program(
'/usr/libexec/tangd-keygen',
required: false
)
-updt = find_program(
- join_paths(libexecdir, 'tangd-update'),
- '/usr/libexec/tangd-update',
- required: false
-)
tang = find_program(
join_paths(libexecdir, 'tangd'),
'/usr/libexec/tangd',
@@ -25,7 +20,7 @@ if curl.found()
bins += join_paths(meson.current_source_dir(), 'clevis-encrypt-tang')
mans += join_paths(meson.current_source_dir(), 'clevis-encrypt-tang.1')
- if actv.found() and kgen.found() and updt.found() and tang.found()
+ if actv.found() and kgen.found() and tang.found()
env = environment()
env.set('SD_ACTIVATE', actv.path())
env.append('PATH',
@@ -42,4 +37,4 @@ if curl.found()
endif
else
warning('Will not install tang pin due to missing dependencies!')
-endif
\ No newline at end of file
+endif
diff --git a/src/pins/tang/pin-tang b/src/pins/tang/pin-tang
index f420818..9dcc2da 100755
--- a/src/pins/tang/pin-tang
+++ b/src/pins/tang/pin-tang
@@ -31,18 +31,23 @@ mkdir -p $TMP/db
mkdir -p $TMP/cache
# Generate the server keys
+KEYS=$TMP/db
tangd-keygen $TMP/db sig exc
-tangd-update $TMP/db $TMP/cache
+if which tangd-update; then
+ tangd-update $TMP/db $TMP/cache
+ KEYS=$TMP/cache
+fi
# Start the server
port=`shuf -i 1024-65536 -n 1`
-$SD_ACTIVATE --inetd -l 127.0.0.1:$port -a tangd $TMP/cache &
+$SD_ACTIVATE --inetd -l 127.0.0.1:$port -a tangd $KEYS &
export PID=$!
sleep 0.25
thp=`jose jwk thp -i "$TMP/db/sig.jwk"`
-adv="$TMP/cache/default.jws"
url="http://localhost:${port}"
+adv="$TMP/adv"
+curl "$url/adv" -o $adv
cfg=`printf '{"url":"%s","adv":"%s"}' "$url" "$adv"`
enc=`echo -n "hi" | clevis encrypt tang "$cfg"`
--
2.21.0

View File

@ -1,30 +0,0 @@
From 8b707e8bfcbfd073579ee553b982b4784490f5ea Mon Sep 17 00:00:00 2001
From: Daniel Kopecek <dkopecek@redhat.com>
Date: Wed, 5 Dec 2018 13:18:59 +0100
Subject: [PATCH] clevis-encrypt-tang: check key derivation key is available
before encryption
---
src/pins/tang/clevis-encrypt-tang | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/pins/tang/clevis-encrypt-tang b/src/pins/tang/clevis-encrypt-tang
index e65a7d1..7fc55ca 100755
--- a/src/pins/tang/clevis-encrypt-tang
+++ b/src/pins/tang/clevis-encrypt-tang
@@ -114,7 +114,11 @@ elif [ "$thp" != "any" ] && \
fi
### Perform encryption
-enc=`jose jwk use -i- -r -u deriveKey -o- <<< "$jwks"`
+if ! enc=`jose jwk use -i- -r -u deriveKey -o- <<< "$jwks"`; then
+ echo "Key derivation key not available!" >&2
+ exit 1
+fi
+
jose fmt -j "$enc" -Og keys -A || enc="{\"keys\":[$enc]}"
for jwk in `jose fmt -j- -Og keys -Af- <<< "$enc"`; do
--
2.13.6

View File

@ -1,132 +0,0 @@
From 1e344dbf6a60fcd2c60a4b8512be455e112d8398 Mon Sep 17 00:00:00 2001
From: Javier Martinez Canillas <javierm@redhat.com>
Date: Wed, 7 Nov 2018 14:53:08 +0100
Subject: [PATCH 1/3] Delete remaining references to the removed http pin
Commit 800d73185d7f ("Remove HTTP pin") removed the clevis http pin, but
there are still references of it in the docs and also the dracut module.
This was causing dracut to fail building the initramfs due the following:
dracut-install: ERROR: installing 'clevis-decrypt-http'
Suggested-by: Dominick Grift <dac.override@gmail.com>
Fixes: #73
---
README.md | 21 ---------------------
src/clevis.1.adoc | 21 ---------------------
src/luks/clevis-luks-bind.1.adoc | 1 -
src/luks/systemd/dracut/module-setup.sh.in | 1 -
src/pins/sss/clevis-encrypt-sss.1.adoc | 1 -
5 files changed, 45 deletions(-)
diff --git a/README.md b/README.md
index ce8def12ec96..d57339aca5d9 100644
--- a/README.md
+++ b/README.md
@@ -58,27 +58,6 @@ advertisement is stored, or the JSON contents of the advertisment itself. When
the advertisment is specified manually like this, Clevis presumes that the
advertisement is trusted.
-#### PIN: HTTP
-
-Clevis also ships a pin for performing escrow using HTTP. Please note that,
-at this time, this pin does not provide HTTPS support and is suitable only
-for use over local sockets. This provides integration with services like
-[Custodia](http://github.com/latchset/custodia).
-
-For example:
-
-```bash
-$ echo hi | clevis encrypt http '{"url": "http://server.local/key"}' > hi.jwe
-```
-
-The HTTP pin generate a new (cryptographically-strong random) key and performs
-encryption using it. It then performs a PUT request to the URL specified. It is
-understood that the server will securely store this key for later retrieval.
-During decryption, the pin will perform a GET request to retrieve the key and
-perform decryption.
-
-Patches to provide support for HTTPS and authentication are welcome.
-
#### PIN: TPM2
Clevis provides support to encrypt a key in a Trusted Platform Module 2.0 (TPM2)
diff --git a/src/clevis.1.adoc b/src/clevis.1.adoc
index 756aba57a4c8..dea0a696f5f7 100644
--- a/src/clevis.1.adoc
+++ b/src/clevis.1.adoc
@@ -21,26 +21,6 @@ take a policy as its first argument and plaintext on standard input and to
encrypt the data so that it can be automatically decrypted if the policy is
met. Lets walk through an example.
-== HTTP ESCROW
-
-When using the HTTP pin, we create a new, cryptographically-strong, random key.
-This key is stored in a remote HTTP escrow server (using a simple PUT or POST).
-Then at decryption time, we attempt to fetch the key back again in order to
-decrypt our data. So, for our configuration we need to pass the URL to the key
-location:
-
- $ clevis encrypt http '{"url":"https://escrow.srv/1234"}' < PT > JWE
-
-To decrypt the data, simply provide the ciphertext (JWE):
-
- $ clevis decrypt < JWE > PLAINTEXT
-
-Notice that we did not pass any configuration during decryption. The decrypt
-command extracted the URL (and possibly other configuration) from the JWE
-object, fetched the encryption key from the escrow and performed decryption.
-
-For more information, see link:clevis-encrypt-http.1.adoc[*clevis-encrypt-http*(1)].
-
== TANG BINDING
Clevis provides support for the Tang network binding server. Tang provides
@@ -136,7 +116,6 @@ For more information, see link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)].
== SEE ALSO
-link:clevis-encrypt-http.1.adoc[*clevis-encrypt-http*(1)],
link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)],
link:clevis-encrypt-tpm2.1.adoc[*clevis-encrypt-tpm2*(1)],
link:clevis-encrypt-sss.1.adoc[*clevis-encrypt-sss*(1)],
diff --git a/src/luks/clevis-luks-bind.1.adoc b/src/luks/clevis-luks-bind.1.adoc
index 9f3a880cfb0c..0d649e3ec28b 100644
--- a/src/luks/clevis-luks-bind.1.adoc
+++ b/src/luks/clevis-luks-bind.1.adoc
@@ -61,7 +61,6 @@ The images cannot be shared without also sharing a master key.
== SEE ALSO
link:clevis-luks-unlockers.7.adoc[*clevis-luks-unlockers*(7)],
-link:clevis-encrypt-http.1.adoc[*clevis-encrypt-http*(1)],
link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)],
link:clevis-encrypt-sss.1.adoc[*clevis-encrypt-sss*(1)],
link:clevis-decrypt.1.adoc[*clevis-decrypt*(1)]
diff --git a/src/luks/systemd/dracut/module-setup.sh.in b/src/luks/systemd/dracut/module-setup.sh.in
index 119762e38326..48aea5b3f29a 100755
--- a/src/luks/systemd/dracut/module-setup.sh.in
+++ b/src/luks/systemd/dracut/module-setup.sh.in
@@ -36,7 +36,6 @@ install() {
inst_hook initqueue/settled 60 "$moddir/clevis-hook.sh"
inst_multiple /etc/services \
- clevis-decrypt-http \
clevis-decrypt-tang \
clevis-decrypt-sss \
@libexecdir@/clevis-luks-askpass \
diff --git a/src/pins/sss/clevis-encrypt-sss.1.adoc b/src/pins/sss/clevis-encrypt-sss.1.adoc
index d46498db328c..7144e7e9ea96 100644
--- a/src/pins/sss/clevis-encrypt-sss.1.adoc
+++ b/src/pins/sss/clevis-encrypt-sss.1.adoc
@@ -54,6 +54,5 @@ receive key fragments.
== SEE ALSO
-link:clevis-encrypt-http.1.adoc[*clevis-encrypt-http*(1)],
link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)],
link:clevis-decrypt.1.adoc[*clevis-decrypt*(1)]
--
2.19.1

View File

@ -1,42 +0,0 @@
From 02f17448e379c92745f8203f47e5de0725b1c1b6 Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Fri, 18 Oct 2019 09:04:22 -0300
Subject: [PATCH] Improve error message when bind is given an invalid PIN
---
src/luks/clevis-luks-bind | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/luks/clevis-luks-bind b/src/luks/clevis-luks-bind
index 7aae2ea..1b5caf2 100755
--- a/src/luks/clevis-luks-bind
+++ b/src/luks/clevis-luks-bind
@@ -19,6 +19,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+. clevis-luks-common-functions
+
SUMMARY="Binds a LUKS device using the specified policy"
UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
@@ -68,6 +70,9 @@ fi
if ! PIN=${@:$((OPTIND++)):1} || [ -z "$PIN" ]; then
echo "Did not specify a pin!" >&2
usage
+elif ! EXE=$(findexe clevis-encrypt-"${PIN}"); then
+ echo "'$PIN' is not a valid pin!" >&2
+ usage
fi
if ! CFG=${@:$((OPTIND++)):1} || [ -z "$CFG" ]; then
@@ -142,4 +147,4 @@ else
cryptsetup luksRemoveKey "$DEV" <<<"$key"
exit 1
fi
-fi
\ No newline at end of file
+fi
--
2.21.0

View File

@ -1,60 +0,0 @@
From 874ee402645f9c3c40eaf5882a9cb92bc88b1a8f Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Sun, 22 Dec 2019 16:46:19 -0500
Subject: [PATCH] Improve tests speed Also run tests only as root, if they
involve cryptsetup
---
src/luks/tests/tests-common-functions | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/src/luks/tests/tests-common-functions b/src/luks/tests/tests-common-functions
index b65a84a..7758876 100644
--- a/src/luks/tests/tests-common-functions
+++ b/src/luks/tests/tests-common-functions
@@ -25,6 +25,11 @@ luks2_supported() {
return 0
}
+skip_test() {
+ echo "${1}" >&2
+ exit 77
+}
+
# Creates a tang adv to be used in the test.
create_tang_adv() {
local adv="${1}"
@@ -39,14 +44,18 @@ create_tang_adv() {
| jose jws sig -I- -s "${TEMPLATE}" -k "${SIG}" -o "${adv}"
}
-
# Creates a new LUKS1 or LUKS2 device to be used.
new_device() {
local LUKS="${1}"
local DEV="${2}"
-
local DEV_CACHED="${TMP}/${LUKS}.cached"
+ # Some builders fail if the cryptsetup steps are not ran as root, so let's
+ # skip the test now if not running as root.
+ if [ $(id -u) != 0 ]; then
+ skip_test "WARNING: You must be root to run this test; test skipped."
+ fi
+
# Let's reuse an existing device, if there is one.
if [ -f "${DEV_CACHED}" ]; then
echo "Reusing cached ${LUKS} device..."
@@ -55,7 +64,8 @@ new_device() {
fi
fallocate -l16M "${DEV}"
- cryptsetup luksFormat --type "${LUKS}" --batch-mode --force-password "${DEV}" <<< "${DEFAULT_PASS}"
+ local extra_options='--pbkdf pbkdf2 --pbkdf-force-iterations 1000'
+ cryptsetup luksFormat --type "${LUKS}" ${extra_options} --batch-mode --force-password "${DEV}" <<< "${DEFAULT_PASS}"
# Caching the just-formatted device for possible reuse.
cp -f "${DEV}" "${DEV_CACHED}"
}
--
2.18.1

View File

@ -1,49 +0,0 @@
From 34658590e45ab85f6008379d9433406a5c7fd914 Mon Sep 17 00:00:00 2001
From: Javier Martinez Canillas <javierm@redhat.com>
Date: Wed, 7 Nov 2018 15:12:17 +0100
Subject: [PATCH 2/3] Install cryptsetup and tpm2_pcrlist in the initramfs
The cryptsetup and tpm2_pcrlist are missing in the initramfs, this makes
automatic LUKS unlocking fail with the following errors:
dracut-initqueue[382]: /usr/libexec/clevis-luks-askpass: line 52: cryptsetup: command not found
dracut-initqueue[382]: /usr/bin/clevis-decrypt-tpm2: line 40: tpm2_pcrlist: command not found
Suggested-by: Federico Chiacchiaretta <federico.chia@gmail.com>
Fixes: #74
---
src/luks/systemd/dracut/module-setup.sh.in | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/luks/systemd/dracut/module-setup.sh.in b/src/luks/systemd/dracut/module-setup.sh.in
index 48aea5b3f29a..41e7d6c9b002 100755
--- a/src/luks/systemd/dracut/module-setup.sh.in
+++ b/src/luks/systemd/dracut/module-setup.sh.in
@@ -40,6 +40,7 @@ install() {
clevis-decrypt-sss \
@libexecdir@/clevis-luks-askpass \
clevis-decrypt \
+ cryptsetup \
luksmeta \
clevis \
mktemp \
@@ -49,6 +50,7 @@ install() {
for cmd in clevis-decrypt-tpm2 \
tpm2_createprimary \
+ tpm2_pcrlist \
tpm2_unseal \
tpm2_load; do
@@ -60,6 +62,7 @@ install() {
if (($ret == 0)); then
inst_multiple clevis-decrypt-tpm2 \
tpm2_createprimary \
+ tpm2_pcrlist \
tpm2_unseal \
tpm2_load
fi
--
2.19.1

View File

@ -1,237 +0,0 @@
From 523f1361c759d5af0952b0137d4dbd51be1e7b3d Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Sun, 22 Dec 2019 17:01:09 -0500
Subject: [PATCH] Use one clevis-luks-askpass per device
This should improve the reliability of the boot unlocking, especially
when unlocking multiple devices upon boot.
It also greatly simplifies the configuration, as three is no need to
enable any systemd units manually nor add _netdev to either fstab or
crypttab.
---
src/luks/clevis-luks-unlockers.7.adoc | 16 +++----------
src/luks/systemd/clevis-luks-askpass | 7 +++++-
src/luks/systemd/clevis-luks-askpass.path | 10 --------
.../systemd/clevis-luks-askpass.service.in | 8 -------
src/luks/systemd/clevis-luks-askpass@.path | 12 ++++++++++
.../systemd/clevis-luks-askpass@.service.in | 9 +++++++
src/luks/systemd/dracut/module-setup.sh.in | 24 +++++++++++++++++++
src/luks/systemd/meson.build | 8 +++----
8 files changed, 58 insertions(+), 36 deletions(-)
delete mode 100644 src/luks/systemd/clevis-luks-askpass.path
delete mode 100644 src/luks/systemd/clevis-luks-askpass.service.in
create mode 100644 src/luks/systemd/clevis-luks-askpass@.path
create mode 100644 src/luks/systemd/clevis-luks-askpass@.service.in
diff --git a/src/luks/clevis-luks-unlockers.7.adoc b/src/luks/clevis-luks-unlockers.7.adoc
index 161b73a..e8d47ba 100644
--- a/src/luks/clevis-luks-unlockers.7.adoc
+++ b/src/luks/clevis-luks-unlockers.7.adoc
@@ -26,7 +26,7 @@ You can unlock a LUKS volume manually using the following command:
For more information, see link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)].
-== EARLY BOOT UNLOCKING
+== BOOT UNLOCKING
If Clevis integration does not already ship in your initramfs, you may need to
rebuild your initramfs with this command:
@@ -34,23 +34,13 @@ rebuild your initramfs with this command:
$ sudo dracut -f
Once Clevis is integrated into your initramfs, a simple reboot should unlock
-your root volume. Note, however, that early boot integration only works for the
-root volume. Non-root volumes should use the late boot unlocker.
+your clevis-bound volumes. Root volumes will be unlocked in early-boot, while the
+remaining volumes will be unlocked after dracut switch-root.
Dracut will bring up your network using DHCP by default. If you need to specify
additional network parameters, such as static IP configuration, please consult
the dracut documentation.
-== LATE BOOT UNLOCKING
-
-You can enable late boot unlocking by executing the following command:
-
- $ sudo systemctl enable clevis-luks-askpass.path
-
-After a reboot, Clevis will attempt to unlock all *_netdev* devices listed in
-*/etc/crypttab* when systemd prompts for their passwords. This implies that
-systemd support for *_netdev* is required.
-
== DESKTOP UNLOCKING
When the udisks2 unlocker is installed, your GNOME desktop session should
diff --git a/src/luks/systemd/clevis-luks-askpass b/src/luks/systemd/clevis-luks-askpass
index b01d93a..feebb1a 100755
--- a/src/luks/systemd/clevis-luks-askpass
+++ b/src/luks/systemd/clevis-luks-askpass
@@ -24,15 +24,17 @@ UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
shopt -s nullglob
path=/run/systemd/ask-password
-while getopts ":lp:" o; do
+while getopts ":lpu:" o; do
case "$o" in
l) loop=true;;
p) path=$OPTARG;;
+ u) device_uuid=$OPTARG;;
esac
done
while true; do
todo=0
+ [ -n "${device_uuid}" ] && todo=1 && loop=true
for question in $path/ask.*; do
metadata=false
@@ -48,6 +50,8 @@ while true; do
done < "$question"
[ -z "$d" -o -z "$s" ] && continue
+ [[ -n "${device_uuid}" ]] && [[ "${d}" != *"${device_uuid}"* ]] \
+ && continue
if cryptsetup isLuks --type luks1 "$d"; then
# If the device is not initialized, sliently skip it.
@@ -79,6 +83,7 @@ while true; do
done
fi
+ [ -n "${device_uuid}" ] && [ "${unlocked}" == true ] && todo=0 && break
[ $metadata == true ] || continue
[ $unlocked == true ] && continue
todo=$((todo + 1))
diff --git a/src/luks/systemd/clevis-luks-askpass.path b/src/luks/systemd/clevis-luks-askpass.path
deleted file mode 100644
index a4d01ba..0000000
--- a/src/luks/systemd/clevis-luks-askpass.path
+++ /dev/null
@@ -1,10 +0,0 @@
-[Unit]
-Description=Clevis systemd-ask-password Watcher
-Before=remote-fs-pre.target
-Wants=remote-fs-pre.target
-
-[Path]
-PathChanged=/run/systemd/ask-password
-
-[Install]
-WantedBy=remote-fs.target
diff --git a/src/luks/systemd/clevis-luks-askpass.service.in b/src/luks/systemd/clevis-luks-askpass.service.in
deleted file mode 100644
index 2c6bbed..0000000
--- a/src/luks/systemd/clevis-luks-askpass.service.in
+++ /dev/null
@@ -1,8 +0,0 @@
-[Unit]
-Description=Clevis LUKS systemd-ask-password Responder
-Requires=network-online.target
-After=network-online.target
-
-[Service]
-Type=oneshot
-ExecStart=@libexecdir@/clevis-luks-askpass -l
diff --git a/src/luks/systemd/clevis-luks-askpass@.path b/src/luks/systemd/clevis-luks-askpass@.path
new file mode 100644
index 0000000..3f23665
--- /dev/null
+++ b/src/luks/systemd/clevis-luks-askpass@.path
@@ -0,0 +1,12 @@
+[Unit]
+Description=Clevis systemd-ask-password Watcher for %i
+DefaultDependencies=no
+Conflicts=shutdown.target
+Before=basic.target shutdown.target
+
+[Path]
+DirectoryNotEmpty=/run/systemd/ask-password
+MakeDirectory=yes
+
+[Install]
+WantedBy=basic.target
diff --git a/src/luks/systemd/clevis-luks-askpass@.service.in b/src/luks/systemd/clevis-luks-askpass@.service.in
new file mode 100644
index 0000000..cd26eb2
--- /dev/null
+++ b/src/luks/systemd/clevis-luks-askpass@.service.in
@@ -0,0 +1,9 @@
+[Unit]
+Description=Clevis LUKS systemd-ask-password Responder for luks-%i
+DefaultDependencies=no
+Conflicts=shutdown.target
+Before=shutdown.target
+
+[Service]
+Type=oneshot
+ExecStart=@libexecdir@/clevis-luks-askpass -u %i
diff --git a/src/luks/systemd/dracut/module-setup.sh.in b/src/luks/systemd/dracut/module-setup.sh.in
index 841f7a8..1877715 100755
--- a/src/luks/systemd/dracut/module-setup.sh.in
+++ b/src/luks/systemd/dracut/module-setup.sh.in
@@ -29,6 +29,29 @@ is_bound_to_tang() {
return 1
}
+configure_passwd_watchers() {
+ if ! command -v systemctl >/dev/null; then
+ return 1
+ fi
+
+ local proc_cmdline
+ proc_cmdline=$(</proc/cmdline)
+
+ local luks_uuid
+ local cfg
+ for dev in $(lsblk -p -n -s -r \
+ | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
+ luks_uuid=$(cryptsetup luksUUID "${dev}")
+ [[ "${proc_cmdline}" == *"rd.luks.uuid=luks-${luks_uuid}"* ]] && continue
+
+ if cfg=$(clevis luks list -d "${dev}" 2>/dev/null); then
+ local action=enable
+ [ -z "${cfg}" ] && action=disable
+ systemctl "${action}" "clevis-luks-askpass@${luks_uuid}.path" 2>/dev/null
+ fi
+ done
+}
+
depends() {
local depends="crypt systemd"
if is_bound_to_tang; then
@@ -84,6 +107,7 @@ install() {
inst_libdir_file "libtss2-tcti-device.so*"
fi
+ configure_passwd_watchers
dracut_need_initqueue
}
diff --git a/src/luks/systemd/meson.build b/src/luks/systemd/meson.build
index 108e9d8..334e84c 100644
--- a/src/luks/systemd/meson.build
+++ b/src/luks/systemd/meson.build
@@ -6,14 +6,14 @@ if systemd.found()
unitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
configure_file(
- input: 'clevis-luks-askpass.service.in',
- output: 'clevis-luks-askpass.service',
+ input: 'clevis-luks-askpass@.service.in',
+ output: 'clevis-luks-askpass@.service',
install_dir: unitdir,
configuration: data,
)
- install_data('clevis-luks-askpass.path', install_dir: unitdir)
+ install_data('clevis-luks-askpass@.path', install_dir: unitdir)
install_data('clevis-luks-askpass', install_dir: libexecdir)
else
warning('Will not install systemd support due to missing dependencies!')
-endif
\ No newline at end of file
+endif
--
2.18.1

View File

@ -1,61 +0,0 @@
From 1f9e0d9533e970a79bb9a525b5e407bf80f6fc5b Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Mon, 6 Jul 2020 08:53:58 -0300
Subject: [PATCH] luks: fix handling of devices in clevis-luks-askpass to
handle
---
src/luks/systemd/clevis-luks-askpass | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/src/luks/systemd/clevis-luks-askpass b/src/luks/systemd/clevis-luks-askpass
index feebb1a..5719ab6 100755
--- a/src/luks/systemd/clevis-luks-askpass
+++ b/src/luks/systemd/clevis-luks-askpass
@@ -23,6 +23,12 @@ UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
shopt -s nullglob
+clevis_is_luks_device_by_uuid_open() {
+ local LUKS_UUID="${1}"
+ [ -z "${LUKS_UUID}" ] && return 1
+ test -b /dev/disk/by-id/dm-uuid-*"${LUKS_UUID//-/}"*
+}
+
path=/run/systemd/ask-password
while getopts ":lpu:" o; do
case "$o" in
@@ -49,9 +55,13 @@ while true; do
esac
done < "$question"
- [ -z "$d" -o -z "$s" ] && continue
- [[ -n "${device_uuid}" ]] && [[ "${d}" != *"${device_uuid}"* ]] \
- && continue
+ [ -b "${d}" ] || continue
+ [ -S "${s}" ] || continue
+
+ if [ -n "${device_uuid}" ]; then
+ uuid="$(cryptsetup luksUUID "${d}")"
+ [ "${uuid}" != "${device_uuid}" ] && todo=1 && continue
+ fi
if cryptsetup isLuks --type luks1 "$d"; then
# If the device is not initialized, sliently skip it.
@@ -89,6 +99,13 @@ while true; do
todo=$((todo + 1))
done
+ if [ -n "${device_uuid}" ]; then
+ [ ! -b /dev/disk/by-uuid/"${device_uuid}" ] && break
+ if clevis_is_luks_device_by_uuid_open "${device_uuid}"; then
+ break
+ fi
+ fi
+
if [ $todo -eq 0 ] || [ "$loop" != "true" ]; then
break;
fi
--
2.18.4

View File

@ -1,28 +1,24 @@
%global _hardened_build 1 %global _hardened_build 1
Name: clevis Name: clevis
Version: 11 Version: 13
Release: 9%{?dist}.1 Release: 3%{?dist}
Summary: Automated decryption framework Summary: Automated decryption framework
License: GPLv3+ License: GPLv3+
URL: https://github.com/latchset/%{name} URL: https://github.com/latchset/%{name}
Source0: https://github.com/latchset/%{name}/releases/download/v%{version}/%{name}-%{version}.tar.xz Source0: https://github.com/latchset/%{name}/releases/download/v%{version}/%{name}-%{version}.tar.xz
Patch01: Delete-remaining-references-to-the-removed-http-pin.patch Patch0001: 0001-Adjust-pin-tang-test-to-account-for-newer-tang-witho.patch
Patch02: Install-cryptsetup-and-tpm2_pcrlist-in-the-initramfs.patch Patch0002: 0002-Fix-clevis-luks-unlock-and-add-related-tests.patch
Patch03: Add-device-TCTI-library-to-the-initramfs.patch Patch0003: 0003-Improve-error-message-when-bind-is-given-an-invalid-.patch
Patch04: Check-key-derivation-key-is-available.patch Patch0004: 0004-Add-rd.neednet-1-to-cmdline-only-if-there-are-device.patch
Patch05: Adjust-pin-tang-test-to-account-for-newer-tang-witho.patch Patch0005: 0005-Add-the-option-to-extract-luks-passphrase-used-for-b.patch
Patch06: Add-clevis-luks-report-regen.patch Patch0006: 0006-Add-clevis-luks-regen-command.patch
Patch07: Improve-error-message-when-bind-is-given-an-invalid-.patch Patch0007: 0007-Add-clevis-luks-report.patch
Patch08: Add-support-for-listing-existing-PBD-policies-in-pla.patch Patch0008: 0008-Use-one-clevis-luks-askpass-per-device.patch
Patch09: Add-the-option-to-extract-luks-passphrase-used-for-b.patch Patch0009: 0009-Introduce-y-assume-yes-argument-to-clevis-luks-bind.patch
Patch10: Add-rd.neednet-1-to-cmdline-only-if-there-are-device.patch Patch0010: 0010-Add-clevis-luks-edit-command.patch
Patch11: Improve-tests-speed.patch
Patch12: Use-one-clevis-luks-askpass-per-device.patch
Patch13: Improve-clevis-luks-regen-no-unbind-in-every-case.patch
Patch14: luks-fix-handling-of-devices-in-clevis-luks-askpass-.patch
BuildRequires: gcc BuildRequires: gcc
BuildRequires: meson BuildRequires: meson
@ -48,11 +44,14 @@ BuildRequires: cracklib-dicts
Buildrequires: jq Buildrequires: jq
BuildRequires: diffutils BuildRequires: diffutils
BuildRequires: expect BuildRequires: expect
BuildRequires: openssl
Requires: cracklib-dicts
Requires: tpm2-tools >= 3.0.0 Requires: tpm2-tools >= 3.0.0
Requires: coreutils Requires: coreutils
Requires: jose >= 8 Requires: jose >= 8
Requires: curl Requires: curl
Requires: jq
Requires(pre): shadow-utils Requires(pre): shadow-utils
%description %description
@ -63,17 +62,17 @@ occur automatically.
The clevis package provides basic encryption/decryption policy support. The clevis package provides basic encryption/decryption policy support.
Users can use this directly; but most commonly, it will be used as a Users can use this directly; but most commonly, it will be used as a
building block for other packages. For example, see the clevis-luks building block for other packages. For example, see the clevis-luks
and clevis-dracut packages for automatic root volume unlocking of LUKSv1 and clevis-dracut packages for automatic root volume unlocking of LUKS
volumes during early boot. volumes during early boot.
%package luks %package luks
Summary: LUKSv1 integration for clevis Summary: LUKS integration for clevis
Requires: %{name}%{?_isa} = %{version}-%{release} Requires: %{name}%{?_isa} = %{version}-%{release}
Requires: cryptsetup Requires: cryptsetup
Requires: luksmeta >= 8 Requires: luksmeta >= 8
%description luks %description luks
LUKSv1 integration for clevis. This package allows you to bind a LUKSv1 LUKS integration for clevis. This package allows you to bind a LUKS
volume to a clevis unlocking policy. For automated unlocking, an unlocker volume to a clevis unlocking policy. For automated unlocking, an unlocker
will also be required. See, for example, clevis-dracut and clevis-udisks2. will also be required. See, for example, clevis-dracut and clevis-udisks2.
@ -96,7 +95,7 @@ Requires: systemd%{?_isa} >= 236
Requires: nc Requires: nc
%description systemd %description systemd
Automatically unlocks LUKSv1 _netdev block devices from /etc/crypttab. Automatically unlocks clevis-bound LUKS block devices during boot.
%package dracut %package dracut
Summary: Dracut integration for clevis Summary: Dracut integration for clevis
@ -104,18 +103,18 @@ Requires: %{name}-systemd%{?_isa} = %{version}-%{release}
Requires: dracut-network Requires: dracut-network
%description dracut %description dracut
Automatically unlocks LUKSv1 block devices in early boot. Automatically unlocks LUKS block devices in early boot.
%package udisks2 %package udisks2
Summary: UDisks2/Storaged integration for clevis Summary: UDisks2/Storaged integration for clevis
Requires: %{name}-luks%{?_isa} = %{version}-%{release} Requires: %{name}-luks%{?_isa} = %{version}-%{release}
%description udisks2 %description udisks2
Automatically unlocks LUKSv1 block devices in desktop environments that Automatically unlocks LUKS block devices in desktop environments that
use UDisks2 or storaged (like GNOME). use UDisks2 or storaged (like GNOME).
%prep %prep
%autosetup -p1 %autosetup -S git
%build %build
%meson -Duser=clevis -Dgroup=clevis %meson -Duser=clevis -Dgroup=clevis
@ -167,22 +166,24 @@ exit 0
%{_mandir}/man1/%{name}-luks-unlock.1* %{_mandir}/man1/%{name}-luks-unlock.1*
%{_mandir}/man1/%{name}-luks-unbind.1* %{_mandir}/man1/%{name}-luks-unbind.1*
%{_mandir}/man1/%{name}-luks-bind.1* %{_mandir}/man1/%{name}-luks-bind.1*
%{_mandir}/man1/%{name}-luks-list.1*
%{_mandir}/man1/%{name}-luks-pass.1*
%{_mandir}/man1/%{name}-luks-regen.1* %{_mandir}/man1/%{name}-luks-regen.1*
%{_mandir}/man1/%{name}-luks-report.1* %{_mandir}/man1/%{name}-luks-report.1*
%{_mandir}/man1/%{name}-luks-list.1* %{_mandir}/man1/%{name}-luks-edit.1*
%{_mandir}/man1/%{name}-luks-pass.1.*
%{_bindir}/%{name}-luks-unlock %{_bindir}/%{name}-luks-unlock
%{_bindir}/%{name}-luks-unbind %{_bindir}/%{name}-luks-unbind
%{_bindir}/%{name}-luks-bind %{_bindir}/%{name}-luks-bind
%{_bindir}/%{name}-luks-common-functions %{_bindir}/%{name}-luks-common-functions
%{_bindir}/%{name}-luks-list
%{_bindir}/%{name}-luks-pass
%{_bindir}/%{name}-luks-regen %{_bindir}/%{name}-luks-regen
%{_bindir}/%{name}-luks-report %{_bindir}/%{name}-luks-report
%{_bindir}/%{name}-luks-report-compare %{_bindir}/%{name}-luks-report-compare
%{_bindir}/%{name}-luks-report-decode %{_bindir}/%{name}-luks-report-decode
%{_bindir}/%{name}-luks-report-sss %{_bindir}/%{name}-luks-report-sss
%{_bindir}/%{name}-luks-report-tang %{_bindir}/%{name}-luks-report-tang
%{_bindir}/%{name}-luks-list %{_bindir}/%{name}-luks-edit
%{_bindir}/%{name}-luks-pass
%files systemd %files systemd
%{_libexecdir}/%{name}-luks-askpass %{_libexecdir}/%{name}-luks-askpass
@ -191,17 +192,33 @@ exit 0
%files dracut %files dracut
%{_prefix}/lib/dracut/modules.d/60%{name} %{_prefix}/lib/dracut/modules.d/60%{name}
%{_prefix}/lib/dracut/modules.d/60%{name}-pin-sss
%{_prefix}/lib/dracut/modules.d/60%{name}-pin-tang
%{_prefix}/lib/dracut/modules.d/60%{name}-pin-tpm2
%files udisks2 %files udisks2
%{_sysconfdir}/xdg/autostart/%{name}-luks-udisks2.desktop %{_sysconfdir}/xdg/autostart/%{name}-luks-udisks2.desktop
%attr(4755, root, root) %{_libexecdir}/%{name}-luks-udisks2 %attr(4755, root, root) %{_libexecdir}/%{name}-luks-udisks2
%changelog %changelog
* Mon Jul 06 2020 Sergio Correia <scorreia@redhat.com> - 11-9.1 * Wed May 20 2020 Sergio Correia <scorreia@redhat.com> - 13-3
- Fix handling of device names in clevis-luks-askpass - Add clevis luks edit command
Resolves: rhbz#1849593 Resolves: rhbz#1436735
* Wed Feb 02 2020 Sergio Correia <scorreia@redhat.com> - 11-9 * Mon May 18 2020 Sergio Correia <scorreia@redhat.com> - 13-2
- Introduce -y (assume yes) argument to clevis luks bind
Resolves: rhbz#1819767
* Sun May 10 2020 Sergio Correia <scorreia@redhat.com> - 13-1
- Update to new upstream release, v13
Resolves: rhbz#1827225
Resolves: rhbz#1827665
Resolves: rhbz#1801556
Resolves: rhbz#1784448
Resolves: rhbz#1826917
Resolves: rhbz#1812014
* Sun Feb 02 2020 Sergio Correia <scorreia@redhat.com> - 11-9
- Improve clevis luks regen not to unbind+bind in every case - Improve clevis luks regen not to unbind+bind in every case
Resolves: rhbz#1795675 Resolves: rhbz#1795675