Skip to content

Commit

Permalink
Merge tag 'nvme-6.7-2023-10-17' of git://git.infradead.org/nvme into …
Browse files Browse the repository at this point in the history
…for-6.7/block

Pull NVMe updates from Keith:

"nvme updates for Linux 6.7

 - nvme-auth updates (Mark)
 - nvme-tcp tls (Hannes)
 - nvme-fc annotaions (Kees)"

* tag 'nvme-6.7-2023-10-17' of git://git.infradead.org/nvme: (24 commits)
  nvme-auth: allow mixing of secret and hash lengths
  nvme-auth: use transformed key size to create resp
  nvme-auth: alloc nvme_dhchap_key as single buffer
  nvmet-tcp: use 'spin_lock_bh' for state_lock()
  nvme: rework NVME_AUTH Kconfig selection
  nvmet-tcp: peek icreq before starting TLS
  nvmet-tcp: control messages for recvmsg()
  nvmet-tcp: enable TLS handshake upcall
  nvmet: Set 'TREQ' to 'required' when TLS is enabled
  nvmet-tcp: allocate socket file
  nvmet-tcp: make nvmet_tcp_alloc_queue() a void function
  nvmet: make TCP sectype settable via configfs
  nvme-fabrics: parse options 'keyring' and 'tls_key'
  nvme-tcp: improve icreq/icresp logging
  nvme-tcp: control message handling for recvmsg()
  nvme-tcp: enable TLS handshake upcall
  nvme-tcp: allocate socket file
  security/keys: export key_lookup()
  nvme-keyring: implement nvme_tls_psk_default()
  nvme-tcp: add definitions for TLS cipher suites
  ...
  • Loading branch information
axboe committed Oct 17, 2023
2 parents ec8cf23 + 3244552 commit 5bc8f14
Show file tree
Hide file tree
Showing 25 changed files with 1,090 additions and 132 deletions.
13 changes: 13 additions & 0 deletions drivers/nvme/common/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,16 @@

config NVME_COMMON
tristate

config NVME_KEYRING
bool
select KEYS

config NVME_AUTH
bool
select CRYPTO
select CRYPTO_HMAC
select CRYPTO_SHA256
select CRYPTO_SHA512
select CRYPTO_DH
select CRYPTO_DH_RFC7919_GROUPS
3 changes: 2 additions & 1 deletion drivers/nvme/common/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ ccflags-y += -I$(src)

obj-$(CONFIG_NVME_COMMON) += nvme-common.o

nvme-common-y += auth.o
nvme-common-$(CONFIG_NVME_AUTH) += auth.o
nvme-common-$(CONFIG_NVME_KEYRING) += keyring.o
68 changes: 39 additions & 29 deletions drivers/nvme/common/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ size_t nvme_auth_hmac_hash_len(u8 hmac_id)
}
EXPORT_SYMBOL_GPL(nvme_auth_hmac_hash_len);

u32 nvme_auth_key_struct_size(u32 key_len)
{
struct nvme_dhchap_key key;

return struct_size(&key, key, key_len);
}
EXPORT_SYMBOL_GPL(nvme_auth_key_struct_size);

struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
u8 key_hash)
{
Expand All @@ -163,14 +171,9 @@ struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
p = strrchr(secret, ':');
if (p)
allocated_len = p - secret;
key = kzalloc(sizeof(*key), GFP_KERNEL);
key = nvme_auth_alloc_key(allocated_len, 0);
if (!key)
return ERR_PTR(-ENOMEM);
key->key = kzalloc(allocated_len, GFP_KERNEL);
if (!key->key) {
ret = -ENOMEM;
goto out_free_key;
}

key_len = base64_decode(secret, allocated_len, key->key);
if (key_len < 0) {
Expand All @@ -187,14 +190,6 @@ struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
goto out_free_secret;
}

if (key_hash > 0 &&
(key_len - 4) != nvme_auth_hmac_hash_len(key_hash)) {
pr_err("Mismatched key len %d for %s\n", key_len,
nvme_auth_hmac_name(key_hash));
ret = -EINVAL;
goto out_free_secret;
}

/* The last four bytes is the CRC in little-endian format */
key_len -= 4;
/*
Expand All @@ -213,37 +208,51 @@ struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
key->hash = key_hash;
return key;
out_free_secret:
kfree_sensitive(key->key);
out_free_key:
kfree(key);
nvme_auth_free_key(key);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(nvme_auth_extract_key);

struct nvme_dhchap_key *nvme_auth_alloc_key(u32 len, u8 hash)
{
u32 num_bytes = nvme_auth_key_struct_size(len);
struct nvme_dhchap_key *key = kzalloc(num_bytes, GFP_KERNEL);

if (key) {
key->len = len;
key->hash = hash;
}
return key;
}
EXPORT_SYMBOL_GPL(nvme_auth_alloc_key);

void nvme_auth_free_key(struct nvme_dhchap_key *key)
{
if (!key)
return;
kfree_sensitive(key->key);
kfree(key);
kfree_sensitive(key);
}
EXPORT_SYMBOL_GPL(nvme_auth_free_key);

u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
struct nvme_dhchap_key *nvme_auth_transform_key(
struct nvme_dhchap_key *key, char *nqn)
{
const char *hmac_name;
struct crypto_shash *key_tfm;
struct shash_desc *shash;
u8 *transformed_key;
int ret;
struct nvme_dhchap_key *transformed_key;
int ret, key_len;

if (!key || !key->key) {
if (!key) {
pr_warn("No key specified\n");
return ERR_PTR(-ENOKEY);
}
if (key->hash == 0) {
transformed_key = kmemdup(key->key, key->len, GFP_KERNEL);
return transformed_key ? transformed_key : ERR_PTR(-ENOMEM);
key_len = nvme_auth_key_struct_size(key->len);
transformed_key = kmemdup(key, key_len, GFP_KERNEL);
if (!transformed_key)
return ERR_PTR(-ENOMEM);
return transformed_key;
}
hmac_name = nvme_auth_hmac_name(key->hash);
if (!hmac_name) {
Expand All @@ -253,7 +262,7 @@ u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)

key_tfm = crypto_alloc_shash(hmac_name, 0, 0);
if (IS_ERR(key_tfm))
return (u8 *)key_tfm;
return ERR_CAST(key_tfm);

shash = kmalloc(sizeof(struct shash_desc) +
crypto_shash_descsize(key_tfm),
Expand All @@ -263,7 +272,8 @@ u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
goto out_free_key;
}

transformed_key = kzalloc(crypto_shash_digestsize(key_tfm), GFP_KERNEL);
key_len = crypto_shash_digestsize(key_tfm);
transformed_key = nvme_auth_alloc_key(key_len, key->hash);
if (!transformed_key) {
ret = -ENOMEM;
goto out_free_shash;
Expand All @@ -282,7 +292,7 @@ u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
ret = crypto_shash_update(shash, "NVMe-over-Fabrics", 17);
if (ret < 0)
goto out_free_transformed_key;
ret = crypto_shash_final(shash, transformed_key);
ret = crypto_shash_final(shash, transformed_key->key);
if (ret < 0)
goto out_free_transformed_key;

Expand All @@ -292,7 +302,7 @@ u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
return transformed_key;

out_free_transformed_key:
kfree_sensitive(transformed_key);
nvme_auth_free_key(transformed_key);
out_free_shash:
kfree(shash);
out_free_key:
Expand Down
182 changes: 182 additions & 0 deletions drivers/nvme/common/keyring.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023 Hannes Reinecke, SUSE Labs
*/

#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/key.h>
#include <linux/key-type.h>
#include <keys/user-type.h>
#include <linux/nvme.h>
#include <linux/nvme-tcp.h>
#include <linux/nvme-keyring.h>

static struct key *nvme_keyring;

key_serial_t nvme_keyring_id(void)
{
return nvme_keyring->serial;
}
EXPORT_SYMBOL_GPL(nvme_keyring_id);

static void nvme_tls_psk_describe(const struct key *key, struct seq_file *m)
{
seq_puts(m, key->description);
seq_printf(m, ": %u", key->datalen);
}

static bool nvme_tls_psk_match(const struct key *key,
const struct key_match_data *match_data)
{
const char *match_id;
size_t match_len;

if (!key->description) {
pr_debug("%s: no key description\n", __func__);
return false;
}
match_len = strlen(key->description);
pr_debug("%s: id %s len %zd\n", __func__, key->description, match_len);

if (!match_data->raw_data) {
pr_debug("%s: no match data\n", __func__);
return false;
}
match_id = match_data->raw_data;
pr_debug("%s: match '%s' '%s' len %zd\n",
__func__, match_id, key->description, match_len);
return !memcmp(key->description, match_id, match_len);
}

static int nvme_tls_psk_match_preparse(struct key_match_data *match_data)
{
match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
match_data->cmp = nvme_tls_psk_match;
return 0;
}

static struct key_type nvme_tls_psk_key_type = {
.name = "psk",
.flags = KEY_TYPE_NET_DOMAIN,
.preparse = user_preparse,
.free_preparse = user_free_preparse,
.match_preparse = nvme_tls_psk_match_preparse,
.instantiate = generic_key_instantiate,
.revoke = user_revoke,
.destroy = user_destroy,
.describe = nvme_tls_psk_describe,
.read = user_read,
};

static struct key *nvme_tls_psk_lookup(struct key *keyring,
const char *hostnqn, const char *subnqn,
int hmac, bool generated)
{
char *identity;
size_t identity_len = (NVMF_NQN_SIZE) * 2 + 11;
key_ref_t keyref;
key_serial_t keyring_id;

identity = kzalloc(identity_len, GFP_KERNEL);
if (!identity)
return ERR_PTR(-ENOMEM);

snprintf(identity, identity_len, "NVMe0%c%02d %s %s",
generated ? 'G' : 'R', hmac, hostnqn, subnqn);

if (!keyring)
keyring = nvme_keyring;
keyring_id = key_serial(keyring);
pr_debug("keyring %x lookup tls psk '%s'\n",
keyring_id, identity);
keyref = keyring_search(make_key_ref(keyring, true),
&nvme_tls_psk_key_type,
identity, false);
if (IS_ERR(keyref)) {
pr_debug("lookup tls psk '%s' failed, error %ld\n",
identity, PTR_ERR(keyref));
kfree(identity);
return ERR_PTR(-ENOKEY);
}
kfree(identity);

return key_ref_to_ptr(keyref);
}

/*
* NVMe PSK priority list
*
* 'Retained' PSKs (ie 'generated == false')
* should be preferred to 'generated' PSKs,
* and SHA-384 should be preferred to SHA-256.
*/
struct nvme_tls_psk_priority_list {
bool generated;
enum nvme_tcp_tls_cipher cipher;
} nvme_tls_psk_prio[] = {
{ .generated = false,
.cipher = NVME_TCP_TLS_CIPHER_SHA384, },
{ .generated = false,
.cipher = NVME_TCP_TLS_CIPHER_SHA256, },
{ .generated = true,
.cipher = NVME_TCP_TLS_CIPHER_SHA384, },
{ .generated = true,
.cipher = NVME_TCP_TLS_CIPHER_SHA256, },
};

/*
* nvme_tls_psk_default - Return the preferred PSK to use for TLS ClientHello
*/
key_serial_t nvme_tls_psk_default(struct key *keyring,
const char *hostnqn, const char *subnqn)
{
struct key *tls_key;
key_serial_t tls_key_id;
int prio;

for (prio = 0; prio < ARRAY_SIZE(nvme_tls_psk_prio); prio++) {
bool generated = nvme_tls_psk_prio[prio].generated;
enum nvme_tcp_tls_cipher cipher = nvme_tls_psk_prio[prio].cipher;

tls_key = nvme_tls_psk_lookup(keyring, hostnqn, subnqn,
cipher, generated);
if (!IS_ERR(tls_key)) {
tls_key_id = tls_key->serial;
key_put(tls_key);
return tls_key_id;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(nvme_tls_psk_default);

int nvme_keyring_init(void)
{
int err;

nvme_keyring = keyring_alloc(".nvme",
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
current_cred(),
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
(KEY_USR_ALL & ~KEY_USR_SETATTR),
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(nvme_keyring))
return PTR_ERR(nvme_keyring);

err = register_key_type(&nvme_tls_psk_key_type);
if (err) {
key_put(nvme_keyring);
return err;
}
return 0;
}
EXPORT_SYMBOL_GPL(nvme_keyring_init);

void nvme_keyring_exit(void)
{
unregister_key_type(&nvme_tls_psk_key_type);
key_revoke(nvme_keyring);
key_put(nvme_keyring);
}
EXPORT_SYMBOL_GPL(nvme_keyring_exit);
24 changes: 17 additions & 7 deletions drivers/nvme/host/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,26 @@ config NVME_TCP

If unsure, say N.

config NVME_AUTH
config NVME_TCP_TLS
bool "NVMe over Fabrics TCP TLS encryption support"
depends on NVME_TCP
select NVME_COMMON
select NVME_KEYRING
select NET_HANDSHAKE
select KEYS
help
Enables TLS encryption for NVMe TCP using the netlink handshake API.

The TLS handshake daemon is availble at
https://github.com/oracle/ktls-utils.

If unsure, say N.

config NVME_HOST_AUTH
bool "NVM Express over Fabrics In-Band Authentication"
depends on NVME_CORE
select NVME_COMMON
select CRYPTO
select CRYPTO_HMAC
select CRYPTO_SHA256
select CRYPTO_SHA512
select CRYPTO_DH
select CRYPTO_DH_RFC7919_GROUPS
select NVME_AUTH
help
This provides support for NVMe over Fabrics In-Band Authentication.

Expand Down
2 changes: 1 addition & 1 deletion drivers/nvme/host/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ nvme-core-$(CONFIG_NVME_MULTIPATH) += multipath.o
nvme-core-$(CONFIG_BLK_DEV_ZONED) += zns.o
nvme-core-$(CONFIG_FAULT_INJECTION_DEBUG_FS) += fault_inject.o
nvme-core-$(CONFIG_NVME_HWMON) += hwmon.o
nvme-core-$(CONFIG_NVME_AUTH) += auth.o
nvme-core-$(CONFIG_NVME_HOST_AUTH) += auth.o

nvme-y += pci.o

Expand Down
Loading

0 comments on commit 5bc8f14

Please sign in to comment.