Skip to content

Commit

Permalink
nvme-auth: Diffie-Hellman key exchange support
Browse files Browse the repository at this point in the history
Implement Diffie-Hellman key exchange using FFDHE groups
for NVMe In-Band Authentication.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
  • Loading branch information
Hannes Reinecke authored and Jens Axboe committed Aug 2, 2022
1 parent f50fff7 commit b61775d
Show file tree
Hide file tree
Showing 4 changed files with 358 additions and 6 deletions.
153 changes: 153 additions & 0 deletions drivers/nvme/common/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,159 @@ u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
}
EXPORT_SYMBOL_GPL(nvme_auth_transform_key);

static int nvme_auth_hash_skey(int hmac_id, u8 *skey, size_t skey_len, u8 *hkey)
{
const char *digest_name;
struct crypto_shash *tfm;
int ret;

digest_name = nvme_auth_digest_name(hmac_id);
if (!digest_name) {
pr_debug("%s: failed to get digest for %d\n", __func__,
hmac_id);
return -EINVAL;
}
tfm = crypto_alloc_shash(digest_name, 0, 0);
if (IS_ERR(tfm))
return -ENOMEM;

ret = crypto_shash_tfm_digest(tfm, skey, skey_len, hkey);
if (ret < 0)
pr_debug("%s: Failed to hash digest len %zu\n", __func__,
skey_len);

crypto_free_shash(tfm);
return ret;
}

int nvme_auth_augmented_challenge(u8 hmac_id, u8 *skey, size_t skey_len,
u8 *challenge, u8 *aug, size_t hlen)
{
struct crypto_shash *tfm;
struct shash_desc *desc;
u8 *hashed_key;
const char *hmac_name;
int ret;

hashed_key = kmalloc(hlen, GFP_KERNEL);
if (!hashed_key)
return -ENOMEM;

ret = nvme_auth_hash_skey(hmac_id, skey,
skey_len, hashed_key);
if (ret < 0)
goto out_free_key;

hmac_name = nvme_auth_hmac_name(hmac_id);
if (!hmac_name) {
pr_warn("%s: invalid hash algoritm %d\n",
__func__, hmac_id);
ret = -EINVAL;
goto out_free_key;
}

tfm = crypto_alloc_shash(hmac_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, hlen);
if (ret)
goto out_free_desc;

ret = crypto_shash_init(desc);
if (ret)
goto out_free_desc;

ret = crypto_shash_update(desc, challenge, hlen);
if (ret)
goto out_free_desc;

ret = crypto_shash_final(desc, aug);
out_free_desc:
kfree_sensitive(desc);
out_free_hash:
crypto_free_shash(tfm);
out_free_key:
kfree_sensitive(hashed_key);
return ret;
}
EXPORT_SYMBOL_GPL(nvme_auth_augmented_challenge);

int nvme_auth_gen_privkey(struct crypto_kpp *dh_tfm, u8 dh_gid)
{
int ret;

ret = crypto_kpp_set_secret(dh_tfm, NULL, 0);
if (ret)
pr_debug("failed to set private key, error %d\n", ret);

return ret;
}
EXPORT_SYMBOL_GPL(nvme_auth_gen_privkey);

int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm,
u8 *host_key, size_t host_key_len)
{
struct kpp_request *req;
struct crypto_wait wait;
struct scatterlist dst;
int ret;

req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
if (!req)
return -ENOMEM;

crypto_init_wait(&wait);
kpp_request_set_input(req, NULL, 0);
sg_init_one(&dst, host_key, host_key_len);
kpp_request_set_output(req, &dst, host_key_len);
kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
crypto_req_done, &wait);

ret = crypto_wait_req(crypto_kpp_generate_public_key(req), &wait);
kpp_request_free(req);
return ret;
}
EXPORT_SYMBOL_GPL(nvme_auth_gen_pubkey);

int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm,
u8 *ctrl_key, size_t ctrl_key_len,
u8 *sess_key, size_t sess_key_len)
{
struct kpp_request *req;
struct crypto_wait wait;
struct scatterlist src, dst;
int ret;

req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
if (!req)
return -ENOMEM;

crypto_init_wait(&wait);
sg_init_one(&src, ctrl_key, ctrl_key_len);
kpp_request_set_input(req, &src, ctrl_key_len);
sg_init_one(&dst, sess_key, sess_key_len);
kpp_request_set_output(req, &dst, sess_key_len);
kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
crypto_req_done, &wait);

ret = crypto_wait_req(crypto_kpp_compute_shared_secret(req), &wait);

kpp_request_free(req);
return ret;
}
EXPORT_SYMBOL_GPL(nvme_auth_gen_shared_secret);

int nvme_auth_generate_key(u8 *secret, struct nvme_dhchap_key **ret_key)
{
struct nvme_dhchap_key *key;
Expand Down
2 changes: 2 additions & 0 deletions drivers/nvme/host/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ config NVME_AUTH
select CRYPTO_HMAC
select CRYPTO_SHA256
select CRYPTO_SHA512
select CRYPTO_DH
select CRYPTO_DH_RFC7919_GROUPS
help
This provides support for NVMe over Fabrics In-Band Authentication.

Expand Down
Loading

0 comments on commit b61775d

Please sign in to comment.