public inbox for linux-nvme@lists.infradead.org
 help / color / mirror / Atom feed
From: Chris Leech <cleech@redhat.com>
To: linux-nvme@lists.infradead.org
Cc: Hannes Reinecke <hare@suse.de>, Daniel Wagner <dwagner@suse.de>,
	Maurizio Lombardi <mlombard@redhat.com>
Subject: [RFC] example request-key helper script
Date: Wed, 22 Apr 2026 16:10:23 -0700	[thread overview]
Message-ID: <20260422231043.2689681-3-cleech@redhat.com> (raw)
In-Reply-To: <20260422231043.2689681-1-cleech@redhat.com>

This is a prototype of a request-key helper to instantiate a "PSK request" key.

Assisted-by: Claude:claude-sonnet-4.5
---
#!/usr/bin/bash
#
# NVMe PSK Provider
#
# This script is called by /sbin/request-key when the kernel requests
# NVMe TLS PSKs via the nvme-psk-request key type.
#
# configure /etc/request-key.conf with an entry like the following:
# create  nvme-psk-request  *  *  /usr/libexec/nvme-psk-provider %k %d %c %S

KEY_ID=$1
DESCRIPTION=$2
CALLOUT_INFO=$3
KEYRING=$4

exec > >(logger -t "key.nvme-psk") 2>&1
echo "$0: $@"

# Parse callout info
eval $(echo "$CALLOUT_INFO" | tr ' ' '\n' | grep '=')

KEYFILE="/etc/nvme/tls-keys"
HOST_NQN=${hostnqn}
SUBSYS_NQN=${subnqn}

if [ -z "$KEYFILE" ] || [ -z "$HOST_NQN" ] || [ -z "$SUBSYS_NQN" ]; then
    echo "Error: Missing required parameters"
    keyctl negate "$KEY_ID" 1 "$KEYRING"
    exit 1
fi

if [ ! -f "$KEYFILE" ]; then
    echo "Error: Keyfile '$KEYFILE' not found"
    keyctl negate "$KEY_ID" 1 "$KEYRING"
    exit 1
fi

# Temporary file for binary payload
PAYLOAD_FILE=$(mktemp)
trap "rm -f $PAYLOAD_FILE" EXIT

KEY_COUNT=0

# Search for all matching entries in keyfile
while IFS= read -r line; do
    # Skip empty lines and comments
    [ -z "$line" ] && continue
    [[ "$line" =~ ^#.* ]] && continue

    # Extract the last space-separated field (the encoded key)
    encoded_key="${line##* }"
    # Extract everything before the last space (the description)
    description="${line% *}"

    # Parse description: NVMe<ver><type>0<hmac> <hostnqn> <subsysnqn> <digest>
    if [[ "$description" =~ ^NVMe([0-9])([RG])([0-9][0-9])[[:space:]]+([^[:space:]]+)[[:space:]]+([^[:space:]]+)[[:space:]]+([^[:space:]]+)$ ]]; then
        ver="${BASH_REMATCH[1]}"
        type="${BASH_REMATCH[2]}"
        hmac="${BASH_REMATCH[3]}"
        desc_hostnqn="${BASH_REMATCH[4]}"
        desc_subsysnqn="${BASH_REMATCH[5]}"
        desc_digest="${BASH_REMATCH[6]}"

        # Only process Retained keys (not Generated)
        if [ "$type" != "R" ]; then
            continue
        fi

        # Check if this matches our search criteria
        if [ "$desc_hostnqn" = "$HOST_NQN" ] && [ "$desc_subsysnqn" = "$SUBSYS_NQN" ]; then
            # Validate the encoded key format: NVMeTLSkey-1:xx:...:
            if [[ "$encoded_key" =~ ^NVMeTLSkey-1:([0-9][0-9]):(.+):$ ]]; then
                key_hmac="${BASH_REMATCH[1]}"
                base64_data="${BASH_REMATCH[2]}"

                echo "Found matching PSK: version=$ver type=$type hmac=$hmac"

                # Decode base64
                tmpfile=$(mktemp)
                echo -n "$base64_data" | base64 -d > "$tmpfile"
                decoded_len=$(stat -c%s "$tmpfile")

                if [ "$decoded_len" -lt 36 ]; then
                    echo "Warning: Decoded data too short ($decoded_len bytes), skipping"
                    rm -f "$tmpfile"
                    continue
                fi

                # Key length is decoded_len - 4 (CRC is last 4 bytes)
                key_len=$((decoded_len - 4))

                # Verify CRC32 (optional - nvme-cli already validated on import)
                # Extract key data (without CRC)
                key_data=$(dd if="$tmpfile" bs=1 count="$key_len" 2>/dev/null)

                # Decode digest from base64
                digest_data=$(echo -n "$desc_digest" | base64 -d)
                digest_len=$(echo -n "$digest_data" | wc -c)

                # Pack binary: hmac(1) + key_len(1) + digest_len(1) + key_data[key_len] + digest[digest_len]
                # Convert hmac from decimal string to hex byte
                printf "\\x$(printf '%02x' $key_hmac)" >> "$PAYLOAD_FILE"
                printf "\\x$(printf '%02x' $key_len)" >> "$PAYLOAD_FILE"
                printf "\\x$(printf '%02x' $digest_len)" >> "$PAYLOAD_FILE"
                echo -n "$key_data" >> "$PAYLOAD_FILE"
                echo -n "$digest_data" >> "$PAYLOAD_FILE"

                KEY_COUNT=$((KEY_COUNT + 1))
                rm -f "$tmpfile"
            else
                echo "Warning: Invalid encoded key format, skipping"
            fi
        fi
    fi
done < "$KEYFILE"

if [ "$KEY_COUNT" -eq 0 ]; then
    echo "Error: No matching keys found for host-nqn '$HOST_NQN' and subsystem-nqn '$SUBSYS_NQN'"
    keyctl negate "$KEY_ID" 1 "$KEYRING"
    exit 1
fi

# Instantiate the nvme-psk-request key with binary payload
echo keyctl instantiate "$KEY_ID" @s "$KEYRING" < "$PAYLOAD_FILE"
keyctl pinstantiate "$KEY_ID" "$KEYRING" < "$PAYLOAD_FILE"
if [ $? -eq 0 ]; then
    echo "Successfully instantiated $KEY_COUNT PSK(s)"
    exit 0
else
    echo "Error: Failed to instantiate request key"
    keyctl negate "$KEY_ID" 1 "$KEYRING"
    exit 1
fi



  parent reply	other threads:[~2026-04-23  3:08 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-22 23:10 [RFC nvme-keyring nvme-cli] Should NVMe/TLS PSKs support the request_key API? Chris Leech
2026-04-22 23:10 ` [RFC PATCH] nvme-keyring: add request_key upcalls for dynamic key loading Chris Leech
2026-04-22 23:10 ` Chris Leech [this message]
2026-04-23 12:05 ` [RFC nvme-keyring nvme-cli] Should NVMe/TLS PSKs support the request_key API? Hannes Reinecke
2026-04-23 17:15   ` Daniel Wagner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260422231043.2689681-3-cleech@redhat.com \
    --to=cleech@redhat.com \
    --cc=dwagner@suse.de \
    --cc=hare@suse.de \
    --cc=linux-nvme@lists.infradead.org \
    --cc=mlombard@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox