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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox