xref: /linux/drivers/nvme/target/fabrics-cmd-auth.c (revision 55ab7e14222e5f0b0fd9f7711ca391d2924b35e3)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * NVMe over Fabrics DH-HMAC-CHAP authentication command handling.
4  * Copyright (c) 2020 Hannes Reinecke, SUSE Software Solutions.
5  * All rights reserved.
6  */
7 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8 #include <linux/blkdev.h>
9 #include <linux/random.h>
10 #include <linux/nvme-auth.h>
11 #include <crypto/kpp.h>
12 #include <crypto/utils.h>
13 #include "nvmet.h"
14 
nvmet_auth_expired_work(struct work_struct * work)15 static void nvmet_auth_expired_work(struct work_struct *work)
16 {
17 	struct nvmet_sq *sq = container_of(to_delayed_work(work),
18 			struct nvmet_sq, auth_expired_work);
19 
20 	pr_debug("%s: ctrl %d qid %d transaction %u expired, resetting\n",
21 		 __func__, sq->ctrl->cntlid, sq->qid, sq->dhchap_tid);
22 	sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE;
23 	sq->dhchap_tid = -1;
24 }
25 
nvmet_auth_sq_init(struct nvmet_sq * sq)26 void nvmet_auth_sq_init(struct nvmet_sq *sq)
27 {
28 	/* Initialize in-band authentication */
29 	INIT_DELAYED_WORK(&sq->auth_expired_work, nvmet_auth_expired_work);
30 	sq->authenticated = false;
31 	sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE;
32 }
33 
nvmet_auth_negotiate(struct nvmet_req * req,void * d,u32 tl)34 static u8 nvmet_auth_negotiate(struct nvmet_req *req, void *d, u32 tl)
35 {
36 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
37 	struct nvmf_auth_dhchap_negotiate_data *data = d;
38 	int i, hash_id = 0, fallback_hash_id = 0, dhgid, fallback_dhgid;
39 
40 	if (tl < sizeof(*data) +
41 			sizeof(struct nvmf_auth_dhchap_protocol_descriptor))
42 		return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
43 
44 	pr_debug("%s: ctrl %d qid %d: data sc_d %d napd %d authid %d halen %d dhlen %d\n",
45 		 __func__, ctrl->cntlid, req->sq->qid,
46 		 data->sc_c, data->napd, data->auth_protocol[0].dhchap.authid,
47 		 data->auth_protocol[0].dhchap.halen,
48 		 data->auth_protocol[0].dhchap.dhlen);
49 	req->sq->dhchap_tid = le16_to_cpu(data->t_id);
50 	req->sq->sc_c = data->sc_c;
51 	if (data->sc_c != NVME_AUTH_SECP_NOSC) {
52 		if (!IS_ENABLED(CONFIG_NVME_TARGET_TCP_TLS))
53 			return NVME_AUTH_DHCHAP_FAILURE_CONCAT_MISMATCH;
54 		/* Secure concatenation can only be enabled on the admin queue */
55 		if (req->sq->qid)
56 			return NVME_AUTH_DHCHAP_FAILURE_CONCAT_MISMATCH;
57 		switch (data->sc_c) {
58 		case NVME_AUTH_SECP_NEWTLSPSK:
59 			if (nvmet_queue_tls_keyid(req->sq))
60 				return NVME_AUTH_DHCHAP_FAILURE_CONCAT_MISMATCH;
61 			break;
62 		case NVME_AUTH_SECP_REPLACETLSPSK:
63 			if (!nvmet_queue_tls_keyid(req->sq))
64 				return NVME_AUTH_DHCHAP_FAILURE_CONCAT_MISMATCH;
65 			break;
66 		default:
67 			return NVME_AUTH_DHCHAP_FAILURE_CONCAT_MISMATCH;
68 		}
69 		ctrl->concat = true;
70 	}
71 
72 	if (data->napd != 1)
73 		return NVME_AUTH_DHCHAP_FAILURE_HASH_UNUSABLE;
74 
75 	if (data->auth_protocol[0].dhchap.authid !=
76 	    NVME_AUTH_DHCHAP_AUTH_ID)
77 		return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
78 
79 	if (data->auth_protocol[0].dhchap.dhlen > NVME_AUTH_DHCHAP_MAX_DH_IDS ||
80 	    data->auth_protocol[0].dhchap.halen > NVME_AUTH_DHCHAP_MAX_HASH_IDS)
81 		return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
82 
83 	for (i = 0; i < data->auth_protocol[0].dhchap.halen; i++) {
84 		u8 host_hmac_id = data->auth_protocol[0].dhchap.idlist[i];
85 
86 		if (!fallback_hash_id && nvme_auth_hmac_hash_len(host_hmac_id))
87 			fallback_hash_id = host_hmac_id;
88 		if (ctrl->shash_id != host_hmac_id)
89 			continue;
90 		hash_id = ctrl->shash_id;
91 		break;
92 	}
93 	if (hash_id == 0) {
94 		if (fallback_hash_id == 0) {
95 			pr_debug("%s: ctrl %d qid %d: no usable hash found\n",
96 				 __func__, ctrl->cntlid, req->sq->qid);
97 			return NVME_AUTH_DHCHAP_FAILURE_HASH_UNUSABLE;
98 		}
99 		pr_debug("%s: ctrl %d qid %d: no usable hash found, falling back to %s\n",
100 			 __func__, ctrl->cntlid, req->sq->qid,
101 			 nvme_auth_hmac_name(fallback_hash_id));
102 		ctrl->shash_id = fallback_hash_id;
103 	}
104 
105 	dhgid = -1;
106 	fallback_dhgid = -1;
107 	for (i = 0; i < data->auth_protocol[0].dhchap.dhlen; i++) {
108 		int tmp_dhgid = data->auth_protocol[0].dhchap.idlist[i + 30];
109 
110 		if (tmp_dhgid != ctrl->dh_gid) {
111 			dhgid = tmp_dhgid;
112 			break;
113 		}
114 		if (fallback_dhgid < 0) {
115 			const char *kpp = nvme_auth_dhgroup_kpp(tmp_dhgid);
116 
117 			if (crypto_has_kpp(kpp, 0, 0))
118 				fallback_dhgid = tmp_dhgid;
119 		}
120 	}
121 	if (dhgid < 0) {
122 		if (fallback_dhgid < 0) {
123 			pr_debug("%s: ctrl %d qid %d: no usable DH group found\n",
124 				 __func__, ctrl->cntlid, req->sq->qid);
125 			return NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE;
126 		}
127 		pr_debug("%s: ctrl %d qid %d: configured DH group %s not found\n",
128 			 __func__, ctrl->cntlid, req->sq->qid,
129 			 nvme_auth_dhgroup_name(fallback_dhgid));
130 		ctrl->dh_gid = fallback_dhgid;
131 	}
132 	if (ctrl->dh_gid == NVME_AUTH_DHGROUP_NULL && ctrl->concat) {
133 		pr_debug("%s: ctrl %d qid %d: NULL DH group invalid "
134 			 "for secure channel concatenation\n", __func__,
135 			 ctrl->cntlid, req->sq->qid);
136 		return NVME_AUTH_DHCHAP_FAILURE_CONCAT_MISMATCH;
137 	}
138 	pr_debug("%s: ctrl %d qid %d: selected DH group %s (%d)\n",
139 		 __func__, ctrl->cntlid, req->sq->qid,
140 		 nvme_auth_dhgroup_name(ctrl->dh_gid), ctrl->dh_gid);
141 	return 0;
142 }
143 
nvmet_auth_reply(struct nvmet_req * req,void * d,u32 tl)144 static u8 nvmet_auth_reply(struct nvmet_req *req, void *d, u32 tl)
145 {
146 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
147 	struct nvmf_auth_dhchap_reply_data *data = d;
148 	u16 dhvlen;
149 	u8 *response;
150 
151 	if (tl < sizeof(*data))
152 		return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
153 
154 	dhvlen = le16_to_cpu(data->dhvlen);
155 
156 	/* Validate that hl and dhvlen fit within the transfer length */
157 	if (sizeof(*data) + 2 * (size_t)data->hl + dhvlen > tl)
158 		return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
159 
160 	pr_debug("%s: ctrl %d qid %d: data hl %d cvalid %d dhvlen %u\n",
161 		 __func__, ctrl->cntlid, req->sq->qid,
162 		 data->hl, data->cvalid, dhvlen);
163 
164 	if (dhvlen) {
165 		if (!ctrl->dh_tfm)
166 			return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
167 		if (nvmet_auth_ctrl_sesskey(req, data->rval + 2 * data->hl,
168 					    dhvlen) < 0)
169 			return NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE;
170 	}
171 
172 	response = kmalloc(data->hl, GFP_KERNEL);
173 	if (!response)
174 		return NVME_AUTH_DHCHAP_FAILURE_FAILED;
175 
176 	if (!ctrl->host_key) {
177 		pr_warn("ctrl %d qid %d no host key\n",
178 			ctrl->cntlid, req->sq->qid);
179 		kfree(response);
180 		return NVME_AUTH_DHCHAP_FAILURE_FAILED;
181 	}
182 	if (nvmet_auth_host_hash(req, response, data->hl) < 0) {
183 		pr_debug("ctrl %d qid %d host hash failed\n",
184 			 ctrl->cntlid, req->sq->qid);
185 		kfree(response);
186 		return NVME_AUTH_DHCHAP_FAILURE_FAILED;
187 	}
188 
189 	if (crypto_memneq(data->rval, response, data->hl)) {
190 		pr_info("ctrl %d qid %d host response mismatch\n",
191 			ctrl->cntlid, req->sq->qid);
192 		pr_debug("ctrl %d qid %d rval %*ph\n",
193 			 ctrl->cntlid, req->sq->qid, data->hl, data->rval);
194 		pr_debug("ctrl %d qid %d response %*ph\n",
195 			 ctrl->cntlid, req->sq->qid, data->hl, response);
196 		kfree(response);
197 		return NVME_AUTH_DHCHAP_FAILURE_FAILED;
198 	}
199 	kfree(response);
200 	pr_debug("%s: ctrl %d qid %d host authenticated\n",
201 		 __func__, ctrl->cntlid, req->sq->qid);
202 	if (!data->cvalid && ctrl->concat) {
203 		pr_debug("%s: ctrl %d qid %d invalid challenge\n",
204 			 __func__, ctrl->cntlid, req->sq->qid);
205 		return NVME_AUTH_DHCHAP_FAILURE_FAILED;
206 	}
207 	req->sq->dhchap_s2 = le32_to_cpu(data->seqnum);
208 	if (data->cvalid) {
209 		req->sq->dhchap_c2 = kmemdup(data->rval + data->hl, data->hl,
210 					     GFP_KERNEL);
211 		if (!req->sq->dhchap_c2)
212 			return NVME_AUTH_DHCHAP_FAILURE_FAILED;
213 
214 		pr_debug("%s: ctrl %d qid %d challenge %*ph\n",
215 			 __func__, ctrl->cntlid, req->sq->qid, data->hl,
216 			 req->sq->dhchap_c2);
217 	}
218 	/*
219 	 * NVMe Base Spec 2.2 section 8.3.4.5.4: DH-HMAC-CHAP_Reply message
220 	 * Sequence Number (SEQNUM): [ .. ]
221 	 * The value 0h is used to indicate that bidirectional authentication
222 	 * is not performed, but a challenge value C2 is carried in order to
223 	 * generate a pre-shared key (PSK) for subsequent establishment of a
224 	 * secure channel.
225 	 */
226 	if (req->sq->dhchap_s2 == 0) {
227 		if (ctrl->concat)
228 			nvmet_auth_insert_psk(req->sq);
229 		req->sq->authenticated = true;
230 		kfree(req->sq->dhchap_c2);
231 		req->sq->dhchap_c2 = NULL;
232 	} else if (!data->cvalid)
233 		req->sq->authenticated = true;
234 
235 	return 0;
236 }
237 
nvmet_auth_failure2(void * d)238 static u8 nvmet_auth_failure2(void *d)
239 {
240 	struct nvmf_auth_dhchap_failure_data *data = d;
241 
242 	return data->rescode_exp;
243 }
244 
nvmet_auth_send_data_len(struct nvmet_req * req)245 u32 nvmet_auth_send_data_len(struct nvmet_req *req)
246 {
247 	return le32_to_cpu(req->cmd->auth_send.tl);
248 }
249 
nvmet_execute_auth_send(struct nvmet_req * req)250 void nvmet_execute_auth_send(struct nvmet_req *req)
251 {
252 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
253 	struct nvmf_auth_dhchap_success2_data *data;
254 	void *d;
255 	u32 tl;
256 	u16 status = 0;
257 	u8 dhchap_status;
258 
259 	if (req->cmd->auth_send.secp != NVME_AUTH_DHCHAP_PROTOCOL_IDENTIFIER) {
260 		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
261 		req->error_loc =
262 			offsetof(struct nvmf_auth_send_command, secp);
263 		goto done;
264 	}
265 	if (req->cmd->auth_send.spsp0 != 0x01) {
266 		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
267 		req->error_loc =
268 			offsetof(struct nvmf_auth_send_command, spsp0);
269 		goto done;
270 	}
271 	if (req->cmd->auth_send.spsp1 != 0x01) {
272 		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
273 		req->error_loc =
274 			offsetof(struct nvmf_auth_send_command, spsp1);
275 		goto done;
276 	}
277 	tl = nvmet_auth_send_data_len(req);
278 	if (!tl) {
279 		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
280 		req->error_loc =
281 			offsetof(struct nvmf_auth_send_command, tl);
282 		goto done;
283 	}
284 	if (!nvmet_check_transfer_len(req, tl)) {
285 		pr_debug("%s: transfer length mismatch (%u)\n", __func__, tl);
286 		return;
287 	}
288 
289 	d = kmalloc(tl, GFP_KERNEL);
290 	if (!d) {
291 		status = NVME_SC_INTERNAL;
292 		goto done;
293 	}
294 
295 	status = nvmet_copy_from_sgl(req, 0, d, tl);
296 	if (status)
297 		goto done_kfree;
298 
299 	data = d;
300 	pr_debug("%s: ctrl %d qid %d type %d id %d step %x\n", __func__,
301 		 ctrl->cntlid, req->sq->qid, data->auth_type, data->auth_id,
302 		 req->sq->dhchap_step);
303 	if (data->auth_type != NVME_AUTH_COMMON_MESSAGES &&
304 	    data->auth_type != NVME_AUTH_DHCHAP_MESSAGES)
305 		goto done_failure1;
306 	if (data->auth_type == NVME_AUTH_COMMON_MESSAGES) {
307 		if (data->auth_id == NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE) {
308 			/* Restart negotiation */
309 			pr_debug("%s: ctrl %d qid %d reset negotiation\n",
310 				 __func__, ctrl->cntlid, req->sq->qid);
311 			if (!req->sq->qid) {
312 				dhchap_status = nvmet_setup_auth(ctrl, req->sq,
313 								 true);
314 				if (dhchap_status) {
315 					pr_err("ctrl %d qid 0 failed to setup re-authentication\n",
316 					       ctrl->cntlid);
317 					req->sq->dhchap_status = dhchap_status;
318 					req->sq->dhchap_step =
319 						NVME_AUTH_DHCHAP_MESSAGE_FAILURE1;
320 					goto done_kfree;
321 				}
322 			}
323 			req->sq->dhchap_step =
324 				NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE;
325 		} else if (data->auth_id != req->sq->dhchap_step)
326 			goto done_failure1;
327 		/* Validate negotiation parameters */
328 		dhchap_status = nvmet_auth_negotiate(req, d, tl);
329 		if (dhchap_status == 0)
330 			req->sq->dhchap_step =
331 				NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE;
332 		else {
333 			req->sq->dhchap_step =
334 				NVME_AUTH_DHCHAP_MESSAGE_FAILURE1;
335 			req->sq->dhchap_status = dhchap_status;
336 		}
337 		goto done_kfree;
338 	}
339 	if (data->auth_id != req->sq->dhchap_step) {
340 		pr_debug("%s: ctrl %d qid %d step mismatch (%d != %d)\n",
341 			 __func__, ctrl->cntlid, req->sq->qid,
342 			 data->auth_id, req->sq->dhchap_step);
343 		goto done_failure1;
344 	}
345 	if (le16_to_cpu(data->t_id) != req->sq->dhchap_tid) {
346 		pr_debug("%s: ctrl %d qid %d invalid transaction %d (expected %d)\n",
347 			 __func__, ctrl->cntlid, req->sq->qid,
348 			 le16_to_cpu(data->t_id),
349 			 req->sq->dhchap_tid);
350 		req->sq->dhchap_step =
351 			NVME_AUTH_DHCHAP_MESSAGE_FAILURE1;
352 		req->sq->dhchap_status =
353 			NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
354 		goto done_kfree;
355 	}
356 
357 	switch (data->auth_id) {
358 	case NVME_AUTH_DHCHAP_MESSAGE_REPLY:
359 		dhchap_status = nvmet_auth_reply(req, d, tl);
360 		if (dhchap_status == 0)
361 			req->sq->dhchap_step =
362 				NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1;
363 		else {
364 			req->sq->dhchap_step =
365 				NVME_AUTH_DHCHAP_MESSAGE_FAILURE1;
366 			req->sq->dhchap_status = dhchap_status;
367 		}
368 		goto done_kfree;
369 	case NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2:
370 		if (ctrl->concat)
371 			nvmet_auth_insert_psk(req->sq);
372 		req->sq->authenticated = true;
373 		pr_debug("%s: ctrl %d qid %d ctrl authenticated\n",
374 			 __func__, ctrl->cntlid, req->sq->qid);
375 		goto done_kfree;
376 	case NVME_AUTH_DHCHAP_MESSAGE_FAILURE2:
377 		dhchap_status = nvmet_auth_failure2(d);
378 		if (dhchap_status) {
379 			pr_warn("ctrl %d qid %d: authentication failed (%d)\n",
380 				ctrl->cntlid, req->sq->qid, dhchap_status);
381 			req->sq->dhchap_status = dhchap_status;
382 			req->sq->authenticated = false;
383 		}
384 		goto done_kfree;
385 	default:
386 		req->sq->dhchap_status =
387 			NVME_AUTH_DHCHAP_FAILURE_INCORRECT_MESSAGE;
388 		req->sq->dhchap_step =
389 			NVME_AUTH_DHCHAP_MESSAGE_FAILURE2;
390 		req->sq->authenticated = false;
391 		goto done_kfree;
392 	}
393 done_failure1:
394 	req->sq->dhchap_status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_MESSAGE;
395 	req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_FAILURE2;
396 
397 done_kfree:
398 	kfree(d);
399 done:
400 	pr_debug("%s: ctrl %d qid %d dhchap status %x step %x\n", __func__,
401 		 ctrl->cntlid, req->sq->qid,
402 		 req->sq->dhchap_status, req->sq->dhchap_step);
403 	if (status)
404 		pr_debug("%s: ctrl %d qid %d nvme status %x error loc %d\n",
405 			 __func__, ctrl->cntlid, req->sq->qid,
406 			 status, req->error_loc);
407 	if (req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2 &&
408 	    req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) {
409 		unsigned long auth_expire_secs = ctrl->kato ? ctrl->kato : 120;
410 
411 		mod_delayed_work(system_percpu_wq, &req->sq->auth_expired_work,
412 				 auth_expire_secs * HZ);
413 		goto complete;
414 	}
415 	/* Final states, clear up variables */
416 	nvmet_auth_sq_free(req->sq);
417 	if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2)
418 		nvmet_ctrl_fatal_error(ctrl);
419 
420 complete:
421 	nvmet_req_complete(req, status);
422 }
423 
nvmet_auth_challenge(struct nvmet_req * req,void * d,int al)424 static int nvmet_auth_challenge(struct nvmet_req *req, void *d, int al)
425 {
426 	struct nvmf_auth_dhchap_challenge_data *data = d;
427 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
428 	int ret = 0;
429 	int hash_len = nvme_auth_hmac_hash_len(ctrl->shash_id);
430 	int data_size = sizeof(*d) + hash_len;
431 
432 	if (ctrl->dh_tfm)
433 		data_size += ctrl->dh_keysize;
434 	if (al < data_size) {
435 		pr_debug("%s: buffer too small (al %d need %d)\n", __func__,
436 			 al, data_size);
437 		return -EINVAL;
438 	}
439 	memset(data, 0, data_size);
440 	req->sq->dhchap_s1 = nvme_auth_get_seqnum();
441 	data->auth_type = NVME_AUTH_DHCHAP_MESSAGES;
442 	data->auth_id = NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE;
443 	data->t_id = cpu_to_le16(req->sq->dhchap_tid);
444 	data->hashid = ctrl->shash_id;
445 	data->hl = hash_len;
446 	data->seqnum = cpu_to_le32(req->sq->dhchap_s1);
447 	req->sq->dhchap_c1 = kmalloc(data->hl, GFP_KERNEL);
448 	if (!req->sq->dhchap_c1)
449 		return -ENOMEM;
450 	get_random_bytes(req->sq->dhchap_c1, data->hl);
451 	memcpy(data->cval, req->sq->dhchap_c1, data->hl);
452 	if (ctrl->dh_tfm) {
453 		data->dhgid = ctrl->dh_gid;
454 		data->dhvlen = cpu_to_le16(ctrl->dh_keysize);
455 		ret = nvmet_auth_ctrl_exponential(req, data->cval + data->hl,
456 						  ctrl->dh_keysize);
457 	}
458 	pr_debug("%s: ctrl %d qid %d seq %d transaction %d hl %d dhvlen %zu\n",
459 		 __func__, ctrl->cntlid, req->sq->qid, req->sq->dhchap_s1,
460 		 req->sq->dhchap_tid, data->hl, ctrl->dh_keysize);
461 	return ret;
462 }
463 
nvmet_auth_success1(struct nvmet_req * req,void * d,int al)464 static int nvmet_auth_success1(struct nvmet_req *req, void *d, int al)
465 {
466 	struct nvmf_auth_dhchap_success1_data *data = d;
467 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
468 	int hash_len = nvme_auth_hmac_hash_len(ctrl->shash_id);
469 
470 	WARN_ON(al < sizeof(*data));
471 	memset(data, 0, sizeof(*data));
472 	data->auth_type = NVME_AUTH_DHCHAP_MESSAGES;
473 	data->auth_id = NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1;
474 	data->t_id = cpu_to_le16(req->sq->dhchap_tid);
475 	data->hl = hash_len;
476 	if (req->sq->dhchap_c2) {
477 		if (!ctrl->ctrl_key) {
478 			pr_warn("ctrl %d qid %d no ctrl key\n",
479 				ctrl->cntlid, req->sq->qid);
480 			return NVME_AUTH_DHCHAP_FAILURE_FAILED;
481 		}
482 		if (nvmet_auth_ctrl_hash(req, data->rval, data->hl))
483 			return NVME_AUTH_DHCHAP_FAILURE_HASH_UNUSABLE;
484 		data->rvalid = 1;
485 		pr_debug("ctrl %d qid %d response %*ph\n",
486 			 ctrl->cntlid, req->sq->qid, data->hl, data->rval);
487 	}
488 	return 0;
489 }
490 
nvmet_auth_failure1(struct nvmet_req * req,void * d,int al)491 static void nvmet_auth_failure1(struct nvmet_req *req, void *d, int al)
492 {
493 	struct nvmf_auth_dhchap_failure_data *data = d;
494 
495 	WARN_ON(al < sizeof(*data));
496 	data->auth_type = NVME_AUTH_COMMON_MESSAGES;
497 	data->auth_id = NVME_AUTH_DHCHAP_MESSAGE_FAILURE1;
498 	data->t_id = cpu_to_le16(req->sq->dhchap_tid);
499 	data->rescode = NVME_AUTH_DHCHAP_FAILURE_REASON_FAILED;
500 	data->rescode_exp = req->sq->dhchap_status;
501 }
502 
nvmet_auth_receive_data_len(struct nvmet_req * req)503 u32 nvmet_auth_receive_data_len(struct nvmet_req *req)
504 {
505 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
506 	u32 al = le32_to_cpu(req->cmd->auth_receive.al);
507 	u32 min_len;
508 
509 	/*
510 	 * Reject too-short al before kmalloc(al), since the SUCCESS1 and
511 	 * FAILURE1/default builders write fixed response headers into it.
512 	 */
513 	switch (req->sq->dhchap_step) {
514 	case NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE:
515 		return al;
516 	case NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1:
517 		min_len = sizeof(struct nvmf_auth_dhchap_success1_data);
518 		if (req->sq->dhchap_c2)
519 			min_len += nvme_auth_hmac_hash_len(ctrl->shash_id);
520 		break;
521 	default:
522 		min_len = sizeof(struct nvmf_auth_dhchap_failure_data);
523 		break;
524 	}
525 
526 	if (al < min_len)
527 		return 0;
528 
529 	return al;
530 }
531 
nvmet_execute_auth_receive(struct nvmet_req * req)532 void nvmet_execute_auth_receive(struct nvmet_req *req)
533 {
534 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
535 	void *d;
536 	u32 al;
537 	u16 status = 0;
538 
539 	if (req->cmd->auth_receive.secp != NVME_AUTH_DHCHAP_PROTOCOL_IDENTIFIER) {
540 		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
541 		req->error_loc =
542 			offsetof(struct nvmf_auth_receive_command, secp);
543 		goto done;
544 	}
545 	if (req->cmd->auth_receive.spsp0 != 0x01) {
546 		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
547 		req->error_loc =
548 			offsetof(struct nvmf_auth_receive_command, spsp0);
549 		goto done;
550 	}
551 	if (req->cmd->auth_receive.spsp1 != 0x01) {
552 		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
553 		req->error_loc =
554 			offsetof(struct nvmf_auth_receive_command, spsp1);
555 		goto done;
556 	}
557 	al = nvmet_auth_receive_data_len(req);
558 	if (!al) {
559 		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
560 		req->error_loc =
561 			offsetof(struct nvmf_auth_receive_command, al);
562 		goto done;
563 	}
564 	if (!nvmet_check_transfer_len(req, al)) {
565 		pr_debug("%s: transfer length mismatch (%u)\n", __func__, al);
566 		return;
567 	}
568 
569 	d = kzalloc(al, GFP_KERNEL);
570 	if (!d) {
571 		status = NVME_SC_INTERNAL;
572 		goto done;
573 	}
574 	pr_debug("%s: ctrl %d qid %d step %x\n", __func__,
575 		 ctrl->cntlid, req->sq->qid, req->sq->dhchap_step);
576 	switch (req->sq->dhchap_step) {
577 	case NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE:
578 		if (nvmet_auth_challenge(req, d, al) < 0) {
579 			pr_warn("ctrl %d qid %d: challenge error (%d)\n",
580 				ctrl->cntlid, req->sq->qid, status);
581 			status = NVME_SC_INTERNAL;
582 			break;
583 		}
584 		req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_REPLY;
585 		break;
586 	case NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1:
587 		status = nvmet_auth_success1(req, d, al);
588 		if (status) {
589 			req->sq->dhchap_status = status;
590 			req->sq->authenticated = false;
591 			nvmet_auth_failure1(req, d, al);
592 			pr_warn("ctrl %d qid %d: success1 status (%x)\n",
593 				ctrl->cntlid, req->sq->qid,
594 				req->sq->dhchap_status);
595 			break;
596 		}
597 		req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2;
598 		break;
599 	case NVME_AUTH_DHCHAP_MESSAGE_FAILURE1:
600 		req->sq->authenticated = false;
601 		nvmet_auth_failure1(req, d, al);
602 		pr_warn("ctrl %d qid %d failure1 (%x)\n",
603 			ctrl->cntlid, req->sq->qid, req->sq->dhchap_status);
604 		break;
605 	default:
606 		pr_warn("ctrl %d qid %d unhandled step (%d)\n",
607 			ctrl->cntlid, req->sq->qid, req->sq->dhchap_step);
608 		req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_FAILURE1;
609 		req->sq->dhchap_status = NVME_AUTH_DHCHAP_FAILURE_FAILED;
610 		nvmet_auth_failure1(req, d, al);
611 		status = 0;
612 		break;
613 	}
614 
615 	status = nvmet_copy_to_sgl(req, 0, d, al);
616 	kfree(d);
617 done:
618 	if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2)
619 		nvmet_auth_sq_free(req->sq);
620 	else if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) {
621 		nvmet_auth_sq_free(req->sq);
622 		nvmet_ctrl_fatal_error(ctrl);
623 	}
624 	nvmet_req_complete(req, status);
625 }
626