From 03127b4e4658df5ae528706235161c7e9501d5c6 Mon Sep 17 00:00:00 2001 From: Luc Date: Mon, 10 Feb 2025 15:36:04 +0100 Subject: [PATCH 01/31] src/zlevis-decrypt: update w.r.t. issue #1 --- src/zlevis-decrypt | 67 ++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/src/zlevis-decrypt b/src/zlevis-decrypt index c218fbd..9fcc270 100755 --- a/src/zlevis-decrypt +++ b/src/zlevis-decrypt @@ -25,15 +25,6 @@ if [ -t 0 ]; then exit 2 fi -# Function to clean up temporary files on exit -on_exit() { - if [ ! -d "$tmp" ] || ! rm -rf "$tmp"; then - echo "Delete temporary files failed" >&2 - echo "You need to clean up: $tmp" >&2 - exit 1 - fi -} - # Get the version of tpm2-tools tpm2tools_version=$(tpm2_createprimary -v | awk -F'version="' '{print $2}' | awk -F'.' '{print $1}') @@ -43,73 +34,69 @@ if [ -z "$tpm2tools_version" ] || [ "$tpm2tools_version" -lt 4 ] || [ "$tpm2tool exit 1 fi -# Create a temporary directory for TPM files -if ! tmp="$(mktemp -d)"; then - echo "Creating a temporary dir for TPM files failed" >&2 - exit 1 -fi - -# Set up cleanup on exit -trap 'on_exit' EXIT - # Read the JWE protected header read -r -d . hdr -echo "$hdr" > "$tmp"/hdr # Decode the JWE protected header -if ! jhd="$(jose b64 dec -i- < "$tmp"/hdr)"; then +if ! jhd="$(printf "%s" "$hdr" | jose b64 dec -i-)"; then echo "Error decoding JWE protected header" >&2 exit 1 fi -echo "$jhd" > "$tmp"/jhd # Validate the JWE pin type -if [ "$(jose fmt -j- -Og zlevis -g pin -u- < "$tmp"/jhd)" != "tpm2" ]; then +if [ "$(printf "%s" "$jhd" | jose fmt -j- -Og zlevis -g pin -u-)" != "tpm2" ]; then echo "JWE pin mismatch" >&2 exit 1 fi # Extract required parameters from the JWE header -if ! hash="$(jose fmt -j- -Og zlevis -g tpm2 -g hash -Su- < "$tmp"/jhd)"; then +if ! hash="$(printf "%s" "$jhd" | jose fmt -j- -Og zlevis -g tpm2 -g hash -Su-)"; then echo "JWE missing required 'hash' header parameter!" >&2 exit 1 fi -if ! key="$(jose fmt -j- -Og zlevis -g tpm2 -g key -Su- < "$tmp"/jhd)"; then +if ! key="$(printf "%s" "$jhd" | jose fmt -j- -Og zlevis -g tpm2 -g key -Su-)"; then echo "JWE missing required 'key' header parameter!" >&2 exit 1 fi -if ! jwk_pub="$(jose fmt -j- -Og zlevis -g tpm2 -g jwk_pub -Su- < "$tmp"/jhd)"; then +if ! jwk_pub="$(printf "%s" "$jhd" | jose fmt -j- -Og zlevis -g tpm2 -g jwk_pub -Su-)"; then echo "JWE missing required 'jwk_pub' header parameter!" >&2 exit 1 fi -echo "$jwk_pub" > "$tmp"/jwk_pub -if ! jwk_priv="$(jose fmt -j- -Og zlevis -g tpm2 -g jwk_priv -Su- < "$tmp"/jhd)"; then +if ! jwk_priv="$(printf "%s" "$jhd" | jose fmt -j- -Og zlevis -g tpm2 -g jwk_priv -Su-)"; then echo "JWE missing required 'jwk_priv' header parameter!" >&2 exit 1 fi -echo "$jwk_priv" > "$tmp"/jwk_priv # Handle optional PCR parameters -pcr_ids="$(jose fmt -j- -Og zlevis -g tpm2 -g pcr_ids -Su- < "$tmp"/jhd)" || true +pcr_ids="$(printf "%s" "$jhd" | jose fmt -j- -Og zlevis -g tpm2 -g pcr_ids -Su-)" || true pcr_spec="" if [ -n "$pcr_ids" ]; then - pcr_bank="$(jose fmt -j- -Og zlevis -g tpm2 -g pcr_bank -Su- < "$tmp"/jhd)" + pcr_bank="$(printf "%s" "$jhd" | jose fmt -j- -Og zlevis -g tpm2 -g pcr_bank -Su-)" pcr_spec="$pcr_bank:$pcr_ids" fi +# Define and trap tmp jwk_pub and jwk_priv +tmp_jwk_pub = "/tmp/jwk_pub.$" +tmp_jwk_priv = "/tmp/jwk_priv.$" +trap 'rm -f "$tmp_jwk_pub" "$tmp_jwk_priv"' EXIT + # Decode the public and private keys from Base64 -if ! jose b64 dec -i- -O "$tmp"/jwk.pub < "$tmp"/jwk_pub; then +if ! printf "%s" "$jwk_pub" | jose b64 dec -i- -O "$tmp_jwk_pub"; then echo "Decoding jwk.pub from Base64 failed" >&2 exit 1 fi -if ! jose b64 dec -i- -O "$tmp"/jwk.priv < "$tmp"/jwk_priv; then +if ! printf "%s" "$jwk_priv" | jose b64 dec -i- -O "$tmp_jwk_priv"; then echo "Decoding jwk.priv from Base64 failed" >&2 exit 1 fi +# Define and trap primary_context +tmp_primary_context = "/tmp/primary_context.$" +trap 'rm -f "$tmp_jwk_pub" "$tmp_jwk_priv" "$tmp_primary_context"' EXIT + # Create the primary key in the TPM case "$tpm2tools_version" in - 4|5) 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 @@ -118,9 +105,13 @@ if [ -n "$fail" ]; then fi tpm2_flushcontext -t +# Define and trap load_context +tmp_load_context = "/tmp/load_context.$" +trap 'rm -f "$tmp_jwk_pub" "$tmp_jwk_priv" "$tmp_primary_context" "$tmp_load_context"' EXIT + # Load the JWK into the TPM case "$tpm2tools_version" in - 4|5) 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 @@ -129,9 +120,12 @@ if [ -n "$fail" ]; then fi tpm2_flushcontext -t +# Remove tmp_jwk_pub, tmp_jwk_priv and tmp_primary_context +rm -f "$tmp_jwk_pub" "$tmp_jwk_priv" "$tmp_primary_context" + # Unseal the JWK from the TPM case "$tpm2tools_version" in - 4|5) 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 @@ -140,6 +134,9 @@ if [ -n "$fail" ]; then fi tpm2_flushcontext -t +# Remove tmp_load_context +rm -f "$tmp_load_context" + # Output the decrypted JWK along with the original header (echo "$jwk$hdr."; /bin/cat) | jose jwe dec -k- -i- From 024ea1195b6b0246f1c597b81d67fb467094c220 Mon Sep 17 00:00:00 2001 From: Luc Date: Mon, 10 Feb 2025 15:44:04 +0100 Subject: [PATCH 02/31] src/zlevis-decrypt: removed minor bug --- src/zlevis-decrypt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/zlevis-decrypt b/src/zlevis-decrypt index 9fcc270..db9cfab 100755 --- a/src/zlevis-decrypt +++ b/src/zlevis-decrypt @@ -76,8 +76,8 @@ if [ -n "$pcr_ids" ]; then fi # Define and trap tmp jwk_pub and jwk_priv -tmp_jwk_pub = "/tmp/jwk_pub.$" -tmp_jwk_priv = "/tmp/jwk_priv.$" +tmp_jwk_pub="/tmp/jwk_pub.$" +tmp_jwk_priv="/tmp/jwk_priv.$" trap 'rm -f "$tmp_jwk_pub" "$tmp_jwk_priv"' EXIT # Decode the public and private keys from Base64 @@ -91,7 +91,7 @@ if ! printf "%s" "$jwk_priv" | jose b64 dec -i- -O "$tmp_jwk_priv"; then fi # Define and trap primary_context -tmp_primary_context = "/tmp/primary_context.$" +tmp_primary_context="/tmp/primary_context.$" trap 'rm -f "$tmp_jwk_pub" "$tmp_jwk_priv" "$tmp_primary_context"' EXIT # Create the primary key in the TPM @@ -106,7 +106,7 @@ fi tpm2_flushcontext -t # Define and trap load_context -tmp_load_context = "/tmp/load_context.$" +tmp_load_context="/tmp/load_context.$" trap 'rm -f "$tmp_jwk_pub" "$tmp_jwk_priv" "$tmp_primary_context" "$tmp_load_context"' EXIT # Load the JWK into the TPM From 67e14db93014b7accfaa096fc0aca0e157b4496a Mon Sep 17 00:00:00 2001 From: Luc Date: Mon, 10 Feb 2025 15:55:18 +0100 Subject: [PATCH 03/31] src/zlevis-decrypt: added id to tmp-files properly --- src/zlevis-decrypt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/zlevis-decrypt b/src/zlevis-decrypt index db9cfab..c839ee7 100755 --- a/src/zlevis-decrypt +++ b/src/zlevis-decrypt @@ -76,8 +76,8 @@ if [ -n "$pcr_ids" ]; then fi # Define and trap tmp jwk_pub and jwk_priv -tmp_jwk_pub="/tmp/jwk_pub.$" -tmp_jwk_priv="/tmp/jwk_priv.$" +tmp_jwk_pub="/tmp/jwk_pub.$$" +tmp_jwk_priv="/tmp/jwk_priv.$$" trap 'rm -f "$tmp_jwk_pub" "$tmp_jwk_priv"' EXIT # Decode the public and private keys from Base64 @@ -91,7 +91,7 @@ if ! printf "%s" "$jwk_priv" | jose b64 dec -i- -O "$tmp_jwk_priv"; then fi # Define and trap primary_context -tmp_primary_context="/tmp/primary_context.$" +tmp_primary_context="/tmp/primary_context.$$" trap 'rm -f "$tmp_jwk_pub" "$tmp_jwk_priv" "$tmp_primary_context"' EXIT # Create the primary key in the TPM @@ -106,7 +106,7 @@ fi tpm2_flushcontext -t # Define and trap load_context -tmp_load_context="/tmp/load_context.$" +tmp_load_context="/tmp/load_context.$$" trap 'rm -f "$tmp_jwk_pub" "$tmp_jwk_priv" "$tmp_primary_context" "$tmp_load_context"' EXIT # Load the JWK into the TPM From 3344160e528b06220f9f84cb5effb74f6b947221 Mon Sep 17 00:00:00 2001 From: Luc Date: Tue, 11 Feb 2025 21:13:31 +0100 Subject: [PATCH 04/31] src/zlevis-encrypt: update w.r.t. issue #1 --- src/zlevis-encrypt | 79 +++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/zlevis-encrypt b/src/zlevis-encrypt index f604242..267e56e 100755 --- a/src/zlevis-encrypt +++ b/src/zlevis-encrypt @@ -58,15 +58,6 @@ validate_pcrs() { return 0 } -# Function to clean up temporary files on exit -on_exit() { - if [ ! -d "$tmp" ] || ! rm -rf "$tmp"; then - echo "Delete temporary files failed" >&2 - echo "You need to clean up: $tmp" >&2 - exit 1 - fi -} - # Get the version of tpm2-tools tpm2tools_version=$(tpm2_createprimary -v | awk -F'version="' '{print $2}' | awk -F'.' '{print $1}') @@ -76,30 +67,18 @@ if [ -z "$tpm2tools_version" ] || [ "$tpm2tools_version" -lt 4 ] || [ "$tpm2tool exit 1 fi -# Create a temporary directory for TPM files -if ! tmp="$(mktemp -d)"; then - echo "Creating a temporary dir for TPM files failed" >&2 - exit 1 -fi - -# Set up cleanup on exit -trap 'on_exit' EXIT - # Validate the configuration input if ! cfg="$(jose fmt -j "$1" -Oo- 2>/dev/null)"; then echo "Configuration is malformed" >&2 exit 1 fi -# Store the configuration in a temporary file -echo "$cfg" > "$tmp"/cfg - # Extract hash and key from the configuration, defaulting if not present -hash="$(jose fmt -j- -Og hash -u- < "$tmp"/cfg)" || hash="sha256" -key="$(jose fmt -j- -Og key -u- < "$tmp"/cfg)" || key="ecc" +hash="$(printf "%s" "$cfg" | jose fmt -j- -Og hash -u-)" || hash="sha256" +key="$(printf "%s" "$cfg" | jose fmt -j- -Og key -u-)" || key="ecc" # Determine the PCR bank to use for policy -pcr_bank="$(jose fmt -j- -Og pcr_bank -u- < "$tmp"/cfg)" || { +pcr_bank="$(printf "%s" "$cfg" | jose fmt -j- -Og pcr_bank -u-)" || { # If not specified, find a non-empty PCR algorithm bank if ! pcr_bank=$(tpm2_getcap pcrs | awk '/^[[:space:]]*-[[:space:]]*([^:]+):[[:space:]]*\[[[:space:]]*[^][:space:]]/ {found=1; split($0, m, /[-:[:space:]]+/); print m[2]; exit} END {exit !found}'); then echo "Unable to find non-empty PCR algorithm bank, please check output of tpm2_getcap pcrs" >&2 @@ -108,15 +87,14 @@ pcr_bank="$(jose fmt -j- -Og pcr_bank -u- < "$tmp"/cfg)" || { } # Trim spaces from the configuration for parsing PCR IDs -pcr_cfg=$(tr -d '[:space:]' < "$tmp"/cfg) -echo "$pcr_cfg" > "$tmp"/pcr_cfg +pcr_cfg=$(printf "%s" "$cfg" | tr -d '[:space:]') # Handle both string and JSON array formats for pcr_ids -if jose fmt -j- -Og pcr_ids 2>/dev/null < "$tmp"/pcr_cfg && ! pcr_ids="$(jose fmt -j- -Og pcr_ids -u- 2>/dev/null < "$tmp"/pcr_cfg)"; then +if printf "%s" "$pcr_cfg" | jose fmt -j- -Og pcr_ids 2>/dev/null && ! pcr_ids="$(jose fmt -j- -Og pcr_ids -u- 2>/dev/null < "$tmp"/pcr_cfg)"; then # Attempt to parse as a JSON array if string parsing fails - if jose fmt -j- -Og pcr_ids -A 2>/dev/null < "$tmp"/pcr_cfg; then + if printf "%s" "$pcr_cfg" | jose fmt -j- -Og pcr_ids -A 2>/dev/null; then # Construct a comma-separated string from the array - for pcr in $(jose fmt -j- -Og pcr_ids -Af- < "$tmp"/pcr_cfg | tr -d '"'); do + for pcr in $(printf "%s" "$pcr_cfg" | jose fmt -j- -Og pcr_ids -Af- | tr -d '"'); do pcr_ids=$(printf '%s,%s' "${pcr_ids}" "${pcr}") done # Remove leading comma @@ -134,19 +112,21 @@ if ! validate_pcrs "${tpm2tools_version}" "${pcr_bank}" "${pcr_ids}"; then fi # Get the PCR digest from the configuration or read it if not provided -pcr_digest="$(jose fmt -j- -Og pcr_digest -u- < "$tmp"/cfg)" || true -echo "$pcr_digest" > "$tmp"/pcr_digest +pcr_digest="$(printf "%s" "$cfg" | jose fmt -j- -Og pcr_digest -u-)" || true # Generate a JSON Web Key (JWK) if ! jwk="$(jose jwk gen -i '{"alg":"A256GCM"}')"; then echo "Generating a jwk failed" >&2 exit 1 fi -echo "$jwk" > "$tmp"/jwk + +# Define and trap primary_context +tmp_primary_context="/tmp/primary_context.$$" +trap 'rm -f "$tmp_primary_context"' EXIT # Create the primary key in the TPM case "$tpm2tools_version" in - 4|5) 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 @@ -155,12 +135,17 @@ if [ -n "$fail" ]; then fi tpm2_flushcontext -t +# Define and trap pcr_digest and pcr_policy +tmp_pcr_digest="/tmp/pcr_digest.$$" +tmp_pcr_policy="/tmp/pcr_policy.$$" +trap 'rm -f "$tmp_primary_context" "$tmp_pcr_digest" "$tmp_pcr_policy"' EXIT + # Handle PCRs and policy creation if PCR IDs are provided policy_options="" if [ -n "$pcr_ids" ]; then if [ -z "$pcr_digest" ]; then case "$tpm2tools_version" in - 4|5) 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 @@ -169,7 +154,7 @@ if [ -n "$pcr_ids" ]; then fi tpm2_flushcontext -t else - if ! jose b64 dec -i- -O "$tmp"/pcr.digest < "$tmp"/pcr_digest; then + if ! printf "%s" "$pcr_digest" | jose b64 dec -i- -O "$tmp_pcr_digest"; then echo "Error decoding PCR digest" >&2 exit 1 fi @@ -177,7 +162,7 @@ if [ -n "$pcr_ids" ]; then # Create the policy based on PCRs case "$tpm2tools_version" in - 4|5) tpm2_createpolicy -Q -g "$hash" --policy-pcr -l "$pcr_bank":"$pcr_ids" -f "$tmp"/pcr.digest -L "$tmp"/pcr.policy || fail=$?;; + 4|5) tpm2_createpolicy -Q -g "$hash" --policy-pcr -l "$pcr_bank":"$pcr_ids" -f "$tmp_pcr_digest" -L "$tmp_pcr_policy" || fail=$?;; *) fail=1;; esac if [ -n "$fail" ]; then @@ -188,15 +173,23 @@ if [ -n "$pcr_ids" ]; then tpm2_flushcontext -l # Set the policy options to the created policy file - policy_options="$tmp/pcr.policy" + policy_options="$tmp_pcr_policy" else # If no PCR IDs are provided, add user authentication to the object attributes obj_attr="$obj_attr|userwithauth" fi +# Remove tmp_pcr_digest and tmp_pcr_policy +rm -f "$tmp_pcr_digest" "$tmp_pcr_policy" + +# Define and trap tmp jwk_pub and jwk_priv +tmp_jwk_pub="/tmp/jwk_pub.$$" +tmp_jwk_priv="/tmp/jwk_priv.$$" +trap 'rm -f "$tmp_primary_context" "$tmp_jwk_pub" "$tmp_jwk_priv"' EXIT + # Create the TPM2 object for the JWK case "$tpm2tools_version" in - 4|5) tpm2_create -Q -g "$hash" -C "$tmp"/primary.context -u "$tmp"/jwk.pub -r "$tmp"/jwk.priv -a "$obj_attr" -L "$policy_options" -i- < "$tmp"/jwk || fail=$?;; + 4|5) printf "%s" "$jwk" | tpm2_create -Q -g "$hash" -C "$tmp_primary_context" -u "$tmp_jwk_pub" -r "$tmp_jwk_priv" -a "$obj_attr" -L "$policy_options" -i- || fail=$?;; *) fail=1;; esac if [ -n "$fail" ]; then @@ -205,16 +198,22 @@ if [ -n "$fail" ]; then fi tpm2_flushcontext -t +# Remove tmp_primary_context +rm -f "$tmp_primary_context" + # Encode the JWK public and private keys in Base64 -if ! jwk_pub="$(jose b64 enc -I "$tmp"/jwk.pub)"; then +if ! jwk_pub="$(jose b64 enc -I "$tmp_jwk_pub")"; then echo "Encoding jwk.pub in Base64 failed" >&2 exit 1 fi -if ! jwk_priv="$(jose b64 enc -I "$tmp"/jwk.priv)"; then +if ! jwk_priv="$(jose b64 enc -I "$tmp_jwk_priv")"; then echo "Encoding jwk.priv in Base64 failed" >&2 exit 1 fi +# Remove tmp_jwk_pub and tmp_jwk_priv +rm -f "$tmp_jwk_pub" "$tmp_jwk_priv" + # Construct the JWE (JSON Web Encryption) structure jwe='{"protected":{"zlevis":{"pin":"tpm2","tpm2":{}}}}' jwe="$(jose fmt -j "$jwe" -g protected -g zlevis -g tpm2 -q "$hash" -s hash -UUUUo-)" From 788a251e6bd7fb3eb4a126c8188cc5e94e5b3f5d Mon Sep 17 00:00:00 2001 From: Luc Date: Thu, 13 Feb 2025 21:17:53 +0100 Subject: [PATCH 05/31] src/zlevis: add main binary w.r.t. issue #2 --- src/zlevis | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/zlevis diff --git a/src/zlevis b/src/zlevis new file mode 100644 index 0000000..fc9b701 --- /dev/null +++ b/src/zlevis @@ -0,0 +1,39 @@ +#!/bin/sh + +# Exit immediately if a command exits with a non-zero status +set -e + +# Summary of the script's functionality +summary="A tool that enables automatic decryption of ZFS rpools with TPM2" + +# Display summary if requested +if [ "$1" = "--summary" ]; then + echo "$summary" + exit 0 +fi + +# Display usage information if input is from a terminal +if [ -t 0 ]; then + exec >&2 + echo "Usage: zlevis {decrypt|encrypt} {pool|*} [options]" + exit 2 +fi + +case "$1" in + decrypt) + case "$2" in + pool) zfs list -Ho tpm:jwe $3 | zlevis-decrypt;; + *) zlevis-decrypt $2;; + esac + ;; + encrypt) + case "$2" in + pool) read -r -d . key || zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt $4) $3;; + *) zlevis-encrypt $2;; + esac + ;; + *) exit 1;; +esac + +# Exit with the status of the last command +exit $? \ No newline at end of file From 0454a9c388da74fb2f2dde33df6b1e8bf32bbcb1 Mon Sep 17 00:00:00 2001 From: Luc Date: Thu, 13 Feb 2025 21:18:26 +0100 Subject: [PATCH 06/31] src/meson.build: add zlevis --- src/meson.build | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/meson.build b/src/meson.build index 509d9af..fa1bb45 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,14 +1,17 @@ # Find scripts +main = find_program('zlevis') encrypt = find_program('zlevis-encrypt') decrypt = find_program('zlevis-decrypt') fetch = find_program('zlevis-fetch') # Test the scripts +test('zlevis', main, args: '--summary') test('zlevis-encrypt', encrypt, args: '--summary') test('zlevis-decrypt', decrypt, args: '--summary') test('zlevis-fetch', fetch, args: '--summary') # Add paths of scripts to bins +bins += join_paths(meson.current_source_dir(), 'zlevis') bins += join_paths(meson.current_source_dir(), 'zlevis-encrypt') bins += join_paths(meson.current_source_dir(), 'zlevis-decrypt') bins += join_paths(meson.current_source_dir(), 'zlevis-fetch') \ No newline at end of file From 1bb31363c1c4aed953835a74789a6d3461708919 Mon Sep 17 00:00:00 2001 From: Luc Date: Thu, 13 Feb 2025 21:19:05 +0100 Subject: [PATCH 07/31] src/zlevis-decrypt: update usage information --- src/zlevis-decrypt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/zlevis-decrypt b/src/zlevis-decrypt index c839ee7..f079835 100755 --- a/src/zlevis-decrypt +++ b/src/zlevis-decrypt @@ -18,10 +18,7 @@ fi # Display usage information if input is from a terminal if [ -t 0 ]; then exec >&2 - echo "$summary" - echo echo "Usage: \"zlevis-decrypt < file.jwe\"" - echo "Usage ZFS: \"zfs list -Ho tpm:jwe | zlevis-decrypt\"" exit 2 fi From d6376c2672ecd7287e92b0bd4a29261dd259bc4c Mon Sep 17 00:00:00 2001 From: Luc Date: Thu, 13 Feb 2025 21:19:34 +0100 Subject: [PATCH 08/31] src/zlevis-encrypt: update usage information --- src/zlevis-encrypt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/zlevis-encrypt b/src/zlevis-encrypt index 267e56e..b58c508 100755 --- a/src/zlevis-encrypt +++ b/src/zlevis-encrypt @@ -21,7 +21,7 @@ fi # Display usage information if input is from a terminal if [ -t 0 ]; then exec >&2 - echo "$summary" + echo "Usage: \"zlevis-encrypt '{\"property\":\"value\"}' < file.key > file.jwe\"" echo echo "This command uses the following configuration properties:" echo " hash: -> Hash algorithm used in the computation of the object name (default: sha256)." @@ -29,9 +29,6 @@ if [ -t 0 ]; then echo " pcr_bank: -> PCR algorithm bank to use for policy (default: first supported by TPM)." echo " pcr_ids: -> PCR list used for policy. If not present, no policy is used." echo " pcr_digest: -> Binary PCR hashes encoded in base64. If not present, the hash values are looked up." - echo - echo "Usage: \"zlevis-encrypt '{\"property\":\"value\"}' < file.key > file.jwe\"" - echo "Usage ZFS: \"zfs set tpm:jwe=\$(zlevis-encrypt '{\"property\":\"value\"}' < tank.key) \"" exit 2 fi From 9bddc2d8daeb05dd804339659b96063447e1d90f Mon Sep 17 00:00:00 2001 From: Luc Date: Thu, 13 Feb 2025 21:26:02 +0100 Subject: [PATCH 09/31] src/zlevis: made executable --- src/zlevis | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 src/zlevis diff --git a/src/zlevis b/src/zlevis old mode 100644 new mode 100755 From 44e6d7efd0a276f767f945c2580bed03ba85a28e Mon Sep 17 00:00:00 2001 From: Luc Date: Thu, 13 Feb 2025 21:26:31 +0100 Subject: [PATCH 10/31] README.md: useful update --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 80dddc0..aa9b3f2 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,10 @@ Zlevis can be manually installed with `meson`, after cloning the repository, set $ meson setup builddir ``` +> Using the `--prefix=/usr` flag will install `zlevis` in `/usr/bin` instead of `/usr/local/bin`. + +> Using the `--reconfigure` flag will reconfigure the build directory. + Installation of the zlevis scripts is now performed with ``` From f022b1fe3c0d98cd7a2b75e08353dd25bc8a3516 Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 14 Feb 2025 21:22:52 +0100 Subject: [PATCH 11/31] src/zlevis: specified options --- src/zlevis | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/zlevis b/src/zlevis index fc9b701..85a6733 100755 --- a/src/zlevis +++ b/src/zlevis @@ -15,21 +15,23 @@ fi # Display usage information if input is from a terminal if [ -t 0 ]; then exec >&2 - echo "Usage: zlevis {decrypt|encrypt} {pool|*} [options]" + echo "Usage: \"zlevis {decrypt|encrypt} {pool|key} [options]\"" exit 2 fi case "$1" in decrypt) - case "$2" in + case "$2" in pool) zfs list -Ho tpm:jwe $3 | zlevis-decrypt;; - *) zlevis-decrypt $2;; + key) zlevis-decrypt;; + *) exit 1;; esac ;; encrypt) case "$2" in pool) read -r -d . key || zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt $4) $3;; - *) zlevis-encrypt $2;; + key) zlevis-encrypt $3;; + *) exit 1;; esac ;; *) exit 1;; From 078495815c3eaa919bbe714eee5ea63d2a76cd86 Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 14 Feb 2025 22:08:23 +0100 Subject: [PATCH 12/31] scr/zlevis: update format --- src/zlevis | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/zlevis b/src/zlevis index 85a6733..06c9f2a 100755 --- a/src/zlevis +++ b/src/zlevis @@ -12,6 +12,24 @@ if [ "$1" = "--summary" ]; then exit 0 fi +case "$1" in + "decrypt") + case "$2" in + "pool") zfs list -Ho tpm:jwe "$3" | zlevis-decrypt;; + "key") zlevis-decrypt;; + *) exit 1;; + esac + ;; + "encrypt") + case "$2" in + "pool") read -r -d . key || zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt "$4") "$3";; + "key") zlevis-encrypt "$3";; + *) exit 1;; + esac + ;; + *) exit 1;; +esac + # Display usage information if input is from a terminal if [ -t 0 ]; then exec >&2 @@ -19,23 +37,5 @@ if [ -t 0 ]; then exit 2 fi -case "$1" in - decrypt) - case "$2" in - pool) zfs list -Ho tpm:jwe $3 | zlevis-decrypt;; - key) zlevis-decrypt;; - *) exit 1;; - esac - ;; - encrypt) - case "$2" in - pool) read -r -d . key || zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt $4) $3;; - key) zlevis-encrypt $3;; - *) exit 1;; - esac - ;; - *) exit 1;; -esac - # Exit with the status of the last command exit $? \ No newline at end of file From e0424c61a8fbd316f553fe2380b133696cdc1f78 Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 14 Feb 2025 22:09:06 +0100 Subject: [PATCH 13/31] src/zlevis-decrypt update error messages --- src/zlevis-decrypt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/zlevis-decrypt b/src/zlevis-decrypt index f079835..a0e9bad 100755 --- a/src/zlevis-decrypt +++ b/src/zlevis-decrypt @@ -48,19 +48,19 @@ fi # Extract required parameters from the JWE header if ! hash="$(printf "%s" "$jhd" | jose fmt -j- -Og zlevis -g tpm2 -g hash -Su-)"; then - echo "JWE missing required 'hash' header parameter!" >&2 + echo "JWE missing required 'hash' header parameter" >&2 exit 1 fi if ! key="$(printf "%s" "$jhd" | jose fmt -j- -Og zlevis -g tpm2 -g key -Su-)"; then - echo "JWE missing required 'key' header parameter!" >&2 + echo "JWE missing required 'key' header parameter" >&2 exit 1 fi if ! jwk_pub="$(printf "%s" "$jhd" | jose fmt -j- -Og zlevis -g tpm2 -g jwk_pub -Su-)"; then - echo "JWE missing required 'jwk_pub' header parameter!" >&2 + echo "JWE missing required 'jwk_pub' header parameter" >&2 exit 1 fi if ! jwk_priv="$(printf "%s" "$jhd" | jose fmt -j- -Og zlevis -g tpm2 -g jwk_priv -Su-)"; then - echo "JWE missing required 'jwk_priv' header parameter!" >&2 + echo "JWE missing required 'jwk_priv' header parameter" >&2 exit 1 fi From 6f2a1051883ee2b1a0cc9ba814c9954b6223fa8e Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 14 Feb 2025 22:09:28 +0100 Subject: [PATCH 14/31] src/zlevis-encrypt: update error message --- src/zlevis-encrypt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zlevis-encrypt b/src/zlevis-encrypt index b58c508..a03ded1 100755 --- a/src/zlevis-encrypt +++ b/src/zlevis-encrypt @@ -66,7 +66,7 @@ fi # Validate the configuration input if ! cfg="$(jose fmt -j "$1" -Oo- 2>/dev/null)"; then - echo "Configuration is malformed" >&2 + echo "Configuration '{\"property\":\"value\"}' is malformed" >&2 exit 1 fi From d42a13b5601905e9a961de03196b6bb7148b22f4 Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 14 Feb 2025 23:15:36 +0100 Subject: [PATCH 15/31] src/zlevis: updated info call --- src/zlevis | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/zlevis b/src/zlevis index 06c9f2a..a81feed 100755 --- a/src/zlevis +++ b/src/zlevis @@ -12,30 +12,31 @@ if [ "$1" = "--summary" ]; then exit 0 fi +# Function to display usage information when called +info() { + exec >&2 + echo "Usage: \"zlevis {decrypt|encrypt} {pool|key} [options]\"" + exit 2 +} + +# Case statement to handle the argument path case "$1" in "decrypt") case "$2" in "pool") zfs list -Ho tpm:jwe "$3" | zlevis-decrypt;; "key") zlevis-decrypt;; - *) exit 1;; + *) info;; esac ;; "encrypt") case "$2" in - "pool") read -r -d . key || zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt "$4") "$3";; + "pool") read -r -d . key && zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt "$4") "$3";; "key") zlevis-encrypt "$3";; - *) exit 1;; + *) info;; esac ;; - *) exit 1;; + *) info;; esac -# Display usage information if input is from a terminal -if [ -t 0 ]; then - exec >&2 - echo "Usage: \"zlevis {decrypt|encrypt} {pool|key} [options]\"" - exit 2 -fi - # Exit with the status of the last command exit $? \ No newline at end of file From 17eb015918c1347028fb4e33d522ad29f5207341 Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 14 Feb 2025 23:46:19 +0100 Subject: [PATCH 16/31] src/zlevis: restructured argument path structure --- src/zlevis | 73 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/src/zlevis b/src/zlevis index a81feed..2b6967e 100755 --- a/src/zlevis +++ b/src/zlevis @@ -12,31 +12,64 @@ if [ "$1" = "--summary" ]; then exit 0 fi -# Function to display usage information when called +# Function to display usage information of zlevis info() { exec >&2 - echo "Usage: \"zlevis {decrypt|encrypt} {pool|key} [options]\"" + echo "Usage: \"zlevis {decrypt|encrypt} {pool|key}\"" exit 2 } -# Case statement to handle the argument path -case "$1" in - "decrypt") - case "$2" in - "pool") zfs list -Ho tpm:jwe "$3" | zlevis-decrypt;; - "key") zlevis-decrypt;; - *) info;; - esac - ;; - "encrypt") - case "$2" in - "pool") read -r -d . key && zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt "$4") "$3";; - "key") zlevis-encrypt "$3";; - *) info;; - esac - ;; - *) info;; -esac +# Function to display usage information of zlevis encrypt pool +encrypt_pool_info() { + exec >&2 + echo "Usage: \"zlevis encrypt pool '{\"property\":\"value\"}' < file.key\"" + echo + echo "This command uses the following configuration properties:" + echo " hash: -> Hash algorithm used in the computation of the object name (default: sha256)." + echo " key: -> Algorithm type for the generated key (default: ecc)." + echo " pcr_bank: -> PCR algorithm bank to use for policy (default: first supported by TPM)." + echo " pcr_ids: -> PCR list used for policy. If not present, no policy is used." + echo " pcr_digest: -> Binary PCR hashes encoded in base64. If not present, the hash values are looked up." + exit 2 +} + +# Determine the argument path and execute the relevant script or function +if [ -t 0]; then + case "$1" in + "decrypt") + case "$2" in + "pool") zfs list -Ho tpm:jwe "$3" | zlevis-decrypt;; + "key") zlevis-decrypt;; + *) info;; + esac + ;; + "encrypt") + case "$2" in + "pool") encrypt_pool_info;; + "key") zlevis-encrypt;; + *) info;; + esac + ;; + *) info;; + esac +else + case "$1" in + "decrypt") + case "$2" in + "key") zlevis-decrypt;; + *) info;; + esac + ;; + "encrypt") + case "$2" in + "pool") read -r -d . key || zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt "$4") "$3";; + "key") zlevis-encrypt "$3";; + *) info;; + esac + ;; + *) info;; + esac +fi # Exit with the status of the last command exit $? \ No newline at end of file From e2135379d80ee4ec92a2eefb4b2a0b31249bd385 Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 14 Feb 2025 23:48:04 +0100 Subject: [PATCH 17/31] src/zlevis-encrypt: update --- src/zlevis-encrypt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zlevis-encrypt b/src/zlevis-encrypt index a03ded1..989c711 100755 --- a/src/zlevis-encrypt +++ b/src/zlevis-encrypt @@ -66,7 +66,7 @@ fi # Validate the configuration input if ! cfg="$(jose fmt -j "$1" -Oo- 2>/dev/null)"; then - echo "Configuration '{\"property\":\"value\"}' is malformed" >&2 + echo "Configuration '{\"property\":\"value\"}' is not present or malformed" >&2 exit 1 fi From 9ac3017da4f929ef30c9d157a394123564d113ff Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 14 Feb 2025 23:50:39 +0100 Subject: [PATCH 18/31] src/zlevis: removed minor bug --- src/zlevis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zlevis b/src/zlevis index 2b6967e..f1a0361 100755 --- a/src/zlevis +++ b/src/zlevis @@ -34,7 +34,7 @@ encrypt_pool_info() { } # Determine the argument path and execute the relevant script or function -if [ -t 0]; then +if [ -t 0 ]; then case "$1" in "decrypt") case "$2" in From 5b914c13a3749ab042d3bef50339c4a3c8b2ed25 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 19 Feb 2025 21:09:44 +0100 Subject: [PATCH 19/31] src/zlevis: removed key option --- src/zlevis | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/zlevis b/src/zlevis index f1a0361..8f3eb7a 100755 --- a/src/zlevis +++ b/src/zlevis @@ -15,14 +15,14 @@ fi # Function to display usage information of zlevis info() { exec >&2 - echo "Usage: \"zlevis {decrypt|encrypt} {pool|key}\"" + echo "Usage: \"zlevis {decrypt|encrypt} \"" exit 2 } # Function to display usage information of zlevis encrypt pool encrypt_pool_info() { exec >&2 - echo "Usage: \"zlevis encrypt pool '{\"property\":\"value\"}' < file.key\"" + echo "Usage: \"zlevis encrypt '{\"property\":\"value\"}' < file.key\"" echo echo "This command uses the following configuration properties:" echo " hash: -> Hash algorithm used in the computation of the object name (default: sha256)." @@ -39,14 +39,12 @@ if [ -t 0 ]; then "decrypt") case "$2" in "pool") zfs list -Ho tpm:jwe "$3" | zlevis-decrypt;; - "key") zlevis-decrypt;; *) info;; esac ;; "encrypt") case "$2" in "pool") encrypt_pool_info;; - "key") zlevis-encrypt;; *) info;; esac ;; @@ -54,16 +52,9 @@ if [ -t 0 ]; then esac else case "$1" in - "decrypt") - case "$2" in - "key") zlevis-decrypt;; - *) info;; - esac - ;; "encrypt") case "$2" in "pool") read -r -d . key || zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt "$4") "$3";; - "key") zlevis-encrypt "$3";; *) info;; esac ;; From 1b067ff34c9ec0e4f4e1defed90f3fb72ff67a46 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 19 Feb 2025 21:14:25 +0100 Subject: [PATCH 20/31] src/zlevis: removed key option indefinitely --- src/zlevis | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/zlevis b/src/zlevis index 8f3eb7a..34acddc 100755 --- a/src/zlevis +++ b/src/zlevis @@ -36,28 +36,13 @@ encrypt_pool_info() { # Determine the argument path and execute the relevant script or function if [ -t 0 ]; then case "$1" in - "decrypt") - case "$2" in - "pool") zfs list -Ho tpm:jwe "$3" | zlevis-decrypt;; - *) info;; - esac - ;; - "encrypt") - case "$2" in - "pool") encrypt_pool_info;; - *) info;; - esac - ;; + "decrypt") zfs list -Ho tpm:jwe "$2" | zlevis-decrypt;; + "encrypt") encrypt_pool_info;; *) info;; esac else case "$1" in - "encrypt") - case "$2" in - "pool") read -r -d . key || zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt "$4") "$3";; - *) info;; - esac - ;; + "encrypt") read -r -d . key || zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt "$3") "$2";; *) info;; esac fi From 8c62ea0b88ed57e26c366c85525c187244154354 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 19 Feb 2025 21:35:57 +0100 Subject: [PATCH 21/31] src/zlevis-fetch: removed --- src/zlevis-fetch | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100755 src/zlevis-fetch diff --git a/src/zlevis-fetch b/src/zlevis-fetch deleted file mode 100755 index 39c8d0f..0000000 --- a/src/zlevis-fetch +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -# Exit immediately if a command exits with a non-zero status -set -e - -# Summary of the script's functionality -summary="Decrypts a ZFS root pool with a TPM2.0 chip." - -# Display summary if requested -if [ "$1" = "--summary" ]; then - echo "$summary" - exit 0 -fi - -# Check if zlevis-decrypt is present -if ! command -v zlevis-decrypt > /dev/null; then - echo "Script zlevis-decrypt is not present" - exit 1 -fi - -# Read ZFS dataset information. -zfs list -Ho name,encryption,keystatus,encryptionroot,tpm:jwe | while IFS=$'\t' read -r ds enc keystatus encroot jwe; do - # Check if the dataset is the encryption root. - if [ "$ds" = "$encroot" ] && [ "$enc" != "off" ] && [ "$jwe" != "-" ]; then - if [ "$keystatus" = "available" ]; then - echo "Pool $ds already unlocked" - else - echo "Loading key for $ds" - if echo -n "$jwe" | zlevis-decrypt | zfs load-key -L prompt "$ds"; then - echo "Unlocked $ds" - else - echo "Failed to unlock $ds" >&2 - exit 1 - fi - fi - fi -done From 740418826cddb4d3859671506bec8e978a5f2a70 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 19 Feb 2025 21:37:04 +0100 Subject: [PATCH 22/31] src/meson.build: remove zlevis-fetch --- src/meson.build | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/meson.build b/src/meson.build index fa1bb45..09c3d2c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -2,16 +2,13 @@ main = find_program('zlevis') encrypt = find_program('zlevis-encrypt') decrypt = find_program('zlevis-decrypt') -fetch = find_program('zlevis-fetch') # Test the scripts test('zlevis', main, args: '--summary') test('zlevis-encrypt', encrypt, args: '--summary') test('zlevis-decrypt', decrypt, args: '--summary') -test('zlevis-fetch', fetch, args: '--summary') # Add paths of scripts to bins bins += join_paths(meson.current_source_dir(), 'zlevis') bins += join_paths(meson.current_source_dir(), 'zlevis-encrypt') -bins += join_paths(meson.current_source_dir(), 'zlevis-decrypt') -bins += join_paths(meson.current_source_dir(), 'zlevis-fetch') \ No newline at end of file +bins += join_paths(meson.current_source_dir(), 'zlevis-decrypt') \ No newline at end of file From 361efcc26bd6abc575c6d6c16886de7a629bac59 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 19 Feb 2025 21:48:05 +0100 Subject: [PATCH 23/31] src/zlevis-decrypt: typeset update --- src/zlevis-decrypt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zlevis-decrypt b/src/zlevis-decrypt index a0e9bad..e0798b1 100755 --- a/src/zlevis-decrypt +++ b/src/zlevis-decrypt @@ -4,7 +4,7 @@ set -e # Summary of the script's functionality -summary="Decrypts a JWE using a TPM2.0 chip." +summary="Decrypts a JWE using a TPM2.0 chip" # TPM2.0 owner hierarchy to be used by the Operating System auth="o" @@ -27,7 +27,7 @@ tpm2tools_version=$(tpm2_createprimary -v | awk -F'version="' '{print $2}' | awk # Check if the tpm2-tools version is supported if [ -z "$tpm2tools_version" ] || [ "$tpm2tools_version" -lt 4 ] || [ "$tpm2tools_version" -gt 5 ]; then - echo "The tpm2 pin requires a tpm2-tools version between 4 and 5" + echo "The tpm2 pin requires a tpm2-tools version between 4 and 5" >&2 exit 1 fi From 4d1ab8d9fc905c0353f40cbb15007a74f96de579 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 19 Feb 2025 21:48:25 +0100 Subject: [PATCH 24/31] src/zlevis-encrypt typeset update --- src/zlevis-encrypt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zlevis-encrypt b/src/zlevis-encrypt index 989c711..df95863 100755 --- a/src/zlevis-encrypt +++ b/src/zlevis-encrypt @@ -4,7 +4,7 @@ set -e # Summary of the script's functionality -summary="Encrypts using a TPM2.0 chip binding policy." +summary="Encrypts using a TPM2.0 chip binding policy" # TPM2.0 owner hierarchy to be used by the Operating System auth="o" @@ -60,7 +60,7 @@ tpm2tools_version=$(tpm2_createprimary -v | awk -F'version="' '{print $2}' | awk # Check if the tpm2-tools version is supported if [ -z "$tpm2tools_version" ] || [ "$tpm2tools_version" -lt 4 ] || [ "$tpm2tools_version" -gt 5 ]; then - echo "The tpm2 pin requires a tpm2-tools version between 4 and 5" + echo "The tpm2 pin requires a tpm2-tools version between 4 and 5" >&2 exit 1 fi From f7af42f39685f5c06abc6e798ec2f649703f2cd5 Mon Sep 17 00:00:00 2001 From: luc Date: Sun, 2 Mar 2025 20:48:52 +0100 Subject: [PATCH 25/31] README.md: update installation section --- README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index aa9b3f2..6c6722a 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,7 @@ A minimal fork of [Clevis](https://github.com/latchset/clevis), rewritten in POS ## Installation -### Alpine Linux - -Work in progress. - -### Manual - -Zlevis can be manually installed with `meson`, after cloning the repository, setup the build directory +Zlevis can be installed with `meson`, after cloning the repository, setup the build directory ``` $ meson setup builddir From 8df4ff53a954041be44a0d819ff031230404dc45 Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 2 May 2025 20:39:52 +0200 Subject: [PATCH 26/31] src/zlevis-encrypt: bug fix Removed bug in parsing of pcr_cfg and removed bug in policy_options parsing. --- src/zlevis-encrypt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/zlevis-encrypt b/src/zlevis-encrypt index df95863..5099a65 100755 --- a/src/zlevis-encrypt +++ b/src/zlevis-encrypt @@ -87,7 +87,7 @@ pcr_bank="$(printf "%s" "$cfg" | jose fmt -j- -Og pcr_bank -u-)" || { pcr_cfg=$(printf "%s" "$cfg" | tr -d '[:space:]') # Handle both string and JSON array formats for pcr_ids -if printf "%s" "$pcr_cfg" | jose fmt -j- -Og pcr_ids 2>/dev/null && ! pcr_ids="$(jose fmt -j- -Og pcr_ids -u- 2>/dev/null < "$tmp"/pcr_cfg)"; then +if printf "%s" "$pcr_cfg" | jose fmt -j- -Og pcr_ids 2>/dev/null && ! pcr_ids="$(printf "%s" "$pcr_cfg" | jose fmt -j- -Og pcr_ids -u- 2>/dev/null)"; then # Attempt to parse as a JSON array if string parsing fails if printf "%s" "$pcr_cfg" | jose fmt -j- -Og pcr_ids -A 2>/dev/null; then # Construct a comma-separated string from the array @@ -176,13 +176,13 @@ else obj_attr="$obj_attr|userwithauth" fi -# Remove tmp_pcr_digest and tmp_pcr_policy -rm -f "$tmp_pcr_digest" "$tmp_pcr_policy" +# Remove tmp_pcr_digest +rm -f "$tmp_pcr_digest" # Define and trap tmp jwk_pub and jwk_priv tmp_jwk_pub="/tmp/jwk_pub.$$" tmp_jwk_priv="/tmp/jwk_priv.$$" -trap 'rm -f "$tmp_primary_context" "$tmp_jwk_pub" "$tmp_jwk_priv"' EXIT +trap 'rm -f "$tmp_primary_context" "$tmp_pcr_policy" "$tmp_jwk_pub" "$tmp_jwk_priv"' EXIT # Create the TPM2 object for the JWK case "$tpm2tools_version" in @@ -195,8 +195,8 @@ if [ -n "$fail" ]; then fi tpm2_flushcontext -t -# Remove tmp_primary_context -rm -f "$tmp_primary_context" +# Remove tmp_primary_context and tmp_pcr_policy +rm -f "$tmp_primary_context" "$tmp_pcr_policy" # Encode the JWK public and private keys in Base64 if ! jwk_pub="$(jose b64 enc -I "$tmp_jwk_pub")"; then From 8bf01a4a03cdcaa2f61c82d3449bb4fe0db1237b Mon Sep 17 00:00:00 2001 From: Luc Date: Thu, 31 Jul 2025 13:45:49 +0200 Subject: [PATCH 27/31] src/zlevis-encrypt: update Bug fix in parsing policy_options in tpm2_create. --- src/zlevis-encrypt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zlevis-encrypt b/src/zlevis-encrypt index 5099a65..d9a06ed 100755 --- a/src/zlevis-encrypt +++ b/src/zlevis-encrypt @@ -186,7 +186,7 @@ trap 'rm -f "$tmp_primary_context" "$tmp_pcr_policy" "$tmp_jwk_pub" "$tmp_jwk_pr # Create the TPM2 object for the JWK case "$tpm2tools_version" in - 4|5) printf "%s" "$jwk" | tpm2_create -Q -g "$hash" -C "$tmp_primary_context" -u "$tmp_jwk_pub" -r "$tmp_jwk_priv" -a "$obj_attr" -L "$policy_options" -i- || fail=$?;; + 4|5) printf "%s" "$jwk" | tpm2_create -Q -g "$hash" -C "$tmp_primary_context" -u "$tmp_jwk_pub" -r "$tmp_jwk_priv" -a "$obj_attr" -L "${policy_options[@]}" -i- || fail=$?;; *) fail=1;; esac if [ -n "$fail" ]; then @@ -230,4 +230,4 @@ jwe="$(jose fmt -j "$jwe" -g protected -g zlevis -g tpm2 -q "$jwk_priv" -s jwk_p (echo "$jwe$jwk$(/bin/cat)") | jose jwe enc -i- -k- -I- -c # Exit with the status of the last command -exit $? \ No newline at end of file +exit $? From 4a3b0583c4e1756ea0d732c84bedde90f4ee5676 Mon Sep 17 00:00:00 2001 From: Luc Date: Thu, 31 Jul 2025 13:48:59 +0200 Subject: [PATCH 28/31] src/zlevis-decrypt: update Silenced tpm2_unseal error when TPM is empty. --- src/zlevis-decrypt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zlevis-decrypt b/src/zlevis-decrypt index e0798b1..7cac845 100755 --- a/src/zlevis-decrypt +++ b/src/zlevis-decrypt @@ -122,7 +122,7 @@ rm -f "$tmp_jwk_pub" "$tmp_jwk_priv" "$tmp_primary_context" # Unseal the JWK from the TPM case "$tpm2tools_version" in - 4|5) 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} 2>/dev/null)" || fail=$?;; *) fail=1;; esac if [ -n "$fail" ]; then @@ -138,4 +138,4 @@ rm -f "$tmp_load_context" (echo "$jwk$hdr."; /bin/cat) | jose jwe dec -k- -i- # Exit with the status of the last command -exit $? \ No newline at end of file +exit $? From cc1a1b7065d0292ecaa9cdeb9434d38b02ceef88 Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 1 Aug 2025 20:02:36 +0200 Subject: [PATCH 29/31] README.md: update --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6c6722a..8c7f31e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# Zlevis +# zlevis A minimal fork of [Clevis](https://github.com/latchset/clevis), rewritten in POSIX shell to accommodate automatic decryption of a ZFS root pool with TPM2. ## Installation -Zlevis can be installed with `meson`, after cloning the repository, setup the build directory +`zlevis` can be installed with `meson`, after cloning the repository, setup the build directory: ``` $ meson setup builddir @@ -14,7 +14,7 @@ $ meson setup builddir > Using the `--reconfigure` flag will reconfigure the build directory. -Installation of the zlevis scripts is now performed with +Installation of the `zlevis` scripts is now performed with: ``` # meson install -C builddir From fb6d31b727a51c5fe2a3172b1bc396710f8f03b9 Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 1 Aug 2025 21:16:02 +0200 Subject: [PATCH 30/31] meson.build: remove version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 3e6f611..e8969cc 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ # Project definition -project('zlevis', license: 'GPL3', version: '1') +project('zlevis', license: 'GPL3') # Define bindir bindir = join_paths(get_option('prefix'), get_option('bindir')) From d415066add315110214e73063cf7c5f64082648e Mon Sep 17 00:00:00 2001 From: Luc Date: Fri, 1 Aug 2025 21:16:32 +0200 Subject: [PATCH 31/31] src/zlevis-encrypt: update Reverted prior adaptation in parsing policy_options in tpm2_create due to incombatility with systems using busybox --- src/zlevis-encrypt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zlevis-encrypt b/src/zlevis-encrypt index d9a06ed..6700bbe 100755 --- a/src/zlevis-encrypt +++ b/src/zlevis-encrypt @@ -186,7 +186,7 @@ trap 'rm -f "$tmp_primary_context" "$tmp_pcr_policy" "$tmp_jwk_pub" "$tmp_jwk_pr # Create the TPM2 object for the JWK case "$tpm2tools_version" in - 4|5) printf "%s" "$jwk" | tpm2_create -Q -g "$hash" -C "$tmp_primary_context" -u "$tmp_jwk_pub" -r "$tmp_jwk_priv" -a "$obj_attr" -L "${policy_options[@]}" -i- || fail=$?;; + 4|5) printf "%s" "$jwk" | tpm2_create -Q -g "$hash" -C "$tmp_primary_context" -u "$tmp_jwk_pub" -r "$tmp_jwk_priv" -a "$obj_attr" -L "$policy_options" -i- || fail=$?;; *) fail=1;; esac if [ -n "$fail" ]; then