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