From 69556d143544a72f84e9daf25924e3ae5132ce1a Mon Sep 17 00:00:00 2001 From: Sergio Correia Date: Sat, 30 Nov 2019 14:58:43 -0500 Subject: [PATCH] Add the option to extract luks passphrase used for binding 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/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(+) 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 create mode 100755 src/luks/tests/pass-tang-luks2 diff --git a/src/luks/clevis-luks-pass b/src/luks/clevis-luks-pass new file mode 100755 index 0000000..1ce8c4c --- /dev/null +++ b/src/luks/clevis-luks-pass @@ -0,0 +1,69 @@ +#!/bin/bash -e +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2019 Red Hat, Inc. +# Author: Sergio Correia - LUKS2 support. +# +# 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="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 + exit 1 +} + +if [ ${#} -eq 1 ] && [ "${1}" = "--summary" ]; then + echo "${SUMMARY}" + exit 0 +fi + +while getopts ":d:s:" o; do + case "$o" in + d) DEV=${OPTARG};; + s) SLT=${OPTARG};; + *) 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 ! 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 + exit 1 +fi diff --git a/src/luks/clevis-luks-pass.1.adoc b/src/luks/clevis-luks-pass.1.adoc new file mode 100644 index 0000000..fa9526a --- /dev/null +++ b/src/luks/clevis-luks-pass.1.adoc @@ -0,0 +1,43 @@ +CLEVIS-LUKS-PASS(1) +=================== +:doctype: manpage + + +== NAME + +clevis-luks-pass - Extracts the passphrase used for binding a particular slot in a LUKS device + +== SYNOPSIS + +*clevis luks pass* -d DEV -s SLT + +== OVERVIEW + +The *clevis luks pass* command extracts the passphrase used for binding a particular slot in a LUKS device. +For example: + + clevis luks pass -d /dev/sda1 -s 1 + +== OPTIONS + +* *-d* _DEV_ : + The LUKS device on which to extract a passphrase from + +* *-s* _SLT_ : + The slot to use for extracting the passphrase + +== EXAMPLE + + clevis luks pass -d /dev/sda1 -s 1 + + +Note that the output of *clevis luks pass* might be non-printable, in which case it would be better to redirect its output to a file and use it as a key +file together with cryptsetup. For instance: + + clevis luks pass -d /dev/sda1 -s 1 > slot1-passphrase + +And the file slot1-passphrase will contain the passphrase associated with slot #1 in /dev/sda1. + +== SEE ALSO + +link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)], diff --git a/src/luks/meson.build b/src/luks/meson.build index 51d82fb..b2dd724 100644 --- a/src/luks/meson.build +++ b/src/luks/meson.build @@ -23,6 +23,9 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found() bins += join_paths(meson.current_source_dir(), 'clevis-luks-list') mans += join_paths(meson.current_source_dir(), 'clevis-luks-list.1') + bins += join_paths(meson.current_source_dir(), 'clevis-luks-pass') + mans += join_paths(meson.current_source_dir(), 'clevis-luks-pass.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') diff --git a/src/luks/tests/meson.build b/src/luks/tests/meson.build index 6513eaa..248d2ea 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) @@ -15,8 +21,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()) if jq.found() test('list-recursive-luks1', find_program('list-recursive-luks1'), env: env) @@ -25,6 +34,7 @@ if jq.found() else warning('Will not run "clevis luks list" tests due to missing jq dependency') 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. @@ -34,3 +44,4 @@ if jq.found() 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('pass-tang-luks2', find_program('pass-tang-luks2'), env: env, timeout: 60) diff --git a/src/luks/tests/pass-tang-luks1 b/src/luks/tests/pass-tang-luks1 new file mode 100755 index 0000000..05cdb3e --- /dev/null +++ b/src/luks/tests/pass-tang-luks1 @@ -0,0 +1,75 @@ +#!/bin/bash -x +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2019 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}" + +if ! clevis luks bind -f -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then + error "${TEST}: Bind should have succeeded." +fi + +#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 + 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 --- /dev/null +++ b/src/luks/tests/pass-tang-luks2 @@ -0,0 +1,75 @@ +#!/bin/bash -x +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2019 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}" + +if ! clevis luks bind -f -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then + error "${TEST}: Bind should have succeeded." +fi + +#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 + error "Passphrase obtained from clevis luks pass failed." +fi + +kill -9 "${PID}" +! wait "${PID}" +unset PID -- 2.18.1