xref: /spdk/test/unit/lib/nvmf/auth.c/auth_ut.c (revision 7b8c7efe8fe5cbfb09d5ebff2fbad7ce49c7504d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2024 Intel Corporation. All rights reserved.
3  */
4 #include "spdk/stdinc.h"
5 
6 #include "spdk_internal/cunit.h"
7 #include "spdk_internal/mock.h"
8 
9 #include "common/lib/ut_multithread.c"
10 #include "unit/lib/json_mock.c"
11 #include "nvmf/auth.c"
12 
13 DEFINE_STUB(spdk_nvme_dhchap_get_digest_name, const char *, (int d), NULL);
14 DEFINE_STUB(spdk_nvme_dhchap_get_dhgroup_name, const char *, (int d), NULL);
15 DEFINE_STUB(spdk_nvme_dhchap_get_digest_length, uint8_t, (int d), 0);
16 DEFINE_STUB_V(spdk_keyring_put_key, (struct spdk_key *k));
17 DEFINE_STUB(nvmf_subsystem_get_dhchap_key, struct spdk_key *,
18 	    (struct spdk_nvmf_subsystem *s, const char *h, enum nvmf_auth_key_type t), NULL);
19 DEFINE_STUB(spdk_nvme_dhchap_generate_dhkey, struct spdk_nvme_dhchap_dhkey *,
20 	    (enum spdk_nvmf_dhchap_dhgroup dhgroup), NULL);
21 DEFINE_STUB_V(spdk_nvme_dhchap_dhkey_free, (struct spdk_nvme_dhchap_dhkey **key));
22 DEFINE_STUB(spdk_nvme_dhchap_dhkey_derive_secret, int,
23 	    (struct spdk_nvme_dhchap_dhkey *key, const void *peer, size_t peerlen, void *secret,
24 	     size_t *seclen), 0);
25 DECLARE_WRAPPER(RAND_bytes, int, (unsigned char *buf, int num));
26 
27 static uint8_t g_rand_val;
28 DEFINE_WRAPPER_MOCK(RAND_bytes, int) = 1;
29 
30 int
31 __wrap_RAND_bytes(unsigned char *buf, int num)
32 {
33 	memset(buf, g_rand_val, num);
34 	return MOCK_GET(RAND_bytes);
35 }
36 
37 void
38 nvmf_qpair_set_state(struct spdk_nvmf_qpair *qpair, enum spdk_nvmf_qpair_state state)
39 {
40 	qpair->state = state;
41 }
42 
43 int
44 spdk_nvmf_qpair_disconnect(struct spdk_nvmf_qpair *qpair)
45 {
46 	nvmf_qpair_set_state(qpair, SPDK_NVMF_QPAIR_ERROR);
47 	return 0;
48 }
49 
50 static bool g_req_completed;
51 
52 int
53 spdk_nvmf_request_complete(struct spdk_nvmf_request *req)
54 {
55 	g_req_completed = true;
56 	return 0;
57 }
58 
59 static uint8_t g_rval;
60 DEFINE_RETURN_MOCK(spdk_nvme_dhchap_calculate, int);
61 
62 int
63 spdk_nvme_dhchap_calculate(struct spdk_key *key, enum spdk_nvmf_dhchap_hash hash,
64 			   const char *type, uint32_t seq, uint16_t tid, uint8_t scc,
65 			   const char *nqn1, const char *nqn2, const void *dhkey, size_t dhlen,
66 			   const void *cval, void *rval)
67 {
68 	memset(rval, g_rval, spdk_nvme_dhchap_get_digest_length(hash));
69 	return MOCK_GET(spdk_nvme_dhchap_calculate);
70 }
71 
72 static uint8_t g_dhv;
73 static size_t g_dhvlen;
74 DEFINE_RETURN_MOCK(spdk_nvme_dhchap_dhkey_get_pubkey, int);
75 
76 int
77 spdk_nvme_dhchap_dhkey_get_pubkey(struct spdk_nvme_dhchap_dhkey *dhkey, void *pub, size_t *len)
78 {
79 	int rc;
80 
81 	rc = MOCK_GET(spdk_nvme_dhchap_dhkey_get_pubkey);
82 	if (rc != 0) {
83 		return rc;
84 	}
85 
86 	SPDK_CU_ASSERT_FATAL(*len >= g_dhvlen);
87 	memset(pub, g_dhv, g_dhvlen);
88 	*len = g_dhvlen;
89 
90 	return rc;
91 }
92 
93 static void
94 ut_clear_resp(struct spdk_nvmf_request *req)
95 {
96 	memset(&req->rsp->nvme_cpl, 0, sizeof(req->rsp->nvme_cpl));
97 }
98 
99 #define ut_prep_cmd(_req, _cmd, _buf, _len, _lfield)		\
100 	do {							\
101 		(_req)->cmd = (void *)_cmd;			\
102 		(_req)->iov[0].iov_base = _buf;			\
103 		(_req)->iov[0].iov_len = _len;			\
104 		(_req)->iovcnt = 1;				\
105 		(_req)->length = _len;				\
106 		(_cmd)->secp = SPDK_NVMF_AUTH_SECP_NVME;	\
107 		(_cmd)->spsp0 = 1;				\
108 		(_cmd)->spsp1 = 1;				\
109 		(_cmd)->_lfield = _len;				\
110 	} while (0)
111 
112 #define ut_prep_send_cmd(req, cmd, buf, len) ut_prep_cmd(req, cmd, buf, len, tl)
113 #define ut_prep_recv_cmd(req, cmd, buf, len) ut_prep_cmd(req, cmd, buf, len, al)
114 
115 static void
116 test_auth_send_recv_error(void)
117 {
118 	union nvmf_c2h_msg rsp = {};
119 	struct spdk_nvmf_subsystem subsys = {};
120 	struct spdk_nvmf_ctrlr ctrlr = { .subsys = &subsys };
121 	struct spdk_nvmf_qpair qpair = { .ctrlr = &ctrlr };
122 	struct spdk_nvmf_request req = { .qpair = &qpair, .rsp = &rsp };
123 	struct spdk_nvme_cpl *cpl = &rsp.nvme_cpl;
124 	struct spdk_nvmf_fabric_auth_send_cmd send_cmd = {};
125 	struct spdk_nvmf_fabric_auth_recv_cmd recv_cmd = {};
126 	struct spdk_nvmf_qpair_auth *auth;
127 	int rc;
128 
129 	rc = nvmf_qpair_auth_init(&qpair);
130 	SPDK_CU_ASSERT_FATAL(rc == 0);
131 	ut_prep_send_cmd(&req, &send_cmd, NULL, 255);
132 	ut_prep_recv_cmd(&req, &recv_cmd, NULL, 255);
133 	auth = qpair.auth;
134 
135 	/* Bad secp (send) */
136 	g_req_completed = false;
137 	req.cmd = (void *)&send_cmd;
138 	ut_clear_resp(&req);
139 	send_cmd.secp = SPDK_NVMF_AUTH_SECP_NVME + 1;
140 
141 	nvmf_auth_send_exec(&req);
142 	CU_ASSERT(g_req_completed);
143 	CU_ASSERT_EQUAL(cpl->status.sct, SPDK_NVME_SCT_GENERIC);
144 	CU_ASSERT_EQUAL(cpl->status.sc, SPDK_NVME_SC_INVALID_FIELD);
145 	CU_ASSERT_EQUAL(cpl->status.dnr, 1);
146 	send_cmd.secp = SPDK_NVMF_AUTH_SECP_NVME;
147 
148 	/* Bad secp (recv) */
149 	g_req_completed = false;
150 	req.cmd = (void *)&recv_cmd;
151 	ut_clear_resp(&req);
152 	recv_cmd.secp = SPDK_NVMF_AUTH_SECP_NVME + 1;
153 
154 	nvmf_auth_recv_exec(&req);
155 	CU_ASSERT(g_req_completed);
156 	CU_ASSERT_EQUAL(cpl->status.sct, SPDK_NVME_SCT_GENERIC);
157 	CU_ASSERT_EQUAL(cpl->status.sc, SPDK_NVME_SC_INVALID_FIELD);
158 	CU_ASSERT_EQUAL(cpl->status.dnr, 1);
159 	recv_cmd.secp = SPDK_NVMF_AUTH_SECP_NVME;
160 
161 	/* Bad spsp0 (send) */
162 	g_req_completed = false;
163 	req.cmd = (void *)&send_cmd;
164 	ut_clear_resp(&req);
165 	send_cmd.spsp0 = 2;
166 
167 	nvmf_auth_send_exec(&req);
168 	CU_ASSERT(g_req_completed);
169 	CU_ASSERT_EQUAL(cpl->status.sct, SPDK_NVME_SCT_GENERIC);
170 	CU_ASSERT_EQUAL(cpl->status.sc, SPDK_NVME_SC_INVALID_FIELD);
171 	CU_ASSERT_EQUAL(cpl->status.dnr, 1);
172 	send_cmd.spsp0 = 1;
173 
174 	/* Bad spsp0 (recv) */
175 	g_req_completed = false;
176 	req.cmd = (void *)&recv_cmd;
177 	ut_clear_resp(&req);
178 	recv_cmd.spsp0 = 2;
179 
180 	nvmf_auth_recv_exec(&req);
181 	CU_ASSERT(g_req_completed);
182 	CU_ASSERT_EQUAL(cpl->status.sct, SPDK_NVME_SCT_GENERIC);
183 	CU_ASSERT_EQUAL(cpl->status.sc, SPDK_NVME_SC_INVALID_FIELD);
184 	CU_ASSERT_EQUAL(cpl->status.dnr, 1);
185 	recv_cmd.spsp0 = 1;
186 
187 	/* Bad spsp1 (send) */
188 	g_req_completed = false;
189 	req.cmd = (void *)&send_cmd;
190 	ut_clear_resp(&req);
191 	send_cmd.spsp1 = 2;
192 
193 	nvmf_auth_send_exec(&req);
194 	CU_ASSERT(g_req_completed);
195 	CU_ASSERT_EQUAL(cpl->status.sct, SPDK_NVME_SCT_GENERIC);
196 	CU_ASSERT_EQUAL(cpl->status.sc, SPDK_NVME_SC_INVALID_FIELD);
197 	CU_ASSERT_EQUAL(cpl->status.dnr, 1);
198 	send_cmd.spsp1 = 1;
199 
200 	/* Bad spsp1 (recv) */
201 	g_req_completed = false;
202 	req.cmd = (void *)&recv_cmd;
203 	ut_clear_resp(&req);
204 	recv_cmd.spsp1 = 2;
205 
206 	nvmf_auth_recv_exec(&req);
207 	CU_ASSERT(g_req_completed);
208 	CU_ASSERT_EQUAL(cpl->status.sct, SPDK_NVME_SCT_GENERIC);
209 	CU_ASSERT_EQUAL(cpl->status.sc, SPDK_NVME_SC_INVALID_FIELD);
210 	CU_ASSERT_EQUAL(cpl->status.dnr, 1);
211 	recv_cmd.spsp1 = 1;
212 
213 	/* Bad length (send) */
214 	g_req_completed = false;
215 	req.cmd = (void *)&send_cmd;
216 	ut_clear_resp(&req);
217 	send_cmd.tl = req.length + 1;
218 
219 	nvmf_auth_recv_exec(&req);
220 	CU_ASSERT(g_req_completed);
221 	CU_ASSERT_EQUAL(cpl->status.sct, SPDK_NVME_SCT_GENERIC);
222 	CU_ASSERT_EQUAL(cpl->status.sc, SPDK_NVME_SC_INVALID_FIELD);
223 	CU_ASSERT_EQUAL(cpl->status.dnr, 1);
224 	send_cmd.tl = req.length;
225 
226 	/* Bad length (recv) */
227 	g_req_completed = false;
228 	req.cmd = (void *)&recv_cmd;
229 	ut_clear_resp(&req);
230 	recv_cmd.al = req.length - 1;
231 
232 	nvmf_auth_recv_exec(&req);
233 	CU_ASSERT(g_req_completed);
234 	CU_ASSERT_EQUAL(cpl->status.sct, SPDK_NVME_SCT_GENERIC);
235 	CU_ASSERT_EQUAL(cpl->status.sc, SPDK_NVME_SC_INVALID_FIELD);
236 	CU_ASSERT_EQUAL(cpl->status.dnr, 1);
237 	recv_cmd.al = req.length;
238 
239 	/* Bad length (smaller than common header) */
240 	g_req_completed = false;
241 	req.cmd = (union nvmf_h2c_msg *)&send_cmd;
242 	ut_clear_resp(&req);
243 	send_cmd.tl = req.length = sizeof(struct nvmf_auth_common_header) - 1;
244 
245 	nvmf_auth_send_exec(&req);
246 	CU_ASSERT(g_req_completed);
247 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
248 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
249 	send_cmd.tl = req.length = 255;
250 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
251 	auth->fail_reason = 0;
252 
253 	nvmf_qpair_auth_destroy(&qpair);
254 }
255 
256 static void
257 test_auth_negotiate(void)
258 {
259 	union nvmf_c2h_msg rsp = {};
260 	struct spdk_nvmf_subsystem subsys = {};
261 	struct spdk_nvmf_ctrlr ctrlr = { .subsys = &subsys };
262 	struct spdk_nvmf_qpair qpair = { .ctrlr = &ctrlr };
263 	struct spdk_nvmf_request req = { .qpair = &qpair, .rsp = &rsp };
264 	struct spdk_nvmf_fabric_auth_send_cmd cmd = {};
265 	struct spdk_nvmf_qpair_auth *auth;
266 	struct spdk_nvmf_auth_negotiate *msg;
267 	struct spdk_nvmf_auth_descriptor *desc;
268 	uint8_t msgbuf[4096];
269 	int rc;
270 
271 	msg = (void *)msgbuf;
272 	rc = nvmf_qpair_auth_init(&qpair);
273 	SPDK_CU_ASSERT_FATAL(rc == 0);
274 	ut_prep_send_cmd(&req, &cmd, msgbuf, sizeof(*msg) + sizeof(*desc));
275 	auth = qpair.auth;
276 
277 	/* Successful negotiation */
278 	g_req_completed = false;
279 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
280 	msg->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE;
281 	msg->auth_id = SPDK_NVMF_AUTH_ID_NEGOTIATE;
282 	msg->sc_c = SPDK_NVMF_AUTH_SCC_DISABLED;
283 	msg->napd = 1;
284 	desc = &msg->descriptors[0];
285 	desc->auth_id = SPDK_NVMF_AUTH_TYPE_DHCHAP;
286 	desc->halen = 3;
287 	desc->hash_id_list[0] = SPDK_NVMF_DHCHAP_HASH_SHA256;
288 	desc->hash_id_list[1] = SPDK_NVMF_DHCHAP_HASH_SHA384;
289 	desc->hash_id_list[2] = SPDK_NVMF_DHCHAP_HASH_SHA512;
290 	desc->dhlen = 6;
291 	desc->dhg_id_list[0] = SPDK_NVMF_DHCHAP_DHGROUP_NULL;
292 	desc->dhg_id_list[1] = SPDK_NVMF_DHCHAP_DHGROUP_2048;
293 	desc->dhg_id_list[2] = SPDK_NVMF_DHCHAP_DHGROUP_3072;
294 	desc->dhg_id_list[3] = SPDK_NVMF_DHCHAP_DHGROUP_4096;
295 	desc->dhg_id_list[4] = SPDK_NVMF_DHCHAP_DHGROUP_6144;
296 	desc->dhg_id_list[5] = SPDK_NVMF_DHCHAP_DHGROUP_8192;
297 
298 	nvmf_auth_send_exec(&req);
299 	CU_ASSERT(g_req_completed);
300 	CU_ASSERT_EQUAL(auth->digest, SPDK_NVMF_DHCHAP_HASH_SHA512);
301 	CU_ASSERT_EQUAL(auth->dhgroup, SPDK_NVMF_DHCHAP_DHGROUP_8192);
302 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_CHALLENGE);
303 
304 	/* Invalid auth state */
305 	g_req_completed = false;
306 	auth->state = NVMF_QPAIR_AUTH_ERROR;
307 	auth->digest = -1;
308 
309 	nvmf_auth_send_exec(&req);
310 	CU_ASSERT(g_req_completed);
311 	CU_ASSERT_EQUAL(auth->digest, -1);
312 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
313 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
314 
315 	/* scc mismatch */
316 	g_req_completed = false;
317 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
318 	msg->sc_c = SPDK_NVMF_AUTH_SCC_TLS;
319 
320 	nvmf_auth_send_exec(&req);
321 	CU_ASSERT(g_req_completed);
322 	CU_ASSERT_EQUAL(auth->digest, -1);
323 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
324 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_SCC_MISMATCH);
325 	msg->sc_c = SPDK_NVMF_AUTH_SCC_DISABLED;
326 
327 	/* Missing DH-HMAC-CHAP protocol (napd=0) */
328 	g_req_completed = false;
329 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
330 	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg);
331 	msg->napd = 0;
332 
333 	nvmf_auth_send_exec(&req);
334 	CU_ASSERT(g_req_completed);
335 	CU_ASSERT_EQUAL(auth->digest, -1);
336 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
337 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_PROTOCOL_UNUSABLE);
338 	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg) + sizeof(*desc);
339 	msg->napd = 1;
340 
341 	/* Missing DH-HMAC-CHAP protocol */
342 	g_req_completed = false;
343 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
344 	desc->auth_id = SPDK_NVMF_AUTH_TYPE_DHCHAP + 1;
345 
346 	nvmf_auth_send_exec(&req);
347 	CU_ASSERT(g_req_completed);
348 	CU_ASSERT_EQUAL(auth->digest, -1);
349 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
350 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_PROTOCOL_UNUSABLE);
351 	desc->auth_id = SPDK_NVMF_AUTH_TYPE_DHCHAP;
352 
353 	/* No valid digests (halen=0) */
354 	g_req_completed = false;
355 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
356 	desc->halen = 0;
357 
358 	nvmf_auth_send_exec(&req);
359 	CU_ASSERT(g_req_completed);
360 	CU_ASSERT_EQUAL(auth->digest, -1);
361 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
362 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_HASH_UNUSABLE);
363 
364 	/* No valid digests */
365 	g_req_completed = false;
366 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
367 	desc->hash_id_list[0] = SPDK_NVMF_DHCHAP_HASH_SHA512 + 1;
368 	desc->hash_id_list[1] = SPDK_NVMF_DHCHAP_HASH_SHA512 + 2;
369 	desc->hash_id_list[2] = SPDK_NVMF_DHCHAP_HASH_SHA512 + 3;
370 	desc->halen = 3;
371 
372 	nvmf_auth_send_exec(&req);
373 	CU_ASSERT(g_req_completed);
374 	CU_ASSERT_EQUAL(auth->digest, -1);
375 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
376 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_HASH_UNUSABLE);
377 	desc->hash_id_list[0] = SPDK_NVMF_DHCHAP_HASH_SHA256;
378 	desc->hash_id_list[1] = SPDK_NVMF_DHCHAP_HASH_SHA384;
379 	desc->hash_id_list[2] = SPDK_NVMF_DHCHAP_HASH_SHA512;
380 
381 	/* No valid dhgroups (dhlen=0) */
382 	g_req_completed = false;
383 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
384 	desc->dhlen = 0;
385 
386 	nvmf_auth_send_exec(&req);
387 	CU_ASSERT(g_req_completed);
388 	CU_ASSERT_EQUAL(auth->digest, -1);
389 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
390 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_DHGROUP_UNUSABLE);
391 
392 	/* No valid dhgroups */
393 	g_req_completed = false;
394 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
395 	desc->dhlen = 2;
396 	desc->dhg_id_list[0] = SPDK_NVMF_DHCHAP_DHGROUP_8192 + 1;
397 	desc->dhg_id_list[1] = SPDK_NVMF_DHCHAP_DHGROUP_8192 + 2;
398 
399 	nvmf_auth_send_exec(&req);
400 	CU_ASSERT(g_req_completed);
401 	CU_ASSERT_EQUAL(auth->digest, -1);
402 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
403 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_DHGROUP_UNUSABLE);
404 	desc->dhg_id_list[0] = SPDK_NVMF_DHCHAP_DHGROUP_NULL;
405 	desc->dhg_id_list[1] = SPDK_NVMF_DHCHAP_DHGROUP_2048;
406 	desc->dhlen = 6;
407 
408 	/* Bad halen value */
409 	g_req_completed = false;
410 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
411 	desc->halen = 255;
412 
413 	nvmf_auth_send_exec(&req);
414 	CU_ASSERT(g_req_completed);
415 	CU_ASSERT_EQUAL(auth->digest, -1);
416 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
417 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
418 	desc->halen = 3;
419 
420 	/* Bad dhlen value */
421 	g_req_completed = false;
422 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
423 	desc->dhlen = 255;
424 
425 	nvmf_auth_send_exec(&req);
426 	CU_ASSERT(g_req_completed);
427 	CU_ASSERT_EQUAL(auth->digest, -1);
428 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
429 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
430 	desc->dhlen = 6;
431 
432 	/* Invalid request length (too small) */
433 	g_req_completed = false;
434 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
435 	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg) - 1;
436 
437 	nvmf_auth_send_exec(&req);
438 	CU_ASSERT(g_req_completed);
439 	CU_ASSERT_EQUAL(auth->digest, -1);
440 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
441 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
442 
443 	/* Invalid request length (too small) */
444 	g_req_completed = false;
445 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
446 	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg);
447 
448 	nvmf_auth_send_exec(&req);
449 	CU_ASSERT(g_req_completed);
450 	CU_ASSERT_EQUAL(auth->digest, -1);
451 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
452 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
453 
454 	/* Invalid request length (too small) */
455 	g_req_completed = false;
456 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
457 	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg) + sizeof(*desc) - 1;
458 
459 	nvmf_auth_send_exec(&req);
460 	CU_ASSERT(g_req_completed);
461 	CU_ASSERT_EQUAL(auth->digest, -1);
462 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
463 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
464 
465 	/* Invalid request length (too large) */
466 	g_req_completed = false;
467 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
468 	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg) + sizeof(*desc) + 1;
469 
470 	nvmf_auth_send_exec(&req);
471 	CU_ASSERT(g_req_completed);
472 	CU_ASSERT_EQUAL(auth->digest, -1);
473 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
474 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
475 	req.length = cmd.tl = req.iov[0].iov_len = sizeof(*msg) + sizeof(*desc);
476 
477 	nvmf_qpair_auth_destroy(&qpair);
478 }
479 
480 static void
481 test_auth_timeout(void)
482 {
483 	union nvmf_c2h_msg rsp = {};
484 	struct spdk_nvmf_subsystem subsys = {};
485 	struct spdk_nvmf_ctrlr ctrlr = { .subsys = &subsys };
486 	struct spdk_nvmf_qpair qpair = { .ctrlr = &ctrlr };
487 	struct spdk_nvmf_request req = { .qpair = &qpair, .rsp = &rsp };
488 	struct spdk_nvmf_fabric_auth_send_cmd cmd = {};
489 	struct spdk_nvmf_qpair_auth *auth;
490 	struct spdk_nvmf_auth_negotiate *msg;
491 	struct spdk_nvmf_auth_descriptor *desc;
492 	uint8_t msgbuf[4096];
493 	int rc;
494 
495 	msg = (void *)msgbuf;
496 	ut_prep_send_cmd(&req, &cmd, msgbuf, sizeof(*msg) + sizeof(*desc));
497 	MOCK_SET(spdk_get_ticks_hz, 1000 * 1000);
498 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
499 
500 	/* Check that a timeout is correctly detected and qpair is disconnected */
501 	rc = nvmf_qpair_auth_init(&qpair);
502 	SPDK_CU_ASSERT_FATAL(rc == 0);
503 	MOCK_SET(spdk_get_ticks, NVMF_AUTH_DEFAULT_KATO_US - 1);
504 	poll_threads();
505 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_AUTHENTICATING);
506 	MOCK_SET(spdk_get_ticks, NVMF_AUTH_DEFAULT_KATO_US);
507 	poll_threads();
508 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ERROR);
509 	nvmf_qpair_auth_destroy(&qpair);
510 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
511 	MOCK_SET(spdk_get_ticks, 0);
512 
513 	/* Check a case where a non-zero kato is set in controller features */
514 	ctrlr.feat.keep_alive_timer.bits.kato = 10 * 1000;
515 	rc = nvmf_qpair_auth_init(&qpair);
516 	SPDK_CU_ASSERT_FATAL(rc == 0);
517 	MOCK_SET(spdk_get_ticks, 10 * 1000 * 1000 - 1);
518 	poll_threads();
519 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_AUTHENTICATING);
520 	MOCK_SET(spdk_get_ticks, 10 * 1000 * 1000);
521 	poll_threads();
522 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ERROR);
523 	nvmf_qpair_auth_destroy(&qpair);
524 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
525 	ctrlr.feat.keep_alive_timer.bits.kato = 0;
526 	MOCK_SET(spdk_get_ticks, 0);
527 
528 	/* Check that reception of a command rearms the timeout poller */
529 	rc = nvmf_qpair_auth_init(&qpair);
530 	SPDK_CU_ASSERT_FATAL(rc == 0);
531 	auth = qpair.auth;
532 
533 	MOCK_SET(spdk_get_ticks, NVMF_AUTH_DEFAULT_KATO_US / 2);
534 	g_req_completed = false;
535 	msg->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE;
536 	msg->auth_id = SPDK_NVMF_AUTH_ID_NEGOTIATE;
537 	msg->sc_c = SPDK_NVMF_AUTH_SCC_DISABLED;
538 	msg->napd = 1;
539 	desc = &msg->descriptors[0];
540 	desc->auth_id = SPDK_NVMF_AUTH_TYPE_DHCHAP;
541 	desc->halen = 1;
542 	desc->hash_id_list[0] = SPDK_NVMF_DHCHAP_HASH_SHA256;
543 	desc->dhlen = 1;
544 	desc->dhg_id_list[0] = SPDK_NVMF_DHCHAP_DHGROUP_NULL;
545 
546 	nvmf_auth_send_exec(&req);
547 	CU_ASSERT(g_req_completed);
548 	CU_ASSERT_EQUAL(auth->digest, SPDK_NVMF_DHCHAP_HASH_SHA256);
549 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_CHALLENGE);
550 
551 	MOCK_SET(spdk_get_ticks, NVMF_AUTH_DEFAULT_KATO_US);
552 	poll_threads();
553 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_AUTHENTICATING);
554 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_CHALLENGE);
555 
556 	MOCK_SET(spdk_get_ticks, NVMF_AUTH_DEFAULT_KATO_US + NVMF_AUTH_DEFAULT_KATO_US / 2);
557 	poll_threads();
558 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ERROR);
559 	nvmf_qpair_auth_destroy(&qpair);
560 	MOCK_SET(spdk_get_ticks, 0);
561 }
562 
563 static void
564 test_auth_failure1(void)
565 {
566 	union nvmf_c2h_msg rsp = {};
567 	struct spdk_nvmf_subsystem subsys = {};
568 	struct spdk_nvmf_ctrlr ctrlr = { .subsys = &subsys };
569 	struct spdk_nvmf_qpair qpair = { .ctrlr = &ctrlr };
570 	struct spdk_nvmf_request req = { .qpair = &qpair, .rsp = &rsp };
571 	struct spdk_nvmf_fabric_auth_recv_cmd cmd = {
572 		.fctype = SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV
573 	};
574 	struct spdk_nvme_cpl *cpl = &rsp.nvme_cpl;
575 	struct spdk_nvmf_qpair_auth *auth;
576 	struct spdk_nvmf_auth_failure *msg;
577 	uint8_t msgbuf[sizeof(*msg)];
578 	int rc;
579 
580 	msg = (void *)msgbuf;
581 	rc = nvmf_qpair_auth_init(&qpair);
582 	SPDK_CU_ASSERT_FATAL(rc == 0);
583 	auth = qpair.auth;
584 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
585 
586 	/* Check failure1 message fields */
587 	ut_prep_recv_cmd(&req, &cmd, msgbuf, sizeof(*msg));
588 	g_req_completed = false;
589 	auth->state = NVMF_QPAIR_AUTH_FAILURE1;
590 	auth->fail_reason = SPDK_NVMF_AUTH_FAILED;
591 	auth->tid = 8;
592 
593 	nvmf_auth_recv_exec(&req);
594 	CU_ASSERT(g_req_completed);
595 	CU_ASSERT_EQUAL(cpl->status.sct, 0);
596 	CU_ASSERT_EQUAL(cpl->status.sc, 0);
597 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_ERROR);
598 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ERROR);
599 	CU_ASSERT_EQUAL(msg->auth_type, SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE);
600 	CU_ASSERT_EQUAL(msg->auth_id, SPDK_NVMF_AUTH_ID_FAILURE1);
601 	CU_ASSERT_EQUAL(msg->t_id, 8);
602 	CU_ASSERT_EQUAL(msg->rc, SPDK_NVMF_AUTH_FAILURE);
603 	CU_ASSERT_EQUAL(msg->rce, SPDK_NVMF_AUTH_FAILED);
604 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
605 
606 	/* Do a receive while expecting an auth send command */
607 	ut_prep_recv_cmd(&req, &cmd, msgbuf, sizeof(*msg));
608 	g_req_completed = false;
609 	auth->state = NVMF_QPAIR_AUTH_NEGOTIATE;
610 	auth->fail_reason = 0;
611 
612 	nvmf_auth_recv_exec(&req);
613 	CU_ASSERT(g_req_completed);
614 	CU_ASSERT_EQUAL(cpl->status.sct, 0);
615 	CU_ASSERT_EQUAL(cpl->status.sc, 0);
616 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_ERROR);
617 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ERROR);
618 	CU_ASSERT_EQUAL(msg->auth_type, SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE);
619 	CU_ASSERT_EQUAL(msg->auth_id, SPDK_NVMF_AUTH_ID_FAILURE1);
620 	CU_ASSERT_EQUAL(msg->t_id, 8);
621 	CU_ASSERT_EQUAL(msg->rc, SPDK_NVMF_AUTH_FAILURE);
622 	CU_ASSERT_EQUAL(msg->rce, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
623 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
624 
625 	/* Do a receive but specify a buffer that's too small */
626 	ut_prep_recv_cmd(&req, &cmd, msgbuf, sizeof(*msg));
627 	g_req_completed = false;
628 	auth->state = NVMF_QPAIR_AUTH_FAILURE1;
629 	auth->fail_reason = SPDK_NVMF_AUTH_FAILED;
630 	req.iov[0].iov_len = cmd.al = req.length = sizeof(*msg) - 1;
631 
632 	nvmf_auth_recv_exec(&req);
633 	CU_ASSERT(g_req_completed);
634 	CU_ASSERT_EQUAL(cpl->status.sct, SPDK_NVME_SCT_GENERIC);
635 	CU_ASSERT_EQUAL(cpl->status.sc, SPDK_NVME_SC_INVALID_FIELD);
636 	CU_ASSERT_EQUAL(cpl->status.dnr, 1);
637 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ERROR);
638 	req.iov[0].iov_len = cmd.al = req.length = sizeof(*msg);
639 
640 	nvmf_qpair_auth_destroy(&qpair);
641 }
642 
643 static void
644 test_auth_challenge(void)
645 {
646 	union nvmf_c2h_msg rsp = {};
647 	struct spdk_nvmf_subsystem subsys = { .mutex = PTHREAD_MUTEX_INITIALIZER };
648 	struct spdk_nvmf_ctrlr ctrlr = { .subsys = &subsys };
649 	struct spdk_nvmf_qpair qpair = { .ctrlr = &ctrlr };
650 	struct spdk_nvmf_request req = { .qpair = &qpair, .rsp = &rsp };
651 	struct spdk_nvmf_fabric_auth_recv_cmd cmd = {
652 		.fctype = SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV
653 	};
654 	struct spdk_nvmf_qpair_auth *auth;
655 	struct spdk_nvmf_dhchap_challenge *msg;
656 	struct spdk_nvmf_auth_failure *fail;
657 	uint8_t msgbuf[4096], cval[4096], dhv[4096];
658 	int rc;
659 
660 	msg = (void *)msgbuf;
661 	fail = (void *)msgbuf;
662 	rc = nvmf_qpair_auth_init(&qpair);
663 	SPDK_CU_ASSERT_FATAL(rc == 0);
664 	auth = qpair.auth;
665 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
666 
667 	/* Successfully receive a challenge message */
668 	ut_prep_recv_cmd(&req, &cmd, msgbuf, sizeof(msgbuf));
669 	g_req_completed = false;
670 	auth->state = NVMF_QPAIR_AUTH_CHALLENGE;
671 	auth->dhgroup = SPDK_NVMF_DHCHAP_DHGROUP_NULL;
672 	MOCK_SET(spdk_nvme_dhchap_get_digest_length, 48);
673 	g_rand_val = 0xa5;
674 	memset(cval, g_rand_val, sizeof(cval));
675 	auth->digest = SPDK_NVMF_DHCHAP_HASH_SHA384;
676 	auth->tid = 8;
677 
678 	nvmf_auth_recv_exec(&req);
679 	CU_ASSERT(g_req_completed);
680 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_REPLY);
681 	CU_ASSERT_EQUAL(msg->auth_type, SPDK_NVMF_AUTH_TYPE_DHCHAP);
682 	CU_ASSERT_EQUAL(msg->auth_id, SPDK_NVMF_AUTH_ID_DHCHAP_CHALLENGE);
683 	CU_ASSERT_EQUAL(msg->t_id, 8);
684 	CU_ASSERT_EQUAL(msg->hl, 48);
685 	CU_ASSERT_EQUAL(msg->hash_id, SPDK_NVMF_DHCHAP_HASH_SHA384);
686 	CU_ASSERT_EQUAL(msg->dhg_id, SPDK_NVMF_DHCHAP_DHGROUP_NULL);
687 	CU_ASSERT_EQUAL(msg->dhvlen, 0);
688 	CU_ASSERT_EQUAL(memcmp(msg->cval, cval, 48), 0);
689 	CU_ASSERT(msg->seqnum != 0);
690 
691 	/* Successfully receive a challenge message w/ a non-NULL dhgroup */
692 	ut_prep_recv_cmd(&req, &cmd, msgbuf, sizeof(msgbuf));
693 	g_req_completed = false;
694 	auth->state = NVMF_QPAIR_AUTH_CHALLENGE;
695 	MOCK_SET(spdk_nvme_dhchap_get_digest_length, 48);
696 	MOCK_SET(spdk_nvme_dhchap_generate_dhkey, (struct spdk_nvme_dhchap_dhkey *)0xdeadbeef);
697 	g_rand_val = 0xa5;
698 	g_dhv = 0xfe;
699 	g_dhvlen = 256;
700 	memset(cval, g_rand_val, sizeof(cval));
701 	memset(dhv, g_dhv, sizeof(dhv));
702 	auth->digest = SPDK_NVMF_DHCHAP_HASH_SHA384;
703 	auth->dhgroup = SPDK_NVMF_DHCHAP_DHGROUP_2048;
704 	auth->tid = 8;
705 
706 	nvmf_auth_recv_exec(&req);
707 	CU_ASSERT(g_req_completed);
708 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_REPLY);
709 	CU_ASSERT_EQUAL(msg->auth_type, SPDK_NVMF_AUTH_TYPE_DHCHAP);
710 	CU_ASSERT_EQUAL(msg->auth_id, SPDK_NVMF_AUTH_ID_DHCHAP_CHALLENGE);
711 	CU_ASSERT_EQUAL(msg->t_id, 8);
712 	CU_ASSERT_EQUAL(msg->hl, 48);
713 	CU_ASSERT_EQUAL(msg->hash_id, SPDK_NVMF_DHCHAP_HASH_SHA384);
714 	CU_ASSERT_EQUAL(msg->dhg_id, SPDK_NVMF_DHCHAP_DHGROUP_2048);
715 	CU_ASSERT_EQUAL(msg->dhvlen, g_dhvlen);
716 	CU_ASSERT_EQUAL(memcmp(msg->cval, cval, 48), 0);
717 	CU_ASSERT_EQUAL(memcmp(&msg->cval[48], dhv, g_dhvlen), 0);
718 	CU_ASSERT(msg->seqnum != 0);
719 
720 	/* Check RAND_bytes failure */
721 	ut_prep_recv_cmd(&req, &cmd, msgbuf, sizeof(msgbuf));
722 	g_req_completed = false;
723 	auth->state = NVMF_QPAIR_AUTH_CHALLENGE;
724 	MOCK_SET(spdk_nvme_dhchap_get_digest_length, 48);
725 	auth->digest = SPDK_NVMF_DHCHAP_HASH_SHA384;
726 	auth->tid = 8;
727 	MOCK_SET(RAND_bytes, -1);
728 
729 	nvmf_auth_recv_exec(&req);
730 	CU_ASSERT(g_req_completed);
731 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ERROR);
732 	CU_ASSERT_EQUAL(fail->auth_type, SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE);
733 	CU_ASSERT_EQUAL(fail->auth_id, SPDK_NVMF_AUTH_ID_FAILURE1);
734 	CU_ASSERT_EQUAL(fail->t_id, 8);
735 	CU_ASSERT_EQUAL(fail->rc, SPDK_NVMF_AUTH_FAILURE);
736 	CU_ASSERT_EQUAL(fail->rce, SPDK_NVMF_AUTH_FAILED);
737 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
738 	MOCK_SET(RAND_bytes, 1);
739 
740 	/* Check spdk_nvme_dhchap_generate_dhkey failure */
741 	ut_prep_recv_cmd(&req, &cmd, msgbuf, sizeof(msgbuf));
742 	g_req_completed = false;
743 	MOCK_SET(spdk_nvme_dhchap_generate_dhkey, NULL);
744 	auth->state = NVMF_QPAIR_AUTH_CHALLENGE;
745 	auth->tid = 8;
746 
747 	nvmf_auth_recv_exec(&req);
748 	CU_ASSERT(g_req_completed);
749 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ERROR);
750 	CU_ASSERT_EQUAL(fail->auth_type, SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE);
751 	CU_ASSERT_EQUAL(fail->auth_id, SPDK_NVMF_AUTH_ID_FAILURE1);
752 	CU_ASSERT_EQUAL(fail->t_id, 8);
753 	CU_ASSERT_EQUAL(fail->rc, SPDK_NVMF_AUTH_FAILURE);
754 	CU_ASSERT_EQUAL(fail->rce, SPDK_NVMF_AUTH_FAILED);
755 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
756 
757 	/* Check spdk_nvme_dhchap_dhkey_get_pubkey failure */
758 	ut_prep_recv_cmd(&req, &cmd, msgbuf, sizeof(msgbuf));
759 	g_req_completed = false;
760 	MOCK_SET(spdk_nvme_dhchap_generate_dhkey, (struct spdk_nvme_dhchap_dhkey *)0xdeadbeef);
761 	MOCK_SET(spdk_nvme_dhchap_dhkey_get_pubkey, -EIO);
762 	auth->state = NVMF_QPAIR_AUTH_CHALLENGE;
763 	auth->tid = 8;
764 
765 	nvmf_auth_recv_exec(&req);
766 	CU_ASSERT(g_req_completed);
767 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ERROR);
768 	CU_ASSERT_EQUAL(fail->auth_type, SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE);
769 	CU_ASSERT_EQUAL(fail->auth_id, SPDK_NVMF_AUTH_ID_FAILURE1);
770 	CU_ASSERT_EQUAL(fail->t_id, 8);
771 	CU_ASSERT_EQUAL(fail->rc, SPDK_NVMF_AUTH_FAILURE);
772 	CU_ASSERT_EQUAL(fail->rce, SPDK_NVMF_AUTH_FAILED);
773 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
774 	MOCK_SET(spdk_nvme_dhchap_dhkey_get_pubkey, 0);
775 
776 	/* Check insufficient buffer size */
777 	ut_prep_recv_cmd(&req, &cmd, msgbuf, sizeof(msgbuf));
778 	g_req_completed = false;
779 	auth->state = NVMF_QPAIR_AUTH_CHALLENGE;
780 	MOCK_SET(spdk_nvme_dhchap_get_digest_length, 48);
781 	auth->tid = 8;
782 	cmd.al = req.length = req.iov[0].iov_len = sizeof(msg) + 47;
783 
784 	nvmf_auth_recv_exec(&req);
785 	CU_ASSERT(g_req_completed);
786 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ERROR);
787 	CU_ASSERT_EQUAL(fail->auth_type, SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE);
788 	CU_ASSERT_EQUAL(fail->auth_id, SPDK_NVMF_AUTH_ID_FAILURE1);
789 	CU_ASSERT_EQUAL(fail->t_id, 8);
790 	CU_ASSERT_EQUAL(fail->rc, SPDK_NVMF_AUTH_FAILURE);
791 	CU_ASSERT_EQUAL(fail->rce, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
792 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
793 	MOCK_CLEAR(spdk_nvme_dhchap_get_digest_length);
794 
795 	nvmf_qpair_auth_destroy(&qpair);
796 }
797 
798 static void
799 test_auth_reply(void)
800 {
801 	union nvmf_c2h_msg rsp = {};
802 	struct spdk_nvmf_subsystem subsys = {};
803 	struct spdk_nvmf_ctrlr ctrlr = { .subsys = &subsys };
804 	struct spdk_nvmf_qpair qpair = { .ctrlr = &ctrlr };
805 	struct spdk_nvmf_request req = { .qpair = &qpair, .rsp = &rsp };
806 	struct spdk_nvmf_fabric_auth_send_cmd cmd = {};
807 	struct spdk_nvmf_qpair_auth *auth;
808 	struct spdk_nvmf_dhchap_reply *msg;
809 	uint8_t hl = 48, msgbuf[4096];
810 	int rc;
811 
812 	msg = (void *)msgbuf;
813 	rc = nvmf_qpair_auth_init(&qpair);
814 	SPDK_CU_ASSERT_FATAL(rc == 0);
815 	ut_prep_send_cmd(&req, &cmd, msgbuf, sizeof(*msg) + 2 * hl);
816 	auth = qpair.auth;
817 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
818 	auth->tid = 8;
819 
820 	/* Execute a reply containing a correct response */
821 	g_req_completed = false;
822 	MOCK_SET(nvmf_subsystem_get_dhchap_key, (struct spdk_key *)0xdeadbeef);
823 	MOCK_SET(spdk_nvme_dhchap_get_digest_length, hl);
824 	auth->state = NVMF_QPAIR_AUTH_REPLY;
825 	msg->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP;
826 	msg->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_REPLY;
827 	msg->t_id = auth->tid;
828 	msg->hl = hl;
829 	msg->cvalid = 0;
830 	msg->dhvlen = 0;
831 	msg->seqnum = 0;
832 	memset(msg->rval, 0xa5, hl);
833 	g_rval = 0xa5;
834 
835 	nvmf_auth_send_exec(&req);
836 	CU_ASSERT(g_req_completed);
837 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_SUCCESS1);
838 
839 	/* Execute a reply while not in the REPLY state */
840 	g_req_completed = false;
841 	auth->state = NVMF_QPAIR_AUTH_CHALLENGE;
842 
843 	nvmf_auth_send_exec(&req);
844 	CU_ASSERT(g_req_completed);
845 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
846 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
847 
848 	/* Bad message length (smaller than a base reply message) */
849 	g_req_completed = false;
850 	auth->state = NVMF_QPAIR_AUTH_REPLY;
851 	cmd.tl = req.iov[0].iov_len = req.length = sizeof(*msg) - 1;
852 
853 	nvmf_auth_send_exec(&req);
854 	CU_ASSERT(g_req_completed);
855 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
856 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
857 
858 	/* Hash length mismatch */
859 	g_req_completed = false;
860 	auth->state = NVMF_QPAIR_AUTH_REPLY;
861 	msg->hl = 32;
862 
863 	nvmf_auth_send_exec(&req);
864 	CU_ASSERT(g_req_completed);
865 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
866 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
867 	msg->hl = hl;
868 
869 	/* Bad message length (smaller than size of msg + 2 * hl) */
870 	g_req_completed = false;
871 	auth->state = NVMF_QPAIR_AUTH_REPLY;
872 	cmd.tl = req.iov[0].iov_len = req.length = sizeof(*msg) + 2 * hl - 1;
873 
874 	nvmf_auth_send_exec(&req);
875 	CU_ASSERT(g_req_completed);
876 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
877 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
878 	cmd.tl = req.iov[0].iov_len = req.length = sizeof(*msg) + hl;
879 
880 	/* Bad message length (larger than size of msg + 2 * hl) */
881 	g_req_completed = false;
882 	auth->state = NVMF_QPAIR_AUTH_REPLY;
883 	cmd.tl = req.iov[0].iov_len = req.length = sizeof(*msg) + 2 * hl + 1;
884 
885 	nvmf_auth_send_exec(&req);
886 	CU_ASSERT(g_req_completed);
887 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
888 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
889 	cmd.tl = req.iov[0].iov_len = req.length = sizeof(*msg) + 2 * hl;
890 
891 	/* Transaction ID mismatch */
892 	g_req_completed = false;
893 	auth->state = NVMF_QPAIR_AUTH_REPLY;
894 	msg->t_id = auth->tid + 1;
895 
896 	nvmf_auth_send_exec(&req);
897 	CU_ASSERT(g_req_completed);
898 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
899 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
900 	msg->t_id = auth->tid;
901 
902 	/* Bad cvalid value */
903 	g_req_completed = false;
904 	auth->state = NVMF_QPAIR_AUTH_REPLY;
905 	msg->cvalid = 1;
906 
907 	nvmf_auth_send_exec(&req);
908 	CU_ASSERT(g_req_completed);
909 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
910 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
911 	msg->cvalid = 0;
912 
913 	/* Bad dhvlen (non-zero) */
914 	g_req_completed = false;
915 	auth->state = NVMF_QPAIR_AUTH_REPLY;
916 	msg->dhvlen = 1;
917 
918 	nvmf_auth_send_exec(&req);
919 	CU_ASSERT(g_req_completed);
920 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
921 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
922 	msg->dhvlen = 0;
923 
924 	/* Failure to get the key */
925 	g_req_completed = false;
926 	auth->state = NVMF_QPAIR_AUTH_REPLY;
927 	MOCK_SET(nvmf_subsystem_get_dhchap_key, NULL);
928 
929 	nvmf_auth_send_exec(&req);
930 	CU_ASSERT(g_req_completed);
931 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
932 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_FAILED);
933 	MOCK_SET(nvmf_subsystem_get_dhchap_key, (struct spdk_key *)0xdeadbeef);
934 
935 	/* Calculation failure */
936 	g_req_completed = false;
937 	auth->state = NVMF_QPAIR_AUTH_REPLY;
938 	MOCK_SET(spdk_nvme_dhchap_calculate, -EPERM);
939 
940 	nvmf_auth_send_exec(&req);
941 	CU_ASSERT(g_req_completed);
942 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
943 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_FAILED);
944 	MOCK_SET(spdk_nvme_dhchap_calculate, 0);
945 
946 	/* Response mismatch */
947 	g_req_completed = false;
948 	auth->state = NVMF_QPAIR_AUTH_REPLY;
949 	g_rval = 0x5a;
950 
951 	nvmf_auth_send_exec(&req);
952 	CU_ASSERT(g_req_completed);
953 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
954 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_FAILED);
955 	g_rval = 0xa5;
956 
957 	/* DH secret derivation failure */
958 	g_req_completed = false;
959 	auth->state = NVMF_QPAIR_AUTH_REPLY;
960 	auth->dhgroup = SPDK_NVMF_DHCHAP_DHGROUP_2048;
961 	MOCK_SET(spdk_nvme_dhchap_dhkey_derive_secret, -EIO);
962 
963 	nvmf_auth_send_exec(&req);
964 	CU_ASSERT(g_req_completed);
965 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_FAILURE1);
966 	CU_ASSERT_EQUAL(auth->fail_reason, SPDK_NVMF_AUTH_FAILED);
967 	MOCK_SET(spdk_nvme_dhchap_dhkey_derive_secret, 0);
968 
969 	nvmf_qpair_auth_destroy(&qpair);
970 }
971 
972 static void
973 test_auth_success1(void)
974 {
975 	union nvmf_c2h_msg rsp = {};
976 	struct spdk_nvmf_subsystem subsys = {};
977 	struct spdk_nvmf_ctrlr ctrlr = { .subsys = &subsys };
978 	struct spdk_nvmf_qpair qpair = { .ctrlr = &ctrlr };
979 	struct spdk_nvmf_request req = { .qpair = &qpair, .rsp = &rsp };
980 	struct spdk_nvmf_fabric_auth_recv_cmd cmd = {
981 		.fctype = SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV
982 	};
983 	struct spdk_nvmf_qpair_auth *auth;
984 	struct spdk_nvmf_dhchap_success1 *msg;
985 	struct spdk_nvmf_auth_failure *fail;
986 	uint8_t msgbuf[sizeof(*msg)];
987 	int rc;
988 
989 	msg = (void *)msgbuf;
990 	fail = (void *)msgbuf;
991 	rc = nvmf_qpair_auth_init(&qpair);
992 	SPDK_CU_ASSERT_FATAL(rc == 0);
993 	auth = qpair.auth;
994 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
995 	auth->tid = 8;
996 
997 	/* Successfully receive a success message */
998 	ut_prep_recv_cmd(&req, &cmd, msgbuf, sizeof(*msg));
999 	g_req_completed = false;
1000 	auth->state = NVMF_QPAIR_AUTH_SUCCESS1;
1001 
1002 	nvmf_auth_recv_exec(&req);
1003 	CU_ASSERT(g_req_completed);
1004 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_COMPLETED);
1005 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ENABLED);
1006 	CU_ASSERT_EQUAL(msg->auth_type, SPDK_NVMF_AUTH_TYPE_DHCHAP);
1007 	CU_ASSERT_EQUAL(msg->auth_id, SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS1);
1008 	CU_ASSERT_EQUAL(msg->t_id, 8);
1009 	CU_ASSERT_EQUAL(msg->hl, 48);
1010 	CU_ASSERT_EQUAL(msg->rvalid, 0);
1011 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
1012 
1013 	/* Bad message length (smaller than success1 message) */
1014 	ut_prep_recv_cmd(&req, &cmd, msgbuf, sizeof(*msg));
1015 	g_req_completed = false;
1016 	auth->state = NVMF_QPAIR_AUTH_SUCCESS1;
1017 	cmd.al = req.iov[0].iov_len = req.length = sizeof(*msg) - 1;
1018 
1019 	nvmf_auth_recv_exec(&req);
1020 	CU_ASSERT(g_req_completed);
1021 	CU_ASSERT_EQUAL(auth->state, NVMF_QPAIR_AUTH_ERROR);
1022 	CU_ASSERT_EQUAL(qpair.state, SPDK_NVMF_QPAIR_ERROR);
1023 	CU_ASSERT_EQUAL(fail->auth_type, SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE);
1024 	CU_ASSERT_EQUAL(fail->auth_id, SPDK_NVMF_AUTH_ID_FAILURE1);
1025 	CU_ASSERT_EQUAL(fail->t_id, 8);
1026 	CU_ASSERT_EQUAL(fail->rc, SPDK_NVMF_AUTH_FAILURE);
1027 	CU_ASSERT_EQUAL(fail->rce, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
1028 	qpair.state = SPDK_NVMF_QPAIR_AUTHENTICATING;
1029 	cmd.al = req.iov[0].iov_len = req.length = sizeof(*msg);
1030 
1031 	nvmf_qpair_auth_destroy(&qpair);
1032 }
1033 
1034 int
1035 main(int argc, char **argv)
1036 {
1037 	CU_pSuite suite = NULL;
1038 	unsigned int num_failures;
1039 
1040 	CU_initialize_registry();
1041 	suite = CU_add_suite("nvmf_auth", NULL, NULL);
1042 	CU_ADD_TEST(suite, test_auth_send_recv_error);
1043 	CU_ADD_TEST(suite, test_auth_negotiate);
1044 	CU_ADD_TEST(suite, test_auth_timeout);
1045 	CU_ADD_TEST(suite, test_auth_failure1);
1046 	CU_ADD_TEST(suite, test_auth_challenge);
1047 	CU_ADD_TEST(suite, test_auth_reply);
1048 	CU_ADD_TEST(suite, test_auth_success1);
1049 
1050 	allocate_threads(1);
1051 	set_thread(0);
1052 
1053 	num_failures = spdk_ut_run_tests(argc, argv, NULL);
1054 	CU_cleanup_registry();
1055 
1056 	free_threads();
1057 
1058 	return num_failures;
1059 }
1060