Browse Source

Merge upstream version 20

Christoph Biedl 1 year ago
parent
commit
eab03f02f9
33 changed files with 349 additions and 57 deletions
  1. 11 5
      .github/workflows/build.yml
  2. 3 1
      .github/workflows/differential-shellcheck.yml
  3. 1 1
      .github/workflows/install-dependencies
  4. 43 0
      .github/workflows/spellcheck.yml
  5. 1 1
      INSTALL.md
  6. 49 10
      README.md
  7. 1 1
      meson.build
  8. 8 0
      src/initramfs-tools/hooks/clevis.in
  9. 4 2
      src/initramfs-tools/scripts/local-bottom/clevis.in
  10. 17 0
      src/initramfs-tools/scripts/local-top/clevis.in
  11. 13 25
      src/luks/clevis-luks-common-functions.in
  12. 7 2
      src/luks/clevis-luks-unlock
  13. 3 0
      src/luks/clevis-luks-unlock.1.adoc
  14. 0 0
      src/luks/dracut/clevis-pin-null/meson.build
  15. 0 0
      src/luks/dracut/clevis-pin-null/module-setup.sh.in
  16. 0 0
      src/luks/dracut/clevis-pin-sss/meson.build
  17. 0 0
      src/luks/dracut/clevis-pin-sss/module-setup.sh.in
  18. 0 0
      src/luks/dracut/clevis-pin-tang/meson.build
  19. 0 0
      src/luks/dracut/clevis-pin-tang/module-setup.sh.in
  20. 0 0
      src/luks/dracut/clevis-pin-tpm2/meson.build
  21. 0 0
      src/luks/dracut/clevis-pin-tpm2/module-setup.sh.in
  22. 22 0
      src/luks/dracut/clevis/clevis-hook.sh.in
  23. 72 0
      src/luks/dracut/clevis/clevis-luks-unlocker
  24. 2 0
      src/luks/systemd/dracut/clevis/meson.build
  25. 13 4
      src/luks/systemd/dracut/clevis/module-setup.sh.in
  26. 0 0
      src/luks/dracut/meson.build
  27. 4 2
      src/luks/meson.build
  28. 0 2
      src/luks/systemd/dracut/clevis/clevis-hook.sh.in
  29. 0 1
      src/luks/systemd/meson.build
  30. 3 0
      src/luks/tests/meson.build
  31. 68 0
      src/luks/tests/unlock-arbitrary-parameter
  32. 3 0
      src/luks/udisks2/clevis-luks-udisks2.c
  33. 1 0
      src/pins/sss/clevis-decrypt-sss.c

+ 11 - 5
.github/workflows/build.yml

@@ -1,11 +1,17 @@
 ---
 ---
 name: build
 name: build
 
 
-on: [push, pull_request]
+on:
+  push:
+    ignore-paths:
+      - '**.md'
+  pull_request:
+    ignore-paths:
+      - '**.md'
 
 
 jobs:
 jobs:
   build:
   build:
-    runs-on: ubuntu-18.04
+    runs-on: ubuntu-latest
     continue-on-error: ${{ ! matrix.stable }}
     continue-on-error: ${{ ! matrix.stable }}
     strategy:
     strategy:
       matrix:
       matrix:
@@ -16,15 +22,15 @@ jobs:
           - debian:testing
           - debian:testing
           - debian:latest
           - debian:latest
           - ubuntu:rolling
           - ubuntu:rolling
-          - ubuntu:bionic
+          - ubuntu:latest
         stable: [true]
         stable: [true]
         include:
         include:
-          - os: fedora:rawhide
+          - os: quay.io/fedora/fedora:rawhide
             stable: false
             stable: false
           - os: ubuntu:devel
           - os: ubuntu:devel
             stable: false
             stable: false
     steps:
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
 
 
       - name: Show OS information
       - name: Show OS information
         run: cat /etc/os-release 2>/dev/null || echo /etc/os-release not available
         run: cat /etc/os-release 2>/dev/null || echo /etc/os-release not available

+ 3 - 1
.github/workflows/differential-shellcheck.yml

@@ -5,6 +5,8 @@ name: Differential ShellCheck
 on:
 on:
   pull_request:
   pull_request:
     branches: [master]
     branches: [master]
+    ignore-paths:
+      - '**.md'
 
 
 permissions:
 permissions:
   contents: read
   contents: read
@@ -19,7 +21,7 @@ jobs:
 
 
     steps:
     steps:
       - name: Repository checkout
       - name: Repository checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
         with:
           fetch-depth: 0
           fetch-depth: 0
 
 

+ 1 - 1
.github/workflows/install-dependencies

@@ -29,7 +29,7 @@ debian:*|ubuntu:*)
     done
     done
     ;;
     ;;
 
 
-fedora:*)
+*fedora:*)
     printf 'max_parallel_downloads=10\nfastestmirror=1\n' >> /etc/dnf/dnf.conf
     printf 'max_parallel_downloads=10\nfastestmirror=1\n' >> /etc/dnf/dnf.conf
     dnf -y clean all
     dnf -y clean all
     dnf -y --setopt=deltarpm=0 update
     dnf -y --setopt=deltarpm=0 update

+ 43 - 0
.github/workflows/spellcheck.yml

@@ -0,0 +1,43 @@
+name: Spellcheck
+on: 
+  push:
+    # branches: [main]
+  pull_request:  
+jobs: 
+  spell-check:
+    name: Language tool & Misspell check
+    runs-on: ubuntu-latest
+    steps:
+      - name: check out code
+        uses: actions/checkout@v4
+      - name: running language tool 
+        uses: reviewdog/action-languagetool@v1
+        with:
+          github_token: ${{ secrets.github_token }}
+          # Change reviewdog reporter if you need [github-pr-check,github-check,github-pr-review].
+          reporter: github-check
+          # Change reporter level if you need.
+          level: warning
+          language: en-US
+          disabled_categories: 'TYPOS,TYPOGRAPHY,CASING'
+          disabled_rules: 'WHITESPACE_RULE,EN_QUOTES,DASH_RULE,WORD_CONTAINS_UNDERSCORE,UPPERCASE_SENTENCE_START,ARROWS,COMMA_PARENTHESIS_WHITESPACE,UNLIKELY_OPENING_PUNCTUATION,SENTENCE_WHITESPACE,CURRENCY,EN_UNPAIRED_BRACKETS,PHRASE_REPETITION,PUNCTUATION_PARAGRAPH_END,METRIC_UNITS_EN_US,ENGLISH_WORD_REPEAT_BEGINNING_RULE,DOUBLE_PUNCTUATION,'
+          enabled_only: 'false'
+          enabled_rules: ''
+          enabled_categories: ''
+          patterns: "**.md"
+            
+    
+    
+      - name: running misspell
+        # To perform misspell check even after the language tool test fails 
+        if: success() || failure()  
+        uses: reviewdog/action-misspell@v1
+        with:
+          github_token: ${{ secrets.github_token }}
+          locale: "US"
+          reporter: github-check
+          level: info
+          pattern: "**.md"
+          exclude: |
+            ./.git/*
+            ./.cache/*

+ 1 - 1
INSTALL.md

@@ -57,7 +57,7 @@ $ sudo ninja -C build install
 
 
 This will install Clevis to a location determined at configure time.
 This will install Clevis to a location determined at configure time.
 
 
-See the output of `meson --help` for the available options. Typically
+See the output of `meson --help` for the available options. Typically,
 much won't be needed besides providing an alternative --prefix option at
 much won't be needed besides providing an alternative --prefix option at
 configure time, and maybe DESTDIR at install time if you're packaging for
 configure time, and maybe DESTDIR at install time if you're packaging for
 a distro.
 a distro.

+ 49 - 10
README.md

@@ -12,7 +12,9 @@ volumes.
 What does this look like? Well, the first step is encrypting some data. We do
 What does this look like? Well, the first step is encrypting some data. We do
 this with a simple command:
 this with a simple command:
 
 
-    $ clevis encrypt PIN CONFIG < PLAINTEXT > CIPHERTEXT.jwe
+```bash
+$ clevis encrypt PIN CONFIG < PLAINTEXT > CIPHERTEXT.jwe
+```
 
 
 This command takes plaintext on standard input and produces an encrypted JWE
 This command takes plaintext on standard input and produces an encrypted JWE
 object on standard output. Besides the plaintext, we need to specify two
 object on standard output. Besides the plaintext, we need to specify two
@@ -64,8 +66,7 @@ advertisement is trusted.
 
 
 Clevis provides support to encrypt a key in a Trusted Platform Module 2.0 (TPM2)
 Clevis provides support to encrypt a key in a Trusted Platform Module 2.0 (TPM2)
 chip. The cryptographically-strong, random key used for encryption is encrypted
 chip. The cryptographically-strong, random key used for encryption is encrypted
-using the TPM2 chip, and then at decryption time is decrypted using the TPM2 to
-allow clevis to decrypt the secret stored in the JWE.
+using the TPM2 chip, and is decrypted using TPM2 at the time of decryption to allow clevis to decrypt the secret stored in the JWE.
 
 
 For example:
 For example:
 
 
@@ -88,11 +89,11 @@ recursively). Additionally, you define the threshold `t`. If at least `t`
 pieces can be decrypted, then the encryption key can be recovered and
 pieces can be decrypted, then the encryption key can be recovered and
 decryption can succeed.
 decryption can succeed.
 
 
-Here is an example where we use the SSS pin with both the Tang and HTTP pins:
+Here is an example where we use the SSS pin with both the Tang and TPM2 pins:
 
 
 ```bash
 ```bash
 $ echo hi | clevis encrypt sss \
 $ echo hi | clevis encrypt sss \
-'{"t": 2, "pins": {"http": {"url": "http://server.local/key"}, "tang": {"url": "http://tang.local"}}}' \
+'{"t": 2, "pins": {"tpm2": {"pcr_ids": "0"}, "tang": {"url": "http://tang.local"}}}' \
 > hi.jwe
 > hi.jwe
 ```
 ```
 
 
@@ -100,16 +101,16 @@ In the above example, we define two child pins and have a threshold of 2.
 This means that during decryption **both** child pins must succeed in order for
 This means that during decryption **both** child pins must succeed in order for
 SSS itself to succeed.
 SSS itself to succeed.
 
 
-Here is another example where we use just the HTTP pin:
+Here is another example where we use just the Tang pin:
 
 
 ```bash
 ```bash
 $ echo hi | clevis encrypt sss \
 $ echo hi | clevis encrypt sss \
-'{"t": 1, "pins": {"http": [{"url": "http://server1.local/key"}, {"url": "http://server1.local/key"}]}}' \
+'{"t": 1, "pins": {"tang": [{"url": "http://server1.local/key"}, {"url": "http://server2.local/key"}]}}' \
 > hi.jwe
 > hi.jwe
 ```
 ```
 
 
-In this example, we define two child instances of the HTTP pin - each with its
-own configuration. Since we have a threshold of 1, if **either** of the HTTP
+In this example, we define two child instances of the Tang pin - each with its
+own configuration. Since we have a threshold of 1, if **either** of the Tang
 pin instances succeed during decryption, SSS will succeed.
 pin instances succeed during decryption, SSS will succeed.
 
 
 ### Binding LUKS Volumes
 ### Binding LUKS Volumes
@@ -162,7 +163,7 @@ initramfs you will need to run:
 sudo update-initramfs -u -k 'all'
 sudo update-initramfs -u -k 'all'
 ```
 ```
 
 
-Upon reboot it will behave exactly as if using Dracut.
+Upon reboot, it will behave exactly as if using Dracut.
 
 
 #### Unlocker: UDisks2
 #### Unlocker: UDisks2
 
 
@@ -215,3 +216,41 @@ UDisks2 unlocker, respectively.
 ```bash
 ```bash
 $ sudo dnf install clevis clevis-dracut clevis-udisks2
 $ sudo dnf install clevis clevis-dracut clevis-udisks2
 ```
 ```
+
+## Manual compilation
+
+As remarked in the previous section, **it is suggested not to install Clevis directly**.
+However, in case no Clevis packages exist for your Linux distribution, the steps to 
+manually compile and install Clevis are next ones:
+
+* Download latest version of the binaries (not that the latest version could change):
+```bash
+$ wget https://github.com/latchset/clevis/releases/download/v19/clevis-19.tar.xz
+```
+
+* Untar the binaries file:
+```bash
+$ tar Jxvf clevis-19.tar.xz 
+```
+
+* Create build directory and change path to it:
+```bash
+$ cd clevis-19
+$ mkdir build
+$ cd build
+```
+
+* Execute `meson` to setup compilation:
+```bash
+$ meson setup ..
+```
+
+* Compile with `ninja` command:
+```bash
+$ ninja
+```
+
+* Install with `ninja install` command (you will need root permissions for it):
+```bash
+$ sudo ninja install
+```

+ 1 - 1
meson.build

@@ -1,5 +1,5 @@
 project('clevis', 'c', license: 'GPL3+',
 project('clevis', 'c', license: 'GPL3+',
-  version: '19',
+  version: '20',
   default_options: 'c_std=c99'
   default_options: 'c_std=c99'
 )
 )
 
 

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

@@ -95,3 +95,11 @@ bash_bin=$(find_binary "bash")
 copy_exec "${curl_bin}" || die 2 "Unable to copy ${curl_bin} to initrd image"
 copy_exec "${curl_bin}" || die 2 "Unable to copy ${curl_bin} to initrd image"
 copy_exec "${awk_bin}" || die 2 "Unable to copy ${awk_bin} to initrd image"
 copy_exec "${awk_bin}" || die 2 "Unable to copy ${awk_bin} to initrd image"
 copy_exec "${bash_bin}" || die 2 "Unable to copy ${bash_bin} to initrd image"
 copy_exec "${bash_bin}" || die 2 "Unable to copy ${bash_bin} to initrd image"
+
+# Copy latest versions of shared objects needed for DNS resolution
+for so in $(ldconfig -p | sed -nr 's/^\s*libnss_files\.so\.[0-9]+\s.*=>\s*//p'); do
+  copy_exec "${so}"
+done
+for so in $(ldconfig -p | sed -nr 's/^\s*libnss_dns\.so\.[0-9]+\s.*=>\s*//p'); do
+  copy_exec "${so}"
+done

+ 4 - 2
src/initramfs-tools/scripts/local-bottom/clevis.in

@@ -34,8 +34,10 @@ esac
 [ -s /run/clevis.pid ] || exit 0
 [ -s /run/clevis.pid ] || exit 0
 
 
 pid=$(cat /run/clevis.pid)
 pid=$(cat /run/clevis.pid)
-ps -l | awk -v pid="$pid" '$4==pid { system("kill " $3) }'
-kill "$pid"
+child_pids=$(ps -o pid,ppid | awk -v pid="$pid" '$2==pid { print $1 }')
+for kill_pid in $pid $child_pids; do
+	kill "$kill_pid"
+done
 
 
 # Not really worried about downing extra interfaces: they will come up
 # Not really worried about downing extra interfaces: they will come up
 # during the actual boot. Might make this configurable later if needed.
 # during the actual boot. Might make this configurable later if needed.

+ 17 - 0
src/initramfs-tools/scripts/local-top/clevis.in

@@ -263,6 +263,23 @@ do_configure_networking() {
             echo "clevis: Warning: multiple network interfaces available but no ip= parameter provided."
             echo "clevis: Warning: multiple network interfaces available but no ip= parameter provided."
         fi
         fi
         configure_networking
         configure_networking
+
+        # Add DNS servers from configure_networking to /etc/resolv.conf
+        if [ ! -e /etc/resolv.conf ]; then
+            touch /etc/resolv.conf
+            for intf in /run/net-*.conf; do
+                . "${intf}"
+                if [ ! -z "${IPV4DNS0}" ] && [ "${IPV4DNS0}" != "0.0.0.0" ]; then
+                    echo nameserver "${IPV4DNS0}" >> /etc/resolv.conf
+                fi
+                if [ ! -z "${IPV4DNS1}" ] && [ "${IPV4DNS1}" != "0.0.0.0" ]; then
+                    echo nameserver "${IPV4DNS1}" >> /etc/resolv.conf
+                fi
+                if [ ! -z "${IPV6DNS0}" ]; then
+                    echo nameserver "${IPV6DNS0}" >> /etc/resolv.conf
+                fi
+            done
+        fi
     fi
     fi
 }
 }
 
 

+ 13 - 25
src/luks/clevis-luks-common-functions.in

@@ -20,6 +20,11 @@
 
 
 CLEVIS_UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e"
 CLEVIS_UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e"
 
 
+# Length, in bytes, used for password generated for LUKS key
+# This value corresponds to an entropy of 256 bits if the password
+# was generated by pwmake or similar tool
+JOSE_PASSWORD_LENGTH=40
+
 enable_debugging() {
 enable_debugging() {
     # Automatically enable debugging if in initramfs phase and rd.debug
     # Automatically enable debugging if in initramfs phase and rd.debug
     if [ -e /usr/lib/dracut-lib.sh ]; then
     if [ -e /usr/lib/dracut-lib.sh ]; then
@@ -788,7 +793,7 @@ clevis_luks_add_key() {
     fi
     fi
     local pbkdf_args="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
     local pbkdf_args="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
 
 
-    printf '%s' "${input}" | cryptsetup luksAddKey --batch-mode \
+    printf '%s' "${input}" | cryptsetup luksAddKey --force-password --batch-mode \
                                          --key-slot "${SLT}" \
                                          --key-slot "${SLT}" \
                                          "${DEV}" \
                                          "${DEV}" \
                                          ${pbkdf_args} \
                                          ${pbkdf_args} \
@@ -818,11 +823,11 @@ clevis_luks_update_key() {
     local input extra_args=
     local input extra_args=
     input="$(printf '%s\n%s' "${KEY}" "${NEWKEY}")"
     input="$(printf '%s\n%s' "${KEY}" "${NEWKEY}")"
     if [ -n "${KEYFILE}" ]; then
     if [ -n "${KEYFILE}" ]; then
-        extra_args="$(printf -- '--key-file %s' "${KEYFILE}")"
+        extra_args="$(printf -- '--key-file %s --force-password' "${KEYFILE}")"
         input="$(printf '%s' "${NEWKEY}")"
         input="$(printf '%s' "${NEWKEY}")"
     fi
     fi
     if [ -n "${EXISTING_TOKEN_ID}" ]; then
     if [ -n "${EXISTING_TOKEN_ID}" ]; then
-        extra_args="$(printf -- '--token-id %s' "${EXISTING_TOKEN_ID}")"
+        extra_args="$(printf -- '--token-id %s --force-password' "${EXISTING_TOKEN_ID}")"
         input="$(printf '%s' "${NEWKEY}")"
         input="$(printf '%s' "${NEWKEY}")"
     fi
     fi
 
 
@@ -884,26 +889,10 @@ clevis_luks_save_key_to_slot() {
 
 
 # clevis_luks_generate_key() generates a new key for use with clevis.
 # clevis_luks_generate_key() generates a new key for use with clevis.
 clevis_luks_generate_key() {
 clevis_luks_generate_key() {
-    local DEV="${1}"
-    [ -z "${DEV}" ] && return 1
-
-    local dump filter bits
-    local MAX_ENTROPY_BITS=256  # Maximum allowed by pwmake.
-    dump=$(cryptsetup luksDump "${DEV}")
-    if cryptsetup isLuks --type luks1 "${DEV}"; then
-        filter="$(echo "${dump}" | sed -rn 's|MK bits:[ \t]*([0-9]+)|\1|p')"
-    elif cryptsetup isLuks --type luks2 "${DEV}"; then
-        filter="$(echo -n "${dump}" | \
-                  sed -rn 's|^\s+Key:\s+([0-9]+) bits\s*$|\1|p')"
-    else
-        return 1
-    fi
-
-    bits="$(echo -n "${filter}" | sort -n | tail -n 1)"
-    if [ "${bits}" -gt "${MAX_ENTROPY_BITS}" ]; then
-        bits="${MAX_ENTROPY_BITS}"
-    fi
-    pwmake "${bits}"
+    local input
+    input=$(printf '{"kty":"oct","bytes":%s}' "${JOSE_PASSWORD_LENGTH}")
+    jose jwk gen --input="${input}" --output=- | \
+        jose fmt --json=- --object --get k --unquote=-
 }
 }
 
 
 # clevis_luks_token_id_by_slot() returns the token ID linked to a
 # clevis_luks_token_id_by_slot() returns the token ID linked to a
@@ -993,8 +982,7 @@ clevis_luks_do_bind() {
     fi
     fi
 
 
     local newkey jwe
     local newkey jwe
-    if ! newkey="$(clevis_luks_generate_key "${DEV}")" \
-                   || [ -z "${newkey}" ]; then
+    if ! newkey="$(clevis_luks_generate_key)" || [ -z "${newkey}" ]; then
         echo "Unable to generate a new key" >&2
         echo "Unable to generate a new key" >&2
         return 1
         return 1
     fi
     fi

+ 7 - 2
src/luks/clevis-luks-unlock

@@ -35,6 +35,10 @@ function usage() {
     echo "  -t SLT Test the passphrase for the given slot without unlocking"
     echo "  -t SLT Test the passphrase for the given slot without unlocking"
     echo "         the device"
     echo "         the device"
     echo
     echo
+    echo "  -o OPTS Pass options to underlying 'cryptsetup open'; be sure"
+    echo "          to quote the OPTS you pass, if they contain a space,"
+    echo "          etc."
+    echo
     exit 2
     exit 2
 }
 }
 
 
@@ -43,11 +47,12 @@ if [ $# -eq 1 ] && [ "$1" == "--summary" ]; then
     exit 0
     exit 0
 fi
 fi
 
 
-while getopts ":d:n:t:" o; do
+while getopts ":d:n:t:o:" o; do
     case "$o" in
     case "$o" in
     d) DEV="$OPTARG";;
     d) DEV="$OPTARG";;
     n) NAME="$OPTARG";;
     n) NAME="$OPTARG";;
     t) SLT="$OPTARG";;
     t) SLT="$OPTARG";;
+    o) OPENARGS="$OPTARG";;
     *) usage;;
     *) usage;;
     esac
     esac
 done
 done
@@ -75,5 +80,5 @@ else
         exit 1
         exit 1
     fi
     fi
 
 
-    echo -n "${pt}" | cryptsetup open -d- "${DEV}" "${NAME}"
+    echo -n "${pt}" | cryptsetup ${OPENARGS} open -d- "${DEV}" "${NAME}"
 fi
 fi

+ 3 - 0
src/luks/clevis-luks-unlock.1.adoc

@@ -29,6 +29,9 @@ provisioned Clevis policy. For example:
 * *-t* _SLT_ :
 * *-t* _SLT_ :
   Test the passphrase for the given slot without unlocking the device
   Test the passphrase for the given slot without unlocking the device
 
 
+* *-o* _PARAMS_ :
+  Pass arbitrary parameters to cryptsetup; quote parameters as necessary
+
 == SEE ALSO
 == SEE ALSO
 
 
 link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)]
 link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)]

src/luks/systemd/dracut/clevis-pin-null/meson.build → src/luks/dracut/clevis-pin-null/meson.build


src/luks/systemd/dracut/clevis-pin-null/module-setup.sh.in → src/luks/dracut/clevis-pin-null/module-setup.sh.in


src/luks/systemd/dracut/clevis-pin-sss/meson.build → src/luks/dracut/clevis-pin-sss/meson.build


src/luks/systemd/dracut/clevis-pin-sss/module-setup.sh.in → src/luks/dracut/clevis-pin-sss/module-setup.sh.in


src/luks/systemd/dracut/clevis-pin-tang/meson.build → src/luks/dracut/clevis-pin-tang/meson.build


src/luks/systemd/dracut/clevis-pin-tang/module-setup.sh.in → src/luks/dracut/clevis-pin-tang/module-setup.sh.in


src/luks/systemd/dracut/clevis-pin-tpm2/meson.build → src/luks/dracut/clevis-pin-tpm2/meson.build


src/luks/systemd/dracut/clevis-pin-tpm2/module-setup.sh.in → src/luks/dracut/clevis-pin-tpm2/module-setup.sh.in


+ 22 - 0
src/luks/dracut/clevis/clevis-hook.sh.in

@@ -0,0 +1,22 @@
+#!/bin/sh
+set -eu
+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2020-2024 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/>.
+
+@libexecdir@/clevis-luks-unlocker -l

+ 72 - 0
src/luks/dracut/clevis/clevis-luks-unlocker

@@ -0,0 +1,72 @@
+#!/bin/sh
+set -eu
+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# Copyright (c) 2020-2024 Red Hat, Inc.
+# Author: Sergio Correia <scorreia@redhat.com>
+#
+# Non-systemd clevis unlocker
+# Modifications sponsored by PMGA Tech LLP
+#
+#
+# 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
+
+# Make sure to exit cleanly if SIGTERM is received.
+trap 'echo "Exiting due to SIGTERM" && exit 0' TERM
+
+loop=
+while getopts ":l" o; do
+    case "${o}" in
+    l) loop=true;;
+    *) ;;
+    esac
+done
+
+to_unlock() {
+    _devices=''
+    for _d in $(blkid -t TYPE=crypto_LUKS -o device); do
+        if ! bindings="$(clevis luks list -d "${_d}" 2>/dev/null)" \
+                         || [ -z "${bindings}" ]; then
+            continue
+        fi
+        _uuid="$(cryptsetup luksUUID "${_d}")"
+        if clevis_is_luks_device_by_uuid_open "${_uuid}"; then
+            continue
+        fi
+        _devices="$(printf '%s\n%s' "${_devices}" "${_d}")"
+    done
+    echo "${_devices}" | sed -e 's/^\n$//'
+}
+
+while true; do
+    for d in $(to_unlock); do
+        uuid="$(cryptsetup luksUUID "${d}")"
+        if ! clevis luks unlock -d "${d}"; then
+            echo "Unable to unlock ${d} (UUID=${uuid})" >&2
+            continue
+        fi
+        echo "Unlocked ${d} (UUID=${uuid}) successfully" >&2
+    done
+
+    [ "${loop}" != true ] && break
+    # Checking for pending devices to be unlocked.
+    if remaining=$(to_unlock) && [ -z "${remaining}" ]; then
+        break;
+    fi
+
+    sleep 0.5
+done

+ 2 - 0
src/luks/systemd/dracut/clevis/meson.build

@@ -16,6 +16,8 @@ if dracut.found()
     install_dir: dracutdir,
     install_dir: dracutdir,
     configuration: data,
     configuration: data,
   )
   )
+
+  install_data('clevis-luks-unlocker', install_dir: libexecdir)
 else
 else
   warning('Will not install dracut module due to missing dependencies!')
   warning('Will not install dracut module due to missing dependencies!')
 endif
 endif

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

@@ -19,7 +19,11 @@
 #
 #
 
 
 depends() {
 depends() {
-    echo crypt systemd
+    local __depends=crypt
+    if dracut_module_included "systemd"; then
+        __depends=$(printf '%s systemd' "${__depends}")
+    fi
+    echo "${__depends}"
     return 255
     return 255
 }
 }
 
 
@@ -27,17 +31,22 @@ install() {
     if dracut_module_included "systemd"; then
     if dracut_module_included "systemd"; then
         inst_multiple \
         inst_multiple \
             $systemdsystemunitdir/clevis-luks-askpass.service \
             $systemdsystemunitdir/clevis-luks-askpass.service \
-            $systemdsystemunitdir/clevis-luks-askpass.path
+            $systemdsystemunitdir/clevis-luks-askpass.path \
+            @SYSTEMD_REPLY_PASS@ \
+            @libexecdir@/clevis-luks-askpass
+
         systemctl -q --root "$initdir" add-wants cryptsetup.target clevis-luks-askpass.path
         systemctl -q --root "$initdir" add-wants cryptsetup.target clevis-luks-askpass.path
     else
     else
         inst_hook initqueue/online 60 "$moddir/clevis-hook.sh"
         inst_hook initqueue/online 60 "$moddir/clevis-hook.sh"
         inst_hook initqueue/settled 60 "$moddir/clevis-hook.sh"
         inst_hook initqueue/settled 60 "$moddir/clevis-hook.sh"
+        inst_multiple \
+            @libexecdir@/clevis-luks-unlocker \
+            clevis-luks-unlock \
+            blkid
     fi
     fi
 
 
     inst_multiple \
     inst_multiple \
         /etc/services \
         /etc/services \
-        @SYSTEMD_REPLY_PASS@ \
-        @libexecdir@/clevis-luks-askpass \
         clevis-luks-common-functions \
         clevis-luks-common-functions \
         grep sed cut \
         grep sed cut \
         clevis-decrypt \
         clevis-decrypt \

src/luks/systemd/dracut/meson.build → src/luks/dracut/meson.build


+ 4 - 2
src/luks/meson.build

@@ -1,7 +1,6 @@
 
 
 luksmeta_data = configuration_data()
 luksmeta_data = configuration_data()
 luksmeta = dependency('luksmeta', version: '>=8', required: false)
 luksmeta = dependency('luksmeta', version: '>=8', required: false)
-pwmake = find_program('pwmake', required: false)
 
 
 libcryptsetup = dependency('libcryptsetup', version: '>=2.0.4', required: false)
 libcryptsetup = dependency('libcryptsetup', version: '>=2.0.4', required: false)
 if libcryptsetup.found()
 if libcryptsetup.found()
@@ -33,8 +32,11 @@ clevis_luks_unbind = configure_file(input: 'clevis-luks-unbind.in',
                output: 'clevis-luks-unbind',
                output: 'clevis-luks-unbind',
                configuration: luksmeta_data)
                configuration: luksmeta_data)
 
 
-if libcryptsetup.found() and luksmeta.found() and pwmake.found()
+if libcryptsetup.found() and luksmeta.found()
   subdir('systemd')
   subdir('systemd')
+  # systemd should come before dracut in order to set up
+  # variables like SYSTEMD_REPLY_PASS.
+  subdir('dracut')
   subdir('udisks2')
   subdir('udisks2')
 
 
   bins += clevis_luks_unbind
   bins += clevis_luks_unbind

+ 0 - 2
src/luks/systemd/dracut/clevis/clevis-hook.sh.in

@@ -1,2 +0,0 @@
-#!/bin/bash
-@libexecdir@/clevis-luks-askpass

+ 0 - 1
src/luks/systemd/meson.build

@@ -10,7 +10,6 @@ sd_reply_pass = find_program(
 
 
 if systemd.found() and sd_reply_pass.found()
 if systemd.found() and sd_reply_pass.found()
   data.set('SYSTEMD_REPLY_PASS', sd_reply_pass.path())
   data.set('SYSTEMD_REPLY_PASS', sd_reply_pass.path())
-  subdir('dracut')
 
 
   unitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
   unitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
 
 

+ 3 - 0
src/luks/tests/meson.build

@@ -100,3 +100,6 @@ if luksmeta_data.get('OLD_CRYPTSETUP') == '0'
   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)
   test('pass-tang-luks2', find_program('pass-tang-luks2'), env: env, timeout: 60)
 endif
 endif
+
+test('unlock-arbitrary-parameter', find_program('unlock-arbitrary-parameter'), env: env)
+

+ 68 - 0
src/luks/tests/unlock-arbitrary-parameter

@@ -0,0 +1,68 @@
+#!/bin/bash -ex
+# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
+#
+# 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
+trap 'on_exit' ERR
+
+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")
+
+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
+
+TESTPARAM="arbitrarytestparameter"
+
+#set up a "cryptsetup" function, to hijack the command
+cryptsetup () { 
+    #need to handle "cryptsetup isLuks" from clevis-luks-unlock, among others   
+    if [[ $1 == "isLuks" ]]; then
+        exit 0;
+    elif [[ $1 == "luksUUID" ]]; then
+        echo "TESTINGLUKSUUID"
+        exit 0;
+    else
+        echo "$*" | grep -q -- "${TESTPARAM}"
+        exit $?
+    fi
+}
+export -f cryptsetup
+
+if ! clevis-luks-unlock -o "$TESTPARAM" -d ${DEV} -n clevis_unlock_test; then
+    error "${TEST}: clevis luks unlock did not match arbitrary test parameter \"$TESTPARAM\"."
+fi

+ 3 - 0
src/luks/udisks2/clevis-luks-udisks2.c

@@ -591,6 +591,9 @@ main(int argc, char *const argv[])
         req.used = recv(pair[0], req.data, sizeof(req.data), 0);
         req.used = recv(pair[0], req.data, sizeof(req.data), 0);
         if (req.used < 1 || req.data[req.used - 1])
         if (req.used < 1 || req.data[req.used - 1])
             break;
             break;
+        /* Technically, req.data is already NULL-terminated, but let's
+         * be explicit. */
+        req.data[req.used - 1] = '\0';
 
 
         if (crypt_init(&cd, req.data) < 0)
         if (crypt_init(&cd, req.data) < 0)
             goto next;
             goto next;

+ 1 - 0
src/pins/sss/clevis-decrypt-sss.c

@@ -275,6 +275,7 @@ main(int argc, char *argv[])
         const uint8_t *xy[t];
         const uint8_t *xy[t];
         size_t i = 0;
         size_t i = 0;
 
 
+        memset(xy, 0, t * sizeof(uint8_t));
         for (struct pin *pin = chldrn.next; pin != &chldrn; pin = pin->next) {
         for (struct pin *pin = chldrn.next; pin != &chldrn; pin = pin->next) {
             if (pin->pt && i < (size_t) t)
             if (pin->pt && i < (size_t) t)
                 xy[i++] = pin->pt;
                 xy[i++] = pin->pt;