Browse Source

Import upstream version 16

Sergio Correia 8 months ago
parent
commit
41e48b9644
65 changed files with 1043 additions and 1011 deletions
  1. 0 27
      .travis.yml
  2. 0 91
      .travis/dracut/centos.cfg.in
  3. 0 166
      .travis/dracut/dracut-unlocker
  4. 0 84
      .travis/dracut/fedora.cfg.in
  5. 0 1
      INSTALL.md
  6. 0 1
      README.md
  7. 4 2
      meson.build
  8. 2 1
      src/clevis-decrypt
  9. 2 0
      src/initramfs-tools/hooks/clevis.in
  10. 128 0
      src/luks/clevis-luks-bind
  11. 0 236
      src/luks/clevis-luks-bind.in
  12. 25 2
      src/luks/clevis-luks-common-functions
  13. 64 0
      src/luks/clevis-luks-pass
  14. 42 0
      src/luks/clevis-luks-pass.1.adoc
  15. 1 1
      src/luks/clevis-luks-unlock
  16. 10 5
      src/luks/meson.build
  17. 1 1
      src/luks/systemd/clevis-luks-askpass
  18. 2 2
      src/luks/systemd/dracut/clevis/module-setup.sh.in
  19. 17 2
      src/luks/systemd/meson.build
  20. 6 7
      src/luks/tests/assume-yes
  21. 3 4
      src/luks/tests/assume-yes-luks2
  22. 1 1
      src/luks/tests/backup-restore-luks1
  23. 1 1
      src/luks/tests/backup-restore-luks2
  24. 1 1
      src/luks/tests/bind-already-used-luksmeta-slot
  25. 58 0
      src/luks/tests/bind-binary-keyfile-luks1
  26. 26 13
      src/luks/tests/bind-key-file-non-interactive-luks1
  27. 1 1
      src/luks/tests/bind-luks1
  28. 1 1
      src/luks/tests/bind-luks2
  29. 1 1
      src/luks/tests/bind-pass-with-newline-keyfile-luks1
  30. 1 1
      src/luks/tests/bind-pass-with-newline-luks1
  31. 1 1
      src/luks/tests/bind-wrong-pass-luks1
  32. 1 1
      src/luks/tests/bind-wrong-pass-luks2
  33. 6 8
      src/luks/tests/edit-tang-luks1
  34. 6 8
      src/luks/tests/edit-tang-luks2
  35. 1 1
      src/luks/tests/list-recursive-luks1
  36. 1 1
      src/luks/tests/list-recursive-luks2
  37. 1 1
      src/luks/tests/list-sss-tang-luks1
  38. 1 1
      src/luks/tests/list-sss-tang-luks2
  39. 1 1
      src/luks/tests/list-tang-luks1
  40. 1 1
      src/luks/tests/list-tang-luks2
  41. 19 61
      src/luks/tests/meson.build
  42. 58 0
      src/luks/tests/pass-tang-luks1
  43. 58 0
      src/luks/tests/pass-tang-luks2
  44. 3 4
      src/luks/tests/regen-inplace-luks1
  45. 3 4
      src/luks/tests/regen-inplace-luks2
  46. 3 4
      src/luks/tests/regen-not-inplace-luks1
  47. 3 4
      src/luks/tests/regen-not-inplace-luks2
  48. 3 4
      src/luks/tests/report-sss-luks1
  49. 3 4
      src/luks/tests/report-sss-luks2
  50. 3 4
      src/luks/tests/report-tang-luks1
  51. 3 4
      src/luks/tests/report-tang-luks2
  52. 6 141
      src/luks/tests/tests-common-functions.in
  53. 1 1
      src/luks/tests/unbind-luks1
  54. 1 1
      src/luks/tests/unbind-luks2
  55. 3 4
      src/luks/tests/unlock-tang-luks1
  56. 3 4
      src/luks/tests/unlock-tang-luks2
  57. 2 1
      src/pins/tang/clevis-decrypt-tang
  58. 3 2
      src/pins/tang/clevis-encrypt-tang
  59. 1 46
      src/pins/tang/meson.build
  60. 65 0
      src/pins/tang/tests/meson.build
  61. 12 22
      src/pins/tang/pin-tang
  62. 200 0
      src/pins/tang/tests/tang-common-test-functions.in
  63. 153 0
      src/pins/tang/tests/tang-validate-adv
  64. 8 11
      src/pins/tpm2/clevis-decrypt-tpm2
  65. 8 8
      src/pins/tpm2/clevis-encrypt-tpm2

+ 0 - 27
.travis.yml

@@ -1,27 +0,0 @@
----
-language: c
-os: linux
-dist: focal
-addons:
-  apt:
-    packages:
-      - qemu-kvm
-      - libvirt-daemon-system
-      - libvirt-clients
-      - virtinst
-      - bridge-utils
-      - dnsmasq-base
-      - cpu-checker
-      - cloud-image-utils
-      - tang
-    update: true
-
-env:
-  matrix:
-    - DISTRO=centos:8
-    - DISTRO=centos:8-stream
-    - DISTRO=fedora:32
-    - DISTRO=fedora:rawhide
-
-script: ./.travis/dracut/dracut-unlocker
-# vim:set ts=2 sw=2 et:

+ 0 - 91
.travis/dracut/centos.cfg.in

@@ -1,91 +0,0 @@
-# Use text mode install
-text
-reboot
-
-%packages
-@^minimal-environment
-%end
-
-# SELinux configuration
-selinux --enforcing
-
-# Keyboard layouts
-keyboard --vckeymap=us-acentos --xlayouts='us (intl)'
-# System language
-lang en_US.UTF-8
-
-# Network information
-network --onboot=yes --device=eth0 --bootproto=static --ip=192.168.122.100 --netmask=255.255.255.0 --gateway=192.168.122.1 --nameserver=192.168.122.1
-network  --hostname=centos
-
-# Use network installation
-url --url=@COMPOSE@
-
-firstboot --enable
-# Do not configure the X Window System
-skipx
-
-# Basic services
-services --enabled=sshd
-
-ignoredisk --only-use=vda
-# Partition clearing information
-clearpart --all --initlabel --drive=vda
-
-# Disk partitioning information
-autopart --type=lvm --nohome --encrypted --luks-version=luks2 --pbkdf=pbkdf2 --pbkdf-iterations=1000  --pbkdf-memory=64 --passphrase=centos
-
-%post --erroronfail --interpreter /bin/bash
-printf "Changing output to TTY 3; press Alt-F3 to view\r\n" > /dev/tty1
-{
-    dnf update -y
-
-    mkdir -m0700 /root/.ssh/
-    cat <<EOF >/root/.ssh/authorized_keys
-@PUBKEY@
-EOF
-    chmod 0600 /root/.ssh/authorized_keys
-    restorecon -R /root/.ssh/
-
-    # Build and install clevis.
-    dnf config-manager -y --set-enabled PowerTools || dnf config-manager -y --set-enabled powertools
-
-    dnf -y install epel-release dnf-utils
-    dnf -y install dracut-network nmap-ncat git meson gcc libjose-devel \
-                   jq libluksmeta-devel jansson-devel cracklib-dicts \
-                   luksmeta jose tpm2-tools
-
-    git clone https://github.com/@TRAVIS_REPO_SLUG@.git @TRAVIS_REPO_SLUG@
-    cd @TRAVIS_REPO_SLUG@
-    git checkout -qf @TRAVIS_COMMIT@
-    mkdir build && pushd build
-    meson .. --prefix=/usr
-    ninja install
-
-    # Setup NBDE.
-    TANG=192.168.122.1
-    curl "${TANG}/adv" -o adv.jws
-    cfg=$(printf '{"url":"%s","adv":"adv.jws"}' "${TANG}")
-
-    for dev in $(lsblk -p -n -s -r | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
-        clevis luks bind -f -d "${dev}" tang "${cfg}" <<< centos
-    done
-
-    mkdir -p /etc/dracut.conf.d/
-    cat <<EOF >/etc/dracut.conf.d/clevis.conf
-kernel_cmdline="rd.neednet=1 ip=192.168.122.100::192.168.122.1:255.255.255.0::eth0:none:192.168.122.1"
-EOF
-
-    dracut -f --regenerate-all
-} 2>&1 | tee /root/postinstall.log > /dev/tty3
-%end
-
-# System timezone
-timezone America/Fortaleza --utc
-
-# Root password
-rootpw --plaintext centos
-
-%addon com_redhat_kdump --disable --reserve-mb='128'
-
-%end

+ 0 - 166
.travis/dracut/dracut-unlocker

@@ -1,166 +0,0 @@
-#!/bin/bash
-set -euo pipefail
-
-export VM=clevis
-
-title() {
-    [ -z "${1}" ] && return 0
-    printf '\n\n\n### %s\n' "${@}"
-    return 0
-}
-
-cmd() {
-    [ -z "${1}" ] && return 0
-    ssh "${VM}" "${@}"
-}
-
-is_unlocked() {
-    dev=${1:-}
-    [ -z "${dev}" ] && echo "ERROR" && return 0
-    luks_uuid="$(cmd cryptsetup luksUUID ${dev} | sed -e 's/-//'g)"
-    if cmd test -b /dev/disk/by-id/dm-uuid-*"${luks_uuid}"*; then
-        echo "YES"
-        return 0
-    fi
-    echo "NO"
-}
-
-wait_for_vm() {
-    local _timeout=${1:-120}
-    echo "[$(date)] Waiting up to ${_timeout} seconds for VM to respond..." >&2
-    local _start _elapsed
-    _start=${SECONDS}
-    while /bin/true; do
-        cmd ls 2>/dev/null >/dev/null && break
-        _elapsed=$((SECONDS - _start))
-        [ "${_elapsed}" -gt "${_timeout}" ] && echo "[$(date)] TIMEOUT reached" >&2 && return 1
-
-        sleep 0.1
-    done
-    _elapsed=$((SECONDS - _start))
-    echo "[$(date)] VM is up in ${_elapsed} seconds!" >&2
-    return 0
-}
-
-setup_host() {
-    ip a >&2
-    free -m >&2
-
-    sudo systemctl restart tangd-update
-}
-
-setup_vm() {
-    CWD="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
-    set -x
-
-    mkdir -p ~/.ssh
-    chmod 700 ~/.ssh
-    ssh-keygen -q -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa <<<y 2>&1 >/dev/null
-    rm -f ~/.ssh/known_hosts
-
-    cat << EOF > ~/.ssh/config
-host clevis
-        user root
-        hostname 192.168.122.100
-        StrictHostKeyChecking no
-        ConnectTimeout 20
-        PasswordAuthentication no
-        PreferredAuthentications publickey
-        GSSAPIAuthentication no
-EOF
-
-    chmod 600 ~/.ssh/config
-    PUBKEY="$(< ~/.ssh/id_rsa.pub)"
-
-    NAME=clevis-vm
-    DATA=/data
-    DISK=${DATA}/disk.qcow2
-
-    KS=${DATA}/ks.cfg
-
-    case "${DISTRO}" in
-    fedora:32)
-        COMPOSE=https://download.fedoraproject.org/pub/fedora/linux/releases/32/Everything/x86_64/os/
-        KS_TEMPLATE=${CWD}/fedora.cfg.in
-        ;;
-    fedora:rawhide)
-        COMPOSE=https://download.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os/
-        KS_TEMPLATE=${CWD}/fedora.cfg.in
-        ;;
-    centos:8)
-        COMPOSE=http://mirror.centos.org/centos/8/BaseOS/x86_64/os/
-        KS_TEMPLATE=${CWD}/centos.cfg.in
-        ;;
-    centos:8-stream)
-        COMPOSE=http://mirror.centos.org/centos/8-stream/BaseOS/x86_64/os/
-        KS_TEMPLATE=${CWD}/centos.cfg.in
-        ;;
-    *)
-        echo "Unsupported distro [${DISTRO}]" >&2
-        exit 1
-        ;;
-    esac
-
-    sudo mkdir -m755 -p "${DATA}"
-    pushd "${DATA}"
-
-    cat "${KS_TEMPLATE}" \
-        | sed -e "s#@PUBKEY@#${PUBKEY}#g" \
-        | sed -e "s#@COMPOSE@#${COMPOSE}#g" \
-        | sed -e "s#@TRAVIS_REPO_SLUG@#${TRAVIS_REPO_SLUG}#g" \
-        | sed -e "s#@TRAVIS_COMMIT@#${TRAVIS_COMMIT}#g" \
-        | sudo tee ${KS}
-
-    sudo chown libvirt-qemu:kvm "${DATA}" -R
-
-    sudo virt-install --name=${NAME} --ram=2048 \
-        --os-variant=generic --os-type=linux --vcpus=1 --graphics=none \
-        --disk=path="${DISK}",size=7,bus=virtio,format=qcow2 \
-        --location="${COMPOSE}" --initrd-inject="${KS}" \
-        --extra-args="ip=dhcp ks=file:/ks.cfg inst.repo=${COMPOSE} net.ifnames=0 biosdevname=0 console=tty0 console=ttyS0,115200n8 serial" \
-        --console pty,target_type=serial --noreboot
-
-    set +x
-}
-
-title "host setup"
-setup_host
-
-title "VM setup"
-setup_vm
-
-# Start VM.
-title "Start VM"
-sudo virsh start "${NAME}"
-
-title "Verify dracut boot unlocker"
-# Check if it booted properly (i.e. unlocked on boot).
-if ! wait_for_vm; then
-    echo "[FAIL] Unable to verify the VM booted properly" >&2
-    exit 1
-fi
-
-title "fstab"
-cmd "cat /etc/fstab"
-
-title "crypttab"
-cmd "cat /etc/crypttab"
-
-title "Block devices"
-cmd "lsblk --fs"
-
-title "LUKS devices"
-
-# Check LUKS devices and config.
-for dev in $(cmd "lsblk -p -n -s -r " \
-            | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
-    echo "DEVICE[${dev}] CONFIG[$(cmd clevis luks list -d ${dev})] UNLOCKED[$(is_unlocked "${dev}")]"
-done
-
-title "clevis-luks-askpass journal"
-
-cmd "journalctl -xe -u clevis-luks-askpass"
-
-echo
-echo "[PASS] Test completed successfully" >&2
-exit 0

+ 0 - 84
.travis/dracut/fedora.cfg.in

@@ -1,84 +0,0 @@
-# Use text mode install
-text
-reboot
-
-%packages
-@^minimal-environment
-%end
-
-# SELinux configuration
-selinux --enforcing
-
-# Keyboard layouts
-keyboard --vckeymap=us-acentos --xlayouts='us (intl)'
-# System language
-lang en_US.UTF-8
-
-# Network information
-network --onboot=yes --device=eth0 --bootproto=static --ip=192.168.122.100 --netmask=255.255.255.0 --gateway=192.168.122.1 --nameserver=192.168.122.1
-network  --hostname=fedora
-firstboot --enable
-# Do not configure the X Window System
-skipx
-
-# Basic services
-services --enabled=sshd
-
-ignoredisk --only-use=vda
-# Partition clearing information
-clearpart --all --initlabel --drive=vda
-
-# Disk partitioning information
-autopart --type=lvm --nohome --encrypted --luks-version=luks2 --pbkdf=pbkdf2 --pbkdf-iterations=1000  --pbkdf-memory=64 --passphrase=fedora
-
-%post --erroronfail --interpreter /bin/bash
-printf "Changing output to TTY 3; press Alt-F3 to view\r\n" > /dev/tty1
-{
-    dnf update -y
-
-    mkdir -m0700 /root/.ssh/
-    cat <<EOF >/root/.ssh/authorized_keys
-@PUBKEY@
-EOF
-    chmod 0600 /root/.ssh/authorized_keys
-    restorecon -R /root/.ssh/
-
-    # Build and install clevis.
-    dnf -y install dnf-utils
-    dnf -y builddep clevis
-    dnf -y install dracut-network nmap-ncat
-
-    git clone https://github.com/@TRAVIS_REPO_SLUG@.git @TRAVIS_REPO_SLUG@
-    cd @TRAVIS_REPO_SLUG@
-    git checkout -qf @TRAVIS_COMMIT@
-    mkdir build && pushd build
-    meson .. --prefix=/usr
-    ninja install
-
-    # Setup NBDE.
-    TANG=192.168.122.1
-    curl "${TANG}/adv" -o adv.jws
-    cfg=$(printf '{"url":"%s","adv":"adv.jws"}' "${TANG}")
-
-    for dev in $(lsblk -p -n -s -r | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
-        clevis luks bind -f -d "${dev}" tang "${cfg}" <<< fedora
-    done
-
-    mkdir -p /etc/dracut.conf.d/
-    cat <<EOF >/etc/dracut.conf.d/clevis.conf
-kernel_cmdline="rd.neednet=1 ip=192.168.122.100::192.168.122.1:255.255.255.0::eth0:none:192.168.122.1"
-EOF
-
-    dracut -f --regenerate-all
-} 2>&1 | tee /root/postinstall.log > /dev/tty3
-%end
-
-# System timezone
-timezone America/Fortaleza --utc
-
-# Root password
-rootpw --plaintext fedora
-
-%addon com_redhat_kdump --disable --reserve-mb='128'
-
-%end

+ 0 - 1
INSTALL.md

@@ -22,7 +22,6 @@ following sections describe them for the supported platforms.
 * [tang](https://github.com/latchset/tang)
 * [curl](https://github.com/curl/curl)
 * [tpm2-tools](https://github.com/tpm2-software/tpm2-tools)
-* [ncat](https://nmap.org/ncat/) (for clevis-luks-askpass)
 
 ### Fedora
 

+ 0 - 1
README.md

@@ -1,5 +1,4 @@
 [![build](https://github.com/latchset/clevis/workflows/build/badge.svg)](https://github.com/latchset/clevis/actions)
-[![dracut](https://img.shields.io/travis/latchset/clevis/master.svg?label=dracut+unlocker)](https://travis-ci.org/latchset/clevis)
 
 # Clevis
 

+ 4 - 2
meson.build

@@ -1,5 +1,7 @@
-project('clevis', 'c', license: 'GPL3+', version: '15',
-        default_options: 'c_std=c99')
+project('clevis', 'c', license: 'GPL3+',
+  version: '16',
+  default_options: 'c_std=c99'
+)
 
 libexecdir = join_paths(get_option('prefix'), get_option('libexecdir'))
 sysconfdir = join_paths(get_option('prefix'), get_option('sysconfdir'))

+ 2 - 1
src/clevis-decrypt

@@ -46,7 +46,8 @@ if ! [ -t 0 ]; then
         exit 1
     fi
 
-    exec "$cmd" < <(echo -n "$hdr."; /bin/cat)
+    (echo -n "$hdr."; /bin/cat) | "$cmd"
+    exit $?
 fi
 
 exec >&2

+ 2 - 0
src/initramfs-tools/hooks/clevis.in

@@ -74,6 +74,8 @@ if [ -x @bindir@/clevis-decrypt-tpm2 ]; then
             copy_exec "${_LIBRARY}" || die 2 "Unable to copy ${_LIBRARY}"
         fi
     done
+    manual_add_modules tpm_crb
+    manual_add_modules tpm_tis
 fi
 
 

+ 128 - 0
src/luks/clevis-luks-bind

@@ -0,0 +1,128 @@
+#!/bin/bash -e
+# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2016 Red Hat, Inc.
+# Author: Harald Hoyer <harald@redhat.com>
+# Author: Nathaniel McCallum <npmccallum@redhat.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+. clevis-luks-common-functions
+
+SUMMARY="Binds a LUKS device using the specified policy"
+
+usage() {
+    exec >&2
+    echo
+    echo "Usage: clevis luks bind [-y] [-f] [-s SLT] [-k KEY] [-t TOKEN_ID] -d DEV PIN CFG"
+    echo
+    echo "$SUMMARY":
+    echo
+    echo "  -f           Do not prompt for LUKSMeta initialization"
+    echo
+    echo "  -d DEV       The LUKS device on which to perform binding"
+    echo
+    echo "  -y           Automatically answer yes for all questions"
+    echo
+    echo "  -s SLT       The LUKS slot to use"
+    echo
+    echo "  -t TKN_ID    The LUKS token ID to use; only available for LUKS2"
+    echo
+    echo "  -k KEY       Non-interactively read LUKS password from KEY file"
+    echo "  -k -         Non-interactively read LUKS password from standard input"
+    echo
+    exit 2
+}
+
+if [ $# -eq 1 ] && [ "$1" = "--summary" ]; then
+    echo "$SUMMARY"
+    exit 0
+fi
+
+FRC=
+YES=
+while getopts ":hfyd:s:k:t:" o; do
+    case "$o" in
+    f) FRC='-f';;
+    d) DEV="$OPTARG";;
+    s) SLT="$OPTARG";;
+    k) KEY="$OPTARG";;
+    t) TOKEN_ID="$OPTARG";;
+    y) FRC='-f'
+       YES='-y';;
+    *) usage;;
+    esac
+done
+
+if [ -z "$DEV" ]; then
+    echo "Did not specify a device!" >&2
+    usage
+fi
+
+if ! luks_type="$(clevis_luks_type "${DEV}")"; then
+    echo "${DEV} is not a supported LUKS device" >&2
+    exit 1
+fi
+
+if ! PIN="${@:$((OPTIND++)):1}" || [ -z "$PIN" ]; then
+    echo "Did not specify a pin!" >&2
+    usage
+elif ! EXE=$(command -v clevis-encrypt-"${PIN}") || [ -z "${EXE}" ]; then
+    echo "'${PIN}' is not a valid pin!" >&2
+    usage
+fi
+
+if ! CFG="${@:$((OPTIND++)):1}" || [ -z "$CFG" ]; then
+    echo "Did not specify a pin config!" >&2
+    usage
+fi
+
+
+if [ "${luks_type}" = "luks1" ] && [ -n "${TOKEN_ID}" ]; then
+    echo "${DEV} is a LUKS1 device; -t is only supported in LUKS2" >&2
+    exit 1
+fi
+
+# Get the existing passphrase/keyfile.
+existing_key=
+keyfile=
+case "${KEY}" in
+"") IFS= read -r -s -p "Enter existing LUKS password: " existing_key; echo >&2;;
+ -) IFS= read -r -s -p "" existing_key ||:
+    if [ "${luks_type}" = "luks1" ] && ! luksmeta test -d "${DEV}" \
+                                    && [ -z "${FRC}" ]; then
+        echo "Cannot use '-k-' without '-f' or '-y' unless already initialized!" >&2
+        usage
+    fi
+    ;;
+ *) keyfile="${KEY}"
+    if [ ! -r "${keyfile}" ]; then
+        echo "Cannot read key file '${keyfile}'" >&2
+        exit 1
+    fi
+    ;;
+esac
+
+# If necessary, initialize the LUKS volume.
+if [ "${luks_type}" = "luks1" ] && ! luksmeta test -d "${DEV}"; then
+    luksmeta init -d "${DEV}" ${FRC}
+fi
+
+if ! clevis_luks_do_bind "${DEV}" "${SLT}" "" \
+                         "${PIN}" "${CFG}" \
+                         "${YES}" "" \
+                         "${existing_key}" "${keyfile}"; then
+    echo "Error adding new binding to ${DEV}" >&2
+    exit 1
+fi

+ 0 - 236
src/luks/clevis-luks-bind.in

@@ -1,236 +0,0 @@
-#!/bin/bash -e
-# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
-#
-# Copyright (c) 2016 Red Hat, Inc.
-# Author: Harald Hoyer <harald@redhat.com>
-# Author: Nathaniel McCallum <npmccallum@redhat.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-SUMMARY="Binds a LUKS device using the specified policy"
-UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
-
-# We require cryptsetup >= 2.0.4 to fully support LUKSv2.
-# Support is determined at build time.
-function luks2_supported() {
-    return @OLD_CRYPTSETUP@
-}
-
-function usage() {
-    exec >&2
-    echo
-    echo "Usage: clevis luks bind [-y] [-f] [-s SLT] [-k KEY] [-t TOKEN_ID] -d DEV PIN CFG"
-    echo
-    echo "$SUMMARY":
-    echo
-    echo "  -f           Do not prompt for LUKSMeta initialization"
-    echo
-    echo "  -d DEV       The LUKS device on which to perform binding"
-    echo
-    echo "  -y           Automatically answer yes for all questions"
-    echo
-    echo "  -s SLT       The LUKS slot to use"
-    echo
-    echo "  -t TKN_ID    The LUKS token ID to use; only available for LUKS2"
-    echo
-    echo "  -k KEY       Non-interactively read LUKS password from KEY file"
-    echo "  -k -         Non-interactively read LUKS password from standard input"
-    echo
-    exit 2
-}
-
-if [ $# -eq 1 ] && [ "$1" == "--summary" ]; then
-    echo "$SUMMARY"
-    exit 0
-fi
-
-FRC=()
-YES=()
-while getopts ":hfyd:s:k:t:" o; do
-    case "$o" in
-    f) FRC+=(-f);;
-    d) DEV="$OPTARG";;
-    s) SLT="$OPTARG";;
-    k) KEY="$OPTARG";;
-    t) TOKEN_ID="$OPTARG";;
-    y) FRC+=(-f)
-       YES+=(-y);;
-    *) usage;;
-    esac
-done
-
-if [ -z "$DEV" ]; then
-    echo "Did not specify a device!" >&2
-    usage
-fi
-
-if ! cryptsetup isLuks "$DEV"; then
-    echo "$DEV is not a LUKS device!" >&2
-    exit 1
-fi
-
-if ! PIN="${@:$((OPTIND++)):1}" || [ -z "$PIN" ]; then
-    echo "Did not specify a pin!" >&2
-    usage
-elif ! EXE=$(command -v clevis-encrypt-"${PIN}") || [ -z "${EXE}" ]; then
-    echo "'${PIN}' is not a valid pin!" >&2
-    usage
-fi
-
-if ! CFG="${@:$((OPTIND++)):1}" || [ -z "$CFG" ]; then
-    echo "Did not specify a pin config!" >&2
-    usage
-fi
-
-if luks2_supported; then
-    if cryptsetup isLuks --type luks1 "$DEV"; then
-        luks_type="luks1"
-    elif cryptsetup isLuks --type luks2 "$DEV";then
-        luks_type="luks2"
-    else
-        echo "$DEV is not a supported LUKS device!" >&2
-        exit 1
-    fi
-else
-    luks_type="luks1"
-fi
-
-if [ "$luks_type" = "luks1" -a -n "$TOKEN_ID" ]; then
-    echo "$DEV is a LUKS1 device; -t is only supported in LUKS2"
-    exit 1
-fi
-
-if [ "${luks_type}" = "luks1" ]; then
-    # The first free slot, as per cryptsetup. In connection to bug #70, we may
-    # have to wipe out the LUKSMeta slot priot to adding the new key.
-    first_free_cs_slot=$(cryptsetup luksDump "${DEV}" \
-                         | sed -rn 's|^Key Slot ([0-7]): DISABLED$|\1|p' \
-                         | sed -n 1p)
-    if [ -z "${first_free_cs_slot}" ]; then
-        echo "There are no more free slots in ${DEV}!" >&2
-        exit 1
-    fi
-fi
-
-if [ -n "$KEY" ]; then
-    if [ "$KEY" == "-" ]; then
-        if [ "$luks_type" == "luks1" ]; then
-            if ! luksmeta test -d "$DEV" && [ -z "${FRC[*]}" ]; then
-                echo "Cannot use '-k-' without '-f' unless already initialized!" >&2
-                usage
-            fi
-        fi
-    elif ! [ -f "$KEY" ]; then
-        echo "Key file '$KEY' not found!" >&2
-        exit 1
-    fi
-fi
-
-# Generate a key with the same entropy as the LUKS Master Key
-key="$(pwmake "$(
-cryptsetup luksDump "$DEV" \
-    | if [ "$luks_type" == "luks1" ]; then
-        sed -rn 's|MK bits:[ \t]*([0-9]+)|\1|p'
-    else
-        sed -rn 's|^\s+Key:\s+([0-9]+) bits\s*$|\1|p'
-    fi | sort -n | tail -n 1
-)")"
-
-# Encrypt the new key
-jwe="$(echo -n "$key" | clevis encrypt "$PIN" "$CFG" "${YES}")"
-
-# If necessary, initialize the LUKS volume
-if [ "$luks_type" == "luks1" ] && ! luksmeta test -d "$DEV"; then
-    luksmeta init -d "$DEV" "${FRC[@]}"
-fi
-
-# Get the existing key.
-case "$KEY" in
-"") read -r -s -p "Enter existing LUKS password: " existing_key; echo;;
- -) existing_key="$(/bin/cat)";;
- *) ! IFS= read -rd '' existing_key < "$KEY";;
-esac
-
-# Check if the key is valid.
-if ! cryptsetup luksOpen --test-passphrase "${DEV}" \
-        --key-file <(echo -n "${existing_key}"); then
-    exit 1
-fi
-
-if [ "$luks_type" == "luks1" ]; then
-    # In certain circumstances, we may have LUKSMeta slots "not in sync" with
-    # cryptsetup, which means we will try to save LUKSMeta metadata over an
-    # already used or partially used slot -- github issue #70.
-    # If that is the case, let's wipe the LUKSMeta slot here prior to saving.
-    if read -r _ state uuid < <(luksmeta show -d "${DEV}" \
-            | grep "^${first_free_cs_slot} *"); then
-        if [ "${state}" = "inactive" ] && [ "${uuid}" = "${UUID}" ]; then
-            luksmeta wipe -f -d "${DEV}" -s "${first_free_cs_slot}"
-        fi
-    fi
-fi
-
-# Add the new key.
-if [ -n "$SLT" ]; then
-    cryptsetup luksAddKey --key-slot "$SLT" --key-file \
-        <(echo -n "$existing_key") "$DEV"
-else
-    if [ $luks_type == "luks2" ]; then
-        readarray -t usedSlotsBeforeAddKey < <(cryptsetup luksDump "${DEV}" \
-            | sed -rn 's|^\s+([0-9]+): luks2$|\1|p')
-    else
-        readarray -t usedSlotsBeforeAddKey < <(cryptsetup luksDump "${DEV}" \
-            | sed -rn 's|^Key Slot ([0-7]): ENABLED$|\1|p')
-    fi
-    cryptsetup luksAddKey --key-file <(echo -n "${existing_key}") "$DEV"
-fi < <(echo -n "${key}")
-if [ $? -ne 0 ]; then
-    echo "Error while adding new key to LUKS header!" >&2
-    exit 1
-fi
-
-#Determine slot used by new key if a desired slot was not specified
-if [ -z "$SLT" ]; then
-    if [ "$luks_type" == "luks2" ]; then
-        readarray -t usedSlotsAfterAddKey < <(cryptsetup luksDump "${DEV}" \
-            | sed -rn 's|^\s+([0-9]+): luks2$|\1|p')
-    else
-        readarray -t usedSlotsAfterAddKey < <(cryptsetup luksDump "${DEV}" \
-            | sed -rn 's|^Key Slot ([0-7]): ENABLED$|\1|p')
-    fi
-    for i in "${usedSlotsAfterAddKey[@]}"; do
-        if [[ ! " ${usedSlotsBeforeAddKey[@]} " =~ " ${i} " ]]; then
-            SLT=$i
-            break
-        fi
-    done
-fi
-
-if [ -z "$SLT" ]; then
-	echo "Error while adding new key to LUKS header! Key slot is undefined." >&2
-	exit 1
-fi
-
-if [ "$luks_type" == "luks1" ]; then
-    echo -n "$jwe" | luksmeta save -d "$DEV" -u "$UUID" -s "$SLT" 2>/dev/null
-else
-    printf '{"type":"clevis","keyslots":["%s"],"jwe":%s}' "$SLT" "$(jose jwe fmt -i- <<< "$jwe")" \
-        | cryptsetup token import $([ -n "$TOKEN_ID" ] && echo '--token-id '$TOKEN_ID) "$DEV"
-fi
-if [ $? -ne 0 ]; then
-    echo "Error while saving Clevis metadata in LUKSMeta!" >&2
-    echo -n "$key" | cryptsetup luksRemoveKey "$DEV"
-    exit 1
-fi

+ 25 - 2
src/luks/clevis-luks-common-functions

@@ -683,7 +683,7 @@ clevis_luks_get_existing_key() {
     fi
 
     # Let's prompt the user for the password.
-    read -r -s -p "${PROMPT}" pt; echo >&2
+    IFS= read -r -s -p "${PROMPT}" pt; echo >&2
 
     # Check if key is valid.
     clevis_luks_check_valid_key_or_keyfile "${DEV}" "${pt}" || return 1
@@ -929,7 +929,7 @@ clevis_luks_do_bind() {
                                                 "${KEYFILE}" \
                     && ! KEY="$(clevis_luks_get_existing_key "${DEV}" \
                                 "Enter existing LUKS password: " \
-                                "recover")" || [ -z "${KEY}" ]; then
+                                "recover")"; then
         return 1
     fi
 
@@ -990,3 +990,26 @@ clevis_luks_do_bind() {
     trap - EXIT
     return 0
 }
+
+# clevis_luks_luks2_supported() indicates whether we support LUKS2 devices.
+# Suppor is determined at build time.
+function clevis_luks_luks2_supported() {
+    # We require cryptsetup >= 2.0.4 to fully support LUKSv2.
+    return @OLD_CRYPTSETUP@
+}
+
+# clevis_luks_type() returns the LUKS type of a device, e.g. "luks1".
+clevis_luks_type() {
+    local DEV="${1}"
+    [ -z "${DEV}" ] && return 1
+    local luks_type
+    if cryptsetup isLuks --type luks1 "${DEV}"; then
+        luks_type="luks1"
+    elif cryptsetup isLuks --type luks2 "${DEV}"; then
+        clevis_luks_luks2_supported "${DEV}" || return 1
+        luks_type="luks2"
+    else
+        return 1
+    fi
+    echo "${luks_type}"
+}

+ 64 - 0
src/luks/clevis-luks-pass

@@ -0,0 +1,64 @@
+#!/bin/bash -e
+# vim: set ts=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/>.
+#
+
+. clevis-luks-common-functions
+
+SUMMARY="Returns the LUKS passphrase used for binding a particular slot."
+
+usage() {
+    exec >&2
+    echo "Usage: clevis luks pass -d DEV -s SLT"
+    echo
+    echo "$SUMMARY"
+    echo
+    echo "  -d DEV  The LUKS device to extract the LUKS passphrase used for binding"
+    echo
+    echo "  -s SLOT The slot number to extract the LUKS passphrase"
+    echo
+    exit 1
+}
+
+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 ! clevis_luks_unlock_device_by_slot "${DEV}" "${SLT}"; then
+    echo "It was not possible to decrypt the passphrase associated to slot ${SLT} in ${DEV}!" >&2
+    exit 1
+fi

+ 42 - 0
src/luks/clevis-luks-pass.1.adoc

@@ -0,0 +1,42 @@
+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)],

+ 1 - 1
src/luks/clevis-luks-unlock

@@ -65,4 +65,4 @@ if ! pt=$(clevis_luks_unlock_device "${DEV}"); then
     exit 1
 fi
 
-cryptsetup open -d- "${DEV}" "${NAME}" < <(echo -n "${pt}")
+echo -n "${pt}" | cryptsetup open -d- "${DEV}" "${NAME}"

+ 10 - 5
src/luks/meson.build

@@ -14,9 +14,11 @@ else
     endif
 endif
 
-clevis_luks_bind = configure_file(input: 'clevis-luks-bind.in',
-               output: 'clevis-luks-bind',
-               configuration: luksmeta_data)
+clevis_luks_common_functions = configure_file(
+  input: 'clevis-luks-common-functions.in',
+  output: 'clevis-luks-common-functions',
+  configuration: luksmeta_data
+)
 
 clevis_luks_unbind = configure_file(input: 'clevis-luks-unbind.in',
                output: 'clevis-luks-unbind',
@@ -29,12 +31,12 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found()
   bins += clevis_luks_unbind
   mans += join_paths(meson.current_source_dir(), 'clevis-luks-unbind.1')
 
-  bins += clevis_luks_bind
+  bins += join_paths(meson.current_source_dir(), 'clevis-luks-bind')
   mans += join_paths(meson.current_source_dir(), 'clevis-luks-bind.1')
 
   mans += join_paths(meson.current_source_dir(), 'clevis-luks-unlockers.7')
 
-  bins += join_paths(meson.current_source_dir(), 'clevis-luks-common-functions')
+  bins += clevis_luks_common_functions
 
   bins += join_paths(meson.current_source_dir(), 'clevis-luks-list')
   mans += join_paths(meson.current_source_dir(), 'clevis-luks-list.1')
@@ -50,6 +52,9 @@ if libcryptsetup.found() and luksmeta.found() and pwmake.found()
 
   bins += join_paths(meson.current_source_dir(), 'clevis-luks-edit')
   mans += join_paths(meson.current_source_dir(), 'clevis-luks-edit.1')
+
+  bins += join_paths(meson.current_source_dir(), 'clevis-luks-pass')
+  mans += join_paths(meson.current_source_dir(), 'clevis-luks-pass.1')
 else
   warning('Will not install LUKS support due to missing dependencies!')
 endif

+ 1 - 1
src/luks/systemd/clevis-luks-askpass

@@ -58,7 +58,7 @@ while true; do
         fi
 
         uuid="$(cryptsetup luksUUID "${d}")"
-        if ! printf '+%s' "${pt}" | ncat -U -u --send-only "${s}"; then
+        if ! printf '%s' "${pt}" | @SYSTEMD_REPLY_PASS@ 1 "${s}"; then
             echo "Unable to unlock ${d} (UUID=${uuid}) with recovered passphrase" >&2
             continue
         fi

+ 2 - 2
src/luks/systemd/dracut/clevis/module-setup.sh.in

@@ -36,6 +36,7 @@ install() {
 
     inst_multiple \
         /etc/services \
+        @SYSTEMD_REPLY_PASS@ \
         @libexecdir@/clevis-luks-askpass \
         clevis-luks-common-functions \
         grep sed cut \
@@ -45,8 +46,7 @@ install() {
         luksmeta \
         clevis \
         mktemp \
-        jose \
-        ncat
+        jose
 
     dracut_need_initqueue
 }

+ 17 - 2
src/luks/systemd/meson.build

@@ -1,6 +1,15 @@
 systemd = dependency('systemd', required: false)
 
-if systemd.found()
+sd_reply_pass = find_program(
+  join_paths(get_option('prefix'), get_option('libdir'), 'systemd', 'systemd-reply-password'),
+  join_paths(get_option('prefix'), 'lib', 'systemd', 'systemd-reply-password'),
+  join_paths('/', 'usr', get_option('libdir'), 'systemd', 'systemd-reply-password'),
+  join_paths('/', 'usr', 'lib', 'systemd', 'systemd-reply-password'),
+  required: false
+)
+
+if systemd.found() and sd_reply_pass.found()
+  data.set('SYSTEMD_REPLY_PASS', sd_reply_pass.path())
   subdir('dracut')
 
   unitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
@@ -12,8 +21,14 @@ if systemd.found()
     configuration: data,
   )
 
+  configure_file(
+    input: 'clevis-luks-askpass.in',
+    output: 'clevis-luks-askpass',
+    install_dir: libexecdir,
+    configuration: data
+  )
+
   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

+ 6 - 7
src/luks/tests/assume-yes

@@ -33,11 +33,10 @@ trap 'on_exit' ERR
 
 TMP="$(mktemp -d)"
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 cfg=$(printf '{"url":"%s"}' "$url")
 
 test_tang() {
@@ -50,7 +49,7 @@ test_tang() {
                    | clevis decrypt)"; then
             error "${TEST}: tang - encrypt should succeed."
         fi
-        if ["${pt}" != "${data}" ]; then
+        if [ "${pt}" != "${data}" ]; then
             error "${TEST}: tang - pt(${pt}) != data("${data}")."
         fi
     done
@@ -68,7 +67,7 @@ test_sss() {
                    | clevis decrypt)"; then
             error "${TEST}: sss1 - encrypt should succeed."
         fi
-        if ["${pt}" != "${data}" ]; then
+        if [ "${pt}" != "${data}" ]; then
             error "${TEST}: sss1 - pt(${pt}) != data("${data}")."
         fi
 
@@ -76,7 +75,7 @@ test_sss() {
                    | clevis decrypt)"; then
             error "${TEST}: sss2 - encrypt should succeed."
         fi
-        if ["${pt}" != "${data}" ]; then
+        if [ "${pt}" != "${data}" ]; then
             error "${TEST}: sss2 - pt(${pt}) != data("${data}")."
         fi
     done

+ 3 - 4
src/luks/tests/assume-yes-luks2

@@ -33,11 +33,10 @@ trap 'on_exit' ERR
 
 TMP="$(mktemp -d)"
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 cfg=$(printf '{"url":"%s"}' "$url")
 
 # LUKS2.

+ 1 - 1
src/luks/tests/backup-restore-luks1

@@ -31,7 +31,7 @@ trap 'on_exit' EXIT
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 
 # LUKS1.

+ 1 - 1
src/luks/tests/backup-restore-luks2

@@ -31,7 +31,7 @@ trap 'on_exit' EXIT
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 
 # LUKS1.

+ 1 - 1
src/luks/tests/bind-already-used-luksmeta-slot

@@ -31,7 +31,7 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 
 # LUKS1.

+ 58 - 0
src/luks/tests/bind-binary-keyfile-luks1

@@ -0,0 +1,58 @@
+#!/bin/bash -ex
+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2020 Red Hat, Inc.
+# Author: Sergio Correia <scorreia@redhat.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+TEST="${0}"
+. tests-common-functions
+. clevis-luks-common-functions
+
+on_exit() {
+    local exit_status=$?
+    tang_stop "${TMP}"
+    [ -d "${TMP}" ] && rm -rf "${TMP}"
+    exit "${exit_status}"
+}
+
+trap 'on_exit' EXIT
+
+TMP="$(mktemp -d)"
+
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
+
+url="http://localhost:${port}"
+ADV="${TMP}/adv.jws"
+tang_get_adv "${port}" "${ADV}"
+CFG="$(printf '{"url":"%s","adv":"%s"}' "${url}" "$ADV")"
+
+# LUKS1.
+DEV="${TMP}/luks1-device"
+KEYFILE="${TMP}/key"
+
+# Using a binary key file.
+dd if=/dev/urandom bs=4096 count=1 2>/dev/null > "${KEYFILE}"
+
+new_device_keyfile "luks1" "${DEV}" "${KEYFILE}"
+if ! clevis luks bind -f -k "${KEYFILE}" -d "${DEV}" tang "${CFG}"; then
+    error "${TEST}: Binding is expected to succeed when given a correct (${KEYFILE}) keyfile."
+fi
+
+if ! clevis_luks_unlock_device "${DEV}" >/dev/null; then
+    error "${TEST}: Unlock of ${DEV} is expected to work."
+fi

+ 26 - 13
src/luks/tests/bind-key-file-non-interactive-luks1

@@ -31,29 +31,42 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e"
 KEYFILE="${TMP}/key"
-PASS=$(openssl rand -hex 8)
+PASS=$(new_passphrase)
 echo -n "${PASS}" > "${KEYFILE}"
 
 # LUKS1.
 DEV="${TMP}/luks1-device"
 new_device_keyfile "luks1" "${DEV}" "${KEYFILE}"
-if ! clevis luks bind -f -k "${KEYFILE}" -d "${DEV}" tang "${CFG}"; then
-    error "${TEST}: Binding is expected to succeed when given a correct (${KEYFILE})." >&2
-fi
 
-SLT=1
-if ! read -r _ state uuid < <(luksmeta show -d "${DEV}" | grep "^${SLT} *"); then
-    error "${TEST}: Error reading LUKSmeta info for slot ${SLT} of ${DEV}." >&2
-fi
+verify_bind() {
+    local TDEV=${1}
+    local TSLT=${2}
+    local state uuid
+
+    if ! read -r _ state uuid < <(luksmeta show -d "${TDEV}" | grep "^${TSLT} *"); then
+        error "${TEST}: Error reading LUKSmeta info for slot ${TSLT} of ${TDEV}." >&2
+    fi
 
-if [ "${state}" != "active" ]; then
-    error "${TEST}: state (${state}) is expected to be 'active'." >&2
+    if [ "${state}" != "active" ]; then
+        error "${TEST}: state (${state}) is expected to be 'active'." >&2
+    fi
+
+    if [ "${uuid}" != "${UUID}" ]; then
+        error "${TEST}: UUID ($uuid) is expected to be '${UUID}'." >&2
+    fi
+}
+
+if ! clevis luks bind -f -k "${KEYFILE}" -d "${DEV}" tang "${CFG}"; then
+    error "${TEST}: Binding is expected to succeed when given a correct keyfile (${KEYFILE})." >&2
 fi
+verify_bind "${DEV}" "1"
 
-if [ "${uuid}" != "${UUID}" ]; then
-    error "${TEST}: UUID ($uuid) is expected to be '${UUID}'." >&2
+# Now let's pass the keyfile via stdin, non-interactively.
+if ! echo -n "${PASS}" | clevis luks bind -f -k- -d "${DEV}" tang "${CFG}"; then
+    error "${TEST}: Binding is expected to succeed when given a correct passphrase (${PASS})." >&2
 fi
+verify_bind "${DEV}" "2"

+ 1 - 1
src/luks/tests/bind-luks1

@@ -31,7 +31,7 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 
 # LUKS1.

+ 1 - 1
src/luks/tests/bind-luks2

@@ -35,7 +35,7 @@ fi
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 
 # LUKS2.

+ 1 - 1
src/luks/tests/bind-pass-with-newline-keyfile-luks1

@@ -31,7 +31,7 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 
 # LUKS1.

+ 1 - 1
src/luks/tests/bind-pass-with-newline-luks1

@@ -31,7 +31,7 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 
 # LUKS1.

+ 1 - 1
src/luks/tests/bind-wrong-pass-luks1

@@ -31,7 +31,7 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 
 # LUKS1.

+ 1 - 1
src/luks/tests/bind-wrong-pass-luks2

@@ -35,7 +35,7 @@ fi
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 
 # LUKS2.

+ 6 - 8
src/luks/tests/edit-tang-luks1

@@ -36,11 +36,10 @@ trap 'on_exit' ERR
 
 TMP="$(mktemp -d)"
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 
 cfg=$(printf '{"url":"%s"}' "${url}")
 
@@ -65,11 +64,10 @@ fi
 
 # Now let's have another tang instance running and change the config to use
 # the new one.
-port2=$(get_random_port)
+port2=$(tang_new_random_port)
 TMP2="$(mktemp -d)"
-tang_run "${TMP2}" "${port2}" &
-tang_wait_until_ready "${port2}"
-new_url="http://${TANG_HOST}:${port2}"
+tang_run "${TMP2}" "${port2}"
+new_url="http://localhost:${port2}"
 new_cfg=$(printf '{"url":"%s"}' "${new_url}")
 
 if ! clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then

+ 6 - 8
src/luks/tests/edit-tang-luks2

@@ -36,11 +36,10 @@ trap 'on_exit' ERR
 
 TMP="$(mktemp -d)"
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 
 cfg=$(printf '{"url":"%s"}' "${url}")
 
@@ -65,11 +64,10 @@ fi
 
 # Now let's have another tang instance running and change the config to use
 # the new one.
-port2=$(get_random_port)
+port2=$(tang_new_random_port)
 TMP2="$(mktemp -d)"
-tang_run "${TMP2}" "${port2}" &
-tang_wait_until_ready "${port2}"
-new_url="http://${TANG_HOST}:${port2}"
+tang_run "${TMP2}" "${port2}"
+new_url="http://localhost:${port2}"
 new_cfg=$(printf '{"url":"%s"}' "${new_url}")
 
 if ! clevis luks edit -d "${DEV}" -s 1 -c "${new_cfg}"; then

+ 1 - 1
src/luks/tests/list-recursive-luks1

@@ -31,7 +31,7 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 PIN="sss"
 CFG=$(printf '
 {

+ 1 - 1
src/luks/tests/list-recursive-luks2

@@ -31,7 +31,7 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 PIN="sss"
 CFG=$(printf '
 {

+ 1 - 1
src/luks/tests/list-sss-tang-luks1

@@ -31,7 +31,7 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 PIN="sss"
 CFG=$(printf '
 {

+ 1 - 1
src/luks/tests/list-sss-tang-luks2

@@ -31,7 +31,7 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 PIN="sss"
 CFG=$(printf '
 {

+ 1 - 1
src/luks/tests/list-tang-luks1

@@ -31,7 +31,7 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 PIN="tang"
 CFG=$(printf '{"url": "ADDR","adv": "%s"}' "${ADV}")
 

+ 1 - 1
src/luks/tests/list-tang-luks2

@@ -31,7 +31,7 @@ trap 'exit' ERR
 TMP="$(mktemp -d)"
 
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 PIN="tang"
 CFG=$(printf '{"url": "ADDR","adv": "%s"}' "${ADV}")
 

+ 19 - 61
src/luks/tests/meson.build

@@ -1,39 +1,6 @@
 # We use jq for comparing the pin config in the clevis luks list tests.
 jq = find_program('jq', required: false)
 
-# We use systemd-socket-activate for running test tang servers.
-actv = find_program(
-  'systemd-socket-activate',
-  'systemd-activate',
-  join_paths('/', 'usr', 'lib', 'systemd', 'systemd-activate'),
-  required: false
-)
-
-kgen = find_program(
-  join_paths(libexecdir, 'tangd-keygen'),
-  join_paths(get_option('prefix'), get_option('libdir'), 'tangd-keygen'),
-  join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd-keygen'),
-  join_paths('/', 'usr', get_option('libdir'), 'tangd-keygen'),
-  join_paths('/', 'usr', get_option('libexecdir'), 'tangd-keygen'),
-  required: false
-)
-updt = find_program(
-  join_paths(libexecdir, 'tangd-update'),
-  join_paths(get_option('prefix'), get_option('libdir'), 'tangd-update'),
-  join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd-update'),
-  join_paths('/', 'usr', get_option('libdir'), 'tangd-update'),
-  join_paths('/', 'usr', get_option('libexecdir'), 'tangd-update'),
-  required: false
-)
-tang = find_program(
-  join_paths(libexecdir, 'tangd'),
-  join_paths(get_option('prefix'), get_option('libdir'), 'tangd'),
-  join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd'),
-  join_paths('/', 'usr', get_option('libdir'), 'tangd'),
-  join_paths('/', 'usr', get_option('libexecdir'), 'tangd'),
-  required: false
-)
-
 common_functions = configure_file(input: 'tests-common-functions.in',
   output: 'tests-common-functions',
   configuration: luksmeta_data,
@@ -53,19 +20,11 @@ env.prepend('PATH',
   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', 'tang', 'tests'),
   join_paths(meson.build_root(), 'src', 'pins', 'tpm2'),
   separator: ':'
 )
 
-has_tang = false
-if actv.found() and kgen.found() and updt.found() and tang.found()
-  has_tang = true
-  env.set('SD_ACTIVATE', actv.path())
-  env.set('TANGD_KEYGEN', kgen.path())
-  env.set('TANGD_UPDATE', updt.path())
-  env.set('TANGD', tang.path())
-endif
-
 test('bind-wrong-pass-luks1', find_program('bind-wrong-pass-luks1'), env: env)
 test('bind-luks1', find_program('bind-luks1'), env: env)
 test('unbind-unbound-slot-luks1', find_program('unbind-unbound-slot-luks1'), env: env)
@@ -73,6 +32,7 @@ test('unbind-luks1', find_program('unbind-luks1'), env: env)
 test('bind-key-file-non-interactive', find_program('bind-key-file-non-interactive-luks1'), env: env)
 test('bind-pass-with-newline', find_program('bind-pass-with-newline-luks1'), env: env)
 test('bind-pass-with-newline-keyfile', find_program('bind-pass-with-newline-keyfile-luks1'), env: env)
+test('bind-binary-keyfile', find_program('bind-binary-keyfile-luks1'), env: env)
 # Bug #70.
 test('bind-already-used-luksmeta-slot', find_program('bind-already-used-luksmeta-slot'), env: env, timeout: 60)
 test('bad-sss', find_program('bad-sss'), env: env)
@@ -85,17 +45,16 @@ else
   warning('Will not run "clevis luks list" tests due to missing jq dependency')
 endif
 
-if has_tang
-  test('unlock-tang-luks1', find_program('unlock-tang-luks1'), env: env, timeout: 90)
-  test('assume-yes', find_program('assume-yes'), env: env, timeout: 60)
-  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)
-  test('report-tang-luks1', find_program('report-tang-luks1'), env: env, timeout: 90)
-  test('report-sss-luks1', find_program('report-sss-luks1'), env: env, timeout: 90)
-  test('edit-tang-luks1', find_program('edit-tang-luks1'), env: env, timeout: 150)
-endif
+test('unlock-tang-luks1', find_program('unlock-tang-luks1'), env: env, timeout: 90)
+test('assume-yes', find_program('assume-yes'), env: env, timeout: 60)
+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)
+test('report-tang-luks1', find_program('report-tang-luks1'), env: env, timeout: 90)
+test('report-sss-luks1', find_program('report-sss-luks1'), env: env, timeout: 90)
+test('edit-tang-luks1', find_program('edit-tang-luks1'), env: env, timeout: 150)
 
 test('backup-restore-luks1', find_program('backup-restore-luks1'), env: env, timeout: 60)
+test('pass-tang-luks1', find_program('pass-tang-luks1'), env: env, timeout: 60)
 
 # LUKS2 tests go here, and they get included if we get support for it, based
 # on the cryptsetup version.
@@ -112,15 +71,14 @@ if luksmeta_data.get('OLD_CRYPTSETUP') == '0'
     test('list-sss-tang-luks2', find_program('list-sss-tang-luks2'), env: env, timeout: 60)
   endif
 
-  if has_tang
-    test('unlock-tang-luks2', find_program('unlock-tang-luks2'), env: env, timeout: 120)
-    test('assume-yes-luks2', find_program('assume-yes-luks2'), env: env, timeout: 90)
-    test('regen-inplace-luks2', find_program('regen-inplace-luks2'), env: env, timeout: 120)
-    test('regen-not-inplace-luks2', find_program('regen-not-inplace-luks2'), env: env, timeout: 120)
-    test('report-tang-luks2', find_program('report-tang-luks2'), env: env, timeout: 120)
-    test('report-sss-luks2', find_program('report-sss-luks2'), env: env, timeout: 120)
-    test('edit-tang-luks2', find_program('edit-tang-luks2'), env: env, timeout: 210)
-  endif
+  test('unlock-tang-luks2', find_program('unlock-tang-luks2'), env: env, timeout: 120)
+  test('assume-yes-luks2', find_program('assume-yes-luks2'), env: env, timeout: 90)
+  test('regen-inplace-luks2', find_program('regen-inplace-luks2'), env: env, timeout: 120)
+  test('regen-not-inplace-luks2', find_program('regen-not-inplace-luks2'), env: env, timeout: 120)
+  test('report-tang-luks2', find_program('report-tang-luks2'), env: env, timeout: 120)
+  test('report-sss-luks2', find_program('report-sss-luks2'), env: env, timeout: 120)
+  test('edit-tang-luks2', find_program('edit-tang-luks2'), env: env, timeout: 210)
 
-test('backup-restore-luks2', find_program('backup-restore-luks2'), env: env, timeout: 120)
+  test('backup-restore-luks2', find_program('backup-restore-luks2'), env: env, timeout: 120)
+  test('pass-tang-luks2', find_program('pass-tang-luks2'), env: env, timeout: 60)
 endif

+ 58 - 0
src/luks/tests/pass-tang-luks1

@@ -0,0 +1,58 @@
+#!/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=$(basename "${0}")
+. tests-common-functions
+. clevis-luks-common-functions
+
+on_exit() {
+    [ ! -d "${TMP}" ] && return 0
+    tang_stop "${TMP}"
+    rm -rf "${TMP}"
+}
+
+trap 'on_exit' EXIT
+
+TMP=$(mktemp -d)
+
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
+
+url="http://localhost:${port}"
+adv="${TMP}/adv"
+tang_get_adv "${port}" "${adv}"
+
+cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv")
+
+# LUKS1.
+DEV="${TMP}/luks1-device"
+new_device "luks1" "${DEV}"
+
+if ! clevis luks bind -f -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then
+    error "${TEST}: Bind should have succeeded."
+fi
+
+# Now let's test the passphrase.
+SLT=1
+PASS=$(clevis luks pass -d "${DEV}" -s "${SLT}")
+echo $PASS >&2
+if ! clevis_luks_check_valid_key_or_keyfile "${DEV}" "${PASS}" "" "${SLT}"; then
+    error "Passphrase obtained from clevis luks pass failed."
+fi

+ 58 - 0
src/luks/tests/pass-tang-luks2

@@ -0,0 +1,58 @@
+#!/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
+. clevis-luks-common-functions
+
+on_exit() {
+    [ ! -d "${TMP}" ] && return 0
+    tang_stop "${TMP}"
+    rm -rf "${TMP}"
+}
+
+trap 'on_exit' EXIT
+
+TMP=$(mktemp -d)
+
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
+
+url="http://localhost:${port}"
+adv="${TMP}/adv"
+tang_get_adv "${port}" "${adv}"
+
+cfg=$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv")
+
+# LUKS2.
+DEV="${TMP}/luks2-device"
+new_device "luks2" "${DEV}"
+
+if ! clevis luks bind -f -d "${DEV}" tang "${cfg}" <<< "${DEFAULT_PASS}"; then
+    error "${TEST}: Bind should have succeeded."
+fi
+
+# Now let's test the passphrase.
+SLT=1
+PASS=$(clevis luks pass -d "${DEV}" -s "${SLT}")
+echo $PASS >&2
+if ! clevis_luks_check_valid_key_or_keyfile "${DEV}" "${PASS}" "" "${SLT}"; then
+    error "Passphrase obtained from clevis luks pass failed."
+fi

+ 3 - 4
src/luks/tests/regen-inplace-luks1

@@ -32,11 +32,10 @@ trap 'on_exit' EXIT
 
 TMP=$(mktemp -d)
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 adv="${TMP}/adv"
 tang_get_adv "${port}" "${adv}"
 

+ 3 - 4
src/luks/tests/regen-inplace-luks2

@@ -32,11 +32,10 @@ trap 'on_exit' EXIT
 
 TMP=$(mktemp -d)
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 adv="${TMP}/adv"
 tang_get_adv "${port}" "${adv}"
 

+ 3 - 4
src/luks/tests/regen-not-inplace-luks1

@@ -32,11 +32,10 @@ trap 'on_exit' EXIT
 
 export TMP=$(mktemp -d)
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 adv="${TMP}/adv"
 tang_get_adv "${port}" "${adv}"
 

+ 3 - 4
src/luks/tests/regen-not-inplace-luks2

@@ -32,11 +32,10 @@ trap 'on_exit' EXIT
 
 export TMP=$(mktemp -d)
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 adv="${TMP}/adv"
 tang_get_adv "${port}" "${adv}"
 

+ 3 - 4
src/luks/tests/report-sss-luks1

@@ -32,11 +32,10 @@ trap 'on_exit' EXIT
 
 TMP=$(mktemp -d)
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 adv="${TMP}/adv"
 tang_get_adv "${port}" "${adv}"
 

+ 3 - 4
src/luks/tests/report-sss-luks2

@@ -32,11 +32,10 @@ trap 'on_exit' EXIT
 
 TMP=$(mktemp -d)
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 adv="${TMP}/adv"
 tang_get_adv "${port}" "${adv}"
 

+ 3 - 4
src/luks/tests/report-tang-luks1

@@ -32,11 +32,10 @@ trap 'on_exit' EXIT
 
 TMP=$(mktemp -d)
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 adv="${TMP}/adv"
 tang_get_adv "${port}" "${adv}"
 

+ 3 - 4
src/luks/tests/report-tang-luks2

@@ -32,11 +32,10 @@ trap 'on_exit' EXIT
 
 TMP=$(mktemp -d)
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 adv="${TMP}/adv"
 tang_get_adv "${port}" "${adv}"
 

+ 6 - 141
src/luks/tests/tests-common-functions.in

@@ -18,6 +18,8 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
+. tang-common-test-functions
+
 error() {
     echo "${1}" >&2
     exit 1
@@ -34,20 +36,6 @@ luks2_supported() {
     return @OLD_CRYPTSETUP@
 }
 
-# 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}"
@@ -236,132 +224,9 @@ compare_luks2_metadata() {
     return 0
 }
 
-
-# Get a random port to be used with a test tang server.
-get_random_port() {
-    shuf -i 1024-65535 -n 1
-}
-
-# Removes tang rotated keys from the test server.
-tang_remove_rotated_keys() {
-    local basedir="${1}"
-
-    if [ -z "${basedir}" ]; then
-        echo "Please pass a valid base directory for tang"
-        return 1
-    fi
-
-    [ -z "${TANGD_UPDATE}" ] && skip_test "WARNING: TANGD_UPDATE is not defined."
-
-    local db="${basedir}/db"
-    local cache="${basedir}/cache"
-    mkdir -p "${db}"
-    mkdir -p "${cache}"
-
-    pushd "${db}"
-        find . -name ".*.jwk" -exec rm -f {} \;
-    popd
-
-    "${TANGD_UPDATE}" "${db}" "${cache}"
-    return 0
-}
-
-# Creates new keys for the test tang server.
-tang_new_keys() {
-    local basedir="${1}"
-    local rotate="${2}"
-
-    if [ -z "${basedir}" ]; then
-        echo "Please pass a valid base directory for tang"
-        return 1
-    fi
-
-    [ -z "${TANGD_KEYGEN}" ] && skip_test "WARNING: TANGD_KEYGEN is not defined."
-    [ -z "${TANGD_UPDATE}" ] && skip_test "WARNING: TANGD_UPDATE is not defined."
-
-    local db="${basedir}/db"
-    local cache="${basedir}/cache"
-    mkdir -p "${db}"
-
-    if [ -n "${rotate}" ]; then
-        pushd "${db}"
-            local k
-            k=$(find . -name "*.jwk" | wc -l)
-            if [ "${k}" -gt 0 ]; then
-                for k in *.jwk; do
-                    mv -f -- "${k}" ".${k}"
-                done
-            fi
-        popd
-    fi
-
-    "${TANGD_KEYGEN}" "${db}"
-    "${TANGD_UPDATE}" "${db}" "${cache}"
-
-    return 0
-}
-
-# Start a test tang server.
-tang_run() {
-    local basedir="${1}"
-    local port="${2}"
-
-    if [ -z "${basedir}" ]; then
-        echo "Please pass a valid base directory for tang" >&2
-        return 1
-    fi
-
-    if [ -z "${port}" ]; then
-        echo "Please pass a valid port for tang" >&2
-        return 1
-    fi
-
-    if ! tang_new_keys "${basedir}"; then
-        echo "Error creating new keys for tang server" >&2
-        return 1
-    fi
-
-    local KEYS="${basedir}/cache"
-    local inetd='--inetd'
-    [ "${SD_ACTIVATE##*/}" = "systemd-activate" ] && inetd=
-
-    local pid pidfile
-    pidfile="${basedir}/tang.pid"
-
-    "${SD_ACTIVATE}" ${inetd} -l "${TANG_HOST}":"${port}" \
-            -a "${TANGD}" "${KEYS}" &
-    pid=$!
-    echo "${pid}" > "${pidfile}"
-}
-
-# Stop tang server.
-tang_stop() {
-    local basedir="${1}"
-    local pidfile="${basedir}/tang.pid"
-    [ -f "${pidfile}" ] || return 0
-
-    local pid
-    pid=$(<"${pidfile}")
-    kill "${pid}"
-}
-
-# Wait for the tang server to be operational.
-tang_wait_until_ready() {
-   local port="${1}"
-   while ! curl --output /dev/null --silent --fail \
-                http://"${TANG_HOST}":"${port}"/adv; do
-       sleep 0.1
-       echo -n . >&2
-   done
-}
-
-# Get tang advertisement.
-tang_get_adv() {
-    local port="${1}"
-    local adv="${2}"
-
-    curl -o "${adv}" http://"${TANG_HOST}":"${port}"/adv
+new_passphrase() {
+    jose jwk gen --input='{"kty":"oct","bytes":8}' --output=- \
+        | jose fmt --json=- --object --get k --unquote=-
 }
 
-export TANG_HOST=127.0.0.1
-export DEFAULT_PASS='just-some-test-password-here'
+export DEFAULT_PASS='   just-some-   test-password-here 1.+?~!@#$%^&*();:'"'"'"[]{}_=/`\   '

+ 1 - 1
src/luks/tests/unbind-luks1

@@ -30,7 +30,7 @@ trap 'exit' ERR
 
 TMP="$(mktemp -d)"
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 
 # LUKS1.

+ 1 - 1
src/luks/tests/unbind-luks2

@@ -34,7 +34,7 @@ fi
 
 TMP="$(mktemp -d)"
 ADV="${TMP}/adv.jws"
-create_tang_adv "${ADV}"
+tang_create_adv "${TMP}" "${ADV}"
 CFG="$(printf '{"url":"foobar","adv":"%s"}' "$ADV")"
 
 # LUKS2.

+ 3 - 4
src/luks/tests/unlock-tang-luks1

@@ -33,11 +33,10 @@ trap 'on_exit' ERR
 
 TMP="$(mktemp -d)"
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 adv="${TMP}/adv"
 tang_get_adv "${port}" "${adv}"
 

+ 3 - 4
src/luks/tests/unlock-tang-luks2

@@ -33,11 +33,10 @@ trap 'on_exit' ERR
 
 TMP="$(mktemp -d)"
 
-port=$(get_random_port)
-tang_run "${TMP}" "${port}" &
-tang_wait_until_ready "${port}"
+port=$(tang_new_random_port)
+tang_run "${TMP}" "${port}"
 
-url="http://${TANG_HOST}:${port}"
+url="http://localhost:${port}"
 adv="${TMP}/adv"
 tang_get_adv "${port}" "${adv}"
 

+ 2 - 1
src/pins/tang/clevis-decrypt-tang

@@ -88,4 +88,5 @@ fi
 tmp="$(jose jwk exc -i '{"alg":"ECMR"}' -l- -r- <<< "$eph$srv")"
 rep="$(jose jwk pub -i- <<< "$rep")"
 jwk="$(jose jwk exc -l- -r- <<< "$rep$tmp")"
-exec jose jwe dec -k- -i- < <(echo -n "$jwk$hdr."; /bin/cat)
+(echo -n "$jwk$hdr."; /bin/cat) | jose jwe dec -k- -i-
+exit $?

+ 3 - 2
src/pins/tang/clevis-encrypt-tang

@@ -83,7 +83,7 @@ elif jws="$(jose fmt -j- -g adv -Su- <<< "$cfg")"; then
         exit 1
     fi
 
-    if ! jws="$(jose fmt -j "$jws" -Oo-)"; then
+    if ! jws="$(jose fmt --json="${jws}" -Oo- 2>/dev/null)"; then
         echo "Advertisement file '$jws' is malformed!" >&2
         exit 1
     fi
@@ -94,7 +94,8 @@ elif ! jws="$(curl -sfg "$url/adv/$thp")"; then
     exit 1
 fi
 
-if ! jwks="$(jose fmt -j- -Og payload -SyOg keys -AUo- <<< "$jws")"; then
+if ! jwks="$(jose fmt --json="${jws}" -Og payload -SyOg keys \
+             -AUo- 2>/dev/null)"; then
     echo "Advertisement is malformed!" >&2
     exit 1
 fi

+ 1 - 46
src/pins/tang/meson.build

@@ -1,33 +1,3 @@
-actv = find_program(
-  'systemd-socket-activate',
-  'systemd-activate',
-  join_paths('/', 'usr', 'lib', 'systemd', 'systemd-activate'),
-  required: false
-)
-kgen = find_program(
-  join_paths(libexecdir, 'tangd-keygen'),
-  join_paths(get_option('prefix'), get_option('libdir'), 'tangd-keygen'),
-  join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd-keygen'),
-  join_paths('/', 'usr', get_option('libdir'), 'tangd-keygen'),
-  join_paths('/', 'usr', get_option('libexecdir'), 'tangd-keygen'),
-  required: false
-)
-updt = find_program(
-  join_paths(libexecdir, 'tangd-update'),
-  join_paths(get_option('prefix'), get_option('libdir'), 'tangd-update'),
-  join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd-update'),
-  join_paths('/', 'usr', get_option('libdir'), 'tangd-update'),
-  join_paths('/', 'usr', get_option('libexecdir'), 'tangd-update'),
-  required: false
-)
-tang = find_program(
-  join_paths(libexecdir, 'tangd'),
-  join_paths(get_option('prefix'), get_option('libdir'), 'tangd'),
-  join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd'),
-  join_paths('/', 'usr', get_option('libdir'), 'tangd'),
-  join_paths('/', 'usr', get_option('libexecdir'), 'tangd'),
-  required: false
-)
 curl = find_program('curl', required: false)
 
 if curl.found()
@@ -35,22 +5,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()
-    env = environment()
-    env.set('SD_ACTIVATE', actv.path())
-    env.set('TANGD_KEYGEN', kgen.path())
-    env.set('TANGD_UPDATE', updt.path())
-    env.set('TANGD', tang.path())
-    env.prepend('PATH',
-      join_paths(meson.source_root(), 'src'),
-      meson.current_source_dir(),
-      separator: ':'
-    )
-
-    test('pin-tang', find_program('./pin-tang'), env: env)
-  else
-    warning('Will not run tang tests due to missing dependencies!')
-  endif
+  subdir('tests')
 else
   warning('Will not install tang pin due to missing dependencies!')
 endif

+ 65 - 0
src/pins/tang/tests/meson.build

@@ -0,0 +1,65 @@
+kgen = find_program(
+  join_paths(libexecdir, 'tangd-keygen'),
+  join_paths(get_option('prefix'), get_option('libdir'), 'tangd-keygen'),
+  join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd-keygen'),
+  join_paths('/', 'usr', get_option('libdir'), 'tangd-keygen'),
+  join_paths('/', 'usr', get_option('libexecdir'), 'tangd-keygen'),
+  required: false
+)
+updt = find_program(
+  join_paths(libexecdir, 'tangd-update'),
+  join_paths(get_option('prefix'), get_option('libdir'), 'tangd-update'),
+  join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd-update'),
+  join_paths('/', 'usr', get_option('libdir'), 'tangd-update'),
+  join_paths('/', 'usr', get_option('libexecdir'), 'tangd-update'),
+  required: false
+)
+tang = find_program(
+  join_paths(libexecdir, 'tangd'),
+  join_paths(get_option('prefix'), get_option('libdir'), 'tangd'),
+  join_paths(get_option('prefix'), get_option('libexecdir'), 'tangd'),
+  join_paths('/', 'usr', get_option('libdir'), 'tangd'),
+  join_paths('/', 'usr', get_option('libexecdir'), 'tangd'),
+  required: false
+)
+
+socat = find_program('socat', required: false)
+
+tang_data = configuration_data()
+tang_data.set('SOCAT', '')
+tang_data.set('TANGD_KEYGEN', '')
+tang_data.set('TANGD_UPDATE', '')
+tang_data.set('TANGD', '')
+
+if socat.found()
+  tang_data.set('SOCAT', socat.path())
+endif
+
+if kgen.found()
+  tang_data.set('TANGD_KEYGEN', kgen.path())
+endif
+
+if tang.found()
+  tang_data.set('TANGD', tang.path())
+endif
+
+if updt.found()
+  tang_data.set('TANGD_UPDATE', updt.path())
+endif
+
+tang_tests_common = configure_file(
+  input: 'tang-common-test-functions.in',
+  output: 'tang-common-test-functions',
+  configuration: tang_data
+)
+
+env = environment()
+env.prepend('PATH',
+  join_paths(meson.source_root(), 'src'),
+  join_paths(meson.source_root(), 'src', 'pins', 'tang'),
+  join_paths(meson.build_root(), 'src', 'pins', 'tang', 'tests'),
+  separator: ':'
+)
+
+test('pin-tang', find_program('pin-tang'), env: env)
+test('tang-validate-adv', find_program('tang-validate-adv'), env: env)

+ 12 - 22
src/pins/tang/pin-tang

@@ -1,4 +1,4 @@
-#!/bin/bash -x
+#!/bin/bash -xe
 # vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
 #
 # Copyright (c) 2016 Red Hat, Inc.
@@ -18,34 +18,26 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-function on_exit() {
-    if [ "$PID" ]; then kill $PID; wait $PID || true; fi
+. tang-common-test-functions
+
+on_exit() {
+    exit_status=$?
+    tang_stop "${TMP}"
     [ -d "$TMP" ] && rm -rf "$TMP"
+    exit "${exit_status}"
 }
 
 trap 'on_exit' EXIT
-trap 'exit' ERR
 
 TMP="$(mktemp -d)"
-mkdir -p "$TMP"/db
-mkdir -p "$TMP"/cache
-
-# Generate the server keys
-"${TANGD_KEYGEN}" "$TMP"/db sig exc
-"${TANGD_UPDATE}" "$TMP"/db "$TMP"/cache
-
-# Start the server
-port="$(shuf -i 1024-65536 -n 1)"
 
-inetd='--inetd'
-[ "${SD_ACTIVATE##*/}" = "systemd-activate" ] && inetd=
+port=$(tang_new_random_port)
 
-"$SD_ACTIVATE" $inetd -l 127.0.0.1:"$port" -a "$TANGD" "$TMP"/cache &
-PID=$!
-sleep 0.25
+tang_run "${TMP}" "${port}" sig exc
 
 thp="$(jose jwk thp -i "$TMP/db/sig.jwk")"
-adv="$TMP/cache/default.jws"
+adv="${TMP}/adv.jws"
+tang_get_adv "${port}" "${adv}"
 url="http://localhost:${port}"
 
 cfg="$(printf '{"url":"%s","adv":"%s"}' "$url" "$adv")"
@@ -58,8 +50,6 @@ enc="$(echo -n "hi" | clevis encrypt tang "$cfg")"
 dec="$(echo -n "$enc" | clevis decrypt)"
 test "$dec" == "hi"
 
-kill -9 $PID
-! wait $PID
-unset PID
+tang_stop "${TMP}"
 
 ! echo "$enc" | clevis decrypt

+ 200 - 0
src/pins/tang/tests/tang-common-test-functions.in

@@ -0,0 +1,200 @@
+#!/bin/bash -ex
+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2020 Red Hat, Inc.
+# Author: Sergio Correia <scorreia@redhat.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+SOCAT="@SOCAT@"
+TANGD_KEYGEN="@TANGD_KEYGEN@"
+TANGD_UPDATE="@TANGD_UPDATE@"
+TANGD="@TANGD@"
+
+tang_error() {
+    echo "${1}" >&2
+    exit 1
+}
+
+tang_skip() {
+    echo "${1}" >&2
+    exit 77
+}
+
+tang_sanity_check() {
+    [ -n "${SOCAT}" ] && [ -n "${TANGD_KEYGEN}" ] && \
+        [ -n "${TANGD}" ] && return 0
+    tang_skip "tang is not enabled/supported. Check if you have met all the requirements"
+}
+
+# Creates a tang adv to be used in the tests.
+tang_create_adv() {
+    local basedir="${1}"
+    local adv="${2:-/dev/stdout}"
+
+    local SIG="${basedir}/sig.jwk"
+    jose jwk gen --input='{"alg":"ES512"}' --output="${SIG}"
+
+    local EXC="${basedir}/exc.jwk"
+    jose jwk gen --input='{"alg":"ECMR"}' --output="${EXC}"
+
+    local TEMPLATE='{"protected":{"cty":"jwk-set+json"}}'
+    jose jwk pub --set --input="${SIG}" --input="${EXC}" \
+        | jose jws sig --detached=- --signature="${TEMPLATE}" \
+                       --key="${SIG}" --output="${adv}"
+}
+
+# Get a random port to be used with a test tang server.
+tang_new_random_port() {
+    tang_sanity_check
+    shuf -i 1024-65535 -n 1
+}
+
+# Removes tang rotated keys from the test server.
+tang_remove_rotated_keys() {
+    tang_sanity_check
+    local basedir="${1}"
+
+    [ -z "${basedir}" ] && \
+        tang_error "tang_remove_rotated_keys: please specify 'basedir'"
+
+    local db="${basedir}/db"
+
+    mkdir -p "${db}"
+    pushd "${db}"
+        find . -name ".*.jwk" -exec rm -f {} \;
+    popd
+
+    [ -n "${TANGD_UPDATE}" ] && "${TANGD_UPDATE}" "${db}" "${basedir}/cache"
+    return 0
+}
+
+# Creates new keys for the test tang server.
+tang_new_keys() {
+    tang_sanity_check
+    local basedir="${1}"
+    local rotate="${2:-}"
+    local sig_name="${3:-}"
+    local exc_name="${4:-}"
+
+    [ -z "${basedir}" ] && tang_error "tang_new_keys: please specify 'basedir'"
+
+    local db="${basedir}/db"
+    mkdir -p "${db}"
+
+    if [ -n "${rotate}" ]; then
+        pushd "${db}"
+            local k
+            k=$(find . -name "*.jwk" | wc -l)
+            if [ "${k}" -gt 0 ]; then
+                for k in *.jwk; do
+                    mv -f -- "${k}" ".${k}"
+                done
+            fi
+        popd
+    fi
+
+    "${TANGD_KEYGEN}" "${db}" ${sig_name} ${exc_name}
+    [ -n "${TANGD_UPDATE}" ] && "${TANGD_UPDATE}" "${db}" "${basedir}/cache"
+
+    return 0
+}
+
+# Wait for the tang server to be operational.
+tang_wait_until_ready() {
+    tang_sanity_check
+    local port="${1}"
+
+    [ -z "${port}" ] && \
+        tang_error "tang_wait_until_ready: please specify 'port'"
+
+    local max_timeout_in_s=5
+    local start elapsed
+    start="${SECONDS}"
+    while ! curl --output /dev/null --silent --fail \
+                "http://localhost:${port}/adv"; do
+        elapsed=$((SECONDS - start))
+        if [ "${elapsed}" -gt "${max_timeout_in_s}" ]; then
+            tang_error "Timeout (${max_timeout_in_s}s) waiting for tang server"
+        fi
+        sleep 0.1
+        echo -n . >&2
+    done
+}
+
+# Start a test tang server.
+tang_run() {
+    tang_sanity_check
+    local basedir="${1}"
+    local port="${2}"
+    local sig_name="${3:-}"
+    local exc_name="${4:-}"
+
+    [ -z "${basedir}" ] && tang_error "tang_run: please specify 'basedir'"
+    [ -z "${port}" ] && tang_error "tang_run: please specify 'port'"
+
+    if ! tang_new_keys "${basedir}" "" "${sig_name}" "${exc_name}"; then
+        tang_error "Error creating new keys for tang server"
+    fi
+
+    local KEYS="${basedir}/cache"
+    [ -z "${TANGD_UPDATE}" ] && KEYS="${basedir}/db"
+
+    local pid pidfile
+    pidfile="${basedir}/tang.pid"
+
+    "${SOCAT}" -v -v TCP-LISTEN:${port},reuseaddr,fork \
+               exec:"${TANGD} ${KEYS}" &
+
+    pid=$!
+    echo "${pid}" > "${pidfile}"
+    tang_wait_until_ready "${port}"
+}
+
+# Stop tang server.
+tang_stop() {
+    tang_sanity_check
+    local basedir="${1}"
+    [ -z "${basedir}" ] && tang_error "tang_stop: please specify 'basedir'"
+
+    local pidfile="${basedir}/tang.pid"
+    [ -f "${pidfile}" ] || return 0
+
+    local pid
+    pid=$(<"${pidfile}")
+    kill -9 "${pid}" 2>/dev/null || :
+}
+
+# Get tang advertisement.
+tang_get_adv() {
+    tang_sanity_check
+    local port="${1}"
+    local adv="${2:-/dev/stdout}"
+
+    [ -z "${port}" ] && tang_error "tang_get_adv: please specify 'port'"
+    curl -L -o "${adv}" "http://localhost:${port}/adv"
+}
+
+run_test_server() {
+    local port="${1}"
+    local response="${2}"
+
+    [ -z "${SOCAT}" ] && tang_skip "run_test_server: socat is not available"
+    [ -z "${port}" ] && tang_error "run_test_server: please specify 'port'"
+    [ -z "${response}" ] && tang_error "run_test_server: please specify 'response'"
+
+    "${SOCAT}" -v -v TCP-LISTEN:${port},reuseaddr SYSTEM:"cat ${response}" &
+    sleep 1
+}

+ 153 - 0
src/pins/tang/tests/tang-validate-adv

@@ -0,0 +1,153 @@
+#!/bin/bash -xe
+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2020 Red Hat, Inc.
+# Author: Sergio Correia <scorreia@redhat.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+. tang-common-test-functions
+
+on_exit() {
+    local exit_status=$?
+    tang_stop "${TMP}"
+    [ -d "${TMP}" ] && rm -rf "${TMP}"
+    exit "${exit_status}"
+}
+
+do_test() {
+    local port="${1}"
+    local response="${2}"
+    local stderr="${3:-/dev/stderr}"
+
+    run_test_server "${port}" "${response}"
+    cfg="$(printf '{"url":"localhost:%d"}' "${port}")"
+    if ! echo foo | clevis encrypt tang "${cfg}" -y 2>"${stderr}"; then
+        echo "Error (do_test) response: ${response}" >&2
+        [ -r "${stderr}" ] && cat "${stderr}" >&2
+        return 1
+    fi
+}
+
+do_test_with_adv() {
+    local port="${1}"
+    local adv="${2}"
+    local stderr="${3:-/dev/stderr}"
+
+    cfg="$(printf '{"url":"localhost:%d","adv":"%s"}' "${port}" "${adv}")"
+    if ! echo foo-adv | clevis encrypt tang "${cfg}" 2>"${stderr}"; then
+        echo "Error (do_test_with_adv) adv: ${adv} response: ${response}" >&2
+        [ -r "${stderr}" ] && cat "${stderr}" >&2
+        return 1
+    fi
+}
+
+validate_output() {
+    local output="${1}"
+    if grep -Fq jose "${output}"; then
+        tang_error "'jose' is not expected to appear in the error output"
+    fi
+}
+
+trap 'on_exit' EXIT
+
+TMP="$(mktemp -d)"
+CASES="${TMP}/cases"
+mkdir -p "${CASES}"
+
+port=$(tang_new_random_port)
+
+# Let's test server responses.
+# Case 1 - regular advertisement - PASS.
+RESP="${CASES}"/good-01
+cat << EOF > "${RESP}"
+HTTP/1.0 200 OK
+
+$(tang_create_adv "${TMP}" /dev/stdout)
+EOF
+
+# Case 2 - bad advertisement.
+RESP="${CASES}"/bad-01
+adv='{'
+cat << EOF > "${RESP}"
+HTTP/1.0 200 OK
+
+${adv}
+EOF
+
+# Case 3 - returning 404.
+RESP="${CASES}"/bad-02
+cat << EOF > "${RESP}"
+HTTP/1.0 404 Not Found
+
+EOF
+
+# case 4 - returning 301.
+RESP="${CASES}"/bad-03
+cat << EOF > "${RESP}"
+HTTP/1.0 301 Moved Permanently
+
+EOF
+
+# case 5 - returning 500.
+RESP="${CASES}"/bad-04
+cat << EOF > "${RESP}"
+HTTP/1.0 500 Internal Server Error
+
+EOF
+
+for c in "${CASES}"/good-*; do
+    port=$(tang_new_random_port)
+    STDERR="${c}".stderr
+    do_test "${port}" "${c}" "${STDERR}"
+    validate_output "${STDERR}"
+done
+
+# Tests where bind is expected to fail (validate is still expected to succeed).
+for c in "${CASES}"/bad-*; do
+    port=$(tang_new_random_port)
+    STDERR="${c}".stderr
+    ! do_test "${port}" "${c}" "${STDERR}"
+    validate_output "${STDERR}"
+done
+
+# Now let's do some tests passing "adv" in the configuration.
+STDERR="${CASES}"/stderr
+for adv in "[]" "]" "" "{}"; do
+    ! do_test_with_adv "${port}" "${adv}" "${STDERR}"
+    validate_output "${STDERR}"
+done
+
+# Now let's use existing files as well.
+tang_run "${TMP}" "${port}"
+
+touch "${CASES}"/adv-bad-01
+echo '{' > "${CASES}"/adv-bad-02
+echo "foobar" > "${CASES}"/adv-bad-03
+tang_get_adv "${port}" "${CASES}"/adv-good-01
+
+# Tests where bind is expected to pass.
+for adv in "${CASES}"/adv-good-*; do
+    STDERR="${adv}".stderr
+    do_test_with_adv "${port}" "${adv}" "${STDERR}"
+    validate_output "${STDERR}"
+done
+
+# Tests where bind is expected to fail. validate still should pass.
+for adv in "${CASES}"/adv-bad-*; do
+    STDERR="${adv}".stderr
+    ! do_test_with_adv "${port}" "${adv}" "${STDERR}"
+    validate_output "${STDERR}"
+done

+ 8 - 11
src/pins/tpm2/clevis-decrypt-tpm2

@@ -49,8 +49,8 @@ TPM2TOOLS_INFO="$(tpm2_createprimary -v)"
 
 match='version="(.)\.'
 [[ $TPM2TOOLS_INFO =~ $match ]] && TPM2TOOLS_VERSION="${BASH_REMATCH[1]}"
-if [[ $TPM2TOOLS_VERSION != 3 ]] && [[ $TPM2TOOLS_VERSION != 4 ]]; then
-    echo "The tpm2 pin requires tpm2-tools version 3 or 4" >&2
+if [[ $TPM2TOOLS_VERSION -lt 3 ]] || [[ $TPM2TOOLS_VERSION -gt 5 ]]; then
+    echo "The tpm2 pin requires a tpm2-tools version between 3 and 5" >&2
     exit 1
 fi
 
@@ -135,7 +135,7 @@ fi
 
 case "$TPM2TOOLS_VERSION" in
     3) tpm2_createprimary -Q -H "$auth" -g "$hash" -G "$key" -C "$TMP"/primary.context || fail=$?;;
-    4) tpm2_createprimary -Q -C "$auth" -g "$hash" -G "$key" -c "$TMP"/primary.context || fail=$?;;
+    4|5) tpm2_createprimary -Q -C "$auth" -g "$hash" -G "$key" -c "$TMP"/primary.context || fail=$?;;
     *) fail=1;;
 esac
 if [ -n "$fail" ]; then
@@ -146,8 +146,8 @@ fi
 case "$TPM2TOOLS_VERSION" in
     3) tpm2_load -Q -c "$TMP"/primary.context -u "$TMP"/jwk.pub -r "$TMP"/jwk.priv \
                  -C "$TMP"/load.context || fail=$?;;
-    4) tpm2_load -Q -C "$TMP"/primary.context -u "$TMP"/jwk.pub -r "$TMP"/jwk.priv \
-                 -c "$TMP"/load.context || fail=$?;;
+    4|5) tpm2_load -Q -C "$TMP"/primary.context -u "$TMP"/jwk.pub -r "$TMP"/jwk.priv \
+                   -c "$TMP"/load.context || fail=$?;;
     *) fail=1;;
 esac
 if [ -n "$fail" ]; then
@@ -157,7 +157,7 @@ fi
 
 case "$TPM2TOOLS_VERSION" in
     3) jwk="$(tpm2_unseal -c "$TMP"/load.context ${pcr_spec:+-L $pcr_spec})" || fail=$?;;
-    4) jwk="$(tpm2_unseal -c "$TMP"/load.context ${pcr_spec:+-p pcr:$pcr_spec})" || fail=$?;;
+    4|5) jwk="$(tpm2_unseal -c "$TMP"/load.context ${pcr_spec:+-p pcr:$pcr_spec})" || fail=$?;;
     *) fail=1;;
 esac
 if [ -n "$fail" ]; then
@@ -165,8 +165,5 @@ if [ -n "$fail" ]; then
     exit 1
 fi
 
-# The on_exit() trap will not be fired after exec, so let's clean up the temp
-# directory at this point.
-[ -d "${TMP}" ] && rm -rf "${TMP}"
-
-exec jose jwe dec -k- -i- < <(echo -n "$jwk$hdr."; /bin/cat)
+(echo -n "$jwk$hdr."; /bin/cat) | jose jwe dec -k- -i-
+exit $?

+ 8 - 8
src/pins/tpm2/clevis-encrypt-tpm2

@@ -71,8 +71,8 @@ TPM2TOOLS_INFO="$(tpm2_createprimary -v)"
 
 match='version="(.)\.'
 [[ $TPM2TOOLS_INFO =~ $match ]] && TPM2TOOLS_VERSION="${BASH_REMATCH[1]}"
-if [[ $TPM2TOOLS_VERSION != 3 ]] && [[ $TPM2TOOLS_VERSION != 4 ]]; then
-    echo "The tpm2 pin requires tpm2-tools version 3 or 4" >&2
+if [[ $TPM2TOOLS_VERSION -lt 3 ]] || [[ $TPM2TOOLS_VERSION -gt 5 ]]; then
+    echo "The tpm2 pin requires a tpm2-tools version between 3 and 5" >&2
     exit 1
 fi
 
@@ -153,7 +153,7 @@ trap 'on_exit' EXIT
 
 case "$TPM2TOOLS_VERSION" in
     3) tpm2_createprimary -Q -H "$auth" -g "$hash" -G "$key" -C "$TMP"/primary.context || fail=$?;;
-    4) tpm2_createprimary -Q -C "$auth" -g "$hash" -G "$key" -c "$TMP"/primary.context || fail=$?;;
+    4|5) tpm2_createprimary -Q -C "$auth" -g "$hash" -G "$key" -c "$TMP"/primary.context || fail=$?;;
     *) fail=1;;
 esac
 if [ -n "$fail" ]; then
@@ -166,7 +166,7 @@ if [ -n "$pcr_ids" ]; then
     if [ -z "$pcr_digest" ]; then
         case "$TPM2TOOLS_VERSION" in
             3) tpm2_pcrlist -Q -L "$pcr_bank":"$pcr_ids" -o "$TMP"/pcr.digest || fail=$?;;
-            4) tpm2_pcrread -Q "$pcr_bank":"$pcr_ids" -o "$TMP"/pcr.digest || fail=$?;;
+            4|5) tpm2_pcrread -Q "$pcr_bank":"$pcr_ids" -o "$TMP"/pcr.digest || fail=$?;;
             *) fail=1;;
         esac
         if [ -n "$fail" ]; then
@@ -183,8 +183,8 @@ if [ -n "$pcr_ids" ]; then
     case "$TPM2TOOLS_VERSION" in
         3) tpm2_createpolicy -Q -g "$hash" -P -L "$pcr_bank":"$pcr_ids" \
                              -F "$TMP"/pcr.digest -f "$TMP"/pcr.policy || fail=$?;;
-        4) tpm2_createpolicy -Q -g "$hash" --policy-pcr -l "$pcr_bank":"$pcr_ids" \