[PATCH 11/11] nvme: add non-standard ECDH and curve25517 algorithms
From: Hannes Reinecke <hare@suse.de>
Date: 2021-07-16 11:06:32
Also in:
linux-nvme
Subsystem:
nvm express driver, nvm express fabrics authentication, nvm express target driver, the rest · Maintainers:
Keith Busch, Jens Axboe, Christoph Hellwig, Sagi Grimberg, Hannes Reinecke, Chaitanya Kulkarni, Linus Torvalds
TLS 1.3 specifies ECDH and curve25517 in addition to the FFDHE groups, and these are already implemented in the kernel. So add support for these non-standard groups for NVMe in-band authentication to validate the augmented challenge implementation. Signed-off-by: Hannes Reinecke <hare@suse.de> --- drivers/nvme/host/auth.c | 38 +++++++++++++++++++++++++++++++++++++- drivers/nvme/target/auth.c | 23 +++++++++++++++++++++++ include/linux/nvme.h | 2 ++ 3 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c
index 754343aced19..d0dd63b455ef 100644
--- a/drivers/nvme/host/auth.c
+++ b/drivers/nvme/host/auth.c@@ -10,6 +10,8 @@ #include <crypto/kpp.h> #include <crypto/dh.h> #include <crypto/ffdhe.h> +#include <crypto/ecdh.h> +#include <crypto/curve25519.h> #include "nvme.h" #include "fabrics.h" #include "auth.h"
@@ -67,6 +69,13 @@ struct nvme_auth_dhgroup_map { { .id = NVME_AUTH_DHCHAP_DHGROUP_8192, .name = "ffdhe8192", .kpp = "dh", .privkey_size = 1024, .pubkey_size = 1024 }, + { .id = NVME_AUTH_DHCHAP_DHGROUP_ECDH, + .name = "ecdh", .kpp = "ecdh-nist-p256", + .privkey_size = 32, .pubkey_size = 64 }, + { .id = NVME_AUTH_DHCHAP_DHGROUP_25519, + .name = "curve25519", .kpp = "curve25519", + .privkey_size = CURVE25519_KEY_SIZE, + .pubkey_size = CURVE25519_KEY_SIZE }, }; const char *nvme_auth_dhgroup_name(int dhgroup_id)
@@ -337,7 +346,7 @@ static int nvme_auth_dhchap_negotiate(struct nvme_ctrl *ctrl, data->napd = 1; data->auth_protocol[0].dhchap.authid = NVME_AUTH_DHCHAP_AUTH_ID; data->auth_protocol[0].dhchap.halen = 3; - data->auth_protocol[0].dhchap.dhlen = 6; + data->auth_protocol[0].dhchap.dhlen = 8; data->auth_protocol[0].dhchap.idlist[0] = NVME_AUTH_DHCHAP_HASH_SHA256; data->auth_protocol[0].dhchap.idlist[1] = NVME_AUTH_DHCHAP_HASH_SHA384; data->auth_protocol[0].dhchap.idlist[2] = NVME_AUTH_DHCHAP_HASH_SHA512;
@@ -347,6 +356,8 @@ static int nvme_auth_dhchap_negotiate(struct nvme_ctrl *ctrl, data->auth_protocol[0].dhchap.idlist[6] = NVME_AUTH_DHCHAP_DHGROUP_4096; data->auth_protocol[0].dhchap.idlist[7] = NVME_AUTH_DHCHAP_DHGROUP_6144; data->auth_protocol[0].dhchap.idlist[8] = NVME_AUTH_DHCHAP_DHGROUP_8192; + data->auth_protocol[0].dhchap.idlist[9] = NVME_AUTH_DHCHAP_DHGROUP_ECDH; + data->auth_protocol[0].dhchap.idlist[10] = NVME_AUTH_DHCHAP_DHGROUP_25519; return size; }
@@ -889,6 +900,31 @@ static int nvme_auth_dhchap_exponential(struct nvme_ctrl *ctrl, } chap->host_key_len = pubkey_size; chap->sess_key_len = pubkey_size; + } else if (chap->dhgroup_id == NVME_AUTH_DHCHAP_DHGROUP_ECDH) { + struct ecdh p = {0}; + + pkey_len = crypto_ecdh_key_len(&p); + pkey = kzalloc(pkey_len, GFP_KERNEL); + if (!pkey) + return -ENOMEM; + + get_random_bytes(pkey, pkey_len); + ret = crypto_ecdh_encode_key(pkey, pkey_len, &p); + if (ret) { + dev_dbg(ctrl->device, + "failed to encode pkey, error %d\n", ret); + kfree(pkey); + return ret; + } + chap->host_key_len = 64; + chap->sess_key_len = 32; + } else if (chap->dhgroup_id == NVME_AUTH_DHCHAP_DHGROUP_25519) { + pkey_len = CURVE25519_KEY_SIZE; + pkey = kzalloc(pkey_len, GFP_KERNEL); + if (!pkey) + return -ENOMEM; + get_random_bytes(pkey, pkey_len); + chap->host_key_len = chap->sess_key_len = CURVE25519_KEY_SIZE; } else { dev_warn(ctrl->device, "Invalid DH group id %d\n", chap->dhgroup_id);
diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c
index cc7f12a7c8bf..7e3b613cb08b 100644
--- a/drivers/nvme/target/auth.c
+++ b/drivers/nvme/target/auth.c@@ -13,6 +13,8 @@ #include <crypto/kpp.h> #include <crypto/dh.h> #include <crypto/ffdhe.h> +#include <crypto/ecdh.h> +#include <crypto/curve25519.h> #include <linux/crc32.h> #include <linux/base64.h> #include <linux/ctype.h>
@@ -498,6 +500,27 @@ int nvmet_auth_ctrl_exponential(struct nvmet_req *req, ret); goto out; } + } else if (ctrl->dh_gid == NVME_AUTH_DHCHAP_DHGROUP_ECDH) { + struct ecdh p = {0}; + + pkey_len = crypto_ecdh_key_len(&p); + pkey = kmalloc(pkey_len, GFP_KERNEL); + if (!pkey) + return -ENOMEM; + + get_random_bytes(pkey, pkey_len); + ret = crypto_ecdh_encode_key(pkey, pkey_len, &p); + if (ret) { + pr_debug("failed to encode private key, error %d\n", + ret); + goto out; + } + } else if (ctrl->dh_gid == NVME_AUTH_DHCHAP_DHGROUP_25519) { + pkey_len = CURVE25519_KEY_SIZE; + pkey = kmalloc(pkey_len, GFP_KERNEL); + if (!pkey) + return -ENOMEM; + get_random_bytes(pkey, pkey_len); } else { pr_warn("invalid dh group %d\n", ctrl->dh_gid); return -EINVAL;
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 7b94abacfd08..75b638adbca1 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h@@ -1476,6 +1476,8 @@ enum { NVME_AUTH_DHCHAP_DHGROUP_4096 = 0x03, NVME_AUTH_DHCHAP_DHGROUP_6144 = 0x04, NVME_AUTH_DHCHAP_DHGROUP_8192 = 0x05, + NVME_AUTH_DHCHAP_DHGROUP_ECDH = 0x0e, + NVME_AUTH_DHCHAP_DHGROUP_25519 = 0x0f, }; union nvmf_auth_protocol {
--
2.29.2