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 6/9] nvme: allow to pass in key description as dhchap secret
Date: Wed, 28 May 2025 16:05:14 +0200 [thread overview]
Message-ID: <20250528140517.3284-7-hare@kernel.org> (raw)
In-Reply-To: <20250528140517.3284-1-hare@kernel.org>
In order to use pre-populated keys update the parsing for
DH-HMAC-CHAP secret to allow for a key description instead
of an encoded binary secret.
Signed-off-by: Hannes Reinecke <hare@kernel.org>
---
drivers/nvme/common/auth.c | 15 ++++++---
drivers/nvme/host/auth.c | 17 ++++++++--
drivers/nvme/host/fabrics.c | 24 ++++++++++----
drivers/nvme/host/fabrics.h | 4 +++
drivers/nvme/host/nvme.h | 2 ++
drivers/nvme/host/sysfs.c | 60 ++++++++++++++++++++++------------
drivers/nvme/target/auth.c | 20 ++++++++++--
drivers/nvme/target/configfs.c | 10 +++---
drivers/nvme/target/nvmet.h | 2 ++
include/linux/nvme-auth.h | 3 +-
10 files changed, 116 insertions(+), 41 deletions(-)
diff --git a/drivers/nvme/common/auth.c b/drivers/nvme/common/auth.c
index 8c2ccbfb9986..cbf35a7c3105 100644
--- a/drivers/nvme/common/auth.c
+++ b/drivers/nvme/common/auth.c
@@ -156,14 +156,21 @@ size_t nvme_auth_hmac_hash_len(u8 hmac_id)
EXPORT_SYMBOL_GPL(nvme_auth_hmac_hash_len);
struct key *nvme_auth_extract_key(struct key *keyring, const u8 *secret,
- size_t secret_len)
+ size_t secret_len, bool *generated)
{
struct key *key;
+ key = nvme_dhchap_psk_lookup(keyring, secret);
+ if (!IS_ERR(key)) {
+ *generated = false;
+ return key;
+ }
key = nvme_dhchap_psk_refresh(keyring, secret, secret_len);
- if (!IS_ERR(key))
- pr_debug("generated dhchap key %08x\n",
- key_serial(key));
+ if (!IS_ERR(key)) {
+ *generated = true;
+ pr_debug("generated dhchap key %s\n",
+ key->description);
+ }
return key;
}
EXPORT_SYMBOL_GPL(nvme_auth_extract_key);
diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c
index 0e8a5b544f63..0464e23b2a21 100644
--- a/drivers/nvme/host/auth.c
+++ b/drivers/nvme/host/auth.c
@@ -1057,19 +1057,29 @@ static void nvme_ctrl_auth_work(struct work_struct *work)
static void nvme_auth_clear_key(struct nvme_ctrl *ctrl, bool is_ctrl)
{
struct key *key;
+ bool generated;
if (is_ctrl) {
key = ctrl->ctrl_key;
ctrl->ctrl_key = NULL;
+ generated = ctrl->ctrl_key_generated;
+ ctrl->ctrl_key_generated = false;
} else {
key = ctrl->host_key;
ctrl->host_key = NULL;
+ generated = ctrl->host_key_generated;
+ ctrl->host_key_generated = false;
}
if (key) {
- dev_dbg(ctrl->device, "%s: revoke%s key %08x\n",
+ if (generated) {
+ dev_dbg(ctrl->device, "%s: revoke%s key %08x\n",
+ __func__, is_ctrl ? " ctrl" : "",
+ key_serial(key));
+ key_revoke(key);
+ }
+ dev_dbg(ctrl->device, "%s: drop%s key %08x\n",
__func__, is_ctrl ? " ctrl" : "",
key_serial(key));
- key_revoke(key);
key_put(key);
}
}
@@ -1099,6 +1109,7 @@ int nvme_auth_init_ctrl(struct nvme_ctrl *ctrl)
key_serial(ctrl->opts->dhchap_key));
return -ENOKEY;
}
+ ctrl->host_key_generated = ctrl->opts->dhchap_key_generated;
down_read(&ctrl->host_key->sem);
ret = key_validate(ctrl->host_key);
up_read(&ctrl->host_key->sem);
@@ -1125,6 +1136,8 @@ int nvme_auth_init_ctrl(struct nvme_ctrl *ctrl)
key_serial(ctrl->opts->dhchap_ctrl_key));
return -ENOKEY;
}
+ ctrl->ctrl_key_generated =
+ ctrl->opts->dhchap_ctrl_key_generated;
down_read(&ctrl->ctrl_key->sem);
ret = key_validate(ctrl->ctrl_key);
up_read(&ctrl->ctrl_key->sem);
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 009a6cf8a86b..6ec94c4f6075 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -741,7 +741,9 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
opts->keyring = NULL;
opts->concat = false;
opts->dhchap_key = NULL;
+ opts->dhchap_key_generated = false;
opts->dhchap_ctrl_key = NULL;
+ opts->dhchap_ctrl_key_generated = false;
options = o = kstrdup(buf, GFP_KERNEL);
if (!options)
@@ -1095,7 +1097,8 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
if (host_secret) {
pr_debug("lookup host identity '%s'\n", host_secret);
key = nvme_auth_extract_key(opts->keyring, host_secret,
- strlen(host_secret));
+ strlen(host_secret),
+ &opts->dhchap_key_generated);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto out;
@@ -1110,7 +1113,8 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
}
pr_debug("lookup ctrl identity '%s'\n", ctrl_secret);
key = nvme_auth_extract_key(opts->keyring, ctrl_secret,
- strlen(ctrl_secret));
+ strlen(ctrl_secret),
+ &opts->dhchap_ctrl_key_generated);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto out;
@@ -1315,15 +1319,23 @@ void nvmf_free_options(struct nvmf_ctrl_options *opts)
kfree(opts->host_traddr);
kfree(opts->host_iface);
if (opts->dhchap_key) {
- pr_debug("revoke dhchap key %08x\n",
+ if (opts->dhchap_key_generated) {
+ pr_debug("revoke dhchap key %08x\n",
+ key_serial(opts->dhchap_key));
+ key_revoke(opts->dhchap_key);
+ }
+ pr_debug("drop dhchap key %08x\n",
key_serial(opts->dhchap_key));
- key_revoke(opts->dhchap_key);
key_put(opts->dhchap_key);
}
if (opts->dhchap_ctrl_key) {
- pr_debug("revoke dhchap ctrl key %08x\n",
+ if (opts->dhchap_ctrl_key_generated) {
+ pr_debug("revoke dhchap ctrl key %08x\n",
+ key_serial(opts->dhchap_ctrl_key));
+ key_revoke(opts->dhchap_key);
+ }
+ pr_debug("drop dhchap ctrl key %08x\n",
key_serial(opts->dhchap_ctrl_key));
- key_revoke(opts->dhchap_key);
key_put(opts->dhchap_ctrl_key);
}
kfree(opts);
diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h
index 95a3d8ce1201..4b0ef3182f4c 100644
--- a/drivers/nvme/host/fabrics.h
+++ b/drivers/nvme/host/fabrics.h
@@ -99,6 +99,8 @@ enum {
* @dhchap_key: DH-HMAC-CHAP pre-shared key
* @dhchap_ctrl_key: DH-HMAC-CHAP controller pre-shared key for bi-directional
* authentication
+ * @dhchap_key_generated: True if the @dhchap_key has been auto-generated
+ * @dhchap_ctrl_key_generated: True if @dhchap_ctrl_key has been auto-generated
* @keyring: Keyring to use for key lookups
* @tls_key: TLS key for encrypted connections (TCP)
* @tls: Start TLS encrypted connections (TCP)
@@ -129,6 +131,8 @@ struct nvmf_ctrl_options {
struct nvmf_host *host;
struct key *dhchap_key;
struct key *dhchap_ctrl_key;
+ bool dhchap_key_generated;
+ bool dhchap_ctrl_key_generated;
struct key *keyring;
struct key *tls_key;
bool tls;
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 3dd83a48532a..45beb701011b 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -381,6 +381,8 @@ struct nvme_ctrl {
struct key *host_key;
struct key *ctrl_key;
u16 transaction;
+ bool host_key_generated;
+ bool ctrl_key_generated;
#endif
key_serial_t tls_pskid;
diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c
index 8a96228ff244..f1ab165c1f86 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -588,13 +588,14 @@ static ssize_t nvme_ctrl_dhchap_secret_show(struct device *dev,
down_read(&key->sem);
if (key_validate(key))
count = sysfs_emit(buf, "<invalidated>\n");
- else {
+ else if (ctrl->host_key_generated) {
count = key->type->read(key, buf, PAGE_SIZE);
if (count > 0) {
buf[count] = '\n';
count++;
}
- }
+ } else
+ count = sysfs_emit(buf, "%s\n", key->description);
up_read(&key->sem);
return count;
}
@@ -606,6 +607,7 @@ static ssize_t nvme_ctrl_dhchap_secret_store(struct device *dev,
struct nvmf_ctrl_options *opts = ctrl->opts;
struct key *key, *old_key;
char *dhchap_secret;
+ bool generated = false;
size_t len;
int ret;
@@ -618,8 +620,8 @@ static ssize_t nvme_ctrl_dhchap_secret_store(struct device *dev,
return -ENOMEM;
memcpy(dhchap_secret, buf, len);
nvme_auth_stop(ctrl);
- key = nvme_auth_extract_key(opts->keyring,
- dhchap_secret, count);
+ key = nvme_auth_extract_key(opts->keyring, dhchap_secret, len,
+ &generated);
if (IS_ERR(key)) {
kfree(dhchap_secret);
return PTR_ERR(key);
@@ -629,19 +631,25 @@ static ssize_t nvme_ctrl_dhchap_secret_store(struct device *dev,
up_read(&key->sem);
if (ret) {
dev_warn(ctrl->dev, "key %08x invalidated\n", key_serial(key));
- dev_dbg(ctrl->dev, "revoke key %08x\n", key_serial(key));
- key_revoke(key);
+ if (generated) {
+ dev_dbg(ctrl->dev, "revoke key %08x\n", key_serial(key));
+ key_revoke(key);
+ synchronize_rcu();
+ }
key_put(key);
kfree(dhchap_secret);
return ret;
}
mutex_lock(&ctrl->dhchap_auth_mutex);
old_key = ctrl->host_key;
- dev_dbg(ctrl->dev, "revoke key %08x\n",
- key_serial(old_key));
- key_revoke(old_key);
-
+ if (ctrl->host_key_generated) {
+ dev_dbg(ctrl->dev, "revoke key %08x\n",
+ key_serial(old_key));
+ key_revoke(old_key);
+ synchronize_rcu();
+ }
ctrl->host_key = key;
+ ctrl->host_key_generated = generated;
mutex_unlock(&ctrl->dhchap_auth_mutex);
key_put(old_key);
kfree(dhchap_secret);
@@ -667,13 +675,14 @@ static ssize_t nvme_ctrl_dhchap_ctrl_secret_show(struct device *dev,
down_read(&key->sem);
if (key_validate(key))
count = sysfs_emit(buf, "<invalidated>");
- else {
+ else if (ctrl->ctrl_key_generated) {
count = key->type->read(key, buf, PAGE_SIZE);
if (count > 0) {
buf[count] = '\n';
count++;
}
- }
+ } else
+ count = sysfs_emit(buf, "%s\n", key->description);
up_read(&key->sem);
return count;
}
@@ -685,6 +694,7 @@ static ssize_t nvme_ctrl_dhchap_ctrl_secret_store(struct device *dev,
struct nvmf_ctrl_options *opts = ctrl->opts;
struct key *key, *old_key;
char *dhchap_secret;
+ bool generated = false;
size_t len;
int ret;
@@ -697,8 +707,8 @@ static ssize_t nvme_ctrl_dhchap_ctrl_secret_store(struct device *dev,
return -ENOMEM;
memcpy(dhchap_secret, buf, len);
nvme_auth_stop(ctrl);
- key = nvme_auth_extract_key(opts->keyring,
- dhchap_secret, count);
+ key = nvme_auth_extract_key(opts->keyring, dhchap_secret, len,
+ &generated);
if (IS_ERR(key)) {
kfree(dhchap_secret);
return PTR_ERR(key);
@@ -708,18 +718,25 @@ static ssize_t nvme_ctrl_dhchap_ctrl_secret_store(struct device *dev,
up_read(&key->sem);
if (ret) {
dev_warn(ctrl->dev, "key %08x invalidated\n", key_serial(key));
- dev_dbg(ctrl->dev, "revoke key %08x\n", key_serial(key));
- key_revoke(key);
+ if (generated) {
+ dev_dbg(ctrl->dev, "revoke key %08x\n", key_serial(key));
+ key_revoke(key);
+ synchronize_rcu();
+ }
key_put(key);
kfree(dhchap_secret);
return ret;
}
mutex_lock(&ctrl->dhchap_auth_mutex);
old_key = ctrl->ctrl_key;
- dev_dbg(ctrl->dev, "revoke key %08x\n",
- key_serial(old_key));
- key_revoke(old_key);
+ if (ctrl->ctrl_key_generated) {
+ dev_dbg(ctrl->dev, "revoke key %08x\n",
+ key_serial(old_key));
+ key_revoke(old_key);
+ synchronize_rcu();
+ }
ctrl->ctrl_key = key;
+ ctrl->ctrl_key_generated = generated;
mutex_unlock(&ctrl->dhchap_auth_mutex);
key_put(old_key);
kfree(dhchap_secret);
@@ -745,13 +762,14 @@ static ssize_t dhchap_key_show(struct device *dev,
down_read(&key->sem);
if (key_validate(key))
count = sysfs_emit(buf, "<invalidated>\n");
- else {
+ else if (ctrl->host_key_generated) {
count = key->type->read(key, buf, PAGE_SIZE);
if (count > 0) {
buf[count] = '\n';
count++;
}
- }
+ } else
+ count = sysfs_emit(buf, "%08x\n", key_serial(ctrl->host_key));
up_read(&key->sem);
return count;
}
diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c
index 2058e35908f8..036652de3489 100644
--- a/drivers/nvme/target/auth.c
+++ b/drivers/nvme/target/auth.c
@@ -23,23 +23,34 @@
void nvmet_auth_revoke_key(struct nvmet_host *host, bool set_ctrl)
{
struct key *key = ERR_PTR(-ENOKEY);
+ bool generated = false;
if (set_ctrl) {
if (host->dhchap_ctrl_key) {
key = host->dhchap_ctrl_key;
+ generated = host->dhchap_ctrl_key_generated;
host->dhchap_ctrl_key = NULL;
+ host->dhchap_ctrl_key_generated = false;
}
} else {
if (host->dhchap_key) {
key = host->dhchap_key;
+ generated = host->dhchap_key_generated;
host->dhchap_key = NULL;
+ host->dhchap_key_generated = false;
}
}
if (!IS_ERR(key)) {
- pr_debug("%s: revoke %s key %08x\n",
+ if (generated) {
+ pr_debug("%s: revoke %s key %08x\n",
+ __func__, set_ctrl ? "ctrl" : "host",
+ key_serial(key));
+ key_revoke(key);
+ synchronize_rcu();
+ }
+ pr_debug("%s: drop %s key %08x\n",
__func__, set_ctrl ? "ctrl" : "host",
key_serial(key));
- key_revoke(key);
key_put(key);
}
}
@@ -48,6 +59,7 @@ int nvmet_auth_set_key(struct nvmet_host *host, const char *secret,
bool set_ctrl)
{
unsigned char key_hash;
+ bool generated = false;
struct key *key;
size_t len;
@@ -57,7 +69,7 @@ int nvmet_auth_set_key(struct nvmet_host *host, const char *secret,
}
len = strcspn(secret, "\n");
- key = nvme_auth_extract_key(NULL, secret, len);
+ key = nvme_auth_extract_key(NULL, secret, len, &generated);
if (IS_ERR(key)) {
pr_debug("%s: invalid key specification\n", __func__);
return PTR_ERR(key);
@@ -87,8 +99,10 @@ int nvmet_auth_set_key(struct nvmet_host *host, const char *secret,
nvmet_auth_revoke_key(host, set_ctrl);
if (set_ctrl) {
host->dhchap_ctrl_key = key;
+ host->dhchap_ctrl_key_generated = generated;
} else {
host->dhchap_key = key;
+ host->dhchap_key_generated = generated;
}
return 0;
}
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 3c5ccc012168..e165905fab31 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -2114,13 +2114,14 @@ static ssize_t nvmet_host_dhchap_key_show(struct config_item *item,
down_read(&key->sem);
if (key_validate(key))
ret = sprintf(page, "<invalidated>\n");
- else {
+ else if (host->dhchap_key_generated) {
ret = key->type->read(key, page, PAGE_SIZE);
if (ret > 0) {
page[ret] = '\n';
ret++;
}
- }
+ } else
+ ret = sprintf(page, "%s\n", key->description);
up_read(&key->sem);
key_put(key);
}
@@ -2173,13 +2174,14 @@ static ssize_t nvmet_host_dhchap_ctrl_key_show(struct config_item *item,
down_read(&key->sem);
if (key_validate(key))
ret = sprintf(page, "<invalidated>\n");
- else {
+ else if (host->dhchap_ctrl_key_generated) {
ret = key->type->read(key, page, PAGE_SIZE);
if (ret > 0) {
page[ret] = '\n';
ret++;
}
- }
+ } else
+ ret = sprintf(page, "%s\n", key->description);
up_read(&key->sem);
key_put(key);
}
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 409a1580afe9..772a3fc69162 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -379,7 +379,9 @@ static inline struct nvmet_subsys *namespaces_to_subsys(
struct nvmet_host {
struct config_group group;
struct key *dhchap_key;
+ bool dhchap_key_generated;
struct key *dhchap_ctrl_key;
+ bool dhchap_ctrl_key_generated;
u8 dhchap_hash_id;
u8 dhchap_dhgroup_id;
};
diff --git a/include/linux/nvme-auth.h b/include/linux/nvme-auth.h
index 4e53ef96eea7..a9ae1d60a5f9 100644
--- a/include/linux/nvme-auth.h
+++ b/include/linux/nvme-auth.h
@@ -18,7 +18,8 @@ const char *nvme_auth_digest_name(u8 hmac_id);
size_t nvme_auth_hmac_hash_len(u8 hmac_id);
u8 nvme_auth_hmac_id(const char *hmac_name);
-struct key *nvme_auth_extract_key(struct key *keyring, const u8 *secret, size_t secret_len);
+struct key *nvme_auth_extract_key(struct key *keyring, const u8 *secret, size_t secret_len,
+ bool *generated);
int nvme_auth_transform_key(struct key *key, char *nqn,
u8 **transformed_secret);
int nvme_auth_augmented_challenge(u8 hmac_id, u8 *skey, size_t skey_len,
--
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 ` [PATCH 5/9] nvmet-auth: parse dhchap key from configfs attribute Hannes Reinecke
2025-11-30 21:53 ` Sagi Grimberg
2025-12-01 9:02 ` Hannes Reinecke
2025-05-28 14:05 ` Hannes Reinecke [this message]
2025-11-30 22:06 ` [PATCH 6/9] nvme: allow to pass in key description as dhchap secret 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-7-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.