From dbe4f9bd04f213dd3a674e777b3a3029dd0d7bc5 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 18 May 2021 02:44:16 -0400 Subject: [PATCH] import clevis-15-1.el8 --- .clevis.metadata | 2 +- .gitignore | 2 +- ...test-to-account-for-newer-tang-witho.patch | 84 - ...g-with-newer-tang-without-tangd-upda.patch | 176 +++ ...-extract-luks-passphrase-used-for-b.patch} | 197 +-- ...is-luks-unlock-and-add-related-tests.patch | 732 --------- ...ssage-when-bind-is-given-an-invalid-.patch | 57 - ...-to-cmdline-only-if-there-are-device.patch | 53 - .../0006-Add-clevis-luks-regen-command.patch | 1387 ----------------- SOURCES/0007-Add-clevis-luks-report.patch | 464 ------ ...e-one-clevis-luks-askpass-per-device.patch | 339 ---- ...ume-yes-argument-to-clevis-luks-bind.patch | 555 ------- .../0010-Add-clevis-luks-edit-command.patch | 1036 ------------ SPECS/clevis.spec | 55 +- 14 files changed, 276 insertions(+), 4863 deletions(-) delete mode 100644 SOURCES/0001-Adjust-pin-tang-test-to-account-for-newer-tang-witho.patch create mode 100644 SOURCES/0001-Fixes-for-dealing-with-newer-tang-without-tangd-upda.patch rename SOURCES/{0005-Add-the-option-to-extract-luks-passphrase-used-for-b.patch => 0002-Add-the-option-to-extract-luks-passphrase-used-for-b.patch} (62%) delete mode 100644 SOURCES/0002-Fix-clevis-luks-unlock-and-add-related-tests.patch delete mode 100644 SOURCES/0003-Improve-error-message-when-bind-is-given-an-invalid-.patch delete mode 100644 SOURCES/0004-Add-rd.neednet-1-to-cmdline-only-if-there-are-device.patch delete mode 100644 SOURCES/0006-Add-clevis-luks-regen-command.patch delete mode 100644 SOURCES/0007-Add-clevis-luks-report.patch delete mode 100644 SOURCES/0008-Use-one-clevis-luks-askpass-per-device.patch delete mode 100644 SOURCES/0009-Introduce-y-assume-yes-argument-to-clevis-luks-bind.patch delete mode 100644 SOURCES/0010-Add-clevis-luks-edit-command.patch diff --git a/.clevis.metadata b/.clevis.metadata index 2d0caa9..e096a61 100644 --- a/.clevis.metadata +++ b/.clevis.metadata @@ -1 +1 @@ -83aebcbe5792b43bf281b442f379cea08d7c43b0 SOURCES/clevis-13.tar.xz +ce825a10c5aa885e001c963be4cc4a8dea2137b0 SOURCES/clevis-15.tar.xz diff --git a/.gitignore b/.gitignore index a769e5f..2e87ac2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/clevis-13.tar.xz +SOURCES/clevis-15.tar.xz diff --git a/SOURCES/0001-Adjust-pin-tang-test-to-account-for-newer-tang-witho.patch b/SOURCES/0001-Adjust-pin-tang-test-to-account-for-newer-tang-witho.patch deleted file mode 100644 index 8455003..0000000 --- a/SOURCES/0001-Adjust-pin-tang-test-to-account-for-newer-tang-witho.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 27a27befed2257c2156ed8b94d679951b9b1a4d5 Mon Sep 17 00:00:00 2001 -From: Sergio Correia -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 - diff --git a/SOURCES/0001-Fixes-for-dealing-with-newer-tang-without-tangd-upda.patch b/SOURCES/0001-Fixes-for-dealing-with-newer-tang-without-tangd-upda.patch new file mode 100644 index 0000000..23679bc --- /dev/null +++ b/SOURCES/0001-Fixes-for-dealing-with-newer-tang-without-tangd-upda.patch @@ -0,0 +1,176 @@ +From 16f667d9f3d649e33ca762afa1a8a7f909b953a8 Mon Sep 17 00:00:00 2001 +From: Sergio Correia +Date: Sun, 25 Oct 2020 11:15:46 -0300 +Subject: [PATCH] Fixes for dealing with newer tang without tangd-update + +--- + src/luks/tests/meson.build | 11 +---------- + src/luks/tests/tests-common-functions.in | 19 +++++++++++-------- + src/pins/tang/meson.build | 11 +---------- + src/pins/tang/pin-tang | 11 ++++++++--- + 4 files changed, 21 insertions(+), 31 deletions(-) + +diff --git a/src/luks/tests/meson.build b/src/luks/tests/meson.build +index ba5f6a2..c0f9dc3 100644 +--- a/src/luks/tests/meson.build ++++ b/src/luks/tests/meson.build +@@ -17,14 +17,6 @@ kgen = find_program( + join_paths('/', 'usr', get_option('libexecdir'), 'tangd-keygen'), + required: false + ) +-updt = find_program( +- join_paths(libexecdir, 'tangd-update'), +- join_paths(get_option('prefix'), get_option('libdir'), 'tangd-update'), +- join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd-update'), +- join_paths('/', 'usr', get_option('libdir'), 'tangd-update'), +- join_paths('/', 'usr', get_option('libexecdir'), 'tangd-update'), +- required: false +-) + tang = find_program( + join_paths(libexecdir, 'tangd'), + join_paths(get_option('prefix'), get_option('libdir'), 'tangd'), +@@ -58,11 +50,10 @@ env.prepend('PATH', + ) + + has_tang = false +-if actv.found() and kgen.found() and updt.found() and tang.found() ++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_UPDATE', updt.path()) + env.set('TANGD', tang.path()) + endif + +diff --git a/src/luks/tests/tests-common-functions.in b/src/luks/tests/tests-common-functions.in +index 8520715..318d007 100755 +--- a/src/luks/tests/tests-common-functions.in ++++ b/src/luks/tests/tests-common-functions.in +@@ -251,18 +251,19 @@ tang_remove_rotated_keys() { + return 1 + fi + +- [ -z "${TANGD_UPDATE}" ] && skip_test "WARNING: TANGD_UPDATE is not defined." +- + local db="${basedir}/db" +- local cache="${basedir}/cache" + mkdir -p "${db}" +- mkdir -p "${cache}" ++ ++ if [ -n "${TANGD_UPDATE}" ]; then ++ local cache="${basedir}/cache" ++ mkdir -p "${cache}" ++ fi + + pushd "${db}" + find . -name ".*.jwk" -exec rm -f {} \; + popd + +- "${TANGD_UPDATE}" "${db}" "${cache}" ++ [ -n "${TANGD_UPDATE}" ] && "${TANGD_UPDATE}" "${db}" "${cache}" + return 0 + } + +@@ -277,12 +278,12 @@ tang_new_keys() { + fi + + [ -z "${TANGD_KEYGEN}" ] && skip_test "WARNING: TANGD_KEYGEN is not defined." +- [ -z "${TANGD_UPDATE}" ] && skip_test "WARNING: TANGD_UPDATE is not defined." + + local db="${basedir}/db" +- local cache="${basedir}/cache" + mkdir -p "${db}" + ++ [ -n "${TANGD_UPDATE}" ] && local cache="${basedir}/cache" ++ + if [ -n "${rotate}" ]; then + pushd "${db}" + local k +@@ -296,7 +297,7 @@ tang_new_keys() { + fi + + "${TANGD_KEYGEN}" "${db}" +- "${TANGD_UPDATE}" "${db}" "${cache}" ++ [ -n "${TANGD_UPDATE}" ] && "${TANGD_UPDATE}" "${db}" "${cache}" + + return 0 + } +@@ -322,6 +323,8 @@ tang_run() { + fi + + local KEYS="${basedir}/cache" ++ [ -z "${TANGD_UPDATE}" ] && KEYS="${basedir}/db" ++ + local inetd='--inetd' + [ "${SD_ACTIVATE##*/}" = "systemd-activate" ] && inetd= + +diff --git a/src/pins/tang/meson.build b/src/pins/tang/meson.build +index f7d8226..ebcdd4a 100644 +--- a/src/pins/tang/meson.build ++++ b/src/pins/tang/meson.build +@@ -12,14 +12,6 @@ kgen = find_program( + join_paths('/', 'usr', get_option('libexecdir'), 'tangd-keygen'), + required: false + ) +-updt = find_program( +- join_paths(libexecdir, 'tangd-update'), +- join_paths(get_option('prefix'), get_option('libdir'), 'tangd-update'), +- join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd-update'), +- join_paths('/', 'usr', get_option('libdir'), 'tangd-update'), +- join_paths('/', 'usr', get_option('libexecdir'), 'tangd-update'), +- required: false +-) + tang = find_program( + join_paths(libexecdir, 'tangd'), + join_paths(get_option('prefix'), get_option('libdir'), 'tangd'), +@@ -35,11 +27,10 @@ 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.set('TANGD_KEYGEN', kgen.path()) +- env.set('TANGD_UPDATE', updt.path()) + env.set('TANGD', tang.path()) + env.prepend('PATH', + join_paths(meson.source_root(), 'src'), +diff --git a/src/pins/tang/pin-tang b/src/pins/tang/pin-tang +index 98e5e4d..a63d0a2 100755 +--- a/src/pins/tang/pin-tang ++++ b/src/pins/tang/pin-tang +@@ -31,8 +31,12 @@ 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)" +@@ -40,13 +44,14 @@ port="$(shuf -i 1024-65536 -n 1)" + inetd='--inetd' + [ "${SD_ACTIVATE##*/}" = "systemd-activate" ] && inetd= + +-"$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 + diff --git a/SOURCES/0005-Add-the-option-to-extract-luks-passphrase-used-for-b.patch b/SOURCES/0002-Add-the-option-to-extract-luks-passphrase-used-for-b.patch similarity index 62% rename from SOURCES/0005-Add-the-option-to-extract-luks-passphrase-used-for-b.patch rename to SOURCES/0002-Add-the-option-to-extract-luks-passphrase-used-for-b.patch index b3ed25b..103911c 100644 --- a/SOURCES/0005-Add-the-option-to-extract-luks-passphrase-used-for-b.patch +++ b/SOURCES/0002-Add-the-option-to-extract-luks-passphrase-used-for-b.patch @@ -1,7 +1,7 @@ -From e3641a7193adac1cea525c093f39679c2cfa22c9 Mon Sep 17 00:00:00 2001 -From: Sergio Correia -Date: Wed, 13 May 2020 23:53:38 -0300 -Subject: [PATCH 5/8] Add the option to extract luks passphrase used for +From aa52396c35e76aabd085a819b08167d559042a20 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 3 Nov 2020 08:42:48 -0300 +Subject: [PATCH 2/2] Add the option to extract luks passphrase used for binding Usage: @@ -9,13 +9,13 @@ Usage: clevis luks pass -d /dev/sda1 -s 1 --- - src/luks/clevis-luks-pass | 69 +++++++++++++++++++++++++++++ - src/luks/clevis-luks-pass.1.adoc | 43 ++++++++++++++++++ + src/luks/clevis-luks-pass | 64 ++++++++++++++++++++++++++++++++ + src/luks/clevis-luks-pass.1.adoc | 43 +++++++++++++++++++++ src/luks/meson.build | 3 ++ - src/luks/tests/meson.build | 11 +++++ - src/luks/tests/pass-tang-luks1 | 75 ++++++++++++++++++++++++++++++++ - src/luks/tests/pass-tang-luks2 | 75 ++++++++++++++++++++++++++++++++ - 6 files changed, 276 insertions(+) + src/luks/tests/meson.build | 2 + + src/luks/tests/pass-tang-luks1 | 59 +++++++++++++++++++++++++++++ + src/luks/tests/pass-tang-luks2 | 59 +++++++++++++++++++++++++++++ + 6 files changed, 230 insertions(+) create mode 100755 src/luks/clevis-luks-pass create mode 100644 src/luks/clevis-luks-pass.1.adoc create mode 100755 src/luks/tests/pass-tang-luks1 @@ -23,12 +23,12 @@ clevis luks pass -d /dev/sda1 -s 1 diff --git a/src/luks/clevis-luks-pass b/src/luks/clevis-luks-pass new file mode 100755 -index 0000000..1ce8c4c +index 0000000..1f59b39 --- /dev/null +++ b/src/luks/clevis-luks-pass -@@ -0,0 +1,69 @@ +@@ -0,0 +1,64 @@ +#!/bin/bash -e -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: ++# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2019 Red Hat, Inc. +# Author: Sergio Correia - LUKS2 support. @@ -51,16 +51,16 @@ index 0000000..1ce8c4c + +SUMMARY="Returns the LUKS passphrase used for binding a particular slot." + -+function usage() { -+ echo >&2 -+ echo "Usage: clevis luks pass -d DEV -s SLT" >&2 -+ echo >&2 -+ echo "$SUMMARY": >&2 -+ echo >&2 -+ echo " -d DEV The LUKS device to extract the LUKS passphrase used for binding" >&2 -+ echo >&2 -+ echo " -s SLOT The slot number to extract the LUKS passphrase" >&2 -+ echo >&2 ++usage() { ++ exec >&2 ++ echo "Usage: clevis luks pass -d DEV -s SLT" ++ echo ++ echo "$SUMMARY" ++ echo ++ echo " -d DEV The LUKS device to extract the LUKS passphrase used for binding" ++ echo ++ echo " -s SLOT The slot number to extract the LUKS passphrase" ++ echo + exit 1 +} + @@ -87,13 +87,8 @@ index 0000000..1ce8c4c + usage +fi + -+if ! jwe=$(clevis_luks_read_slot "${DEV}" "${SLT}" 2>/dev/null); then -+ echo "It was not possible to read slot ${SLT} from ${DEV}!" >&2 -+ exit 1 -+fi -+ -+if ! clevis decrypt < <(echo -n "${jwe}"); then -+ echo "It was not possible to decrypt the passphrase associated to slot ${SLT} in {DEV}!" >&2 ++if ! clevis_luks_unlock_device_by_slot "${DEV}" "${SLT}"; then ++ echo "It was not possible to decrypt the passphrase associated to slot ${SLT} in ${DEV}!" >&2 + exit 1 +fi diff --git a/src/luks/clevis-luks-pass.1.adoc b/src/luks/clevis-luks-pass.1.adoc @@ -146,13 +141,13 @@ index 0000000..fa9526a + +link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)], diff --git a/src/luks/meson.build b/src/luks/meson.build -index 0d24f8d..fda2ca8 100644 +index 12f5a0d..008736e 100644 --- a/src/luks/meson.build +++ b/src/luks/meson.build -@@ -41,6 +41,9 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found() +@@ -50,6 +50,9 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found() - 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-edit') + mans += join_paths(meson.current_source_dir(), 'clevis-luks-edit.1') + + bins += join_paths(meson.current_source_dir(), 'clevis-luks-pass') + mans += join_paths(meson.current_source_dir(), 'clevis-luks-pass.1') @@ -160,51 +155,31 @@ index 0d24f8d..fda2ca8 100644 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 9a16b42..4757c4b 100644 +index c22a069..f4584aa 100644 --- a/src/luks/tests/meson.build +++ b/src/luks/tests/meson.build -@@ -1,3 +1,9 @@ -+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) - -@@ -45,8 +51,11 @@ env.prepend('PATH', - 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() -@@ -77,6 +86,7 @@ endif - if has_tang - test('unlock-tang-luks1', find_program('unlock-tang-luks1'), env: env, timeout: 90) +@@ -84,6 +84,7 @@ if has_tang + test('report-tang-luks1', find_program('report-tang-luks1'), env: env, timeout: 90) + test('report-sss-luks1', find_program('report-sss-luks1'), env: env, timeout: 90) + test('edit-tang-luks1', find_program('edit-tang-luks1'), env: env, timeout: 150) ++ test('pass-tang-luks1', find_program('pass-tang-luks1'), env: env, timeout: 60) 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. -@@ -96,4 +106,5 @@ if luksmeta_data.get('OLD_CRYPTSETUP') == '0' - if has_tang - test('unlock-tang-luks2', find_program('unlock-tang-luks2'), env: env, timeout: 120) + test('backup-restore-luks1', find_program('backup-restore-luks1'), env: env, timeout: 60) +@@ -111,6 +112,7 @@ if luksmeta_data.get('OLD_CRYPTSETUP') == '0' + test('report-tang-luks2', find_program('report-tang-luks2'), env: env, timeout: 120) + test('report-sss-luks2', find_program('report-sss-luks2'), env: env, timeout: 120) + test('edit-tang-luks2', find_program('edit-tang-luks2'), env: env, timeout: 210) ++ test('pass-tang-luks2', find_program('pass-tang-luks2'), env: env, timeout: 60) endif -+ test('pass-tang-luks2', find_program('pass-tang-luks2'), env: env, timeout: 60) - endif + + test('backup-restore-luks2', find_program('backup-restore-luks2'), env: env, timeout: 120) diff --git a/src/luks/tests/pass-tang-luks1 b/src/luks/tests/pass-tang-luks1 new file mode 100755 -index 0000000..05cdb3e +index 0000000..0d91e6c --- /dev/null +++ b/src/luks/tests/pass-tang-luks1 -@@ -0,0 +1,75 @@ +@@ -0,0 +1,59 @@ +#!/bin/bash -x +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# @@ -227,36 +202,25 @@ index 0000000..05cdb3e + +TEST="${0}" +. tests-common-functions ++. clevis-luks-common-functions + +function on_exit() { -+ if [ "$PID" ]; then kill $PID; wait $PID || true; fi -+ [ -d "$TMP" ] && rm -rf $TMP ++ [ ! -d "${TMP}" ] && return 0 ++ tang_stop "${TMP}" ++ rm -rf "${TMP}" +} + +trap 'on_exit' EXIT -+trap 'exit' ERR + -+export TMP=$(mktemp -d) -+mkdir -p "${TMP}/db" ++TMP=$(mktemp -d) + -+# Generate the server keys -+KEYS="$TMP/db" -+tangd-keygen $TMP/db sig exc -+if which tangd-update; then -+ mkdir -p "${TMP}/cache" -+ 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 "${KEYS}" & -+export PID=$! -+sleep 0.25 ++port=$(get_random_port) ++tang_run "${TMP}" "${port}" & ++tang_wait_until_ready "${port}" + +url="http://localhost:${port}" +adv="${TMP}/adv" -+curl "${url}/adv" -o "${adv}" ++tang_get_adv "${port}" "${adv}" + +cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv") + @@ -268,24 +232,19 @@ index 0000000..05cdb3e + error "${TEST}: Bind should have succeeded." +fi + -+#Now let's test the passphrase. ++# Now let's test the passphrase. +SLT=1 +PASS=$(clevis luks pass -d "${DEV}" -s "${SLT}") +echo $PASS >&2 -+if ! cryptsetup luksOpen --test-passphrase ""${DEV} \ -+ --key-file <(clevis luks pass -d "${DEV}" -s "${SLT}"); then ++if ! clevis_luks_check_valid_key_or_keyfile "${DEV}" "${PASS}" "" "${SLT}"; then + error "Passphrase obtained from clevis luks pass failed." +fi -+ -+kill -9 "${PID}" -+! wait "${PID}" -+unset PID diff --git a/src/luks/tests/pass-tang-luks2 b/src/luks/tests/pass-tang-luks2 new file mode 100755 -index 0000000..9123aa0 +index 0000000..2d50413 --- /dev/null +++ b/src/luks/tests/pass-tang-luks2 -@@ -0,0 +1,75 @@ +@@ -0,0 +1,59 @@ +#!/bin/bash -x +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# @@ -308,36 +267,25 @@ index 0000000..9123aa0 + +TEST="${0}" +. tests-common-functions ++. clevis-luks-common-functions + +function on_exit() { -+ if [ "$PID" ]; then kill $PID; wait $PID || true; fi -+ [ -d "$TMP" ] && rm -rf $TMP ++ [ ! -d "${TMP}" ] && return 0 ++ tang_stop "${TMP}" ++ rm -rf "${TMP}" +} + +trap 'on_exit' EXIT -+trap 'exit' ERR + -+export TMP=$(mktemp -d) -+mkdir -p "${TMP}/db" ++TMP=$(mktemp -d) + -+# Generate the server keys -+KEYS="$TMP/db" -+tangd-keygen $TMP/db sig exc -+if which tangd-update; then -+ mkdir -p "${TMP}/cache" -+ 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 "${KEYS}" & -+export PID=$! -+sleep 0.25 ++port=$(get_random_port) ++tang_run "${TMP}" "${port}" & ++tang_wait_until_ready "${port}" + +url="http://localhost:${port}" +adv="${TMP}/adv" -+curl "${url}/adv" -o "${adv}" ++tang_get_adv "${port}" "${adv}" + +cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv") + @@ -349,18 +297,13 @@ index 0000000..9123aa0 + error "${TEST}: Bind should have succeeded." +fi + -+#Now let's test the passphrase. ++# Now let's test the passphrase. +SLT=1 +PASS=$(clevis luks pass -d "${DEV}" -s "${SLT}") +echo $PASS >&2 -+if ! cryptsetup luksOpen --test-passphrase ""${DEV} \ -+ --key-file <(clevis luks pass -d "${DEV}" -s "${SLT}"); then ++if ! clevis_luks_check_valid_key_or_keyfile "${DEV}" "${PASS}" "" "${SLT}"; then + error "Passphrase obtained from clevis luks pass failed." +fi -+ -+kill -9 "${PID}" -+! wait "${PID}" -+unset PID -- -2.18.4 +2.29.2 diff --git a/SOURCES/0002-Fix-clevis-luks-unlock-and-add-related-tests.patch b/SOURCES/0002-Fix-clevis-luks-unlock-and-add-related-tests.patch deleted file mode 100644 index 0f4b835..0000000 --- a/SOURCES/0002-Fix-clevis-luks-unlock-and-add-related-tests.patch +++ /dev/null @@ -1,732 +0,0 @@ -From e5f6d87d5c71f3faf0c0dbe38534fd3eab30f43e Mon Sep 17 00:00:00 2001 -From: Sergio Correia -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 -+# -+# 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 . -+# -+. 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 --# --# This program is free software: you can redistribute it and/or modify --# it under the terms of the GNU General Public License as published by --# the Free Software Foundation, either version 3 of the License, or --# (at your option) any later version. --# --# This program is distributed in the hope that it will be useful, --# but WITHOUT ANY WARRANTY; without even the implied warranty of --# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --# GNU General Public License for more details. --# --# You should have received a copy of the GNU General Public License --# along with this program. If not, see . --# -- --SUMMARY="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 -+# -+# 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 . -+ -+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 -+# -+# 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 . -+ -+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 - diff --git a/SOURCES/0003-Improve-error-message-when-bind-is-given-an-invalid-.patch b/SOURCES/0003-Improve-error-message-when-bind-is-given-an-invalid-.patch deleted file mode 100644 index 73f3470..0000000 --- a/SOURCES/0003-Improve-error-message-when-bind-is-given-an-invalid-.patch +++ /dev/null @@ -1,57 +0,0 @@ -From d393fbc256e22cc8019d18214e4d140d58f3302a Mon Sep 17 00:00:00 2001 -From: Sergio Correia -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 . - # - -+. 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 - diff --git a/SOURCES/0004-Add-rd.neednet-1-to-cmdline-only-if-there-are-device.patch b/SOURCES/0004-Add-rd.neednet-1-to-cmdline-only-if-there-are-device.patch deleted file mode 100644 index 0f0af18..0000000 --- a/SOURCES/0004-Add-rd.neednet-1-to-cmdline-only-if-there-are-device.patch +++ /dev/null @@ -1,53 +0,0 @@ -From fc0cc6f159857e463aacababdc0735b0972d103c Mon Sep 17 00:00:00 2001 -From: Sergio Correia -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 . - # - -+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 - diff --git a/SOURCES/0006-Add-clevis-luks-regen-command.patch b/SOURCES/0006-Add-clevis-luks-regen-command.patch deleted file mode 100644 index bce58e3..0000000 --- a/SOURCES/0006-Add-clevis-luks-regen-command.patch +++ /dev/null @@ -1,1387 +0,0 @@ -From 158bdeda3ca961b0e615c8adfc58b61e1a1ba5c7 Mon Sep 17 00:00:00 2001 -From: Sergio Correia -Date: Wed, 13 May 2020 23:55:41 -0300 -Subject: [PATCH 6/8] Add clevis luks regen command - -The clevis luks regen command regenerates the LUKS binding for a given -device/slot, using the same configuration of the existing binding. - -Example: - -clevis luks list -d /dev/sda1 -1: tang '{"url":"http://tang.server"}' -2: tpm2 '{"hash":"sha256","key":"ecc"}' - -To rotate the binding in slot 1, we can use the following: -clevis luks regen -d /dev/sda1 -s 1 - -The new binding will use the existing configuration, namely: -'{"url":"http://tang.server"}', with the `tang' pin. ---- - src/luks/clevis-luks-common-functions | 230 +++++++++++++++++++++++ - src/luks/clevis-luks-pass | 5 +- - src/luks/clevis-luks-regen | 185 ++++++++++++++++++ - src/luks/clevis-luks-regen.1.adoc | 48 +++++ - src/luks/meson.build | 3 + - src/luks/tests/backup-restore-luks1 | 114 +++++++++++ - src/luks/tests/backup-restore-luks2 | 115 ++++++++++++ - src/luks/tests/meson.build | 6 + - src/luks/tests/meson.build.orig | 110 +++++++++++ - src/luks/tests/regen-inplace-luks1 | 98 ++++++++++ - src/luks/tests/regen-inplace-luks2 | 99 ++++++++++ - 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-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-luks2 - create mode 100755 src/luks/tests/regen-not-inplace-luks1 - 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 -index 36f0bfd..5b515ad 100644 ---- a/src/luks/clevis-luks-common-functions -+++ b/src/luks/clevis-luks-common-functions -@@ -325,3 +325,233 @@ clevis_luks_unlock_device() { - - 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 -+# to a specific device and slot. The last parameter indicates whether we -+# should overwrite existing metadata. -+clevis_luks1_save_slot() { -+ local DEV="${1}" -+ local SLOT="${2}" -+ local JWE="${3}" -+ local OVERWRITE="${4}" -+ -+ ! luksmeta test -d "${DEV}" && return 1 -+ -+ local UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e" -+ if luksmeta load -d "${DEV}" -s "${SLOT}" -u "${UUID}" >/dev/null 2>/dev/null; then -+ [ -z "${OVERWRITE}" ] && return 1 -+ if ! luksmeta wipe -f -d "${DEV}" -s "${SLOT}" -u "${UUID}"; then -+ echo "Error wiping slot ${SLOT} from ${DEV}" >&2 -+ return 1 -+ fi -+ fi -+ -+ if ! echo -n "${jwe}" | luksmeta save -d "${DEV}" -s "${SLOT}" -u "${UUID}"; then -+ echo "Error saving metadata to LUKSMeta slot ${SLOT} from ${DEV}" >&2 -+ return 1 -+ fi -+ return 0 -+} -+ -+# clevis_luks2_save_slot() works with LUKS2 devices and it saves a given JWE -+# to a specific device and slot. The last parameter indicates whether we -+# should overwrite existing metadata. -+clevis_luks2_save_slot() { -+ local DEV="${1}" -+ local SLOT="${2}" -+ local JWE="${3}" -+ local OVERWRITE="${4}" -+ -+ local dump token -+ dump="$(cryptsetup luksDump "${DEV}")" -+ if ! token="$(grep -E -B1 "^\s+Keyslot:\s+${SLOT}$" <<< "${dump}" \ -+ | sed -rn 's|^\s+([0-9]+): clevis|\1|p')"; then -+ echo "Error trying to read token from LUKS2 device ${DEV}, slot ${SLOT}" >&2 -+ return 1 -+ fi -+ -+ if [ -n "${token}" ]; then -+ [ -z "${OVERWRITE}" ] && return 1 -+ if ! cryptsetup token remove --token-id "${token}" "${DEV}"; then -+ echo "Error while removing token ${token} from LUKS2 device ${DEV}" >&2 -+ return 1 -+ fi -+ fi -+ -+ local metadata -+ metadata=$(printf '{"type":"clevis","keyslots":["%s"],"jwe":%s}' \ -+ "${SLOT}" "$(jose jwe fmt -i- <<< "${JWE}")") -+ if ! cryptsetup token import "${DEV}" <<< "${metadata}"; then -+ echo "Error saving metadata to LUKS2 header in device ${DEV}" >&2 -+ return 1 -+ fi -+ return 0 -+} -+ -+# clevis_luks_save_slot() saves a given JWE to a LUKS device+slot. It can also -+# overwrite existing metadata. -+clevis_luks_save_slot() { -+ local DEV="${1}" -+ local SLOT="${2}" -+ local JWE="${3}" -+ local OVERWRITE="${4}" -+ -+ if cryptsetup isLuks --type luks1 "${DEV}"; then -+ ! clevis_luks1_save_slot "${DEV}" "${SLOT}" "${JWE}" "${OVERWRITE}" \ -+ && return 1 -+ elif cryptsetup isLuks --type luks2 "${DEV}"; then -+ ! clevis_luks2_save_slot "${DEV}" "${SLOT}" "${JWE}" "${OVERWRITE}" \ -+ && return 1 -+ else -+ return 1 -+ fi -+ return 0 -+} -+ -+# clevis_luks1_backup_dev() backups the LUKSMeta slots from a LUKS device, -+# which can be restored with clevis_luks1_restore_dev(). -+clevis_luks1_backup_dev() { -+ local DEV="${1}" -+ local TMP="${2}" -+ -+ [ -z "${DEV}" ] && return 1 -+ [ -z "${TMP}" ] && return 1 -+ -+ local slots slt uuid jwe fname -+ readarray -t slots < <(cryptsetup luksDump "${DEV}" \ -+ | sed -rn 's|^Key Slot ([0-7]): ENABLED$|\1|p') -+ -+ for slt in "${slots[@]}"; do -+ if ! uuid=$(luksmeta show -d "${DEV}" -s "${slt}") \ -+ || [ -z "${uuid}" ]; then -+ continue -+ fi -+ if ! jwe=$(luksmeta load -d "${DEV}" -s "${slt}") \ -+ || [ -z "${jwe}" ]; then -+ continue -+ fi -+ -+ fname=$(printf "slot_%s_%s" "${slt}" "${uuid}") -+ printf "%s" "${jwe}" > "${TMP}/${fname}" -+ done -+ return 0 -+} -+ -+# clevis_luks1_restore_dev() takes care of restoring the LUKSMeta slots from -+# a LUKS device that was backup'ed by clevis_luks1_backup_dev(). -+clevis_luks1_restore_dev() { -+ local DEV="${1}" -+ local TMP="${2}" -+ -+ [ -z "${DEV}" ] && return 1 -+ [ -z "${TMP}" ] && return 1 -+ -+ local slt uuid jwe fname -+ for fname in "${TMP}"/slot_*; do -+ [ -f "${fname}" ] || break -+ if ! slt=$(echo "${fname}" | cut -d '_' -f 2) \ -+ || [ -z "${slt}" ]; then -+ continue -+ fi -+ if ! uuid=$(echo "${fname}" | cut -d '_' -f 3) \ -+ || [ -z "${uuid}" ]; then -+ continue -+ fi -+ if ! jwe=$(< "${fname}") || [ -z "${jwe}" ]; then -+ continue -+ fi -+ if ! clevis_luks1_save_slot "${DEV}" "${slt}" \ -+ "${jwe}" "overwrite"; then -+ echo "Error restoring LUKSmeta slot ${slt} from ${DEV}" >&2 -+ return 1 -+ fi -+ done -+ return 0 -+} -+ -+# clevis_luks_backup_dev() backups a particular LUKS device, which can then -+# be restored with clevis_luks_restore_dev(). -+clevis_luks_backup_dev() { -+ local DEV="${1}" -+ local TMP="${2}" -+ -+ [ -z "${DEV}" ] && return 1 -+ [ -z "${TMP}" ] && return 1 -+ -+ local HDR -+ HDR="${TMP}/$(basename "${DEV}").header" -+ if ! cryptsetup luksHeaderBackup "${DEV}" --batch-mode \ -+ --header-backup-file "${HDR}"; then -+ echo "Error backing up LUKS header from ${DEV}" >&2 -+ return 1 -+ fi -+ -+ # If LUKS1, we need to manually back up (and later restore) the -+ # LUKSmeta slots. For LUKS2, simply saving the header also saves -+ # the associated tokens. -+ if cryptsetup isLuks --type luks1 "${DEV}"; then -+ if ! clevis_luks1_backup_dev "${DEV}" "${TMP}"; then -+ return 1 -+ fi -+ fi -+ return 0 -+} -+ -+# clevis_luks_restore_dev() restores a given device that was backup'ed by -+# clevis_luks_backup_dev(). -+clevis_luks_restore_dev() { -+ local DEV="${1}" -+ local TMP="${2}" -+ -+ [ -z "${DEV}" ] && return 1 -+ [ -z "${TMP}" ] && return 1 -+ -+ local HDR -+ HDR="${TMP}/$(basename "${DEV}").header" -+ if [ ! -e "${HDR}" ]; then -+ echo "LUKS header backup does not exist" >&2 -+ return 1 -+ fi -+ -+ if ! cryptsetup luksHeaderRestore "${DEV}" --batch-mode \ -+ --header-backup-file "${HDR}"; then -+ echo "Error restoring LUKS header from ${DEV}" >&2 -+ return 1 -+ fi -+ -+ # If LUKS1, we need to manually back up (and later restore) the -+ # LUKSmeta slots. For LUKS2, simply saving the header also saves -+ # the associated tokens. -+ if cryptsetup isLuks --type luks1 "${DEV}"; then -+ if ! clevis_luks1_restore_dev "${DEV}" "${TMP}"; then -+ return 1 -+ fi -+ fi -+ return 0 -+} -diff --git a/src/luks/clevis-luks-pass b/src/luks/clevis-luks-pass -index 1ce8c4c..d31bc17 100755 ---- a/src/luks/clevis-luks-pass -+++ b/src/luks/clevis-luks-pass -@@ -63,7 +63,8 @@ if ! jwe=$(clevis_luks_read_slot "${DEV}" "${SLT}" 2>/dev/null); then - exit 1 - fi - --if ! clevis decrypt < <(echo -n "${jwe}"); then -- echo "It was not possible to decrypt the passphrase associated to slot ${SLT} in {DEV}!" >&2 -+if ! passphrase=$(clevis decrypt < <(echo -n "${jwe}") 2>/dev/null); then -+ echo "It was not possible to decrypt the passphrase associated to slot ${SLT} in ${DEV}!" >&2 - exit 1 - fi -+echo -n "${passphrase}" -diff --git a/src/luks/clevis-luks-regen b/src/luks/clevis-luks-regen -new file mode 100755 -index 0000000..44fd673 ---- /dev/null -+++ b/src/luks/clevis-luks-regen -@@ -0,0 +1,185 @@ -+#!/usr/bin/bash -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2018 Red Hat, Inc. -+# Author: Radovan Sroka -+# Author: Sergio Correia -+# -+# 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 . -+# -+ -+. clevis-luks-common-functions -+ -+SUMMARY="Regenerate LUKS metadata" -+ -+if [ "$1" == "--summary" ]; then -+ echo "$SUMMARY" -+ exit 0 -+fi -+ -+function usage_and_exit () { -+ exec >&2 -+ echo "Usage: clevis luks regen -d DEV -s SLOT" -+ echo -+ echo "$SUMMARY" -+ echo -+ echo " -d DEV The LUKS device on which to perform rebinding" -+ echo -+ echo " -s SLT The LUKS slot to use" -+ echo -+ exit "${1}" -+} -+ -+on_exit() { -+ if [ ! -d "${TMP}" ] || ! rm -rf "${TMP}"; then -+ echo "Delete temporary files failed!" >&2 -+ echo "You need to clean up: ${TMP}" >&2 -+ exit 1 -+ fi -+} -+ -+while getopts ":hfd:s:" o; do -+ case "$o" in -+ d) DEV="$OPTARG";; -+ h) usage_and_exit 0;; -+ s) SLT="$OPTARG";; -+ *) usage_and_exit 1;; -+ esac -+done -+ -+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 ! pin_cfg=$(clevis luks list -d "${DEV}" -s "${SLT}" 2>/dev/null); then -+ echo "Error obtaining current configuration of device ${DEV}:${SLT}" >&2 -+ exit 1 -+fi -+ -+PIN=$(echo "${pin_cfg}" | awk '{ print $2 }') -+CFG=$(echo "${pin_cfg}" | awk '{ print $3 }' | tr -d "'") -+ -+echo "Regenerating with:" -+echo "PIN: $PIN" -+echo "CONFIG: $CFG" -+ -+trap 'echo "Ignoring CONTROL-C!"' INT TERM -+ -+# Get the existing key. -+if ! existing_key=$(clevis luks pass -d "${DEV}" -s "${SLT}" 2>/dev/null); then -+ # We failed to obtain the passphrase for the slot -- perhaps -+ # it was rotated? --, so let's request user input. -+ read -r -s -p "Enter existing LUKS password: " existing_key; echo -+fi -+ -+# Check if the key is valid. -+if ! cryptsetup open --test-passphrase "${DEV}" <<< "${existing_key}"; then -+ exit 1 -+fi -+ -+# Check if we can do the update in-place, i.e., if the key we got is the one -+# for the slot we are interested in. -+in_place= -+if cryptsetup open --test-passphrase --key-slot "${SLT}" "${DEV}" \ -+ <<< "${existing_key}"; then -+ in_place=true -+fi -+ -+# Create new key. -+if ! new_passphrase=$(generate_key "${DEV}"); then -+ echo "Error generating new key for device ${DEV}" >&2 -+ exit 1 -+fi -+ -+# Reencrypt the new password. -+if ! jwe=$(clevis encrypt "${PIN}" "${CFG}" <<< "${new_passphrase}"); then -+ echo "Error using pin '${PIN}' with config '${CFG}'" >&2 -+ exit 1 -+fi -+ -+# Updating the metadata and the actual passphrase are destructive operations, -+# hence we will do a backup of the LUKS header and restore it later in case -+# we have issues performing these operations. -+if ! TMP="$(mktemp -d)"; then -+ echo "Creating a temporary dir for device backup/restore failed!" >&2 -+ exit 1 -+fi -+trap 'on_exit' EXIT -+ -+# Backup LUKS header. -+if ! clevis_luks_backup_dev "${DEV}" "${TMP}"; then -+ echo "Error while trying to back up LUKS header from ${DEV}" >&2 -+ exit 1 -+fi -+ -+restore_device() { -+ local DEV="${1}" -+ local TMP="${2}" -+ -+ if ! clevis_luks_restore_dev "${DEV}" "${TMP}"; then -+ echo "Error while trying to restore LUKS header from ${DEV}." >&2 -+ else -+ echo "LUKS header restored successfully." >&2 -+ fi -+} -+ -+# Update the key slot with the new key. If we have the key for this slot, -+# the change happens in-place. Otherwise, we kill the slot and re-add it. -+if [ -n "${in_place}" ]; then -+ if ! cryptsetup luksChangeKey "${DEV}" --key-slot "${SLT}" \ -+ <(echo -n "${new_passphrase}") <<< "${existing_key}"; then -+ echo "Error updating LUKS passphrase in ${DEV}:${SLT}" >&2 -+ restore_device "${DEV}" "${TMP}" -+ exit 1 -+ fi -+else -+ if ! cryptsetup luksKillSlot --batch-mode "${DEV}" "${SLT}"; then -+ echo "Error wiping slot ${SLT} from ${DEV}" >&2 -+ restore_device "${DEV}" "${TMP}" -+ exit 1 -+ fi -+ -+ if ! echo -n "${new_passphrase}" \ -+ | cryptsetup luksAddKey --key-slot "${SLT}" \ -+ --key-file <(echo -n "${existing_key}") "${DEV}"; then -+ echo "Error updating LUKS passphrase in ${DEV}:${SLT}." >&2 -+ restore_device "${DEV}" "${TMP}" -+ exit 1 -+ fi -+fi -+ -+# Update the metadata. -+if ! clevis_luks_save_slot "${DEV}" "${SLT}" "${jwe}" "overwrite"; then -+ echo "Error updating metadata in ${DEV}:${SLT}" >&2 -+ restore_device "${DEV}" "${TMP}" -+ exit 1 -+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 -+ echo "Invalid configuration detected after rebinding. Reverting changes." -+ restore_device "${DEV}" "${TMP}" -+ 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..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 -new file mode 100755 -index 0000000..733a4b6 ---- /dev/null -+++ b/src/luks/tests/backup-restore-luks1 -@@ -0,0 +1,114 @@ -+#!/bin/bash -x -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2020 Red Hat, Inc. -+# Author: Sergio Correia -+# -+# 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 . -+# -+ -+TEST="${0}" -+. tests-common-functions -+. clevis-luks-common-functions -+ -+function on_exit() { -+ if [ "$PID" ]; then kill $PID; wait $PID || true; fi -+ [ -d "$TMP" ] && rm -rf $TMP -+} -+ -+trap 'on_exit' EXIT -+trap 'exit' ERR -+ -+export TMP=$(mktemp -d) -+mkdir -p "${TMP}/db" -+ -+# Generate the server keys -+KEYS="$TMP/db" -+tangd-keygen $TMP/db sig exc -+if which tangd-update; then -+ mkdir -p "${TMP}/cache" -+ 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 "${KEYS}" & -+export PID=$! -+sleep 0.25 -+ -+url="http://localhost:${port}" -+adv="${TMP}/adv" -+curl "${url}/adv" -o "${adv}" -+ -+cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv") -+ -+# LUKS1. -+DEV="${TMP}/luks1-device" -+new_device "luks1" "${DEV}" -+ -+SLT=5 -+if ! clevis luks bind -f -s "${SLT}" -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: Bind should have succeeded." -+fi -+ -+ORIG_DEV="${TMP}/device.orig" -+# Let's save it for comparison later. -+cp -f "${DEV}" "${ORIG_DEV}" -+ -+# Now let's backup and restore. -+if ! clevis_luks_backup_dev "${DEV}" "${TMP}"; then -+ error "${TEST}: backup of ${DEV} failed." -+fi -+ -+# Now let's remove both the binding and the initial passphrase. -+if ! clevis luks unbind -f -s "${SLT}" -d "${DEV}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: unbind of slot ${SLT} in ${DEV} failed." -+fi -+ -+if ! cryptsetup luksRemoveKey --batch-mode "${DEV}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: error removing the default password from ${DEV}." -+fi -+ -+# Making sure we have no slots enabled. -+enabled=$(cryptsetup luksDump "${DEV}" | grep ENABLED | wc -l) -+if [ "${enabled}" -ne 0 ]; then -+ error "${TEST}: we should not have any enabled (${enabled}) slots." -+fi -+ -+# Now we can restore it. -+if ! clevis_luks_restore_dev "${DEV}" "${TMP}"; then -+ error "${TEST}: error restoring ${DEV}." -+fi -+ -+# And compare whether they are the same. -+if ! cmp --silent "${ORIG_DEV}" "${DEV}"; then -+ error "${TEST}: the device differs from the original one after the restore." -+fi -+ -+# And making sure both the default passphrase and the binding work. -+if ! cryptsetup open --test-passphrase "${DEV}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: the default passphrase for ${DEV} did no work." -+fi -+ -+TEST_DEV="test-device-${RANDOM}" -+if ! clevis luks unlock -d "${DEV}" -n "${TEST_DEV}"; then -+ error "${TEST}: we were unable to unlock ${DEV}." -+fi -+ -+cryptsetup close "${TEST_DEV}" -+ -+kill -9 "${PID}" -+! wait "${PID}" -+unset PID -diff --git a/src/luks/tests/backup-restore-luks2 b/src/luks/tests/backup-restore-luks2 -new file mode 100755 -index 0000000..a3b8608 ---- /dev/null -+++ b/src/luks/tests/backup-restore-luks2 -@@ -0,0 +1,115 @@ -+#!/bin/bash -x -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2020 Red Hat, Inc. -+# Author: Sergio Correia -+# -+# 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 . -+# -+ -+TEST="${0}" -+. tests-common-functions -+. clevis-luks-common-functions -+ -+function on_exit() { -+ if [ "$PID" ]; then kill $PID; wait $PID || true; fi -+ [ -d "$TMP" ] && rm -rf $TMP -+} -+ -+trap 'on_exit' EXIT -+trap 'exit' ERR -+ -+export TMP=$(mktemp -d) -+mkdir -p "${TMP}/db" -+ -+# Generate the server keys -+KEYS="$TMP/db" -+tangd-keygen $TMP/db sig exc -+if which tangd-update; then -+ mkdir -p "${TMP}/cache" -+ 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 "${KEYS}" & -+export PID=$! -+sleep 0.25 -+ -+url="http://localhost:${port}" -+adv="${TMP}/adv" -+curl "${url}/adv" -o "${adv}" -+ -+cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv") -+ -+# LUKS2. -+DEV="${TMP}/luks2-device" -+new_device "luks2" "${DEV}" -+ -+SLT=5 -+if ! clevis luks bind -f -s "${SLT}" -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: Bind should have succeeded." -+fi -+ -+ORIG_DEV="${TMP}/device.orig" -+# Let's save it for comparison later. -+cp -f "${DEV}" "${ORIG_DEV}" -+ -+# Now let's backup and restore. -+if ! clevis_luks_backup_dev "${DEV}" "${TMP}"; then -+ error "${TEST}: backup of ${DEV} failed." -+fi -+ -+# Now let's remove both the binding and the initial passphrase. -+if ! clevis luks unbind -f -s "${SLT}" -d "${DEV}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: unbind of slot ${SLT} in ${DEV} failed." -+fi -+ -+if ! cryptsetup luksRemoveKey --batch-mode "${DEV}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: error removing the default password from ${DEV}." -+fi -+ -+# Making sure we have no slots enabled. -+enabled=$(cryptsetup luksDump "${DEV}" \ -+ | sed -rn 's|^\s+([0-9]+): luks2$|\1|p' | wc -l) -+if [ "${enabled}" -ne 0 ]; then -+ error "${TEST}: we should not have any enabled (${enabled}) slots." -+fi -+ -+# Now we can restore it. -+if ! clevis_luks_restore_dev "${DEV}" "${TMP}"; then -+ error "${TEST}: error restoring ${DEV}." -+fi -+ -+# And compare whether they are the same. -+if ! cmp --silent "${ORIG_DEV}" "${DEV}"; then -+ error "${TEST}: the device differs from the original one after the restore." -+fi -+ -+# And making sure both the default passphrase and the binding work. -+if ! cryptsetup open --test-passphrase "${DEV}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: the default passphrase for ${DEV} did no work." -+fi -+ -+TEST_DEV="test-device-${RANDOM}" -+if ! clevis luks unlock -d "${DEV}" -n "${TEST_DEV}"; then -+ error "${TEST}: we were unable to unlock ${DEV}." -+fi -+ -+cryptsetup close "${TEST_DEV}" -+ -+kill -9 "${PID}" -+! wait "${PID}" -+unset PID -diff --git a/src/luks/tests/meson.build b/src/luks/tests/meson.build -index 4757c4b..dbef9bf 100644 ---- a/src/luks/tests/meson.build -+++ b/src/luks/tests/meson.build -@@ -87,6 +87,9 @@ 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) -+test('backup-restore-luks1', find_program('backup-restore-luks1'), env: env) -+test('regen-inplace-luks1', find_program('regen-inplace-luks1'), env: env, timeout: 90) -+test('regen-not-inplace-luks1', find_program('regen-not-inplace-luks1'), env: env, timeout: 90) - - # LUKS2 tests go here, and they get included if we get support for it, based - # on the cryptsetup version. -@@ -107,4 +110,7 @@ if luksmeta_data.get('OLD_CRYPTSETUP') == '0' - 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) -+ 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-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 -new file mode 100755 -index 0000000..3a42ced ---- /dev/null -+++ b/src/luks/tests/regen-inplace-luks1 -@@ -0,0 +1,98 @@ -+#!/bin/bash -x -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2020 Red Hat, Inc. -+# Author: Sergio Correia -+# -+# 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 . -+# -+ -+TEST="${0}" -+. tests-common-functions -+ -+function on_exit() { -+ if [ "$PID" ]; then kill $PID; wait $PID || true; fi -+ [ -d "$TMP" ] && rm -rf $TMP -+} -+ -+trap 'on_exit' EXIT -+trap 'exit' ERR -+ -+export TMP=$(mktemp -d) -+mkdir -p "${TMP}/db" -+ -+# Generate the server keys -+KEYS="$TMP/db" -+tangd-keygen $TMP/db sig exc -+if which tangd-update; then -+ mkdir -p "${TMP}/cache" -+ 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 "${KEYS}" & -+export PID=$! -+sleep 0.25 -+ -+url="http://localhost:${port}" -+adv="${TMP}/adv" -+curl "${url}/adv" -o "${adv}" -+ -+cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv") -+ -+# LUKS1. -+DEV="${TMP}/luks1-device" -+new_device "luks1" "${DEV}" -+ -+SLT=1 -+if ! clevis luks bind -f -s "${SLT}" -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: Bind should have succeeded." -+fi -+ -+# Now let's remove the initial passphrase. -+if ! cryptsetup luksRemoveKey --batch-mode "${DEV}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: error removing the default password from ${DEV}." -+fi -+ -+# Making sure we have a single slot enabled. -+enabled=$(cryptsetup luksDump "${DEV}" | grep ENABLED | wc -l) -+if [ "${enabled}" -ne 1 ]; then -+ error "${TEST}: we should have only one slot enabled (${enabled})." -+fi -+ -+old_key=$(clevis luks pass -d "${DEV}" -s "${SLT}") -+ -+# Now let's try regen. -+if ! clevis_regen "${DEV}" "${SLT}" "${DEFAULT_PASS}"; then -+ error "${TEST}: clevis luks regen failed" -+fi -+ -+new_key=$(clevis luks pass -d "${DEV}" -s "${SLT}") -+ -+if [ "${old_key}" = "${new_key}" ]; then -+ error "${TEST}: the passphrases should be different" -+fi -+ -+TEST_DEV="test-device-${RANDOM}" -+if ! clevis luks unlock -d "${DEV}" -n "${TEST_DEV}"; then -+ error "${TEST}: we were unable to unlock ${DEV}." -+fi -+ -+cryptsetup close "${TEST_DEV}" -+ -+kill -9 "${PID}" -+! wait "${PID}" -+unset PID -diff --git a/src/luks/tests/regen-inplace-luks2 b/src/luks/tests/regen-inplace-luks2 -new file mode 100755 -index 0000000..1cb7a29 ---- /dev/null -+++ b/src/luks/tests/regen-inplace-luks2 -@@ -0,0 +1,99 @@ -+#!/bin/bash -x -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2020 Red Hat, Inc. -+# Author: Sergio Correia -+# -+# 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 . -+# -+ -+TEST="${0}" -+. tests-common-functions -+ -+function on_exit() { -+ if [ "$PID" ]; then kill $PID; wait $PID || true; fi -+ [ -d "$TMP" ] && rm -rf $TMP -+} -+ -+trap 'on_exit' EXIT -+trap 'exit' ERR -+ -+export TMP=$(mktemp -d) -+mkdir -p "${TMP}/db" -+ -+# Generate the server keys -+KEYS="$TMP/db" -+tangd-keygen $TMP/db sig exc -+if which tangd-update; then -+ mkdir -p "${TMP}/cache" -+ 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 "${KEYS}" & -+export PID=$! -+sleep 0.25 -+ -+url="http://localhost:${port}" -+adv="${TMP}/adv" -+curl "${url}/adv" -o "${adv}" -+ -+cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv") -+ -+# LUKS2. -+DEV="${TMP}/luks2-device" -+new_device "luks2" "${DEV}" -+ -+SLT=1 -+if ! clevis luks bind -f -s "${SLT}" -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: Bind should have succeeded." -+fi -+ -+# Now let's remove the initial passphrase. -+if ! cryptsetup luksRemoveKey --batch-mode "${DEV}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: error removing the default password from ${DEV}." -+fi -+ -+# Making sure we have a single slot enabled. -+enabled=$(cryptsetup luksDump "${DEV}" \ -+ | sed -rn 's|^\s+([0-9]+): luks2$|\1|p' | wc -l) -+if [ "${enabled}" -ne 1 ]; then -+ error "${TEST}: we should have only one slot enabled (${enabled})." -+fi -+ -+old_key=$(clevis luks pass -d "${DEV}" -s "${SLT}") -+ -+# Now let's try regen. -+if ! clevis_regen "${DEV}" "${SLT}" "${DEFAULT_PASS}"; then -+ error "${TEST}: clevis luks regen failed" -+fi -+ -+new_key=$(clevis luks pass -d "${DEV}" -s "${SLT}") -+ -+if [ "${old_key}" = "${new_key}" ]; then -+ error "${TEST}: the passphrases should be different" -+fi -+ -+TEST_DEV="test-device-${RANDOM}" -+if ! clevis luks unlock -d "${DEV}" -n "${TEST_DEV}"; then -+ error "${TEST}: we were unable to unlock ${DEV}." -+fi -+ -+cryptsetup close "${TEST_DEV}" -+ -+kill -9 "${PID}" -+! wait "${PID}" -+unset PID -diff --git a/src/luks/tests/regen-not-inplace-luks1 b/src/luks/tests/regen-not-inplace-luks1 -new file mode 100755 -index 0000000..1b65ca7 ---- /dev/null -+++ b/src/luks/tests/regen-not-inplace-luks1 -@@ -0,0 +1,95 @@ -+#!/bin/bash -x -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2020 Red Hat, Inc. -+# Author: Sergio Correia -+# -+# 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 . -+# -+ -+TEST="${0}" -+. tests-common-functions -+ -+function on_exit() { -+ if [ "$PID" ]; then kill $PID; wait $PID || true; fi -+ [ -d "$TMP" ] && rm -rf $TMP -+} -+ -+trap 'on_exit' EXIT -+trap 'exit' ERR -+ -+export TMP=$(mktemp -d) -+mkdir -p "${TMP}/db" -+ -+# Generate the server keys -+KEYS="$TMP/db" -+tangd-keygen $TMP/db sig exc -+if which tangd-update; then -+ mkdir -p "${TMP}/cache" -+ 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 "${KEYS}" & -+export PID=$! -+sleep 0.25 -+ -+url="http://localhost:${port}" -+adv="${TMP}/adv" -+curl "${url}/adv" -o "${adv}" -+ -+cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv") -+ -+# LUKS1. -+DEV="${TMP}/luks1-device" -+new_device "luks1" "${DEV}" -+ -+SLT=1 -+if ! clevis luks bind -f -s "${SLT}" -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: Bind should have succeeded." -+fi -+ -+# Now let's rotate the keys in the server and remove the old ones, so that we -+# will be unable to unlock the volume using clevis and will have to provide -+# manually a password for clevis luks regen. -+rm -rf "${TMP}"/db/* -+tangd-keygen $TMP/db sig exc -+if which tangd-update; then -+ mkdir -p "${TMP}/cache" -+ tangd-update "${TMP}/db" "${TMP}/cache" -+fi -+ -+# Making sure we have two slots enabled. -+enabled=$(cryptsetup luksDump "${DEV}" | grep ENABLED | wc -l) -+if [ "${enabled}" -ne 2 ]; then -+ error "${TEST}: we should have two slots enabled (${enabled})." -+fi -+ -+# Now let's try regen. -+if ! clevis_regen "${DEV}" "${SLT}" "${DEFAULT_PASS}"; then -+ error "${TEST}: clevis luks regen failed" -+fi -+ -+TEST_DEV="test-device-${RANDOM}" -+if ! clevis luks unlock -d "${DEV}" -n "${TEST_DEV}"; then -+ error "${TEST}: we were unable to unlock ${DEV}." -+fi -+ -+cryptsetup close "${TEST_DEV}" -+ -+kill -9 "${PID}" -+! wait "${PID}" -+unset PID -diff --git a/src/luks/tests/regen-not-inplace-luks2 b/src/luks/tests/regen-not-inplace-luks2 -new file mode 100755 -index 0000000..dc91449 ---- /dev/null -+++ b/src/luks/tests/regen-not-inplace-luks2 -@@ -0,0 +1,96 @@ -+#!/bin/bash -x -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2020 Red Hat, Inc. -+# Author: Sergio Correia -+# -+# 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 . -+# -+ -+TEST="${0}" -+. tests-common-functions -+ -+function on_exit() { -+ if [ "$PID" ]; then kill $PID; wait $PID || true; fi -+ [ -d "$TMP" ] && rm -rf $TMP -+} -+ -+trap 'on_exit' EXIT -+trap 'exit' ERR -+ -+export TMP=$(mktemp -d) -+mkdir -p "${TMP}/db" -+ -+# Generate the server keys -+KEYS="$TMP/db" -+tangd-keygen $TMP/db sig exc -+if which tangd-update; then -+ mkdir -p "${TMP}/cache" -+ 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 "${KEYS}" & -+export PID=$! -+sleep 0.25 -+ -+url="http://localhost:${port}" -+adv="${TMP}/adv" -+curl "${url}/adv" -o "${adv}" -+ -+cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv") -+ -+# LUKS2. -+DEV="${TMP}/luks2-device" -+new_device "luks2" "${DEV}" -+ -+SLT=1 -+if ! clevis luks bind -f -s "${SLT}" -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: Bind should have succeeded." -+fi -+ -+# Now let's rotate the keys in the server and remove the old ones, so that we -+# will be unable to unlock the volume using clevis and will have to provide -+# manually a password for clevis luks regen. -+rm -rf "${TMP}"/db/* -+tangd-keygen $TMP/db sig exc -+if which tangd-update; then -+ mkdir -p "${TMP}/cache" -+ tangd-update "${TMP}/db" "${TMP}/cache" -+fi -+ -+# Making sure we have two slots enabled. -+enabled=$(cryptsetup luksDump "${DEV}" \ -+ | sed -rn 's|^\s+([0-9]+): luks2$|\1|p' | wc -l) -+if [ "${enabled}" -ne 2 ]; then -+ error "${TEST}: we should have two slots enabled (${enabled})." -+fi -+ -+# Now let's try regen. -+if ! clevis_regen "${DEV}" "${SLT}" "${DEFAULT_PASS}"; then -+ error "${TEST}: clevis luks regen failed" -+fi -+ -+TEST_DEV="test-device-${RANDOM}" -+if ! clevis luks unlock -d "${DEV}" -n "${TEST_DEV}"; then -+ error "${TEST}: we were unable to unlock ${DEV}." -+fi -+ -+cryptsetup close "${TEST_DEV}" -+ -+kill -9 "${PID}" -+! wait "${PID}" -+unset PID -diff --git a/src/luks/tests/tests-common-functions.in b/src/luks/tests/tests-common-functions.in -index 7b3fdad..6101f28 100755 ---- a/src/luks/tests/tests-common-functions.in -+++ b/src/luks/tests/tests-common-functions.in -@@ -229,5 +229,31 @@ tang_get_adv() { - curl -o "${adv}" http://"${TANG_HOST}":"${port}"/adv - } - -+# Regenerate binding. -+clevis_regen() { -+ local DEV="${1}" -+ local SLT="${2}" -+ local PASS="${3}" -+ -+ expect -d << CLEVIS_REGEN -+ set timeout 120 -+ spawn sh -c "clevis luks regen -d $DEV -s $SLT" -+ expect { -+ "Enter existing LUKS password" { -+ send "$PASS\r" -+ exp_continue -+ } -+ "Do you wish to trust these keys" { -+ send "y\r" -+ exp_continue -+ } -+ expect eof -+ wait -+ } -+CLEVIS_REGEN -+ ret=$? -+ return "${ret}" -+} -+ - export TANG_HOST=127.0.0.1 - export DEFAULT_PASS='just-some-test-password-here' --- -2.18.4 - diff --git a/SOURCES/0007-Add-clevis-luks-report.patch b/SOURCES/0007-Add-clevis-luks-report.patch deleted file mode 100644 index 962e700..0000000 --- a/SOURCES/0007-Add-clevis-luks-report.patch +++ /dev/null @@ -1,464 +0,0 @@ -From a85f50f789d69d9ca0a4096a64ac912f5967f97f Mon Sep 17 00:00:00 2001 -From: Sergio Correia -Date: Sun, 10 May 2020 15:32:50 -0300 -Subject: [PATCH 7/8] Add clevis luks report - ---- - src/luks/clevis-luks-report | 95 +++++++++++++++++++++++++++++ - src/luks/clevis-luks-report-compare | 71 +++++++++++++++++++++ - src/luks/clevis-luks-report-decode | 59 ++++++++++++++++++ - src/luks/clevis-luks-report-sss | 53 ++++++++++++++++ - src/luks/clevis-luks-report-tang | 67 ++++++++++++++++++++ - src/luks/clevis-luks-report.1.adoc | 41 +++++++++++++ - src/luks/meson.build | 7 +++ - 7 files changed, 393 insertions(+) - 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-decode - create mode 100755 src/luks/clevis-luks-report-sss - create mode 100755 src/luks/clevis-luks-report-tang - create mode 100644 src/luks/clevis-luks-report.1.adoc - -diff --git a/src/luks/clevis-luks-report b/src/luks/clevis-luks-report -new file mode 100755 -index 0000000..f047256 ---- /dev/null -+++ b/src/luks/clevis-luks-report -@@ -0,0 +1,95 @@ -+#!/usr/bin/bash -e -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2018 Red Hat, Inc. -+# Author: Radovan Sroka -+# -+# 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 . -+# -+ -+. clevis-luks-common-functions -+ -+SUMMARY="Report any key rotation on the server side" -+ -+if [ "$1" == "--summary" ]; then -+ echo "$SUMMARY" -+ exit 0 -+fi -+ -+function usage_and_exit () { -+ echo >&2 -+ echo "Usage: clevis luks report [-qr] -d DEV -s SLOT" >&2 -+ echo >&2 -+ echo -e " -q\t Quiet mode" >&2 -+ echo -e " -r\t Regenerate luks metadata with \"clevis luks regen -d DEV -s SLOT\"" >&2 -+ echo >&2 -+ echo "$SUMMARY" >&2 -+ echo >&2 -+ exit "$1" -+} -+ -+while getopts "hd:s:rq" o; do -+ case "$o" in -+ d) DEV="$OPTARG";; -+ h) usage_and_exit 0;; -+ r) ROPT="regen";; -+ s) SLT="$OPTARG";; -+ q) QOPT="quiet";; -+ *) usage_and_exit 1;; -+ esac -+done -+ -+### 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 ! DATA_CODED=$(clevis_luks_read_slot "${DEV}" "${SLT}"); then -+ # Error message was already displayed by clevis_luks_read_slot(), -+ # at this point. -+ exit 1 -+fi -+ -+EXE="$(findexe clevis-luks-report-decode)" -+RESULT="$($EXE "${DATA_CODED}")" -+ -+if [ -n "$RESULT" ]; then -+ echo "$RESULT" -+ echo "Report detected that some keys were rotated." -+ if [ -z "$QOPT" ]; then -+ if [ -z "$ROPT" ]; then -+ read -r -p "Do you want to regenerate luks metadata with \"clevis luks regen -d $DEV -s $SLT\"? [ynYN] " ans < /dev/tty -+ [[ "$ans" =~ ^[yY]$ ]] && ROPT="regen" -+ fi -+ fi -+else -+ exit 0 -+fi -+ -+if [ "$ROPT" = "regen" ]; then -+ EXE="$(findexe clevis-luks-regen)" -+ exec "$EXE" -d "$DEV" -s "$SLT" -+else -+ if [ -n "${RESULT}" ]; then -+ # Keys were rotated. -+ exit 1 -+ fi -+fi -diff --git a/src/luks/clevis-luks-report-compare b/src/luks/clevis-luks-report-compare -new file mode 100755 -index 0000000..2ba5132 ---- /dev/null -+++ b/src/luks/clevis-luks-report-compare -@@ -0,0 +1,71 @@ -+#!/usr/bin/bash -e -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2018 Red Hat, Inc. -+# Author: Radovan Sroka -+# -+# This program is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+# -+ -+SUMMARY="Compare two sets of keys" -+ -+if [ "$1" == "--summary" ]; then -+ echo "$SUMMARY" -+ exit 1 -+fi -+ -+if [ -z "$1" ]; then -+ echo "$0 missing the first argument!" -+ exit 1 -+fi -+ -+if [ -z "$2" ]; then -+ echo "$0 missing the second argument!" -+ exit 1 -+fi -+ -+ADV_KEYS="$1" # keys from advertisement -+LUKS_KEYS="$2" # keys from luks metadata -+ -+### iterate over adv keys and make thumbprints -+CNT=0 -+declare -a ADV_KEYS_ARRAY -+while res="$(jose fmt -j- -g keys -g"$CNT" -o- <<< "$ADV_KEYS")"; do -+ thp="$(echo "$res" | jose jwk thp -i-)" -+ ADV_KEYS_ARRAY["$CNT"]="$thp" -+ CNT=$(( CNT + 1 )) -+done -+ -+CNT=0 -+while key="$(jose fmt -j- -g keys -g"$CNT" -o- <<< "$LUKS_KEYS")"; do -+ thp="$(echo "$key" | jose jwk thp -i-)" -+ -+ FOUND=0 -+ for k in "${ADV_KEYS_ARRAY[@]}" -+ do -+ if [ "$k" = "$thp" ]; then -+ FOUND=1 -+ break -+ fi -+ done -+ -+ if [ "$FOUND" -eq "0" ]; then -+ echo "Key \"$thp\" is not in the advertisement and was probably rotated!" -+ echo "$key" -+ echo -+ fi -+ CNT=$(( CNT + 1 )) -+done -+ -+exit 0 -diff --git a/src/luks/clevis-luks-report-decode b/src/luks/clevis-luks-report-decode -new file mode 100755 -index 0000000..f39d1e9 ---- /dev/null -+++ b/src/luks/clevis-luks-report-decode -@@ -0,0 +1,59 @@ -+#!/usr/bin/bash -e -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2018 Red Hat, Inc. -+# Author: Radovan Sroka -+# -+# 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 . -+# -+ -+. clevis-luks-common-functions -+ -+SUMMARY="Decode luks header" -+ -+if [ "$1" == "--summary" ]; then -+ echo "$SUMMARY" -+ exit 1 -+fi -+ -+if [ -z "$1" ]; then -+ echo "$0 missing the first argument!" -+ exit 1 -+fi -+ -+DATA_CODED="$1" -+ -+if DATA_CODED="$(jose jwe fmt -i- <<< "$DATA_CODED")"; 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 -+ -+### get pin and url -+ -+if ! PIN="$(jose fmt -j- -g clevis -g pin -u- <<< "$DATA_DECODED")" || [ -z "$PIN" ]; then -+ echo "Pin wasn't found in luks metadata!" >&2 -+ exit 1 -+fi -+ -+if ! CONTENT="$(jose fmt -j- -g clevis -g "$PIN" -o- <<< "$DATA_DECODED")" || [ -z "$CONTENT" ]; then -+ echo "Content wasn't found!" >&2 -+ exit 1 -+fi -+ -+EXE="$(findexe clevis-luks-report-"$PIN")" -+ -+exec "$EXE" "$CONTENT" -diff --git a/src/luks/clevis-luks-report-sss b/src/luks/clevis-luks-report-sss -new file mode 100755 -index 0000000..1dba4c1 ---- /dev/null -+++ b/src/luks/clevis-luks-report-sss -@@ -0,0 +1,53 @@ -+#!/bin/bash -e -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2018 Red Hat, Inc. -+# Author: Radovan Sroka -+# -+# 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 . -+# -+ -+. clevis-luks-common-functions -+ -+SUMMARY="SSS report plugin" -+ -+if [ "$1" == "--summary" ]; then -+ echo "$SUMMARY" -+ exit 1 -+fi -+ -+if [ -z "$1" ]; then -+ echo "$0 missing the first argument!" >&2 -+ exit 1 -+fi -+ -+CONTENT="$1" # sss content -+ -+CNT=0 -+while DATA_CODED="$(jose fmt -j- -g jwe -g"$CNT" -u- <<< "$CONTENT")"; do -+ if [ -z "$DATA_CODED" ]; then -+ CNT=$(( CNT + 1 )) -+ continue # in some cases it can be empty string -+ fi -+ -+ EXE="$(findexe clevis-luks-report-decode)" -+ if ! $EXE "$DATA_CODED"; then -+ echo "Failed" >&2 -+ exit 1 -+ fi -+ -+ CNT=$(( CNT + 1 )) -+done -+ -+exit 0 -diff --git a/src/luks/clevis-luks-report-tang b/src/luks/clevis-luks-report-tang -new file mode 100755 -index 0000000..07f2a72 ---- /dev/null -+++ b/src/luks/clevis-luks-report-tang -@@ -0,0 +1,67 @@ -+#!/usr/bin/bash -e -+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2018 Red Hat, Inc. -+# Author: Radovan Sroka -+# -+# 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 . -+# -+ -+. clevis-luks-common-functions -+ -+SUMMARY="Tang report plugin" -+ -+if [ "$1" == "--summary" ]; then -+ echo "$SUMMARY" -+ exit 1 -+fi -+ -+if [ -z "$1" ]; then -+ echo "$0 missing the first argument!" -+ exit 1 -+fi -+ -+CONTENT="$1" -+ -+### Get the advertisement -+if ! URL="$(jose fmt -j- -g url -u- <<< "$CONTENT")" || [ -z "$URL" ]; then -+ echo "URL was not found!" >&2 -+ exit 1 -+fi -+ -+if ! jws="$(curl -sfg "$URL/adv")"; then -+ echo "Unable to fetch advertisement: $URL/adv!" >&2 -+ exit 1 -+fi -+ -+if ! TANG_KEYS="$(jose fmt -j- -Og payload -SyOg keys -AUo- <<< "$jws")"; then -+ echo "Advertisement is malformed!" >&2 -+ exit 1 -+fi -+ -+### Check advertisement validity -+ver="$(jose jwk use -i- -r -u verify -o- <<< "$TANG_KEYS")" -+if ! jose jws ver -i "$jws" -k- -a <<< "$ver"; then -+ echo "Advertisement is missing signatures!" >&2 -+ exit 1 -+fi -+ -+if ! LUKS_KEYS="$(jose fmt -j- -g adv -o- <<< "$CONTENT")" || [ -z "$LUKS_KEYS" ]; then -+ echo "LUKS keys from LUKS metadata were not found!" >&2 -+ exit 1 -+fi -+ -+EXE="$(findexe clevis-luks-report-compare)" -+ -+exec "$EXE" "$TANG_KEYS" "$LUKS_KEYS" -diff --git a/src/luks/clevis-luks-report.1.adoc b/src/luks/clevis-luks-report.1.adoc -new file mode 100644 -index 0000000..cf42afe ---- /dev/null -+++ b/src/luks/clevis-luks-report.1.adoc -@@ -0,0 +1,41 @@ -+CLEVIS-LUKS-REPORT(1) -+===================== -+:doctype: manpage -+ -+ -+== NAME -+ -+clevis-luks-report - Reports whether a pin bound to a LUKS1 or LUKS2 volume has been rotated -+ -+== SYNOPSIS -+ -+*clevis luks report* -d DEV -s SLT -+ -+== OVERVIEW -+ -+The *clevis luks report* command checks a given slot of a LUKS device and reports whether the pin bound to it -+-- if any -- has been rotated. -+ -+== OPTIONS -+ -+* *-d* _DEV_ : -+ The bound LUKS device -+ -+* *-s* _SLT_ : -+ The slot or key slot number for the pin to be verified -+ -+* *-q* : -+ Quiet mode. If used, we will not prompt whether to regenerate data with *clevis luks regen* -+ -+* *-r* : -+ Regenerates LUKS metadata with *clevis luks regen -d DEV -s SLOT* -+ -+== EXAMPLE -+ -+ Check whether the pin bound to slot 1 in /dev/sda1 has been rotated: -+ -+ # clevis luks report -d /dev/sda1 -s 1 -+ -+== SEE ALSO -+ -+link:clevis-luks-regen.1.adoc[*clevis-luks-regen*(1)] -diff --git a/src/luks/meson.build b/src/luks/meson.build -index f21388d..ee588c3 100644 ---- a/src/luks/meson.build -+++ b/src/luks/meson.build -@@ -47,6 +47,13 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found() - - 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-compare') -+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-decode') -+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-sss') -+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-tang') -+ mans += join_paths(meson.current_source_dir(), 'clevis-luks-report.1') - else - warning('Will not install LUKS support due to missing dependencies!') - endif --- -2.18.4 - diff --git a/SOURCES/0008-Use-one-clevis-luks-askpass-per-device.patch b/SOURCES/0008-Use-one-clevis-luks-askpass-per-device.patch deleted file mode 100644 index b9f0532..0000000 --- a/SOURCES/0008-Use-one-clevis-luks-askpass-per-device.patch +++ /dev/null @@ -1,339 +0,0 @@ -From 3250784e99016d9f920892dbb1438b9e76fb210b Mon Sep 17 00:00:00 2001 -From: Sergio Correia -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 . - # - --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 - diff --git a/SOURCES/0009-Introduce-y-assume-yes-argument-to-clevis-luks-bind.patch b/SOURCES/0009-Introduce-y-assume-yes-argument-to-clevis-luks-bind.patch deleted file mode 100644 index 0e54343..0000000 --- a/SOURCES/0009-Introduce-y-assume-yes-argument-to-clevis-luks-bind.patch +++ /dev/null @@ -1,555 +0,0 @@ -From 7b1639b2194a8bfbb0daedf1cbdfc4ebef5f6b31 Mon Sep 17 00:00:00 2001 -From: Sergio Correia -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 -+# -+# 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 . -+ -+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 -+# -+# 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 . -+ -+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: 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 - diff --git a/SOURCES/0010-Add-clevis-luks-edit-command.patch b/SOURCES/0010-Add-clevis-luks-edit-command.patch deleted file mode 100644 index f41161f..0000000 --- a/SOURCES/0010-Add-clevis-luks-edit-command.patch +++ /dev/null @@ -1,1036 +0,0 @@ -From 46dc5904a9a6b0f1dcdb2511cc3f09671ef54b2a Mon Sep 17 00:00:00 2001 -From: Sergio Correia -Date: Wed, 20 May 2020 21:09:15 -0300 -Subject: [PATCH] Add clevis luks edit command - ---- - src/luks/clevis-luks-common-functions | 65 ++++-- - src/luks/clevis-luks-edit | 242 +++++++++++++++++++++++ - src/luks/clevis-luks-edit.1.adoc | 69 +++++++ - src/luks/clevis-luks-regen | 125 ++---------- - src/luks/meson.build | 3 + - src/luks/tests/edit-tang-luks1 | 106 ++++++++++ - src/luks/tests/edit-tang-luks2 | 106 ++++++++++ - src/luks/tests/meson.build | 28 ++- - src/luks/tests/regen-inplace-luks1 | 2 +- - src/luks/tests/regen-inplace-luks2 | 2 +- - src/luks/tests/regen-not-inplace-luks1 | 2 +- - src/luks/tests/regen-not-inplace-luks2 | 2 +- - src/luks/tests/tests-common-functions.in | 26 --- - src/luks/tests/unlock-tang-luks1 | 7 +- - src/luks/tests/unlock-tang-luks2 | 8 +- - 15 files changed, 606 insertions(+), 187 deletions(-) - create mode 100755 src/luks/clevis-luks-edit - create mode 100644 src/luks/clevis-luks-edit.1.adoc - create mode 100755 src/luks/tests/edit-tang-luks1 - create mode 100755 src/luks/tests/edit-tang-luks2 - -diff --git a/src/luks/clevis-luks-common-functions b/src/luks/clevis-luks-common-functions -index c9d712a..f3a875c 100644 ---- a/src/luks/clevis-luks-common-functions -+++ b/src/luks/clevis-luks-common-functions -@@ -141,11 +141,7 @@ clevis_luks_decode_jwe() { - local jwe="${1}" - - local coded -- if ! coded=$(jose jwe fmt -i- <<< "${jwe}"); then -- return 1 -- fi -- -- coded=$(jose fmt -j- -g protected -u- <<< "${coded}" | tr -d '"') -+ read -r -d . coded <<< "${jwe}" - jose b64 dec -i- <<< "${coded}" - } - -@@ -291,6 +287,46 @@ clevis_luks_read_pins_from_slot() { - printf "%s: %s\n" "${SLOT}" "${cfg}" - } - -+# clevis_luks_is_key_valid() checks whether the given key is valid to unlock -+# the given device. -+clevis_luks_is_key_valid() { -+ local DEV="${1}" -+ local KEY="${2}" -+ -+ if ! cryptsetup open --test-passphrase "${DEV}" \ -+ --key-file <(echo -n "${KEY}") 2>/dev/null; then -+ return 1 -+ fi -+ return 0 -+} -+ -+# clevis_luks_unlock_device_by_slot() does the unlock of the device and slot -+# passed as parameters and returns the decoded passphrase. -+clevis_luks_unlock_device_by_slot() { -+ local DEV="${1}" -+ local SLT="${2}" -+ -+ [ -z "${DEV}" ] && return 1 -+ [ -z "${SLT}" ] && return 1 -+ -+ local jwe passphrase -+ if ! jwe="$(clevis_luks_read_slot "${DEV}" "${SLT}" 2>/dev/null)" \ -+ || [ -z "${jwe}" ]; then -+ return 1 -+ fi -+ -+ if ! passphrase="$(clevis decrypt < <(echo -n "${jwe}") 2>/dev/null)" \ -+ || [ -z "${passphrase}" ]; then -+ return 1 -+ fi -+ -+ if ! clevis_luks_is_key_valid "${DEV}" "${passphrase}"; then -+ return 1 -+ fi -+ echo -n "${passphrase}" -+ return 0 -+} -+ - # clevis_luks_unlock_device() does the unlock of the device passed as - # parameter and returns the decoded passphrase. - clevis_luks_unlock_device() { -@@ -303,26 +339,15 @@ clevis_luks_unlock_device() { - return 1 - fi - -- local slt jwe passphrase -+ local slt pt - 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 -+ if ! pt=$(clevis_luks_unlock_device_by_slot "${DEV}" "${slt}") \ -+ || [ -z "${pt}" ]; then - continue - fi -- -- if ! cryptsetup luksOpen --test-passphrase "${DEV}" \ -- --key-file <(echo -n "${passphrase}"); then -- continue -- fi -- echo -n "${passphrase}" -+ echo -n "${pt}" - return 0 - done -- - return 1 - } - -diff --git a/src/luks/clevis-luks-edit b/src/luks/clevis-luks-edit -new file mode 100755 -index 0000000..fc95f75 ---- /dev/null -+++ b/src/luks/clevis-luks-edit -@@ -0,0 +1,242 @@ -+#!/bin/bash -e -+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2020 Red Hat, Inc. -+# Author: Sergio Correia -+# -+# 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 . -+# -+ -+. clevis-luks-common-functions -+ -+SUMMARY="Edit a binding from a clevis-bound slot in a LUKS device" -+ -+usage() { -+ echo >&2 -+ echo "Usage: clevis luks edit [-f] -d DEV -s SLT [-c CONFIG]" >&2 -+ echo >&2 -+ echo "$SUMMARY": >&2 -+ echo >&2 -+ echo " -d DEV The LUKS device to edit clevis-bound pins" >&2 -+ echo >&2 -+ echo " -s SLOT The slot to use when editing the clevis binding" >&2 -+ echo >&2 -+ echo " -f Proceed with the edit operation even if the configuration is the same" >&2 -+ echo >&2 -+ echo " -c CONFIG The updated config to use" >&2 -+ echo >&2 -+ exit 1 -+} -+ -+on_exit() { -+ [ -d "$TMP" ] && rm -rf "${TMP}" -+} -+ -+validate_cfg() { -+ local json="${1}" -+ jose fmt -j- -O <<< "${json}" 2>/dev/null -+} -+ -+edit_cfg() { -+ local cfg_file="${1}" -+ local editor="${EDITOR:-vi}" -+ -+ "${editor}" "${cfg_file}" || true -+ if ! validate_cfg "$(<"${cfg_file}")"; then -+ local ans= -+ while true; do -+ read -r -p \ -+ "Malformed configuration. Would you like to edit again? [ynYN] " \ -+ ans < /dev/tty -+ -+ [[ "${ans}" =~ ^[nN]$ ]] && return 1 -+ [[ "${ans}" =~ ^[yY]$ ]] && break -+ done -+ edit_cfg "${cfg_file}" -+ fi -+ return 0 -+} -+ -+if [ "${#}" -eq 1 ] && [ "${1}" = "--summary" ]; then -+ echo "${SUMMARY}" -+ exit 0 -+fi -+ -+CFG= -+FRC= -+while getopts ":fd:s:c:" o; do -+ case "$o" in -+ d) DEV=${OPTARG};; -+ s) SLT=${OPTARG};; -+ c) CFG=${OPTARG};; -+ f) FRC=-f;; -+ *) usage;; -+ esac -+done -+ -+if [ -z "${DEV}" ]; then -+ echo "Did not specify a device!" >&2 -+ usage -+fi -+ -+if [ -z "${SLT}" ]; then -+ echo "Did not specify a slot!" >&2 -+ usage -+fi -+ -+if ! binding="$(clevis luks list -d "${DEV}" -s "${SLT}" 2>/dev/null)" \ -+ || [ -z "${binding}" ]; then -+ echo "Error retrieving current configuration from ${DEV}:${SLT}" >&2 -+ exit 1 -+fi -+ -+read -r _ pin cfg <<< "${binding}" -+# Remove single quotes. -+cfg=${cfg//\'} -+if ! pretty_cfg="$(jq . <<< "${cfg}")" || [ -z "${pretty_cfg}" ]; then -+ echo "Error reading the configuration from ${DEV}:${SLT}" >&2 -+ exit 1 -+fi -+ -+if ! TMP="$(mktemp -d)" || [ -z "${TMP}" ]; then -+ echo "Creating a temporary dir for editing binding failed" >&2 -+ exit 1 -+fi -+ -+trap 'on_exit' EXIT -+trap 'on_exit' ERR -+ -+if [ -z "${CFG}" ]; then -+ CFG_FILE="${TMP}/cfg" -+ echo "${pretty_cfg}" > "${CFG_FILE}" -+ if ! edit_cfg "${CFG_FILE}"; then -+ exit 1 -+ fi -+ -+ if ! new_cfg="$(jq . -S < "${CFG_FILE}")" || [ -z "${new_cfg}" ]; then -+ echo "Error reading the updated config for ${DEV}:${SLT}" >&2 -+ exit 1 -+ fi -+else -+ if ! validate_cfg "${CFG}"; then -+ echo "Invalid configuration given as parameter with -c" >&2 -+ exit 1 -+ fi -+ new_cfg="$(jq . -S <<< "${CFG}")" -+fi -+ -+if [ "${new_cfg}" = "$(jq -S . <<< "${pretty_cfg}")" ] && [ -z "${FRC}" ]; then -+ echo "No changes detected; exiting" >&2 -+ exit 1 -+fi -+ -+if ! jcfg="$(jose fmt -j- -Oo- <<< "${new_cfg}" 2>/dev/null)" \ -+ || [ -z "${jcfg}" ]; then -+ echo "Error preparing the configuration for the binding update" >&2 -+ exit 1 -+fi -+ -+if [ -z "${CFG}" ]; then -+ printf "Pin: %s\nNew config:\n%s\n" "${pin}" "${new_cfg}" -+ while true; do -+ read -r -p \ -+ "Would you like to proceed with the updated configuration? [ynYN] " \ -+ ans < /dev/tty -+ [[ "${ans}" =~ ^[nN]$ ]] && exit 0 -+ [[ "${ans}" =~ ^[yY]$ ]] && break -+ done -+fi -+ -+echo "Updating binding..." -+ -+# Create new key. -+if ! new_pass=$(generate_key "${DEV}"); then -+ echo "Error generating new key for device ${DEV}" >&2 -+ exit 1 -+fi -+ -+# Reencrypt the new password. -+if ! jwe="$(clevis encrypt "${pin}" "${jcfg}" -y <<< "${new_pass}")"; then -+ echo "Error using pin '${pin}' with config '${jcfg}'" >&2 -+ exit 1 -+fi -+ -+# Backup LUKS header. -+if ! clevis_luks_backup_dev "${DEV}" "${TMP}"; then -+ echo "Error while trying to back up LUKS header from ${DEV}" >&2 -+ exit 1 -+fi -+ -+# Get passphrase. -+if ! pt="$(clevis_luks_unlock_device "${DEV}")" \ -+ || [ -z "${pt}" ]; then -+ # Unable to retrieve a passphrase from the bindings, so let's query -+ # the user. -+ read -r -s -p "Enter existing LUKS password: " pt; echo -+ # Check if the key is valid. -+ if ! clevis_luks_is_key_valid "${DEV}" "${pt}"; then -+ echo "The key provided is not valid for ${DEV}" >&2 -+ exit 1 -+ fi -+fi -+ -+# Check if we can do the update in-place, i.e., if the key we got is the one -+# for the slot we are interested in. -+in_place= -+if cryptsetup open --test-passphrase --key-slot "${SLT}" "${DEV}" \ -+ <<< "${pt}"; then -+ in_place=true -+fi -+ -+# Update the key slot with the new key. If we have the key for this slot, -+# the change happens in-place. Otherwise, we kill the slot and re-add it. -+if [ -n "${in_place}" ]; then -+ if ! cryptsetup luksChangeKey "${DEV}" --key-slot "${SLT}" \ -+ <(echo -n "${new_pass}") <<< "${pt}"; then -+ echo "Error updating LUKS passphrase in ${DEV}:${SLT}" >&2 -+ clevis_luks_restore_dev "${DEV}" "${TMP}" -+ exit 1 -+ fi -+else -+ if ! cryptsetup luksKillSlot --batch-mode "${DEV}" "${SLT}"; then -+ echo "Error wiping slot ${SLT} from ${DEV}" >&2 -+ clevis_luks_restore_dev "${DEV}" "${TMP}" -+ exit 1 -+ fi -+ -+ if ! echo -n "${new_pass}" \ -+ | cryptsetup luksAddKey --key-slot "${SLT}" \ -+ --key-file <(echo -n "${pt}") "${DEV}"; then -+ echo "Error updating LUKS passphrase in ${DEV}:${SLT}." >&2 -+ clevis_luks_restore_dev "${DEV}" "${TMP}" -+ exit 1 -+ fi -+fi -+ -+# Update the metadata. -+if ! clevis_luks_save_slot "${DEV}" "${SLT}" "${jwe}" "overwrite"; then -+ echo "Error updating metadata in ${DEV}:${SLT}" >&2 -+ clevis_luks_restore_dev "${DEV}" "${TMP}" -+ exit 1 -+fi -+ -+# Make sure we can unlock the device with this keyslot. -+if ! clevis_luks_unlock_device_by_slot "${DEV}" "${SLT}" >/dev/null \ -+ 2>/dev/null; then -+ echo "Invalid configuration detected. Reverting changes." >&2 -+ clevis_luks_restore_dev "${DEV}" "${TMP}" -+ exit 1 -+fi -+ -+echo "Binding edited successfully." -diff --git a/src/luks/clevis-luks-edit.1.adoc b/src/luks/clevis-luks-edit.1.adoc -new file mode 100644 -index 0000000..454de89 ---- /dev/null -+++ b/src/luks/clevis-luks-edit.1.adoc -@@ -0,0 +1,69 @@ -+CLEVIS-LUKS-EDIT(1) -+=================== -+:doctype: manpage -+ -+ -+== NAME -+ -+clevis-luks-edit - Edit a binding from a clevis-bound slot in a LUKS device -+ -+== SYNOPSIS -+ -+*clevis luks edit* -d DEV -s SLT [-c CONFIG] -+ -+== OVERVIEW -+ -+The *clevis luks edit* command edits clevis bindings from a LUKS device. -+For example: -+ -+ clevis luks edit -d /dev/sda1 -s 1 -+ -+== OPTIONS -+ -+* *-d* _DEV_ : -+ The LUKS device to edit clevis-bound pins -+ -+* *-s* _SLT_ : -+ The slot to use when editing the clevis binding -+ -+* *-f* : -+ Proceed with the edit operation even if the config is the same as the current one -+ -+* *-c* _CONFIG_ : -+ The updated config to use -+ -+ -+== EXAMPLES -+ -+ clevis luks list -d /dev/sda1 -+ 1: tang '{"url":"addr"}' -+ -+As we can see in the example above, */dev/sda1* has one slots bound, in this case, to a _tang_ pin. -+ -+We can edit this binding by issuing the following command: -+ -+ clevis luks edit -d /dev/sda1 -s 1 -+ -+This will open a text editor -- the one set in the $EDITOR environment variable, or _vi_, as a fallback -- with the current -+configuration of this binding to be edited. In this case, we should have the following: -+ -+ { -+ "url": "addr" -+ } -+ -+Once at the editor, we can edit the pin configuration. For _tang_, we could edit the _url_, for instance. After completing the change, -+save the file and exit. The updated configuration will be validated for JSON, and if there are no errors, you will be shown the -+updated configuration and prompted whether to proceed. -+ -+By proceeding, the binding will be updated. There may be required to provide a valid LUKS passphrase for the device. -+ -+In the second example, we will update the same device and slot, but we will be providing the updated configuration as well: -+ -+ clevis luks edit -d /dev/sda1 -s 1 -c '{"url":"new-addr-here"}' -+ -+In this case, the binding update will be done in non-interactive mode, however it also may be required to provide a valud LUKS -+passphrase for the device. -+ -+== SEE ALSO -+ -+link:clevis-luks-list.1.adoc[*clevis-luks-list*(1)], -diff --git a/src/luks/clevis-luks-regen b/src/luks/clevis-luks-regen -index 6071d85..8f32e08 100755 ---- a/src/luks/clevis-luks-regen -+++ b/src/luks/clevis-luks-regen -@@ -41,15 +41,7 @@ function usage_and_exit () { - exit "${1}" - } - --on_exit() { -- if [ ! -d "${TMP}" ] || ! rm -rf "${TMP}"; then -- echo "Delete temporary files failed!" >&2 -- echo "You need to clean up: ${TMP}" >&2 -- exit 1 -- fi --} -- --while getopts ":hfd:s:" o; do -+while getopts ":hd:s:" o; do - case "$o" in - d) DEV="$OPTARG";; - h) usage_and_exit 0;; -@@ -68,117 +60,22 @@ if [ -z "$SLT" ]; then - exit 1 - fi - --### ---------------------------------------------------------------------- --if ! pin_cfg=$(clevis luks list -d "${DEV}" -s "${SLT}" 2>/dev/null); then -- echo "Error obtaining current configuration of device ${DEV}:${SLT}" >&2 -+if ! binding="$(clevis luks list -d "${DEV}" -s "${SLT}" 2>/dev/null)" \ -+ || [ -z "${binding}" ]; then -+ echo "Error retrieving current configuration from ${DEV}:${SLT}" >&2 - exit 1 - fi - --PIN=$(echo "${pin_cfg}" | awk '{ print $2 }') --CFG=$(echo "${pin_cfg}" | awk '{ print $3 }' | tr -d "'") -+read -r _ pin cfg <<< "${binding}" - - echo "Regenerating with:" --echo "PIN: $PIN" --echo "CONFIG: $CFG" -- --trap 'echo "Ignoring CONTROL-C!"' INT TERM -- --# Get the existing key. --if ! existing_key=$(clevis luks pass -d "${DEV}" -s "${SLT}" 2>/dev/null); then -- # We failed to obtain the passphrase for the slot -- perhaps -- # it was rotated? --, so let's request user input. -- read -r -s -p "Enter existing LUKS password: " existing_key; echo --fi -- --# Check if the key is valid. --if ! cryptsetup open --test-passphrase "${DEV}" <<< "${existing_key}"; then -- exit 1 --fi -- --# Check if we can do the update in-place, i.e., if the key we got is the one --# for the slot we are interested in. --in_place= --if cryptsetup open --test-passphrase --key-slot "${SLT}" "${DEV}" \ -- <<< "${existing_key}"; then -- in_place=true --fi -- --# Create new key. --if ! new_passphrase=$(generate_key "${DEV}"); then -- echo "Error generating new key for device ${DEV}" >&2 -- exit 1 --fi -- --# Reencrypt the new password. --if ! jwe="$(clevis encrypt "${PIN}" "${CFG}" <<< "${new_passphrase}")"; then -- echo "Error using pin '${PIN}' with config '${CFG}'" >&2 -- exit 1 --fi -- --# Updating the metadata and the actual passphrase are destructive operations, --# hence we will do a backup of the LUKS header and restore it later in case --# we have issues performing these operations. --if ! TMP="$(mktemp -d)"; then -- echo "Creating a temporary dir for device backup/restore failed!" >&2 -- exit 1 --fi --trap 'on_exit' EXIT -- --# Backup LUKS header. --if ! clevis_luks_backup_dev "${DEV}" "${TMP}"; then -- echo "Error while trying to back up LUKS header from ${DEV}" >&2 -- exit 1 --fi -- --restore_device() { -- local DEV="${1}" -- local TMP="${2}" -- -- if ! clevis_luks_restore_dev "${DEV}" "${TMP}"; then -- echo "Error while trying to restore LUKS header from ${DEV}." >&2 -- else -- echo "LUKS header restored successfully." >&2 -- fi --} -- --# Update the key slot with the new key. If we have the key for this slot, --# the change happens in-place. Otherwise, we kill the slot and re-add it. --if [ -n "${in_place}" ]; then -- if ! cryptsetup luksChangeKey "${DEV}" --key-slot "${SLT}" \ -- <(echo -n "${new_passphrase}") <<< "${existing_key}"; then -- echo "Error updating LUKS passphrase in ${DEV}:${SLT}" >&2 -- restore_device "${DEV}" "${TMP}" -- exit 1 -- fi --else -- if ! cryptsetup luksKillSlot --batch-mode "${DEV}" "${SLT}"; then -- echo "Error wiping slot ${SLT} from ${DEV}" >&2 -- restore_device "${DEV}" "${TMP}" -- exit 1 -- fi -- -- if ! echo -n "${new_passphrase}" \ -- | cryptsetup luksAddKey --key-slot "${SLT}" \ -- --key-file <(echo -n "${existing_key}") "${DEV}"; then -- echo "Error updating LUKS passphrase in ${DEV}:${SLT}." >&2 -- restore_device "${DEV}" "${TMP}" -- exit 1 -- fi --fi -- --# Update the metadata. --if ! clevis_luks_save_slot "${DEV}" "${SLT}" "${jwe}" "overwrite"; then -- echo "Error updating metadata in ${DEV}:${SLT}" >&2 -- restore_device "${DEV}" "${TMP}" -- exit 1 --fi -+echo "PIN: ${pin}" -+echo "CONFIG: ${cfg}" - --# 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 -- echo "Invalid configuration detected after rebinding. Reverting changes." -- restore_device "${DEV}" "${TMP}" -+# Remove single quotes. -+cfg=${cfg//\'} -+if ! clevis luks edit -f -d "${DEV}" -s "${SLT}" -c "${cfg}" >/dev/null; then -+ echo "Error rotating keys in ${DEV}:${SLT}" >&2 - exit 1 - fi - -diff --git a/src/luks/meson.build b/src/luks/meson.build -index ee588c3..ba02bd9 100644 ---- a/src/luks/meson.build -+++ b/src/luks/meson.build -@@ -54,6 +54,9 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found() - bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-sss') - bins += join_paths(meson.current_source_dir(), 'clevis-luks-report-tang') - mans += join_paths(meson.current_source_dir(), 'clevis-luks-report.1') -+ -+ bins += join_paths(meson.current_source_dir(), 'clevis-luks-edit') -+ mans += join_paths(meson.current_source_dir(), 'clevis-luks-edit.1') - else - warning('Will not install LUKS support due to missing dependencies!') - endif -diff --git a/src/luks/tests/edit-tang-luks1 b/src/luks/tests/edit-tang-luks1 -new file mode 100755 -index 0000000..3d42d68 ---- /dev/null -+++ b/src/luks/tests/edit-tang-luks1 -@@ -0,0 +1,106 @@ -+#!/bin/bash -ex -+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2020 Red Hat, Inc. -+# Author: Sergio Correia -+# -+# 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 . -+ -+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 -+ -+# Now let's try to change the config but using the same one we already have. -+if clevis luks edit -d "${DEV}" -s 1 -c "${cfg}"; then -+ error "${TEST}: edit should not have succeeded because the config is the same." -+fi -+ -+# And now, just a broken config. -+new_cfg=$(printf '{"url&:"%s"}' "${url}") -+if clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then -+ error "${TEST}: edit should have failed because of invalid JSON" -+fi -+ -+# Now let's have another tang instance running and change the config to use -+# the new one. -+port2=$(get_random_port) -+TMP2="$(mktemp -d)" -+tang_run "${TMP2}" "${port2}" & -+tang_wait_until_ready "${port2}" -+new_url="http://${TANG_HOST}:${port2}" -+new_cfg=$(printf '{"url":"%s"}' "${new_url}") -+ -+if ! clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then -+ error "${TEST}: edit should have succeeded." -+fi -+ -+# And now let's use sss and start with a single tang server, then add a second -+# one. -+new_device "luks1" "${DEV}" -+cfg=$(printf '{"t":1,"pins":{"tang":[{"url":"%s"}]}}' "${url}") -+if ! clevis luks bind -y -d "${DEV}" sss "${cfg}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: Bind should have succeeded." -+fi -+new_cfg=$(printf '{"t":1,"pins":{"tang":[{"url":"%s"},{"url":"%s"}]}}' \ -+ "${url}" "${new_url}") -+ -+if ! clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then -+ error "${TEST}: edit should have succeeded and added a new tang server" -+fi -+ -+# Now let's change the threshold to 2. -+new_cfg=$(printf '{"t":2,"pins":{"tang":[{"url":"%s"},{"url":"%s"}]}}' \ -+ "${url}" "${new_url}") -+ -+if ! clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then -+ error "${TEST}: edit should have succeeded and added a new tang server" -+fi -+ -+# And finally, let's try a broken config, with a wrong threshold. -+new_cfg=$(printf '{"t":3,"pins":{"tang":[{"url":"%s"},{"url":"%s"}]}}' \ -+ "${url}" "${new_url}") -+if clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then -+ error "${TEST}: edit should have failed because threshold > number of servers" -+fi -diff --git a/src/luks/tests/edit-tang-luks2 b/src/luks/tests/edit-tang-luks2 -new file mode 100755 -index 0000000..9000053 ---- /dev/null -+++ b/src/luks/tests/edit-tang-luks2 -@@ -0,0 +1,106 @@ -+#!/bin/bash -ex -+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: -+# -+# Copyright (c) 2020 Red Hat, Inc. -+# Author: Sergio Correia -+# -+# 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 . -+ -+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 -+ -+# Now let's try to change the config but using the same one we already have. -+if clevis luks edit -d "${DEV}" -s 1 -c "${cfg}"; then -+ error "${TEST}: edit should not have succeeded because the config is the same." -+fi -+ -+# And now, just a broken config. -+new_cfg=$(printf '{"url&:"%s"}' "${url}") -+if clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then -+ error "${TEST}: edit should have failed because of invalid JSON" -+fi -+ -+# Now let's have another tang instance running and change the config to use -+# the new one. -+port2=$(get_random_port) -+TMP2="$(mktemp -d)" -+tang_run "${TMP2}" "${port2}" & -+tang_wait_until_ready "${port2}" -+new_url="http://${TANG_HOST}:${port2}" -+new_cfg=$(printf '{"url":"%s"}' "${new_url}") -+ -+if ! clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then -+ error "${TEST}: edit should have succeeded." -+fi -+ -+# And now let's use sss and start with a single tang server, then add a second -+# one. -+new_device "luks2" "${DEV}" -+cfg=$(printf '{"t":1,"pins":{"tang":[{"url":"%s"}]}}' "${url}") -+if ! clevis luks bind -y -d "${DEV}" sss "${cfg}" <<< "${DEFAULT_PASS}"; then -+ error "${TEST}: Bind should have succeeded." -+fi -+new_cfg=$(printf '{"t":1,"pins":{"tang":[{"url":"%s"},{"url":"%s"}]}}' \ -+ "${url}" "${new_url}") -+ -+if ! clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then -+ error "${TEST}: edit should have succeeded and added a new tang server" -+fi -+ -+# Now let's change the threshold to 2. -+new_cfg=$(printf '{"t":2,"pins":{"tang":[{"url":"%s"},{"url":"%s"}]}}' \ -+ "${url}" "${new_url}") -+ -+if ! clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then -+ error "${TEST}: edit should have succeeded and added a new tang server" -+fi -+ -+# And finally, let's try a broken config, with a wrong threshold. -+new_cfg=$(printf '{"t":3,"pins":{"tang":[{"url":"%s"},{"url":"%s"}]}}' \ -+ "${url}" "${new_url}") -+if clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then -+ error "${TEST}: edit should have failed because threshold > number of servers" -+fi -diff --git a/src/luks/tests/meson.build b/src/luks/tests/meson.build -index 4795488..67fa597 100644 ---- a/src/luks/tests/meson.build -+++ b/src/luks/tests/meson.build -@@ -4,8 +4,9 @@ actv = find_program( - required: false - ) - --# We use jq for comparing the pin config in the clevis luks list tests. --jq = find_program('jq', required: false) -+# We use jq for comparing the pin config in the clevis luks list tests -+# and also in clevis luks edit. -+jq = find_program('jq', required: true) - - # we use systemd-socket-activate for running test tang servers. - actv = find_program( -@@ -74,19 +75,16 @@ test('bind-pass-with-newline', find_program('bind-pass-with-newline-luks1'), 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 -+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) - - 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) -+ test('edit-tang-luks1', find_program('edit-tang-luks1'), env: env, timeout: 90) - endif -+ - test('pass-tang-luks1', find_program('pass-tang-luks1'), env: env) - test('backup-restore-luks1', find_program('backup-restore-luks1'), env: env) - test('regen-inplace-luks1', find_program('regen-inplace-luks1'), env: env, timeout: 90) -@@ -100,16 +98,14 @@ if luksmeta_data.get('OLD_CRYPTSETUP') == '0' - 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 -+ 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) - - 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) -+ test('edit-tang-luks2', find_program('edit-tang-luks2'), env: env, timeout: 120) - 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/luks/tests/regen-inplace-luks1 b/src/luks/tests/regen-inplace-luks1 -index 3a42ced..32072c4 100755 ---- a/src/luks/tests/regen-inplace-luks1 -+++ b/src/luks/tests/regen-inplace-luks1 -@@ -76,7 +76,7 @@ fi - old_key=$(clevis luks pass -d "${DEV}" -s "${SLT}") - - # Now let's try regen. --if ! clevis_regen "${DEV}" "${SLT}" "${DEFAULT_PASS}"; then -+if ! clevis luks regen -d "${DEV}" -s "${SLT}"; then - error "${TEST}: clevis luks regen failed" - fi - -diff --git a/src/luks/tests/regen-inplace-luks2 b/src/luks/tests/regen-inplace-luks2 -index 1cb7a29..d1bc182 100755 ---- a/src/luks/tests/regen-inplace-luks2 -+++ b/src/luks/tests/regen-inplace-luks2 -@@ -77,7 +77,7 @@ fi - old_key=$(clevis luks pass -d "${DEV}" -s "${SLT}") - - # Now let's try regen. --if ! clevis_regen "${DEV}" "${SLT}" "${DEFAULT_PASS}"; then -+if ! clevis luks regen -d "${DEV}" -s "${SLT}"; then - error "${TEST}: clevis luks regen failed" - fi - -diff --git a/src/luks/tests/regen-not-inplace-luks1 b/src/luks/tests/regen-not-inplace-luks1 -index 1b65ca7..fba61dc 100755 ---- a/src/luks/tests/regen-not-inplace-luks1 -+++ b/src/luks/tests/regen-not-inplace-luks1 -@@ -79,7 +79,7 @@ if [ "${enabled}" -ne 2 ]; then - fi - - # Now let's try regen. --if ! clevis_regen "${DEV}" "${SLT}" "${DEFAULT_PASS}"; then -+if ! clevis luks regen -d "${DEV}" -s "${SLT}" <<< "${DEFAULT_PASS}"; then - error "${TEST}: clevis luks regen failed" - fi - -diff --git a/src/luks/tests/regen-not-inplace-luks2 b/src/luks/tests/regen-not-inplace-luks2 -index dc91449..6e3b012 100755 ---- a/src/luks/tests/regen-not-inplace-luks2 -+++ b/src/luks/tests/regen-not-inplace-luks2 -@@ -80,7 +80,7 @@ if [ "${enabled}" -ne 2 ]; then - fi - - # Now let's try regen. --if ! clevis_regen "${DEV}" "${SLT}" "${DEFAULT_PASS}"; then -+if ! clevis luks regen -d "${DEV}" -s "${SLT}" <<< "${DEFAULT_PASS}"; then - error "${TEST}: clevis luks regen failed" - fi - -diff --git a/src/luks/tests/tests-common-functions.in b/src/luks/tests/tests-common-functions.in -index 6101f28..7b3fdad 100755 ---- a/src/luks/tests/tests-common-functions.in -+++ b/src/luks/tests/tests-common-functions.in -@@ -229,31 +229,5 @@ tang_get_adv() { - curl -o "${adv}" http://"${TANG_HOST}":"${port}"/adv - } - --# Regenerate binding. --clevis_regen() { -- local DEV="${1}" -- local SLT="${2}" -- local PASS="${3}" -- -- expect -d << CLEVIS_REGEN -- set timeout 120 -- spawn sh -c "clevis luks regen -d $DEV -s $SLT" -- expect { -- "Enter existing LUKS password" { -- send "$PASS\r" -- exp_continue -- } -- "Do you wish to trust these keys" { -- send "y\r" -- exp_continue -- } -- expect eof -- wait -- } --CLEVIS_REGEN -- ret=$? -- return "${ret}" --} -- - 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 -index 841ba01..6ede47b 100755 ---- a/src/luks/tests/unlock-tang-luks1 -+++ b/src/luks/tests/unlock-tang-luks1 -@@ -31,6 +31,10 @@ on_exit() { - trap 'on_exit' EXIT - trap 'on_exit' ERR - -+# LUKS1. -+DEV="${TMP}/luks1-device" -+new_device "luks1" "${DEV}" -+ - TMP="$(mktemp -d)" - - port=$(get_random_port) -@@ -43,9 +47,6 @@ 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." -diff --git a/src/luks/tests/unlock-tang-luks2 b/src/luks/tests/unlock-tang-luks2 -index 81822fb..b32c5aa 100755 ---- a/src/luks/tests/unlock-tang-luks2 -+++ b/src/luks/tests/unlock-tang-luks2 -@@ -31,6 +31,10 @@ on_exit() { - trap 'on_exit' EXIT - trap 'on_exit' ERR - -+# LUKS2. -+DEV="${TMP}/luks2-device" -+new_device "luks2" "${DEV}" -+ - TMP="$(mktemp -d)" - - port=$(get_random_port) -@@ -43,10 +47,6 @@ 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 --- -2.18.4 - diff --git a/SPECS/clevis.spec b/SPECS/clevis.spec index 63a02e4..6ad3954 100644 --- a/SPECS/clevis.spec +++ b/SPECS/clevis.spec @@ -1,25 +1,18 @@ %global _hardened_build 1 Name: clevis -Version: 13 -Release: 3%{?dist} +Version: 15 +Release: 1%{?dist} Summary: Automated decryption framework License: GPLv3+ URL: https://github.com/latchset/%{name} Source0: https://github.com/latchset/%{name}/releases/download/v%{version}/%{name}-%{version}.tar.xz -Patch0001: 0001-Adjust-pin-tang-test-to-account-for-newer-tang-witho.patch -Patch0002: 0002-Fix-clevis-luks-unlock-and-add-related-tests.patch -Patch0003: 0003-Improve-error-message-when-bind-is-given-an-invalid-.patch -Patch0004: 0004-Add-rd.neednet-1-to-cmdline-only-if-there-are-device.patch -Patch0005: 0005-Add-the-option-to-extract-luks-passphrase-used-for-b.patch -Patch0006: 0006-Add-clevis-luks-regen-command.patch -Patch0007: 0007-Add-clevis-luks-report.patch -Patch0008: 0008-Use-one-clevis-luks-askpass-per-device.patch -Patch0009: 0009-Introduce-y-assume-yes-argument-to-clevis-luks-bind.patch -Patch0010: 0010-Add-clevis-luks-edit-command.patch +Patch0001: 0001-Fixes-for-dealing-with-newer-tang-without-tangd-upda.patch +Patch0002: 0002-Add-the-option-to-extract-luks-passphrase-used-for-b.patch +BuildRequires: git BuildRequires: gcc BuildRequires: meson BuildRequires: asciidoc @@ -129,19 +122,25 @@ desktop-file-validate \ %meson_test %pre -getent group %{name} >/dev/null || groupadd -r %{name} +getent group %{name} >/dev/null || groupadd -r %{name} &>/dev/null getent passwd %{name} >/dev/null || \ useradd -r -g %{name} -d %{_localstatedir}/cache/%{name} -s /sbin/nologin \ - -c "Clevis Decryption Framework unprivileged user" %{name} + -c "Clevis Decryption Framework unprivileged user" %{name} &>/dev/null +# Add clevis user to tss group. +if getent group tss >/dev/null && ! groups %{name} | grep -q "\btss\b"; then + usermod -a -G tss %{name} &>/dev/null +fi exit 0 -%pre systemd -if [ $1 -ge 0 ]; then - # clevis-systemd < 11-8 shipped with clevis-luks-askpass.path unit. - # Make sure it's gone. - [ -e /usr/lib/systemd/system/clevis-luks-askpass.path ] && \ - systemctl disable clevis-luks-askpass.path -fi +%posttrans +# In case clevis-luks-askpass is enabled, make sure it's using the +# correct target, which changed in v14. +[ "$(find /etc/systemd/system/ -name "clevis-luks-askpass*")" ] || exit 0 +find /etc/systemd/system/ -name "clevis-luks-askpass*" \ + | grep -q cryptsetup.target.wants && exit 0 + +find /etc/systemd/system/ -name "clevis-luks-askpass*" -exec rm {} + +systemctl enable clevis-luks-askpass.path >/dev/null 2>&1 || : exit 0 %files @@ -179,16 +178,12 @@ exit 0 %{_bindir}/%{name}-luks-pass %{_bindir}/%{name}-luks-regen %{_bindir}/%{name}-luks-report -%{_bindir}/%{name}-luks-report-compare -%{_bindir}/%{name}-luks-report-decode -%{_bindir}/%{name}-luks-report-sss -%{_bindir}/%{name}-luks-report-tang %{_bindir}/%{name}-luks-edit %files systemd %{_libexecdir}/%{name}-luks-askpass -%{_unitdir}/%{name}-luks-askpass@.path -%{_unitdir}/%{name}-luks-askpass@.service +%{_unitdir}/%{name}-luks-askpass.path +%{_unitdir}/%{name}-luks-askpass.service %files dracut %{_prefix}/lib/dracut/modules.d/60%{name} @@ -201,6 +196,12 @@ exit 0 %attr(4755, root, root) %{_libexecdir}/%{name}-luks-udisks2 %changelog +* Mon Oct 26 2020 Sergio Correia - 15-1 +- Update to latest upstream release, v15 + Resolves: rhbz#1887836 + Resolves: rhbz#1853651 + Resolves: rhbz#1874460 + * Wed May 20 2020 Sergio Correia - 13-3 - Add clevis luks edit command Resolves: rhbz#1436735