Skip to contentSkip to conversation

nvme: In-band authentication support

PATCH Superseded Hannes Reinecke 4 participants 21 messages Sep 28, 2021 – Oct 8, 2021

Subsystems (5)

v4 of 18 Superseded Latest is v18 →

lore
Share & tools
lore

Hannes Reinecke

author maintainer
#0 lore raw

v4 cover nvme: In-band authentication support

Hi all,

recent updates to the NVMe spec have added definitions for in-band authentication, and seeing that it provides some real benefit especially for NVMe-TCP here's an attempt to implement it.

Tricky bit here is that the specification orients itself on TLS 1.3, but supports only the FFDHE groups. Which of course the kernel doesn't support. I've been able to come up with a patch for this, but as this is my first attempt to fix anything in the crypto area I would invite people more familiar with these matters to have a look.

Also note that this is just for in-band authentication. Secure concatenation (ie starting TLS with the negotiated parameters) is not implemented; one would need to update the kernel TLS implementation for this, which at this time is beyond scope.

As usual, comments and reviews are welcome.

Changes to v3:
- Renamed parameter to 'dhchap_ctrl_key'
- Fixed bi-directional authentication
- Included reviews from Sagi
- Fixed base64 algorithm for transport encoding

Changes to v2:
- Dropped non-standard algorithms
- Reworked base64 based on fs/crypto/fname.c
- Fixup crash with no keys

Changes to the original submission:
- Included reviews from Vladislav
- Included reviews from Sagi
- Implemented re-authentication support
- Fixed up key handling

Hannes Reinecke (12):
crypto: add crypto_has_shash()
crypto: add crypto_has_kpp()
crypto/ffdhe: Finite Field DH Ephemeral Parameters lib/base64: RFC4648-compliant base64 encoding
nvme: add definitions for NVMe In-Band authentication
nvme-fabrics: decode 'authentication required' connect error
nvme: Implement In-Band authentication
nvme-auth: Diffie-Hellman key exchange support
nvmet: Parse fabrics commands on all queues
nvmet: Implement basic In-Band Authentication
nvmet-auth: Diffie-Hellman key exchange support
nvmet-auth: expire authentication sessions

 crypto/Kconfig                         |    8 +
 crypto/Makefile                        |    1 +
 crypto/ffdhe_helper.c                  |  880 ++++++++++++++
 crypto/kpp.c                           |    6 +
 crypto/shash.c                         |    6 +
 drivers/nvme/host/Kconfig              |   12 +
 drivers/nvme/host/Makefile             |    1 +
 drivers/nvme/host/auth.c               | 1501 ++++++++++++++++++++++++
 drivers/nvme/host/auth.h               |   33 +
 drivers/nvme/host/core.c               |  126 +-
 drivers/nvme/host/fabrics.c            |   85 +-
 drivers/nvme/host/fabrics.h            |    7 +
 drivers/nvme/host/nvme.h               |   33 +
 drivers/nvme/host/trace.c              |   32 +
 drivers/nvme/target/Kconfig            |   12 +
 drivers/nvme/target/Makefile           |    1 +
 drivers/nvme/target/admin-cmd.c        |    4 +
 drivers/nvme/target/auth.c             |  486 ++++++++
 drivers/nvme/target/configfs.c         |  133 ++-
 drivers/nvme/target/core.c             |   10 +
 drivers/nvme/target/fabrics-cmd-auth.c |  507 ++++++++
 drivers/nvme/target/fabrics-cmd.c      |   30 +-
 drivers/nvme/target/nvmet.h            |   74 ++
 include/crypto/ffdhe.h                 |   24 +
 include/crypto/hash.h                  |    2 +
 include/crypto/kpp.h                   |    2 +
 include/linux/base64.h                 |   16 +
 include/linux/nvme.h                   |  186 ++-
 lib/Makefile                           |    2 +-
 lib/base64.c                           |  100 ++
 30 files changed, 4309 insertions(+), 11 deletions(-)
 create mode 100644 crypto/ffdhe_helper.c
 create mode 100644 drivers/nvme/host/auth.c
 create mode 100644 drivers/nvme/host/auth.h
 create mode 100644 drivers/nvme/target/auth.c
 create mode 100644 drivers/nvme/target/fabrics-cmd-auth.c
 create mode 100644 include/crypto/ffdhe.h
 create mode 100644 include/linux/base64.h
 create mode 100644 lib/base64.c
Signature · 7 lines
2.29.2


_______________________________________________
Linux-nvme mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-nvme
author maintainer
#1 lore raw

PATCH v4 1/12 crypto: add crypto_has_shash()

Add helper function to determine if a given synchronous hash is supported.

---
 crypto/shash.c        | 6 ++++++
 include/crypto/hash.h | 2 ++
 2 files changed, 8 insertions(+)
crypto/shash.c +6 -0
index 0a0a50cb694f..4c88e63b3350 100644
@@ -521,6 +521,12 @@ struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type,
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_shash);
 
+int crypto_has_shash(const char *alg_name, u32 type, u32 mask)
+{
+	return crypto_type_has_alg(alg_name, &crypto_shash_type, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_has_shash);
+
 static int shash_prepare_alg(struct shash_alg *alg)
 {
 	struct crypto_alg *base = &alg->base;
include/crypto/hash.h +2 -0
index f140e4643949..f5841992dc9b 100644
@@ -718,6 +718,8 @@ static inline void ahash_request_set_crypt(struct ahash_request *req,
 struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type,
 					u32 mask);
 
+int crypto_has_shash(const char *alg_name, u32 type, u32 mask);
+
 static inline struct crypto_tfm *crypto_shash_tfm(struct crypto_shash *tfm)
 {
 	return &tfm->base;
Signature · 1 line
2.29.2
author maintainer
#2 lore raw

PATCH v4 2/12 crypto: add crypto_has_kpp()

In reply to Hannes Reinecke

Add helper function to determine if a given key-agreement protocol primitive is supported.

---
 crypto/kpp.c         | 6 ++++++
 include/crypto/kpp.h | 2 ++
 2 files changed, 8 insertions(+)
crypto/kpp.c +6 -0
index 313b2c699963..416e8a1a03ee 100644
@@ -87,6 +87,12 @@ struct crypto_kpp *crypto_alloc_kpp(const char *alg_name, u32 type, u32 mask)
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_kpp);
 
+int crypto_has_kpp(const char *alg_name, u32 type, u32 mask)
+{
+	return crypto_type_has_alg(alg_name, &crypto_kpp_type, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_has_kpp);
+
 static void kpp_prepare_alg(struct kpp_alg *alg)
 {
 	struct crypto_alg *base = &alg->base;
include/crypto/kpp.h +2 -0
index cccceadc164b..24d01e9877c1 100644
@@ -104,6 +104,8 @@ struct kpp_alg {
  */
 struct crypto_kpp *crypto_alloc_kpp(const char *alg_name, u32 type, u32 mask);
 
+int crypto_has_kpp(const char *alg_name, u32 type, u32 mask);
+
 static inline struct crypto_tfm *crypto_kpp_tfm(struct crypto_kpp *tfm)
 {
 	return &tfm->base;
Signature · 7 lines
2.29.2


_______________________________________________
Linux-nvme mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-nvme
author maintainer
#3 lore raw

PATCH v4 3/12 crypto/ffdhe: Finite Field DH Ephemeral Parameters

In reply to Hannes Reinecke

Add helper functions to generaten Finite Field DH Ephemeral Parameters as specified in RFC 7919.

---
 crypto/Kconfig         |   8 +
 crypto/Makefile        |   1 +
 crypto/ffdhe_helper.c  | 880 +++++++++++++++++++++++++++++++++++++++++
 include/crypto/ffdhe.h |  24 ++
 4 files changed, 913 insertions(+)
 create mode 100644 crypto/ffdhe_helper.c
 create mode 100644 include/crypto/ffdhe.h
crypto/Kconfig +8 -0
index 536df4b6b825..2178649c8128 100644
@@ -231,6 +231,14 @@ config CRYPTO_DH
 	help
 	  Generic implementation of the Diffie-Hellman algorithm.
 
+config CRYPTO_FFDHE
+	tristate "Finite Field DH (RFC 7919) ephemeral parameters"
+	select CRYPTO_DH
+	select CRYPTO_KPP
+	select CRYPTO_RNG_DEFAULT
+	help
+	  Generic implementation of the Finite Field DH algorithm
+
 config CRYPTO_ECC
 	tristate
 
crypto/Makefile +1 -0
index c633f15a0481..2b29a35f375a 100644
@@ -176,6 +176,7 @@ obj-$(CONFIG_CRYPTO_OFB) += ofb.o
 obj-$(CONFIG_CRYPTO_ECC) += ecc.o
 obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o
 obj-$(CONFIG_CRYPTO_CURVE25519) += curve25519-generic.o
+obj-$(CONFIG_CRYPTO_FFDHE) += ffdhe_helper.o
 
 ecdh_generic-y += ecdh.o
 ecdh_generic-y += ecdh_helper.o
crypto/ffdhe_helper.c new file +880 -0

880 lines not on this page · raw message

include/crypto/ffdhe.h new file +24 -0
new file mode 100644
index 000000000000..6cb9253ddb34
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Finite-Field Diffie-Hellman definition according to RFC 7919
+ *
+ * Copyright (c) 2021, SUSE Software Products
+ * Authors: Hannes Reinecke <[email protected]>
+ */
+#ifndef _CRYPTO_FFDHE_
+#define _CRYPTO_FFDHE_
+
+/**
+ * crypto_ffdhe_params() - Generate FFDHE params
+ * @params: DH params
+ * @bits: Bitsize of the FFDHE parameters
+ *
+ * This functions sets the FFDHE parameter for @bits in @params.
+ * Valid bit sizes are 2048, 3072, 4096, 6144, or 8194.
+ *
+ * Returns: 0 on success, errno on failure.
+ */
+
+int crypto_ffdhe_params(struct dh *p, int bits);
+
+#endif /* _CRYPTO_FFDHE_H */
Signature · 1 line
2.29.2
author maintainer
#4 lore raw

PATCH v4 4/12 lib/base64: RFC4648-compliant base64 encoding

In reply to Hannes Reinecke

Add RFC4648-compliant base64 encoding and decoding routines, based on the base64url encoding in fs/crypto/fname.c.

---
 include/linux/base64.h |  16 +++++++
 lib/Makefile           |   2 +-
 lib/base64.c           | 100 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 117 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/base64.h
 create mode 100644 lib/base64.c
include/linux/base64.h new file +16 -0
new file mode 100644
index 000000000000..660d4cb1ef31
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * base64 encoding, lifted from fs/crypto/fname.c.
+ */
+
+#ifndef _LINUX_BASE64_H
+#define _LINUX_BASE64_H
+
+#include <linux/types.h>
+
+#define BASE64_CHARS(nbytes)   DIV_ROUND_UP((nbytes) * 4, 3)
+
+int base64_encode(const u8 *src, int len, char *dst);
+int base64_decode(const char *src, int len, u8 *dst);
+
+#endif /* _LINUX_BASE64_H */
lib/Makefile +1 -1
index 5efd1b435a37..ce964f013412 100644
@@ -46,7 +46,7 @@ obj-y += bcd.o sort.o parser.o debug_locks.o random32.o \
 	 bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \
 	 list_sort.o uuid.o iov_iter.o clz_ctz.o \
 	 bsearch.o find_bit.o llist.o memweight.o kfifo.o \
-	 percpu-refcount.o rhashtable.o \
+	 percpu-refcount.o rhashtable.o base64.o \
 	 once.o refcount.o usercopy.o errseq.o bucket_locks.o \
 	 generic-radix-tree.o
 obj-$(CONFIG_STRING_SELFTEST) += test_string.o
lib/base64.c new file +100 -0

100 lines not on this page · raw message

Signature · 1 line
2.29.2
#5 lore raw

Re: [PATCH 04/12] lib/base64: RFC4648-compliant base64 encoding

Quoted 1 line · Hannes Reinecke

+ * Return: the length of the resulting base64url-encoded string in bytes.

base64, not base64url.

Quoted 2 lines

+ * Decodes a string using base64url encoding, i.e. the "Base 64 Encoding"
+ * specified by RFC 4648, including the '='-padding.

base64, not base64url.

- Eric

author maintainer
#6 lore raw

Re: [PATCH 04/12] lib/base64: RFC4648-compliant base64 encoding

Quoted 10 lines · Eric Biggers
Quoted 1 line · Hannes Reinecke

+ * Return: the length of the resulting base64url-encoded string in bytes.

base64, not base64url.

Quoted 2 lines

+ * Decodes a string using base64url encoding, i.e. the "Base 64 Encoding"
+ * specified by RFC 4648, including the '='-padding.

base64, not base64url.

Sheesh, you are right.

But now you know I've copied it as requested :-)

Cheers,

Hannes

Signature · 4 lines
Dr. Hannes Reinecke		           Kernel Storage Architect
[email protected]			                  +49 911 74053 688
SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
author maintainer
#7 lore raw

PATCH v4 5/12 nvme: add definitions for NVMe In-Band authentication

In reply to Hannes Reinecke

Add new definitions for NVMe In-band authentication as defined in the NVMe Base Specification v2.0.

---
 include/linux/nvme.h | 186 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 185 insertions(+), 1 deletion(-)
include/linux/nvme.h +185 -1
index b7c4c4130b65..e2142e3246eb 100644
@@ -19,6 +19,7 @@
 #define NVMF_TRSVCID_SIZE	32
 #define NVMF_TRADDR_SIZE	256
 #define NVMF_TSAS_SIZE		256
+#define NVMF_AUTH_HASH_LEN	64
 
 #define NVME_DISC_SUBSYS_NAME	"nqn.2014-08.org.nvmexpress.discovery"
 
@@ -1263,6 +1264,8 @@ enum nvmf_capsule_command {
 	nvme_fabrics_type_property_set	= 0x00,
 	nvme_fabrics_type_connect	= 0x01,
 	nvme_fabrics_type_property_get	= 0x04,
+	nvme_fabrics_type_auth_send	= 0x05,
+	nvme_fabrics_type_auth_receive	= 0x06,
 };
 
 #define nvme_fabrics_type_name(type)   { type, #type }
@@ -1270,7 +1273,9 @@ enum nvmf_capsule_command {
 	__print_symbolic(type,						\
 		nvme_fabrics_type_name(nvme_fabrics_type_property_set),	\
 		nvme_fabrics_type_name(nvme_fabrics_type_connect),	\
-		nvme_fabrics_type_name(nvme_fabrics_type_property_get))
+		nvme_fabrics_type_name(nvme_fabrics_type_property_get), \
+		nvme_fabrics_type_name(nvme_fabrics_type_auth_send),	\
+		nvme_fabrics_type_name(nvme_fabrics_type_auth_receive))
 
 /*
  * If not fabrics command, fctype will be ignored.
@@ -1393,6 +1398,183 @@ struct nvmf_property_get_command {
 	__u8		resv4[16];
 };
 
+struct nvmf_auth_send_command {
+	__u8		opcode;
+	__u8		resv1;
+	__u16		command_id;
+	__u8		fctype;
+	__u8		resv2[19];
+	union nvme_data_ptr dptr;
+	__u8		resv3;
+	__u8		spsp0;
+	__u8		spsp1;
+	__u8		secp;
+	__le32		tl;
+	__u8		resv4[16];
+};
+
+struct nvmf_auth_receive_command {
+	__u8		opcode;
+	__u8		resv1;
+	__u16		command_id;
+	__u8		fctype;
+	__u8		resv2[19];
+	union nvme_data_ptr dptr;
+	__u8		resv3;
+	__u8		spsp0;
+	__u8		spsp1;
+	__u8		secp;
+	__le32		al;
+	__u8		resv4[16];
+};
+
+/* Value for secp */
+enum {
+	NVME_AUTH_DHCHAP_PROTOCOL_IDENTIFIER	= 0xe9,
+};
+
+/* Defined value for auth_type */
+enum {
+	NVME_AUTH_COMMON_MESSAGES	= 0x00,
+	NVME_AUTH_DHCHAP_MESSAGES	= 0x01,
+};
+
+/* Defined messages for auth_id */
+enum {
+	NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE	= 0x00,
+	NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE	= 0x01,
+	NVME_AUTH_DHCHAP_MESSAGE_REPLY		= 0x02,
+	NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1	= 0x03,
+	NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2	= 0x04,
+	NVME_AUTH_DHCHAP_MESSAGE_FAILURE2	= 0xf0,
+	NVME_AUTH_DHCHAP_MESSAGE_FAILURE1	= 0xf1,
+};
+
+struct nvmf_auth_dhchap_protocol_descriptor {
+	__u8		authid;
+	__u8		rsvd;
+	__u8		halen;
+	__u8		dhlen;
+	__u8		idlist[60];
+};
+
+enum {
+	NVME_AUTH_DHCHAP_AUTH_ID	= 0x01,
+};
+
+/* Defined hash functions for DH-HMAC-CHAP authentication */
+enum {
+	NVME_AUTH_DHCHAP_SHA256	= 0x01,
+	NVME_AUTH_DHCHAP_SHA384	= 0x02,
+	NVME_AUTH_DHCHAP_SHA512	= 0x03,
+};
+
+/* Defined Diffie-Hellman group identifiers for DH-HMAC-CHAP authentication */
+enum {
+	NVME_AUTH_DHCHAP_DHGROUP_NULL	= 0x00,
+	NVME_AUTH_DHCHAP_DHGROUP_2048	= 0x01,
+	NVME_AUTH_DHCHAP_DHGROUP_3072	= 0x02,
+	NVME_AUTH_DHCHAP_DHGROUP_4096	= 0x03,
+	NVME_AUTH_DHCHAP_DHGROUP_6144	= 0x04,
+	NVME_AUTH_DHCHAP_DHGROUP_8192	= 0x05,
+};
+
+union nvmf_auth_protocol {
+	struct nvmf_auth_dhchap_protocol_descriptor dhchap;
+};
+
+struct nvmf_auth_dhchap_negotiate_data {
+	__u8		auth_type;
+	__u8		auth_id;
+	__le16		rsvd;
+	__le16		t_id;
+	__u8		sc_c;
+	__u8		napd;
+	union nvmf_auth_protocol auth_protocol[];
+};
+
+struct nvmf_auth_dhchap_challenge_data {
+	__u8		auth_type;
+	__u8		auth_id;
+	__u16		rsvd1;
+	__le16		t_id;
+	__u8		hl;
+	__u8		rsvd2;
+	__u8		hashid;
+	__u8		dhgid;
+	__le16		dhvlen;
+	__le32		seqnum;
+	/* 'hl' bytes of challenge value */
+	__u8		cval[];
+	/* followed by 'dhvlen' bytes of DH value */
+};
+
+struct nvmf_auth_dhchap_reply_data {
+	__u8		auth_type;
+	__u8		auth_id;
+	__le16		rsvd1;
+	__le16		t_id;
+	__u8		hl;
+	__u8		rsvd2;
+	__u8		cvalid;
+	__u8		rsvd3;
+	__le16		dhvlen;
+	__le32		seqnum;
+	/* 'hl' bytes of response data */
+	__u8		rval[];
+	/* followed by 'hl' bytes of Challenge value */
+	/* followed by 'dhvlen' bytes of DH value */
+};
+
+enum {
+	NVME_AUTH_DHCHAP_RESPONSE_VALID	= (1 << 0),
+};
+
+struct nvmf_auth_dhchap_success1_data {
+	__u8		auth_type;
+	__u8		auth_id;
+	__le16		rsvd1;
+	__le16		t_id;
+	__u8		hl;
+	__u8		rsvd2;
+	__u8		rvalid;
+	__u8		rsvd3[7];
+	/* 'hl' bytes of response value if 'rvalid' is set */
+	__u8		rval[];
+};
+
+struct nvmf_auth_dhchap_success2_data {
+	__u8		auth_type;
+	__u8		auth_id;
+	__le16		rsvd1;
+	__le16		t_id;
+	__u8		rsvd2[10];
+};
+
+struct nvmf_auth_dhchap_failure_data {
+	__u8		auth_type;
+	__u8		auth_id;
+	__le16		rsvd1;
+	__le16		t_id;
+	__u8		rescode;
+	__u8		rescode_exp;
+};
+
+enum {
+	NVME_AUTH_DHCHAP_FAILURE_REASON_FAILED	= 0x01,
+};
+
+enum {
+	NVME_AUTH_DHCHAP_FAILURE_FAILED			= 0x01,
+	NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE		= 0x02,
+	NVME_AUTH_DHCHAP_FAILURE_CONCAT_MISMATCH	= 0x03,
+	NVME_AUTH_DHCHAP_FAILURE_HASH_UNUSABLE		= 0x04,
+	NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE	= 0x05,
+	NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD	= 0x06,
+	NVME_AUTH_DHCHAP_FAILURE_INCORRECT_MESSAGE	= 0x07,
+};
+
+
 struct nvme_dbbuf {
 	__u8			opcode;
 	__u8			flags;
@@ -1436,6 +1618,8 @@ struct nvme_command {
 		struct nvmf_connect_command connect;
 		struct nvmf_property_set_command prop_set;
 		struct nvmf_property_get_command prop_get;
+		struct nvmf_auth_send_command auth_send;
+		struct nvmf_auth_receive_command auth_receive;
 		struct nvme_dbbuf dbbuf;
 		struct nvme_directive_cmd directive;
 	};
Signature · 1 line
2.29.2
author maintainer
#8 lore raw

PATCH v4 6/12 nvme-fabrics: decode 'authentication required' connect error

In reply to Hannes Reinecke

The 'connect' command might fail with NVME_SC_AUTH_REQUIRED, so we should be decoding this error, too.

---
 drivers/nvme/host/fabrics.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/nvme/host/fabrics.c +4 -0
index 668c6bb7a567..9a8eade7cd23 100644
@@ -332,6 +332,10 @@ static void nvmf_log_connect_error(struct nvme_ctrl *ctrl,
 		dev_err(ctrl->device,
 			"Connect command failed: host path error\n");
 		break;
+	case NVME_SC_AUTH_REQUIRED:
+		dev_err(ctrl->device,
+			"Connect command failed: authentication required\n");
+		break;
 	default:
 		dev_err(ctrl->device,
 			"Connect command failed, error wo/DNR bit: %d\n",
Signature · 7 lines
2.29.2


_______________________________________________
Linux-nvme mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-nvme
author maintainer
#9 lore raw

PATCH v4 7/12 nvme: Implement In-Band authentication

In reply to Hannes Reinecke

Implement NVMe-oF In-Band authentication according to NVMe TPAR 8006. This patch adds two new fabric options 'dhchap_secret' to specify the pre-shared key (in ASCII respresentation according to NVMe 2.0 section 8.13.5.8 'Secret representation') and 'dhchap_ctrl_secret' to specify the pre-shared controller key for bi-directional authentication of both the host and the controller.
Re-authentication can be triggered by writing the PSK into the new controller sysfs attribute 'dhchap_secret' or 'dhchap_ctrl_secret'.

---
 drivers/nvme/host/Kconfig   |   11 +
 drivers/nvme/host/Makefile  |    1 +
 drivers/nvme/host/auth.c    | 1069 +++++++++++++++++++++++++++++++++++
 drivers/nvme/host/auth.h    |   25 +
 drivers/nvme/host/core.c    |  128 ++++-
 drivers/nvme/host/fabrics.c |   81 ++-
 drivers/nvme/host/fabrics.h |    7 +
 drivers/nvme/host/nvme.h    |   33 ++
 drivers/nvme/host/trace.c   |   32 ++
 9 files changed, 1381 insertions(+), 6 deletions(-)
 create mode 100644 drivers/nvme/host/auth.c
 create mode 100644 drivers/nvme/host/auth.h
drivers/nvme/host/Kconfig +11 -0
index dc0450ca23a3..49269c581ec4 100644
@@ -83,3 +83,14 @@ config NVME_TCP
 	  from https://github.com/linux-nvme/nvme-cli.
 
 	  If unsure, say N.
+
+config NVME_AUTH
+	bool "NVM Express over Fabrics In-Band Authentication"
+	depends on NVME_CORE
+	select CRYPTO_HMAC
+	select CRYPTO_SHA256
+	select CRYPTO_SHA512
+	help
+	  This provides support for NVMe over Fabrics In-Band Authentication.
+
+	  If unsure, say N.
drivers/nvme/host/Makefile +1 -0
index dfaacd472e5d..4bae2a4a8d8c 100644
@@ -15,6 +15,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-y					+= pci.o
 
drivers/nvme/host/auth.c new file +1069 -0

1,069 lines not on this page · raw message

drivers/nvme/host/auth.h new file +25 -0
new file mode 100644
index 000000000000..cf1255f9db6d
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 Hannes Reinecke, SUSE Software Solutions
+ */
+
+#ifndef _NVME_AUTH_H
+#define _NVME_AUTH_H
+
+#include <crypto/kpp.h>
+
+const char *nvme_auth_dhgroup_name(int dhgroup_id);
+int nvme_auth_dhgroup_pubkey_size(int dhgroup_id);
+int nvme_auth_dhgroup_privkey_size(int dhgroup_id);
+const char *nvme_auth_dhgroup_kpp(int dhgroup_id);
+int nvme_auth_dhgroup_id(const char *dhgroup_name);
+
+const char *nvme_auth_hmac_name(int hmac_id);
+const char *nvme_auth_digest_name(int hmac_id);
+int nvme_auth_hmac_id(const char *hmac_name);
+
+unsigned char *nvme_auth_extract_secret(unsigned char *dhchap_secret,
+					size_t *dhchap_key_len);
+u8 *nvme_auth_transform_key(u8 *key, size_t key_len, u8 key_hash, char *nqn);
+
+#endif /* _NVME_AUTH_H */
drivers/nvme/host/core.c +125 -3

215 lines not on this page · raw message

drivers/nvme/host/fabrics.c +78 -3

136 lines not on this page · raw message

drivers/nvme/host/fabrics.h +7 -0
index a146cb903869..d1cb61e5f8d4 100644
@@ -67,6 +67,8 @@ enum {
 	NVMF_OPT_TOS		= 1 << 19,
 	NVMF_OPT_FAIL_FAST_TMO	= 1 << 20,
 	NVMF_OPT_HOST_IFACE	= 1 << 21,
+	NVMF_OPT_DHCHAP_SECRET	= 1 << 22,
+	NVMF_OPT_DHCHAP_CTRL_SECRET = 1 << 23,
 };
 
 /**
@@ -96,6 +98,9 @@ enum {
  * @max_reconnects: maximum number of allowed reconnect attempts before removing
  *              the controller, (-1) means reconnect forever, zero means remove
  *              immediately;
+ * @dhchap_secret: DH-HMAC-CHAP secret
+ * @dhchap_ctrl_secret: DH-HMAC-CHAP controller secret for bi-directional
+ *              authentication
  * @disable_sqflow: disable controller sq flow control
  * @hdr_digest: generate/verify header digest (TCP)
  * @data_digest: generate/verify data digest (TCP)
@@ -120,6 +125,8 @@ struct nvmf_ctrl_options {
 	unsigned int		kato;
 	struct nvmf_host	*host;
 	int			max_reconnects;
+	char			*dhchap_secret;
+	char			*dhchap_ctrl_secret;
 	bool			disable_sqflow;
 	bool			hdr_digest;
 	bool			data_digest;
drivers/nvme/host/nvme.h +33 -0
index 9871c0c9374c..b67fdcd6b1fb 100644
@@ -318,6 +318,17 @@ struct nvme_ctrl {
 	struct work_struct ana_work;
 #endif
 
+#ifdef CONFIG_NVME_AUTH
+	struct work_struct dhchap_auth_work;
+	struct list_head dhchap_auth_list;
+	struct mutex dhchap_auth_mutex;
+	unsigned char *dhchap_key;
+	unsigned char *dhchap_ctrl_key;
+	size_t dhchap_key_len;
+	size_t dhchap_ctrl_key_len;
+	u16 transaction;
+#endif
+
 	/* Power saving configuration */
 	u64 ps_max_latency_us;
 	bool apst_enabled;
@@ -885,6 +896,28 @@ static inline bool nvme_ctrl_sgl_supported(struct nvme_ctrl *ctrl)
 	return ctrl->sgls & ((1 << 0) | (1 << 1));
 }
 
+#ifdef CONFIG_NVME_AUTH
+void nvme_auth_init_ctrl(struct nvme_ctrl *ctrl);
+void nvme_auth_stop(struct nvme_ctrl *ctrl);
+int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid);
+int nvme_auth_wait(struct nvme_ctrl *ctrl, int qid);
+void nvme_auth_free(struct nvme_ctrl *ctrl);
+int nvme_auth_generate_key(struct nvme_ctrl *ctrl);
+int nvme_auth_generate_ctrl_key(struct nvme_ctrl *ctrl);
+#else
+static inline void nvme_auth_init_ctrl(struct nvme_ctrl *ctrl) {};
+static inline void nvme_auth_stop(struct nvme_ctrl *ctrl) {};
+static inline int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid)
+{
+	return -EPROTONOSUPPORT;
+}
+static inline int nvme_auth_wait(struct nvme_ctrl *ctrl, int qid)
+{
+	return NVME_SC_AUTH_REQUIRED;
+}
+static inline void nvme_auth_free(struct nvme_ctrl *ctrl) {};
+#endif
+
 u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
 			 u8 opcode);
 int nvme_execute_passthru_rq(struct request *rq);
drivers/nvme/host/trace.c +32 -0
index 2a89c5aa0790..1c36fcedea20 100644
@@ -287,6 +287,34 @@ static const char *nvme_trace_fabrics_property_get(struct trace_seq *p, u8 *spc)
 	return ret;
 }
 
+static const char *nvme_trace_fabrics_auth_send(struct trace_seq *p, u8 *spc)
+{
+	const char *ret = trace_seq_buffer_ptr(p);
+	u8 spsp0 = spc[1];
+	u8 spsp1 = spc[2];
+	u8 secp = spc[3];
+	u32 tl = get_unaligned_le32(spc + 4);
+
+	trace_seq_printf(p, "spsp0=%02x, spsp1=%02x, secp=%02x, tl=%u",
+			 spsp0, spsp1, secp, tl);
+	trace_seq_putc(p, 0);
+	return ret;
+}
+
+static const char *nvme_trace_fabrics_auth_receive(struct trace_seq *p, u8 *spc)
+{
+	const char *ret = trace_seq_buffer_ptr(p);
+	u8 spsp0 = spc[1];
+	u8 spsp1 = spc[2];
+	u8 secp = spc[3];
+	u32 al = get_unaligned_le32(spc + 4);
+
+	trace_seq_printf(p, "spsp0=%02x, spsp1=%02x, secp=%02x, al=%u",
+			 spsp0, spsp1, secp, al);
+	trace_seq_putc(p, 0);
+	return ret;
+}
+
 static const char *nvme_trace_fabrics_common(struct trace_seq *p, u8 *spc)
 {
 	const char *ret = trace_seq_buffer_ptr(p);
@@ -306,6 +334,10 @@ const char *nvme_trace_parse_fabrics_cmd(struct trace_seq *p,
 		return nvme_trace_fabrics_connect(p, spc);
 	case nvme_fabrics_type_property_get:
 		return nvme_trace_fabrics_property_get(p, spc);
+	case nvme_fabrics_type_auth_send:
+		return nvme_trace_fabrics_auth_send(p, spc);
+	case nvme_fabrics_type_auth_receive:
+		return nvme_trace_fabrics_auth_receive(p, spc);
 	default:
 		return nvme_trace_fabrics_common(p, spc);
 	}
Signature · 1 line
2.29.2
author maintainer
#10 lore raw

PATCH v4 8/12 nvme-auth: Diffie-Hellman key exchange support

In reply to Hannes Reinecke

Implement Diffie-Hellman key exchange using FFDHE groups for NVMe In-Band Authentication.

---
 drivers/nvme/host/Kconfig |   1 +
 drivers/nvme/host/auth.c  | 460 ++++++++++++++++++++++++++++++++++++--
 drivers/nvme/host/auth.h  |   8 +
 drivers/nvme/host/core.c  |   6 +-
 4 files changed, 457 insertions(+), 18 deletions(-)
drivers/nvme/host/Kconfig +1 -0
index 49269c581ec4..0fab5684feca 100644
@@ -90,6 +90,7 @@ config NVME_AUTH
 	select CRYPTO_HMAC
 	select CRYPTO_SHA256
 	select CRYPTO_SHA512
+	select CRYPTO_FFDHE
 	help
 	  This provides support for NVMe over Fabrics In-Band Authentication.
 
drivers/nvme/host/auth.c +446 -14

569 lines not on this page · raw message

drivers/nvme/host/auth.h +8 -0
index cf1255f9db6d..aec954e9de1e 100644
@@ -21,5 +21,13 @@ int nvme_auth_hmac_id(const char *hmac_name);
 unsigned char *nvme_auth_extract_secret(unsigned char *dhchap_secret,
 					size_t *dhchap_key_len);
 u8 *nvme_auth_transform_key(u8 *key, size_t key_len, u8 key_hash, char *nqn);
+int nvme_auth_augmented_challenge(u8 hmac_id, u8 *skey, size_t skey_len,
+				  u8 *challenge, u8 *aug, size_t hlen);
+int nvme_auth_gen_privkey(struct crypto_kpp *dh_tfm, int dh_gid);
+int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm,
+			 u8 *host_key, size_t host_key_len);
+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);
 
 #endif /* _NVME_AUTH_H */
drivers/nvme/host/core.c +2 -4
index 737b744f564e..1d103ae4afdf 100644
@@ -3508,14 +3508,13 @@ static ssize_t nvme_ctrl_dhchap_secret_store(struct device *dev,
 	if (strcmp(dhchap_secret, opts->dhchap_secret)) {
 		kfree(opts->dhchap_secret);
 		opts->dhchap_secret = dhchap_secret;
-		/* Key has changed; re-authenticate with new key */
+		/* Key has changed; re-authentication with new key */
 		nvme_auth_free(ctrl);
 		nvme_auth_generate_key(ctrl);
 	}
 	/* Start re-authentication */
 	dev_info(ctrl->device, "re-authenticating controller\n");
 	queue_work(nvme_wq, &ctrl->dhchap_auth_work);
-
 	return count;
 }
 DEVICE_ATTR(dhchap_secret, S_IRUGO | S_IWUSR,
@@ -3553,14 +3552,13 @@ static ssize_t nvme_ctrl_dhchap_ctrl_secret_store(struct device *dev,
 	if (strcmp(dhchap_secret, opts->dhchap_ctrl_secret)) {
 		kfree(opts->dhchap_ctrl_secret);
 		opts->dhchap_ctrl_secret = dhchap_secret;
-		/* Key has changed; re-authenticate with new key */
+		/* Key has changed; re-authentication with new key */
 		nvme_auth_free(ctrl);
 		nvme_auth_generate_ctrl_key(ctrl);
 	}
 	/* Start re-authentication */
 	dev_info(ctrl->device, "re-authenticating controller\n");
 	queue_work(nvme_wq, &ctrl->dhchap_auth_work);
-
 	return count;
 }
 DEVICE_ATTR(dhchap_ctrl_secret, S_IRUGO | S_IWUSR,
Signature · 1 line
2.29.2
author maintainer
#11 lore raw

PATCH v4 9/12 nvmet: Parse fabrics commands on all queues

In reply to Hannes Reinecke

Fabrics commands might be sent to all queues, not just the admin one.

---
 drivers/nvme/target/core.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/nvme/target/core.c +2 -0
index b8425fa34300..6e253c3c5e0f 100644
@@ -943,6 +943,8 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
 	if (unlikely(!req->sq->ctrl))
 		/* will return an error for any non-connect command: */
 		status = nvmet_parse_connect_cmd(req);
+	else if (nvme_is_fabrics(req->cmd))
+		status = nvmet_parse_fabrics_cmd(req);
 	else if (likely(req->sq->qid != 0))
 		status = nvmet_parse_io_cmd(req);
 	else
Signature · 7 lines
2.29.2


_______________________________________________
Linux-nvme mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-nvme
author maintainer
#12 lore raw

PATCH v4 10/12 nvmet: Implement basic In-Band Authentication

In reply to Hannes Reinecke

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 changed to switch to a different HMAC algorithm.

---
 drivers/nvme/target/Kconfig            |  11 +
 drivers/nvme/target/Makefile           |   1 +
 drivers/nvme/target/admin-cmd.c        |   4 +
 drivers/nvme/target/auth.c             | 345 ++++++++++++++++++
 drivers/nvme/target/configfs.c         | 102 +++++-
 drivers/nvme/target/core.c             |   8 +
 drivers/nvme/target/fabrics-cmd-auth.c | 466 +++++++++++++++++++++++++
 drivers/nvme/target/fabrics-cmd.c      |  30 +-
 drivers/nvme/target/nvmet.h            |  67 ++++
 9 files changed, 1031 insertions(+), 3 deletions(-)
 create mode 100644 drivers/nvme/target/auth.c
 create mode 100644 drivers/nvme/target/fabrics-cmd-auth.c
drivers/nvme/target/Kconfig +11 -0
index 973561c93888..70f3c385fc9f 100644
@@ -83,3 +83,14 @@ config NVME_TARGET_TCP
 	  devices over TCP.
 
 	  If unsure, say N.
+
+config NVME_TARGET_AUTH
+	bool "NVMe over Fabrics In-band Authentication support"
+	depends on NVME_TARGET
+	select CRYPTO_HMAC
+	select CRYPTO_SHA256
+	select CRYPTO_SHA512
+	help
+	  This enables support for NVMe over Fabrics In-band Authentication
+
+	  If unsure, say N.
drivers/nvme/target/Makefile +1 -0
index 9837e580fa7e..c66820102493 100644
@@ -13,6 +13,7 @@ nvmet-y		+= core.o configfs.o admin-cmd.o fabrics-cmd.o \
 			discovery.o io-cmd-file.o io-cmd-bdev.o
 nvmet-$(CONFIG_NVME_TARGET_PASSTHRU)	+= passthru.o
 nvmet-$(CONFIG_BLK_DEV_ZONED)		+= zns.o
+nvmet-$(CONFIG_NVME_TARGET_AUTH)	+= fabrics-cmd-auth.o auth.o
 nvme-loop-y	+= loop.o
 nvmet-rdma-y	+= rdma.o
 nvmet-fc-y	+= fc.o
drivers/nvme/target/admin-cmd.c +4 -0
index aa6d84d8848e..868d65c869cd 100644
@@ -1008,6 +1008,10 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
 
 	if (nvme_is_fabrics(cmd))
 		return nvmet_parse_fabrics_cmd(req);
+
+	if (unlikely(!nvmet_check_auth_status(req)))
+		return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR;
+
 	if (nvmet_req_subsys(req)->type == NVME_NQN_DISC)
 		return nvmet_parse_discovery_cmd(req);
 
drivers/nvme/target/auth.c new file +345 -0

345 lines not on this page · raw message

drivers/nvme/target/configfs.c +101 -1

125 lines not on this page · raw message

drivers/nvme/target/core.c +8 -0
index 6e253c3c5e0f..afe7ca1f9175 100644
@@ -793,6 +793,7 @@ void nvmet_sq_destroy(struct nvmet_sq *sq)
 	wait_for_completion(&sq->confirm_done);
 	wait_for_completion(&sq->free_done);
 	percpu_ref_exit(&sq->ref);
+	nvmet_auth_sq_free(sq);
 
 	if (ctrl) {
 		/*
@@ -1268,6 +1269,11 @@ u16 nvmet_check_ctrl_status(struct nvmet_req *req)
 		       req->cmd->common.opcode, req->sq->qid);
 		return NVME_SC_CMD_SEQ_ERROR | NVME_SC_DNR;
 	}
+
+	if (unlikely(!nvmet_check_auth_status(req))) {
+		pr_warn("qid %d not authenticated\n", req->sq->qid);
+		return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR;
+	}
 	return 0;
 }
 
@@ -1459,6 +1465,8 @@ static void nvmet_ctrl_free(struct kref *ref)
 	flush_work(&ctrl->async_event_work);
 	cancel_work_sync(&ctrl->fatal_err_work);
 
+	nvmet_destroy_auth(ctrl);
+
 	ida_simple_remove(&cntlid_ida, ctrl->cntlid);
 
 	nvmet_async_events_free(ctrl);
drivers/nvme/target/fabrics-cmd-auth.c new file +466 -0

466 lines not on this page · raw message

drivers/nvme/target/fabrics-cmd.c +28 -2
index 7d0454cee920..d5a4a9a68ee1 100644
@@ -93,6 +93,14 @@ u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req)
 	case nvme_fabrics_type_property_get:
 		req->execute = nvmet_execute_prop_get;
 		break;
+#ifdef CONFIG_NVME_TARGET_AUTH
+	case nvme_fabrics_type_auth_send:
+		req->execute = nvmet_execute_auth_send;
+		break;
+	case nvme_fabrics_type_auth_receive:
+		req->execute = nvmet_execute_auth_receive;
+		break;
+#endif
 	default:
 		pr_debug("received unknown capsule type 0x%x\n",
 			cmd->fabrics.fctype);
@@ -173,6 +181,7 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req)
 	struct nvmf_connect_data *d;
 	struct nvmet_ctrl *ctrl = NULL;
 	u16 status = 0;
+	int ret;
 
 	if (!nvmet_check_transfer_len(req, sizeof(struct nvmf_connect_data)))
 		return;
@@ -215,17 +224,31 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req)
 
 	uuid_copy(&ctrl->hostid, &d->hostid);
 
+	ret = nvmet_setup_auth(ctrl);
+	if (ret < 0) {
+		pr_err("Failed to setup authentication, error %d\n", ret);
+		nvmet_ctrl_put(ctrl);
+		if (ret == -EPERM)
+			status = (NVME_SC_CONNECT_INVALID_HOST | NVME_SC_DNR);
+		else
+			status = NVME_SC_INTERNAL;
+		goto out;
+	}
+
 	status = nvmet_install_queue(ctrl, req);
 	if (status) {
 		nvmet_ctrl_put(ctrl);
 		goto out;
 	}
 
-	pr_info("creating controller %d for subsystem %s for NQN %s%s.\n",
+	pr_info("creating controller %d for subsystem %s for NQN %s%s%s.\n",
 		ctrl->cntlid, ctrl->subsys->subsysnqn, ctrl->hostnqn,
-		ctrl->pi_support ? " T10-PI is enabled" : "");
+		ctrl->pi_support ? " T10-PI is enabled" : "",
+		nvmet_has_auth(ctrl) ? " with DH-HMAC-CHAP" : "");
 	req->cqe->result.u16 = cpu_to_le16(ctrl->cntlid);
 
+	if (nvmet_has_auth(ctrl))
+		nvmet_init_auth(ctrl, req);
 out:
 	kfree(d);
 complete:
@@ -285,6 +308,9 @@ static void nvmet_execute_io_connect(struct nvmet_req *req)
 	req->cqe->result.u16 = cpu_to_le16(ctrl->cntlid);
 
 	pr_debug("adding queue %d to ctrl %d.\n", qid, ctrl->cntlid);
+	req->cqe->result.u16 = cpu_to_le16(ctrl->cntlid);
+	if (nvmet_has_auth(ctrl))
+		nvmet_init_auth(ctrl, req);
 
 out:
 	kfree(d);
drivers/nvme/target/nvmet.h +67 -0

89 lines not on this page · raw message

Signature · 1 line
2.29.2
maintainer
#13 lore raw

Re: [PATCH 10/12] nvmet: Implement basic In-Band Authentication

Quoted 286 lines · Hannes Reinecke

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 changed to switch to a different HMAC algorithm.

---
  drivers/nvme/target/Kconfig            |  11 +
  drivers/nvme/target/Makefile           |   1 +
  drivers/nvme/target/admin-cmd.c        |   4 +
  drivers/nvme/target/auth.c             | 345 ++++++++++++++++++
  drivers/nvme/target/configfs.c         | 102 +++++-
  drivers/nvme/target/core.c             |   8 +
  drivers/nvme/target/fabrics-cmd-auth.c | 466 +++++++++++++++++++++++++
  drivers/nvme/target/fabrics-cmd.c      |  30 +-
  drivers/nvme/target/nvmet.h            |  67 ++++
  9 files changed, 1031 insertions(+), 3 deletions(-)

create mode 100644 drivers/nvme/target/auth.c create mode 100644 drivers/nvme/target/fabrics-cmd-auth.c

drivers/nvme/target/Kconfig +11 -0
index 973561c93888..70f3c385fc9f 100644
@@ -83,3 +83,14 @@ config NVME_TARGET_TCP
  	  devices over TCP.
 
  	  If unsure, say N.
+
+config NVME_TARGET_AUTH
+	bool "NVMe over Fabrics In-band Authentication support"
+	depends on NVME_TARGET
+	select CRYPTO_HMAC
+	select CRYPTO_SHA256
+	select CRYPTO_SHA512
+	help
+	  This enables support for NVMe over Fabrics In-band Authentication
+
+	  If unsure, say N.
drivers/nvme/target/Makefile +1 -0
index 9837e580fa7e..c66820102493 100644
@@ -13,6 +13,7 @@ nvmet-y		+= core.o configfs.o admin-cmd.o fabrics-cmd.o \
  			discovery.o io-cmd-file.o io-cmd-bdev.o
  nvmet-$(CONFIG_NVME_TARGET_PASSTHRU)	+= passthru.o
  nvmet-$(CONFIG_BLK_DEV_ZONED)		+= zns.o
+nvmet-$(CONFIG_NVME_TARGET_AUTH)	+= fabrics-cmd-auth.o auth.o
  nvme-loop-y	+= loop.o
  nvmet-rdma-y	+= rdma.o
  nvmet-fc-y	+= fc.o
drivers/nvme/target/admin-cmd.c +4 -0
index aa6d84d8848e..868d65c869cd 100644
@@ -1008,6 +1008,10 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
 
  	if (nvme_is_fabrics(cmd))
  		return nvmet_parse_fabrics_cmd(req);
+
+	if (unlikely(!nvmet_check_auth_status(req)))
+		return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR;
+
  	if (nvmet_req_subsys(req)->type == NVME_NQN_DISC)
  		return nvmet_parse_discovery_cmd(req);
 
drivers/nvme/target/auth.c new file +211 -0
new file mode 100644
index 000000000000..7247a7b97644
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVMe over Fabrics DH-HMAC-CHAP authentication.
+ * Copyright (c) 2020 Hannes Reinecke, SUSE Software Solutions.
+ * All rights reserved.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <crypto/hash.h>
+#include <linux/crc32.h>
+#include <linux/base64.h>
+#include <linux/ctype.h>
+#include <linux/random.h>
+#include <asm/unaligned.h>
+
+#include "nvmet.h"
+#include "../host/auth.h"
+
+int nvmet_auth_set_host_key(struct nvmet_host *host, const char *secret)
+{
+	if (sscanf(secret, "DHHC-1:%hhd:%*s", &host->dhchap_key_hash) != 1)
+		return -EINVAL;
+	if (host->dhchap_key_hash > 3) {
+		pr_warn("Invalid DH-HMAC-CHAP hash id %d\n",
+			 host->dhchap_key_hash);
+		return -EINVAL;
+	}
+	if (host->dhchap_key_hash > 0) {
+		/* Validate selected hash algorithm */
+		const char *hmac = nvme_auth_hmac_name(host->dhchap_key_hash);
+
+		if (!crypto_has_shash(hmac, 0, 0)) {
+			pr_err("DH-HMAC-CHAP hash %s unsupported\n", hmac);
+			host->dhchap_key_hash = -1;
+			return -ENOTSUPP;
+		}
+		/* Use this hash as default */
+		if (!host->dhchap_hash_id)
+			host->dhchap_hash_id = host->dhchap_key_hash;
+	}
+	host->dhchap_secret = kstrdup(secret, GFP_KERNEL);
+	if (!host->dhchap_secret)
+		return -ENOMEM;
+	/* Default to SHA256 */
+	if (!host->dhchap_hash_id)
+		host->dhchap_hash_id = NVME_AUTH_DHCHAP_SHA256;
+
+	pr_debug("Using hash %s\n",
+		 nvme_auth_hmac_name(host->dhchap_hash_id));
+	return 0;
+}
+
+int nvmet_auth_set_ctrl_key(struct nvmet_host *host, const char *secret)
+{
+	unsigned char dhchap_key_hash;
+
+	if (sscanf(secret, "DHHC-1:%hhd:%*s", &dhchap_key_hash) != 1)
+		return -EINVAL;
+	if (dhchap_key_hash > 3) {
+		pr_warn("Invalid DH-HMAC-CHAP hash id %d\n",
+			 dhchap_key_hash);
+		return -EINVAL;
+	}
+	if (dhchap_key_hash > 0) {
+		/* Validate selected hash algorithm */
+		const char *hmac = nvme_auth_hmac_name(dhchap_key_hash);
+
+		if (!crypto_has_shash(hmac, 0, 0)) {
+			pr_err("DH-HMAC-CHAP hash %s unsupported\n", hmac);
+			return -ENOTSUPP;
+		}
+	}
+	host->dhchap_ctrl_secret = kstrdup(secret, GFP_KERNEL);
+	return host->dhchap_ctrl_secret ? 0 : -ENOMEM;
+}
+
+int nvmet_setup_auth(struct nvmet_ctrl *ctrl)
+{
+	int ret = 0;
+	struct nvmet_host_link *p;
+	struct nvmet_host *host = NULL;
+	const char *hash_name;
+
+	down_read(&nvmet_config_sem);
+	if (ctrl->subsys->type == NVME_NQN_DISC)
+		goto out_unlock;
+
+	if (ctrl->subsys->allow_any_host)
+		goto out_unlock;
+
+	list_for_each_entry(p, &ctrl->subsys->hosts, entry) {
+		pr_debug("check %s\n", nvmet_host_name(p->host));
+		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 = -EPERM;
+		goto out_unlock;
+	}
+	if (!host->dhchap_secret) {
+		pr_debug("No authentication provided\n");
+		goto out_unlock;
+	}
+
+	if (ctrl->shash_tfm) {
+		if (host->dhchap_hash_id == ctrl->shash_id) {
+			pr_debug("Re-use existing hash ID %d\n",
+				 ctrl->shash_id);
+			goto out_unlock;
+		}
+		crypto_free_shash(ctrl->shash_tfm);
+		ctrl->shash_tfm = NULL;
+	}
+
+	hash_name = nvme_auth_hmac_name(host->dhchap_hash_id);
+	if (!hash_name) {
+		pr_warn("Hash ID %d invalid\n", host->dhchap_hash_id);
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+	ctrl->shash_tfm = crypto_alloc_shash(hash_name, 0,
+					     CRYPTO_ALG_ALLOCATES_MEMORY);
+	if (IS_ERR(ctrl->shash_tfm)) {
+		pr_err("failed to allocate shash %s\n", hash_name);
+		ret = PTR_ERR(ctrl->shash_tfm);
+		ctrl->shash_tfm = NULL;
+		goto out_unlock;
+	}
+	ctrl->shash_id = host->dhchap_hash_id;
+
+	/* Skip the 'DHHC-1:XX:' prefix */
+	ctrl->dhchap_key = nvme_auth_extract_secret(host->dhchap_secret + 10,
+						    &ctrl->dhchap_key_len);
+	if (IS_ERR(ctrl->dhchap_key)) {
+		ret = PTR_ERR(ctrl->dhchap_key);
+		pr_debug("failed to extract host key, error %d\n", ret);
+		ctrl->dhchap_key = NULL;
+		goto out_free_hash;
+	}
+	pr_debug("%s: using key %*ph\n", __func__,
+		 (int)ctrl->dhchap_key_len, ctrl->dhchap_key);
+
+	if (!host->dhchap_ctrl_secret)
+		goto out_unlock;
+
+	ctrl->dhchap_ctrl_key = nvme_auth_extract_secret(host->dhchap_ctrl_secret + 10,
+							 &ctrl->dhchap_ctrl_key_len);
+	if (IS_ERR(ctrl->dhchap_ctrl_key)) {
+		ret = PTR_ERR(ctrl->dhchap_ctrl_key);
+		pr_debug("failed to extract ctrl key, error %d\n", ret);
+		ctrl->dhchap_ctrl_key = NULL;
+	}
+
+out_free_hash:
+	if (ret) {
+		if (ctrl->dhchap_key) {
+			kfree_sensitive(ctrl->dhchap_key);
+			ctrl->dhchap_key = NULL;
+		}
+		crypto_free_shash(ctrl->shash_tfm);
+		ctrl->shash_tfm = NULL;
+		ctrl->shash_id = 0;
+	}
+out_unlock:
+	up_read(&nvmet_config_sem);
+
+	return ret;
+}
+
+void nvmet_auth_sq_free(struct nvmet_sq *sq)
+{
+	kfree(sq->dhchap_c1);
+	sq->dhchap_c1 = NULL;
+	kfree(sq->dhchap_c2);
+	sq->dhchap_c2 = NULL;
+	kfree(sq->dhchap_skey);
+	sq->dhchap_skey = NULL;
+}
+
+void nvmet_destroy_auth(struct nvmet_ctrl *ctrl)
+{
+	if (ctrl->shash_tfm) {
+		crypto_free_shash(ctrl->shash_tfm);
+		ctrl->shash_tfm = NULL;
+		ctrl->shash_id = 0;
+	}
+	if (ctrl->dhchap_key) {
+		kfree_sensitive(ctrl->dhchap_key);
+		ctrl->dhchap_key = NULL;
+	}
+	if (ctrl->dhchap_ctrl_key) {
+		kfree_sensitive(ctrl->dhchap_ctrl_key);
+		ctrl->dhchap_ctrl_key = NULL;
+	}
+}
+
+bool nvmet_check_auth_status(struct nvmet_req *req)
+{
+	if (req->sq->ctrl->shash_tfm &&
+	    !req->sq->authenticated)
+		return false;
+	return true;
+}
+
+int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response,

drivers/nvme/target/auth.c line 221

Quoted 10 lines
drivers/nvme/target/auth.c new file +10 -0
+			 unsigned int shash_len)
+{
+	struct nvmet_ctrl *ctrl = req->sq->ctrl;
+	SHASH_DESC_ON_STACK(shash, ctrl->shash_tfm);
+	u8 *challenge = req->sq->dhchap_c1, *host_response;
+	u8 buf[4];
+	int ret;
+
+	if (shash_len != ctrl->dhchap_key_len)
+		return -EINVAL;

Is this condition correct? the shash_len is sent by the host and afaict the host is setting it by what the controller sent in the challenge. the ctrl->dhchap_key_len is taken from nvme_auth_extract_secret.

In other words, if the nvmet host is set to use hmac(sha512) then authentication fails, regardless of the key.

I think we need a set of blktests to sanity test different hash, dh_group, secrect-length, dhchap_key and dhchap_ctrl_key combinations.

The code is not trivial to follow with the different transformations, hashes etc...

author maintainer
#14 lore raw

Re: [PATCH 10/12] nvmet: Implement basic In-Band Authentication

Quoted 298 lines · Sagi Grimberg
Quoted 295 lines · Hannes Reinecke

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 changed to switch to a different HMAC algorithm.

---
  drivers/nvme/target/Kconfig            |  11 + drivers/nvme/target/Makefile           |   1 + drivers/nvme/target/admin-cmd.c        |   4 + drivers/nvme/target/auth.c             | 345 ++++++++++++++++++ drivers/nvme/target/configfs.c         | 102 +++++- drivers/nvme/target/core.c             |   8 + drivers/nvme/target/fabrics-cmd-auth.c | 466 +++++++++++++++++++++++++ drivers/nvme/target/fabrics-cmd.c      |  30 +- drivers/nvme/target/nvmet.h            |  67 ++++

  9 files changed, 1031 insertions(+), 3 deletions(-)

  create mode 100644 drivers/nvme/target/auth.c create mode 100644 drivers/nvme/target/fabrics-cmd-auth.c

drivers/nvme/target/Kconfig +0 -0
index 973561c93888..70f3c385fc9f 100644
@@ -83,3 +83,14 @@ config NVME_TARGET_TCP

        devices over TCP.
          If unsure, say N.

drivers/nvme/target/Kconfig +11 -0
+
+config NVME_TARGET_AUTH
+    bool "NVMe over Fabrics In-band Authentication support"
+    depends on NVME_TARGET
+    select CRYPTO_HMAC
+    select CRYPTO_SHA256
+    select CRYPTO_SHA512
+    help
+      This enables support for NVMe over Fabrics In-band Authentication
+
+      If unsure, say N.
drivers/nvme/target/Makefile +0 -0
index 9837e580fa7e..c66820102493 100644
@@ -13,6 +13,7 @@ nvmet-y        += core.o configfs.o admin-cmd.o
 fabrics-cmd.o \

              discovery.o io-cmd-file.o io-cmd-bdev.o nvmet-$(CONFIG_NVME_TARGET_PASSTHRU)    += passthru.o nvmet-$(CONFIG_BLK_DEV_ZONED)        += zns.o +nvmet-$(CONFIG_NVME_TARGET_AUTH)    += fabrics-cmd-auth.o auth.o nvme-loop-y    += loop.o
  nvmet-rdma-y    += rdma.o
  nvmet-fc-y    += fc.o

drivers/nvme/target/admin-cmd.c +4 -0
index aa6d84d8848e..868d65c869cd 100644
@@ -1008,6 +1008,10 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
         if (nvme_is_fabrics(cmd))
           return nvmet_parse_fabrics_cmd(req);
+
+    if (unlikely(!nvmet_check_auth_status(req)))
+        return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR;
+
       if (nvmet_req_subsys(req)->type == NVME_NQN_DISC)
           return nvmet_parse_discovery_cmd(req);

  diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c new file mode 100644
index 000000000000..7247a7b97644

drivers/nvme/target/auth.c new file +138 -0
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVMe over Fabrics DH-HMAC-CHAP authentication.
+ * Copyright (c) 2020 Hannes Reinecke, SUSE Software Solutions.
+ * All rights reserved.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <crypto/hash.h>
+#include <linux/crc32.h>
+#include <linux/base64.h>
+#include <linux/ctype.h>
+#include <linux/random.h>
+#include <asm/unaligned.h>
+
+#include "nvmet.h"
+#include "../host/auth.h"
+
+int nvmet_auth_set_host_key(struct nvmet_host *host, const char *secret)
+{
+    if (sscanf(secret, "DHHC-1:%hhd:%*s", &host->dhchap_key_hash) != 1)
+        return -EINVAL;
+    if (host->dhchap_key_hash > 3) {
+        pr_warn("Invalid DH-HMAC-CHAP hash id %d\n",
+             host->dhchap_key_hash);
+        return -EINVAL;
+    }
+    if (host->dhchap_key_hash > 0) {
+        /* Validate selected hash algorithm */
+        const char *hmac = nvme_auth_hmac_name(host->dhchap_key_hash);
+
+        if (!crypto_has_shash(hmac, 0, 0)) {
+            pr_err("DH-HMAC-CHAP hash %s unsupported\n", hmac);
+            host->dhchap_key_hash = -1;
+            return -ENOTSUPP;
+        }
+        /* Use this hash as default */
+        if (!host->dhchap_hash_id)
+            host->dhchap_hash_id = host->dhchap_key_hash;
+    }
+    host->dhchap_secret = kstrdup(secret, GFP_KERNEL);
+    if (!host->dhchap_secret)
+        return -ENOMEM;
+    /* Default to SHA256 */
+    if (!host->dhchap_hash_id)
+        host->dhchap_hash_id = NVME_AUTH_DHCHAP_SHA256;
+
+    pr_debug("Using hash %s\n",
+         nvme_auth_hmac_name(host->dhchap_hash_id));
+    return 0;
+}
+
+int nvmet_auth_set_ctrl_key(struct nvmet_host *host, const char *secret)
+{
+    unsigned char dhchap_key_hash;
+
+    if (sscanf(secret, "DHHC-1:%hhd:%*s", &dhchap_key_hash) != 1)
+        return -EINVAL;
+    if (dhchap_key_hash > 3) {
+        pr_warn("Invalid DH-HMAC-CHAP hash id %d\n",
+             dhchap_key_hash);
+        return -EINVAL;
+    }
+    if (dhchap_key_hash > 0) {
+        /* Validate selected hash algorithm */
+        const char *hmac = nvme_auth_hmac_name(dhchap_key_hash);
+
+        if (!crypto_has_shash(hmac, 0, 0)) {
+            pr_err("DH-HMAC-CHAP hash %s unsupported\n", hmac);
+            return -ENOTSUPP;
+        }
+    }
+    host->dhchap_ctrl_secret = kstrdup(secret, GFP_KERNEL);
+    return host->dhchap_ctrl_secret ? 0 : -ENOMEM;
+}
+
+int nvmet_setup_auth(struct nvmet_ctrl *ctrl)
+{
+    int ret = 0;
+    struct nvmet_host_link *p;
+    struct nvmet_host *host = NULL;
+    const char *hash_name;
+
+    down_read(&nvmet_config_sem);
+    if (ctrl->subsys->type == NVME_NQN_DISC)
+        goto out_unlock;
+
+    if (ctrl->subsys->allow_any_host)
+        goto out_unlock;
+
+    list_for_each_entry(p, &ctrl->subsys->hosts, entry) {
+        pr_debug("check %s\n", nvmet_host_name(p->host));
+        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 = -EPERM;
+        goto out_unlock;
+    }
+    if (!host->dhchap_secret) {
+        pr_debug("No authentication provided\n");
+        goto out_unlock;
+    }
+
+    if (ctrl->shash_tfm) {
+        if (host->dhchap_hash_id == ctrl->shash_id) {
+            pr_debug("Re-use existing hash ID %d\n",
+                 ctrl->shash_id);
+            goto out_unlock;
+        }
+        crypto_free_shash(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+    }
+
+    hash_name = nvme_auth_hmac_name(host->dhchap_hash_id);
+    if (!hash_name) {
+        pr_warn("Hash ID %d invalid\n", host->dhchap_hash_id);
+        ret = -EINVAL;
+        goto out_unlock;
+    }
+    ctrl->shash_tfm = crypto_alloc_shash(hash_name, 0,
+                         CRYPTO_ALG_ALLOCATES_MEMORY);
+    if (IS_ERR(ctrl->shash_tfm)) {
+        pr_err("failed to allocate shash %s\n", hash_name);
+        ret = PTR_ERR(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+        goto out_unlock;
+    }
+    ctrl->shash_id = host->dhchap_hash_id;
+
+    /* Skip the 'DHHC-1:XX:' prefix */
+    ctrl->dhchap_key = nvme_auth_extract_secret(host->dhchap_secret +

10,
+                            &ctrl->dhchap_key_len);
+    if (IS_ERR(ctrl->dhchap_key)) {
+        ret = PTR_ERR(ctrl->dhchap_key);
+        pr_debug("failed to extract host key, error %d\n", ret); +        ctrl->dhchap_key = NULL;
+        goto out_free_hash;
+    }
+    pr_debug("%s: using key %*ph\n", __func__,
+         (int)ctrl->dhchap_key_len, ctrl->dhchap_key);

drivers/nvme/target/auth.c new file +5 -0
+
+    if (!host->dhchap_ctrl_secret)
+        goto out_unlock;
+
+    ctrl->dhchap_ctrl_key =

nvme_auth_extract_secret(host->dhchap_ctrl_secret + 10, +                             &ctrl->dhchap_ctrl_key_len); +    if (IS_ERR(ctrl->dhchap_ctrl_key)) {
+        ret = PTR_ERR(ctrl->dhchap_ctrl_key);
+        pr_debug("failed to extract ctrl key, error %d\n", ret); +        ctrl->dhchap_ctrl_key = NULL;
+    }

drivers/nvme/target/auth.c new file +60 -0
+
+out_free_hash:
+    if (ret) {
+        if (ctrl->dhchap_key) {
+            kfree_sensitive(ctrl->dhchap_key);
+            ctrl->dhchap_key = NULL;
+        }
+        crypto_free_shash(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+        ctrl->shash_id = 0;
+    }
+out_unlock:
+    up_read(&nvmet_config_sem);
+
+    return ret;
+}
+
+void nvmet_auth_sq_free(struct nvmet_sq *sq)
+{
+    kfree(sq->dhchap_c1);
+    sq->dhchap_c1 = NULL;
+    kfree(sq->dhchap_c2);
+    sq->dhchap_c2 = NULL;
+    kfree(sq->dhchap_skey);
+    sq->dhchap_skey = NULL;
+}
+
+void nvmet_destroy_auth(struct nvmet_ctrl *ctrl)
+{
+    if (ctrl->shash_tfm) {
+        crypto_free_shash(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+        ctrl->shash_id = 0;
+    }
+    if (ctrl->dhchap_key) {
+        kfree_sensitive(ctrl->dhchap_key);
+        ctrl->dhchap_key = NULL;
+    }
+    if (ctrl->dhchap_ctrl_key) {
+        kfree_sensitive(ctrl->dhchap_ctrl_key);
+        ctrl->dhchap_ctrl_key = NULL;
+    }
+}
+
+bool nvmet_check_auth_status(struct nvmet_req *req)
+{
+    if (req->sq->ctrl->shash_tfm &&
+        !req->sq->authenticated)
+        return false;
+    return true;
+}
+
+int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response,
+             unsigned int shash_len)
+{
+    struct nvmet_ctrl *ctrl = req->sq->ctrl;
+    SHASH_DESC_ON_STACK(shash, ctrl->shash_tfm);
+    u8 *challenge = req->sq->dhchap_c1, *host_response;
+    u8 buf[4];
+    int ret;
Quoted 9 lines
Quoted 3 lines

+
+    if (shash_len != ctrl->dhchap_key_len)
+        return -EINVAL;

Is this condition correct? the shash_len is sent by the host and afaict the host is setting it by what the controller sent in the challenge. the ctrl->dhchap_key_len is taken from nvme_auth_extract_secret.

Ideally, but shash_len is actually sent by the host, so it _might_ be different (as it's picked up from the command sent by the host).

Quoted 3 lines

In other words, if the nvmet host is set to use hmac(sha512) then authentication fails, regardless of the key.

Nope. The hash algorithm is figured out the 'negotiation' step, so the host _should_ have set the correct hash length. But as this is networking you should be validating each field in the received packet to ensure it matches what you expect.

Quoted 5 lines

I think we need a set of blktests to sanity test different hash, dh_group, secrect-length, dhchap_key and dhchap_ctrl_key combinations.

The code is not trivial to follow with the different transformations, hashes etc...

Most definitely. Thank god you can test it setting up a nvmet configuration using localhost 127.0.0.1, so it should be relatively easy to implement.

Oh, wait. Did I just volunteer?
Bummer.

Cheers,

Hannes

Signature · 4 lines
Dr. Hannes Reinecke		           Kernel Storage Architect
[email protected]			                  +49 911 74053 688
SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
maintainer
#15 lore raw

Re: [PATCH 10/12] nvmet: Implement basic In-Band Authentication

Quoted 311 lines · Hannes Reinecke
Quoted 298 lines · Sagi Grimberg
Quoted 295 lines · Hannes Reinecke

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 changed to switch to a different HMAC algorithm.

---
   drivers/nvme/target/Kconfig            |  11 +
   drivers/nvme/target/Makefile           |   1 +
   drivers/nvme/target/admin-cmd.c        |   4 +
   drivers/nvme/target/auth.c             | 345 ++++++++++++++++++
   drivers/nvme/target/configfs.c         | 102 +++++-
   drivers/nvme/target/core.c             |   8 +
   drivers/nvme/target/fabrics-cmd-auth.c | 466 +++++++++++++++++++++++++
   drivers/nvme/target/fabrics-cmd.c      |  30 +-
   drivers/nvme/target/nvmet.h            |  67 ++++
   9 files changed, 1031 insertions(+), 3 deletions(-)

  create mode 100644 drivers/nvme/target/auth.c create mode 100644 drivers/nvme/target/fabrics-cmd-auth.c

drivers/nvme/target/Kconfig +11 -0
index 973561c93888..70f3c385fc9f 100644
@@ -83,3 +83,14 @@ config NVME_TARGET_TCP
         devices over TCP.
           If unsure, say N.
+
+config NVME_TARGET_AUTH
+    bool "NVMe over Fabrics In-band Authentication support"
+    depends on NVME_TARGET
+    select CRYPTO_HMAC
+    select CRYPTO_SHA256
+    select CRYPTO_SHA512
+    help
+      This enables support for NVMe over Fabrics In-band Authentication
+
+      If unsure, say N.
drivers/nvme/target/Makefile +1 -0
index 9837e580fa7e..c66820102493 100644
@@ -13,6 +13,7 @@ nvmet-y        += core.o configfs.o admin-cmd.o
 fabrics-cmd.o \
               discovery.o io-cmd-file.o io-cmd-bdev.o
   nvmet-$(CONFIG_NVME_TARGET_PASSTHRU)    += passthru.o
   nvmet-$(CONFIG_BLK_DEV_ZONED)        += zns.o
+nvmet-$(CONFIG_NVME_TARGET_AUTH)    += fabrics-cmd-auth.o auth.o
   nvme-loop-y    += loop.o
   nvmet-rdma-y    += rdma.o

  nvmet-fc-y    += fc.o

drivers/nvme/target/admin-cmd.c +4 -0
index aa6d84d8848e..868d65c869cd 100644
@@ -1008,6 +1008,10 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
         if (nvme_is_fabrics(cmd))
           return nvmet_parse_fabrics_cmd(req);
+
+    if (unlikely(!nvmet_check_auth_status(req)))
+        return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR;
+
       if (nvmet_req_subsys(req)->type == NVME_NQN_DISC)
           return nvmet_parse_discovery_cmd(req);
   diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c

new file mode 100644
index 000000000000..7247a7b97644

drivers/nvme/target/auth.c new file +138 -0
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVMe over Fabrics DH-HMAC-CHAP authentication.
+ * Copyright (c) 2020 Hannes Reinecke, SUSE Software Solutions.
+ * All rights reserved.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <crypto/hash.h>
+#include <linux/crc32.h>
+#include <linux/base64.h>
+#include <linux/ctype.h>
+#include <linux/random.h>
+#include <asm/unaligned.h>
+
+#include "nvmet.h"
+#include "../host/auth.h"
+
+int nvmet_auth_set_host_key(struct nvmet_host *host, const char *secret)
+{
+    if (sscanf(secret, "DHHC-1:%hhd:%*s", &host->dhchap_key_hash) != 1)
+        return -EINVAL;
+    if (host->dhchap_key_hash > 3) {
+        pr_warn("Invalid DH-HMAC-CHAP hash id %d\n",
+             host->dhchap_key_hash);
+        return -EINVAL;
+    }
+    if (host->dhchap_key_hash > 0) {
+        /* Validate selected hash algorithm */
+        const char *hmac = nvme_auth_hmac_name(host->dhchap_key_hash);
+
+        if (!crypto_has_shash(hmac, 0, 0)) {
+            pr_err("DH-HMAC-CHAP hash %s unsupported\n", hmac);
+            host->dhchap_key_hash = -1;
+            return -ENOTSUPP;
+        }
+        /* Use this hash as default */
+        if (!host->dhchap_hash_id)
+            host->dhchap_hash_id = host->dhchap_key_hash;
+    }
+    host->dhchap_secret = kstrdup(secret, GFP_KERNEL);
+    if (!host->dhchap_secret)
+        return -ENOMEM;
+    /* Default to SHA256 */
+    if (!host->dhchap_hash_id)
+        host->dhchap_hash_id = NVME_AUTH_DHCHAP_SHA256;
+
+    pr_debug("Using hash %s\n",
+         nvme_auth_hmac_name(host->dhchap_hash_id));
+    return 0;
+}
+
+int nvmet_auth_set_ctrl_key(struct nvmet_host *host, const char *secret)
+{
+    unsigned char dhchap_key_hash;
+
+    if (sscanf(secret, "DHHC-1:%hhd:%*s", &dhchap_key_hash) != 1)
+        return -EINVAL;
+    if (dhchap_key_hash > 3) {
+        pr_warn("Invalid DH-HMAC-CHAP hash id %d\n",
+             dhchap_key_hash);
+        return -EINVAL;
+    }
+    if (dhchap_key_hash > 0) {
+        /* Validate selected hash algorithm */
+        const char *hmac = nvme_auth_hmac_name(dhchap_key_hash);
+
+        if (!crypto_has_shash(hmac, 0, 0)) {
+            pr_err("DH-HMAC-CHAP hash %s unsupported\n", hmac);
+            return -ENOTSUPP;
+        }
+    }
+    host->dhchap_ctrl_secret = kstrdup(secret, GFP_KERNEL);
+    return host->dhchap_ctrl_secret ? 0 : -ENOMEM;
+}
+
+int nvmet_setup_auth(struct nvmet_ctrl *ctrl)
+{
+    int ret = 0;
+    struct nvmet_host_link *p;
+    struct nvmet_host *host = NULL;
+    const char *hash_name;
+
+    down_read(&nvmet_config_sem);
+    if (ctrl->subsys->type == NVME_NQN_DISC)
+        goto out_unlock;
+
+    if (ctrl->subsys->allow_any_host)
+        goto out_unlock;
+
+    list_for_each_entry(p, &ctrl->subsys->hosts, entry) {
+        pr_debug("check %s\n", nvmet_host_name(p->host));
+        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 = -EPERM;
+        goto out_unlock;
+    }
+    if (!host->dhchap_secret) {
+        pr_debug("No authentication provided\n");
+        goto out_unlock;
+    }
+
+    if (ctrl->shash_tfm) {
+        if (host->dhchap_hash_id == ctrl->shash_id) {
+            pr_debug("Re-use existing hash ID %d\n",
+                 ctrl->shash_id);
+            goto out_unlock;
+        }
+        crypto_free_shash(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+    }
+
+    hash_name = nvme_auth_hmac_name(host->dhchap_hash_id);
+    if (!hash_name) {
+        pr_warn("Hash ID %d invalid\n", host->dhchap_hash_id);
+        ret = -EINVAL;
+        goto out_unlock;
+    }
+    ctrl->shash_tfm = crypto_alloc_shash(hash_name, 0,
+                         CRYPTO_ALG_ALLOCATES_MEMORY);
+    if (IS_ERR(ctrl->shash_tfm)) {
+        pr_err("failed to allocate shash %s\n", hash_name);
+        ret = PTR_ERR(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+        goto out_unlock;
+    }
+    ctrl->shash_id = host->dhchap_hash_id;
+
+    /* Skip the 'DHHC-1:XX:' prefix */
+    ctrl->dhchap_key = nvme_auth_extract_secret(host->dhchap_secret +

10,
+                            &ctrl->dhchap_key_len);
+    if (IS_ERR(ctrl->dhchap_key)) {
+        ret = PTR_ERR(ctrl->dhchap_key);
+        pr_debug("failed to extract host key, error %d\n", ret); +        ctrl->dhchap_key = NULL;
+        goto out_free_hash;
+    }
+    pr_debug("%s: using key %*ph\n", __func__,
+         (int)ctrl->dhchap_key_len, ctrl->dhchap_key);

drivers/nvme/target/auth.c new file +5 -0
+
+    if (!host->dhchap_ctrl_secret)
+        goto out_unlock;
+
+    ctrl->dhchap_ctrl_key =

nvme_auth_extract_secret(host->dhchap_ctrl_secret + 10, +                             &ctrl->dhchap_ctrl_key_len); +    if (IS_ERR(ctrl->dhchap_ctrl_key)) {
+        ret = PTR_ERR(ctrl->dhchap_ctrl_key);
+        pr_debug("failed to extract ctrl key, error %d\n", ret); +        ctrl->dhchap_ctrl_key = NULL;
+    }

drivers/nvme/target/auth.c new file +60 -0
+
+out_free_hash:
+    if (ret) {
+        if (ctrl->dhchap_key) {
+            kfree_sensitive(ctrl->dhchap_key);
+            ctrl->dhchap_key = NULL;
+        }
+        crypto_free_shash(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+        ctrl->shash_id = 0;
+    }
+out_unlock:
+    up_read(&nvmet_config_sem);
+
+    return ret;
+}
+
+void nvmet_auth_sq_free(struct nvmet_sq *sq)
+{
+    kfree(sq->dhchap_c1);
+    sq->dhchap_c1 = NULL;
+    kfree(sq->dhchap_c2);
+    sq->dhchap_c2 = NULL;
+    kfree(sq->dhchap_skey);
+    sq->dhchap_skey = NULL;
+}
+
+void nvmet_destroy_auth(struct nvmet_ctrl *ctrl)
+{
+    if (ctrl->shash_tfm) {
+        crypto_free_shash(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+        ctrl->shash_id = 0;
+    }
+    if (ctrl->dhchap_key) {
+        kfree_sensitive(ctrl->dhchap_key);
+        ctrl->dhchap_key = NULL;
+    }
+    if (ctrl->dhchap_ctrl_key) {
+        kfree_sensitive(ctrl->dhchap_ctrl_key);
+        ctrl->dhchap_ctrl_key = NULL;
+    }
+}
+
+bool nvmet_check_auth_status(struct nvmet_req *req)
+{
+    if (req->sq->ctrl->shash_tfm &&
+        !req->sq->authenticated)
+        return false;
+    return true;
+}
+
+int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response,
+             unsigned int shash_len)
+{
+    struct nvmet_ctrl *ctrl = req->sq->ctrl;
+    SHASH_DESC_ON_STACK(shash, ctrl->shash_tfm);
+    u8 *challenge = req->sq->dhchap_c1, *host_response;
+    u8 buf[4];
+    int ret;
Quoted 9 lines
Quoted 3 lines

+
+    if (shash_len != ctrl->dhchap_key_len)
+        return -EINVAL;

Is this condition correct? the shash_len is sent by the host and afaict the host is setting it by what the controller sent in the challenge. the ctrl->dhchap_key_len is taken from nvme_auth_extract_secret.

Ideally, but shash_len is actually sent by the host, so it _might_ be different (as it's picked up from the command sent by the host).

Quoted 7 lines
Quoted 3 lines

In other words, if the nvmet host is set to use hmac(sha512) then authentication fails, regardless of the key.

Nope. The hash algorithm is figured out the 'negotiation' step, so the host _should_ have set the correct hash length. But as this is networking you should be validating each field in the received packet to ensure it matches what you expect.

On the target:

# grep -r '' /sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress\:uuid\:b73ff014-2723-4114-aa8d-2f784ecba4f4/
/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_dhgroup:null
/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_hash:hmac(sha512)
/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_ctrl_key:
/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_key:DHHC-1:03:KUwVlIUo627Pn05W/lRL2XD57kzIs1yZzJWdd2vgZJUC74kr:

On the host:

# ./nvme connect-all --dhchap-secret="DHHC-1:03:KUwVlIUo627Pn05W/lRL2XD57kzIs1yZzJWdd2vgZJUC74kr:"
failed to connect controller, error 5

On the target dmesg:

[ 8695.716117] nvmet: creating controller 1 for subsystem nqn.2014-08.org.nvmexpress.discovery for NQN nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4.
[ 8695.749996] nvmet: creating controller 2 for subsystem testnqn1 for NQN nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4 with DH-HMAC-CHAP.
[ 8695.755361] nvmet: ctrl 2 qid 0 failure1 (1)
[ 8695.755449] nvmet: ctrl 2 fatal error occurred!

On the host dmesg:

[ 8781.616712] nvme nvme1: new ctrl: NQN "nqn.2014-08.org.nvmexpress.discovery", addr 192.168.123.1:8009
[ 8781.637954] nvme nvme2: qid 0: authentication failed
[ 8781.638084] nvme nvme2: failed to connect queue: 0 ret=401

If I change the dhchap_hash to hmac(sha256) authentication succeeds. The failure with hmac(sha512) comes from the above condition as the host is sending key length 64 and nvmet is expecting 32.

author maintainer
#16 lore raw

Re: [PATCH 10/12] nvmet: Implement basic In-Band Authentication

Quoted 361 lines · Sagi Grimberg
Quoted 320 lines · Hannes Reinecke
Quoted 307 lines · Sagi Grimberg
Quoted 304 lines · Hannes Reinecke

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 changed to switch to
a different HMAC algorithm.

---
   drivers/nvme/target/Kconfig            |  11 + drivers/nvme/target/Makefile           |   1 + drivers/nvme/target/admin-cmd.c        |   4 + drivers/nvme/target/auth.c             | 345 ++++++++++++++++++ drivers/nvme/target/configfs.c         | 102 +++++- drivers/nvme/target/core.c             |   8 + drivers/nvme/target/fabrics-cmd-auth.c | 466
+++++++++++++++++++++++++
   drivers/nvme/target/fabrics-cmd.c      |  30 +- drivers/nvme/target/nvmet.h            |  67 ++++

   9 files changed, 1031 insertions(+), 3 deletions(-)

   create mode 100644 drivers/nvme/target/auth.c create mode 100644 drivers/nvme/target/fabrics-cmd-auth.c

drivers/nvme/target/Kconfig +0 -0
index 973561c93888..70f3c385fc9f 100644
@@ -83,3 +83,14 @@ config NVME_TARGET_TCP

         devices over TCP.
           If unsure, say N.

drivers/nvme/target/Kconfig +9 -0
+
+config NVME_TARGET_AUTH
+    bool "NVMe over Fabrics In-band Authentication support"
+    depends on NVME_TARGET
+    select CRYPTO_HMAC
+    select CRYPTO_SHA256
+    select CRYPTO_SHA512
+    help
+      This enables support for NVMe over Fabrics In-band

Authentication

drivers/nvme/target/Kconfig +2 -0
+
+      If unsure, say N.
drivers/nvme/target/Makefile +0 -0
index 9837e580fa7e..c66820102493 100644
@@ -13,6 +13,7 @@ nvmet-y        += core.o configfs.o admin-cmd.o
 fabrics-cmd.o \

               discovery.o io-cmd-file.o io-cmd-bdev.o nvmet-$(CONFIG_NVME_TARGET_PASSTHRU)    += passthru.o nvmet-$(CONFIG_BLK_DEV_ZONED)        += zns.o +nvmet-$(CONFIG_NVME_TARGET_AUTH)    += fabrics-cmd-auth.o auth.o nvme-loop-y    += loop.o
   nvmet-rdma-y    += rdma.o
   nvmet-fc-y    += fc.o

drivers/nvme/target/admin-cmd.c +4 -0
index aa6d84d8848e..868d65c869cd 100644
@@ -1008,6 +1008,10 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
          if (nvme_is_fabrics(cmd))
            return nvmet_parse_fabrics_cmd(req);
+
+    if (unlikely(!nvmet_check_auth_status(req)))
+        return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR;
+
        if (nvmet_req_subsys(req)->type == NVME_NQN_DISC)
            return nvmet_parse_discovery_cmd(req);

   diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c new file mode 100644
index 000000000000..7247a7b97644

drivers/nvme/target/auth.c new file +22 -0
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVMe over Fabrics DH-HMAC-CHAP authentication.
+ * Copyright (c) 2020 Hannes Reinecke, SUSE Software Solutions.
+ * All rights reserved.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <crypto/hash.h>
+#include <linux/crc32.h>
+#include <linux/base64.h>
+#include <linux/ctype.h>
+#include <linux/random.h>
+#include <asm/unaligned.h>
+
+#include "nvmet.h"
+#include "../host/auth.h"
+
+int nvmet_auth_set_host_key(struct nvmet_host *host, const char

*secret)
+{
+    if (sscanf(secret, "DHHC-1:%hhd:%*s", &host->dhchap_key_hash) != 1)
+        return -EINVAL;
+    if (host->dhchap_key_hash > 3) {
+        pr_warn("Invalid DH-HMAC-CHAP hash id %d\n",
+             host->dhchap_key_hash);
+        return -EINVAL;
+    }
+    if (host->dhchap_key_hash > 0) {
+        /* Validate selected hash algorithm */
+        const char *hmac = nvme_auth_hmac_name(host->dhchap_key_hash);

drivers/nvme/target/auth.c new file +23 -0
+
+        if (!crypto_has_shash(hmac, 0, 0)) {
+            pr_err("DH-HMAC-CHAP hash %s unsupported\n", hmac);
+            host->dhchap_key_hash = -1;
+            return -ENOTSUPP;
+        }
+        /* Use this hash as default */
+        if (!host->dhchap_hash_id)
+            host->dhchap_hash_id = host->dhchap_key_hash;
+    }
+    host->dhchap_secret = kstrdup(secret, GFP_KERNEL);
+    if (!host->dhchap_secret)
+        return -ENOMEM;
+    /* Default to SHA256 */
+    if (!host->dhchap_hash_id)
+        host->dhchap_hash_id = NVME_AUTH_DHCHAP_SHA256;
+
+    pr_debug("Using hash %s\n",
+         nvme_auth_hmac_name(host->dhchap_hash_id));
+    return 0;
+}
+
+int nvmet_auth_set_ctrl_key(struct nvmet_host *host, const char

*secret)

drivers/nvme/target/auth.c new file +82 -0
+{
+    unsigned char dhchap_key_hash;
+
+    if (sscanf(secret, "DHHC-1:%hhd:%*s", &dhchap_key_hash) != 1)
+        return -EINVAL;
+    if (dhchap_key_hash > 3) {
+        pr_warn("Invalid DH-HMAC-CHAP hash id %d\n",
+             dhchap_key_hash);
+        return -EINVAL;
+    }
+    if (dhchap_key_hash > 0) {
+        /* Validate selected hash algorithm */
+        const char *hmac = nvme_auth_hmac_name(dhchap_key_hash);
+
+        if (!crypto_has_shash(hmac, 0, 0)) {
+            pr_err("DH-HMAC-CHAP hash %s unsupported\n", hmac);
+            return -ENOTSUPP;
+        }
+    }
+    host->dhchap_ctrl_secret = kstrdup(secret, GFP_KERNEL);
+    return host->dhchap_ctrl_secret ? 0 : -ENOMEM;
+}
+
+int nvmet_setup_auth(struct nvmet_ctrl *ctrl)
+{
+    int ret = 0;
+    struct nvmet_host_link *p;
+    struct nvmet_host *host = NULL;
+    const char *hash_name;
+
+    down_read(&nvmet_config_sem);
+    if (ctrl->subsys->type == NVME_NQN_DISC)
+        goto out_unlock;
+
+    if (ctrl->subsys->allow_any_host)
+        goto out_unlock;
+
+    list_for_each_entry(p, &ctrl->subsys->hosts, entry) {
+        pr_debug("check %s\n", nvmet_host_name(p->host));
+        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 = -EPERM;
+        goto out_unlock;
+    }
+    if (!host->dhchap_secret) {
+        pr_debug("No authentication provided\n");
+        goto out_unlock;
+    }
+
+    if (ctrl->shash_tfm) {
+        if (host->dhchap_hash_id == ctrl->shash_id) {
+            pr_debug("Re-use existing hash ID %d\n",
+                 ctrl->shash_id);
+            goto out_unlock;
+        }
+        crypto_free_shash(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+    }
+
+    hash_name = nvme_auth_hmac_name(host->dhchap_hash_id);
+    if (!hash_name) {
+        pr_warn("Hash ID %d invalid\n", host->dhchap_hash_id);
+        ret = -EINVAL;
+        goto out_unlock;
+    }
+    ctrl->shash_tfm = crypto_alloc_shash(hash_name, 0,
+                         CRYPTO_ALG_ALLOCATES_MEMORY);
+    if (IS_ERR(ctrl->shash_tfm)) {
+        pr_err("failed to allocate shash %s\n", hash_name);
+        ret = PTR_ERR(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+        goto out_unlock;
+    }
+    ctrl->shash_id = host->dhchap_hash_id;
+
+    /* Skip the 'DHHC-1:XX:' prefix */
+    ctrl->dhchap_key = nvme_auth_extract_secret(host->dhchap_secret +

10,
+                            &ctrl->dhchap_key_len);
+    if (IS_ERR(ctrl->dhchap_key)) {
+        ret = PTR_ERR(ctrl->dhchap_key);
+        pr_debug("failed to extract host key, error %d\n", ret); +        ctrl->dhchap_key = NULL;
+        goto out_free_hash;
+    }
+    pr_debug("%s: using key %*ph\n", __func__,
+         (int)ctrl->dhchap_key_len, ctrl->dhchap_key);

drivers/nvme/target/auth.c new file +5 -0
+
+    if (!host->dhchap_ctrl_secret)
+        goto out_unlock;
+
+    ctrl->dhchap_ctrl_key =

nvme_auth_extract_secret(host->dhchap_ctrl_secret + 10, +                             &ctrl->dhchap_ctrl_key_len); +    if (IS_ERR(ctrl->dhchap_ctrl_key)) {
+        ret = PTR_ERR(ctrl->dhchap_ctrl_key);
+        pr_debug("failed to extract ctrl key, error %d\n", ret); +        ctrl->dhchap_ctrl_key = NULL;
+    }

drivers/nvme/target/auth.c new file +60 -0
+
+out_free_hash:
+    if (ret) {
+        if (ctrl->dhchap_key) {
+            kfree_sensitive(ctrl->dhchap_key);
+            ctrl->dhchap_key = NULL;
+        }
+        crypto_free_shash(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+        ctrl->shash_id = 0;
+    }
+out_unlock:
+    up_read(&nvmet_config_sem);
+
+    return ret;
+}
+
+void nvmet_auth_sq_free(struct nvmet_sq *sq)
+{
+    kfree(sq->dhchap_c1);
+    sq->dhchap_c1 = NULL;
+    kfree(sq->dhchap_c2);
+    sq->dhchap_c2 = NULL;
+    kfree(sq->dhchap_skey);
+    sq->dhchap_skey = NULL;
+}
+
+void nvmet_destroy_auth(struct nvmet_ctrl *ctrl)
+{
+    if (ctrl->shash_tfm) {
+        crypto_free_shash(ctrl->shash_tfm);
+        ctrl->shash_tfm = NULL;
+        ctrl->shash_id = 0;
+    }
+    if (ctrl->dhchap_key) {
+        kfree_sensitive(ctrl->dhchap_key);
+        ctrl->dhchap_key = NULL;
+    }
+    if (ctrl->dhchap_ctrl_key) {
+        kfree_sensitive(ctrl->dhchap_ctrl_key);
+        ctrl->dhchap_ctrl_key = NULL;
+    }
+}
+
+bool nvmet_check_auth_status(struct nvmet_req *req)
+{
+    if (req->sq->ctrl->shash_tfm &&
+        !req->sq->authenticated)
+        return false;
+    return true;
+}
+
+int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response,
+             unsigned int shash_len)
+{
+    struct nvmet_ctrl *ctrl = req->sq->ctrl;
+    SHASH_DESC_ON_STACK(shash, ctrl->shash_tfm);
+    u8 *challenge = req->sq->dhchap_c1, *host_response;
+    u8 buf[4];
+    int ret;
Quoted 9 lines
Quoted 3 lines

+
+    if (shash_len != ctrl->dhchap_key_len)
+        return -EINVAL;

Is this condition correct? the shash_len is sent by the host and afaict the host is setting it by what the controller sent in the challenge. the ctrl->dhchap_key_len is taken from nvme_auth_extract_secret.

Ideally, but shash_len is actually sent by the host, so it _might_ be different (as it's picked up from the command sent by the host).

Quoted 7 lines
Quoted 3 lines

In other words, if the nvmet host is set to use hmac(sha512) then authentication fails, regardless of the key.

Nope. The hash algorithm is figured out the 'negotiation' step, so the host _should_ have set the correct hash length. But as this is networking you should be validating each field in the received packet to ensure it matches what you expect.

On the target:

# grep -r ''
/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress\:uuid\:b73ff014-2723-4114-aa8d-2f784ecba4f4/

/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_dhgroup:null

/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_hash:hmac(sha512)

/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_ctrl_key:

/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_key:DHHC-1:03:KUwVlIUo627Pn05W/lRL2XD57kzIs1yZzJWdd2vgZJUC74kr:

On the host:

# ./nvme connect-all
--dhchap-secret="DHHC-1:03:KUwVlIUo627Pn05W/lRL2XD57kzIs1yZzJWdd2vgZJUC74kr:"

failed to connect controller, error 5

On the target dmesg:

[ 8695.716117] nvmet: creating controller 1 for subsystem
nqn.2014-08.org.nvmexpress.discovery for NQN
nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4.
[ 8695.749996] nvmet: creating controller 2 for subsystem testnqn1 for
NQN nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4
with DH-HMAC-CHAP.
[ 8695.755361] nvmet: ctrl 2 qid 0 failure1 (1)
[ 8695.755449] nvmet: ctrl 2 fatal error occurred!

On the host dmesg:

Quoted 8 lines
[ 8781.616712] nvme nvme1: new ctrl: NQN
"nqn.2014-08.org.nvmexpress.discovery", addr 192.168.123.1:8009
[ 8781.637954] nvme nvme2: qid 0: authentication failed
[ 8781.638084] nvme nvme2: failed to connect queue: 0 ret=401

If I change the dhchap_hash to hmac(sha256) authentication succeeds. The failure with hmac(sha512) comes from the above condition as the host is sending key length 64 and nvmet is expecting 32.

A-ha. That shouldn't have happened; selecting the hash on the target was _supposed_ to be reflected to the host.

You did mention something about blocktests; guess I'll need to bite the bullet and actually implement something there.

Cheers,

Hannes

Signature · 4 lines
Dr. Hannes Reinecke		           Kernel Storage Architect
[email protected]			                  +49 911 74053 688
SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
maintainer
#17 lore raw

Re: [PATCH 10/12] nvmet: Implement basic In-Band Authentication

Quoted 40 lines
Quoted 31 lines

On the target:

# grep -r ''
/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress\:uuid\:b73ff014-2723-4114-aa8d-2f784ecba4f4/

/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_dhgroup:null

/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_hash:hmac(sha512)

/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_ctrl_key:

/sys/kernel/config/nvmet/hosts/nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4/dhchap_key:DHHC-1:03:KUwVlIUo627Pn05W/lRL2XD57kzIs1yZzJWdd2vgZJUC74kr:

On the host:

# ./nvme connect-all
--dhchap-secret="DHHC-1:03:KUwVlIUo627Pn05W/lRL2XD57kzIs1yZzJWdd2vgZJUC74kr:"

failed to connect controller, error 5

On the target dmesg:

[ 8695.716117] nvmet: creating controller 1 for subsystem
nqn.2014-08.org.nvmexpress.discovery for NQN
nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4.
[ 8695.749996] nvmet: creating controller 2 for subsystem testnqn1 for
NQN nqn.2014-08.org.nvmexpress:uuid:b73ff014-2723-4114-aa8d-2f784ecba4f4
with DH-HMAC-CHAP.
[ 8695.755361] nvmet: ctrl 2 qid 0 failure1 (1)
[ 8695.755449] nvmet: ctrl 2 fatal error occurred!

On the host dmesg:

Quoted 8 lines
[ 8781.616712] nvme nvme1: new ctrl: NQN
"nqn.2014-08.org.nvmexpress.discovery", addr 192.168.123.1:8009
[ 8781.637954] nvme nvme2: qid 0: authentication failed
[ 8781.638084] nvme nvme2: failed to connect queue: 0 ret=401

If I change the dhchap_hash to hmac(sha256) authentication succeeds. The failure with hmac(sha512) comes from the above condition as the host is sending key length 64 and nvmet is expecting 32.

Quoted 5 lines

A-ha. That shouldn't have happened; selecting the hash on the target was _supposed_ to be reflected to the host.

You did mention something about blocktests; guess I'll need to bite the bullet and actually implement something there.

That is why I mentioned it ;)

author maintainer
#18 lore raw

PATCH v4 11/12 nvmet-auth: Diffie-Hellman key exchange support

In reply to Hannes Reinecke

Implement Diffie-Hellman key exchange using FFDHE groups for NVMe In-Band Authentication.
This patch adds a new host configfs attribute 'dhchap_dhgroup' to select the FFDHE group to use.

---
 drivers/nvme/target/Kconfig            |   1 +
 drivers/nvme/target/auth.c             | 148 ++++++++++++++++++++++++-
 drivers/nvme/target/configfs.c         |  31 ++++++
 drivers/nvme/target/fabrics-cmd-auth.c |  31 +++++-
 drivers/nvme/target/nvmet.h            |   6 +
 5 files changed, 209 insertions(+), 8 deletions(-)
drivers/nvme/target/Kconfig +1 -0
index 70f3c385fc9f..2e41d70fd881 100644
@@ -90,6 +90,7 @@ config NVME_TARGET_AUTH
 	select CRYPTO_HMAC
 	select CRYPTO_SHA256
 	select CRYPTO_SHA512
+	select CRYPTO_FFDHE
 	help
 	  This enables support for NVMe over Fabrics In-band Authentication
 
drivers/nvme/target/auth.c +144 -4

175 lines not on this page · raw message

drivers/nvme/target/configfs.c +31 -0
index d1f749ecbe4a..0414ff7f4873 100644
@@ -1743,10 +1743,41 @@ static ssize_t nvmet_host_dhchap_hash_store(struct config_item *item,
 
 CONFIGFS_ATTR(nvmet_host_, dhchap_hash);
 
+static ssize_t nvmet_host_dhchap_dhgroup_show(struct config_item *item,
+		char *page)
+{
+	struct nvmet_host *host = to_host(item);
+	const char *dhgroup = nvme_auth_dhgroup_name(host->dhchap_dhgroup_id);
+
+	return sprintf(page, "%s\n", dhgroup ? dhgroup : "none");
+}
+
+static ssize_t nvmet_host_dhchap_dhgroup_store(struct config_item *item,
+		const char *page, size_t count)
+{
+	struct nvmet_host *host = to_host(item);
+	int dhgroup_id;
+
+	dhgroup_id = nvme_auth_dhgroup_id(page);
+	if (dhgroup_id < 0)
+		return -EINVAL;
+	if (dhgroup_id != NVME_AUTH_DHCHAP_DHGROUP_NULL) {
+		const char *kpp = nvme_auth_dhgroup_kpp(dhgroup_id);
+
+		if (!crypto_has_kpp(kpp, 0, 0))
+			return -EINVAL;
+	}
+	host->dhchap_dhgroup_id = dhgroup_id;
+	return count;
+}
+
+CONFIGFS_ATTR(nvmet_host_, dhchap_dhgroup);
+
 static struct configfs_attribute *nvmet_host_attrs[] = {
 	&nvmet_host_attr_dhchap_key,
 	&nvmet_host_attr_dhchap_ctrl_key,
 	&nvmet_host_attr_dhchap_hash,
+	&nvmet_host_attr_dhchap_dhgroup,
 	NULL,
 };
 #endif /* CONFIG_NVME_TARGET_AUTH */
drivers/nvme/target/fabrics-cmd-auth.c +27 -4
index 10ab646e85e5..a11de590a5a4 100644
@@ -64,13 +64,24 @@ static u16 nvmet_auth_negotiate(struct nvmet_req *req, void *d)
 			null_dh = dhgid;
 			continue;
 		}
+		if (ctrl->dh_tfm && ctrl->dh_gid == dhgid) {
+			pr_debug("%s: ctrl %d qid %d: reusing existing DH group %d\n",
+				 __func__, ctrl->cntlid, req->sq->qid, dhgid);
+			break;
+		}
+		if (nvmet_setup_dhgroup(ctrl, dhgid) < 0)
+			continue;
+		if (nvme_auth_gen_privkey(ctrl->dh_tfm, dhgid) == 0)
+			break;
+		crypto_free_kpp(ctrl->dh_tfm);
+		ctrl->dh_tfm = NULL;
+		ctrl->dh_gid = 0;
 	}
-	if (null_dh < 0) {
+	if (!ctrl->dh_tfm && null_dh < 0) {
 		pr_debug("%s: ctrl %d qid %d: no DH group selected\n",
 			 __func__, ctrl->cntlid, req->sq->qid);
 		return NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE;
 	}
-	ctrl->dh_gid = null_dh;
 	pr_debug("%s: ctrl %d qid %d: DH group %s (%d)\n",
 		 __func__, ctrl->cntlid, req->sq->qid,
 		 nvme_auth_dhgroup_name(ctrl->dh_gid), ctrl->dh_gid);
@@ -92,7 +103,11 @@ static u16 nvmet_auth_reply(struct nvmet_req *req, void *d)
 		return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
 
 	if (dhvlen) {
-		return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
+		if (!ctrl->dh_tfm)
+			return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
+		if (nvmet_auth_ctrl_sesskey(req, data->rval + 2 * data->hl,
+					    dhvlen) < 0)
+			return NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE;
 	}
 
 	response = kmalloc(data->hl, GFP_KERNEL);
@@ -305,6 +320,8 @@ static int nvmet_auth_challenge(struct nvmet_req *req, void *d, int al)
 	int hash_len = crypto_shash_digestsize(ctrl->shash_tfm);
 	int data_size = sizeof(*d) + hash_len;
 
+	if (ctrl->dh_tfm)
+		data_size += ctrl->dh_keysize;
 	if (al < data_size) {
 		pr_debug("%s: buffer too small (al %d need %d)\n", __func__,
 			 al, data_size);
@@ -323,9 +340,15 @@ static int nvmet_auth_challenge(struct nvmet_req *req, void *d, int al)
 		return -ENOMEM;
 	get_random_bytes(req->sq->dhchap_c1, data->hl);
 	memcpy(data->cval, req->sq->dhchap_c1, data->hl);
+	if (ctrl->dh_tfm) {
+		data->dhgid = ctrl->dh_gid;
+		data->dhvlen = cpu_to_le32(ctrl->dh_keysize);
+		ret = nvmet_auth_ctrl_exponential(req, data->cval + data->hl,
+						  ctrl->dh_keysize);
+	}
 	pr_debug("%s: ctrl %d qid %d seq %d transaction %d hl %d dhvlen %d\n",
 		 __func__, ctrl->cntlid, req->sq->qid, req->sq->dhchap_s1,
-		 req->sq->dhchap_tid, data->hl, 0);
+		 req->sq->dhchap_tid, data->hl, ctrl->dh_keysize);
 	return ret;
 }
 
drivers/nvme/target/nvmet.h +6 -0
index 7fdd48193f83..4e34ee0e51ec 100644
@@ -229,6 +229,7 @@ struct nvmet_ctrl {
 	size_t			dhchap_ctrl_key_len;
 	struct crypto_shash	*shash_tfm;
 	u8			shash_id;
+	struct crypto_kpp	*dh_tfm;
 	u32			dh_gid;
 	u32			dh_keysize;
 #endif
@@ -698,6 +699,7 @@ int nvmet_setup_auth(struct nvmet_ctrl *ctrl);
 void nvmet_init_auth(struct nvmet_ctrl *ctrl, struct nvmet_req *req);
 void nvmet_destroy_auth(struct nvmet_ctrl *ctrl);
 void nvmet_auth_sq_free(struct nvmet_sq *sq);
+int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, int dhgroup_id);
 bool nvmet_check_auth_status(struct nvmet_req *req);
 int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response,
 			 unsigned int hash_len);
@@ -707,6 +709,10 @@ static inline bool nvmet_has_auth(struct nvmet_ctrl *ctrl)
 {
 	return ctrl->shash_tfm != NULL;
 }
+int nvmet_auth_ctrl_exponential(struct nvmet_req *req,
+				u8 *buf, int buf_size);
+int nvmet_auth_ctrl_sesskey(struct nvmet_req *req,
+			    u8 *buf, int buf_size);
 #else
 static inline int nvmet_setup_auth(struct nvmet_ctrl *ctrl)
 {
Signature · 1 line
2.29.2
author maintainer
#19 lore raw

PATCH v4 12/12 nvmet-auth: expire authentication sessions

In reply to Hannes Reinecke

Each authentication step is required to be completed within the KATO interval (or two minutes if not set). So add a workqueue function to reset the transaction ID and the expected next protocol step; this will automatically the next authentication command referring to the terminated authentication.

---
 drivers/nvme/target/auth.c             |  1 +
 drivers/nvme/target/fabrics-cmd-auth.c | 20 +++++++++++++++++++-
 drivers/nvme/target/nvmet.h            |  1 +
 3 files changed, 21 insertions(+), 1 deletion(-)
drivers/nvme/target/auth.c +1 -0
index 274b199bb6d7..173d573b40c2 100644
@@ -240,6 +240,7 @@ int nvmet_setup_auth(struct nvmet_ctrl *ctrl)
 
 void nvmet_auth_sq_free(struct nvmet_sq *sq)
 {
+	cancel_delayed_work(&sq->auth_expired_work);
 	kfree(sq->dhchap_c1);
 	sq->dhchap_c1 = NULL;
 	kfree(sq->dhchap_c2);
drivers/nvme/target/fabrics-cmd-auth.c +19 -1
index a11de590a5a4..bb0239da576a 100644
@@ -12,9 +12,22 @@
 #include "nvmet.h"
 #include "../host/auth.h"
 
+static void nvmet_auth_expired_work(struct work_struct *work)
+{
+	struct nvmet_sq *sq = container_of(to_delayed_work(work),
+			struct nvmet_sq, auth_expired_work);
+
+	pr_debug("%s: ctrl %d qid %d transaction %u expired, resetting\n",
+		 __func__, sq->ctrl->cntlid, sq->qid, sq->dhchap_tid);
+	sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE;
+	sq->dhchap_tid = -1;
+}
+
 void nvmet_init_auth(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
 {
 	/* Initialize in-band authentication */
+	INIT_DELAYED_WORK(&req->sq->auth_expired_work,
+			  nvmet_auth_expired_work);
 	req->sq->authenticated = false;
 	req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE;
 	req->cqe->result.u32 |= 0x2 << 16;
@@ -304,8 +317,13 @@ void nvmet_execute_auth_send(struct nvmet_req *req)
 	req->cqe->result.u64 = 0;
 	nvmet_req_complete(req, status);
 	if (req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2 &&
-	    req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_FAILURE2)
+	    req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) {
+		unsigned long auth_expire_secs = ctrl->kato ? ctrl->kato : 120;
+
+		mod_delayed_work(system_wq, &req->sq->auth_expired_work,
+				 auth_expire_secs * HZ);
 		return;
+	}
 	/* Final states, clear up variables */
 	nvmet_auth_sq_free(req->sq);
 	if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2)
drivers/nvme/target/nvmet.h +1 -0
index 4e34ee0e51ec..b1972c0dd28a 100644
@@ -109,6 +109,7 @@ struct nvmet_sq {
 	u32			sqhd;
 	bool			sqhd_disabled;
 #ifdef CONFIG_NVME_TARGET_AUTH
+	struct delayed_work	auth_expired_work;
 	bool			authenticated;
 	u16			dhchap_tid;
 	u16			dhchap_status;
Signature · 1 line
2.29.2
Reviewed-by on the v4 series
#20 lore raw
In reply to Hannes Reinecke
Quoted 85 lines · Hannes Reinecke

Hi all,

recent updates to the NVMe spec have added definitions for in-band authentication, and seeing that it provides some real benefit especially for NVMe-TCP here's an attempt to implement it.

Tricky bit here is that the specification orients itself on TLS 1.3, but supports only the FFDHE groups. Which of course the kernel doesn't support. I've been able to come up with a patch for this, but as this is my first attempt to fix anything in the crypto area I would invite people more familiar with these matters to have a look.

Also note that this is just for in-band authentication. Secure concatenation (ie starting TLS with the negotiated parameters) is not implemented; one would need to update the kernel TLS implementation for this, which at this time is beyond scope.

As usual, comments and reviews are welcome.

Changes to v3:
- Renamed parameter to 'dhchap_ctrl_key'
- Fixed bi-directional authentication
- Included reviews from Sagi
- Fixed base64 algorithm for transport encoding

Changes to v2:
- Dropped non-standard algorithms
- Reworked base64 based on fs/crypto/fname.c
- Fixup crash with no keys

Changes to the original submission:
- Included reviews from Vladislav
- Included reviews from Sagi
- Implemented re-authentication support
- Fixed up key handling

Hannes Reinecke (12):
crypto: add crypto_has_shash()
crypto: add crypto_has_kpp()
crypto/ffdhe: Finite Field DH Ephemeral Parameters lib/base64: RFC4648-compliant base64 encoding
nvme: add definitions for NVMe In-Band authentication
nvme-fabrics: decode 'authentication required' connect error
nvme: Implement In-Band authentication
nvme-auth: Diffie-Hellman key exchange support
nvmet: Parse fabrics commands on all queues
nvmet: Implement basic In-Band Authentication
nvmet-auth: Diffie-Hellman key exchange support
nvmet-auth: expire authentication sessions

crypto/Kconfig                         |    8 +
crypto/Makefile                        |    1 +
crypto/ffdhe_helper.c                  |  880 ++++++++++++++
crypto/kpp.c                           |    6 +
crypto/shash.c                         |    6 +
drivers/nvme/host/Kconfig              |   12 +
drivers/nvme/host/Makefile             |    1 +
drivers/nvme/host/auth.c               | 1501 ++++++++++++++++++++++++
drivers/nvme/host/auth.h               |   33 +
drivers/nvme/host/core.c               |  126 +-
drivers/nvme/host/fabrics.c            |   85 +-
drivers/nvme/host/fabrics.h            |    7 +
drivers/nvme/host/nvme.h               |   33 +
drivers/nvme/host/trace.c              |   32 +
drivers/nvme/target/Kconfig            |   12 +
drivers/nvme/target/Makefile           |    1 +
drivers/nvme/target/admin-cmd.c        |    4 +
drivers/nvme/target/auth.c             |  486 ++++++++
drivers/nvme/target/configfs.c         |  133 ++-
drivers/nvme/target/core.c             |   10 +
drivers/nvme/target/fabrics-cmd-auth.c |  507 ++++++++
drivers/nvme/target/fabrics-cmd.c      |   30 +-
drivers/nvme/target/nvmet.h            |   74 ++
include/crypto/ffdhe.h                 |   24 +
include/crypto/hash.h                  |    2 +
include/crypto/kpp.h                   |    2 +
include/linux/base64.h                 |   16 +
include/linux/nvme.h                   |  186 ++-
lib/Makefile                           |    2 +-
lib/base64.c                           |  100 ++
30 files changed, 4309 insertions(+), 11 deletions(-)
Quoted 17 lines

create mode 100644 crypto/ffdhe_helper.c
create mode 100644 drivers/nvme/host/auth.c create mode 100644 drivers/nvme/host/auth.h create mode 100644 drivers/nvme/target/auth.c create mode 100644 drivers/nvme/target/fabrics-cmd-auth.c create mode 100644 include/crypto/ffdhe.h
create mode 100644 include/linux/base64.h
create mode 100644 lib/base64.c

Signature · 7 lines
2.29.2


_______________________________________________
Linux-nvme mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-nvme

I reviewed patches 1-7 using b4 to apply on my local tree, because I am not able to locate them in my mailbox and lack of versioning on each patch makes it hard to figure out which one belong to which revision.

Please add for v4 patches 1 - 7

--
Himanshu Madhani Oracle Linux Engineering