nvmet: implement basic In-Band Authentication

Implement NVMe-oF In-Band authentication according to NVMe TPAR 8006.
This patch adds three additional configfs entries 'dhchap_key',
'dhchap_ctrl_key', and 'dhchap_hash' to the 'host' configfs directory.
The 'dhchap_key' and 'dhchap_ctrl_key' entries need to be in the ASCII
format as specified in NVMe Base Specification v2.0 section 8.13.5.8
'Secret representation'.
'dhchap_hash' defaults to 'hmac(sha256)', and can be written to to
switch to a different HMAC algorithm.

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>
This commit is contained in:
Hannes Reinecke
2022-06-27 11:52:05 +02:00
committed by Jens Axboe
parent 6490c9ed06
commit db1312dd95
9 changed files with 1100 additions and 3 deletions

View File

@@ -11,6 +11,11 @@
#include <linux/ctype.h>
#include <linux/pci.h>
#include <linux/pci-p2pdma.h>
#ifdef CONFIG_NVME_TARGET_AUTH
#include <linux/nvme-auth.h>
#endif
#include <crypto/hash.h>
#include <crypto/kpp.h>
#include "nvmet.h"
@@ -1680,10 +1685,102 @@ static const struct config_item_type nvmet_ports_type = {
static struct config_group nvmet_subsystems_group;
static struct config_group nvmet_ports_group;
#ifdef CONFIG_NVME_TARGET_AUTH
static ssize_t nvmet_host_dhchap_key_show(struct config_item *item,
char *page)
{
u8 *dhchap_secret = to_host(item)->dhchap_secret;
if (!dhchap_secret)
return sprintf(page, "\n");
return sprintf(page, "%s\n", dhchap_secret);
}
static ssize_t nvmet_host_dhchap_key_store(struct config_item *item,
const char *page, size_t count)
{
struct nvmet_host *host = to_host(item);
int ret;
ret = nvmet_auth_set_key(host, page, false);
/*
* Re-authentication is a soft state, so keep the
* current authentication valid until the host
* requests re-authentication.
*/
return ret < 0 ? ret : count;
}
CONFIGFS_ATTR(nvmet_host_, dhchap_key);
static ssize_t nvmet_host_dhchap_ctrl_key_show(struct config_item *item,
char *page)
{
u8 *dhchap_secret = to_host(item)->dhchap_ctrl_secret;
if (!dhchap_secret)
return sprintf(page, "\n");
return sprintf(page, "%s\n", dhchap_secret);
}
static ssize_t nvmet_host_dhchap_ctrl_key_store(struct config_item *item,
const char *page, size_t count)
{
struct nvmet_host *host = to_host(item);
int ret;
ret = nvmet_auth_set_key(host, page, true);
/*
* Re-authentication is a soft state, so keep the
* current authentication valid until the host
* requests re-authentication.
*/
return ret < 0 ? ret : count;
}
CONFIGFS_ATTR(nvmet_host_, dhchap_ctrl_key);
static ssize_t nvmet_host_dhchap_hash_show(struct config_item *item,
char *page)
{
struct nvmet_host *host = to_host(item);
const char *hash_name = nvme_auth_hmac_name(host->dhchap_hash_id);
return sprintf(page, "%s\n", hash_name ? hash_name : "none");
}
static ssize_t nvmet_host_dhchap_hash_store(struct config_item *item,
const char *page, size_t count)
{
struct nvmet_host *host = to_host(item);
u8 hmac_id;
hmac_id = nvme_auth_hmac_id(page);
if (hmac_id == NVME_AUTH_HASH_INVALID)
return -EINVAL;
if (!crypto_has_shash(nvme_auth_hmac_name(hmac_id), 0, 0))
return -ENOTSUPP;
host->dhchap_hash_id = hmac_id;
return count;
}
CONFIGFS_ATTR(nvmet_host_, dhchap_hash);
static struct configfs_attribute *nvmet_host_attrs[] = {
&nvmet_host_attr_dhchap_key,
&nvmet_host_attr_dhchap_ctrl_key,
&nvmet_host_attr_dhchap_hash,
NULL,
};
#endif /* CONFIG_NVME_TARGET_AUTH */
static void nvmet_host_release(struct config_item *item)
{
struct nvmet_host *host = to_host(item);
#ifdef CONFIG_NVME_TARGET_AUTH
if (host->dhchap_secret)
kfree(host->dhchap_secret);
#endif
kfree(host);
}
@@ -1693,6 +1790,9 @@ static struct configfs_item_operations nvmet_host_item_ops = {
static const struct config_item_type nvmet_host_type = {
.ct_item_ops = &nvmet_host_item_ops,
#ifdef CONFIG_NVME_TARGET_AUTH
.ct_attrs = nvmet_host_attrs,
#endif
.ct_owner = THIS_MODULE,
};
@@ -1705,6 +1805,11 @@ static struct config_group *nvmet_hosts_make_group(struct config_group *group,
if (!host)
return ERR_PTR(-ENOMEM);
#ifdef CONFIG_NVME_TARGET_AUTH
/* Default to SHA256 */
host->dhchap_hash_id = NVME_AUTH_HASH_SHA256;
#endif
config_group_init_type_name(&host->group, name, &nvmet_host_type);
return &host->group;