diff --git a/.clevis.metadata b/.clevis.metadata
new file mode 100644
index 0000000..4602876
--- /dev/null
+++ b/.clevis.metadata
@@ -0,0 +1 @@
+086374814a4d71db8625d27a1719e03244a7cff0 SOURCES/clevis-11.tar.xz
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f017bbb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/clevis-11.tar.xz
diff --git a/SOURCES/Add-clevis-luks-report-regen.patch b/SOURCES/Add-clevis-luks-report-regen.patch
new file mode 100644
index 0000000..274e651
--- /dev/null
+++ b/SOURCES/Add-clevis-luks-report-regen.patch
@@ -0,0 +1,858 @@
+From 70d3da5ce8d68e8ff258122592670eb70da0c839 Mon Sep 17 00:00:00 2001
+From: Sergio Correia <scorreia@redhat.com>
+Date: Wed, 16 Oct 2019 09:14:58 -0300
+Subject: [PATCH 2/2] Add clevis luks report/regen
+
+---
+ src/luks/clevis-luks-common-functions | 143 ++++++++++++++++++++
+ src/luks/clevis-luks-regen            | 186 ++++++++++++++++++++++++++
+ src/luks/clevis-luks-regen.1.adoc     |  36 +++++
+ 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                  |  12 ++
+ 10 files changed, 763 insertions(+)
+ create mode 100644 src/luks/clevis-luks-common-functions
+ create mode 100755 src/luks/clevis-luks-regen
+ create mode 100644 src/luks/clevis-luks-regen.1.adoc
+ create mode 100755 src/luks/clevis-luks-report
+ create mode 100755 src/luks/clevis-luks-report-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-common-functions b/src/luks/clevis-luks-common-functions
+new file mode 100644
+index 0000000..d676253
+--- /dev/null
++++ b/src/luks/clevis-luks-common-functions
+@@ -0,0 +1,143 @@
++#!/bin/bash -e
++# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
++#
++# Copyright (c) 2019 Red Hat, Inc.
++# Author: Sergio Correia <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++# valid_slot() will check whether a given slot is possibly valid, i.e., if it
++# is a numeric value within the specified range.
++valid_slot() {
++    local SLT="${1}"
++    local MAX_SLOTS="${2}"
++    case "${SLT}" in
++        ''|*[!0-9]*)
++            return 1
++            ;;
++        *)
++            # We got an integer, now let's make sure it is within the
++            # supported range.
++            if [ "${SLT}" -ge "${MAX_SLOTS}" ]; then
++                return 1
++            fi
++            ;;
++    esac
++}
++
++# clevis_luks_read_slot() will read a particular slot of a given device, which
++# should be either LUKS1 or LUKS2. Returns 1 in case of failure; 0 in case of
++# success.
++clevis_luks_read_slot() {
++    local DEV="${1}"
++    local SLT="${2}"
++
++    if [ -z "${DEV}" ] || [ -z "${SLT}" ]; then
++        echo "Need both a device and a slot as arguments." >&2
++        return 1
++    fi
++
++    local DATA_CODED=''
++    local MAX_LUKS1_SLOTS=8
++    local MAX_LUKS2_SLOTS=32
++    if cryptsetup isLuks --type luks1 "${DEV}"; then
++        if ! valid_slot "${SLT}" "${MAX_LUKS1_SLOTS}"; then
++            echo "Please, provide a valid key slot number; 0-7 for LUKS1" >&2
++            return 1
++        fi
++
++        if ! luksmeta test -d "${DEV}"; then
++            echo "The ${DEV} device is not valid!" >&2
++            return 1
++        fi
++
++        local uuid
++        # Pattern from luksmeta: active slot uuid.
++        read -r _ _ uuid <<< "$(luksmeta show -d "${DEV}" | grep "^${SLT} *")"
++
++        if [ "${uuid}" = "empty" ]; then
++           echo "The LUKSMeta slot ${SLT} on device ${DEV} is already empty." >&2
++           return 1
++        fi
++
++        if ! DATA_CODED="$(luksmeta load -d "${DEV}" -s "${SLT}")"; then
++            echo "Cannot load data from ${DEV} slot:${SLT}!" >&2
++            return 1
++        fi
++    elif cryptsetup isLuks --type luks2 "${DEV}"; then
++        if ! valid_slot "${SLT}" "${MAX_LUKS2_SLOTS}"; then
++            echo "Please, provide a valid key slot number; 0-31 for LUKS2" >&2
++            return 1
++        fi
++
++        local token_id
++        token_id=$(cryptsetup luksDump "${DEV}" \
++                    | grep -E -B1 "^\s+Keyslot:\s+${SLT}$" \
++                    | head -n 1 | sed -rn 's|^\s+([0-9]+): clevis|\1|p')
++        if [ -z "${token_id}" ]; then
++            echo "Cannot load data from ${DEV} slot:${SLT}. No token found!" >&2
++            return 1
++        fi
++
++        local token
++        token=$(cryptsetup token export --token-id "${token_id}" "${DEV}")
++        DATA_CODED=$(jose fmt -j- -Og jwe -o- <<< "${token}" \
++                     | jose jwe fmt -i- -c)
++
++        if [ -z "${DATA_CODED}" ]; then
++            echo "Cannot load data from ${DEV} slot:${SLT}!" >&2
++            return 1
++        fi
++    else
++        echo "${DEV} is not a supported LUKS device!" >&2
++        return 1
++    fi
++    echo "${DATA_CODED}"
++}
++
++# Generate a key with the same entropy as the LUKS Master key of a given
++# device.
++generate_key() {
++    local DEV="${1}"
++
++    if [ -z "${DEV}" ]; then
++        echo "Please, specify a device." >&2
++        return 1
++    fi
++
++    local dump
++    local filter
++    dump=$(cryptsetup luksDump "${DEV}")
++    if cryptsetup isLuks --type luks1 "${DEV}"; then
++        filter=$(sed -rn 's|MK bits:[ \t]*([0-9]+)|\1|p' <<< "${dump}")
++    elif cryptsetup isLuks --type luks2 "${DEV}"; then
++        filter=$(sed -rn 's|^\s+Key:\s+([0-9]+) bits\s*$|\1|p' <<< "${dump}")
++    else
++        echo "${DEV} is not a supported LUKS device!" >&2
++        return 1
++    fi
++    local bits
++    bits=$(sort -n <<< "${filter}" | tail -n 1)
++    pwmake "${bits}"
++}
++
++findexe() {
++    while read -r -d: path; do
++        [ -f "${path}/${1}" ] && [ -x "${path}/${1}" ] && \
++          echo "${path}/${1}" && return 0
++    done <<< "${PATH}:"
++    return 1
++}
++
+diff --git a/src/luks/clevis-luks-regen b/src/luks/clevis-luks-regen
+new file mode 100755
+index 0000000..9535ba3
+--- /dev/null
++++ b/src/luks/clevis-luks-regen
+@@ -0,0 +1,186 @@
++#!/usr/bin/env bash
++# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
++#
++# Copyright (c) 2018 Red Hat, Inc.
++# Author: Radovan Sroka <rsroka@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++. clevis-luks-common-functions
++
++SUMMARY="Regenerate LUKS metadata"
++
++if [ "$1" == "--summary" ]; then
++    echo "$SUMMARY"
++    exit 0
++fi
++
++function usage_and_exit () {
++    echo >&2
++    echo "Usage: clevis luks regen -d DEV -s SLOT" >&2
++    echo >&2
++    echo "$SUMMARY" >&2
++    echo >&2
++    exit "$1"
++}
++
++if [ "$#" -ne "4" ]; then
++    usage_and_exit 1
++fi
++
++while getopts "hd:s:" o; do
++    case "$o" in
++    d) DEV="$OPTARG";;
++    h) usage_and_exit 0;;
++    s) SLT="$OPTARG";;
++    *) usage_and_exit 1;;
++    esac
++done
++
++function decode_luks_header () {
++    if DATA_CODED="$(jose jwe fmt -i- <<< "$1")"; then
++        DATA_CODED="$(jose fmt -j- -g protected -u- <<< "$DATA_CODED")"
++        DATA_DECODED="$(jose b64 dec -i- <<< "$DATA_CODED")"
++    else
++        echo "Error decoding JWE protected header!" >&2
++        exit 1
++    fi
++
++    echo "$DATA_DECODED"
++}
++
++function generate_cfg () {
++    echo -n "{"
++    DATA="$(decode_luks_header "$1")"
++
++    if ! P="$(jose fmt -j- -g clevis -g pin -u- <<< "$DATA")" || [ -z "$P" ]; then
++        echo "Pin wasn't found in LUKS metadata!" >&2
++        exit 1
++    fi
++
++    if ! CONTENT="$(jose fmt -j- -g clevis -g "$P" -o- <<< "$DATA")" || [ -z "$CONTENT" ]; then
++        echo "Content was not found!" >&2
++    fi
++
++    # echo -n "\"$P\": ["
++
++    if [ "$P" = "tang" ] || [ "$P" = "http" ]; then
++        URL="$(jose fmt -j- -g url -u- <<< "$CONTENT")"
++        echo -n "\"url\":\"$URL\""
++    elif [ "$P" = "sss" ]; then
++        THRESHOLD="$(jose fmt -j- -g t -o- <<< "$CONTENT")"
++        if [ -n "$THRESHOLD" ]; then
++            echo -n "\"t\":$THRESHOLD,"
++        fi
++
++        echo -n "\"pins\":{"
++
++        CNT=0
++        PREV=""
++        while ITEM="$(jose fmt -j- -g jwe -g"$CNT" -u- <<< "$CONTENT")"; do
++            if [ -z "$ITEM" ]; then
++                CNT=$(( CNT + 1 ))
++                continue # in some cases it can be empty string
++            fi
++
++            DD="$(decode_luks_header "$ITEM")"
++
++            if ! PP="$(jose fmt -j- -g clevis -g pin -u- <<< "$DD")" || [ -z "$PP" ]; then
++                echo "Pin wasn't found in LUKS metadata!" >&2
++                exit 1
++            fi
++
++            if [ "$CNT" -eq 0 ]; then
++                PREV="$PP"
++                echo -n "\"$PP\":["
++                echo -n "$(generate_cfg "$ITEM")"
++            else
++                if ! [ "$PREV" = "$PP" ]; then
++                    echo -n "],\"$PP\":["
++                    echo -n "$(generate_cfg "$ITEM")"
++                else
++                    echo -n ",$(generate_cfg "$ITEM")"
++                fi
++            fi
++
++            PREV="$PP"
++            CNT=$(( CNT + 1 ))
++        done
++
++        echo -n "]}"
++
++    else
++        echo "Unknown pin $P!" >&2
++        exit 1
++    fi
++
++    echo -n "}"
++}
++
++### get luks metadata
++
++if [ -z "$DEV" ]; then
++    echo "Did not specify a device!" >&2
++    exit 1
++fi
++
++if [ -z "$SLT" ]; then
++    echo "Did not specify a slot!" >&2
++    exit 1
++fi
++
++if ! OLD_LUKS_CODED="$(clevis_luks_read_slot "$DEV" "$SLT")"; then
++    echo "Error reading metadata from LUKS device!" >&2
++    exit 1
++fi
++
++### ----------------------------------------------------------------------
++
++DECODED="$(decode_luks_header "$OLD_LUKS_CODED")"
++
++if ! PIN="$(jose fmt -j- -g clevis -g pin -u- <<< "$DECODED")" || [ -z "$PIN" ]; then
++    echo "Pin wasn't found in LUKS metadata!" >&2
++    exit 1
++fi
++
++CFG="$(generate_cfg "$OLD_LUKS_CODED")"
++
++### ----------------------------------------------------------------------
++
++echo "Regenerating with:"
++echo "PIN: $PIN"
++echo "CONFIG: $CFG"
++
++trap 'echo "Ignoring CONTROL-C!"' INT TERM
++
++# Get the existing key.
++read -r -s -p "Enter existing LUKS password: " existing_key; echo
++
++# Check if the key is valid.
++if ! cryptsetup luksOpen --test-passphrase "${DEV}" <<< "${existing_key}"; then
++    exit 1
++fi
++
++if ! clevis luks unbind -d "${DEV}" -s "${SLT}" -f; then
++    echo "Error during unbind of rotated key from slot:$SLT in $DEV" >&2
++    exit 1
++fi
++
++if ! clevis luks bind -d "${DEV}" -s "${SLT}" "${PIN}" "${CFG}" -k - <<< "${existing_key}"; then
++    echo "Error during bind of new key from slot:$SLT in $DEV" >&2
++    exit 1
++fi
++
++echo "Keys were succesfully rotated."
+diff --git a/src/luks/clevis-luks-regen.1.adoc b/src/luks/clevis-luks-regen.1.adoc
+new file mode 100644
+index 0000000..3cd6b7c
+--- /dev/null
++++ b/src/luks/clevis-luks-regen.1.adoc
+@@ -0,0 +1,36 @@
++CLEVIS-LUKS-REGEN(1)
++=====================
++:doctype: manpage
++
++
++== NAME
++
++clevis-luks-regen - Regenerates LUKS metadata
++
++== SYNOPSIS
++
++*clevis luks regen* -d DEV -s SLT
++
++== OVERVIEW
++
++The *clevis luks regen* command regenerates the LUKS metadata for a given slot in a LUKS device. It effectively
++performs an operation equivalent to *clevis luks unbind* and *clevis luks bind* for rebinding said slot and device.
++
++== OPTIONS
++
++* *-d* _DEV_ :
++  The bound LUKS device
++
++* *-s* _SLT_ :
++  The slot or key slot number for rebinding. Note that it requires that such slot is currently bound by clevis.
++
++== EXAMPLE
++
++    Regenerate the binding of slot 1 from /dev/sda1:
++
++    # clevis luks regen -d /dev/sda1 -s 1
++
++== SEE ALSO
++
++link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)]
++link:clevis-luks-unbind.1.adoc[*clevis-luks-unbind*(1)]
+diff --git a/src/luks/clevis-luks-report b/src/luks/clevis-luks-report
+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 <rsroka@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++. clevis-luks-common-functions
++
++SUMMARY="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 <rsroka@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++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 <rsroka@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++. clevis-luks-common-functions
++
++SUMMARY="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 <rsroka@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++. clevis-luks-common-functions
++
++SUMMARY="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 <rsroka@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++. clevis-luks-common-functions
++
++SUMMARY="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 1f64ab0..7c045c4 100644
+--- a/src/luks/meson.build
++++ b/src/luks/meson.build
+@@ -15,6 +15,18 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found()
+   bins += join_paths(meson.current_source_dir(), 'clevis-luks-bind')
+   mans += join_paths(meson.current_source_dir(), 'clevis-luks-bind.1')
+ 
++  bins += join_paths(meson.current_source_dir(), 'clevis-luks-common-functions')
++
++  bins += join_paths(meson.current_source_dir(), 'clevis-luks-regen')
++  mans += join_paths(meson.current_source_dir(), 'clevis-luks-regen.1')
++
++  bins += join_paths(meson.current_source_dir(), 'clevis-luks-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')
++
+   mans += join_paths(meson.current_source_dir(), 'clevis-luks-unlockers.7')
+ else
+   warning('Will not install LUKS support due to missing dependencies!')
+-- 
+2.21.0
+
diff --git a/SOURCES/Add-device-TCTI-library-to-the-initramfs.patch b/SOURCES/Add-device-TCTI-library-to-the-initramfs.patch
new file mode 100644
index 0000000..6757e60
--- /dev/null
+++ b/SOURCES/Add-device-TCTI-library-to-the-initramfs.patch
@@ -0,0 +1,34 @@
+From 6826e5d31d6323eac5137404f0194bf2183b561c Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 7 Nov 2018 16:48:47 +0100
+Subject: [PATCH 3/3] Add device TCTI library to the initramfs
+
+The tpm2-tools don't dynamically link against the TCTI libraries anymore,
+but instead dlopen() the correct library depending on the TCTI used.
+
+So dracut isn't able anymore to figure out automatically using ldd what
+libraries are needed by the tpm2-tools. Since clevis uses the device TCTI
+to access the TPM directly, add the libtss2-tcti-device.so to the initrd.
+
+Suggested-by: Federico Chiacchiaretta <federico.chia@gmail.com>
+
+Fixes: ##74
+---
+ src/luks/systemd/dracut/module-setup.sh.in | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/luks/systemd/dracut/module-setup.sh.in b/src/luks/systemd/dracut/module-setup.sh.in
+index 41e7d6c9b002..990bf4aeed56 100755
+--- a/src/luks/systemd/dracut/module-setup.sh.in
++++ b/src/luks/systemd/dracut/module-setup.sh.in
+@@ -65,6 +65,7 @@ install() {
+ 	    tpm2_pcrlist \
+ 	    tpm2_unseal \
+ 	    tpm2_load
++	inst_libdir_file "libtss2-tcti-device.so*"
+     fi
+ 
+     dracut_need_initqueue
+-- 
+2.19.1
+
diff --git a/SOURCES/Add-rd.neednet-1-to-cmdline-only-if-there-are-device.patch b/SOURCES/Add-rd.neednet-1-to-cmdline-only-if-there-are-device.patch
new file mode 100644
index 0000000..a73b797
--- /dev/null
+++ b/SOURCES/Add-rd.neednet-1-to-cmdline-only-if-there-are-device.patch
@@ -0,0 +1,57 @@
+From 25009adea66d3bf9b73f128273de28e532b03281 Mon Sep 17 00:00:00 2001
+From: Sergio Correia <scorreia@redhat.com>
+Date: Sat, 30 Nov 2019 18:23:09 -0500
+Subject: [PATCH] Add rd.neednet=1 to cmdline only if there are devices bound
+ to tang
+
+---
+ src/luks/systemd/dracut/module-setup.sh.in | 24 ++++++++++++++++++----
+ 1 file changed, 20 insertions(+), 4 deletions(-)
+
+diff --git a/src/luks/systemd/dracut/module-setup.sh.in b/src/luks/systemd/dracut/module-setup.sh.in
+index 990bf4a..841f7a8 100755
+--- a/src/luks/systemd/dracut/module-setup.sh.in
++++ b/src/luks/systemd/dracut/module-setup.sh.in
+@@ -18,19 +18,35 @@
+ # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ #
+ 
++is_bound_to_tang() {
++    local dev
++    for dev in $(lsblk -p -n -s -r \
++                 | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
++       if clevis luks list -d "${dev}" 2>/dev/null | grep -q tang; then
++           return 0
++       fi
++    done
++    return 1
++}
++
+ depends() {
+-    echo crypt systemd network
+-    return 0
++    local depends="crypt systemd"
++    if is_bound_to_tang; then
++        depends=$(printf "%s network" "${depends}")
++    fi
++    echo "${depends}"
+ }
+ 
+-cmdline() {
++tang_cmdline() {
+     echo "rd.neednet=1"
+ }
+ 
+ install() {
+     local ret=0
+ 
+-    cmdline > "${initdir}/etc/cmdline.d/99clevis.conf"
++    if is_bound_to_tang; then
++        tang_cmdline > "${initdir}/etc/cmdline.d/99clevis.conf"
++    fi
+ 
+     inst_hook initqueue/online 60 "$moddir/clevis-hook.sh"
+     inst_hook initqueue/settled 60 "$moddir/clevis-hook.sh"
+-- 
+2.18.1
+
diff --git a/SOURCES/Add-support-for-listing-existing-PBD-policies-in-pla.patch b/SOURCES/Add-support-for-listing-existing-PBD-policies-in-pla.patch
new file mode 100644
index 0000000..4f6c2bf
--- /dev/null
+++ b/SOURCES/Add-support-for-listing-existing-PBD-policies-in-pla.patch
@@ -0,0 +1,1009 @@
+From a128130755bcd893ccf1d70b52c13fbaf29613c9 Mon Sep 17 00:00:00 2001
+From: Sergio Correia <scorreia@redhat.com>
+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 <javierm@redhat.com>
++# Author: Sergio Correia <scorreia@redhat.com> - 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 <http://www.gnu.org/licenses/>.
++#
++
++. 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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST=$(basename "${0}")
++. tests-common-functions
++
++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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST=$(basename "${0}")
++. tests-common-functions
++
++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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST=$(basename "${0}")
++. tests-common-functions
++
++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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST=$(basename "${0}")
++. tests-common-functions
++
++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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST=$(basename "${0}")
++. tests-common-functions
++
++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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST=$(basename "${0}")
++. tests-common-functions
++
++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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++# 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
+
diff --git a/SOURCES/Add-the-option-to-extract-luks-passphrase-used-for-b.patch b/SOURCES/Add-the-option-to-extract-luks-passphrase-used-for-b.patch
new file mode 100644
index 0000000..4f2465d
--- /dev/null
+++ b/SOURCES/Add-the-option-to-extract-luks-passphrase-used-for-b.patch
@@ -0,0 +1,364 @@
+From 69556d143544a72f84e9daf25924e3ae5132ce1a Mon Sep 17 00:00:00 2001
+From: Sergio Correia <scorreia@redhat.com>
+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
+<passphrase here>
+---
+ 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 <scorreia@redhat.com> - 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 <http://www.gnu.org/licenses/>.
++#
++
++. 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
++    <passphrase here>
++
++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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST="${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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST="${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
+
diff --git a/SOURCES/Adjust-pin-tang-test-to-account-for-newer-tang-witho.patch b/SOURCES/Adjust-pin-tang-test-to-account-for-newer-tang-witho.patch
new file mode 100644
index 0000000..20e6137
--- /dev/null
+++ b/SOURCES/Adjust-pin-tang-test-to-account-for-newer-tang-witho.patch
@@ -0,0 +1,77 @@
+From 53ecfcf6d934206e3daef4ed3515a0d6f098e276 Mon Sep 17 00:00:00 2001
+From: Sergio Correia <scorreia@redhat.com>
+Date: Wed, 16 Oct 2019 11:40:33 -0300
+Subject: [PATCH 1/2] Adjust pin-tang test to account for newer tang without
+ tangd-update
+
+---
+ src/pins/tang/meson.build |  9 ++-------
+ src/pins/tang/pin-tang    | 11 ++++++++---
+ 2 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/src/pins/tang/meson.build b/src/pins/tang/meson.build
+index 110d72d..061a79f 100644
+--- a/src/pins/tang/meson.build
++++ b/src/pins/tang/meson.build
+@@ -8,11 +8,6 @@ kgen = find_program(
+   '/usr/libexec/tangd-keygen',
+   required: false
+ )
+-updt = find_program(
+-  join_paths(libexecdir, 'tangd-update'),
+-  '/usr/libexec/tangd-update',
+-  required: false
+-)
+ tang = find_program(
+   join_paths(libexecdir, 'tangd'),
+   '/usr/libexec/tangd',
+@@ -25,7 +20,7 @@ if curl.found()
+   bins += join_paths(meson.current_source_dir(), 'clevis-encrypt-tang')
+   mans += join_paths(meson.current_source_dir(), 'clevis-encrypt-tang.1')
+ 
+-  if actv.found() and kgen.found() and updt.found() and tang.found()
++  if actv.found() and kgen.found() and tang.found()
+     env = environment()
+     env.set('SD_ACTIVATE', actv.path())
+     env.append('PATH',
+@@ -42,4 +37,4 @@ if curl.found()
+   endif
+ else
+   warning('Will not install tang pin due to missing dependencies!')
+-endif
+\ No newline at end of file
++endif
+diff --git a/src/pins/tang/pin-tang b/src/pins/tang/pin-tang
+index f420818..9dcc2da 100755
+--- a/src/pins/tang/pin-tang
++++ b/src/pins/tang/pin-tang
+@@ -31,18 +31,23 @@ mkdir -p $TMP/db
+ mkdir -p $TMP/cache
+ 
+ # Generate the server keys
++KEYS=$TMP/db
+ tangd-keygen $TMP/db sig exc
+-tangd-update $TMP/db $TMP/cache
++if which tangd-update; then
++    tangd-update $TMP/db $TMP/cache
++    KEYS=$TMP/cache
++fi
+ 
+ # Start the server
+ port=`shuf -i 1024-65536 -n 1`
+-$SD_ACTIVATE --inetd -l 127.0.0.1:$port -a tangd $TMP/cache &
++$SD_ACTIVATE --inetd -l 127.0.0.1:$port -a tangd $KEYS &
+ export PID=$!
+ sleep 0.25
+ 
+ thp=`jose jwk thp -i "$TMP/db/sig.jwk"`
+-adv="$TMP/cache/default.jws"
+ url="http://localhost:${port}"
++adv="$TMP/adv"
++curl "$url/adv" -o $adv
+ 
+ cfg=`printf '{"url":"%s","adv":"%s"}' "$url" "$adv"`
+ enc=`echo -n "hi" | clevis encrypt tang "$cfg"`
+-- 
+2.21.0
+
diff --git a/SOURCES/Check-key-derivation-key-is-available.patch b/SOURCES/Check-key-derivation-key-is-available.patch
new file mode 100644
index 0000000..bc1be6f
--- /dev/null
+++ b/SOURCES/Check-key-derivation-key-is-available.patch
@@ -0,0 +1,30 @@
+From 8b707e8bfcbfd073579ee553b982b4784490f5ea Mon Sep 17 00:00:00 2001
+From: Daniel Kopecek <dkopecek@redhat.com>
+Date: Wed, 5 Dec 2018 13:18:59 +0100
+Subject: [PATCH] clevis-encrypt-tang: check key derivation key is available
+ before encryption
+
+---
+ src/pins/tang/clevis-encrypt-tang | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/pins/tang/clevis-encrypt-tang b/src/pins/tang/clevis-encrypt-tang
+index e65a7d1..7fc55ca 100755
+--- a/src/pins/tang/clevis-encrypt-tang
++++ b/src/pins/tang/clevis-encrypt-tang
+@@ -114,7 +114,11 @@ elif [ "$thp" != "any" ] && \
+ fi
+ 
+ ### Perform encryption
+-enc=`jose jwk use -i- -r -u deriveKey -o- <<< "$jwks"`
++if ! enc=`jose jwk use -i- -r -u deriveKey -o- <<< "$jwks"`; then
++    echo "Key derivation key not available!" >&2
++    exit 1
++fi
++
+ jose fmt -j "$enc" -Og keys -A || enc="{\"keys\":[$enc]}"
+ 
+ for jwk in `jose fmt -j- -Og keys -Af- <<< "$enc"`; do
+-- 
+2.13.6
+
diff --git a/SOURCES/Delete-remaining-references-to-the-removed-http-pin.patch b/SOURCES/Delete-remaining-references-to-the-removed-http-pin.patch
new file mode 100644
index 0000000..36f1361
--- /dev/null
+++ b/SOURCES/Delete-remaining-references-to-the-removed-http-pin.patch
@@ -0,0 +1,132 @@
+From 1e344dbf6a60fcd2c60a4b8512be455e112d8398 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 7 Nov 2018 14:53:08 +0100
+Subject: [PATCH 1/3] Delete remaining references to the removed http pin
+
+Commit 800d73185d7f ("Remove HTTP pin") removed the clevis http pin, but
+there are still references of it in the docs and also the dracut module.
+
+This was causing dracut to fail building the initramfs due the following:
+
+dracut-install: ERROR: installing 'clevis-decrypt-http'
+
+Suggested-by: Dominick Grift <dac.override@gmail.com>
+
+Fixes: #73
+---
+ README.md                                  | 21 ---------------------
+ src/clevis.1.adoc                          | 21 ---------------------
+ src/luks/clevis-luks-bind.1.adoc           |  1 -
+ src/luks/systemd/dracut/module-setup.sh.in |  1 -
+ src/pins/sss/clevis-encrypt-sss.1.adoc     |  1 -
+ 5 files changed, 45 deletions(-)
+
+diff --git a/README.md b/README.md
+index ce8def12ec96..d57339aca5d9 100644
+--- a/README.md
++++ b/README.md
+@@ -58,27 +58,6 @@ advertisement is stored, or the JSON contents of the advertisment itself. When
+ the advertisment is specified manually like this, Clevis presumes that the
+ advertisement is trusted.
+ 
+-#### PIN: HTTP
+-
+-Clevis also ships a pin for performing escrow using HTTP. Please note that,
+-at this time, this pin does not provide HTTPS support and is suitable only
+-for use over local sockets. This provides integration with services like
+-[Custodia](http://github.com/latchset/custodia).
+-
+-For example:
+-
+-```bash
+-$ echo hi | clevis encrypt http '{"url": "http://server.local/key"}' > hi.jwe
+-```
+-
+-The HTTP pin generate a new (cryptographically-strong random) key and performs
+-encryption using it. It then performs a PUT request to the URL specified. It is
+-understood that the server will securely store this key for later retrieval.
+-During decryption, the pin will perform a GET request to retrieve the key and
+-perform decryption.
+-
+-Patches to provide support for HTTPS and authentication are welcome.
+-
+ #### PIN: TPM2
+ 
+ Clevis provides support to encrypt a key in a Trusted Platform Module 2.0 (TPM2)
+diff --git a/src/clevis.1.adoc b/src/clevis.1.adoc
+index 756aba57a4c8..dea0a696f5f7 100644
+--- a/src/clevis.1.adoc
++++ b/src/clevis.1.adoc
+@@ -21,26 +21,6 @@ take a policy as its first argument and plaintext on standard input and to
+ encrypt the data so that it can be automatically decrypted if the policy is
+ met. Lets walk through an example.
+ 
+-== HTTP ESCROW
+-
+-When using the HTTP pin, we create a new, cryptographically-strong, random key.
+-This key is stored in a remote HTTP escrow server (using a simple PUT or POST).
+-Then at decryption time, we attempt to fetch the key back again in order to
+-decrypt our data. So, for our configuration we need to pass the URL to the key
+-location:
+-
+-    $ clevis encrypt http '{"url":"https://escrow.srv/1234"}' < PT > JWE
+-
+-To decrypt the data, simply provide the ciphertext (JWE):
+-
+-    $ clevis decrypt < JWE > PLAINTEXT
+-
+-Notice that we did not pass any configuration during decryption. The decrypt
+-command extracted the URL (and possibly other configuration) from the JWE
+-object, fetched the encryption key from the escrow and performed decryption.
+-
+-For more information, see link:clevis-encrypt-http.1.adoc[*clevis-encrypt-http*(1)].
+-
+ == TANG BINDING
+ 
+ Clevis provides support for the Tang network binding server. Tang provides
+@@ -136,7 +116,6 @@ For more information, see link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)].
+ 
+ == SEE ALSO
+ 
+-link:clevis-encrypt-http.1.adoc[*clevis-encrypt-http*(1)],
+ link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)],
+ link:clevis-encrypt-tpm2.1.adoc[*clevis-encrypt-tpm2*(1)],
+ link:clevis-encrypt-sss.1.adoc[*clevis-encrypt-sss*(1)],
+diff --git a/src/luks/clevis-luks-bind.1.adoc b/src/luks/clevis-luks-bind.1.adoc
+index 9f3a880cfb0c..0d649e3ec28b 100644
+--- a/src/luks/clevis-luks-bind.1.adoc
++++ b/src/luks/clevis-luks-bind.1.adoc
+@@ -61,7 +61,6 @@ The images cannot be shared without also sharing a master key.
+ == SEE ALSO
+ 
+ link:clevis-luks-unlockers.7.adoc[*clevis-luks-unlockers*(7)],
+-link:clevis-encrypt-http.1.adoc[*clevis-encrypt-http*(1)],
+ link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)],
+ link:clevis-encrypt-sss.1.adoc[*clevis-encrypt-sss*(1)],
+ link:clevis-decrypt.1.adoc[*clevis-decrypt*(1)]
+diff --git a/src/luks/systemd/dracut/module-setup.sh.in b/src/luks/systemd/dracut/module-setup.sh.in
+index 119762e38326..48aea5b3f29a 100755
+--- a/src/luks/systemd/dracut/module-setup.sh.in
++++ b/src/luks/systemd/dracut/module-setup.sh.in
+@@ -36,7 +36,6 @@ install() {
+     inst_hook initqueue/settled 60 "$moddir/clevis-hook.sh"
+ 
+     inst_multiple /etc/services \
+-        clevis-decrypt-http \
+         clevis-decrypt-tang \
+         clevis-decrypt-sss \
+         @libexecdir@/clevis-luks-askpass \
+diff --git a/src/pins/sss/clevis-encrypt-sss.1.adoc b/src/pins/sss/clevis-encrypt-sss.1.adoc
+index d46498db328c..7144e7e9ea96 100644
+--- a/src/pins/sss/clevis-encrypt-sss.1.adoc
++++ b/src/pins/sss/clevis-encrypt-sss.1.adoc
+@@ -54,6 +54,5 @@ receive key fragments.
+ 
+ == SEE ALSO
+ 
+-link:clevis-encrypt-http.1.adoc[*clevis-encrypt-http*(1)],
+ link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)],
+ link:clevis-decrypt.1.adoc[*clevis-decrypt*(1)]
+-- 
+2.19.1
+
diff --git a/SOURCES/Improve-clevis-luks-regen-no-unbind-in-every-case.patch b/SOURCES/Improve-clevis-luks-regen-no-unbind-in-every-case.patch
new file mode 100644
index 0000000..b905ada
--- /dev/null
+++ b/SOURCES/Improve-clevis-luks-regen-no-unbind-in-every-case.patch
@@ -0,0 +1,1262 @@
+From 5536f15b9235cb6ae1b79a5ad1d96a8ea97b3113 Mon Sep 17 00:00:00 2001
+From: Sergio Correia <scorreia@redhat.com>
+Date: Wed, 29 Jan 2020 06:29:32 -0500
+Subject: [PATCH] Improve clevis luks regen; no unbind in every case
+
+When updating the metadata -- likely due to a tang key rotation --,
+clevis will not do unbind + bind in every case.
+
+Now we have 2 cases to be handled:
+1) we have the key for the slot being rotated; in this case, the
+   rotation happens in-place
+
+2) we don't have the key for the slot being rotated; in this case,
+   we have to re-add the keyslot with updated info.
+
+Added also mechanisms for backup + restore of the LUKS header/slots,
+so that we can revert back to the original state if clevis luks regen
+fails.
+---
+ src/luks/clevis-luks-common-functions  | 202 ++++++++++++++++++++++
+ src/luks/clevis-luks-pass              |   5 +-
+ src/luks/clevis-luks-regen             | 223 ++++++++++++-------------
+ src/luks/tests/backup-restore-luks1    | 114 +++++++++++++
+ src/luks/tests/backup-restore-luks2    | 115 +++++++++++++
+ src/luks/tests/meson.build             |   7 +
+ 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  |  27 ++-
+ 11 files changed, 966 insertions(+), 115 deletions(-)
+ create mode 100755 src/luks/tests/backup-restore-luks1
+ create mode 100755 src/luks/tests/backup-restore-luks2
+ 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 9ba1812..2a1af26 100644
+--- a/src/luks/clevis-luks-common-functions
++++ b/src/luks/clevis-luks-common-functions
+@@ -314,3 +314,205 @@ clevis_luks_read_pins_from_slot() {
+     fi
+     printf "%s: %s\n" "${SLOT}" "${cfg}"
+ }
++
++# 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="${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="${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
+index 9535ba3..44fd673 100755
+--- a/src/luks/clevis-luks-regen
++++ b/src/luks/clevis-luks-regen
+@@ -1,8 +1,9 @@
+-#!/usr/bin/env bash
++#!/usr/bin/bash
+ # vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+ #
+ # Copyright (c) 2018 Red Hat, Inc.
+ # Author: Radovan Sroka <rsroka@redhat.com>
++# Author: Sergio Correia <scorreia@redhat.com>
+ #
+ # This program is free software: you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+@@ -28,19 +29,27 @@ if [ "$1" == "--summary" ]; then
+ fi
+ 
+ function usage_and_exit () {
+-    echo >&2
+-    echo "Usage: clevis luks regen -d DEV -s SLOT" >&2
+-    echo >&2
+-    echo "$SUMMARY" >&2
+-    echo >&2
+-    exit "$1"
++    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}"
+ }
+ 
+-if [ "$#" -ne "4" ]; then
+-    usage_and_exit 1
+-fi
++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 "hd:s:" o; do
++while getopts ":hfd:s:" o; do
+     case "$o" in
+     d) DEV="$OPTARG";;
+     h) usage_and_exit 0;;
+@@ -49,88 +58,6 @@ while getopts "hd:s:" o; do
+     esac
+ done
+ 
+-function decode_luks_header () {
+-    if DATA_CODED="$(jose jwe fmt -i- <<< "$1")"; then
+-        DATA_CODED="$(jose fmt -j- -g protected -u- <<< "$DATA_CODED")"
+-        DATA_DECODED="$(jose b64 dec -i- <<< "$DATA_CODED")"
+-    else
+-        echo "Error decoding JWE protected header!" >&2
+-        exit 1
+-    fi
+-
+-    echo "$DATA_DECODED"
+-}
+-
+-function generate_cfg () {
+-    echo -n "{"
+-    DATA="$(decode_luks_header "$1")"
+-
+-    if ! P="$(jose fmt -j- -g clevis -g pin -u- <<< "$DATA")" || [ -z "$P" ]; then
+-        echo "Pin wasn't found in LUKS metadata!" >&2
+-        exit 1
+-    fi
+-
+-    if ! CONTENT="$(jose fmt -j- -g clevis -g "$P" -o- <<< "$DATA")" || [ -z "$CONTENT" ]; then
+-        echo "Content was not found!" >&2
+-    fi
+-
+-    # echo -n "\"$P\": ["
+-
+-    if [ "$P" = "tang" ] || [ "$P" = "http" ]; then
+-        URL="$(jose fmt -j- -g url -u- <<< "$CONTENT")"
+-        echo -n "\"url\":\"$URL\""
+-    elif [ "$P" = "sss" ]; then
+-        THRESHOLD="$(jose fmt -j- -g t -o- <<< "$CONTENT")"
+-        if [ -n "$THRESHOLD" ]; then
+-            echo -n "\"t\":$THRESHOLD,"
+-        fi
+-
+-        echo -n "\"pins\":{"
+-
+-        CNT=0
+-        PREV=""
+-        while ITEM="$(jose fmt -j- -g jwe -g"$CNT" -u- <<< "$CONTENT")"; do
+-            if [ -z "$ITEM" ]; then
+-                CNT=$(( CNT + 1 ))
+-                continue # in some cases it can be empty string
+-            fi
+-
+-            DD="$(decode_luks_header "$ITEM")"
+-
+-            if ! PP="$(jose fmt -j- -g clevis -g pin -u- <<< "$DD")" || [ -z "$PP" ]; then
+-                echo "Pin wasn't found in LUKS metadata!" >&2
+-                exit 1
+-            fi
+-
+-            if [ "$CNT" -eq 0 ]; then
+-                PREV="$PP"
+-                echo -n "\"$PP\":["
+-                echo -n "$(generate_cfg "$ITEM")"
+-            else
+-                if ! [ "$PREV" = "$PP" ]; then
+-                    echo -n "],\"$PP\":["
+-                    echo -n "$(generate_cfg "$ITEM")"
+-                else
+-                    echo -n ",$(generate_cfg "$ITEM")"
+-                fi
+-            fi
+-
+-            PREV="$PP"
+-            CNT=$(( CNT + 1 ))
+-        done
+-
+-        echo -n "]}"
+-
+-    else
+-        echo "Unknown pin $P!" >&2
+-        exit 1
+-    fi
+-
+-    echo -n "}"
+-}
+-
+-### get luks metadata
+-
+ if [ -z "$DEV" ]; then
+     echo "Did not specify a device!" >&2
+     exit 1
+@@ -141,23 +68,14 @@ if [ -z "$SLT" ]; then
+     exit 1
+ fi
+ 
+-if ! OLD_LUKS_CODED="$(clevis_luks_read_slot "$DEV" "$SLT")"; then
+-    echo "Error reading metadata from LUKS device!" >&2
+-    exit 1
+-fi
+-
+ ### ----------------------------------------------------------------------
+-
+-DECODED="$(decode_luks_header "$OLD_LUKS_CODED")"
+-
+-if ! PIN="$(jose fmt -j- -g clevis -g pin -u- <<< "$DECODED")" || [ -z "$PIN" ]; then
+-    echo "Pin wasn't found in LUKS metadata!" >&2
++if ! pin_cfg=$(clevis luks list -d "${DEV}" -s "${SLT}" 2>/dev/null); then
++    echo "Error obtaining current configuration of device ${DEV}:${SLT}" >&2
+     exit 1
+ fi
+ 
+-CFG="$(generate_cfg "$OLD_LUKS_CODED")"
+-
+-### ----------------------------------------------------------------------
++PIN=$(echo "${pin_cfg}" | awk '{ print $2 }')
++CFG=$(echo "${pin_cfg}" | awk '{ print $3 }' | tr -d "'")
+ 
+ echo "Regenerating with:"
+ echo "PIN: $PIN"
+@@ -166,20 +84,101 @@ echo "CONFIG: $CFG"
+ trap 'echo "Ignoring CONTROL-C!"' INT TERM
+ 
+ # Get the existing key.
+-read -r -s -p "Enter existing LUKS password: " existing_key; echo
++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 luksOpen --test-passphrase "${DEV}" <<< "${existing_key}"; then
++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
+ 
+-if ! clevis luks unbind -d "${DEV}" -s "${SLT}" -f; then
+-    echo "Error during unbind of rotated key from slot:$SLT in $DEV" >&2
++restore_device() {
++    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
+ 
+-if ! clevis luks bind -d "${DEV}" -s "${SLT}" "${PIN}" "${CFG}" -k - <<< "${existing_key}"; then
+-    echo "Error during bind of new key from slot:$SLT in $DEV" >&2
++# Now make sure that we can unlock this device after the change.
++# 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
+ 
+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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST="${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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST="${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 248d2ea..4e0a6cb 100644
+--- a/src/luks/tests/meson.build
++++ b/src/luks/tests/meson.build
+@@ -35,6 +35,9 @@ 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)
++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.
+@@ -45,3 +48,7 @@ if jq.found()
+   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)
++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)
++
+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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST="${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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST="${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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST="${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 <scorreia@redhat.com>
++#
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++TEST="${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 b/src/luks/tests/tests-common-functions
+index 7758876..1139f09 100644
+--- a/src/luks/tests/tests-common-functions
++++ b/src/luks/tests/tests-common-functions
+@@ -63,7 +63,7 @@ new_device() {
+         return 0
+     fi
+ 
+-    fallocate -l16M "${DEV}"
++    fallocate -l64M "${DEV}"
+     local extra_options='--pbkdf pbkdf2 --pbkdf-force-iterations 1000'
+     cryptsetup luksFormat --type "${LUKS}" ${extra_options} --batch-mode --force-password "${DEV}" <<< "${DEFAULT_PASS}"
+     # Caching the just-formatted device for possible reuse.
+@@ -83,4 +83,29 @@ pin_cfg_equal() {
+          <(jq -S . < <(echo -n "${cfg2}"))
+ }
+ 
++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 DEFAULT_PASS='just-some-test-password-here'
+-- 
+2.18.2
+
diff --git a/SOURCES/Improve-error-message-when-bind-is-given-an-invalid-.patch b/SOURCES/Improve-error-message-when-bind-is-given-an-invalid-.patch
new file mode 100644
index 0000000..e0c2af0
--- /dev/null
+++ b/SOURCES/Improve-error-message-when-bind-is-given-an-invalid-.patch
@@ -0,0 +1,42 @@
+From 02f17448e379c92745f8203f47e5de0725b1c1b6 Mon Sep 17 00:00:00 2001
+From: Sergio Correia <scorreia@redhat.com>
+Date: Fri, 18 Oct 2019 09:04:22 -0300
+Subject: [PATCH] Improve error message when bind is given an invalid PIN
+
+---
+ src/luks/clevis-luks-bind | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/src/luks/clevis-luks-bind b/src/luks/clevis-luks-bind
+index 7aae2ea..1b5caf2 100755
+--- a/src/luks/clevis-luks-bind
++++ b/src/luks/clevis-luks-bind
+@@ -19,6 +19,8 @@
+ # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ #
+ 
++. clevis-luks-common-functions
++
+ SUMMARY="Binds a LUKS device using the specified policy"
+ UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
+ 
+@@ -68,6 +70,9 @@ fi
+ if ! PIN=${@:$((OPTIND++)):1} || [ -z "$PIN" ]; then
+     echo "Did not specify a pin!" >&2
+     usage
++elif ! EXE=$(findexe clevis-encrypt-"${PIN}"); then
++    echo "'$PIN' is not a valid pin!" >&2
++    usage
+ fi
+ 
+ if ! CFG=${@:$((OPTIND++)):1} || [ -z "$CFG" ]; then
+@@ -142,4 +147,4 @@ else
+         cryptsetup luksRemoveKey "$DEV" <<<"$key"
+         exit 1
+     fi
+-fi
+\ No newline at end of file
++fi
+-- 
+2.21.0
+
diff --git a/SOURCES/Improve-tests-speed.patch b/SOURCES/Improve-tests-speed.patch
new file mode 100644
index 0000000..3993614
--- /dev/null
+++ b/SOURCES/Improve-tests-speed.patch
@@ -0,0 +1,60 @@
+From 874ee402645f9c3c40eaf5882a9cb92bc88b1a8f Mon Sep 17 00:00:00 2001
+From: Sergio Correia <scorreia@redhat.com>
+Date: Sun, 22 Dec 2019 16:46:19 -0500
+Subject: [PATCH] Improve tests speed Also run tests only as root, if they
+ involve cryptsetup
+
+---
+ src/luks/tests/tests-common-functions | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/src/luks/tests/tests-common-functions b/src/luks/tests/tests-common-functions
+index b65a84a..7758876 100644
+--- a/src/luks/tests/tests-common-functions
++++ b/src/luks/tests/tests-common-functions
+@@ -25,6 +25,11 @@ luks2_supported() {
+     return 0
+ }
+ 
++skip_test() {
++    echo "${1}" >&2
++    exit 77
++}
++
+ # Creates a tang adv to be used in the test.
+ create_tang_adv() {
+     local adv="${1}"
+@@ -39,14 +44,18 @@ create_tang_adv() {
+         | jose jws sig -I- -s "${TEMPLATE}" -k "${SIG}" -o "${adv}"
+ }
+ 
+-
+ # Creates a new LUKS1 or LUKS2 device to be used.
+ new_device() {
+     local LUKS="${1}"
+     local DEV="${2}"
+-
+     local DEV_CACHED="${TMP}/${LUKS}.cached"
+ 
++    # Some builders fail if the cryptsetup steps are not ran as root, so let's
++    # skip the test now if not running as root.
++    if [ $(id -u) != 0 ]; then
++        skip_test "WARNING: You must be root to run this test; test skipped."
++    fi
++
+     # Let's reuse an existing device, if there is one.
+     if [ -f "${DEV_CACHED}" ]; then
+         echo "Reusing cached ${LUKS} device..."
+@@ -55,7 +64,8 @@ new_device() {
+     fi
+ 
+     fallocate -l16M "${DEV}"
+-    cryptsetup luksFormat --type "${LUKS}" --batch-mode --force-password "${DEV}" <<< "${DEFAULT_PASS}"
++    local extra_options='--pbkdf pbkdf2 --pbkdf-force-iterations 1000'
++    cryptsetup luksFormat --type "${LUKS}" ${extra_options} --batch-mode --force-password "${DEV}" <<< "${DEFAULT_PASS}"
+     # Caching the just-formatted device for possible reuse.
+     cp -f "${DEV}" "${DEV_CACHED}"
+ }
+-- 
+2.18.1
+
diff --git a/SOURCES/Install-cryptsetup-and-tpm2_pcrlist-in-the-initramfs.patch b/SOURCES/Install-cryptsetup-and-tpm2_pcrlist-in-the-initramfs.patch
new file mode 100644
index 0000000..28082b7
--- /dev/null
+++ b/SOURCES/Install-cryptsetup-and-tpm2_pcrlist-in-the-initramfs.patch
@@ -0,0 +1,49 @@
+From 34658590e45ab85f6008379d9433406a5c7fd914 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 7 Nov 2018 15:12:17 +0100
+Subject: [PATCH 2/3] Install cryptsetup and tpm2_pcrlist in the initramfs
+
+The cryptsetup and tpm2_pcrlist are missing in the initramfs, this makes
+automatic LUKS unlocking fail with the following errors:
+
+dracut-initqueue[382]: /usr/libexec/clevis-luks-askpass: line 52: cryptsetup: command not found
+dracut-initqueue[382]: /usr/bin/clevis-decrypt-tpm2: line 40: tpm2_pcrlist: command not found
+
+Suggested-by: Federico Chiacchiaretta <federico.chia@gmail.com>
+
+Fixes: #74
+---
+ src/luks/systemd/dracut/module-setup.sh.in | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/luks/systemd/dracut/module-setup.sh.in b/src/luks/systemd/dracut/module-setup.sh.in
+index 48aea5b3f29a..41e7d6c9b002 100755
+--- a/src/luks/systemd/dracut/module-setup.sh.in
++++ b/src/luks/systemd/dracut/module-setup.sh.in
+@@ -40,6 +40,7 @@ install() {
+         clevis-decrypt-sss \
+         @libexecdir@/clevis-luks-askpass \
+         clevis-decrypt \
++        cryptsetup \
+         luksmeta \
+         clevis \
+         mktemp \
+@@ -49,6 +50,7 @@ install() {
+ 
+     for cmd in clevis-decrypt-tpm2 \
+ 	tpm2_createprimary \
++	tpm2_pcrlist \
+ 	tpm2_unseal \
+ 	tpm2_load; do
+ 
+@@ -60,6 +62,7 @@ install() {
+     if (($ret == 0)); then
+ 	inst_multiple clevis-decrypt-tpm2 \
+ 	    tpm2_createprimary \
++	    tpm2_pcrlist \
+ 	    tpm2_unseal \
+ 	    tpm2_load
+     fi
+-- 
+2.19.1
+
diff --git a/SOURCES/Use-one-clevis-luks-askpass-per-device.patch b/SOURCES/Use-one-clevis-luks-askpass-per-device.patch
new file mode 100644
index 0000000..87c657b
--- /dev/null
+++ b/SOURCES/Use-one-clevis-luks-askpass-per-device.patch
@@ -0,0 +1,237 @@
+From 523f1361c759d5af0952b0137d4dbd51be1e7b3d Mon Sep 17 00:00:00 2001
+From: Sergio Correia <scorreia@redhat.com>
+Date: Sun, 22 Dec 2019 17:01:09 -0500
+Subject: [PATCH] Use one clevis-luks-askpass per device
+
+This should improve the reliability of the boot unlocking, especially
+when unlocking multiple devices upon boot.
+
+It also greatly simplifies the configuration, as three is no need to
+enable any systemd units manually nor add _netdev to either fstab or
+crypttab.
+---
+ src/luks/clevis-luks-unlockers.7.adoc         | 16 +++----------
+ src/luks/systemd/clevis-luks-askpass          |  7 +++++-
+ src/luks/systemd/clevis-luks-askpass.path     | 10 --------
+ .../systemd/clevis-luks-askpass.service.in    |  8 -------
+ src/luks/systemd/clevis-luks-askpass@.path    | 12 ++++++++++
+ .../systemd/clevis-luks-askpass@.service.in   |  9 +++++++
+ src/luks/systemd/dracut/module-setup.sh.in    | 24 +++++++++++++++++++
+ src/luks/systemd/meson.build                  |  8 +++----
+ 8 files changed, 58 insertions(+), 36 deletions(-)
+ delete mode 100644 src/luks/systemd/clevis-luks-askpass.path
+ delete mode 100644 src/luks/systemd/clevis-luks-askpass.service.in
+ create mode 100644 src/luks/systemd/clevis-luks-askpass@.path
+ create mode 100644 src/luks/systemd/clevis-luks-askpass@.service.in
+
+diff --git a/src/luks/clevis-luks-unlockers.7.adoc b/src/luks/clevis-luks-unlockers.7.adoc
+index 161b73a..e8d47ba 100644
+--- a/src/luks/clevis-luks-unlockers.7.adoc
++++ b/src/luks/clevis-luks-unlockers.7.adoc
+@@ -26,7 +26,7 @@ You can unlock a LUKS volume manually using the following command:
+ 
+ For more information, see link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)].
+ 
+-== EARLY BOOT UNLOCKING
++== BOOT UNLOCKING
+ 
+ If Clevis integration does not already ship in your initramfs, you may need to
+ rebuild your initramfs with this command:
+@@ -34,23 +34,13 @@ rebuild your initramfs with this command:
+     $ sudo dracut -f
+ 
+ Once Clevis is integrated into your initramfs, a simple reboot should unlock
+-your root volume. Note, however, that early boot integration only works for the
+-root volume. Non-root volumes should use the late boot unlocker.
++your clevis-bound volumes. Root volumes will be unlocked in early-boot, while the
++remaining volumes will be unlocked after dracut switch-root.
+ 
+ Dracut will bring up your network using DHCP by default. If you need to specify
+ additional network parameters, such as static IP configuration, please consult
+ the dracut documentation.
+ 
+-== LATE BOOT UNLOCKING
+-
+-You can enable late boot unlocking by executing the following command:
+-
+-    $ sudo systemctl enable clevis-luks-askpass.path
+-
+-After a reboot, Clevis will attempt to unlock all *_netdev* devices listed in
+-*/etc/crypttab* when systemd prompts for their passwords. This implies that
+-systemd support for *_netdev* is required.
+-
+ == DESKTOP UNLOCKING
+ 
+ When the udisks2 unlocker is installed, your GNOME desktop session should
+diff --git a/src/luks/systemd/clevis-luks-askpass b/src/luks/systemd/clevis-luks-askpass
+index b01d93a..feebb1a 100755
+--- a/src/luks/systemd/clevis-luks-askpass
++++ b/src/luks/systemd/clevis-luks-askpass
+@@ -24,15 +24,17 @@ UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
+ shopt -s nullglob
+ 
+ path=/run/systemd/ask-password
+-while getopts ":lp:" o; do
++while getopts ":lpu:" o; do
+     case "$o" in
+     l) loop=true;;
+     p) path=$OPTARG;;
++    u) device_uuid=$OPTARG;;
+     esac
+ done
+ 
+ while true; do
+     todo=0
++    [ -n "${device_uuid}" ] && todo=1 && loop=true
+ 
+     for question in $path/ask.*; do
+         metadata=false
+@@ -48,6 +50,8 @@ while true; do
+         done < "$question"
+ 
+         [ -z "$d" -o -z "$s" ] && continue
++        [[ -n "${device_uuid}" ]] && [[ "${d}" != *"${device_uuid}"* ]] \
++            && continue
+ 
+         if cryptsetup isLuks --type luks1 "$d"; then
+             # If the device is not initialized, sliently skip it.
+@@ -79,6 +83,7 @@ while true; do
+             done
+         fi
+ 
++        [ -n "${device_uuid}" ] && [ "${unlocked}" == true ] && todo=0 && break
+         [ $metadata == true ] || continue
+         [ $unlocked == true ] && continue
+         todo=$((todo + 1))
+diff --git a/src/luks/systemd/clevis-luks-askpass.path b/src/luks/systemd/clevis-luks-askpass.path
+deleted file mode 100644
+index a4d01ba..0000000
+--- a/src/luks/systemd/clevis-luks-askpass.path
++++ /dev/null
+@@ -1,10 +0,0 @@
+-[Unit]
+-Description=Clevis systemd-ask-password Watcher
+-Before=remote-fs-pre.target
+-Wants=remote-fs-pre.target
+-
+-[Path]
+-PathChanged=/run/systemd/ask-password
+-
+-[Install]
+-WantedBy=remote-fs.target
+diff --git a/src/luks/systemd/clevis-luks-askpass.service.in b/src/luks/systemd/clevis-luks-askpass.service.in
+deleted file mode 100644
+index 2c6bbed..0000000
+--- a/src/luks/systemd/clevis-luks-askpass.service.in
++++ /dev/null
+@@ -1,8 +0,0 @@
+-[Unit]
+-Description=Clevis LUKS systemd-ask-password Responder
+-Requires=network-online.target
+-After=network-online.target
+-
+-[Service]
+-Type=oneshot
+-ExecStart=@libexecdir@/clevis-luks-askpass -l
+diff --git a/src/luks/systemd/clevis-luks-askpass@.path b/src/luks/systemd/clevis-luks-askpass@.path
+new file mode 100644
+index 0000000..3f23665
+--- /dev/null
++++ b/src/luks/systemd/clevis-luks-askpass@.path
+@@ -0,0 +1,12 @@
++[Unit]
++Description=Clevis systemd-ask-password Watcher for %i
++DefaultDependencies=no
++Conflicts=shutdown.target
++Before=basic.target shutdown.target
++
++[Path]
++DirectoryNotEmpty=/run/systemd/ask-password
++MakeDirectory=yes
++
++[Install]
++WantedBy=basic.target
+diff --git a/src/luks/systemd/clevis-luks-askpass@.service.in b/src/luks/systemd/clevis-luks-askpass@.service.in
+new file mode 100644
+index 0000000..cd26eb2
+--- /dev/null
++++ b/src/luks/systemd/clevis-luks-askpass@.service.in
+@@ -0,0 +1,9 @@
++[Unit]
++Description=Clevis LUKS systemd-ask-password Responder for luks-%i
++DefaultDependencies=no
++Conflicts=shutdown.target
++Before=shutdown.target
++
++[Service]
++Type=oneshot
++ExecStart=@libexecdir@/clevis-luks-askpass -u %i
+diff --git a/src/luks/systemd/dracut/module-setup.sh.in b/src/luks/systemd/dracut/module-setup.sh.in
+index 841f7a8..1877715 100755
+--- a/src/luks/systemd/dracut/module-setup.sh.in
++++ b/src/luks/systemd/dracut/module-setup.sh.in
+@@ -29,6 +29,29 @@ is_bound_to_tang() {
+     return 1
+ }
+ 
++configure_passwd_watchers() {
++    if ! command -v systemctl >/dev/null; then
++        return 1
++    fi
++
++    local proc_cmdline
++    proc_cmdline=$(</proc/cmdline)
++
++    local luks_uuid
++    local cfg
++    for dev in $(lsblk -p -n -s -r \
++                 | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
++        luks_uuid=$(cryptsetup luksUUID "${dev}")
++        [[ "${proc_cmdline}" == *"rd.luks.uuid=luks-${luks_uuid}"* ]] && continue
++
++        if cfg=$(clevis luks list -d "${dev}" 2>/dev/null); then
++            local action=enable
++            [ -z "${cfg}" ] && action=disable
++            systemctl "${action}" "clevis-luks-askpass@${luks_uuid}.path" 2>/dev/null
++        fi
++    done
++}
++
+ depends() {
+     local depends="crypt systemd"
+     if is_bound_to_tang; then
+@@ -84,6 +107,7 @@ install() {
+ 	inst_libdir_file "libtss2-tcti-device.so*"
+     fi
+ 
++    configure_passwd_watchers
+     dracut_need_initqueue
+ }
+ 
+diff --git a/src/luks/systemd/meson.build b/src/luks/systemd/meson.build
+index 108e9d8..334e84c 100644
+--- a/src/luks/systemd/meson.build
++++ b/src/luks/systemd/meson.build
+@@ -6,14 +6,14 @@ if systemd.found()
+   unitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
+ 
+   configure_file(
+-    input: 'clevis-luks-askpass.service.in',
+-    output: 'clevis-luks-askpass.service',
++    input: 'clevis-luks-askpass@.service.in',
++    output: 'clevis-luks-askpass@.service',
+     install_dir: unitdir,
+     configuration: data,
+   )
+ 
+-  install_data('clevis-luks-askpass.path', install_dir: unitdir)
++  install_data('clevis-luks-askpass@.path', install_dir: unitdir)
+   install_data('clevis-luks-askpass', install_dir: libexecdir)
+ else
+   warning('Will not install systemd support due to missing dependencies!')
+-endif
+\ No newline at end of file
++endif
+-- 
+2.18.1
+
diff --git a/SPECS/clevis.spec b/SPECS/clevis.spec
new file mode 100644
index 0000000..02a259b
--- /dev/null
+++ b/SPECS/clevis.spec
@@ -0,0 +1,288 @@
+%global _hardened_build 1
+
+Name:           clevis
+Version:        11
+Release:        9%{?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
+
+Patch01: Delete-remaining-references-to-the-removed-http-pin.patch
+Patch02: Install-cryptsetup-and-tpm2_pcrlist-in-the-initramfs.patch
+Patch03: Add-device-TCTI-library-to-the-initramfs.patch
+Patch04: Check-key-derivation-key-is-available.patch
+Patch05: Adjust-pin-tang-test-to-account-for-newer-tang-witho.patch
+Patch06: Add-clevis-luks-report-regen.patch
+Patch07: Improve-error-message-when-bind-is-given-an-invalid-.patch
+Patch08: Add-support-for-listing-existing-PBD-policies-in-pla.patch
+Patch09: Add-the-option-to-extract-luks-passphrase-used-for-b.patch
+Patch10: Add-rd.neednet-1-to-cmdline-only-if-there-are-device.patch
+Patch11: Improve-tests-speed.patch
+Patch12: Use-one-clevis-luks-askpass-per-device.patch
+Patch13: Improve-clevis-luks-regen-no-unbind-in-every-case.patch
+
+BuildRequires:  gcc
+BuildRequires:  meson
+BuildRequires:  asciidoc
+BuildRequires:  ninja-build
+BuildRequires:  bash-completion
+
+BuildRequires:  libjose-devel >= 8
+BuildRequires:  libluksmeta-devel >= 8
+BuildRequires:  audit-libs-devel
+BuildRequires:  libudisks2-devel
+BuildRequires:  openssl-devel
+
+BuildRequires:  tpm2-tools >= 3.0.0
+BuildRequires:  desktop-file-utils
+BuildRequires:  pkgconfig
+BuildRequires:  systemd
+BuildRequires:  dracut
+BuildRequires:  tang >= 6
+BuildRequires:  curl
+BuildRequires:  luksmeta
+BuildRequires:  cracklib-dicts
+Buildrequires:  jq
+BuildRequires:  diffutils
+BuildRequires:  expect
+
+Requires:       tpm2-tools >= 3.0.0
+Requires:       coreutils
+Requires:       jose >= 8
+Requires:       curl
+Requires(pre):  shadow-utils
+
+%description
+Clevis is a framework for automated decryption. It allows you to encrypt
+data using sophisticated unlocking policies which enable decryption to
+occur automatically.
+
+The clevis package provides basic encryption/decryption policy support.
+Users can use this directly; but most commonly, it will be used as a
+building block for other packages. For example, see the clevis-luks
+and clevis-dracut packages for automatic root volume unlocking of LUKSv1
+volumes during early boot.
+
+%package luks
+Summary:        LUKSv1 integration for clevis
+Requires:       %{name}%{?_isa} = %{version}-%{release}
+Requires:       cryptsetup
+Requires:       luksmeta >= 8
+
+%description luks
+LUKSv1 integration for clevis. This package allows you to bind a LUKSv1
+volume to a clevis unlocking policy. For automated unlocking, an unlocker
+will also be required. See, for example, clevis-dracut and clevis-udisks2.
+
+%package systemd
+Summary:        systemd integration for clevis
+Requires:       %{name}-luks%{?_isa} = %{version}-%{release}
+%if 0%{?fedora} > 27
+Requires:       systemd%{?_isa} >= 235-3
+%else
+%if 0%{?fedora} == 27
+Requires:       systemd%{?_isa} >= 234-9
+%else
+%if 0%{?fedora} == 26
+Requires:       systemd%{?_isa} >= 233-7
+%else
+Requires:       systemd%{?_isa} >= 236
+%endif
+%endif
+%endif
+Requires:       nc
+
+%description systemd
+Automatically unlocks LUKSv1 _netdev block devices from /etc/crypttab.
+
+%package dracut
+Summary:        Dracut integration for clevis
+Requires:       %{name}-systemd%{?_isa} = %{version}-%{release}
+Requires:       dracut-network
+
+%description dracut
+Automatically unlocks LUKSv1 block devices in early boot.
+
+%package udisks2
+Summary:        UDisks2/Storaged integration for clevis
+Requires:       %{name}-luks%{?_isa} = %{version}-%{release}
+
+%description udisks2
+Automatically unlocks LUKSv1 block devices in desktop environments that
+use UDisks2 or storaged (like GNOME).
+
+%prep
+%autosetup -p1
+
+%build
+%meson -Duser=clevis -Dgroup=clevis
+%meson_build
+
+%install
+%meson_install
+
+%check
+desktop-file-validate \
+  %{buildroot}/%{_sysconfdir}/xdg/autostart/%{name}-luks-udisks2.desktop
+%meson_test
+
+%pre
+getent group %{name} >/dev/null || groupadd -r %{name}
+getent passwd %{name} >/dev/null || \
+    useradd -r -g %{name} -d %{_localstatedir}/cache/%{name} -s /sbin/nologin \
+    -c "Clevis Decryption Framework unprivileged user" %{name}
+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
+exit 0
+
+%files
+%license COPYING
+%{_datadir}/bash-completion/
+%{_bindir}/%{name}-decrypt-tang
+%{_bindir}/%{name}-decrypt-tpm2
+%{_bindir}/%{name}-decrypt-sss
+%{_bindir}/%{name}-decrypt
+%{_bindir}/%{name}-encrypt-tang
+%{_bindir}/%{name}-encrypt-tpm2
+%{_bindir}/%{name}-encrypt-sss
+%{_bindir}/%{name}
+%{_mandir}/man1/%{name}-encrypt-tang.1*
+%{_mandir}/man1/%{name}-encrypt-tpm2.1*
+%{_mandir}/man1/%{name}-encrypt-sss.1*
+%{_mandir}/man1/%{name}-decrypt.1*
+%{_mandir}/man1/%{name}.1*
+
+%files luks
+%{_mandir}/man7/%{name}-luks-unlockers.7*
+%{_mandir}/man1/%{name}-luks-unlock.1*
+%{_mandir}/man1/%{name}-luks-unbind.1*
+%{_mandir}/man1/%{name}-luks-bind.1*
+%{_mandir}/man1/%{name}-luks-regen.1*
+%{_mandir}/man1/%{name}-luks-report.1*
+%{_mandir}/man1/%{name}-luks-list.1*
+%{_mandir}/man1/%{name}-luks-pass.1.*
+%{_bindir}/%{name}-luks-unlock
+%{_bindir}/%{name}-luks-unbind
+%{_bindir}/%{name}-luks-bind
+%{_bindir}/%{name}-luks-common-functions
+%{_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-list
+%{_bindir}/%{name}-luks-pass
+
+%files systemd
+%{_libexecdir}/%{name}-luks-askpass
+%{_unitdir}/%{name}-luks-askpass@.path
+%{_unitdir}/%{name}-luks-askpass@.service
+
+%files dracut
+%{_prefix}/lib/dracut/modules.d/60%{name}
+
+%files udisks2
+%{_sysconfdir}/xdg/autostart/%{name}-luks-udisks2.desktop
+%attr(4755, root, root) %{_libexecdir}/%{name}-luks-udisks2
+
+%changelog
+* Wed Feb 02 2020 Sergio Correia <scorreia@redhat.com> - 11-9
+- Improve clevis luks regen not to unbind+bind in every case
+  Resolves: rhbz#1795675
+
+* Mon Jan 13 2020 Sergio Correia <scorreia@redhat.com> - 11-8
+- Use one clevis-luks-askpass per device
+  Resolves: rhbz#1784524
+
+* Sat Nov 30 2019 Sergio Correia <scorreia@redhat.com> - 11-7
+- Add rd.neednet=1 to cmdline only if there are devices bound to tang
+  Resolves: rhbz#1762028
+
+* Sat Nov 30 2019 Sergio Correia <scorreia@redhat.com> - 11-6
+- Add option to extract luks passphrase used for binding
+  Resolves: rhbz#1436780
+
+* Thu Nov 28 2019 Sergio Correia <scorreia@redhat.com> - 11-5
+- Add support for listing existing PBD policies in place
+  Resolves: rhbz#1766526
+
+* Fri Oct 18 2019 Sergio Correia <scorreia@redhat.com> - 11-4
+- Improve error message when bind is given an invalid PIN
+  Resolves: rhbz#1543380
+
+* Wed Oct 16 2019 Sergio Correia <scorreia@redhat.com> - 11-3
+- Add clevis luks report and regen
+  Resolves: rhbz#1564566
+  Resolves: rhbz#1564559
+
+* Fri Jan 04 2019 Daniel Kopecek <dkopecek@redhat.com> - 11-2
+- Check that key derivation key is available
+- Delete remaining references to the removed http pin
+- Install cryptsetup and tpm2_pcrlist in the initramfs
+- Add device TCTI library to the initramfs
+  Resolves: rhbz#1648004
+  Resolves: rhbz#1650246
+
+* Tue Aug 14 2018 Nathaniel McCallum <npmccallum@redhat.com> - 11-1
+- Update to v11
+
+* Thu Jul 12 2018 Fedora Release Engineering <releng@fedoraproject.org> - 10-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
+
+* Wed Mar 21 2018 Nathaniel McCallum <npmccallum@redhat.com> - 10-1
+- Update to v10
+
+* Tue Feb 13 2018 Nathaniel McCallum <npmccallum@redhat.com> - 9-1
+- Update to v9
+
+* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 8-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
+
+* Mon Nov 13 2017 Nathaniel McCallum <npmccallum@redhat.com> - 8-1
+- Update to v8
+
+* Wed Nov 08 2017 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 7-2
+- Rebuild for cryptsetup-2.0.0
+
+* Fri Oct 27 2017 Nathaniel McCallum <npmccallum@redhat.com> - 7-1
+- Update to v7
+
+* Wed Aug 02 2017 Fedora Release Engineering <releng@fedoraproject.org> - 6-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
+
+* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 6-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
+
+* Tue Jun 27 2017 Nathaniel McCallum <npmccallum@redhat.com> - 6-1
+- New upstream release
+- Specify unprivileged user/group during configuration
+- Move clevis user/group creation to base clevis package
+
+* Mon Jun 26 2017 Nathaniel McCallum <npmccallum@redhat.com> - 5-1
+- New upstream release
+- Run clevis decryption from udisks2 under an unprivileged user
+
+* Wed Jun 14 2017 Nathaniel McCallum <npmccallum@redhat.com> - 4-1
+- New upstream release
+
+* Wed Jun 14 2017 Nathaniel McCallum <npmccallum@redhat.com> - 3-1
+- New upstream release
+
+* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
+
+* Fri Nov 18 2016 Nathaniel McCallum <npmccallum@redhat.com> - 2-1
+- New upstream release
+
+* Mon Nov 14 2016 Nathaniel McCallum <npmccallum@redhat.com> - 1-1
+- First release