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/9] nvmet-auth: parse dhchap key from configfs attribute
Date: Wed, 28 May 2025 16:05:13 +0200 [thread overview]
Message-ID: <20250528140517.3284-6-hare@kernel.org> (raw)
In-Reply-To: <20250528140517.3284-1-hare@kernel.org>
When writing a new dhchap key to the 'dhchap_secret' attribute
we should be parsing it directly and only use the pointer to the
inserted key. 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, 182 insertions(+), 85 deletions(-)
diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c
index 7f87dc39a2de..2058e35908f8 100644
--- a/drivers/nvme/target/auth.c
+++ b/drivers/nvme/target/auth.c
@@ -20,54 +20,76 @@
#include "nvmet.h"
+void nvmet_auth_revoke_key(struct nvmet_host *host, bool set_ctrl)
+{
+ struct key *key = ERR_PTR(-ENOKEY);
+
+ 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 (!IS_ERR(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);
+ }
+ 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;
}
+
+ key_hash = nvme_dhchap_psk_hash(key);
if (key_hash > 0) {
/* Validate selected hash algorithm */
const char *hmac = nvme_auth_hmac_name(key_hash);
if (!crypto_has_shash(hmac, 0, 0)) {
pr_err("DH-HMAC-CHAP hash %s unsupported\n", hmac);
+ up_read(&key->sem);
+ key_put(key);
return -ENOTSUPP;
}
}
- dhchap_secret = kstrdup(secret, GFP_KERNEL);
- if (!dhchap_secret)
- return -ENOMEM;
- down_write(&nvmet_config_sem);
+ up_read(&key->sem);
+ nvmet_auth_revoke_key(host, set_ctrl);
if (set_ctrl) {
- kfree(host->dhchap_ctrl_secret);
- host->dhchap_ctrl_secret = strim(dhchap_secret);
- host->dhchap_ctrl_key_hash = key_hash;
+ host->dhchap_ctrl_key = key;
} else {
- kfree(host->dhchap_secret);
- host->dhchap_secret = strim(dhchap_secret);
- host->dhchap_key_hash = key_hash;
+ host->dhchap_key = key;
}
- up_write(&nvmet_config_sem);
return 0;
}
@@ -145,7 +167,8 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq)
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))
@@ -179,7 +202,7 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq)
goto out_unlock;
}
- if (!host->dhchap_secret) {
+ if (!host->dhchap_key) {
pr_debug("No authentication provided\n");
goto out_unlock;
}
@@ -191,47 +214,68 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq)
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);
@@ -265,12 +309,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 e44ef69dffc2..3c5ccc012168 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -14,6 +14,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/hash.h>
@@ -2100,15 +2101,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;
}
@@ -2117,9 +2132,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
@@ -2133,15 +2160,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;
}
@@ -2150,9 +2191,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
@@ -2233,8 +2285,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 ca6053fbaac8..409a1580afe9 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;
};
@@ -890,6 +888,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.35.3
next prev parent reply other threads:[~2025-05-28 14:19 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-28 14:05 [PATCHv2 0/9] nvme-auth: switch to use the kernel keyring Hannes Reinecke
2025-05-28 14:05 ` [PATCH 1/9] nvme-auth: modify nvme_auth_transform_key() to return status Hannes Reinecke
2025-11-26 7:39 ` Sagi Grimberg
2025-11-27 8:01 ` Hannes Reinecke
2025-11-30 21:42 ` Sagi Grimberg
2025-12-01 8:49 ` Hannes Reinecke
2025-05-28 14:05 ` [PATCH 2/9] nvme-keyring: add 'dhchap' key type Hannes Reinecke
2025-06-03 0:32 ` Shinichiro Kawasaki
2025-06-03 6:11 ` Hannes Reinecke
2025-11-26 7:46 ` Sagi Grimberg
2025-11-27 8:06 ` Hannes Reinecke
2025-05-28 14:05 ` [PATCH 3/9] nvme-auth: switch to use 'struct key' Hannes Reinecke
2025-11-26 7:53 ` Sagi Grimberg
2025-11-27 8:15 ` Hannes Reinecke
2025-11-30 21:44 ` Sagi Grimberg
2025-12-01 8:50 ` Hannes Reinecke
2025-05-28 14:05 ` [PATCH 4/9] nvme: parse dhchap keys during option parsing Hannes Reinecke
2025-11-26 9:04 ` Sagi Grimberg
2025-05-28 14:05 ` Hannes Reinecke [this message]
2025-11-30 21:53 ` [PATCH 5/9] nvmet-auth: parse dhchap key from configfs attribute Sagi Grimberg
2025-12-01 9:02 ` Hannes Reinecke
2025-05-28 14:05 ` [PATCH 6/9] nvme: allow to pass in key description as dhchap secret Hannes Reinecke
2025-11-30 22:06 ` Sagi Grimberg
2025-05-28 14:05 ` [PATCH 7/9] nvme-auth: wait for authentication to finish when changing keys Hannes Reinecke
2025-11-30 22:08 ` Sagi Grimberg
2025-05-28 14:05 ` [PATCH 8/9] nvme-fabrics: allow to pass in keyring by name Hannes Reinecke
2025-11-30 22:11 ` Sagi Grimberg
2025-05-28 14:05 ` [PATCH 9/9] nvmet: add configfs attribute 'dhchap_keyring' Hannes Reinecke
2025-11-30 22:14 ` Sagi Grimberg
2025-07-03 9:39 ` [PATCHv2 0/9] nvme-auth: switch to use the kernel keyring Christoph Hellwig
2025-07-03 9:43 ` Hannes Reinecke
2025-11-30 22:15 ` Sagi Grimberg
2025-09-30 12:27 ` Keith Busch
2025-12-01 17:02 ` Keith Busch
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=20250528140517.3284-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.