Commit b2dcccf3 authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Jim Harris
Browse files

nvmf/auth: execute AUTH_negotiate message



This negotiates parameters of the authentication transaction between the
host and the target.  Currently, this boils down to selecting the hash
function to use, as neither Diffie-Hellman, nor scc will be supported
initially.

Signed-off-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Change-Id: I86d6df742f1a7da56545292f703093e0e51fd5bd
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/22660


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarBen Walker <ben@nvidia.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Reviewed-by: default avatarSeung yeon Shin <syeon.shin@samsung.com>
parent 52939f25
Loading
Loading
Loading
Loading
+175 −3
Original line number Diff line number Diff line
@@ -2,10 +2,12 @@
 * Copyright (c) 2024 Intel Corporation
 */

#include "spdk/nvme.h"
#include "spdk/log.h"
#include "spdk/stdinc.h"
#include "spdk/string.h"
#include "spdk/thread.h"
#include "spdk/util.h"

#include "nvmf_internal.h"

@@ -20,12 +22,24 @@

enum nvmf_qpair_auth_state {
	NVMF_QPAIR_AUTH_NEGOTIATE,
	NVMF_QPAIR_AUTH_CHALLENGE,
	NVMF_QPAIR_AUTH_FAILURE1,
	NVMF_QPAIR_AUTH_ERROR,
};

struct spdk_nvmf_qpair_auth {
	enum nvmf_qpair_auth_state	state;
	struct spdk_poller		*poller;
	int				fail_reason;
	uint16_t			tid;
	int				digest;
};

struct nvmf_auth_common_header {
	uint8_t		auth_type;
	uint8_t		auth_id;
	uint8_t		reserved0[2];
	uint16_t	t_id;
};

static void
@@ -40,11 +54,13 @@ nvmf_auth_request_complete(struct spdk_nvmf_request *req, int sct, int sc, int d
	spdk_nvmf_request_complete(req);
}

__attribute__((unused)) static const char *
static const char *
nvmf_auth_get_state_name(enum nvmf_qpair_auth_state state)
{
	static const char *state_names[] = {
		[NVMF_QPAIR_AUTH_NEGOTIATE] = "negotiate",
		[NVMF_QPAIR_AUTH_CHALLENGE] = "challenge",
		[NVMF_QPAIR_AUTH_FAILURE1] = "failure1",
		[NVMF_QPAIR_AUTH_ERROR] = "error",
	};

@@ -71,6 +87,21 @@ nvmf_auth_disconnect_qpair(struct spdk_nvmf_qpair *qpair)
	spdk_nvmf_qpair_disconnect(qpair);
}

static void
nvmf_auth_request_fail1(struct spdk_nvmf_request *req, int reason)
{
	struct spdk_nvmf_qpair *qpair = req->qpair;
	struct spdk_nvmf_qpair_auth *auth = qpair->auth;

	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_FAILURE1);
	auth->fail_reason = reason;

	/* The command itself is completed successfully, but a subsequent AUTHENTICATION_RECV
	 * command will be completed with an AUTH_failure1 message
	 */
	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
}

static int
nvmf_auth_timeout_poller(void *ctx)
{
@@ -127,10 +158,129 @@ nvmf_auth_check_command(struct spdk_nvmf_request *req, uint8_t secp,
	return 0;
}

static void *
nvmf_auth_get_message(struct spdk_nvmf_request *req, size_t size)
{
	if (req->length > 0 && req->iovcnt == 1 && req->iov[0].iov_len >= size) {
		return req->iov[0].iov_base;
	}

	return NULL;
}

static void
nvmf_auth_negotiate_exec(struct spdk_nvmf_request *req, struct spdk_nvmf_auth_negotiate *msg)
{
	struct spdk_nvmf_qpair *qpair = req->qpair;
	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
	struct spdk_nvmf_auth_descriptor *desc = NULL;
	/* These arrays are sorted from the strongest hash/dhgroup to the weakest, so the strongest
	 * hash/dhgroup pair supported by the host is always selected
	 */
	enum spdk_nvmf_dhchap_hash digests[] = {
		SPDK_NVMF_DHCHAP_HASH_SHA512,
		SPDK_NVMF_DHCHAP_HASH_SHA384,
		SPDK_NVMF_DHCHAP_HASH_SHA256
	};
	enum spdk_nvmf_dhchap_dhgroup dhgroups[] = {
		SPDK_NVMF_DHCHAP_DHGROUP_NULL,
	};
	int digest = -1, dhgroup = -1;
	size_t i, j;

	if (auth->state != NVMF_QPAIR_AUTH_NEGOTIATE) {
		AUTH_ERRLOG(qpair, "invalid state: %s\n", nvmf_auth_get_state_name(auth->state));
		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
		return;
	}

	auth->tid = msg->t_id;
	if (req->length < sizeof(*msg) || req->length != sizeof(*msg) + msg->napd * sizeof(*desc)) {
		AUTH_ERRLOG(qpair, "invalid message length: %"PRIu32"\n", req->length);
		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
		return;
	}

	if (msg->sc_c != SPDK_NVMF_AUTH_SCC_DISABLED) {
		AUTH_ERRLOG(qpair, "scc mismatch\n");
		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_SCC_MISMATCH);
		return;
	}

	for (i = 0; i < msg->napd; ++i) {
		if (msg->descriptors[i].auth_id == SPDK_NVMF_AUTH_TYPE_DHCHAP) {
			desc = &msg->descriptors[i];
			break;
		}
	}
	if (desc == NULL) {
		AUTH_ERRLOG(qpair, "no usable protocol found\n");
		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_PROTOCOL_UNUSABLE);
		return;
	}
	if (desc->halen > SPDK_COUNTOF(desc->hash_id_list) ||
	    desc->dhlen > SPDK_COUNTOF(desc->dhg_id_list)) {
		AUTH_ERRLOG(qpair, "invalid halen=%u, dhlen=%u\n", desc->halen, desc->dhlen);
		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
		return;
	}

	for (i = 0; i < SPDK_COUNTOF(digests); ++i) {
		for (j = 0; j < desc->halen; ++j) {
			if (digests[i] == desc->hash_id_list[j]) {
				AUTH_DEBUGLOG(qpair, "selected digest: %s\n",
					      spdk_nvme_dhchap_get_digest_name(digests[i]));
				digest = digests[i];
				break;
			}
		}
		if (digest >= 0) {
			break;
		}
	}
	if (digest < 0) {
		AUTH_ERRLOG(qpair, "no usable digests found\n");
		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_HASH_UNUSABLE);
		return;
	}

	for (i = 0; i < SPDK_COUNTOF(dhgroups); ++i) {
		for (j = 0; j < desc->dhlen; ++j) {
			if (dhgroups[i] == desc->dhg_id_list[j]) {
				AUTH_DEBUGLOG(qpair, "selected dhgroup: %s\n",
					      spdk_nvme_dhchap_get_dhgroup_name(dhgroups[i]));
				dhgroup = dhgroups[i];
				break;
			}
		}
		if (dhgroup >= 0) {
			break;
		}
	}
	if (dhgroup < 0) {
		AUTH_ERRLOG(qpair, "no usable dhgroups found\n");
		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_DHGROUP_UNUSABLE);
		return;
	}

	if (nvmf_auth_rearm_poller(qpair)) {
		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
					   SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 1);
		nvmf_auth_disconnect_qpair(qpair);
		return;
	}

	auth->digest = digest;
	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_CHALLENGE);
	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
}

static void
nvmf_auth_send_exec(struct spdk_nvmf_request *req)
{
	struct spdk_nvmf_qpair *qpair = req->qpair;
	struct spdk_nvmf_fabric_auth_send_cmd *cmd = &req->cmd->auth_send_cmd;
	struct nvmf_auth_common_header *header;
	int rc;

	rc = nvmf_auth_check_command(req, cmd->secp, cmd->spsp0, cmd->spsp1, cmd->tl);
@@ -140,8 +290,29 @@ nvmf_auth_send_exec(struct spdk_nvmf_request *req)
		return;
	}

	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
				   SPDK_NVME_SC_INVALID_OPCODE, 1);
	header = nvmf_auth_get_message(req, sizeof(*header));
	if (header == NULL) {
		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
		return;
	}

	switch (header->auth_type) {
	case SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE:
		switch (header->auth_id) {
		case SPDK_NVMF_AUTH_ID_NEGOTIATE:
			nvmf_auth_negotiate_exec(req, (void *)header);
			break;
		default:
			AUTH_ERRLOG(qpair, "unexpected auth_id=%u\n", header->auth_id);
			nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
			break;
		}
		break;
	case SPDK_NVMF_AUTH_TYPE_DHCHAP:
	default:
		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
		break;
	}
}

static void
@@ -204,6 +375,7 @@ nvmf_qpair_auth_init(struct spdk_nvmf_qpair *qpair)
		return -ENOMEM;
	}

	auth->digest = -1;
	qpair->auth = auth;
	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_NEGOTIATE);

+240 −0
Original line number Diff line number Diff line
@@ -55,12 +55,14 @@ test_auth_send_recv_error(void)
	struct spdk_nvme_cpl *cpl = &rsp.nvme_cpl;
	struct spdk_nvmf_fabric_auth_send_cmd send_cmd = {};
	struct spdk_nvmf_fabric_auth_recv_cmd recv_cmd = {};
	struct spdk_nvmf_qpair_auth *auth;
	int rc;

	rc = nvmf_qpair_auth_init(&qpair);
	SPDK_CU_ASSERT_FATAL(rc == 0);
	ut_prep_send_cmd(&req, &send_cmd, NULL, 255);
	ut_prep_recv_cmd(&req, &recv_cmd, NULL, 255);
	auth = qpair.auth;

	/* Bad secp (send) */
	g_req_completed = false;
@@ -166,6 +168,243 @@ test_auth_send_recv_error(void)
	CU_ASSERT_EQUAL(cpl->status.dnr, 1);
	recv_cmd.al = req.length;

	/* Bad length (smaller than common header) */
	g_req_completed = false;
	req.cmd = (union nvmf_h2c_msg *)&send_cmd;
	ut_clear_resp(&req);
	send_cmd.tl = req.length = sizeof(struct nvmf_auth_common_header) - 1;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
	send_cmd.tl = req.length = 255;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	auth->fail_reason = 0;

	nvmf_qpair_auth_destroy(&qpair);
}

static void
test_auth_negotiate(void)
{
	union nvmf_c2h_msg rsp = {};
	struct spdk_nvmf_subsystem subsys = {};
	struct spdk_nvmf_ctrlr ctrlr = { .subsys = &subsys };
	struct spdk_nvmf_qpair qpair = { .ctrlr = &ctrlr };
	struct spdk_nvmf_request req = { .qpair = &qpair, .rsp = &rsp };
	struct spdk_nvmf_fabric_auth_send_cmd cmd = {};
	struct spdk_nvmf_qpair_auth *auth;
	struct spdk_nvmf_auth_negotiate *msg;
	struct spdk_nvmf_auth_descriptor *desc;
	uint8_t msgbuf[4096];
	int rc;

	msg = (void *)msgbuf;
	rc = nvmf_qpair_auth_init(&qpair);
	SPDK_CU_ASSERT_FATAL(rc == 0);
	ut_prep_send_cmd(&req, &cmd, msgbuf, sizeof(*msg) + sizeof(*desc));
	auth = qpair.auth;

	/* Successful negotiation */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	msg->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE;
	msg->auth_id = SPDK_NVMF_AUTH_ID_NEGOTIATE;
	msg->sc_c = SPDK_NVMF_AUTH_SCC_DISABLED;
	msg->napd = 1;
	desc = &msg->descriptors[0];
	desc->auth_id = SPDK_NVMF_AUTH_TYPE_DHCHAP;
	desc->halen = 3;
	desc->hash_id_list[0] = SPDK_NVMF_DHCHAP_HASH_SHA256;
	desc->hash_id_list[1] = SPDK_NVMF_DHCHAP_HASH_SHA384;
	desc->hash_id_list[2] = SPDK_NVMF_DHCHAP_HASH_SHA512;
	desc->dhlen = 6;
	desc->dhg_id_list[0] = SPDK_NVMF_DHCHAP_DHGROUP_NULL;
	desc->dhg_id_list[1] = SPDK_NVMF_DHCHAP_DHGROUP_2048;
	desc->dhg_id_list[2] = SPDK_NVMF_DHCHAP_DHGROUP_3072;
	desc->dhg_id_list[3] = SPDK_NVMF_DHCHAP_DHGROUP_4096;
	desc->dhg_id_list[4] = SPDK_NVMF_DHCHAP_DHGROUP_6144;
	desc->dhg_id_list[5] = SPDK_NVMF_DHCHAP_DHGROUP_8192;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, SPDK_NVMF_DHCHAP_HASH_SHA512);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_CHALLENGE);

	/* Invalid auth state */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_ERROR;
	auth->digest = -1;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);

	/* scc mismatch */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	msg->sc_c = SPDK_NVMF_AUTH_SCC_TLS;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_SCC_MISMATCH);
	msg->sc_c = SPDK_NVMF_AUTH_SCC_DISABLED;

	/* Missing DH-HMAC-CHAP protocol (napd=0) */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg);
	msg->napd = 0;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_PROTOCOL_UNUSABLE);
	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg) + sizeof(*desc);
	msg->napd = 1;

	/* Missing DH-HMAC-CHAP protocol */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	desc->auth_id = SPDK_NVMF_AUTH_TYPE_DHCHAP + 1;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_PROTOCOL_UNUSABLE);
	desc->auth_id = SPDK_NVMF_AUTH_TYPE_DHCHAP;

	/* No valid digests (halen=0) */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	desc->halen = 0;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_HASH_UNUSABLE);

	/* No valid digests */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	desc->hash_id_list[0] = SPDK_NVMF_DHCHAP_HASH_SHA512 + 1;
	desc->hash_id_list[1] = SPDK_NVMF_DHCHAP_HASH_SHA512 + 2;
	desc->hash_id_list[2] = SPDK_NVMF_DHCHAP_HASH_SHA512 + 3;
	desc->halen = 3;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_HASH_UNUSABLE);
	desc->hash_id_list[0] = SPDK_NVMF_DHCHAP_HASH_SHA256;
	desc->hash_id_list[1] = SPDK_NVMF_DHCHAP_HASH_SHA384;
	desc->hash_id_list[2] = SPDK_NVMF_DHCHAP_HASH_SHA512;

	/* No valid dhgroups (dhlen=0) */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	desc->dhlen = 0;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_DHGROUP_UNUSABLE);

	/* No valid dhgroups */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	desc->dhlen = 2;
	desc->dhg_id_list[0] = SPDK_NVMF_DHCHAP_DHGROUP_8192 + 1;
	desc->dhg_id_list[1] = SPDK_NVMF_DHCHAP_DHGROUP_8192 + 2;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_DHGROUP_UNUSABLE);
	desc->dhg_id_list[0] = SPDK_NVMF_DHCHAP_DHGROUP_NULL;
	desc->dhg_id_list[1] = SPDK_NVMF_DHCHAP_DHGROUP_2048;
	desc->dhlen = 6;

	/* Bad halen value */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	desc->halen = 255;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
	desc->halen = 3;

	/* Bad dhlen value */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	desc->dhlen = 255;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
	desc->dhlen = 6;

	/* Invalid request length (too small) */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg) - 1;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);

	/* Invalid request length (too small) */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg);

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);

	/* Invalid request length (too small) */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg) + sizeof(*desc) - 1;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);

	/* Invalid request length (too large) */
	g_req_completed = false;
	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg) + sizeof(*desc) + 1;

	nvmf_auth_send_exec(&req);
	CU_ASSERT(g_req_completed);
	CU_ASSERT_EQUAL(auth->digest, -1);
	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg) + sizeof(*desc);

	nvmf_qpair_auth_destroy(&qpair);
}

@@ -178,6 +417,7 @@ main(int argc, char **argv)
	CU_initialize_registry();
	suite = CU_add_suite("nvmf_auth", NULL, NULL);
	CU_ADD_TEST(suite, test_auth_send_recv_error);
	CU_ADD_TEST(suite, test_auth_negotiate);

	allocate_threads(1);
	set_thread(0);