[PATCH] nvme-auth: fail when the controller does not authenticate itself

From: Yehyeong Lee

Date: Tue Oct 06 2026 - 09:51:48 EST


nvme_auth_process_dhchap_success1() returns success as soon as the
controller clears the rvalid flag in its DH-HMAC-CHAP success1 message,
without looking at whether the host had asked the controller to
authenticate. A host configured with a controller secret sends a
challenge in its reply, computes the expected controller response, and
sets chap->bi_directional; if the controller then answers with
rvalid = 0 the response is never compared, the host still sends
success2, and the queue is marked as authenticated.

A malicious or man-in-the-middle controller therefore only has to clear
one flag to turn the configured bidirectional authentication into a
one-way one, without holding any secret of its own. The target side
already treats the mirror image of this as fatal: when the host supplied
a challenge but no controller key is configured, nvmet_auth_success1()
fails the authentication rather than answering with rvalid = 0.

Refuse the connection if the controller returns no response although
bidirectional authentication was requested. chap->bi_directional is the
right condition rather than ctrl->ctrl_key, because secure concatenation
sends a challenge only to derive the PSK and deliberately clears
bi_directional; a one-way setup without a controller secret keeps
returning success as before.

Fixes: f50fff73d620 ("nvme: implement In-Band authentication")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yehyeong Lee <yhlee@xxxxxxxxxxxxxxxxxx>
---
Reproduced over an nvmet loop target modified to omit rvalid in its
SUCCESS1 (standing in for a controller that does not authenticate itself),
with the host configured for bidirectional authentication. There is no
oops; this is an authentication-logic flaw, so the evidence is the host's
dmesg.

Unpatched, the host accepts the connection and never validates a controller
response (note the absence of any "controller authenticated" line):

nvme nvme0: qid 0: authenticated with hash hmac(sha256) dhgroup null
nvme nvme0: qid 0: authenticated
nvme nvme0: new ctrl: "nqn.2026-10.test:authsubsys"

With the patch the same controller is refused:

nvme nvme0: qid 0: controller did not authenticate
nvme nvme0: qid 0: authentication failed, error -129

drivers/nvme/host/auth.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c
index e55920642f2c1..cbb38935fa227 100644
--- a/drivers/nvme/host/auth.c
+++ b/drivers/nvme/host/auth.c
@@ -358,8 +358,21 @@ static int nvme_auth_process_dhchap_success1(struct nvme_ctrl *ctrl,
nvme_auth_hmac_name(chap->hash_id),
nvme_auth_dhgroup_name(chap->dhgroup_id));

- if (!data->rvalid)
+ if (!data->rvalid) {
+ /*
+ * The controller did not return a response. If we asked it to
+ * authenticate itself the session must not be used, otherwise
+ * mutual authentication would silently degrade to one-way.
+ */
+ if (chap->bi_directional) {
+ dev_warn(ctrl->device,
+ "qid %d: controller did not authenticate\n",
+ chap->qid);
+ chap->status = NVME_AUTH_DHCHAP_FAILURE_FAILED;
+ return -ECONNREFUSED;
+ }
return 0;
+ }

/* Validate controller response */
if (crypto_memneq(chap->response, data->rval, data->hl)) {
--
2.43.0