Implement support for augmented challenge with FFDHE groups.
This patch adds a new configfs attribute 'dhchap_dhgroup' to
select the DH group to use.
Signed-off-by: Hannes Reinecke <hare@xxxxxxx>
---
drivers/nvme/target/auth.c | 241 ++++++++++++++++++++++++-
drivers/nvme/target/configfs.c | 31 ++++
drivers/nvme/target/fabrics-cmd-auth.c | 14 +-
3 files changed, 281 insertions(+), 5 deletions(-)
diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c
index 00c7d051dfb1..cc7f12a7c8bf 100644
--- a/drivers/nvme/target/auth.c
+++ b/drivers/nvme/target/auth.c
@@ -58,11 +58,56 @@ int nvmet_auth_set_host_key(struct nvmet_host *host,
const char *secret)
int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, int dhgroup_id)
{
+ struct nvmet_host_link *p;
+ struct nvmet_host *host = NULL;
+ const char *dhgroup_kpp;
int ret = -ENOTSUPP;
if (dhgroup_id == NVME_AUTH_DHCHAP_DHGROUP_NULL)
return 0;
+ down_read(&nvmet_config_sem);
+ if (ctrl->subsys->type == NVME_NQN_DISC)
+ goto out_unlock;
+
+ list_for_each_entry(p, &ctrl->subsys->hosts, entry) {
+ if (strcmp(nvmet_host_name(p->host), ctrl->hostnqn))
+ continue;
+ host = p->host;
+ break;
+ }
+ if (!host) {
+ pr_debug("host %s not found\n", ctrl->hostnqn);
+ ret = -ENXIO;
+ goto out_unlock;
+ }
+
+ if (host->dhchap_dhgroup_id != dhgroup_id) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+ dhgroup_kpp = nvme_auth_dhgroup_kpp(dhgroup_id);
+ if (!dhgroup_kpp) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+ ctrl->dh_tfm = crypto_alloc_kpp(dhgroup_kpp, 0, 0);
+ if (IS_ERR(ctrl->dh_tfm)) {
+ pr_debug("failed to setup DH group %d, err %ld\n",
+ dhgroup_id, PTR_ERR(ctrl->dh_tfm));
+ ret = PTR_ERR(ctrl->dh_tfm);
+ ctrl->dh_tfm = NULL;
+ } else {
+ ctrl->dh_gid = dhgroup_id;
+ ctrl->dh_keysize = nvme_auth_dhgroup_pubkey_size(dhgroup_id);
+ pr_debug("select DH group %d keysize %d\n",
+ ctrl->dh_gid, ctrl->dh_keysize);
+ ret = 0;
+ }
+
+out_unlock:
+ up_read(&nvmet_config_sem);
+
return ret;
}
@@ -192,6 +237,101 @@ bool nvmet_check_auth_status(struct nvmet_req *req)
return true;
}
+static int nvmet_auth_hash_sesskey(struct nvmet_req *req, u8 *hashed_key)
+{
+ struct nvmet_ctrl *ctrl = req->sq->ctrl;
+ const char *hmac_name, *digest_name;
+ struct crypto_shash *tfm;
+ int hmac_id, ret;
+
+ if (!ctrl->shash_tfm) {
+ pr_debug("%s: hash alg not set\n", __func__);
+ return -EINVAL;
+ }
+ hmac_name = crypto_shash_alg_name(ctrl->shash_tfm);
+ hmac_id = nvme_auth_hmac_id(hmac_name);
+ if (hmac_id < 0) {
+ pr_debug("%s: unsupported hmac %s\n", __func__,
+ hmac_name);
+ return -EINVAL;
+ }
+ digest_name = nvme_auth_digest_name(hmac_id);
+ if (!digest_name) {
+ pr_debug("%s: failed to get digest for %s\n", __func__,
+ hmac_name);
+ return -EINVAL;
+ }
+ tfm = crypto_alloc_shash(digest_name, 0, 0);
+ if (IS_ERR(tfm))
+ return -ENOMEM;
+
+ ret = crypto_shash_tfm_digest(tfm, req->sq->dhchap_skey,
+ req->sq->dhchap_skey_len, hashed_key);
+ if (ret < 0)
+ pr_debug("%s: Failed to hash digest len %d\n", __func__,
+ req->sq->dhchap_skey_len);
+
+ crypto_free_shash(tfm);
+ return ret;
+}
+
+static int nvmet_auth_augmented_challenge(struct nvmet_req *req,
+ u8 *challenge, u8 *aug)
+{
+ struct nvmet_ctrl *ctrl = req->sq->ctrl;
+ struct crypto_shash *tfm;
+ struct shash_desc *desc;
+ u8 *hashed_key;
+ const char *hash_name;
+ int hash_len = req->sq->dhchap_hash_len;
+ int ret;
+
+ hashed_key = kmalloc(hash_len, GFP_KERNEL);
+ if (!hashed_key)
+ return -ENOMEM;
+
+ ret = nvmet_auth_hash_sesskey(req, hashed_key);
+ if (ret < 0) {
+ pr_debug("failed to hash session key, err %d\n", ret);
+ kfree(hashed_key);
+ return ret;
+ }
+ hash_name = crypto_shash_alg_name(ctrl->shash_tfm);
+ if (!hash_name) {
+ pr_debug("Invalid hash algoritm\n");
+ return -EINVAL;
+ }
+ tfm = crypto_alloc_shash(hash_name, 0, 0);
+ if (IS_ERR(tfm)) {
+ ret = PTR_ERR(tfm);
+ goto out_free_key;
+ }
+ desc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(tfm),
+ GFP_KERNEL);
+ if (!desc) {
+ ret = -ENOMEM;
+ goto out_free_hash;
+ }
+ desc->tfm = tfm;
+
+ ret = crypto_shash_setkey(tfm, hashed_key, hash_len);
+ if (ret)
+ goto out_free_desc;
+ ret = crypto_shash_init(desc);
+ if (ret)
+ goto out_free_desc;
+ crypto_shash_update(desc, challenge, hash_len);
+ crypto_shash_final(desc, aug);
+
+out_free_desc:
+ kfree_sensitive(desc);
+out_free_hash:
+ crypto_free_shash(tfm);
+out_free_key:
+ kfree(hashed_key);
+ return ret;
+}
+
int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response,
unsigned int shash_len)
{
@@ -202,8 +342,15 @@ int nvmet_auth_host_hash(struct nvmet_req *req, u8
*response, int ret;
if (ctrl->dh_gid != NVME_AUTH_DHCHAP_DHGROUP_NULL) {
- ret = -ENOTSUPP;
- goto out;
+ challenge = kmalloc(shash_len, GFP_KERNEL);