From: Hannes Reinecke <hare@kernel.org>
To: Christoph Hellwig <hch@lst.de>
Cc: Sagi Grimberg <sagi@grimberg.me>, Keith Busch <kbusch@kernel.org>,
linux-nvme@lists.infradead.org, Hannes Reinecke <hare@kernel.org>
Subject: [PATCH 5/8] nvmet-auth: parse dhchap key from configfs attribute
Date: Tue, 17 Mar 2026 14:01:00 +0100 [thread overview]
Message-ID: <20260317130103.107360-6-hare@kernel.org> (raw)
In-Reply-To: <20260317130103.107360-1-hare@kernel.org>
In preparation for moving the nvmet DH-HMAC-CHAP code over
to using the kernel keyring convert the configfs interface
to use 'struct key' instead of storing the key data directly.
This avoids having to pass around a pointer with the actual
key material.
Signed-off-by: Hannes Reinecke <hare@kernel.org>
---
drivers/nvme/target/auth.c | 176 ++++++++++++++++++++-------------
drivers/nvme/target/configfs.c | 84 +++++++++++++---
drivers/nvme/target/nvmet.h | 7 +-
3 files changed, 179 insertions(+), 88 deletions(-)
diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c
index 3cb829df964c..4cdf85e86b1a 100644
--- a/drivers/nvme/target/auth.c
+++ b/drivers/nvme/target/auth.c
@@ -19,45 +19,61 @@
#include "nvmet.h"
+void nvmet_auth_revoke_key(struct nvmet_host *host, bool set_ctrl)
+{
+ struct key *key = NULL;
+
+ if (set_ctrl) {
+ if (host->dhchap_ctrl_key) {
+ key = host->dhchap_ctrl_key;
+ host->dhchap_ctrl_key = NULL;
+ }
+ } else {
+ if (host->dhchap_key) {
+ key = host->dhchap_key;
+ host->dhchap_key = NULL;
+ }
+ }
+ if (key) {
+ pr_debug("%s: revoke %s key %08x\n",
+ __func__, set_ctrl ? "ctrl" : "host",
+ key_serial(key));
+ key_revoke(key);
+ key_put(key);
+ }
+}
+
int nvmet_auth_set_key(struct nvmet_host *host, const char *secret,
bool set_ctrl)
{
- unsigned char key_hash;
- char *dhchap_secret;
+ struct key *key;
+ size_t len;
if (!strlen(secret)) {
- if (set_ctrl) {
- kfree(host->dhchap_ctrl_secret);
- host->dhchap_ctrl_secret = NULL;
- host->dhchap_ctrl_key_hash = 0;
- } else {
- kfree(host->dhchap_secret);
- host->dhchap_secret = NULL;
- host->dhchap_key_hash = 0;
- }
+ nvmet_auth_revoke_key(host, set_ctrl);
return 0;
}
- if (sscanf(secret, "DHHC-1:%hhd:%*s", &key_hash) != 1)
- return -EINVAL;
- if (key_hash > 3) {
- pr_warn("Invalid DH-HMAC-CHAP hash id %d\n",
- key_hash);
- return -EINVAL;
+
+ len = strcspn(secret, "\n");
+ key = nvme_auth_extract_key(NULL, secret, len);
+ if (IS_ERR(key)) {
+ pr_debug("%s: invalid key specification\n", __func__);
+ return PTR_ERR(key);
}
- dhchap_secret = kstrdup(secret, GFP_KERNEL);
- if (!dhchap_secret)
- return -ENOMEM;
- down_write(&nvmet_config_sem);
- if (set_ctrl) {
- kfree(host->dhchap_ctrl_secret);
- host->dhchap_ctrl_secret = strim(dhchap_secret);
- host->dhchap_ctrl_key_hash = key_hash;
- } else {
- kfree(host->dhchap_secret);
- host->dhchap_secret = strim(dhchap_secret);
- host->dhchap_key_hash = key_hash;
+ down_read(&key->sem);
+ if (key_validate(key)) {
+ pr_warn("%s: key %08x invalidated\n",
+ __func__, key_serial(key));
+ up_read(&key->sem);
+ key_put(key);
+ return -EKEYREVOKED;
}
- up_write(&nvmet_config_sem);
+ up_read(&key->sem);
+ nvmet_auth_revoke_key(host, set_ctrl);
+ if (set_ctrl)
+ host->dhchap_ctrl_key = key;
+ else
+ host->dhchap_key = key;
return 0;
}
@@ -135,7 +151,8 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, bool reset)
int ret = 0;
struct nvmet_host_link *p;
struct nvmet_host *host = NULL;
- u8 host_hash, ctrl_hash;
+ struct key *key;
+ key_serial_t key_id;
down_read(&nvmet_config_sem);
if (nvmet_is_disc_subsys(ctrl->subsys))
@@ -169,7 +186,7 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, bool reset)
goto out_unlock;
}
- if (!host->dhchap_secret) {
+ if (!host->dhchap_key) {
pr_debug("No authentication provided\n");
goto out_unlock;
}
@@ -181,47 +198,68 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, bool reset)
ctrl->shash_id = host->dhchap_hash_id;
}
- key_put(ctrl->host_key);
- ctrl->host_key = nvme_auth_extract_key(NULL, host->dhchap_secret,
- strlen(host->dhchap_secret));
- if (IS_ERR(ctrl->host_key)) {
- ret = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE;
- ctrl->host_key = NULL;
- goto out_free_hash;
+ key = key_get(host->dhchap_key);
+ if (!key) {
+ pr_warn("%s: host key %08x not found\n",
+ __func__, key_serial(host->dhchap_key));
+ goto out_unlock;
}
- host_hash = nvme_dhchap_psk_hash(ctrl->host_key);
- pr_debug("%s: using hash %s key %u\n", __func__,
- ctrl_hash > 0 ?
- nvme_auth_hmac_name(ctrl_hash) : "none",
- key_serial(ctrl->host_key));
-
- key_put(ctrl->ctrl_key);
- if (!host->dhchap_ctrl_secret) {
- ctrl->ctrl_key = NULL;
+ down_read(&key->sem);
+ ret = key_validate(key);
+ if (!ret) {
+ if (ctrl->host_key) {
+ pr_debug("%s: drop host key %08x\n",
+ __func__, key_serial(ctrl->host_key));
+ key_put(ctrl->host_key);
+ }
+ ctrl->host_key = key;
+ }
+ key_id = key_serial(key);
+ up_read(&key->sem);
+ if (ret) {
+ pr_debug("key id %08x invalidated\n", key_id);
+ key_put(key);
+ key = ERR_PTR(-EKEYREVOKED);
+ }
+ pr_debug("%s: using dhchap hash %s key %08x\n", __func__,
+ nvme_auth_hmac_name(ctrl->shash_id), key_id);
+
+ if (!host->dhchap_ctrl_key) {
+ if (ctrl->ctrl_key) {
+ pr_debug("%s: drop ctrl key %08x\n",
+ __func__, key_serial(ctrl->ctrl_key));
+ key_put(ctrl->ctrl_key);
+ ctrl->ctrl_key = NULL;
+ }
goto out_unlock;
}
- ctrl->ctrl_key = nvme_auth_extract_key(NULL, host->dhchap_ctrl_secret,
- strlen(host->dhchap_ctrl_secret));
- if (IS_ERR(ctrl->ctrl_key)) {
- ret = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE;
- ctrl->ctrl_key = NULL;
- goto out_free_hash;
+ key = key_get(host->dhchap_ctrl_key);
+ if (!key) {
+ pr_warn("%s: ctrl key %08x not found\n",
+ __func__, key_serial(host->dhchap_ctrl_key));
+ goto out_unlock;
}
- ctrl_hash = nvme_dhchap_psk_hash(ctrl->ctrl_key);
- pr_debug("%s: using ctrl hash %s key %u\n", __func__,
- ctrl_hash > 0 ?
- nvme_auth_hmac_name(ctrl_hash) : "none",
- key_serial(ctrl->ctrl_key));
-
-out_free_hash:
- if (ret) {
- if (ctrl->host_key) {
- key_put(ctrl->host_key);
- ctrl->host_key = NULL;
+ down_read(&key->sem);
+ ret = key_validate(key);
+ if (!ret) {
+ if (ctrl->ctrl_key) {
+ pr_debug("%s: drop ctrl key %08x\n",
+ __func__, key_serial(ctrl->ctrl_key));
+ key_put(ctrl->ctrl_key);
}
- ctrl->shash_id = 0;
+ ctrl->ctrl_key = key;
}
+ key_id = key_serial(key);
+ up_read(&key->sem);
+ if (ret) {
+ pr_debug("ctrl key id %08x invalidated\n", key_id);
+ key_put(key);
+ goto out_unlock;
+ }
+ pr_debug("%s: using dhchap ctrl hash %s key %08x\n", __func__,
+ nvme_auth_hmac_name(ctrl->shash_id), key_id);
+
out_unlock:
up_read(&nvmet_config_sem);
@@ -255,12 +293,14 @@ void nvmet_destroy_auth(struct nvmet_ctrl *ctrl)
ctrl->dh_key = NULL;
if (ctrl->host_key) {
- key_revoke(ctrl->host_key);
+ pr_debug("%s: drop host key %08x\n",
+ __func__, key_serial(ctrl->host_key));
key_put(ctrl->host_key);
ctrl->host_key = NULL;
}
if (ctrl->ctrl_key) {
- key_revoke(ctrl->ctrl_key);
+ pr_debug("%s: drop ctrl key %08x\n",
+ __func__, key_serial(ctrl->ctrl_key));
key_put(ctrl->ctrl_key);
ctrl->ctrl_key = NULL;
}
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 463348c7f097..5fa1b8a19bf8 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -15,6 +15,7 @@
#include <linux/pci-p2pdma.h>
#ifdef CONFIG_NVME_TARGET_AUTH
#include <linux/nvme-auth.h>
+#include <linux/key-type.h>
#endif
#include <linux/nvme-keyring.h>
#include <crypto/kpp.h>
@@ -2099,15 +2100,29 @@ static struct config_group nvmet_ports_group;
static ssize_t nvmet_host_dhchap_key_show(struct config_item *item,
char *page)
{
- u8 *dhchap_secret;
+ struct nvmet_host *host = to_host(item);
+ struct key *key;
ssize_t ret;
down_read(&nvmet_config_sem);
- dhchap_secret = to_host(item)->dhchap_secret;
- if (!dhchap_secret)
- ret = sprintf(page, "\n");
- else
- ret = sprintf(page, "%s\n", dhchap_secret);
+ key = key_get(host->dhchap_key);
+ if (!key) {
+ page[0] = '\0';
+ ret = 0;
+ } else {
+ down_read(&key->sem);
+ if (key_validate(key))
+ ret = sprintf(page, "<invalidated>\n");
+ else {
+ ret = key->type->read(key, page, PAGE_SIZE);
+ if (ret > 0) {
+ page[ret] = '\n';
+ ret++;
+ }
+ }
+ up_read(&key->sem);
+ key_put(key);
+ }
up_read(&nvmet_config_sem);
return ret;
}
@@ -2116,9 +2131,21 @@ static ssize_t nvmet_host_dhchap_key_store(struct config_item *item,
const char *page, size_t count)
{
struct nvmet_host *host = to_host(item);
+ u8 *keydata;
+ size_t len;
int ret;
- ret = nvmet_auth_set_key(host, page, false);
+ len = strcspn(page, "\n");
+ if (!len)
+ return -EINVAL;
+ keydata = kstrndup(page, len, GFP_KERNEL);
+ if (!keydata)
+ return -ENOMEM;
+
+ down_write(&nvmet_config_sem);
+ ret = nvmet_auth_set_key(host, keydata, false);
+ up_write(&nvmet_config_sem);
+ kfree(keydata);
/*
* Re-authentication is a soft state, so keep the
* current authentication valid until the host
@@ -2132,15 +2159,29 @@ CONFIGFS_ATTR(nvmet_host_, dhchap_key);
static ssize_t nvmet_host_dhchap_ctrl_key_show(struct config_item *item,
char *page)
{
- u8 *dhchap_secret = to_host(item)->dhchap_ctrl_secret;
+ struct nvmet_host *host = to_host(item);
+ struct key *key;
ssize_t ret;
down_read(&nvmet_config_sem);
- dhchap_secret = to_host(item)->dhchap_ctrl_secret;
- if (!dhchap_secret)
- ret = sprintf(page, "\n");
- else
- ret = sprintf(page, "%s\n", dhchap_secret);
+ key = key_get(host->dhchap_ctrl_key);
+ if (!key) {
+ page[0] = '\0';
+ ret = 0;
+ } else {
+ down_read(&key->sem);
+ if (key_validate(key))
+ ret = sprintf(page, "<invalidated>\n");
+ else {
+ ret = key->type->read(key, page, PAGE_SIZE);
+ if (ret > 0) {
+ page[ret] = '\n';
+ ret++;
+ }
+ }
+ up_read(&key->sem);
+ key_put(key);
+ }
up_read(&nvmet_config_sem);
return ret;
}
@@ -2149,9 +2190,20 @@ static ssize_t nvmet_host_dhchap_ctrl_key_store(struct config_item *item,
const char *page, size_t count)
{
struct nvmet_host *host = to_host(item);
+ u8 *keydata;
+ size_t len;
int ret;
- ret = nvmet_auth_set_key(host, page, true);
+ len = strcspn(page, "\n");
+ if (!len)
+ return -EINVAL;
+ keydata = kstrndup(page, len, GFP_KERNEL);
+ if (!keydata)
+ return -ENOMEM;
+
+ down_write(&nvmet_config_sem);
+ ret = nvmet_auth_set_key(host, keydata, true);
+ up_write(&nvmet_config_sem);
/*
* Re-authentication is a soft state, so keep the
* current authentication valid until the host
@@ -2230,8 +2282,8 @@ static void nvmet_host_release(struct config_item *item)
struct nvmet_host *host = to_host(item);
#ifdef CONFIG_NVME_TARGET_AUTH
- kfree(host->dhchap_secret);
- kfree(host->dhchap_ctrl_secret);
+ nvmet_auth_revoke_key(host, false);
+ nvmet_auth_revoke_key(host, true);
#endif
kfree(host);
}
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index f9f281060ac1..9b0848948b3f 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -378,10 +378,8 @@ static inline struct nvmet_subsys *namespaces_to_subsys(
struct nvmet_host {
struct config_group group;
- u8 *dhchap_secret;
- u8 *dhchap_ctrl_secret;
- u8 dhchap_key_hash;
- u8 dhchap_ctrl_key_hash;
+ struct key *dhchap_key;
+ struct key *dhchap_ctrl_key;
u8 dhchap_hash_id;
u8 dhchap_dhgroup_id;
};
@@ -894,6 +892,7 @@ u32 nvmet_auth_send_data_len(struct nvmet_req *req);
void nvmet_execute_auth_send(struct nvmet_req *req);
u32 nvmet_auth_receive_data_len(struct nvmet_req *req);
void nvmet_execute_auth_receive(struct nvmet_req *req);
+void nvmet_auth_revoke_key(struct nvmet_host *host, bool set_ctrl);
int nvmet_auth_set_key(struct nvmet_host *host, const char *secret,
bool set_ctrl);
int nvmet_auth_set_host_hash(struct nvmet_host *host, const char *hash);
--
2.43.0
next prev parent reply other threads:[~2026-03-17 13:01 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-17 13:00 [PATCHv3 0/8] nvme-auth: switch to use the kernel keyring Hannes Reinecke
2026-03-17 13:00 ` [PATCH 1/8] nvme-auth: modify nvme_auth_transform_key() to return status Hannes Reinecke
2026-03-17 13:09 ` Maurizio Lombardi
2026-03-17 14:55 ` Hannes Reinecke
2026-03-17 13:00 ` [PATCH 2/8] nvme-keyring: add 'dhchap' key type Hannes Reinecke
2026-04-01 18:13 ` Chris Leech
2026-04-07 6:18 ` Hannes Reinecke
2026-03-17 13:00 ` [PATCH 3/8] nvme-auth: switch to use 'struct key' Hannes Reinecke
2026-04-01 18:36 ` Chris Leech
2026-04-07 6:20 ` Hannes Reinecke
2026-03-17 13:00 ` [PATCH 4/8] nvme: parse dhchap keys during option parsing Hannes Reinecke
2026-04-01 18:43 ` Chris Leech
2026-04-07 6:20 ` Hannes Reinecke
2026-03-17 13:01 ` Hannes Reinecke [this message]
2026-03-17 13:01 ` [PATCH 6/8] nvme: allow to pass in key description as dhchap secret Hannes Reinecke
2026-03-17 13:01 ` [PATCH 7/8] nvme-auth: wait for authentication to finish when changing keys Hannes Reinecke
2026-03-17 13:01 ` [PATCH 8/8] nvme-fabrics: allow to pass in keyring by name Hannes Reinecke
2026-03-17 13:20 ` [PATCHv3 0/8] nvme-auth: switch to use the kernel keyring Maurizio Lombardi
2026-03-17 14:44 ` Hannes Reinecke
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=20260317130103.107360-6-hare@kernel.org \
--to=hare@kernel.org \
--cc=hch@lst.de \
--cc=kbusch@kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=sagi@grimberg.me \
/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.