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