diff --git a/README.md b/README.md index 80dddc0..8c7f31e 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,20 @@ -# 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 -### 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 ``` -Installation of the zlevis scripts is now performed with +> 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: ``` # meson install -C builddir diff --git a/meson.build b/meson.build index 2c824ab..e8969cc 100644 --- a/meson.build +++ b/meson.build @@ -1,11 +1,11 @@ # Project definition -project('zlevis', license: 'GPL3', version: '1') +project('zlevis', license: 'GPL3') # Define bindir -bindir=join_paths(get_option('prefix'), get_option('bindir')) +bindir = join_paths(get_option('prefix'), get_option('bindir')) # Define bins list -bins=[] +bins = [] # Define subdir with bins subdir('src') diff --git a/src/meson.build b/src/meson.build index 145e509..09c3d2c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,4 +1,14 @@ +# Find scripts +main = find_program('zlevis') +encrypt = find_program('zlevis-encrypt') +decrypt = find_program('zlevis-decrypt') + +# Test the scripts +test('zlevis', main, args: '--summary') +test('zlevis-encrypt', encrypt, args: '--summary') +test('zlevis-decrypt', decrypt, 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') +bins += join_paths(meson.current_source_dir(), 'zlevis-decrypt') \ No newline at end of file diff --git a/src/zlevis b/src/zlevis new file mode 100755 index 0000000..34acddc --- /dev/null +++ b/src/zlevis @@ -0,0 +1,51 @@ +#!/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 + +# Function to display usage information of zlevis +info() { + exec >&2 + 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 '{\"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") zfs list -Ho tpm:jwe "$2" | zlevis-decrypt;; + "encrypt") encrypt_pool_info;; + *) info;; + esac +else + case "$1" in + "encrypt") read -r -d . key || zfs set tpm:jwe=$(printf "%s" "$key" | zlevis-encrypt "$3") "$2";; + *) info;; + esac +fi + +# Exit with the status of the last command +exit $? \ No newline at end of file diff --git a/src/zlevis-decrypt b/src/zlevis-decrypt index 1d6ee03..7cac845 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" @@ -18,98 +18,82 @@ fi # Display usage information if input is from a terminal if [ -t 0 ]; then exec >&2 - echo echo "Usage: \"zlevis-decrypt < file.jwe\"" - echo "Usage ZFS: \"zfs list -Ho tpm:jwe | zlevis-decrypt\"" - echo - echo "$summary" 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}') # 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 -# 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 # Decode the JWE protected header -if ! jhd="$(jose b64 dec -i- < <(echo "$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 clevis -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 clevis -g tpm2 -g hash -Su- < "$tmp"/jhd)"; then - echo "JWE missing required 'hash' header parameter!" >&2 +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 clevis -g tpm2 -g key -Su- < "$tmp"/jhd)"; then - echo "JWE missing required 'key' header parameter!" >&2 +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 clevis -g tpm2 -g jwk_pub -Su- < "$tmp"/jhd)"; then - echo "JWE missing required 'jwk_pub' header parameter!" >&2 +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 clevis -g tpm2 -g jwk_priv -Su- < "$tmp"/jhd)"; then - echo "JWE missing required 'jwk_priv' header parameter!" >&2 +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 clevis -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 clevis -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 +102,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 +117,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} 2>/dev/null)" || fail=$?;; *) fail=1;; esac if [ -n "$fail" ]; then @@ -140,8 +131,11 @@ 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- # Exit with the status of the last command -exit $? \ No newline at end of file +exit $? diff --git a/src/zlevis-encrypt b/src/zlevis-encrypt index a171674..6700bbe 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" @@ -21,14 +21,8 @@ fi # Display usage information if input is from a terminal if [ -t 0 ]; then exec >&2 - echo echo "Usage: \"zlevis-encrypt '{\"property\":\"value\"}' < file.key > file.jwe\"" echo - echo "Usage ZFS: \"zfs set tpm:jwe=\$(zlevis-encrypt '{\"property\":\"value\"}' < tank.key) \"" - echo - echo - echo "$summary" - 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)." @@ -61,48 +55,27 @@ 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}') # 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 -# 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 + echo "Configuration '{\"property\":\"value\"}' is not present or 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 @@ -111,15 +84,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="$(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 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 @@ -137,19 +109,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 @@ -158,12 +132,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 @@ -172,7 +151,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 @@ -180,7 +159,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 @@ -191,15 +170,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 +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_pcr_policy" "$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 @@ -208,33 +195,39 @@ if [ -n "$fail" ]; then fi tpm2_flushcontext -t +# 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 +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":{"clevis":{"pin":"tpm2","tpm2":{}}}}' -jwe="$(jose fmt -j "$jwe" -g protected -g clevis -g tpm2 -q "$hash" -s hash -UUUUo-)" -jwe="$(jose fmt -j "$jwe" -g protected -g clevis -g tpm2 -q "$key" -s key -UUUUo-)" +jwe='{"protected":{"zlevis":{"pin":"tpm2","tpm2":{}}}}' +jwe="$(jose fmt -j "$jwe" -g protected -g zlevis -g tpm2 -q "$hash" -s hash -UUUUo-)" +jwe="$(jose fmt -j "$jwe" -g protected -g zlevis -g tpm2 -q "$key" -s key -UUUUo-)" # Include PCR bank and IDs in the JWE if they are provided if [ -n "$pcr_ids" ]; then - jwe="$(jose fmt -j "$jwe" -g protected -g clevis -g tpm2 -q "$pcr_bank" -s pcr_bank -UUUUo-)" - jwe="$(jose fmt -j "$jwe" -g protected -g clevis -g tpm2 -q "$pcr_ids" -s pcr_ids -UUUUo-)" + jwe="$(jose fmt -j "$jwe" -g protected -g zlevis -g tpm2 -q "$pcr_bank" -s pcr_bank -UUUUo-)" + jwe="$(jose fmt -j "$jwe" -g protected -g zlevis -g tpm2 -q "$pcr_ids" -s pcr_ids -UUUUo-)" fi # Add the Base64 encoded JWK public and private keys to the JWE -jwe="$(jose fmt -j "$jwe" -g protected -g clevis -g tpm2 -q "$jwk_pub" -s jwk_pub -UUUUo-)" -jwe="$(jose fmt -j "$jwe" -g protected -g clevis -g tpm2 -q "$jwk_priv" -s jwk_priv -UUUUo-)" - -# Clean up the temporary directory at the end of the script -[ -d "${tmp}" ] && rm -rf "${tmp}" +jwe="$(jose fmt -j "$jwe" -g protected -g zlevis -g tpm2 -q "$jwk_pub" -s jwk_pub -UUUUo-)" +jwe="$(jose fmt -j "$jwe" -g protected -g zlevis -g tpm2 -q "$jwk_priv" -s jwk_priv -UUUUo-)" # Output the final JWE -exec jose jwe enc -i- -k- -I- -c < <(echo -n "$jwe$jwk"; /bin/cat) \ No newline at end of file +(echo "$jwe$jwk$(/bin/cat)") | jose jwe enc -i- -k- -I- -c + +# Exit with the status of the last command +exit $? diff --git a/src/zlevis-fetch b/src/zlevis-fetch deleted file mode 100755 index fa8e2b6..0000000 --- a/src/zlevis-fetch +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -# Exit immediately if a command exits with a non-zero status -set -e - -# Check if zlevis-decrypt is present -command -v zlevis-decrypt > /dev/null || exit 1 - -# 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 \ No newline at end of file