From a128130755bcd893ccf1d70b52c13fbaf29613c9 Mon Sep 17 00:00:00 2001 From: Sergio Correia Date: Sat, 30 Nov 2019 14:26:59 -0500 Subject: [PATCH] Add clevis luks list command Usage: clevis luks list -d DEV [-s SLT] Examples: clevis luks list -d device 1: sss '{"t":1,"pins":{"tang":[{"url":"addr1"},{"url":"addr2"}],"tpm2":[{"hash":"sha256","key":"ecc"}],"sss":{"t":1,"pins":{"tang":[{"url":"addr3"}]}}}}' 2: tang '{"url":"addr"}' 3: tpm2 '{"hash":"sha256","key":"ecc","pcr_bank":"sha1","pcr_ids":"7"}' clevis luks list -d device -s 3 3: tpm2 '{"hash":"sha256","key":"ecc","pcr_bank":"sha1","pcr_ids":"7"}' --- src/luks/clevis-luks-common-functions | 173 ++++++++++++++++++++++++++ src/luks/clevis-luks-list | 77 ++++++++++++ src/luks/clevis-luks-list.1.adoc | 58 +++++++++ src/luks/meson.build | 8 +- src/luks/tests/list-recursive-luks1 | 85 +++++++++++++ src/luks/tests/list-recursive-luks2 | 85 +++++++++++++ src/luks/tests/list-sss-tang-luks1 | 77 ++++++++++++ src/luks/tests/list-sss-tang-luks2 | 77 ++++++++++++ src/luks/tests/list-tang-luks1 | 64 ++++++++++ src/luks/tests/list-tang-luks2 | 64 ++++++++++ src/luks/tests/meson.build | 36 ++++++ src/luks/tests/tests-common-functions | 76 +++++++++++ 12 files changed, 879 insertions(+), 1 deletion(-) create mode 100755 src/luks/clevis-luks-list create mode 100644 src/luks/clevis-luks-list.1.adoc create mode 100755 src/luks/tests/list-recursive-luks1 create mode 100755 src/luks/tests/list-recursive-luks2 create mode 100755 src/luks/tests/list-sss-tang-luks1 create mode 100755 src/luks/tests/list-sss-tang-luks2 create mode 100755 src/luks/tests/list-tang-luks1 create mode 100755 src/luks/tests/list-tang-luks2 create mode 100644 src/luks/tests/meson.build create mode 100644 src/luks/tests/tests-common-functions diff --git a/src/luks/clevis-luks-common-functions b/src/luks/clevis-luks-common-functions index d676253..9ba1812 100644 --- a/src/luks/clevis-luks-common-functions +++ b/src/luks/clevis-luks-common-functions @@ -141,3 +141,176 @@ findexe() { return 1 } +# clevis_luks_used_slots() will return the list of used slots for a given LUKS +# device. +clevis_luks_used_slots() { + local DEV="${1}" + + local slots + if cryptsetup isLuks --type luks1 "${DEV}"; then + readarray -t slots < <(cryptsetup luksDump "${DEV}" \ + | sed -rn 's|^Key Slot ([0-7]): ENABLED$|\1|p') + elif cryptsetup isLuks --type luks2 "${DEV}"; then + readarray -t slots < <(cryptsetup luksDump "${DEV}" \ + | sed -rn 's|^\s+([0-9]+): luks2$|\1|p') + else + echo "${DEV} is not a supported LUKS device!" >&2 + return 1 + fi + echo "${slots[@]}" +} + +# clevis_luks_decode_jwe() will decode a given JWE. +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 '"') + jose b64 dec -i- <<< "${coded}" +} + +# clevis_luks_print_pin_config() will print the config of a given pin; i.e. +# for tang it will display the associated url address, and for tpm2, the +# properties in place, like the hash, for instance. +clevis_luks_print_pin_config() { + local P="${1}" + local decoded="${2}" + + local content + if ! content="$(jose fmt -j- -g clevis -g "${P}" -o- <<< "${decoded}")" \ + || [[ -z "${content}" ]]; then + return 1 + fi + + local pin= + case "${P}" in + tang) + local url + url="$(jose fmt -j- -g url -u- <<< "${content}")" + pin=$(printf '{"url":"%s"}' "${url}") + printf "tang '%s'" "${pin}" + ;; + tpm2) + # Valid properties for tpm2 pin are the following: + # hash, key, pcr_bank, pcr_ids, pcr_digest. + local key + local value + for key in 'hash' 'key' 'pcr_bank' 'pcr_ids' 'pcr_digest'; do + if value=$(jose fmt -j- -g "${key}" -u- <<< "${content}"); then + pin=$(printf '%s,"%s":"%s"' "${pin}" "${key}" "${value}") + fi + done + # Remove possible leading comma. + pin=${pin/#,/} + printf "tpm2 '{%s}'" "${pin}" + ;; + sss) + local threshold + threshold=$(jose fmt -j- -Og t -o- <<< "${content}") + clevis_luks_process_sss_pin "${content}" "${threshold}" + ;; + *) + printf "unknown pin '%s'" "${P}" + ;; + esac +} + +# clevis_luks_decode_pin_config() will receive a JWE and extract a pin config +# from it. +clevis_luks_decode_pin_config() { + local jwe="${1}" + + local decoded + if ! decoded=$(clevis_luks_decode_jwe "${jwe}"); then + return 1 + fi + + local P + if ! P=$(jose fmt -j- -Og clevis -g pin -u- <<< "${decoded}"); then + return 1 + fi + + clevis_luks_print_pin_config "${P}" "${decoded}" +} + +# clevis_luks_join_sss_cfg() will receive a list of configurations for a given +# pin and returns it as list, in the format PIN [cfg1, cfg2, ..., cfgN]. +clevis_luks_join_sss_cfg() { + local pin="${1}" + local cfg="${2}" + cfg=$(echo "${cfg}" | tr -d "'" | sed -e 's/^,//') + printf '"%s":[%s]' "${pin}" "${cfg}" +} + +# clevis_luks_process_sss_pin() will receive a JWE with information on the sss +# pin config, and also its associated threshold, and will extract the info. +clevis_luks_process_sss_pin() { + local jwe="${1}" + local threshold="${2}" + + local sss_tang + local sss_tpm2 + local sss + local pin_cfg + local pin + local cfg + + local coded + for coded in $(jose fmt -j- -Og jwe -Af- <<< "${jwe}"| tr -d '"'); do + if ! pin_cfg="$(clevis_luks_decode_pin_config "${coded}")"; then + continue + fi + read -r pin cfg <<< "${pin_cfg}" + case "${pin}" in + tang) + sss_tang="${sss_tang},${cfg}" + ;; + tpm2) + sss_tpm2="${sss_tpm2},${cfg}" + ;; + sss) + sss=$(echo "${cfg}" | tr -d "'") + ;; + esac + done + + cfg= + if [[ -n "${sss_tang}" ]]; then + cfg=$(clevis_luks_join_sss_cfg "tang" "${sss_tang}") + fi + + if [[ -n "${sss_tpm2}" ]]; then + cfg="${cfg},"$(clevis_luks_join_sss_cfg "tpm2" "${sss_tpm2}") + fi + + if [[ -n "${sss}" ]]; then + cfg=$(printf '%s,"sss":%s' "${cfg}" "${sss}") + fi + + # Remove possible leading comma. + cfg=${cfg/#,/} + pin=$(printf '{"t":%d,"pins":{%s}}' "${threshold}" "${cfg}") + printf "sss '%s'" "${pin}" +} + +# clevis_luks_read_pins_from_slot() will receive a given device and slot and +# will then output its associated policy configuration. +clevis_luks_read_pins_from_slot() { + local DEV="${1}" + local SLOT="${2}" + + local jwe + if ! jwe=$(clevis_luks_read_slot "${DEV}" "${SLOT}" 2>/dev/null); then + return 1 + fi + + local cfg + if ! cfg="$(clevis_luks_decode_pin_config "${jwe}")"; then + return 1 + fi + printf "%s: %s\n" "${SLOT}" "${cfg}" +} diff --git a/src/luks/clevis-luks-list b/src/luks/clevis-luks-list new file mode 100755 index 0000000..58678c4 --- /dev/null +++ b/src/luks/clevis-luks-list @@ -0,0 +1,77 @@ +#!/bin/bash -e +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2017-2019 Red Hat, Inc. +# Author: Javier Martinez Canillas +# 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="Lists pins bound to a LUKSv1 or LUKSv2 device" + +function usage() { + echo >&2 + echo "Usage: clevis luks list -d DEV [-s SLT]" >&2 + echo >&2 + echo "$SUMMARY": >&2 + echo >&2 + echo " -d DEV The LUKS device to list bound pins" >&2 + echo >&2 + echo " -s SLOT The slot number to list" >&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 cryptsetup isLuks --type luks1 "${DEV}"; then + if ! luksmeta test -d "${DEV}" 2>/dev/null; then + echo "The ${DEV} device is not valid!" >&2 + exit 1 + fi +fi + +if [ -n "${SLT}" ]; then + clevis_luks_read_pins_from_slot "${DEV}" "${SLT}" +else + if ! slots=$(clevis_luks_used_slots "${DEV}"); then + echo "No used slots detected for device ${DEV}!" >&2 + exit 1 + fi + + for s in ${slots}; do + if ! clevis_luks_read_pins_from_slot "${DEV}" "${s}"; then + continue + fi + done +fi diff --git a/src/luks/clevis-luks-list.1.adoc b/src/luks/clevis-luks-list.1.adoc new file mode 100644 index 0000000..2e84f05 --- /dev/null +++ b/src/luks/clevis-luks-list.1.adoc @@ -0,0 +1,58 @@ +CLEVIS-LUKS-LIST(1) +=================== +:doctype: manpage + + +== NAME + +clevis-luks-list - Lists pins bound to a LUKS device + +== SYNOPSIS + +*clevis luks list* -d DEV [-s SLT] + +== OVERVIEW + +The *clevis luks list* command list the pins bound to LUKS device. +For example: + + clevis luks list -d /dev/sda1 + +== OPTIONS + +* *-d* _DEV_ : + The LUKS device on which to list bound pins + +* *-s* _SLT_ : + The slot to use for listing the pin from + +== EXAMPLES + + clevis luks list -d /dev/sda1 + 1: sss '{"t":1,"pins":{"tang":[{"url":"addr1"},{"url":"addr2"}],"tpm2":[{"hash":"sha256","key":"ecc"}],"sss":{"t":1,"pins":{"tang":[{"url":"addr3"}]}}}}' + 2: tang '{"url":"addr"}' + 3: tpm2 '{"hash":"sha256","key":"ecc","pcr_bank":"sha1","pcr_ids":"7"}' + +As we can see in the example above, */dev/sda1* has three slots bound each with a different pin. +- Slot #1 is bound with the _sss_ pin, and uses also tang and tpm2 pins in its policy. +- Slot #2 is bound using the _tang_ pin +- Slot #3 is bound with the _tpm2_ pin + +Note that the output of *clevis luks list* can be used with the *clevis luks bind* command, such as: + + clevis luks bind -d /dev/sda1 tpm2 '{"hash":"sha256","key":"ecc","pcr_bank":"sha1","pcr_ids":"7"}' + +And we will bind another slot with a policy similar to the one we have in slot #3. +Also note that if you are interested in a particular slot, you can pass the _-s SLT_ argument to *clevis luks list*: + + clevis luks list -d /dev/sda1 -s 2 + 2: tang '{"url":"addr"}' + +In the above example, we listed only the pin bound to slot #2. + +== SEE ALSO + +link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)], +link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)], +link:clevis-encrypt-tpm2.1.adoc[*clevis-encrypt-tpm2*(1)], +link:clevis-encrypt-sss.1.adoc[*clevis-encrypt-sss*(1)], diff --git a/src/luks/meson.build b/src/luks/meson.build index 7c045c4..51d82fb 100644 --- a/src/luks/meson.build +++ b/src/luks/meson.build @@ -20,6 +20,9 @@ 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-list') + mans += join_paths(meson.current_source_dir(), 'clevis-luks-list.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') @@ -30,4 +33,7 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found() mans += join_paths(meson.current_source_dir(), 'clevis-luks-unlockers.7') else warning('Will not install LUKS support due to missing dependencies!') -endif \ No newline at end of file +endif + +# Tests. +subdir('tests') diff --git a/src/luks/tests/list-recursive-luks1 b/src/luks/tests/list-recursive-luks1 new file mode 100755 index 0000000..d9eaa3a --- /dev/null +++ b/src/luks/tests/list-recursive-luks1 @@ -0,0 +1,85 @@ +#!/bin/bash -ex +# 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=$(basename "${0}") +. tests-common-functions + +on_exit() { + [ -d "${TMP}" ] && rm -rf "${TMP}" +} + +trap 'on_exit' EXIT +trap 'exit' ERR + +TMP="$(mktemp -d)" + +ADV="${TMP}/adv.jws" +create_tang_adv "${ADV}" +PIN="sss" +CFG=$(printf ' +{ + "t": 1, + "pins": { + "sss": { + "t": 1, + "pins": { + "sss": { + "t": 1, + "pins": { + "tang": [ + { + "url": "ADDR","adv": "%s" + } + ] + } + } + } + } + } +} +' "${ADV}") + +# LUKS1. +DEV="${TMP}/luks1-device" +UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e" +new_device "luks1" "${DEV}" + +if ! clevis luks bind -f -d "${DEV}" "${PIN}" "${CFG}" <<< "${DEFAULT_PASS}"; then + error "${TEST}: Binding is expected to succeed when given a correct (${DEFAULT_PASS}) password." +fi + +SLT=1 +if ! read -r slot pin cfg < <(clevis luks list -d "${DEV}" -s "${SLT}"); then + error "${TEST}: clevis luks list is expected to succeed for device(${DEV}) and slot (${SLT})" +fi + +if [[ "${slot}" != "${SLT}:" ]]; then + error "${TEST}: slot (${slot}) is expected to be ${SLT}" +fi + +if [[ "${pin}" != "${PIN}" ]]; then + error "${TEST}: pin (${pin}) is expected to be '${PIN}'" +fi + +to_remove_from_cfg=$(printf ',"adv": "%s"' "${ADV}") +cfg_for_cmp=${cfg//"${to_remove_from_cfg}"/} +if ! pin_cfg_equal "${cfg}" "${cfg_for_cmp}"; then + error "${TEST}: config obtained from clevis luks list (${cfg}) is expected to match the one used to bind the test (${cfg_for_cmp})" +fi diff --git a/src/luks/tests/list-recursive-luks2 b/src/luks/tests/list-recursive-luks2 new file mode 100755 index 0000000..80a8278 --- /dev/null +++ b/src/luks/tests/list-recursive-luks2 @@ -0,0 +1,85 @@ +#!/bin/bash -ex +# 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=$(basename "${0}") +. tests-common-functions + +on_exit() { + [ -d "${TMP}" ] && rm -rf "${TMP}" +} + +trap 'on_exit' EXIT +trap 'exit' ERR + +TMP="$(mktemp -d)" + +ADV="${TMP}/adv.jws" +create_tang_adv "${ADV}" +PIN="sss" +CFG=$(printf ' +{ + "t": 1, + "pins": { + "sss": { + "t": 1, + "pins": { + "sss": { + "t": 1, + "pins": { + "tang": [ + { + "url": "ADDR","adv": "%s" + } + ] + } + } + } + } + } +} +' "${ADV}") + +# LUKS2. +DEV="${TMP}/luks1-device" +UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e" +new_device "luks2" "${DEV}" + +if ! clevis luks bind -f -d "${DEV}" "${PIN}" "${CFG}" <<< "${DEFAULT_PASS}"; then + error "${TEST}: Binding is expected to succeed when given a correct (${DEFAULT_PASS}) password." +fi + +SLT=1 +if ! read -r slot pin cfg < <(clevis luks list -d "${DEV}" -s "${SLT}"); then + error "${TEST}: clevis luks list is expected to succeed for device(${DEV}) and slot (${SLT})" +fi + +if [[ "${slot}" != "${SLT}:" ]]; then + error "${TEST}: slot (${slot}) is expected to be ${SLT}" +fi + +if [[ "${pin}" != "${PIN}" ]]; then + error "${TEST}: pin (${pin}) is expected to be '${PIN}'" +fi + +to_remove_from_cfg=$(printf ',"adv": "%s"' "${ADV}") +cfg_for_cmp=${cfg//"${to_remove_from_cfg}"/} +if ! pin_cfg_equal "${cfg}" "${cfg_for_cmp}"; then + error "${TEST}: config obtained from clevis luks list (${cfg}) is expected to match the one used to bind the test (${cfg_for_cmp})" +fi diff --git a/src/luks/tests/list-sss-tang-luks1 b/src/luks/tests/list-sss-tang-luks1 new file mode 100755 index 0000000..086fa35 --- /dev/null +++ b/src/luks/tests/list-sss-tang-luks1 @@ -0,0 +1,77 @@ +#!/bin/bash -ex +# 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=$(basename "${0}") +. tests-common-functions + +on_exit() { + [ -d "${TMP}" ] && rm -rf "${TMP}" +} + +trap 'on_exit' EXIT +trap 'exit' ERR + +TMP="$(mktemp -d)" + +ADV="${TMP}/adv.jws" +create_tang_adv "${ADV}" +PIN="sss" +CFG=$(printf ' +{ + "t": 2, + "pins": { + "tang": [ + {"url":"ADDR1","adv":"%s"}, + {"url":"ADDR2","adv":"%s"}, + {"url":"ADDR3","adv":"%s"}, + {"url":"ADDR4","adv":"%s"}, + {"url":"ADDR5","adv":"%s"} + ] + } +} +' "${ADV}" "${ADV}" "${ADV}" "${ADV}" "${ADV}") + +# LUKS1. +DEV="${TMP}/luks1-device" +UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e" +new_device "luks1" "${DEV}" + +if ! clevis luks bind -f -d "${DEV}" ${PIN} "${CFG}" <<< "${DEFAULT_PASS}"; then + error "${TEST}: Binding is expected to succeed when given a correct (${DEFAULT_PASS}) password." +fi + +SLT=1 +if ! read -r slot pin cfg < <(clevis luks list -d "${DEV}" -s "${SLT}"); then + error "${TEST}: clevis luks list is expected to succeed for device(${DEV}) and slot (${SLT})" +fi + +if [[ "${slot}" != "${SLT}:" ]]; then + error "${TEST}: slot (${slot}) is expected to be ${SLT}" +fi + +if [[ "${pin}" != "${PIN}" ]]; then + error "${TEST}: pin (${pin}) is expected to be '${PIN}'" +fi + +to_remove_from_cfg=$(printf ',"adv": "%s"' "${ADV}") +cfg_for_cmp=${cfg//"${to_remove_from_cfg}"/} +if ! pin_cfg_equal "${cfg}" "${cfg_for_cmp}"; then + error "${TEST}: config obtained from clevis luks list (${cfg}) is expected to match the one used to bind the test (${cfg_for_cmp})" +fi diff --git a/src/luks/tests/list-sss-tang-luks2 b/src/luks/tests/list-sss-tang-luks2 new file mode 100755 index 0000000..ea4cfbb --- /dev/null +++ b/src/luks/tests/list-sss-tang-luks2 @@ -0,0 +1,77 @@ +#!/bin/bash -ex +# 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=$(basename "${0}") +. tests-common-functions + +on_exit() { + [ -d "${TMP}" ] && rm -rf "${TMP}" +} + +trap 'on_exit' EXIT +trap 'exit' ERR + +TMP="$(mktemp -d)" + +ADV="${TMP}/adv.jws" +create_tang_adv "${ADV}" +PIN="sss" +CFG=$(printf ' +{ + "t": 2, + "pins": { + "tang": [ + {"url":"ADDR1","adv":"%s"}, + {"url":"ADDR2","adv":"%s"}, + {"url":"ADDR3","adv":"%s"}, + {"url":"ADDR4","adv":"%s"}, + {"url":"ADDR5","adv":"%s"} + ] + } +} +' "${ADV}" "${ADV}" "${ADV}" "${ADV}" "${ADV}") + +# LUKS2. +DEV="${TMP}/luks1-device" +UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e" +new_device "luks2" "${DEV}" + +if ! clevis luks bind -f -d "${DEV}" ${PIN} "${CFG}" <<< "${DEFAULT_PASS}"; then + error "${TEST}: Binding is expected to succeed when given a correct (${DEFAULT_PASS}) password." +fi + +SLT=1 +if ! read -r slot pin cfg < <(clevis luks list -d "${DEV}" -s "${SLT}"); then + error "${TEST}: clevis luks list is expected to succeed for device(${DEV}) and slot (${SLT})" +fi + +if [[ "${slot}" != "${SLT}:" ]]; then + error "${TEST}: slot (${slot}) is expected to be ${SLT}" +fi + +if [[ "${pin}" != "${PIN}" ]]; then + error "${TEST}: pin (${pin}) is expected to be '${PIN}'" +fi + +to_remove_from_cfg=$(printf ',"adv": "%s"' "${ADV}") +cfg_for_cmp=${cfg//"${to_remove_from_cfg}"/} +if ! pin_cfg_equal "${cfg}" "${cfg_for_cmp}"; then + error "${TEST}: config obtained from clevis luks list (${cfg}) is expected to match the one used to bind the test (${cfg_for_cmp})" +fi diff --git a/src/luks/tests/list-tang-luks1 b/src/luks/tests/list-tang-luks1 new file mode 100755 index 0000000..c526693 --- /dev/null +++ b/src/luks/tests/list-tang-luks1 @@ -0,0 +1,64 @@ +#!/bin/bash -ex +# 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=$(basename "${0}") +. tests-common-functions + +on_exit() { + [ -d "${TMP}" ] && rm -rf "${TMP}" +} + +trap 'on_exit' EXIT +trap 'exit' ERR + +TMP="$(mktemp -d)" + +ADV="${TMP}/adv.jws" +create_tang_adv "${ADV}" +PIN="tang" +CFG=$(printf '{"url": "ADDR","adv": "%s"}' "${ADV}") + +# LUKS1. +DEV="${TMP}/luks1-device" +UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e" +new_device "luks1" "${DEV}" + +if ! clevis luks bind -f -d "${DEV}" "${PIN}" "${CFG}" <<< "${DEFAULT_PASS}"; then + error "${TEST}: Binding is expected to succeed when given a correct (${DEFAULT_PASS}) password." +fi + +SLT=1 +if ! read -r slot pin cfg < <(clevis luks list -d "${DEV}" -s "${SLT}"); then + error "${TEST}: clevis luks list is expected to succeed for device(${DEV}) and slot (${SLT})" +fi + +if [[ "${slot}" != "${SLT}:" ]]; then + error "${TEST}: slot (${slot}) is expected to be ${SLT}" +fi + +if [[ "${pin}" != "${PIN}" ]]; then + error "${TEST}: pin (${pin}) is expected to be '${PIN}'" +fi + +to_remove_from_cfg=$(printf ',"adv": "%s"' "${ADV}") +cfg_for_cmp=${cfg//"${to_remove_from_cfg}"/} +if ! pin_cfg_equal "${cfg}" "${cfg_for_cmp}"; then + error "${TEST}: config obtained from clevis luks list (${cfg}) is expected to match the one used to bind the test (${cfg_for_cmp})" +fi diff --git a/src/luks/tests/list-tang-luks2 b/src/luks/tests/list-tang-luks2 new file mode 100755 index 0000000..d4d4849 --- /dev/null +++ b/src/luks/tests/list-tang-luks2 @@ -0,0 +1,64 @@ +#!/bin/bash -ex +# 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=$(basename "${0}") +. tests-common-functions + +on_exit() { + [ -d "${TMP}" ] && rm -rf "${TMP}" +} + +trap 'on_exit' EXIT +trap 'exit' ERR + +TMP="$(mktemp -d)" + +ADV="${TMP}/adv.jws" +create_tang_adv "${ADV}" +PIN="tang" +CFG=$(printf '{"url": "ADDR","adv": "%s"}' "${ADV}") + +# LUKS2. +DEV="${TMP}/luks1-device" +UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e" +new_device "luks2" "${DEV}" + +if ! clevis luks bind -f -d "${DEV}" "${PIN}" "${CFG}" <<< "${DEFAULT_PASS}"; then + error "${TEST}: Binding is expected to succeed when given a correct (${DEFAULT_PASS}) password." +fi + +SLT=1 +if ! read -r slot pin cfg < <(clevis luks list -d "${DEV}" -s "${SLT}"); then + error "${TEST}: clevis luks list is expected to succeed for device(${DEV}) and slot (${SLT})" +fi + +if [[ "${slot}" != "${SLT}:" ]]; then + error "${TEST}: slot (${slot}) is expected to be ${SLT}" +fi + +if [[ "${pin}" != "${PIN}" ]]; then + error "${TEST}: pin (${pin}) is expected to be '${PIN}'" +fi + +to_remove_from_cfg=$(printf ',"adv": "%s"' "${ADV}") +cfg_for_cmp=${cfg//"${to_remove_from_cfg}"/} +if ! pin_cfg_equal "${cfg}" "${cfg_for_cmp}"; then + error "${TEST}: config obtained from clevis luks list (${cfg}) is expected to match the one used to bind the test (${cfg_for_cmp})" +fi diff --git a/src/luks/tests/meson.build b/src/luks/tests/meson.build new file mode 100644 index 0000000..6513eaa --- /dev/null +++ b/src/luks/tests/meson.build @@ -0,0 +1,36 @@ +# We use jq for comparing the pin config in the clevis luks list tests. +jq = find_program('jq', required: 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'), + separator: ':' +) + +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 + +# 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 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 diff --git a/src/luks/tests/tests-common-functions b/src/luks/tests/tests-common-functions new file mode 100644 index 0000000..b65a84a --- /dev/null +++ b/src/luks/tests/tests-common-functions @@ -0,0 +1,76 @@ +#!/bin/bash -ex +# 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 . +# + +# We require cryptsetup >= 2.0.4 to fully support LUKSv2. +# Support is determined at build time. +luks2_supported() { + # In RHEL8 we support LUKS2. + return 0 +} + +# Creates a tang adv to be used in the test. +create_tang_adv() { + local adv="${1}" + local SIG="${TMP}/sig.jwk" + jose jwk gen -i '{"alg":"ES512"}' > "${SIG}" + + local EXC="${TMP}/exc.jwk" + jose jwk gen -i '{"alg":"ECMR"}' > "${EXC}" + + local TEMPLATE='{"protected":{"cty":"jwk-set+json"}}' + jose jwk pub -s -i "${SIG}" -i "${EXC}" \ + | jose jws sig -I- -s "${TEMPLATE}" -k "${SIG}" -o "${adv}" +} + + +# Creates a new LUKS1 or LUKS2 device to be used. +new_device() { + local LUKS="${1}" + local DEV="${2}" + + local DEV_CACHED="${TMP}/${LUKS}.cached" + + # Let's reuse an existing device, if there is one. + if [ -f "${DEV_CACHED}" ]; then + echo "Reusing cached ${LUKS} device..." + cp -f "${DEV_CACHED}" "${DEV}" + return 0 + fi + + fallocate -l16M "${DEV}" + cryptsetup luksFormat --type "${LUKS}" --batch-mode --force-password "${DEV}" <<< "${DEFAULT_PASS}" + # Caching the just-formatted device for possible reuse. + cp -f "${DEV}" "${DEV_CACHED}" +} + +error() { + echo "${1}" >&2 + exit 1 +} + +pin_cfg_equal() { + local cfg1="${1}" + local cfg2="${1}" + + diff <(jq -S . < <(echo -n "${cfg1}")) \ + <(jq -S . < <(echo -n "${cfg2}")) +} + +export DEFAULT_PASS='just-some-test-password-here' -- 2.18.1