All of lore.kernel.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.