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 : 4692 : nvmf_auth_request_complete(struct spdk_nvmf_request *req, int sct, int sc, int dnr)
65 : : {
66 [ # # # # : 4692 : struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl;
# # ]
67 : :
68 [ # # # # : 4692 : response->status.sct = sct;
# # ]
69 [ # # # # : 4692 : response->status.sc = sc;
# # ]
70 [ # # # # : 4692 : response->status.dnr = dnr;
# # ]
71 : :
72 : 4692 : spdk_nvmf_request_complete(req);
73 : 4692 : }
74 : :
75 : : static const char *
76 : 4984 : 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 [ # # # # : 4984 : return state_names[state];
# # ]
90 : : }
91 : :
92 : : static void
93 : 5688 : nvmf_auth_set_state(struct spdk_nvmf_qpair *qpair, enum nvmf_qpair_auth_state state)
94 : : {
95 [ # # # # ]: 5688 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
96 : :
97 [ + + # # : 5688 : if (auth->state == state) {
# # ]
98 : 1000 : return;
99 : : }
100 : :
101 [ - + + - : 4688 : AUTH_DEBUGLOG(qpair, "auth state: %s\n", nvmf_auth_get_state_name(state));
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
102 [ # # # # ]: 4688 : 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 : 32 : nvmf_auth_request_fail1(struct spdk_nvmf_request *req, int reason)
114 : : {
115 [ # # # # ]: 32 : struct spdk_nvmf_qpair *qpair = req->qpair;
116 [ # # # # ]: 32 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
117 : :
118 : 32 : nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_FAILURE1);
119 [ # # # # ]: 32 : 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 : 32 : nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
125 : 32 : }
126 : :
127 : : static bool
128 : 1292 : nvmf_auth_digest_allowed(struct spdk_nvmf_qpair *qpair, uint8_t digest)
129 : : {
130 [ # # # # : 1292 : struct spdk_nvmf_tgt *tgt = qpair->group->tgt;
# # # # ]
131 : :
132 [ - + # # : 1292 : return tgt->dhchap_digests & SPDK_BIT(digest);
# # ]
133 : : }
134 : :
135 : : static bool
136 : 1732 : nvmf_auth_dhgroup_allowed(struct spdk_nvmf_qpair *qpair, uint8_t dhgroup)
137 : : {
138 [ # # # # : 1732 : struct spdk_nvmf_tgt *tgt = qpair->group->tgt;
# # # # ]
139 : :
140 [ - + # # : 1732 : return tgt->dhchap_dhgroups & SPDK_BIT(dhgroup);
# # ]
141 : : }
142 : :
143 : : static void
144 : 1920 : nvmf_auth_qpair_cleanup(struct spdk_nvmf_qpair_auth *auth)
145 : : {
146 [ # # ]: 1920 : spdk_poller_unregister(&auth->poller);
147 [ # # ]: 1920 : spdk_nvme_dhchap_dhkey_free(&auth->dhkey);
148 : 1920 : }
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 : 4660 : nvmf_auth_rearm_poller(struct spdk_nvmf_qpair *qpair)
172 : : {
173 [ # # # # ]: 4660 : struct spdk_nvmf_ctrlr *ctrlr = qpair->ctrlr;
174 [ # # # # ]: 4660 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
175 : : uint64_t timeout;
176 : :
177 [ # # # # : 4660 : timeout = ctrlr->feat.keep_alive_timer.bits.kato > 0 ?
# # # # #
# ]
178 [ + - # # : 4660 : ctrlr->feat.keep_alive_timer.bits.kato * 1000 :
# # # # ]
179 : : NVMF_AUTH_DEFAULT_KATO_US;
180 : :
181 [ # # ]: 4660 : spdk_poller_unregister(&auth->poller);
182 [ # # # # ]: 4660 : auth->poller = SPDK_POLLER_REGISTER(nvmf_auth_timeout_poller, qpair, timeout);
183 [ - + # # : 4660 : if (auth->poller == NULL) {
# # ]
184 : 0 : return -ENOMEM;
185 : : }
186 : :
187 : 4660 : return 0;
188 : 0 : }
189 : :
190 : : static int
191 : 4692 : nvmf_auth_check_command(struct spdk_nvmf_request *req, uint8_t secp,
192 : : uint8_t spsp0, uint8_t spsp1, uint32_t len)
193 : : {
194 [ # # # # ]: 4692 : struct spdk_nvmf_qpair *qpair = req->qpair;
195 : :
196 [ - + ]: 4692 : if (secp != SPDK_NVMF_AUTH_SECP_NVME) {
197 [ # # # # : 0 : AUTH_ERRLOG(qpair, "invalid secp=%u\n", secp);
# # # # #
# # # # #
# # # # #
# ]
198 : 0 : return -EINVAL;
199 : : }
200 [ + - - + ]: 4692 : if (spsp0 != 1 || spsp1 != 1) {
201 [ # # # # : 0 : AUTH_ERRLOG(qpair, "invalid spsp0=%u, spsp1=%u\n", spsp0, spsp1);
# # # # #
# # # # #
# # # # #
# ]
202 : 0 : return -EINVAL;
203 : : }
204 [ - + # # : 4692 : if (len != req->length) {
# # ]
205 [ # # # # : 0 : AUTH_ERRLOG(qpair, "invalid length: %"PRIu32" != %"PRIu32"\n", len, req->length);
# # # # #
# # # # #
# # # # #
# # # #
# ]
206 : 0 : return -EINVAL;
207 : : }
208 : :
209 : 4692 : return 0;
210 : 0 : }
211 : :
212 : : static void *
213 : 4692 : nvmf_auth_get_message(struct spdk_nvmf_request *req, size_t size)
214 : : {
215 [ + - + - : 4692 : if (req->length > 0 && req->iovcnt == 1 && req->iov[0].iov_len >= size) {
+ - # # #
# # # # #
# # # # #
# # # #
# ]
216 [ # # # # : 4692 : return req->iov[0].iov_base;
# # # # #
# ]
217 : : }
218 : :
219 : 0 : return NULL;
220 : 0 : }
221 : :
222 : : static void
223 : 996 : nvmf_auth_negotiate_exec(struct spdk_nvmf_request *req, struct spdk_nvmf_auth_negotiate *msg)
224 : : {
225 [ # # # # ]: 996 : struct spdk_nvmf_qpair *qpair = req->qpair;
226 [ # # # # ]: 996 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
227 : 996 : 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 : 996 : 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 : 996 : 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 : 996 : int digest = -1, dhgroup = -1;
245 : : size_t i, j;
246 : :
247 [ - + # # : 996 : 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 : 8 : return;
251 : : }
252 : :
253 [ # # # # : 996 : auth->tid = msg->t_id;
# # # # ]
254 [ + - - + : 996 : 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 [ - + # # : 996 : 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 [ + - # # : 996 : for (i = 0; i < msg->napd; ++i) {
# # ]
267 [ + - # # : 996 : if (msg->descriptors[i].auth_id == SPDK_NVMF_AUTH_TYPE_DHCHAP) {
# # # # #
# ]
268 [ # # # # ]: 996 : desc = &msg->descriptors[i];
269 : 996 : break;
270 : : }
271 : 0 : }
272 [ - + ]: 996 : 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 [ + - # # : 996 : if (desc->halen > SPDK_COUNTOF(desc->hash_id_list) ||
# # # # ]
278 [ - + # # ]: 996 : 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 [ + + ]: 1296 : for (i = 0; i < SPDK_COUNTOF(digests); ++i) {
285 [ + + # # : 1292 : if (!nvmf_auth_digest_allowed(qpair, digests[i])) {
# # # # ]
286 : 4 : continue;
287 : : }
288 [ + + # # : 2992 : for (j = 0; j < desc->halen; ++j) {
# # ]
289 [ + + # # : 2696 : if (digests[i] == desc->hash_id_list[j]) {
# # # # #
# # # # #
# # ]
290 [ - + + - : 992 : AUTH_DEBUGLOG(qpair, "selected digest: %s\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
291 : : spdk_nvme_dhchap_get_digest_name(digests[i]));
292 [ # # # # : 992 : digest = digests[i];
# # ]
293 : 992 : break;
294 : : }
295 : 0 : }
296 [ + + ]: 1288 : if (digest >= 0) {
297 : 992 : break;
298 : : }
299 : 0 : }
300 [ + + ]: 996 : if (digest < 0) {
301 [ # # # # : 4 : AUTH_ERRLOG(qpair, "no usable digests found\n");
# # # # #
# # # # #
# # # # #
# ]
302 : 4 : nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_HASH_UNUSABLE);
303 : 4 : return;
304 : : }
305 : :
306 [ + + ]: 1736 : for (i = 0; i < SPDK_COUNTOF(dhgroups); ++i) {
307 [ + + # # : 1732 : if (!nvmf_auth_dhgroup_allowed(qpair, dhgroups[i])) {
# # # # ]
308 : 16 : continue;
309 : : }
310 [ + + # # : 5944 : for (j = 0; j < desc->dhlen; ++j) {
# # ]
311 [ + + # # : 5216 : if (dhgroups[i] == desc->dhg_id_list[j]) {
# # # # #
# # # #
# ]
312 [ - + + - : 988 : AUTH_DEBUGLOG(qpair, "selected dhgroup: %s\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
313 : : spdk_nvme_dhchap_get_dhgroup_name(dhgroups[i]));
314 [ # # # # : 988 : dhgroup = dhgroups[i];
# # ]
315 : 988 : break;
316 : : }
317 : 0 : }
318 [ + + ]: 1716 : if (dhgroup >= 0) {
319 : 988 : break;
320 : : }
321 : 0 : }
322 [ + + ]: 992 : if (dhgroup < 0) {
323 [ # # # # : 4 : AUTH_ERRLOG(qpair, "no usable dhgroups found\n");
# # # # #
# # # # #
# # # # #
# ]
324 : 4 : nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_DHGROUP_UNUSABLE);
325 : 4 : return;
326 : : }
327 : :
328 [ - + ]: 988 : 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 [ # # # # ]: 988 : auth->digest = digest;
336 [ # # # # ]: 988 : auth->dhgroup = dhgroup;
337 : 988 : nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_CHALLENGE);
338 : 988 : nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
339 : 0 : }
340 : :
341 : : static void
342 : 988 : nvmf_auth_reply_exec(struct spdk_nvmf_request *req, struct spdk_nvmf_dhchap_reply *msg)
343 : : {
344 [ # # # # ]: 988 : struct spdk_nvmf_qpair *qpair = req->qpair;
345 [ # # # # ]: 988 : struct spdk_nvmf_ctrlr *ctrlr = qpair->ctrlr;
346 [ # # # # ]: 988 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
347 : 0 : uint8_t response[NVMF_AUTH_DIGEST_MAX_SIZE];
348 : 0 : uint8_t dhsec[NVMF_AUTH_DH_KEY_MAX_SIZE];
349 : 988 : struct spdk_key *key = NULL, *ckey = NULL;
350 : 988 : size_t dhseclen = 0;
351 : : uint8_t hl;
352 : : int rc;
353 : :
354 [ - + # # : 988 : 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 [ - + # # : 988 : 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 [ # # # # ]: 988 : hl = spdk_nvme_dhchap_get_digest_length(auth->digest);
366 [ + - - + : 988 : 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 [ - + # # : 988 : 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 [ - + # # : 988 : 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 [ - + # # : 988 : 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 [ + + - + : 988 : 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 [ + + - + : 988 : 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 [ # # # # : 988 : key = nvmf_subsystem_get_dhchap_key(ctrlr->subsys, ctrlr->hostnqn, NVMF_AUTH_KEY_HOST);
# # ]
399 [ + + ]: 988 : if (key == NULL) {
400 [ # # # # : 4 : AUTH_ERRLOG(qpair, "couldn't get DH-HMAC-CHAP key\n");
# # # # #
# # # # #
# # # # #
# ]
401 : 4 : nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED);
402 : 4 : goto out;
403 : : }
404 : :
405 [ + + # # : 984 : if (auth->dhgroup != SPDK_NVMF_DHCHAP_DHGROUP_NULL) {
# # ]
406 [ - + + - : 936 : AUTH_LOGDUMP("host pubkey:", &msg->rval[2 * hl], msg->dhvlen);
# # # # #
# # # # #
# # ]
407 : 936 : dhseclen = sizeof(dhsec);
408 [ # # # # : 936 : rc = spdk_nvme_dhchap_dhkey_derive_secret(auth->dhkey, &msg->rval[2 * hl],
# # # # #
# ]
409 [ # # # # ]: 936 : msg->dhvlen, dhsec, &dhseclen);
410 [ - + ]: 936 : 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 [ - + + - : 936 : AUTH_LOGDUMP("dh secret:", dhsec, dhseclen);
# # ]
417 : 0 : }
418 : :
419 [ + - + - ]: 984 : assert(hl <= sizeof(response) && hl <= sizeof(auth->cval));
420 [ # # # # ]: 1968 : rc = spdk_nvme_dhchap_calculate(key, (enum spdk_nvmf_dhchap_hash)auth->digest,
421 [ # # # # : 984 : "HostHost", auth->seqnum, auth->tid, 0,
# # # # ]
422 [ # # # # : 984 : ctrlr->hostnqn, ctrlr->subsys->subnqn,
# # # # ]
423 [ # # ]: 984 : dhseclen > 0 ? dhsec : NULL, dhseclen,
424 [ + + ]: 984 : auth->cval, response);
425 [ - + ]: 984 : 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 [ - + + + : 984 : if (memcmp(msg->rval, response, hl) != 0) {
# # # # ]
433 [ # # # # : 16 : AUTH_ERRLOG(qpair, "challenge response mismatch\n");
# # # # #
# # # # #
# # # # #
# ]
434 [ - + + - : 16 : AUTH_LOGDUMP("response:", msg->rval, hl);
# # # # ]
435 [ - + + - : 16 : AUTH_LOGDUMP("expected:", response, hl);
# # ]
436 : 16 : nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED);
437 : 16 : goto out;
438 : : }
439 : :
440 [ + + # # : 968 : if (msg->cvalid) {
# # ]
441 [ # # # # : 728 : ckey = nvmf_subsystem_get_dhchap_key(ctrlr->subsys, ctrlr->hostnqn,
# # ]
442 : : NVMF_AUTH_KEY_CTRLR);
443 [ + + ]: 728 : if (ckey == NULL) {
444 [ # # # # : 4 : AUTH_ERRLOG(qpair, "missing DH-HMAC-CHAP ctrlr key\n");
# # # # #
# # # # #
# # # # #
# ]
445 : 4 : nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED);
446 : 4 : goto out;
447 : : }
448 [ # # # # ]: 1448 : rc = spdk_nvme_dhchap_calculate(ckey, (enum spdk_nvmf_dhchap_hash)auth->digest,
449 [ # # # # : 724 : "Controller", msg->seqnum, auth->tid, 0,
# # # # ]
450 [ # # # # : 724 : ctrlr->subsys->subnqn, ctrlr->hostnqn,
# # # # ]
451 [ # # ]: 724 : dhseclen > 0 ? dhsec : NULL, dhseclen,
452 [ + + # # : 724 : &msg->rval[hl], auth->cval);
# # ]
453 [ - + ]: 724 : 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 [ # # # # ]: 724 : auth->cvalid = true;
460 : 0 : }
461 : :
462 [ - + ]: 964 : 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 : 964 : nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_SUCCESS1);
470 : 964 : nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
471 : 988 : out:
472 : 988 : spdk_keyring_put_key(ckey);
473 : 988 : spdk_keyring_put_key(key);
474 : 988 : }
475 : :
476 : : static void
477 : 712 : nvmf_auth_success2_exec(struct spdk_nvmf_request *req, struct spdk_nvmf_dhchap_success2 *msg)
478 : : {
479 [ # # # # ]: 712 : struct spdk_nvmf_qpair *qpair = req->qpair;
480 [ # # # # ]: 712 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
481 : :
482 [ - + # # : 712 : 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 [ - + # # : 712 : 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 [ - + # # : 712 : 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 [ - + + - : 712 : AUTH_DEBUGLOG(qpair, "controller authentication successful\n");
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
499 : 712 : nvmf_qpair_set_state(qpair, SPDK_NVMF_QPAIR_ENABLED);
500 : 712 : nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_COMPLETED);
501 : 712 : nvmf_auth_qpair_cleanup(auth);
502 : 712 : nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
503 : 0 : }
504 : :
505 : : static void
506 : 12 : nvmf_auth_failure2_exec(struct spdk_nvmf_request *req, struct spdk_nvmf_auth_failure *msg)
507 : : {
508 [ # # # # ]: 12 : struct spdk_nvmf_qpair *qpair = req->qpair;
509 [ # # # # ]: 12 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
510 : :
511 : : /* AUTH_failure2 is only expected when we're waiting for the success2 message */
512 [ - + # # : 12 : 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 [ - + # # : 12 : 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 [ - + # # : 12 : 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 [ # # # # : 12 : AUTH_ERRLOG(qpair, "ctrlr authentication failed: rc=%d, rce=%d\n", msg->rc, msg->rce);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
529 : 12 : nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_ERROR);
530 : 12 : nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
531 : 0 : }
532 : :
533 : : static void
534 : 2708 : nvmf_auth_send_exec(struct spdk_nvmf_request *req)
535 : : {
536 [ # # # # ]: 2708 : struct spdk_nvmf_qpair *qpair = req->qpair;
537 [ # # # # : 2708 : 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 [ # # # # : 2708 : rc = nvmf_auth_check_command(req, cmd->secp, cmd->spsp0, cmd->spsp1, cmd->tl);
# # # # #
# # # # #
# # ]
542 [ - + ]: 2708 : 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 : 2708 : header = nvmf_auth_get_message(req, sizeof(*header));
549 [ - + ]: 2708 : if (header == NULL) {
550 : 0 : nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD);
551 : 0 : return;
552 : : }
553 : :
554 [ + + - # : 2708 : switch (header->auth_type) {
# # # ]
555 : 1008 : case SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE:
556 [ + + - # : 1008 : switch (header->auth_id) {
# # # ]
557 : 996 : case SPDK_NVMF_AUTH_ID_NEGOTIATE:
558 : 996 : nvmf_auth_negotiate_exec(req, (void *)header);
559 : 996 : break;
560 : 12 : case SPDK_NVMF_AUTH_ID_FAILURE2:
561 : 12 : nvmf_auth_failure2_exec(req, (void *)header);
562 : 12 : break;
563 : 0 : 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 : 1008 : break;
569 : 1700 : case SPDK_NVMF_AUTH_TYPE_DHCHAP:
570 [ + + - # : 1700 : switch (header->auth_id) {
# # # ]
571 : 988 : case SPDK_NVMF_AUTH_ID_DHCHAP_REPLY:
572 : 988 : nvmf_auth_reply_exec(req, (void *)header);
573 : 988 : break;
574 : 712 : case SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS2:
575 : 712 : nvmf_auth_success2_exec(req, (void *)header);
576 : 712 : break;
577 : 0 : 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 : 1700 : break;
583 : 0 : 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 : 1984 : nvmf_auth_recv_complete(struct spdk_nvmf_request *req, uint32_t length)
592 : : {
593 [ - + # # : 1984 : assert(req->cmd->nvmf_cmd.fctype == SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV);
# # # # #
# # # #
# ]
594 [ # # # # ]: 1984 : req->length = length;
595 : 1984 : nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0);
596 : 1984 : }
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 : 32 : nvmf_auth_recv_failure1(struct spdk_nvmf_request *req, int fail_reason)
612 : : {
613 [ # # # # ]: 32 : struct spdk_nvmf_qpair *qpair = req->qpair;
614 [ # # # # ]: 32 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
615 : : struct spdk_nvmf_auth_failure *failure;
616 : :
617 : 32 : failure = nvmf_auth_get_message(req, sizeof(*failure));
618 [ - + ]: 32 : 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 [ # # # # ]: 32 : failure->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE;
626 [ # # # # ]: 32 : failure->auth_id = SPDK_NVMF_AUTH_ID_FAILURE1;
627 [ # # # # : 32 : failure->t_id = auth->tid;
# # # # ]
628 [ # # # # ]: 32 : failure->rc = SPDK_NVMF_AUTH_FAILURE;
629 [ # # # # ]: 32 : failure->rce = fail_reason;
630 : :
631 : 32 : nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_FAILURE1);
632 : 32 : nvmf_auth_recv_complete(req, sizeof(*failure));
633 : :
634 [ # # ]: 32 : spdk_poller_unregister(&auth->poller);
635 [ # # # # ]: 32 : auth->poller = SPDK_POLLER_REGISTER(nvmf_auth_recv_failure1_done, qpair,
636 : : NVMF_AUTH_FAILURE1_DELAY_US);
637 : 0 : }
638 : :
639 : : static int
640 : 988 : nvmf_auth_get_seqnum(struct spdk_nvmf_qpair *qpair)
641 : : {
642 [ # # # # : 988 : struct spdk_nvmf_subsystem *subsys = qpair->ctrlr->subsys;
# # # # ]
643 [ # # # # ]: 988 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
644 : : int rc;
645 : :
646 [ - + # # ]: 988 : pthread_mutex_lock(&subsys->mutex);
647 [ + + # # : 988 : if (subsys->auth_seqnum == 0) {
# # ]
648 [ # # ]: 8 : rc = RAND_bytes((void *)&subsys->auth_seqnum, sizeof(subsys->auth_seqnum));
649 [ - + ]: 8 : if (rc != 1) {
650 [ # # # # ]: 0 : pthread_mutex_unlock(&subsys->mutex);
651 : 0 : return -EIO;
652 : : }
653 : 0 : }
654 [ - + # # ]: 988 : if (++subsys->auth_seqnum == 0) {
655 [ # # # # ]: 0 : subsys->auth_seqnum = 1;
656 : :
657 : 0 : }
658 [ # # # # : 988 : auth->seqnum = subsys->auth_seqnum;
# # # # ]
659 [ - + # # ]: 988 : pthread_mutex_unlock(&subsys->mutex);
660 : :
661 : 988 : return 0;
662 : 0 : }
663 : :
664 : : static int
665 : 988 : nvmf_auth_recv_challenge(struct spdk_nvmf_request *req)
666 : : {
667 [ # # # # ]: 988 : struct spdk_nvmf_qpair *qpair = req->qpair;
668 [ # # # # ]: 988 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
669 : : struct spdk_nvmf_dhchap_challenge *challenge;
670 : 0 : uint8_t hl, dhv[NVMF_AUTH_DH_KEY_MAX_SIZE];
671 : 988 : size_t dhvlen = 0;
672 : : int rc;
673 : :
674 [ # # # # ]: 988 : hl = spdk_nvme_dhchap_get_digest_length(auth->digest);
675 [ + - + - ]: 988 : assert(hl > 0 && hl <= sizeof(auth->cval));
676 : :
677 [ + + # # : 988 : if (auth->dhgroup != SPDK_NVMF_DHCHAP_DHGROUP_NULL) {
# # ]
678 [ # # # # : 940 : auth->dhkey = spdk_nvme_dhchap_generate_dhkey(auth->dhgroup);
# # # # ]
679 [ - + # # : 940 : 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 : 940 : dhvlen = sizeof(dhv);
685 [ # # # # ]: 940 : rc = spdk_nvme_dhchap_dhkey_get_pubkey(auth->dhkey, dhv, &dhvlen);
686 [ - + ]: 940 : 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 [ - + + - : 940 : AUTH_LOGDUMP("ctrlr pubkey:", dhv, dhvlen);
# # ]
692 : 0 : }
693 : :
694 : 988 : challenge = nvmf_auth_get_message(req, sizeof(*challenge) + hl + dhvlen);
695 [ - + ]: 988 : 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 : 988 : rc = nvmf_auth_get_seqnum(qpair);
700 [ - + ]: 988 : if (rc != 0) {
701 : 0 : return SPDK_NVMF_AUTH_FAILED;
702 : : }
703 [ # # ]: 988 : rc = RAND_bytes(auth->cval, hl);
704 [ - + ]: 988 : if (rc != 1) {
705 : 0 : return SPDK_NVMF_AUTH_FAILED;
706 : : }
707 [ - + ]: 988 : 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 [ - + - + : 988 : memcpy(challenge->cval, auth->cval, hl);
# # # # ]
715 [ - + - + : 988 : memcpy(&challenge->cval[hl], dhv, dhvlen);
# # # # ]
716 [ # # # # ]: 988 : challenge->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP;
717 [ # # # # ]: 988 : challenge->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_CHALLENGE;
718 [ # # # # : 988 : challenge->t_id = auth->tid;
# # # # ]
719 [ # # # # ]: 988 : challenge->hl = hl;
720 [ # # # # : 988 : challenge->hash_id = (uint8_t)auth->digest;
# # # # ]
721 [ # # # # : 988 : challenge->dhg_id = (uint8_t)auth->dhgroup;
# # # # ]
722 [ # # # # ]: 988 : challenge->dhvlen = dhvlen;
723 [ # # # # : 988 : challenge->seqnum = auth->seqnum;
# # # # ]
724 : :
725 : 988 : nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_REPLY);
726 : 988 : nvmf_auth_recv_complete(req, sizeof(*challenge) + hl + dhvlen);
727 : :
728 : 988 : return 0;
729 : 0 : }
730 : :
731 : : static int
732 : 964 : nvmf_auth_recv_success1(struct spdk_nvmf_request *req)
733 : : {
734 [ # # # # ]: 964 : struct spdk_nvmf_qpair *qpair = req->qpair;
735 [ # # # # ]: 964 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
736 : : struct spdk_nvmf_dhchap_success1 *success;
737 : : uint8_t hl;
738 : :
739 [ # # # # ]: 964 : hl = spdk_nvme_dhchap_get_digest_length(auth->digest);
740 [ - + # # : 964 : success = nvmf_auth_get_message(req, sizeof(*success) + auth->cvalid * hl);
# # ]
741 [ - + ]: 964 : 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 [ - + + - : 964 : AUTH_DEBUGLOG(qpair, "host authentication successful\n");
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
747 [ # # # # ]: 964 : success->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP;
748 [ # # # # ]: 964 : success->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS1;
749 [ # # # # : 964 : success->t_id = auth->tid;
# # # # ]
750 : : /* Kernel initiator always expects hl to be set, regardless of rvalid */
751 [ # # # # ]: 964 : success->hl = hl;
752 [ # # # # ]: 964 : success->rvalid = 0;
753 : :
754 [ - + + + : 964 : if (!auth->cvalid) {
# # # # ]
755 : : /* Host didn't request to authenticate us, we're done */
756 : 240 : nvmf_qpair_set_state(qpair, SPDK_NVMF_QPAIR_ENABLED);
757 : 240 : nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_COMPLETED);
758 : 240 : nvmf_auth_qpair_cleanup(auth);
759 : 0 : } else {
760 [ - + ]: 724 : 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 [ - + + - : 724 : AUTH_DEBUGLOG(qpair, "cvalid=1, starting controller authentication\n");
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
767 : 724 : nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_SUCCESS2);
768 [ - + - + : 724 : memcpy(success->rval, auth->cval, hl);
# # # # ]
769 [ # # # # ]: 724 : success->rvalid = 1;
770 : : }
771 : :
772 [ - + # # : 964 : nvmf_auth_recv_complete(req, sizeof(*success) + auth->cvalid * hl);
# # ]
773 : 964 : return 0;
774 : 0 : }
775 : :
776 : : static void
777 : 1984 : nvmf_auth_recv_exec(struct spdk_nvmf_request *req)
778 : : {
779 [ # # # # ]: 1984 : struct spdk_nvmf_qpair *qpair = req->qpair;
780 [ # # # # ]: 1984 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
781 [ # # # # : 1984 : struct spdk_nvmf_fabric_auth_recv_cmd *cmd = &req->cmd->auth_recv_cmd;
# # ]
782 : : int rc;
783 : :
784 [ # # # # : 1984 : rc = nvmf_auth_check_command(req, cmd->secp, cmd->spsp0, cmd->spsp1, cmd->al);
# # # # #
# # # # #
# # ]
785 [ - + ]: 1984 : 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 [ # # # # : 1984 : spdk_iov_memset(req->iov, req->iovcnt, 0);
# # ]
792 [ + + + - : 1984 : switch (auth->state) {
# # # # ]
793 : 988 : case NVMF_QPAIR_AUTH_CHALLENGE:
794 : 988 : rc = nvmf_auth_recv_challenge(req);
795 [ - + ]: 988 : if (rc != 0) {
796 : 0 : nvmf_auth_recv_failure1(req, rc);
797 : 0 : }
798 : 988 : break;
799 : 964 : case NVMF_QPAIR_AUTH_SUCCESS1:
800 : 964 : rc = nvmf_auth_recv_success1(req);
801 [ - + ]: 964 : if (rc != 0) {
802 : 0 : nvmf_auth_recv_failure1(req, rc);
803 : 0 : }
804 : 964 : break;
805 : 32 : case NVMF_QPAIR_AUTH_FAILURE1:
806 [ # # # # ]: 32 : nvmf_auth_recv_failure1(req, auth->fail_reason);
807 : 32 : break;
808 : 0 : 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 : 4692 : nvmf_auth_check_state(struct spdk_nvmf_qpair *qpair, struct spdk_nvmf_request *req)
816 : : {
817 [ # # # # ]: 4692 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
818 : : int rc;
819 : :
820 [ + + - # : 4692 : switch (qpair->state) {
# # # ]
821 : 4540 : case SPDK_NVMF_QPAIR_AUTHENTICATING:
822 : 4540 : break;
823 : 152 : case SPDK_NVMF_QPAIR_ENABLED:
824 [ + + + + : 152 : if (auth == NULL || auth->state == NVMF_QPAIR_AUTH_COMPLETED) {
# # # # ]
825 : 32 : rc = nvmf_qpair_auth_init(qpair);
826 [ - + ]: 32 : 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 : 152 : break;
833 : 0 : 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 : 4692 : return true;
840 : 0 : }
841 : :
842 : : int
843 : 4692 : nvmf_auth_request_exec(struct spdk_nvmf_request *req)
844 : : {
845 [ # # # # ]: 4692 : struct spdk_nvmf_qpair *qpair = req->qpair;
846 [ # # # # ]: 4692 : union nvmf_h2c_msg *cmd = req->cmd;
847 : :
848 [ - + ]: 4692 : if (!nvmf_auth_check_state(qpair, req)) {
849 : 0 : goto out;
850 : : }
851 : :
852 [ - + # # : 4692 : assert(cmd->nvmf_cmd.opcode == SPDK_NVME_OPC_FABRIC);
# # # # #
# ]
853 [ + + - # : 4692 : switch (cmd->nvmf_cmd.fctype) {
# # # #
# ]
854 : 2708 : case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND:
855 : 2708 : nvmf_auth_send_exec(req);
856 : 2708 : break;
857 : 1984 : case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV:
858 : 1984 : nvmf_auth_recv_exec(req);
859 : 1984 : break;
860 : 0 : 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 : 4692 : out:
867 : 4692 : return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS;
868 : : }
869 : :
870 : : int
871 : 996 : nvmf_qpair_auth_init(struct spdk_nvmf_qpair *qpair)
872 : : {
873 [ # # # # ]: 996 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
874 : : int rc;
875 : :
876 [ + + ]: 996 : if (auth == NULL) {
877 : 968 : auth = calloc(1, sizeof(*qpair->auth));
878 [ - + ]: 968 : if (auth == NULL) {
879 : 0 : return -ENOMEM;
880 : : }
881 : 0 : }
882 : :
883 [ # # # # ]: 996 : auth->digest = -1;
884 [ # # # # ]: 996 : qpair->auth = auth;
885 : 996 : nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_NEGOTIATE);
886 : :
887 : 996 : rc = nvmf_auth_rearm_poller(qpair);
888 [ - + ]: 996 : 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 : 996 : return 0;
895 : 0 : }
896 : :
897 : : void
898 : 9575 : nvmf_qpair_auth_destroy(struct spdk_nvmf_qpair *qpair)
899 : : {
900 [ + - + - ]: 9575 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
901 : :
902 [ + + ]: 9575 : if (auth != NULL) {
903 : 968 : nvmf_auth_qpair_cleanup(auth);
904 [ # # # # ]: 968 : free(qpair->auth);
905 [ # # # # ]: 968 : qpair->auth = NULL;
906 : 0 : }
907 : 9575 : }
908 : :
909 : : void
910 : 298 : nvmf_qpair_auth_dump(struct spdk_nvmf_qpair *qpair, struct spdk_json_write_ctx *w)
911 : : {
912 [ # # # # ]: 298 : struct spdk_nvmf_qpair_auth *auth = qpair->auth;
913 : : const char *digest, *dhgroup;
914 : :
915 [ + + ]: 298 : if (auth == NULL) {
916 : 2 : return;
917 : : }
918 : :
919 : 296 : spdk_json_write_named_object_begin(w, "auth");
920 [ # # # # ]: 296 : spdk_json_write_named_string(w, "state", nvmf_auth_get_state_name(auth->state));
921 [ # # # # ]: 296 : digest = spdk_nvme_dhchap_get_digest_name(auth->digest);
922 [ + - ]: 296 : spdk_json_write_named_string(w, "digest", digest ? digest : "unknown");
923 [ # # # # ]: 296 : dhgroup = spdk_nvme_dhchap_get_dhgroup_name(auth->dhgroup);
924 [ + - ]: 296 : spdk_json_write_named_string(w, "dhgroup", dhgroup ? dhgroup : "unknown");
925 : 296 : spdk_json_write_object_end(w);
926 : 0 : }
927 : :
928 : : bool
929 : 356 : nvmf_auth_is_supported(void)
930 : : {
931 : 356 : return true;
932 : : }
933 : 954 : SPDK_LOG_REGISTER_COMPONENT(nvmf_auth)
|