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
next prev 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.