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