summaryrefslogtreecommitdiff
path: root/drivers/nvme/host
diff options
context:
space:
mode:
authorChris Leech <cleech@redhat.com>2026-04-22 12:06:36 -0700
committerKeith Busch <kbusch@kernel.org>2026-04-22 13:02:16 -0700
commitbd7b7ce96db4487bb77692a85ee4489fd2c395df (patch)
treea83dc705b248a07614685df277d19a79318f72b8 /drivers/nvme/host
parent1cc4cdae2a3b7730d462d69e30f213fd2efe7807 (diff)
nvme-auth: Hash DH shared secret to create session key
The NVMe Base Specification 8.3.5.5.9 states that the session key Ks shall be computed from the ephemeral DH key by applying the hash function selected by the HashID parameter. The current implementation stores the raw DH shared secret as the session key without hashing it. This causes redundant hash operations: 1. Augmented challenge computation (section 8.3.5.5.4) requires Ca = HMAC(H(g^xy mod p), C). The code compensates by hashing the unhashed session key in nvme_auth_augmented_challenge() to produce the correct result. 2. PSK generation (section 8.3.5.5.9) requires PSK = HMAC(Ks, C1 || C2) where Ks should already be H(g^xy mod p). As the DH shared secret is always larger than the HMAC block size, HMAC internally hashes it before use, accidentally producing the correct result. When using secure channel concatenation with bidirectional authentication, this results in hashing the DH value three times: twice for augmented challenge calculations and once during PSK generation. Fix this by: - Modifying nvme_auth_gen_shared_secret() to hash the DH shared secret once after computation: Ks = H(g^xy mod p) - Removing the hash operation from nvme_auth_augmented_challenge() as the session key is now already hashed - Updating session key buffer size from DH key size to hash output size - Adding specification references in comments This avoid storing the raw DH shared secret and reduces the number of hash operations from three to one when using secure channel concatenation. Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Chris Leech <cleech@redhat.com> Signed-off-by: Keith Busch <kbusch@kernel.org>
Diffstat (limited to 'drivers/nvme/host')
-rw-r--r--drivers/nvme/host/auth.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c
index 63f543e80998..16de4499a8e7 100644
--- a/drivers/nvme/host/auth.c
+++ b/drivers/nvme/host/auth.c
@@ -588,7 +588,7 @@ static int nvme_auth_dhchap_exponential(struct nvme_ctrl *ctrl,
}
gen_sesskey:
- chap->sess_key_len = chap->host_key_len;
+ chap->sess_key_len = chap->hash_len;
chap->sess_key = kmalloc(chap->sess_key_len, GFP_KERNEL);
if (!chap->sess_key) {
chap->sess_key_len = 0;
@@ -596,16 +596,17 @@ gen_sesskey:
return -ENOMEM;
}
- ret = nvme_auth_gen_shared_secret(chap->dh_tfm,
- chap->ctrl_key, chap->ctrl_key_len,
- chap->sess_key, chap->sess_key_len);
+ ret = nvme_auth_gen_session_key(chap->dh_tfm,
+ chap->ctrl_key, chap->ctrl_key_len,
+ chap->sess_key, chap->sess_key_len,
+ chap->hash_id);
if (ret) {
dev_dbg(ctrl->device,
- "failed to generate shared secret, error %d\n", ret);
+ "failed to generate session key, error %d\n", ret);
chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
return ret;
}
- dev_dbg(ctrl->device, "shared secret %*ph\n",
+ dev_dbg(ctrl->device, "session key %*ph\n",
(int)chap->sess_key_len, chap->sess_key);
return 0;
}