Skip to contentSkip to conversation

nvme: In-band authentication support

PATCH Superseded Hannes Reinecke 2 participants 25 messages Jun 21, 2022 – Jun 22, 2022

Subsystems (5)

v15 of 18 Superseded Latest is v18 →

lore
Share & tools
lore

Hannes Reinecke

author maintainer
#0 lore raw

v15 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.

Thanks to Nicolai Stange the crypto DH framework has been upgraded to provide us with a FFDHE implementation; I've updated the patchset to use the ephemeral key generation provided there.

Note that this is just for in-band authentication. Secure concatenation (ie starting TLS with the negotiated parameters) requires a TLS handshake, which the in-kernel TLS implementation does not provide. This is being worked on with a different patchset which is still WIP.

The nvme-cli support has already been merged; please use the latest nvme-cli git repository to build the most recent version.

A copy of this patchset can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/hare/scsi-devel
branch auth.v15

The patchset is being cut against nvme-5.19.

As usual, comments and reviews are welcome.

Changes to v14:
- Rebase to nvme-5.19
- Fixup sparse warnings as noted by Christoph
- Fixup Kconfig dependencies
- Add NVME_CONNECT_AUTHREQ definitions

Changes to v13:
- Fixup sysfs attribute visibility (reported by Chaitanya)
- Fixup SUCCESS1 handling
- Re-introduce crypto_has_shash() and crypto_has_kpp() helper
- Unse 'authenticated' flag on failure

Changes to v12:
- Replaces crypto_has_shash() and crypto_has_kpp() helper with CONFIG_ checks
- Fixed kbuild robot warning in pr_fmt()

Changes to v11:
- Fixup type for FAILURE2 message (Prashant Nayak)
- Do not sent SUCCESS2 if bi-directional authentication is not requested (Martin George)

Changes to v10:
- Fixup error return value when authentication failed

Changes to v9:
- Include review from Chaitanya
- Use sparse array for dhgroup and hash lookup
- Common function for auth_send and auth_receive

Changes to v8:
- Rebased to Nicolais crypto DH rework
- Fixed oops on non-fabrics devices

Changes to v7:
- Space out hash list and dhgroup list in nvme negotiate data to be conformant with the spec
- Update sequence number handling to start with a random value and ignore '0' as mandated by the spec
- Update nvme_auth_generate_key to return the key as suggested by Sagi
- Add nvmet_parse_fabrics_io_cmd() as suggested by hch

Changes to v6:
- Use 'u8' for DH group id and hash id
- Use 'struct nvme_dhchap_key'
- Rename variables to drop 'DHCHAP'
- Include reviews from Chaitanya

Changes to v5:
- Unify nvme_auth_generate_key()
- Unify nvme_auth_extract_key()
- Fixed bug where re-authentication with wrong controller key would not fail
- Include reviews from Sagi

Changes to v4:
- Validate against blktest suite
- Fixup base64 decoding
- Transform secret with correct hmac algorithm

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

*
** BLURB HERE ***

Hannes Reinecke (11):
crypto: add crypto_has_shash()
crypto: add crypto_has_kpp()
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 io queues
nvmet: Implement basic In-Band Authentication
nvmet-auth: Diffie-Hellman key exchange support
nvmet-auth: expire authentication sessions

 crypto/kpp.c                           |    6 +
 crypto/shash.c                         |    6 +
 drivers/nvme/Kconfig                   |    1 +
 drivers/nvme/Makefile                  |    1 +
 drivers/nvme/common/Kconfig            |    4 +
 drivers/nvme/common/Makefile           |    7 +
 drivers/nvme/common/auth.c             |  481 ++++++++++++
 drivers/nvme/host/Kconfig              |   15 +
 drivers/nvme/host/Makefile             |    1 +
 drivers/nvme/host/auth.c               | 1000 ++++++++++++++++++++++++
 drivers/nvme/host/core.c               |  143 +++-
 drivers/nvme/host/fabrics.c            |   83 +-
 drivers/nvme/host/fabrics.h            |    7 +
 drivers/nvme/host/nvme.h               |   30 +
 drivers/nvme/host/rdma.c               |    1 +
 drivers/nvme/host/tcp.c                |    1 +
 drivers/nvme/host/trace.c              |   32 +
 drivers/nvme/target/Kconfig            |   15 +
 drivers/nvme/target/Makefile           |    1 +
 drivers/nvme/target/admin-cmd.c        |    4 +-
 drivers/nvme/target/auth.c             |  525 +++++++++++++
 drivers/nvme/target/configfs.c         |  138 +++-
 drivers/nvme/target/core.c             |   15 +
 drivers/nvme/target/fabrics-cmd-auth.c |  545 +++++++++++++
 drivers/nvme/target/fabrics-cmd.c      |   55 +-
 drivers/nvme/target/nvmet.h            |   75 +-
 include/crypto/hash.h                  |    2 +
 include/crypto/kpp.h                   |    2 +
 include/linux/base64.h                 |   16 +
 include/linux/nvme-auth.h              |   41 +
 include/linux/nvme.h                   |  209 ++++-
 lib/Makefile                           |    2 +-
 lib/base64.c                           |  103 +++
 33 files changed, 3552 insertions(+), 15 deletions(-)
 create mode 100644 drivers/nvme/common/Kconfig
 create mode 100644 drivers/nvme/common/Makefile
 create mode 100644 drivers/nvme/common/auth.c
 create mode 100644 drivers/nvme/host/auth.c
 create mode 100644 drivers/nvme/target/auth.c
 create mode 100644 drivers/nvme/target/fabrics-cmd-auth.c
 create mode 100644 include/linux/base64.h
 create mode 100644 include/linux/nvme-auth.h
 create mode 100644 lib/base64.c
Signature · 1 line
2.29.2
author maintainer
#1 lore raw

PATCH v15 1/11 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 v15 2/11 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 7aa6ba4b60a4..678e871ce418 100644
@@ -104,6 +104,12 @@ int crypto_grab_kpp(struct crypto_kpp_spawn *spawn,
 }
 EXPORT_SYMBOL_GPL(crypto_grab_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 · 1 line
2.29.2
author maintainer
#3 lore raw

PATCH v15 3/11 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           | 103 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 120 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 ea54294d73bf..b276684beab3 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 +103 -0

103 lines not on this page · raw message

Signature · 1 line
2.29.2
author maintainer
#4 lore raw

PATCH v15 4/11 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 | 209 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 208 insertions(+), 1 deletion(-)
include/linux/nvme.h +208 -1
index 29ec3e3481ff..ed5ee1167a03 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"
 
@@ -1367,6 +1368,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 }
@@ -1374,7 +1377,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.
@@ -1470,6 +1475,11 @@ struct nvmf_connect_command {
 	__u8		resv4[12];
 };
 
+enum {
+	NVME_CONNECT_AUTHREQ_ASCR	= (1 << 2),
+	NVME_CONNECT_AUTHREQ_ATR	= (1 << 1),
+};
+
 struct nvmf_connect_data {
 	uuid_t		hostid;
 	__le16		cntlid;
@@ -1504,6 +1514,200 @@ struct nvmf_property_get_command {
 	__u8		resv4[16];
 };
 
+struct nvmf_auth_common_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_tl;
+	__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_HASH_SHA256	= 0x01,
+	NVME_AUTH_HASH_SHA384	= 0x02,
+	NVME_AUTH_HASH_SHA512	= 0x03,
+	NVME_AUTH_HASH_INVALID	= 0xff,
+};
+
+/* Defined Diffie-Hellman group identifiers for DH-HMAC-CHAP authentication */
+enum {
+	NVME_AUTH_DHGROUP_NULL		= 0x00,
+	NVME_AUTH_DHGROUP_2048		= 0x01,
+	NVME_AUTH_DHGROUP_3072		= 0x02,
+	NVME_AUTH_DHGROUP_4096		= 0x03,
+	NVME_AUTH_DHGROUP_6144		= 0x04,
+	NVME_AUTH_DHGROUP_8192		= 0x05,
+	NVME_AUTH_DHGROUP_INVALID	= 0xff,
+};
+
+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;
@@ -1547,6 +1751,9 @@ 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_common_command auth_common;
+		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
#5 lore raw

PATCH v15 5/11 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 ee79a6d639b4..953e3076aab1 100644
@@ -331,6 +331,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 · 1 line
2.29.2
author maintainer
#6 lore raw

PATCH v15 6/11 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/Kconfig         |   1 +
 drivers/nvme/Makefile        |   1 +
 drivers/nvme/common/Kconfig  |   4 +
 drivers/nvme/common/Makefile |   7 +
 drivers/nvme/common/auth.c   | 328 ++++++++++++++
 drivers/nvme/host/Kconfig    |  13 +
 drivers/nvme/host/Makefile   |   1 +
 drivers/nvme/host/auth.c     | 813 +++++++++++++++++++++++++++++++++++
 drivers/nvme/host/core.c     | 143 +++++-
 drivers/nvme/host/fabrics.c  |  79 +++-
 drivers/nvme/host/fabrics.h  |   7 +
 drivers/nvme/host/nvme.h     |  30 ++
 drivers/nvme/host/rdma.c     |   1 +
 drivers/nvme/host/tcp.c      |   1 +
 drivers/nvme/host/trace.c    |  32 ++
 include/linux/nvme-auth.h    |  33 ++
 16 files changed, 1487 insertions(+), 7 deletions(-)
 create mode 100644 drivers/nvme/common/Kconfig
 create mode 100644 drivers/nvme/common/Makefile
 create mode 100644 drivers/nvme/common/auth.c
 create mode 100644 drivers/nvme/host/auth.c
 create mode 100644 include/linux/nvme-auth.h
drivers/nvme/Kconfig +1 -0
index 87ae409a32b9..656e46d938da 100644
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menu "NVME Support"
 
+source "drivers/nvme/common/Kconfig"
 source "drivers/nvme/host/Kconfig"
 source "drivers/nvme/target/Kconfig"
 
drivers/nvme/Makefile +1 -0
index fb42c44609a8..eedca8c72098 100644
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
+obj-$(CONFIG_NVME_COMMON)		+= common/
 obj-y		+= host/
 obj-y		+= target/
drivers/nvme/common/Kconfig new file +4 -0
new file mode 100644
index 000000000000..4514f44362dd
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config NVME_COMMON
+       tristate
drivers/nvme/common/Makefile new file +7 -0
new file mode 100644
index 000000000000..720c625b8a52
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+ccflags-y			+= -I$(src)
+
+obj-$(CONFIG_NVME_COMMON)	+= nvme-common.o
+
+nvme-common-y			+= auth.o
drivers/nvme/common/auth.c new file +328 -0

328 lines not on this page · raw message

drivers/nvme/host/Kconfig +13 -0
index 877d2ec4ea9f..6c503f42f3c6 100644
@@ -92,6 +92,19 @@ config NVME_TCP
 
 	  If unsure, say N.
 
+config NVME_AUTH
+	bool "NVM Express over Fabrics In-Band Authentication"
+	depends on NVME_CORE
+	select NVME_COMMON
+	select CRYPTO
+	select CRYPTO_HMAC
+	select CRYPTO_SHA256
+	select CRYPTO_SHA512
+	help
+	  This provides support for NVMe over Fabrics In-Band Authentication.
+
+	  If unsure, say N.
+
 config NVME_APPLE
 	tristate "Apple ANS2 NVM Express host driver"
 	depends on OF && BLOCK
drivers/nvme/host/Makefile +1 -0
index a36ae1612059..a3e88f32f560 100644
@@ -16,6 +16,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 +813 -0

813 lines not on this page · raw message

drivers/nvme/host/core.c +139 -4

225 lines not on this page · raw message

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

134 lines not on this page · raw message

drivers/nvme/host/fabrics.h +7 -0
index 46d6e194ac2b..a6e22116e139 100644
@@ -68,6 +68,8 @@ enum {
 	NVMF_OPT_FAIL_FAST_TMO	= 1 << 20,
 	NVMF_OPT_HOST_IFACE	= 1 << 21,
 	NVMF_OPT_DISCOVERY	= 1 << 22,
+	NVMF_OPT_DHCHAP_SECRET	= 1 << 23,
+	NVMF_OPT_DHCHAP_CTRL_SECRET = 1 << 24,
 };
 
 /**
@@ -97,6 +99,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)
@@ -121,6 +126,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 +30 -0
index 0da94b233fed..798ce748f244 100644
@@ -328,6 +328,15 @@ 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;
+	struct nvme_dhchap_key *host_key;
+	struct nvme_dhchap_key *ctrl_key;
+	u16 transaction;
+#endif
+
 	/* Power saving configuration */
 	u64 ps_max_latency_us;
 	bool apst_enabled;
@@ -991,6 +1000,27 @@ 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_reset(struct nvme_ctrl *ctrl);
+void nvme_auth_free(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/rdma.c +1 -0
index f2a5e1ea508a..84ce3347d158 100644
@@ -1197,6 +1197,7 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)
 	struct nvme_rdma_ctrl *ctrl = container_of(work,
 			struct nvme_rdma_ctrl, err_work);
 
+	nvme_auth_stop(&ctrl->ctrl);
 	nvme_stop_keep_alive(&ctrl->ctrl);
 	flush_work(&ctrl->ctrl.async_event_work);
 	nvme_rdma_teardown_io_queues(ctrl, false);
drivers/nvme/host/tcp.c +1 -0
index bb67538d241b..a7848e430a5c 100644
@@ -2174,6 +2174,7 @@ static void nvme_tcp_error_recovery_work(struct work_struct *work)
 				struct nvme_tcp_ctrl, err_work);
 	struct nvme_ctrl *ctrl = &tcp_ctrl->ctrl;
 
+	nvme_auth_stop(ctrl);
 	nvme_stop_keep_alive(ctrl);
 	flush_work(&ctrl->async_event_work);
 	nvme_tcp_teardown_io_queues(ctrl, false);
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);
 	}
include/linux/nvme-auth.h new file +33 -0
new file mode 100644
index 000000000000..354456826221
@@ -0,0 +1,33 @@
+/* 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>
+
+struct nvme_dhchap_key {
+	u8 *key;
+	size_t len;
+	u8 hash;
+};
+
+u32 nvme_auth_get_seqnum(void);
+const char *nvme_auth_dhgroup_name(u8 dhgroup_id);
+const char *nvme_auth_dhgroup_kpp(u8 dhgroup_id);
+u8 nvme_auth_dhgroup_id(const char *dhgroup_name);
+
+const char *nvme_auth_hmac_name(u8 hmac_id);
+const char *nvme_auth_digest_name(u8 hmac_id);
+size_t nvme_auth_hmac_hash_len(u8 hmac_id);
+u8 nvme_auth_hmac_id(const char *hmac_name);
+
+struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
+					      u8 key_hash);
+void nvme_auth_free_key(struct nvme_dhchap_key *key);
+u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn);
+int nvme_auth_generate_key(u8 *secret, struct nvme_dhchap_key **ret_key);
+
+#endif /* _NVME_AUTH_H */
Signature · 1 line
2.29.2
maintainer
#7 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

This one doesn't compile against nvme-5.20.

drivers/nvme/host/auth.c line 65

Quoted 3 lines
drivers/nvme/host/auth.c new file +3 -0
+	ret = __nvme_submit_sync_cmd(q, &cmd, NULL, data, data_len, 0,
+				     qid == 0 ? NVME_QID_ANY : qid,
+				     0, flags);

here ^^^^^^^

author maintainer
#8 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

Quoted 7 lines · Sagi Grimberg

This one doesn't compile against nvme-5.20.

Quoted 3 lines

+    ret = __nvme_submit_sync_cmd(q, &cmd, NULL, data, data_len, 0, +                     qid == 0 ? NVME_QID_ANY : qid,
+                     0, flags);

here ^^^^^^^

Sheesh. I've compiled it against nvme-5.19, where it works perfectly. Alright, once more unto the breach ...

Cheers,

Hannes

maintainer
#9 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

Quoted 11 lines · Hannes Reinecke
Quoted 7 lines · Sagi Grimberg

This one doesn't compile against nvme-5.20.

Quoted 3 lines

+    ret = __nvme_submit_sync_cmd(q, &cmd, NULL, data, data_len, 0, +                     qid == 0 ? NVME_QID_ANY : qid,
+                     0, flags);

here ^^^^^^^

Sheesh. I've compiled it against nvme-5.19, where it works perfectly. Alright, once more unto the breach ...

Looks like if I pass a malformed ctrl key to nvme connect I am able to crash the system:
--

[   84.793307] Workqueue: nvme-wq __nvme_auth_work [nvme_core]
[   84.794790] RIP: 0010:nvme_auth_transform_key+0x19/0x1f0 [nvme_common]
[   84.796468] Code: bc f4 ff ff ff eb bf e8 f5 2f e1 ee 0f 1f 44 00 00 0f 1f 44 00 00 41 57 41 56 41 55 49 89 f5 41 54 55 53 48 89 fb 48 83 ec 08 <0f> b6 7f 10 e8 ce f9 ff ff 48 89 c7 0f b6 43 10 84 c0 0f 84 4c 01
[   84.800112] RSP: 0018:ffffae5f8047bc78 EFLAGS: 00010296
[   84.801048] RAX: ffff973b854ca0c0 RBX: 0000000000000000 RCX: 0000000000000000
[   84.802289] RDX: ffff973b8355b000 RSI: ffff973b84f568a0 RDI: 0000000000000000
[   84.803447] RBP: ffff973b842dd6b9 R08: 0000000000000003 R09: ffff973bbec308a8
[   84.804638] R10: 0000000000000147 R11: 0000000000000000 R12: ffff973b842dd600
[   84.805767] R13: ffff973b84f568a0 R14: 0000000000000000 R15: ffff973b9e94250d
[   84.806929] FS:  0000000000000000(0000) GS:ffff973bbec00000(0000) knlGS:0000000000000000
[   84.808220] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   84.809178] CR2: 0000000000000010 CR3: 00000000061ac003 CR4: 0000000000370ef0
[   84.810337] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   84.811432] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   84.812527] Call Trace:
[   84.812974]  <TASK>
[   84.813372]  nvme_auth_dhchap_setup_ctrl_response+0x4b/0x3b0 [nvme_core]
[   84.814355]  ? preempt_count_add+0x68/0xa0
[   84.815080]  ? _raw_spin_unlock_irq+0x16/0x28
[   84.815840]  ? __wait_for_common+0x19f/0x1d0
[   84.816587]  ? firmware_map_remove+0x87/0x87
[   84.817333]  ? blk_mq_hctx_has_pending+0x38/0x70
[   84.818123]  ? blk_mq_run_hw_queue+0x7d/0xe0
[   84.818784]  ? __blk_mq_free_request+0x9b/0xa0
[   84.819482]  ? blk_queue_exit+0xe/0x40
[   84.820124]  ? __nvme_submit_sync_cmd+0xe8/0x160 [nvme_core]
[   84.821096]  ? nvme_auth_submit+0x8f/0xd0 [nvme_core]
[   84.821970]  __nvme_auth_work+0x1fb/0x480 [nvme_core]
[   84.822869]  process_one_work+0x1e5/0x3b0
[   84.823608]  worker_thread+0x1c4/0x3a0
[   84.824343]  ? rescuer_thread+0x390/0x390
[   84.825044]  kthread+0xe8/0x110

--

maintainer
#10 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

Quoted 3 lines

Looks like if I pass a malformed ctrl key to nvme connect I am able to crash the system:

This was what I used in this:

$ nvme connect -a 192.168.123.1 -t tcp  -s 8009 -n testnqn1 -S "DHHC-1:00:QpxVGpctx5J+4SeW2MClUI8rfZO3WdP1llImvsPsx7e3TK+I:" -C "DHHC-1:00:Jc/My1o0qtLCWRp+sHhAVafdfaS7YQOMYhk9zSmlatobqB8C:"

The dhchap_ctrl_key is the offending string...

Quoted 34 lines
Signature · 33 lines
[   84.793307] Workqueue: nvme-wq __nvme_auth_work [nvme_core]
[   84.794790] RIP: 0010:nvme_auth_transform_key+0x19/0x1f0 [nvme_common]
[   84.796468] Code: bc f4 ff ff ff eb bf e8 f5 2f e1 ee 0f 1f 44 00 00 0f 1f 44 00 00 41 57 41 56 41 55 49 89 f5 41 54 55 53 48 89 fb 48 83 ec 08 <0f> b6 7f 10 e8 ce f9 ff ff 48 89 c7 0f b6 43 10 84 c0 0f 84 4c 01
[   84.800112] RSP: 0018:ffffae5f8047bc78 EFLAGS: 00010296
[   84.801048] RAX: ffff973b854ca0c0 RBX: 0000000000000000 RCX: 0000000000000000
[   84.802289] RDX: ffff973b8355b000 RSI: ffff973b84f568a0 RDI: 0000000000000000
[   84.803447] RBP: ffff973b842dd6b9 R08: 0000000000000003 R09: ffff973bbec308a8
[   84.804638] R10: 0000000000000147 R11: 0000000000000000 R12: ffff973b842dd600
[   84.805767] R13: ffff973b84f568a0 R14: 0000000000000000 R15: ffff973b9e94250d
[   84.806929] FS:  0000000000000000(0000) GS:ffff973bbec00000(0000) knlGS:0000000000000000
[   84.808220] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   84.809178] CR2: 0000000000000010 CR3: 00000000061ac003 CR4: 0000000000370ef0
[   84.810337] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   84.811432] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   84.812527] Call Trace:
[   84.812974]  <TASK>
[   84.813372]  nvme_auth_dhchap_setup_ctrl_response+0x4b/0x3b0 [nvme_core]
[   84.814355]  ? preempt_count_add+0x68/0xa0
[   84.815080]  ? _raw_spin_unlock_irq+0x16/0x28
[   84.815840]  ? __wait_for_common+0x19f/0x1d0
[   84.816587]  ? firmware_map_remove+0x87/0x87
[   84.817333]  ? blk_mq_hctx_has_pending+0x38/0x70
[   84.818123]  ? blk_mq_run_hw_queue+0x7d/0xe0
[   84.818784]  ? __blk_mq_free_request+0x9b/0xa0
[   84.819482]  ? blk_queue_exit+0xe/0x40
[   84.820124]  ? __nvme_submit_sync_cmd+0xe8/0x160 [nvme_core]
[   84.821096]  ? nvme_auth_submit+0x8f/0xd0 [nvme_core]
[   84.821970]  __nvme_auth_work+0x1fb/0x480 [nvme_core]
[   84.822869]  process_one_work+0x1e5/0x3b0
[   84.823608]  worker_thread+0x1c4/0x3a0
[   84.824343]  ? rescuer_thread+0x390/0x390
[   84.825044]  kthread+0xe8/0x110
-- 
author maintainer
#11 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

Quoted 9 lines · Sagi Grimberg
Quoted 3 lines

Looks like if I pass a malformed ctrl key to nvme connect I am able to crash the system:

This was what I used in this:

$ nvme connect -a 192.168.123.1 -t tcp  -s 8009 -n testnqn1 -S "DHHC-1:00:QpxVGpctx5J+4SeW2MClUI8rfZO3WdP1llImvsPsx7e3TK+I:" -C "DHHC-1:00:Jc/My1o0qtLCWRp+sHhAVafdfaS7YQOMYhk9zSmlatobqB8C:"

The dhchap_ctrl_key is the offending string...

Right. Should be fixed with the attached patch.
Can you check?

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke                Kernel Storage Architect
[email protected]                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman

From 1f4d34016e7cad41f6947143f07f802b05415e26 Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <[email protected]>
Date: Wed, 22 Jun 2022 07:57:06 +0200
Subject: [PATCH] nvme-auth: do not use ctrl->opts->dhchap_ctrl_secret

The user might have passed in an invalid controller secret, causing ctrl->opts->dhchap_ctrl_secret to be present, but ctrl->ctrl_key to be empty. So always use ctrl->ctrl_key when checking if a valid controller secret is present.

---
 drivers/nvme/common/auth.c | 13 +++++++------
 drivers/nvme/host/auth.c   |  8 ++++----
 2 files changed, 11 insertions(+), 10 deletions(-)
drivers/nvme/common/auth.c +7 -6
index 945f6bb6eb1f..0c86ebce59d2 100644
@@ -237,21 +237,21 @@ EXPORT_SYMBOL_GPL(nvme_auth_free_key);
 
 u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
 {
-	const char *hmac_name = nvme_auth_hmac_name(key->hash);
+	const char *hmac_name;
 	struct crypto_shash *key_tfm;
 	struct shash_desc *shash;
 	u8 *transformed_key;
 	int ret;
 
-	if (key->hash == 0) {
-		transformed_key = kmemdup(key->key, key->len, GFP_KERNEL);
-		return transformed_key ? transformed_key : ERR_PTR(-ENOMEM);
-	}
-
 	if (!key || !key->key) {
 		pr_warn("No key specified\n");
 		return ERR_PTR(-ENOKEY);
 	}
+	if (key->hash == 0) {
+		transformed_key = kmemdup(key->key, key->len, GFP_KERNEL);
+		return transformed_key ? transformed_key : ERR_PTR(-ENOMEM);
+	}
+	hmac_name = nvme_auth_hmac_name(key->hash);
 	if (!hmac_name) {
 		pr_warn("Invalid key hash id %d\n", key->hash);
 		return ERR_PTR(-EINVAL);
@@ -470,6 +470,7 @@ int nvme_auth_generate_key(u8 *secret, struct nvme_dhchap_key **ret_key)
 	/* Pass in the secret without the 'DHHC-1:XX:' prefix */
 	key = nvme_auth_extract_key(secret + 10, key_hash);
 	if (IS_ERR(key)) {
+		*ret_key = NULL;
 		return PTR_ERR(key);
 	}
 
drivers/nvme/host/auth.c +4 -4
index 9b84e1e54ca7..53184ac76240 100644
@@ -314,7 +314,7 @@ static int nvme_auth_set_dhchap_reply_data(struct nvme_ctrl *ctrl,
 	data->hl = chap->hash_len;
 	data->dhvlen = cpu_to_le16(chap->host_key_len);
 	memcpy(data->rval, chap->response, chap->hash_len);
-	if (ctrl->opts->dhchap_ctrl_secret) {
+	if (ctrl->ctrl_key) {
 		get_random_bytes(chap->c2, chap->hash_len);
 		data->cvalid = 1;
 		chap->s2 = nvme_auth_get_seqnum();
@@ -344,7 +344,7 @@ static int nvme_auth_process_dhchap_success1(struct nvme_ctrl *ctrl,
 	struct nvmf_auth_dhchap_success1_data *data = chap->buf;
 	size_t size = sizeof(*data);
 
-	if (ctrl->opts->dhchap_ctrl_secret)
+	if (ctrl->ctrl_key)
 		size += chap->hash_len;
 
 	if (chap->buf_size < size) {
@@ -791,7 +791,7 @@ static void __nvme_auth_work(struct work_struct *work)
 		return;
 	}
 
-	if (ctrl->opts->dhchap_ctrl_secret) {
+	if (ctrl->ctrl_key) {
 		dev_dbg(ctrl->device,
 			"%s: qid %d controller response\n",
 			__func__, chap->qid);
@@ -809,7 +809,7 @@ static void __nvme_auth_work(struct work_struct *work)
 		goto fail2;
 	}
 
-	if (ctrl->opts->dhchap_ctrl_secret) {
+	if (ctrl->ctrl_key) {
 		/* DH-HMAC-CHAP Step 5: send success2 */
 		dev_dbg(ctrl->device, "%s: qid %d send success2\n",
 			__func__, chap->qid);
Signature · 1 line
2.26.2
maintainer
#12 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

Quoted 11 lines
Quoted 9 lines
Quoted 3 lines

Looks like if I pass a malformed ctrl key to nvme connect I am able to crash the system:

This was what I used in this:

$ nvme connect -a 192.168.123.1 -t tcp  -s 8009 -n testnqn1 -S "DHHC-1:00:QpxVGpctx5J+4SeW2MClUI8rfZO3WdP1llImvsPsx7e3TK+I:" -C "DHHC-1:00:Jc/My1o0qtLCWRp+sHhAVafdfaS7YQOMYhk9zSmlatobqB8C:"

The dhchap_ctrl_key is the offending string...

Right. Should be fixed with the attached patch.
Can you check?

Yes, that works.

author maintainer
#13 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

Quoted 7 lines · Sagi Grimberg
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

Looks like if I pass a malformed ctrl key to nvme connect I am able to crash the system:

This was what I used in this:

$ nvme connect -a 192.168.123.1 -t tcp  -s 8009 -n testnqn1 -S "DHHC-1:00:QpxVGpctx5J+4SeW2MClUI8rfZO3WdP1llImvsPsx7e3TK+I:" -C "DHHC-1:00:Jc/My1o0qtLCWRp+sHhAVafdfaS7YQOMYhk9zSmlatobqB8C:"
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

The dhchap_ctrl_key is the offending string...

Right. Should be fixed with the attached patch.
Can you check?

Yes, that works.

So, to summarize: With this one and the tentative patch I've sent earlier:

drivers/nvme/host/auth.c +4 -0
index 53184ac76240..a03f41fa146e 100644
@@ -842,6 +842,10 @@ int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid)
                dev_warn(ctrl->device, "qid %d: no key\n", qid);
                return -ENOKEY;
        }
+       if (ctrl->opts->dhchap_ctrl_secret && !ctrl->ctrl_key) {
+               dev_warn(ctrl->device, "qid %d: invalid ctrl key\n", qid);
+               return -ENOKEY;
+       }
 
        mutex_lock(&ctrl->dhchap_auth_mutex);
        /* Check if the context is already queued */

your issues are resolved?
Just to clarify before I sent another round of patches ...

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
#14 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

Quoted 35 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

Looks like if I pass a malformed ctrl key to nvme connect I am able to crash the system:

This was what I used in this:

$ nvme connect -a 192.168.123.1 -t tcp  -s 8009 -n testnqn1 -S "DHHC-1:00:QpxVGpctx5J+4SeW2MClUI8rfZO3WdP1llImvsPsx7e3TK+I:" -C "DHHC-1:00:Jc/My1o0qtLCWRp+sHhAVafdfaS7YQOMYhk9zSmlatobqB8C:"
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

The dhchap_ctrl_key is the offending string...

Right. Should be fixed with the attached patch.
Can you check?

Yes, that works.

So, to summarize: With this one and the tentative patch I've sent earlier:

drivers/nvme/host/auth.c +4 -0
index 53184ac76240..a03f41fa146e 100644
@@ -842,6 +842,10 @@ int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int 
 qid)
                 dev_warn(ctrl->device, "qid %d: no key\n", qid);
                 return -ENOKEY;
         }
+       if (ctrl->opts->dhchap_ctrl_secret && !ctrl->ctrl_key) {
+               dev_warn(ctrl->device, "qid %d: invalid ctrl key\n", qid);
+               return -ENOKEY;
+       }
 
         mutex_lock(&ctrl->dhchap_auth_mutex);

        /* Check if the context is already queued */

Quoted 2 lines

your issues are resolved?
Just to clarify before I sent another round of patches ...

No. I don't understand why this patch is needed. As I noted earlier, when I pass a wrong ctrl key I fail to connect do to authentication error. Also when I pass a malformed ctrl key.

So what does this patch fix? Can you give me an example that should have failed before and only with this patch it fails?

And for the other issue, please read it again, I think it is related to nvme-cli and not this patchset.

author maintainer
#15 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

Quoted 43 lines · Sagi Grimberg
Quoted 36 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

Looks like if I pass a malformed ctrl key to nvme connect I am able to crash the system:

This was what I used in this:

$ nvme connect -a 192.168.123.1 -t tcp  -s 8009 -n testnqn1 -S "DHHC-1:00:QpxVGpctx5J+4SeW2MClUI8rfZO3WdP1llImvsPsx7e3TK+I:" -C "DHHC-1:00:Jc/My1o0qtLCWRp+sHhAVafdfaS7YQOMYhk9zSmlatobqB8C:"
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

The dhchap_ctrl_key is the offending string...

Right. Should be fixed with the attached patch.
Can you check?

Yes, that works.

So, to summarize: With this one and the tentative patch I've sent earlier:

drivers/nvme/host/auth.c +4 -0
index 53184ac76240..a03f41fa146e 100644
@@ -842,6 +842,10 @@ int nvme_auth_negotiate(struct nvme_ctrl *ctrl, 
 int qid)
                  dev_warn(ctrl->device, "qid %d: no key\n", qid);
                  return -ENOKEY;
          }
+       if (ctrl->opts->dhchap_ctrl_secret && !ctrl->ctrl_key) {
+               dev_warn(ctrl->device, "qid %d: invalid ctrl key\n", 
 qid);
+               return -ENOKEY;
+       }
 

         mutex_lock(&ctrl->dhchap_auth_mutex); /* Check if the context is already queued */

Quoted 2 lines

your issues are resolved?
Just to clarify before I sent another round of patches ...

No. I don't understand why this patch is needed. As I noted earlier, when I pass a wrong ctrl key I fail to connect do to authentication error. Also when I pass a malformed ctrl key.

Quoted 3 lines

So what does this patch fix? Can you give me an example that should have failed before and only with this patch it fails?

Reasoning is as follows:
When an invalid controller key is passed via 'ctrl->opts->dhchap_ctrl_secret' we'll end up with an empty 'ctrl->ctrl_key' in nvme_auth_init_ctrl() (which is what caused the original oops). But the negotiation will still start, and, seeing that 'ctrl->ctrl_key' is empty, will _not_ attempt controller authentication.
But as a controller key is passed from userland we should have attempted it, and hence an error is in order.

Quoted 2 lines

And for the other issue, please read it again, I think it is related to nvme-cli and not this patchset.

Hmm. Okay, I'll check, and possibly have to create another blktest for this ...

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
#16 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

Quoted 44 lines · Hannes Reinecke
Quoted 43 lines · Sagi Grimberg
Quoted 36 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

Looks like if I pass a malformed ctrl key to nvme connect I am able to crash the system:

This was what I used in this:

$ nvme connect -a 192.168.123.1 -t tcp  -s 8009 -n testnqn1 -S "DHHC-1:00:QpxVGpctx5J+4SeW2MClUI8rfZO3WdP1llImvsPsx7e3TK+I:" -C "DHHC-1:00:Jc/My1o0qtLCWRp+sHhAVafdfaS7YQOMYhk9zSmlatobqB8C:"
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

The dhchap_ctrl_key is the offending string...

Right. Should be fixed with the attached patch.
Can you check?

Yes, that works.

So, to summarize: With this one and the tentative patch I've sent earlier:

drivers/nvme/host/auth.c +4 -0
index 53184ac76240..a03f41fa146e 100644
@@ -842,6 +842,10 @@ int nvme_auth_negotiate(struct nvme_ctrl *ctrl, 
 int qid)
                  dev_warn(ctrl->device, "qid %d: no key\n", qid);
                  return -ENOKEY;
          }
+       if (ctrl->opts->dhchap_ctrl_secret && !ctrl->ctrl_key) {
+               dev_warn(ctrl->device, "qid %d: invalid ctrl key\n", 
 qid);
+               return -ENOKEY;
+       }
 

         mutex_lock(&ctrl->dhchap_auth_mutex); /* Check if the context is already queued */

Quoted 2 lines

your issues are resolved?
Just to clarify before I sent another round of patches ...

No. I don't understand why this patch is needed. As I noted earlier, when I pass a wrong ctrl key I fail to connect do to authentication error. Also when I pass a malformed ctrl key.

Quoted 7 lines
Quoted 3 lines

So what does this patch fix? Can you give me an example that should have failed before and only with this patch it fails?

Reasoning is as follows:
When an invalid controller key is passed via 'ctrl->opts->dhchap_ctrl_secret' we'll end up with an empty 'ctrl->ctrl_key' in nvme_auth_init_ctrl() (which is what caused the original oops). But the negotiation will still start, and, seeing that 'ctrl->ctrl_key' is empty, will _not_ attempt controller authentication.
But as a controller key is passed from userland we should have attempted it, and hence an error is in order.

Yes, I see it now.
And the patch seems to work.

Quoted 4 lines
Quoted 2 lines

And for the other issue, please read it again, I think it is related to nvme-cli and not this patchset.

Hmm. Okay, I'll check, and possibly have to create another blktest for this ...

Looks like a libnvme fix makes the behavior go away:
--

src/nvme/fabrics.c +4 -1
index 53199a29e264..2dd863fb8b4c 100644
@@ -596,8 +596,11 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c,
                                        nvme_ctrl_get_host_iface(c),
                                        nvme_ctrl_get_trsvcid(c),
                                        NULL);
-               if (fc)
+               if (fc) {
                        cfg = merge_config(c, nvme_ctrl_get_config(fc));
+                       if (fc->dhchap_key)
+                               nvme_ctrl_set_dhchap_key(c, fc->dhchap_key);
+               }
        }
 
        nvme_ctrl_set_discovered(c, true);

--

Looks like when we scan to see an existing controller in the config, we find it, but merge_config does not touch the ctrl dhchap_key.

Maybe it would be better to just add the dhchap_key to the ctrl cfg and have merge_config merge it as well? Or we can live with dhchap_key merged explicitly?

author maintainer
#17 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

Quoted 82 lines · Sagi Grimberg
Quoted 44 lines · Hannes Reinecke
Quoted 43 lines · Sagi Grimberg
Quoted 36 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

Looks like if I pass a malformed ctrl key to nvme connect I am able to crash the system:

This was what I used in this:

$ nvme connect -a 192.168.123.1 -t tcp  -s 8009 -n testnqn1 -S "DHHC-1:00:QpxVGpctx5J+4SeW2MClUI8rfZO3WdP1llImvsPsx7e3TK+I:" -C "DHHC-1:00:Jc/My1o0qtLCWRp+sHhAVafdfaS7YQOMYhk9zSmlatobqB8C:"
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

The dhchap_ctrl_key is the offending string...

Right. Should be fixed with the attached patch.
Can you check?

Yes, that works.

So, to summarize: With this one and the tentative patch I've sent earlier:

drivers/nvme/host/auth.c +4 -0
index 53184ac76240..a03f41fa146e 100644
@@ -842,6 +842,10 @@ int nvme_auth_negotiate(struct nvme_ctrl *ctrl, 
 int qid)
                  dev_warn(ctrl->device, "qid %d: no key\n", qid);
                  return -ENOKEY;
          }
+       if (ctrl->opts->dhchap_ctrl_secret && !ctrl->ctrl_key) {
+               dev_warn(ctrl->device, "qid %d: invalid ctrl key\n", 
 qid);
+               return -ENOKEY;
+       }
 

         mutex_lock(&ctrl->dhchap_auth_mutex); /* Check if the context is already queued */

Quoted 2 lines

your issues are resolved?
Just to clarify before I sent another round of patches ...

No. I don't understand why this patch is needed. As I noted earlier, when I pass a wrong ctrl key I fail to connect do to authentication error. Also when I pass a malformed ctrl key.

Quoted 7 lines
Quoted 3 lines

So what does this patch fix? Can you give me an example that should have failed before and only with this patch it fails?

Reasoning is as follows:
When an invalid controller key is passed via 'ctrl->opts->dhchap_ctrl_secret' we'll end up with an empty 'ctrl->ctrl_key' in nvme_auth_init_ctrl() (which is what caused the original oops). But the negotiation will still start, and, seeing that 'ctrl->ctrl_key' is empty, will _not_ attempt controller authentication.
But as a controller key is passed from userland we should have attempted it, and hence an error is in order.

Yes, I see it now.
And the patch seems to work.

Quoted 4 lines
Quoted 2 lines

And for the other issue, please read it again, I think it is related to nvme-cli and not this patchset.

Hmm. Okay, I'll check, and possibly have to create another blktest for this ...

Looks like a libnvme fix makes the behavior go away:

src/nvme/fabrics.c +4 -1
index 53199a29e264..2dd863fb8b4c 100644
@@ -596,8 +596,11 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c,
                                         nvme_ctrl_get_host_iface(c),
                                         nvme_ctrl_get_trsvcid(c),
                                         NULL);
-               if (fc)
+               if (fc) {
                         cfg = merge_config(c, nvme_ctrl_get_config(fc));
+                       if (fc->dhchap_key)
+                               nvme_ctrl_set_dhchap_key(c, 
 fc->dhchap_key);
+               }
         }
 
Quoted 9 lines

        nvme_ctrl_set_discovered(c, true);

Signature · 6 lines
Looks like when we scan to see an existing controller in the config,
we find it, but merge_config does not touch the ctrl dhchap_key.

Maybe it would be better to just add the dhchap_key to the ctrl cfg
and have merge_config merge it as well? Or we can live with dhchap_key
merged explicitly?

Hmm. That runs slightly afoul of the merge logic.
'merge_config' will overwrite any value _not_ being the default.
Consequently, if a non-default value is already set it won't be overwritten.
Which means that if the 'cfg' structure already contained a controller secret (which could've been used, say, for discovery) we won't overwrite it in merge_config(). Hence I fear we have to go with your suggestion.

Will be preparing a pull request.

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
#18 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

Quoted 89 lines · Hannes Reinecke
Quoted 88 lines · Sagi Grimberg
Quoted 44 lines · Hannes Reinecke
Quoted 43 lines · Sagi Grimberg
Quoted 36 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

Looks like if I pass a malformed ctrl key to nvme connect I am able to crash the system:

This was what I used in this:

$ nvme connect -a 192.168.123.1 -t tcp  -s 8009 -n testnqn1 -S "DHHC-1:00:QpxVGpctx5J+4SeW2MClUI8rfZO3WdP1llImvsPsx7e3TK+I:" -C "DHHC-1:00:Jc/My1o0qtLCWRp+sHhAVafdfaS7YQOMYhk9zSmlatobqB8C:"
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

The dhchap_ctrl_key is the offending string...

Right. Should be fixed with the attached patch.
Can you check?

Yes, that works.

So, to summarize: With this one and the tentative patch I've sent earlier:

drivers/nvme/host/auth.c +4 -0
index 53184ac76240..a03f41fa146e 100644
@@ -842,6 +842,10 @@ int nvme_auth_negotiate(struct nvme_ctrl 
 *ctrl, int qid)
                  dev_warn(ctrl->device, "qid %d: no key\n", qid);
                  return -ENOKEY;
          }
+       if (ctrl->opts->dhchap_ctrl_secret && !ctrl->ctrl_key) {
+               dev_warn(ctrl->device, "qid %d: invalid ctrl 
 key\n", qid);
+               return -ENOKEY;
+       }
 

         mutex_lock(&ctrl->dhchap_auth_mutex); /* Check if the context is already queued */

Quoted 2 lines

your issues are resolved?
Just to clarify before I sent another round of patches ...

No. I don't understand why this patch is needed. As I noted earlier, when I pass a wrong ctrl key I fail to connect do to authentication error. Also when I pass a malformed ctrl key.

Quoted 7 lines
Quoted 3 lines

So what does this patch fix? Can you give me an example that should have failed before and only with this patch it fails?

Reasoning is as follows:
When an invalid controller key is passed via 'ctrl->opts->dhchap_ctrl_secret' we'll end up with an empty 'ctrl->ctrl_key' in nvme_auth_init_ctrl() (which is what caused the original oops). But the negotiation will still start, and, seeing that 'ctrl->ctrl_key' is empty, will _not_ attempt controller authentication.
But as a controller key is passed from userland we should have attempted it, and hence an error is in order.

Yes, I see it now.
And the patch seems to work.

Quoted 4 lines
Quoted 2 lines

And for the other issue, please read it again, I think it is related to nvme-cli and not this patchset.

Hmm. Okay, I'll check, and possibly have to create another blktest for this ...

Looks like a libnvme fix makes the behavior go away:

src/nvme/fabrics.c +4 -1
index 53199a29e264..2dd863fb8b4c 100644
@@ -596,8 +596,11 @@ int nvmf_add_ctrl(nvme_host_t h, nvme_ctrl_t c,
                                          nvme_ctrl_get_host_iface(c),
                                          nvme_ctrl_get_trsvcid(c),
                                          NULL);
-               if (fc)
+               if (fc) {
                          cfg = merge_config(c, nvme_ctrl_get_config(fc));
+                       if (fc->dhchap_key)
+                               nvme_ctrl_set_dhchap_key(c, 
 fc->dhchap_key);
+               }
          }
 

         nvme_ctrl_set_discovered(c, true);

Signature · 2 lines
Looks like when we scan to see an existing controller in the config,
we find it, but merge_config does not touch the ctrl dhchap_key.
Quoted 6 lines
Quoted 3 lines

Maybe it would be better to just add the dhchap_key to the ctrl cfg and have merge_config merge it as well? Or we can live with dhchap_key merged explicitly?

Hmm. That runs slightly afoul of the merge logic. 'merge_config' will overwrite any value _not_ being the default.

There is no ctrl dhchap_key default though...

Quoted 1 line

Consequently, if a non-default value is already set it won't be overwritten.

Makes sense.

Quoted 1 line

Which means that if the 'cfg' structure already contained a controller secret (which could've been used, say, for discovery) we won't overwrite it in merge_config().

We probably shouldn't override it this way either if it was explicitly set by the user no?

Quoted 1 line

Hence I fear we have to go with your suggestion.

Whatever you choose. Don't really care...

Quoted 3 lines

Will be preparing a pull request.

Thanks

author maintainer
#19 lore raw

Re: [PATCH 06/11] nvme: Implement In-Band authentication

In reply to Sagi Grimberg
Quoted 10 lines · Sagi Grimberg
Quoted 7 lines · Hannes Reinecke
Quoted 6 lines · Sagi Grimberg

This one doesn't compile against nvme-5.20.

Quoted 3 lines

+    ret = __nvme_submit_sync_cmd(q, &cmd, NULL, data, data_len, 0, +                     qid == 0 ? NVME_QID_ANY : qid,
+                     0, flags);

Quoted 41 lines
Quoted 4 lines
Quoted 1 line

here ^^^^^^^

Sheesh. I've compiled it against nvme-5.19, where it works perfectly. Alright, once more unto the breach ...

Looks like if I pass a malformed ctrl key to nvme connect I am able to crash the system:

Signature · 33 lines
[   84.793307] Workqueue: nvme-wq __nvme_auth_work [nvme_core]
[   84.794790] RIP: 0010:nvme_auth_transform_key+0x19/0x1f0 [nvme_common]
[   84.796468] Code: bc f4 ff ff ff eb bf e8 f5 2f e1 ee 0f 1f 44 00 00 0f 1f 44 00 00 41 57 41 56 41 55 49 89 f5 41 54 55 53 48 89 fb 48 83 ec 08 <0f> b6 7f 10 e8 ce f9 ff ff 48 89 c7 0f b6 43 10 84 c0 0f 84 4c 01
[   84.800112] RSP: 0018:ffffae5f8047bc78 EFLAGS: 00010296
[   84.801048] RAX: ffff973b854ca0c0 RBX: 0000000000000000 RCX: 0000000000000000
[   84.802289] RDX: ffff973b8355b000 RSI: ffff973b84f568a0 RDI: 0000000000000000
[   84.803447] RBP: ffff973b842dd6b9 R08: 0000000000000003 R09: ffff973bbec308a8
[   84.804638] R10: 0000000000000147 R11: 0000000000000000 R12: ffff973b842dd600
[   84.805767] R13: ffff973b84f568a0 R14: 0000000000000000 R15: ffff973b9e94250d
[   84.806929] FS:  0000000000000000(0000) GS:ffff973bbec00000(0000) knlGS:0000000000000000
[   84.808220] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   84.809178] CR2: 0000000000000010 CR3: 00000000061ac003 CR4: 0000000000370ef0
[   84.810337] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   84.811432] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   84.812527] Call Trace:
[   84.812974]  <TASK>
[   84.813372]  nvme_auth_dhchap_setup_ctrl_response+0x4b/0x3b0 [nvme_core]
[   84.814355]  ? preempt_count_add+0x68/0xa0
[   84.815080]  ? _raw_spin_unlock_irq+0x16/0x28
[   84.815840]  ? __wait_for_common+0x19f/0x1d0
[   84.816587]  ? firmware_map_remove+0x87/0x87
[   84.817333]  ? blk_mq_hctx_has_pending+0x38/0x70
[   84.818123]  ? blk_mq_run_hw_queue+0x7d/0xe0
[   84.818784]  ? __blk_mq_free_request+0x9b/0xa0
[   84.819482]  ? blk_queue_exit+0xe/0x40
[   84.820124]  ? __nvme_submit_sync_cmd+0xe8/0x160 [nvme_core]
[   84.821096]  ? nvme_auth_submit+0x8f/0xd0 [nvme_core]
[   84.821970]  __nvme_auth_work+0x1fb/0x480 [nvme_core]
[   84.822869]  process_one_work+0x1e5/0x3b0
[   84.823608]  worker_thread+0x1c4/0x3a0
[   84.824343]  ? rescuer_thread+0x390/0x390
[   84.825044]  kthread+0xe8/0x110
-- 

Malformed exactly how?
We should've captured any malformed key during nvme_auth_extract_key(). Can you share an example of your malformed key?

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke                Kernel Storage Architect
[email protected]                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman
author maintainer
#20 lore raw

PATCH v15 7/11 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/common/auth.c | 153 ++++++++++++++++++++++++++++
 drivers/nvme/host/Kconfig  |   2 +
 drivers/nvme/host/auth.c   | 199 +++++++++++++++++++++++++++++++++++--
 include/linux/nvme-auth.h  |   8 ++
 4 files changed, 356 insertions(+), 6 deletions(-)
drivers/nvme/common/auth.c +153 -0
index 1cccaf6afdd2..945f6bb6eb1f 100644
@@ -301,6 +301,159 @@ u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
 }
 EXPORT_SYMBOL_GPL(nvme_auth_transform_key);
 
+static int nvme_auth_hash_skey(int hmac_id, u8 *skey, size_t skey_len, u8 *hkey)
+{
+	const char *digest_name;
+	struct crypto_shash *tfm;
+	int ret;
+
+	digest_name = nvme_auth_digest_name(hmac_id);
+	if (!digest_name) {
+		pr_debug("%s: failed to get digest for %d\n", __func__,
+			 hmac_id);
+		return -EINVAL;
+	}
+	tfm = crypto_alloc_shash(digest_name, 0, 0);
+	if (IS_ERR(tfm))
+		return -ENOMEM;
+
+	ret = crypto_shash_tfm_digest(tfm, skey, skey_len, hkey);
+	if (ret < 0)
+		pr_debug("%s: Failed to hash digest len %zu\n", __func__,
+			 skey_len);
+
+	crypto_free_shash(tfm);
+	return ret;
+}
+
+int nvme_auth_augmented_challenge(u8 hmac_id, u8 *skey, size_t skey_len,
+		u8 *challenge, u8 *aug, size_t hlen)
+{
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	u8 *hashed_key;
+	const char *hmac_name;
+	int ret;
+
+	hashed_key = kmalloc(hlen, GFP_KERNEL);
+	if (!hashed_key)
+		return -ENOMEM;
+
+	ret = nvme_auth_hash_skey(hmac_id, skey,
+				  skey_len, hashed_key);
+	if (ret < 0)
+		goto out_free_key;
+
+	hmac_name = nvme_auth_hmac_name(hmac_id);
+	if (!hmac_name) {
+		pr_warn("%s: invalid hash algoritm %d\n",
+			__func__, hmac_id);
+		ret = -EINVAL;
+		goto out_free_key;
+	}
+
+	tfm = crypto_alloc_shash(hmac_name, 0, 0);
+	if (IS_ERR(tfm)) {
+		ret = PTR_ERR(tfm);
+		goto out_free_key;
+	}
+
+	desc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(tfm),
+		       GFP_KERNEL);
+	if (!desc) {
+		ret = -ENOMEM;
+		goto out_free_hash;
+	}
+	desc->tfm = tfm;
+
+	ret = crypto_shash_setkey(tfm, hashed_key, hlen);
+	if (ret)
+		goto out_free_desc;
+
+	ret = crypto_shash_init(desc);
+	if (ret)
+		goto out_free_desc;
+
+	ret = crypto_shash_update(desc, challenge, hlen);
+	if (ret)
+		goto out_free_desc;
+
+	ret = crypto_shash_final(desc, aug);
+out_free_desc:
+	kfree_sensitive(desc);
+out_free_hash:
+	crypto_free_shash(tfm);
+out_free_key:
+	kfree_sensitive(hashed_key);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(nvme_auth_augmented_challenge);
+
+int nvme_auth_gen_privkey(struct crypto_kpp *dh_tfm, u8 dh_gid)
+{
+	int ret;
+
+	ret = crypto_kpp_set_secret(dh_tfm, NULL, 0);
+	if (ret)
+		pr_debug("failed to set private key, error %d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(nvme_auth_gen_privkey);
+
+int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm,
+		u8 *host_key, size_t host_key_len)
+{
+	struct kpp_request *req;
+	struct crypto_wait wait;
+	struct scatterlist dst;
+	int ret;
+
+	req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	crypto_init_wait(&wait);
+	kpp_request_set_input(req, NULL, 0);
+	sg_init_one(&dst, host_key, host_key_len);
+	kpp_request_set_output(req, &dst, host_key_len);
+	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				 crypto_req_done, &wait);
+
+	ret = crypto_wait_req(crypto_kpp_generate_public_key(req), &wait);
+	kpp_request_free(req);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(nvme_auth_gen_pubkey);
+
+int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm,
+		u8 *ctrl_key, size_t ctrl_key_len,
+		u8 *sess_key, size_t sess_key_len)
+{
+	struct kpp_request *req;
+	struct crypto_wait wait;
+	struct scatterlist src, dst;
+	int ret;
+
+	req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	crypto_init_wait(&wait);
+	sg_init_one(&src, ctrl_key, ctrl_key_len);
+	kpp_request_set_input(req, &src, ctrl_key_len);
+	sg_init_one(&dst, sess_key, sess_key_len);
+	kpp_request_set_output(req, &dst, sess_key_len);
+	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				 crypto_req_done, &wait);
+
+	ret = crypto_wait_req(crypto_kpp_compute_shared_secret(req), &wait);
+
+	kpp_request_free(req);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(nvme_auth_gen_shared_secret);
+
 int nvme_auth_generate_key(u8 *secret, struct nvme_dhchap_key **ret_key)
 {
 	struct nvme_dhchap_key *key;
drivers/nvme/host/Kconfig +2 -0
index 6c503f42f3c6..2f6a7f8c94e8 100644
@@ -100,6 +100,8 @@ config NVME_AUTH
 	select CRYPTO_HMAC
 	select CRYPTO_SHA256
 	select CRYPTO_SHA512
+	select CRYPTO_DH
+	select CRYPTO_DH_RFC7919_GROUPS
 	help
 	  This provides support for NVMe over Fabrics In-Band Authentication.
 
drivers/nvme/host/auth.c +193 -6

285 lines not on this page · raw message

include/linux/nvme-auth.h +8 -0
index 354456826221..dcb8030062dd 100644
@@ -29,5 +29,13 @@ struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
 void nvme_auth_free_key(struct nvme_dhchap_key *key);
 u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn);
 int nvme_auth_generate_key(u8 *secret, struct nvme_dhchap_key **ret_key);
+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, u8 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 */
Signature · 1 line
2.29.2
author maintainer
#21 lore raw

PATCH v15 8/11 nvmet: parse fabrics commands on io queues

In reply to Hannes Reinecke

Some fabrics commands can be sent via io queues, so add a new function nvmet_parse_fabrics_io_cmd() and rename the existing nvmet_parse_fabrics_cmd() to nvmet_parse_fabrics_admin_cmd().

---
 drivers/nvme/target/admin-cmd.c   |  2 +-
 drivers/nvme/target/core.c        |  4 ++++
 drivers/nvme/target/fabrics-cmd.c | 17 ++++++++++++++++-
 drivers/nvme/target/nvmet.h       |  3 ++-
 4 files changed, 23 insertions(+), 3 deletions(-)
drivers/nvme/target/admin-cmd.c +1 -1
index 397daaf51f1b..31df40ac828f 100644
@@ -1017,7 +1017,7 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
 	u16 ret;
 
 	if (nvme_is_fabrics(cmd))
-		return nvmet_parse_fabrics_cmd(req);
+		return nvmet_parse_fabrics_admin_cmd(req);
 	if (nvmet_is_disc_subsys(nvmet_req_subsys(req)))
 		return nvmet_parse_discovery_cmd(req);
 
drivers/nvme/target/core.c +4 -0
index 90e75324dae0..792f15621173 100644
@@ -865,8 +865,12 @@ static inline u16 nvmet_io_cmd_check_access(struct nvmet_req *req)
 
 static u16 nvmet_parse_io_cmd(struct nvmet_req *req)
 {
+	struct nvme_command *cmd = req->cmd;
 	u16 ret;
 
+	if (nvme_is_fabrics(cmd))
+		return nvmet_parse_fabrics_io_cmd(req);
+
 	ret = nvmet_check_ctrl_status(req);
 	if (unlikely(ret))
 		return ret;
drivers/nvme/target/fabrics-cmd.c +16 -1
index 70fb587e9413..f23c28729908 100644
@@ -82,7 +82,7 @@ static void nvmet_execute_prop_get(struct nvmet_req *req)
 	nvmet_req_complete(req, status);
 }
 
-u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req)
+u16 nvmet_parse_fabrics_admin_cmd(struct nvmet_req *req)
 {
 	struct nvme_command *cmd = req->cmd;
 
@@ -103,6 +103,21 @@ u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req)
 	return 0;
 }
 
+u16 nvmet_parse_fabrics_io_cmd(struct nvmet_req *req)
+{
+	struct nvme_command *cmd = req->cmd;
+
+	switch (cmd->fabrics.fctype) {
+	default:
+		pr_debug("received unknown capsule type 0x%x\n",
+			cmd->fabrics.fctype);
+		req->error_loc = offsetof(struct nvmf_common_command, fctype);
+		return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
+	}
+
+	return 0;
+}
+
 static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
 {
 	struct nvmf_connect_command *c = &req->cmd->connect;
drivers/nvme/target/nvmet.h +2 -1
index 69818752a33a..c37f41eafc2f 100644
@@ -419,7 +419,8 @@ u16 nvmet_file_parse_io_cmd(struct nvmet_req *req);
 u16 nvmet_bdev_zns_parse_io_cmd(struct nvmet_req *req);
 u16 nvmet_parse_admin_cmd(struct nvmet_req *req);
 u16 nvmet_parse_discovery_cmd(struct nvmet_req *req);
-u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req);
+u16 nvmet_parse_fabrics_admin_cmd(struct nvmet_req *req);
+u16 nvmet_parse_fabrics_io_cmd(struct nvmet_req *req);
 
 bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
 		struct nvmet_sq *sq, const struct nvmet_fabrics_ops *ops);
Signature · 1 line
2.29.2
author maintainer
#22 lore raw

PATCH v15 9/11 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 written to to switch to a different HMAC algorithm.

---
 drivers/nvme/target/Kconfig            |  13 +
 drivers/nvme/target/Makefile           |   1 +
 drivers/nvme/target/admin-cmd.c        |   2 +
 drivers/nvme/target/auth.c             | 367 ++++++++++++++++++
 drivers/nvme/target/configfs.c         | 107 +++++-
 drivers/nvme/target/core.c             |  11 +
 drivers/nvme/target/fabrics-cmd-auth.c | 502 +++++++++++++++++++++++++
 drivers/nvme/target/fabrics-cmd.c      |  38 +-
 drivers/nvme/target/nvmet.h            |  62 +++
 9 files changed, 1100 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 +13 -0
index 973561c93888..df526b59b509 100644
@@ -83,3 +83,16 @@ 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 NVME_COMMON
+	select CRYPTO
+	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 +2 -0
index 31df40ac828f..fc8a957fad0a 100644
@@ -1018,6 +1018,8 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
 
 	if (nvme_is_fabrics(cmd))
 		return nvmet_parse_fabrics_admin_cmd(req);
+	if (unlikely(!nvmet_check_auth_status(req)))
+		return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR;
 	if (nvmet_is_disc_subsys(nvmet_req_subsys(req)))
 		return nvmet_parse_discovery_cmd(req);
 
drivers/nvme/target/auth.c new file +367 -0

367 lines not on this page · raw message

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

134 lines not on this page · raw message

drivers/nvme/target/core.c +11 -0
index 792f15621173..eec0351e1022 100644
@@ -795,6 +795,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) {
 		/*
@@ -871,6 +872,9 @@ static u16 nvmet_parse_io_cmd(struct nvmet_req *req)
 	if (nvme_is_fabrics(cmd))
 		return nvmet_parse_fabrics_io_cmd(req);
 
+	if (unlikely(!nvmet_check_auth_status(req)))
+		return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR;
+
 	ret = nvmet_check_ctrl_status(req);
 	if (unlikely(ret))
 		return ret;
@@ -1275,6 +1279,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;
 }
 
@@ -1465,6 +1474,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_free(&cntlid_ida, ctrl->cntlid);
 
 	nvmet_async_events_free(ctrl);
drivers/nvme/target/fabrics-cmd-auth.c new file +502 -0

502 lines not on this page · raw message

drivers/nvme/target/fabrics-cmd.c +36 -2
index f23c28729908..f91a56180d3d 100644
@@ -93,6 +93,14 @@ u16 nvmet_parse_fabrics_admin_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);
@@ -108,6 +116,14 @@ u16 nvmet_parse_fabrics_io_cmd(struct nvmet_req *req)
 	struct nvme_command *cmd = req->cmd;
 
 	switch (cmd->fabrics.fctype) {
+#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);
@@ -188,6 +204,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;
@@ -230,18 +247,32 @@ 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 %s controller %d for subsystem %s for NQN %s%s.\n",
+	pr_info("creating %s controller %d for subsystem %s for NQN %s%s%s.\n",
 		nvmet_is_disc_subsys(ctrl->subsys) ? "discovery" : "nvm",
 		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:
@@ -301,6 +332,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 +62 -0

84 lines not on this page · raw message

Signature · 1 line
2.29.2
author maintainer
#23 lore raw

PATCH v15 10/11 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            |   2 +
 drivers/nvme/target/auth.c             | 157 +++++++++++++++++++++++++
 drivers/nvme/target/configfs.c         |  31 +++++
 drivers/nvme/target/fabrics-cmd-auth.c |  41 +++++--
 drivers/nvme/target/nvmet.h            |   9 ++
 5 files changed, 232 insertions(+), 8 deletions(-)
drivers/nvme/target/Kconfig +2 -0
index df526b59b509..f0c91f7686a3 100644
@@ -92,6 +92,8 @@ config NVME_TARGET_AUTH
 	select CRYPTO_HMAC
 	select CRYPTO_SHA256
 	select CRYPTO_SHA512
+	select CRYPTO_DH
+	select CRYPTO_DH_GROUPS_RFC7919
 	help
 	  This enables support for NVMe over Fabrics In-band Authentication
 
drivers/nvme/target/auth.c +157 -0

190 lines not on this page · raw message

drivers/nvme/target/configfs.c +31 -0
index 9a7d91c64fcd..1b11f6a83bb6 100644
@@ -1746,10 +1746,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 == NVME_AUTH_DHGROUP_INVALID)
+		return -EINVAL;
+	if (dhgroup_id != NVME_AUTH_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 +33 -8

84 lines not on this page · raw message

drivers/nvme/target/nvmet.h +9 -0
index 765db7541a87..8b239aec3ca2 100644
@@ -225,6 +225,10 @@ struct nvmet_ctrl {
 	struct nvme_dhchap_key	*host_key;
 	struct nvme_dhchap_key	*ctrl_key;
 	u8			shash_id;
+	struct crypto_kpp	*dh_tfm;
+	u8			dh_gid;
+	u8			*dh_key;
+	size_t			dh_keysize;
 #endif
 };
 
@@ -701,6 +705,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, u8 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);
@@ -710,6 +715,10 @@ static inline bool nvmet_has_auth(struct nvmet_ctrl *ctrl)
 {
 	return ctrl->host_key != 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
#24 lore raw

PATCH v15 11/11 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 d5624bdf834b..bf92435c783c 100644
@@ -218,6 +218,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 5b1be7e607e2..cc56e8c821ce 100644
@@ -12,11 +12,24 @@
 #include <crypto/kpp.h>
 #include "nvmet.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)
 {
 	u32 result = le32_to_cpu(req->cqe->result.u32);
 
 	/* 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;
 	result |= (u32)NVME_CONNECT_AUTHREQ_ATR << 16;
@@ -333,8 +346,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 8b239aec3ca2..829fb1d78ee1 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