xref: /spdk/lib/nvmf/auth.c (revision 8afdeef3becfe9409cc9e7372bd0bc10e8b7d46d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2024 Intel Corporation
3  */
4 
5 #include "spdk/nvme.h"
6 #include "spdk/json.h"
7 #include "spdk/log.h"
8 #include "spdk/stdinc.h"
9 #include "spdk/string.h"
10 #include "spdk/thread.h"
11 #include "spdk/util.h"
12 #include "spdk_internal/nvme.h"
13 
14 #include <openssl/rand.h>
15 
16 #include "nvmf_internal.h"
17 
18 #define NVMF_AUTH_DEFAULT_KATO_US (120ull * 1000 * 1000)
19 #define NVMF_AUTH_DIGEST_MAX_SIZE 64
20 #define NVMF_AUTH_DH_KEY_MAX_SIZE 1024
21 
22 #define AUTH_ERRLOG(q, fmt, ...) \
23 	SPDK_ERRLOG("[%s:%s:%u] " fmt, (q)->ctrlr->subsys->subnqn, (q)->ctrlr->hostnqn, \
24 		    (q)->qid, ## __VA_ARGS__)
25 #define AUTH_DEBUGLOG(q, fmt, ...) \
26 	SPDK_DEBUGLOG(nvmf_auth, "[%s:%s:%u] " fmt, \
27 		      (q)->ctrlr->subsys->subnqn, (q)->ctrlr->hostnqn, (q)->qid, ## __VA_ARGS__)
28 #define AUTH_LOGDUMP(msg, buf, len) \
29 	SPDK_LOGDUMP(nvmf_auth, msg, buf, len)
30 
31 enum nvmf_qpair_auth_state {
32 	NVMF_QPAIR_AUTH_NEGOTIATE,
33 	NVMF_QPAIR_AUTH_CHALLENGE,
34 	NVMF_QPAIR_AUTH_REPLY,
35 	NVMF_QPAIR_AUTH_SUCCESS1,
36 	NVMF_QPAIR_AUTH_SUCCESS2,
37 	NVMF_QPAIR_AUTH_FAILURE1,
38 	NVMF_QPAIR_AUTH_COMPLETED,
39 	NVMF_QPAIR_AUTH_ERROR,
40 };
41 
42 struct spdk_nvmf_qpair_auth {
43 	enum nvmf_qpair_auth_state	state;
44 	struct spdk_poller		*poller;
45 	int				fail_reason;
46 	uint16_t			tid;
47 	int				digest;
48 	int				dhgroup;
49 	uint8_t				cval[NVMF_AUTH_DIGEST_MAX_SIZE];
50 	uint32_t			seqnum;
51 	struct spdk_nvme_dhchap_dhkey	*dhkey;
52 	bool				cvalid;
53 };
54 
55 struct nvmf_auth_common_header {
56 	uint8_t		auth_type;
57 	uint8_t		auth_id;
58 	uint8_t		reserved0[2];
59 	uint16_t	t_id;
60 };
61 
62 static void
63 nvmf_auth_request_complete(struct spdk_nvmf_request *req, int sct, int sc, int dnr)
64 {
65 	struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl;
66 
67 	response->status.sct = sct;
68 	response->status.sc = sc;
69 	response->status.dnr = dnr;
70 
71 	spdk_nvmf_request_complete(req);
72 }
73 
74 static const char *
75 nvmf_auth_get_state_name(enum nvmf_qpair_auth_state state)
76 {
77 	static const char *state_names[] = {
78 		[NVMF_QPAIR_AUTH_NEGOTIATE] = "negotiate",
79 		[NVMF_QPAIR_AUTH_CHALLENGE] = "challenge",
80 		[NVMF_QPAIR_AUTH_REPLY] = "reply",
81 		[NVMF_QPAIR_AUTH_SUCCESS1] = "success1",
82 		[NVMF_QPAIR_AUTH_SUCCESS2] = "success2",
83 		[NVMF_QPAIR_AUTH_FAILURE1] = "failure1",
84 		[NVMF_QPAIR_AUTH_COMPLETED] = "completed",
85 		[NVMF_QPAIR_AUTH_ERROR] = "error",
86 	};
87 
88 	return state_names[state];
89 }
90 
91 static void
92 nvmf_auth_set_state(struct spdk_nvmf_qpair *qpair, enum nvmf_qpair_auth_state state)
93 {
94 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
95 
96 	if (auth->state == state) {
97 		return;
98 	}
99 
100 	AUTH_DEBUGLOG(qpair, "auth state: %s\n", nvmf_auth_get_state_name(state));
101 	auth->state = state;
102 }
103 
104 static void
105 nvmf_auth_disconnect_qpair(struct spdk_nvmf_qpair *qpair)
106 {
107 	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_ERROR);
108 	spdk_nvmf_qpair_disconnect(qpair);
109 }
110 
111 static void
112 nvmf_auth_request_fail1(struct spdk_nvmf_request *req, int reason)
113 {
114 	struct spdk_nvmf_qpair *qpair = req->qpair;
115 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
116 
117 	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_FAILURE1);
118 	auth->fail_reason = reason;
119 
120 	/* The command itself is completed successfully, but a subsequent AUTHENTICATION_RECV
121 	 * command will be completed with an AUTH_failure1 message
122 	 */
123 	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
124 }
125 
126 static bool
127 nvmf_auth_digest_allowed(struct spdk_nvmf_qpair *qpair, uint8_t digest)
128 {
129 	struct spdk_nvmf_tgt *tgt = qpair->group->tgt;
130 
131 	return tgt->dhchap_digests & SPDK_BIT(digest);
132 }
133 
134 static bool
135 nvmf_auth_dhgroup_allowed(struct spdk_nvmf_qpair *qpair, uint8_t dhgroup)
136 {
137 	struct spdk_nvmf_tgt *tgt = qpair->group->tgt;
138 
139 	return tgt->dhchap_dhgroups & SPDK_BIT(dhgroup);
140 }
141 
142 static void
143 nvmf_auth_qpair_cleanup(struct spdk_nvmf_qpair_auth *auth)
144 {
145 	spdk_poller_unregister(&auth->poller);
146 	spdk_nvme_dhchap_dhkey_free(&auth->dhkey);
147 }
148 
149 static int
150 nvmf_auth_timeout_poller(void *ctx)
151 {
152 	struct spdk_nvmf_qpair *qpair = ctx;
153 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
154 
155 	AUTH_ERRLOG(qpair, "authentication timed out\n");
156 	spdk_poller_unregister(&auth->poller);
157 
158 	if (qpair->state == SPDK_NVMF_QPAIR_ENABLED) {
159 		/* Reauthentication timeout isn't considered to be a fatal failure */
160 		nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_COMPLETED);
161 		nvmf_auth_qpair_cleanup(auth);
162 	} else {
163 		nvmf_auth_disconnect_qpair(qpair);
164 	}
165 
166 	return SPDK_POLLER_BUSY;
167 }
168 
169 static int
170 nvmf_auth_rearm_poller(struct spdk_nvmf_qpair *qpair)
171 {
172 	struct spdk_nvmf_ctrlr *ctrlr = qpair->ctrlr;
173 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
174 	uint64_t timeout;
175 
176 	timeout = ctrlr->feat.keep_alive_timer.bits.kato > 0 ?
177 		  ctrlr->feat.keep_alive_timer.bits.kato * 1000 :
178 		  NVMF_AUTH_DEFAULT_KATO_US;
179 
180 	spdk_poller_unregister(&auth->poller);
181 	auth->poller = SPDK_POLLER_REGISTER(nvmf_auth_timeout_poller, qpair, timeout);
182 	if (auth->poller == NULL) {
183 		return -ENOMEM;
184 	}
185 
186 	return 0;
187 }
188 
189 static int
190 nvmf_auth_check_command(struct spdk_nvmf_request *req, uint8_t secp,
191 			uint8_t spsp0, uint8_t spsp1, uint32_t len)
192 {
193 	struct spdk_nvmf_qpair *qpair = req->qpair;
194 
195 	if (secp != SPDK_NVMF_AUTH_SECP_NVME) {
196 		AUTH_ERRLOG(qpair, "invalid secp=%u\n", secp);
197 		return -EINVAL;
198 	}
199 	if (spsp0 != 1 || spsp1 != 1) {
200 		AUTH_ERRLOG(qpair, "invalid spsp0=%u, spsp1=%u\n", spsp0, spsp1);
201 		return -EINVAL;
202 	}
203 	if (len != req->length) {
204 		AUTH_ERRLOG(qpair, "invalid length: %"PRIu32" != %"PRIu32"\n", len, req->length);
205 		return -EINVAL;
206 	}
207 
208 	return 0;
209 }
210 
211 static void *
212 nvmf_auth_get_message(struct spdk_nvmf_request *req, size_t size)
213 {
214 	if (req->length > 0 && req->iovcnt == 1 && req->iov[0].iov_len >= size) {
215 		return req->iov[0].iov_base;
216 	}
217 
218 	return NULL;
219 }
220 
221 static void
222 nvmf_auth_negotiate_exec(struct spdk_nvmf_request *req, struct spdk_nvmf_auth_negotiate *msg)
223 {
224 	struct spdk_nvmf_qpair *qpair = req->qpair;
225 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
226 	struct spdk_nvmf_auth_descriptor *desc = NULL;
227 	/* These arrays are sorted from the strongest hash/dhgroup to the weakest, so the strongest
228 	 * hash/dhgroup pair supported by the host is always selected
229 	 */
230 	enum spdk_nvmf_dhchap_hash digests[] = {
231 		SPDK_NVMF_DHCHAP_HASH_SHA512,
232 		SPDK_NVMF_DHCHAP_HASH_SHA384,
233 		SPDK_NVMF_DHCHAP_HASH_SHA256
234 	};
235 	enum spdk_nvmf_dhchap_dhgroup dhgroups[] = {
236 		SPDK_NVMF_DHCHAP_DHGROUP_8192,
237 		SPDK_NVMF_DHCHAP_DHGROUP_6144,
238 		SPDK_NVMF_DHCHAP_DHGROUP_4096,
239 		SPDK_NVMF_DHCHAP_DHGROUP_3072,
240 		SPDK_NVMF_DHCHAP_DHGROUP_2048,
241 		SPDK_NVMF_DHCHAP_DHGROUP_NULL,
242 	};
243 	int digest = -1, dhgroup = -1;
244 	size_t i, j;
245 
246 	if (auth->state != NVMF_QPAIR_AUTH_NEGOTIATE) {
247 		AUTH_ERRLOG(qpair, "invalid state: %s\n", nvmf_auth_get_state_name(auth->state));
248 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
249 		return;
250 	}
251 
252 	auth->tid = msg->t_id;
253 	if (req->length < sizeof(*msg) || req->length != sizeof(*msg) + msg->napd * sizeof(*desc)) {
254 		AUTH_ERRLOG(qpair, "invalid message length: %"PRIu32"\n", req->length);
255 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
256 		return;
257 	}
258 
259 	if (msg->sc_c != SPDK_NVMF_AUTH_SCC_DISABLED) {
260 		AUTH_ERRLOG(qpair, "scc mismatch\n");
261 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_SCC_MISMATCH);
262 		return;
263 	}
264 
265 	for (i = 0; i < msg->napd; ++i) {
266 		if (msg->descriptors[i].auth_id == SPDK_NVMF_AUTH_TYPE_DHCHAP) {
267 			desc = &msg->descriptors[i];
268 			break;
269 		}
270 	}
271 	if (desc == NULL) {
272 		AUTH_ERRLOG(qpair, "no usable protocol found\n");
273 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_PROTOCOL_UNUSABLE);
274 		return;
275 	}
276 	if (desc->halen > SPDK_COUNTOF(desc->hash_id_list) ||
277 	    desc->dhlen > SPDK_COUNTOF(desc->dhg_id_list)) {
278 		AUTH_ERRLOG(qpair, "invalid halen=%u, dhlen=%u\n", desc->halen, desc->dhlen);
279 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
280 		return;
281 	}
282 
283 	for (i = 0; i < SPDK_COUNTOF(digests); ++i) {
284 		if (!nvmf_auth_digest_allowed(qpair, digests[i])) {
285 			continue;
286 		}
287 		for (j = 0; j < desc->halen; ++j) {
288 			if (digests[i] == desc->hash_id_list[j]) {
289 				AUTH_DEBUGLOG(qpair, "selected digest: %s\n",
290 					      spdk_nvme_dhchap_get_digest_name(digests[i]));
291 				digest = digests[i];
292 				break;
293 			}
294 		}
295 		if (digest >= 0) {
296 			break;
297 		}
298 	}
299 	if (digest < 0) {
300 		AUTH_ERRLOG(qpair, "no usable digests found\n");
301 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_HASH_UNUSABLE);
302 		return;
303 	}
304 
305 	for (i = 0; i < SPDK_COUNTOF(dhgroups); ++i) {
306 		if (!nvmf_auth_dhgroup_allowed(qpair, dhgroups[i])) {
307 			continue;
308 		}
309 		for (j = 0; j < desc->dhlen; ++j) {
310 			if (dhgroups[i] == desc->dhg_id_list[j]) {
311 				AUTH_DEBUGLOG(qpair, "selected dhgroup: %s\n",
312 					      spdk_nvme_dhchap_get_dhgroup_name(dhgroups[i]));
313 				dhgroup = dhgroups[i];
314 				break;
315 			}
316 		}
317 		if (dhgroup >= 0) {
318 			break;
319 		}
320 	}
321 	if (dhgroup < 0) {
322 		AUTH_ERRLOG(qpair, "no usable dhgroups found\n");
323 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_DHGROUP_UNUSABLE);
324 		return;
325 	}
326 
327 	if (nvmf_auth_rearm_poller(qpair)) {
328 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
329 					   SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 1);
330 		nvmf_auth_disconnect_qpair(qpair);
331 		return;
332 	}
333 
334 	auth->digest = digest;
335 	auth->dhgroup = dhgroup;
336 	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_CHALLENGE);
337 	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
338 }
339 
340 static void
341 nvmf_auth_reply_exec(struct spdk_nvmf_request *req, struct spdk_nvmf_dhchap_reply *msg)
342 {
343 	struct spdk_nvmf_qpair *qpair = req->qpair;
344 	struct spdk_nvmf_ctrlr *ctrlr = qpair->ctrlr;
345 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
346 	uint8_t response[NVMF_AUTH_DIGEST_MAX_SIZE];
347 	uint8_t dhsec[NVMF_AUTH_DH_KEY_MAX_SIZE];
348 	struct spdk_key *key = NULL, *ckey = NULL;
349 	size_t dhseclen = 0;
350 	uint8_t hl;
351 	int rc;
352 
353 	if (auth->state != NVMF_QPAIR_AUTH_REPLY) {
354 		AUTH_ERRLOG(qpair, "invalid state=%s\n", nvmf_auth_get_state_name(auth->state));
355 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
356 		goto out;
357 	}
358 	if (req->length < sizeof(*msg)) {
359 		AUTH_ERRLOG(qpair, "invalid message length=%"PRIu32"\n", req->length);
360 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
361 		goto out;
362 	}
363 
364 	hl = spdk_nvme_dhchap_get_digest_length(auth->digest);
365 	if (hl == 0 || msg->hl != hl) {
366 		AUTH_ERRLOG(qpair, "hash length mismatch: %u != %u\n", msg->hl, hl);
367 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
368 		goto out;
369 	}
370 	if ((msg->dhvlen % 4) != 0) {
371 		AUTH_ERRLOG(qpair, "dhvlen=%u is not multiple of 4\n", msg->dhvlen);
372 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
373 		goto out;
374 	}
375 	if (req->length != sizeof(*msg) + 2 * hl + msg->dhvlen) {
376 		AUTH_ERRLOG(qpair, "invalid message length: %"PRIu32" != %zu\n",
377 			    req->length, sizeof(*msg) + 2 * hl);
378 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
379 		goto out;
380 	}
381 	if (msg->t_id != auth->tid) {
382 		AUTH_ERRLOG(qpair, "transaction id mismatch: %u != %u\n", msg->t_id, auth->tid);
383 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
384 		goto out;
385 	}
386 	if (msg->cvalid != 0 && msg->cvalid != 1) {
387 		AUTH_ERRLOG(qpair, "unexpected cvalid=%d\n", msg->cvalid);
388 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
389 		goto out;
390 	}
391 	if (msg->cvalid && msg->seqnum == 0) {
392 		AUTH_ERRLOG(qpair, "unexpected seqnum=0 with cvalid=1\n");
393 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
394 		goto out;
395 	}
396 
397 	key = nvmf_subsystem_get_dhchap_key(ctrlr->subsys, ctrlr->hostnqn, NVMF_AUTH_KEY_HOST);
398 	if (key == NULL) {
399 		AUTH_ERRLOG(qpair, "couldn't get DH-HMAC-CHAP key\n");
400 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED);
401 		goto out;
402 	}
403 
404 	if (auth->dhgroup != SPDK_NVMF_DHCHAP_DHGROUP_NULL) {
405 		AUTH_LOGDUMP("host pubkey:", &msg->rval[2 * hl], msg->dhvlen);
406 		dhseclen = sizeof(dhsec);
407 		rc = spdk_nvme_dhchap_dhkey_derive_secret(auth->dhkey, &msg->rval[2 * hl],
408 				msg->dhvlen, dhsec, &dhseclen);
409 		if (rc != 0) {
410 			AUTH_ERRLOG(qpair, "couldn't derive DH secret\n");
411 			nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED);
412 			goto out;
413 		}
414 
415 		AUTH_LOGDUMP("dh secret:", dhsec, dhseclen);
416 	}
417 
418 	assert(hl <= sizeof(response) && hl <= sizeof(auth->cval));
419 	rc = spdk_nvme_dhchap_calculate(key, (enum spdk_nvmf_dhchap_hash)auth->digest,
420 					"HostHost", auth->seqnum, auth->tid, 0,
421 					ctrlr->hostnqn, ctrlr->subsys->subnqn,
422 					dhseclen > 0 ? dhsec : NULL, dhseclen,
423 					auth->cval, response);
424 	if (rc != 0) {
425 		AUTH_ERRLOG(qpair, "failed to calculate challenge response: %s\n",
426 			    spdk_strerror(-rc));
427 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED);
428 		goto out;
429 	}
430 
431 	if (memcmp(msg->rval, response, hl) != 0) {
432 		AUTH_ERRLOG(qpair, "challenge response mismatch\n");
433 		AUTH_LOGDUMP("response:", msg->rval, hl);
434 		AUTH_LOGDUMP("expected:", response, hl);
435 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED);
436 		goto out;
437 	}
438 
439 	if (msg->cvalid) {
440 		ckey = nvmf_subsystem_get_dhchap_key(ctrlr->subsys, ctrlr->hostnqn,
441 						     NVMF_AUTH_KEY_CTRLR);
442 		if (ckey == NULL) {
443 			AUTH_ERRLOG(qpair, "missing DH-HMAC-CHAP ctrlr key\n");
444 			nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED);
445 			goto out;
446 		}
447 		rc = spdk_nvme_dhchap_calculate(ckey, (enum spdk_nvmf_dhchap_hash)auth->digest,
448 						"Controller", msg->seqnum, auth->tid, 0,
449 						ctrlr->subsys->subnqn, ctrlr->hostnqn,
450 						dhseclen > 0 ? dhsec : NULL, dhseclen,
451 						&msg->rval[hl], auth->cval);
452 		if (rc != 0) {
453 			AUTH_ERRLOG(qpair, "failed to calculate ctrlr challenge response: %s\n",
454 				    spdk_strerror(-rc));
455 			nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED);
456 			goto out;
457 		}
458 		auth->cvalid = true;
459 	}
460 
461 	if (nvmf_auth_rearm_poller(qpair)) {
462 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
463 					   SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 1);
464 		nvmf_auth_disconnect_qpair(qpair);
465 		goto out;
466 	}
467 
468 	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_SUCCESS1);
469 	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
470 out:
471 	spdk_keyring_put_key(ckey);
472 	spdk_keyring_put_key(key);
473 }
474 
475 static void
476 nvmf_auth_success2_exec(struct spdk_nvmf_request *req, struct spdk_nvmf_dhchap_success2 *msg)
477 {
478 	struct spdk_nvmf_qpair *qpair = req->qpair;
479 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
480 
481 	if (auth->state != NVMF_QPAIR_AUTH_SUCCESS2) {
482 		AUTH_ERRLOG(qpair, "invalid state=%s\n", nvmf_auth_get_state_name(auth->state));
483 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
484 		return;
485 	}
486 	if (req->length != sizeof(*msg)) {
487 		AUTH_ERRLOG(qpair, "invalid message length=%"PRIu32"\n", req->length);
488 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
489 		return;
490 	}
491 	if (msg->t_id != auth->tid) {
492 		AUTH_ERRLOG(qpair, "transaction id mismatch: %u != %u\n", msg->t_id, auth->tid);
493 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
494 		return;
495 	}
496 
497 	AUTH_DEBUGLOG(qpair, "controller authentication successful\n");
498 	nvmf_qpair_set_state(qpair, SPDK_NVMF_QPAIR_ENABLED);
499 	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_COMPLETED);
500 	nvmf_auth_qpair_cleanup(auth);
501 	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
502 }
503 
504 static void
505 nvmf_auth_failure2_exec(struct spdk_nvmf_request *req, struct spdk_nvmf_auth_failure *msg)
506 {
507 	struct spdk_nvmf_qpair *qpair = req->qpair;
508 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
509 
510 	/* AUTH_failure2 is only expected when we're waiting for the success2 message */
511 	if (auth->state != NVMF_QPAIR_AUTH_SUCCESS2) {
512 		AUTH_ERRLOG(qpair, "invalid state=%s\n", nvmf_auth_get_state_name(auth->state));
513 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
514 		return;
515 	}
516 	if (req->length != sizeof(*msg)) {
517 		AUTH_ERRLOG(qpair, "invalid message length=%"PRIu32"\n", req->length);
518 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
519 		return;
520 	}
521 	if (msg->t_id != auth->tid) {
522 		AUTH_ERRLOG(qpair, "transaction id mismatch: %u != %u\n", msg->t_id, auth->tid);
523 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
524 		return;
525 	}
526 
527 	AUTH_ERRLOG(qpair, "ctrlr authentication failed: rc=%d, rce=%d\n", msg->rc, msg->rce);
528 	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_ERROR);
529 	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
530 }
531 
532 static void
533 nvmf_auth_send_exec(struct spdk_nvmf_request *req)
534 {
535 	struct spdk_nvmf_qpair *qpair = req->qpair;
536 	struct spdk_nvmf_fabric_auth_send_cmd *cmd = &req->cmd->auth_send_cmd;
537 	struct nvmf_auth_common_header *header;
538 	int rc;
539 
540 	rc = nvmf_auth_check_command(req, cmd->secp, cmd->spsp0, cmd->spsp1, cmd->tl);
541 	if (rc != 0) {
542 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
543 					   SPDK_NVME_SC_INVALID_FIELD, 1);
544 		return;
545 	}
546 
547 	header = nvmf_auth_get_message(req, sizeof(*header));
548 	if (header == NULL) {
549 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
550 		return;
551 	}
552 
553 	switch (header->auth_type) {
554 	case SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE:
555 		switch (header->auth_id) {
556 		case SPDK_NVMF_AUTH_ID_NEGOTIATE:
557 			nvmf_auth_negotiate_exec(req, (void *)header);
558 			break;
559 		case SPDK_NVMF_AUTH_ID_FAILURE2:
560 			nvmf_auth_failure2_exec(req, (void *)header);
561 			break;
562 		default:
563 			AUTH_ERRLOG(qpair, "unexpected auth_id=%u\n", header->auth_id);
564 			nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
565 			break;
566 		}
567 		break;
568 	case SPDK_NVMF_AUTH_TYPE_DHCHAP:
569 		switch (header->auth_id) {
570 		case SPDK_NVMF_AUTH_ID_DHCHAP_REPLY:
571 			nvmf_auth_reply_exec(req, (void *)header);
572 			break;
573 		case SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS2:
574 			nvmf_auth_success2_exec(req, (void *)header);
575 			break;
576 		default:
577 			AUTH_ERRLOG(qpair, "unexpected auth_id=%u\n", header->auth_id);
578 			nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
579 			break;
580 		}
581 		break;
582 	default:
583 		AUTH_ERRLOG(qpair, "unexpected auth_type=%u\n", header->auth_type);
584 		nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
585 		break;
586 	}
587 }
588 
589 static void
590 nvmf_auth_recv_complete(struct spdk_nvmf_request *req, uint32_t length)
591 {
592 	assert(req->cmd->nvmf_cmd.fctype == SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV);
593 	req->length = length;
594 	nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
595 }
596 
597 static void
598 nvmf_auth_recv_failure1(struct spdk_nvmf_request *req, int fail_reason)
599 {
600 	struct spdk_nvmf_qpair *qpair = req->qpair;
601 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
602 	struct spdk_nvmf_auth_failure *failure;
603 
604 	failure = nvmf_auth_get_message(req, sizeof(*failure));
605 	if (failure == NULL) {
606 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
607 					   SPDK_NVME_SC_INVALID_FIELD, 1);
608 		nvmf_auth_disconnect_qpair(qpair);
609 		return;
610 	}
611 
612 	failure->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE;
613 	failure->auth_id = SPDK_NVMF_AUTH_ID_FAILURE1;
614 	failure->t_id = auth->tid;
615 	failure->rc = SPDK_NVMF_AUTH_FAILURE;
616 	failure->rce = fail_reason;
617 
618 	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_FAILURE1);
619 	nvmf_auth_recv_complete(req, sizeof(*failure));
620 	nvmf_auth_disconnect_qpair(qpair);
621 }
622 
623 static int
624 nvmf_auth_get_seqnum(struct spdk_nvmf_qpair *qpair)
625 {
626 	struct spdk_nvmf_subsystem *subsys = qpair->ctrlr->subsys;
627 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
628 	int rc;
629 
630 	pthread_mutex_lock(&subsys->mutex);
631 	if (subsys->auth_seqnum == 0) {
632 		rc = RAND_bytes((void *)&subsys->auth_seqnum, sizeof(subsys->auth_seqnum));
633 		if (rc != 1) {
634 			pthread_mutex_unlock(&subsys->mutex);
635 			return -EIO;
636 		}
637 	}
638 	if (++subsys->auth_seqnum == 0) {
639 		subsys->auth_seqnum = 1;
640 
641 	}
642 	auth->seqnum = subsys->auth_seqnum;
643 	pthread_mutex_unlock(&subsys->mutex);
644 
645 	return 0;
646 }
647 
648 static int
649 nvmf_auth_recv_challenge(struct spdk_nvmf_request *req)
650 {
651 	struct spdk_nvmf_qpair *qpair = req->qpair;
652 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
653 	struct spdk_nvmf_dhchap_challenge *challenge;
654 	uint8_t hl, dhv[NVMF_AUTH_DH_KEY_MAX_SIZE];
655 	size_t dhvlen = 0;
656 	int rc;
657 
658 	hl = spdk_nvme_dhchap_get_digest_length(auth->digest);
659 	assert(hl > 0 && hl <= sizeof(auth->cval));
660 
661 	if (auth->dhgroup != SPDK_NVMF_DHCHAP_DHGROUP_NULL) {
662 		auth->dhkey = spdk_nvme_dhchap_generate_dhkey(auth->dhgroup);
663 		if (auth->dhkey == NULL) {
664 			AUTH_ERRLOG(qpair, "failed to generate DH key\n");
665 			return SPDK_NVMF_AUTH_FAILED;
666 		}
667 
668 		dhvlen = sizeof(dhv);
669 		rc = spdk_nvme_dhchap_dhkey_get_pubkey(auth->dhkey, dhv, &dhvlen);
670 		if (rc != 0) {
671 			AUTH_ERRLOG(qpair, "failed to get DH public key\n");
672 			return SPDK_NVMF_AUTH_FAILED;
673 		}
674 
675 		AUTH_LOGDUMP("ctrlr pubkey:", dhv, dhvlen);
676 	}
677 
678 	challenge = nvmf_auth_get_message(req, sizeof(*challenge) + hl + dhvlen);
679 	if (challenge == NULL) {
680 		AUTH_ERRLOG(qpair, "invalid message length: %"PRIu32"\n", req->length);
681 		return SPDK_NVMF_AUTH_INCORRECT_PAYLOAD;
682 	}
683 	rc = nvmf_auth_get_seqnum(qpair);
684 	if (rc != 0) {
685 		return SPDK_NVMF_AUTH_FAILED;
686 	}
687 	rc = RAND_bytes(auth->cval, hl);
688 	if (rc != 1) {
689 		return SPDK_NVMF_AUTH_FAILED;
690 	}
691 	if (nvmf_auth_rearm_poller(qpair)) {
692 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
693 					   SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 1);
694 		nvmf_auth_disconnect_qpair(qpair);
695 		return 0;
696 	}
697 
698 	memcpy(challenge->cval, auth->cval, hl);
699 	memcpy(&challenge->cval[hl], dhv, dhvlen);
700 	challenge->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP;
701 	challenge->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_CHALLENGE;
702 	challenge->t_id = auth->tid;
703 	challenge->hl = hl;
704 	challenge->hash_id = (uint8_t)auth->digest;
705 	challenge->dhg_id = (uint8_t)auth->dhgroup;
706 	challenge->dhvlen = dhvlen;
707 	challenge->seqnum = auth->seqnum;
708 
709 	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_REPLY);
710 	nvmf_auth_recv_complete(req, sizeof(*challenge) + hl + dhvlen);
711 
712 	return 0;
713 }
714 
715 static int
716 nvmf_auth_recv_success1(struct spdk_nvmf_request *req)
717 {
718 	struct spdk_nvmf_qpair *qpair = req->qpair;
719 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
720 	struct spdk_nvmf_dhchap_success1 *success;
721 	uint8_t hl;
722 
723 	hl = spdk_nvme_dhchap_get_digest_length(auth->digest);
724 	success = nvmf_auth_get_message(req, sizeof(*success) + auth->cvalid * hl);
725 	if (success == NULL) {
726 		AUTH_ERRLOG(qpair, "invalid message length: %"PRIu32"\n", req->length);
727 		return SPDK_NVMF_AUTH_INCORRECT_PAYLOAD;
728 	}
729 
730 	AUTH_DEBUGLOG(qpair, "host authentication successful\n");
731 	success->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP;
732 	success->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS1;
733 	success->t_id = auth->tid;
734 	/* Kernel initiator always expects hl to be set, regardless of rvalid */
735 	success->hl = hl;
736 	success->rvalid = 0;
737 
738 	if (!auth->cvalid) {
739 		/* Host didn't request to authenticate us, we're done */
740 		nvmf_qpair_set_state(qpair, SPDK_NVMF_QPAIR_ENABLED);
741 		nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_COMPLETED);
742 		nvmf_auth_qpair_cleanup(auth);
743 	} else {
744 		if (nvmf_auth_rearm_poller(qpair)) {
745 			nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
746 						   SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 1);
747 			nvmf_auth_disconnect_qpair(qpair);
748 			return 0;
749 		}
750 		AUTH_DEBUGLOG(qpair, "cvalid=1, starting controller authentication\n");
751 		nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_SUCCESS2);
752 		memcpy(success->rval, auth->cval, hl);
753 		success->rvalid = 1;
754 	}
755 
756 	nvmf_auth_recv_complete(req, sizeof(*success) + auth->cvalid * hl);
757 	return 0;
758 }
759 
760 static void
761 nvmf_auth_recv_exec(struct spdk_nvmf_request *req)
762 {
763 	struct spdk_nvmf_qpair *qpair = req->qpair;
764 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
765 	struct spdk_nvmf_fabric_auth_recv_cmd *cmd = &req->cmd->auth_recv_cmd;
766 	int rc;
767 
768 	rc = nvmf_auth_check_command(req, cmd->secp, cmd->spsp0, cmd->spsp1, cmd->al);
769 	if (rc != 0) {
770 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
771 					   SPDK_NVME_SC_INVALID_FIELD, 1);
772 		return;
773 	}
774 
775 	spdk_iov_memset(req->iov, req->iovcnt, 0);
776 	switch (auth->state) {
777 	case NVMF_QPAIR_AUTH_CHALLENGE:
778 		rc = nvmf_auth_recv_challenge(req);
779 		if (rc != 0) {
780 			nvmf_auth_recv_failure1(req, rc);
781 		}
782 		break;
783 	case NVMF_QPAIR_AUTH_SUCCESS1:
784 		rc = nvmf_auth_recv_success1(req);
785 		if (rc != 0) {
786 			nvmf_auth_recv_failure1(req, rc);
787 		}
788 		break;
789 	case NVMF_QPAIR_AUTH_FAILURE1:
790 		nvmf_auth_recv_failure1(req, auth->fail_reason);
791 		break;
792 	default:
793 		nvmf_auth_recv_failure1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE);
794 		break;
795 	}
796 }
797 
798 static bool
799 nvmf_auth_check_state(struct spdk_nvmf_qpair *qpair, struct spdk_nvmf_request *req)
800 {
801 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
802 	int rc;
803 
804 	switch (qpair->state) {
805 	case SPDK_NVMF_QPAIR_AUTHENTICATING:
806 		break;
807 	case SPDK_NVMF_QPAIR_ENABLED:
808 		if (auth == NULL || auth->state == NVMF_QPAIR_AUTH_COMPLETED) {
809 			rc = nvmf_qpair_auth_init(qpair);
810 			if (rc != 0) {
811 				nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
812 							   SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 0);
813 				return false;
814 			}
815 		}
816 		break;
817 	default:
818 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
819 					   SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR, 0);
820 		return false;
821 	}
822 
823 	return true;
824 }
825 
826 int
827 nvmf_auth_request_exec(struct spdk_nvmf_request *req)
828 {
829 	struct spdk_nvmf_qpair *qpair = req->qpair;
830 	union nvmf_h2c_msg *cmd = req->cmd;
831 
832 	if (!nvmf_auth_check_state(qpair, req)) {
833 		goto out;
834 	}
835 
836 	assert(cmd->nvmf_cmd.opcode == SPDK_NVME_OPC_FABRIC);
837 	switch (cmd->nvmf_cmd.fctype) {
838 	case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND:
839 		nvmf_auth_send_exec(req);
840 		break;
841 	case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV:
842 		nvmf_auth_recv_exec(req);
843 		break;
844 	default:
845 		assert(0 && "invalid fctype");
846 		nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC,
847 					   SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 0);
848 		break;
849 	}
850 out:
851 	return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS;
852 }
853 
854 int
855 nvmf_qpair_auth_init(struct spdk_nvmf_qpair *qpair)
856 {
857 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
858 	int rc;
859 
860 	if (auth == NULL) {
861 		auth = calloc(1, sizeof(*qpair->auth));
862 		if (auth == NULL) {
863 			return -ENOMEM;
864 		}
865 	}
866 
867 	auth->digest = -1;
868 	qpair->auth = auth;
869 	nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_NEGOTIATE);
870 
871 	rc = nvmf_auth_rearm_poller(qpair);
872 	if (rc != 0) {
873 		AUTH_ERRLOG(qpair, "failed to arm timeout poller: %s\n", spdk_strerror(-rc));
874 		nvmf_qpair_auth_destroy(qpair);
875 		return rc;
876 	}
877 
878 	return 0;
879 }
880 
881 void
882 nvmf_qpair_auth_destroy(struct spdk_nvmf_qpair *qpair)
883 {
884 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
885 
886 	if (auth != NULL) {
887 		nvmf_auth_qpair_cleanup(auth);
888 		free(qpair->auth);
889 		qpair->auth = NULL;
890 	}
891 }
892 
893 void
894 nvmf_qpair_auth_dump(struct spdk_nvmf_qpair *qpair, struct spdk_json_write_ctx *w)
895 {
896 	struct spdk_nvmf_qpair_auth *auth = qpair->auth;
897 	const char *digest, *dhgroup;
898 
899 	if (auth == NULL) {
900 		return;
901 	}
902 
903 	spdk_json_write_named_object_begin(w, "auth");
904 	spdk_json_write_named_string(w, "state", nvmf_auth_get_state_name(auth->state));
905 	digest = spdk_nvme_dhchap_get_digest_name(auth->digest);
906 	spdk_json_write_named_string(w, "digest", digest ? digest : "unknown");
907 	dhgroup = spdk_nvme_dhchap_get_dhgroup_name(auth->dhgroup);
908 	spdk_json_write_named_string(w, "dhgroup", dhgroup ? dhgroup : "unknown");
909 	spdk_json_write_object_end(w);
910 }
911 
912 bool
913 nvmf_auth_is_supported(void)
914 {
915 	return true;
916 }
917 SPDK_LOG_REGISTER_COMPONENT(nvmf_auth)
918