From: Hannes Reinecke <hare@kernel.org>
To: Christoph Hellwig <hch@lst.de>
Cc: Keith Busch <kbusch@kernel.org>, Sagi Grimberg <sagi@grimberg.me>,
linux-nvme@lists.infradead.org, Hannes Reinecke <hare@kernel.org>
Subject: [PATCH 10/12] nvme: allow to pass in key serial number as dhchap secret
Date: Fri, 25 Apr 2025 11:49:25 +0200 [thread overview]
Message-ID: <20250425094927.102656-11-hare@kernel.org> (raw)
In-Reply-To: <20250425094927.102656-1-hare@kernel.org>
In order to use pre-populated keys update the parsing for
DH-HMAC-CHAP secret to allow for a key serial number instead
of an encoded binary secret.
Signed-off-by: Hannes Reinecke <hare@kernel.org>
---
drivers/nvme/common/auth.c | 22 ++++++++++---
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, 122 insertions(+), 42 deletions(-)
diff --git a/drivers/nvme/common/auth.c b/drivers/nvme/common/auth.c
index 8c2ccbfb9986..c47bb70b26ef 100644
--- a/drivers/nvme/common/auth.c
+++ b/drivers/nvme/common/auth.c
@@ -156,14 +156,26 @@ 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)
{
+ key_serial_t key_id;
struct key *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 (kstrtouint(secret, 0, &key_id)) {
+ key = nvme_dhchap_psk_refresh(keyring,
+ secret, secret_len);
+ if (!IS_ERR(key)) {
+ *generated = true;
+ pr_debug("generated dhchap key %08x\n",
+ key_serial(key));
+ }
+ } else if (key_id > 0) {
+ key = nvme_tls_key_lookup(key_id);
+ if (!IS_ERR(key))
+ *generated = false;
+ } else {
+ key = ERR_PTR(-EINVAL);
+ }
return key;
}
EXPORT_SYMBOL_GPL(nvme_auth_extract_key);
diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c
index d15ab5e98fe1..0f45261c50f8 100644
--- a/drivers/nvme/host/auth.c
+++ b/drivers/nvme/host/auth.c
@@ -1037,19 +1037,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);
}
}
@@ -1079,6 +1089,8 @@ int nvme_auth_init_ctrl(struct nvme_ctrl *ctrl)
key_serial(ctrl->opts->dhchap_key));
return -ENOKEY;
}
+ /* Key has been generated during option parsing */
+ ctrl->host_key_generated = false;
down_read(&ctrl->host_key->sem);
ret = key_validate(ctrl->host_key);
up_read(&ctrl->host_key->sem);
@@ -1105,6 +1117,7 @@ int nvme_auth_init_ctrl(struct nvme_ctrl *ctrl)
key_serial(ctrl->opts->dhchap_ctrl_key));
return -ENOKEY;
}
+ ctrl->ctrl_key_generated = false;
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 89c84220e340..c1b4ef6c5233 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 e7a635d6037e..0f0f0608d6c8 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -581,13 +581,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, "%08x\n", key_serial(key));
up_read(&key->sem);
return count;
}
@@ -599,6 +600,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;
@@ -611,8 +613,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);
@@ -622,19 +624,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);
@@ -660,13 +668,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, "%08x\n", key_serial(key));
up_read(&key->sem);
return count;
}
@@ -678,6 +687,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;
@@ -690,8 +700,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);
@@ -701,18 +711,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);
@@ -738,13 +755,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 59394587a875..3f9fad732350 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 1b6ca46d1a64..2f308108159c 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, "%08x\n", key_serial(key));
up_read(&key->sem);
key_put(key);
}
@@ -2161,13 +2162,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, "%08x\n", key_serial(key));
up_read(&key->sem);
key_put(key);
}
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index d23f9d122777..2a1c3850a8ac 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -375,7 +375,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-04-25 11:14 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-25 9:49 [PATCH 00/12] nvme-auth: switch to use the kernel keyring Hannes Reinecke
2025-04-25 9:49 ` [PATCH 01/12] nvme-auth: modify nvme_auth_transform_key() to return status Hannes Reinecke
2025-05-07 7:24 ` Christoph Hellwig
2025-05-07 7:29 ` Hannes Reinecke
2025-04-25 9:49 ` [PATCH 02/12] nvme-auth: use SHASH_DESC_ON_STACK Hannes Reinecke
2025-05-07 7:28 ` Christoph Hellwig
2025-05-07 7:29 ` Hannes Reinecke
2025-05-07 7:35 ` Christoph Hellwig
2025-04-25 9:49 ` [PATCH 03/12] nvmet-auth: " Hannes Reinecke
2025-04-25 9:49 ` [PATCH 04/12] nvme-auth: do not cache the transformed secret Hannes Reinecke
2025-05-07 7:25 ` Christoph Hellwig
2025-04-25 9:49 ` [PATCH 05/12] nvme-keyring: add 'dhchap' key type Hannes Reinecke
2025-04-25 9:49 ` [PATCH 06/12] nvme-auth: switch to use 'struct key' Hannes Reinecke
2025-04-25 9:49 ` [PATCH 07/12] nvme-auth: drop nvme_dhchap_key structure and unused functions Hannes Reinecke
2025-05-07 7:26 ` Christoph Hellwig
2025-05-07 7:30 ` Hannes Reinecke
2025-04-25 9:49 ` [PATCH 08/12] nvme: parse dhchap keys during option parsing Hannes Reinecke
2025-04-25 9:49 ` [PATCH 09/12] nvmet-auth: parse dhchap key from configfs attribute Hannes Reinecke
2025-04-25 9:49 ` Hannes Reinecke [this message]
2025-04-25 9:49 ` [PATCH 11/12] nvme-auth: wait for authentication to finish when changing keys Hannes Reinecke
2025-04-25 9:49 ` [PATCH 12/12] nvme: Unify Kconfig settings Hannes Reinecke
2025-05-07 7:23 ` Christoph Hellwig
2025-05-07 7:30 ` Hannes Reinecke
2025-05-07 7:19 ` [PATCH 00/12] nvme-auth: switch to use the kernel keyring Christoph Hellwig
2025-05-07 7:42 ` Hannes Reinecke
2025-05-07 7:53 ` Sagi Grimberg
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=20250425094927.102656-11-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox