Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2024 Intel Corporation. All rights reserved.
3 : : */
4 : :
5 : : #include "spdk/base64.h"
6 : : #include "spdk/crc32.h"
7 : : #include "spdk/endian.h"
8 : : #include "spdk/log.h"
9 : : #include "spdk/string.h"
10 : : #include "spdk/util.h"
11 : : #include "spdk_internal/nvme.h"
12 : : #include "nvme_internal.h"
13 : :
14 : : #ifdef SPDK_CONFIG_HAVE_EVP_MAC
15 : : #include <openssl/dh.h>
16 : : #include <openssl/evp.h>
17 : : #include <openssl/param_build.h>
18 : : #include <openssl/rand.h>
19 : : #endif
20 : :
21 : : struct nvme_auth_digest {
22 : : uint8_t id;
23 : : const char *name;
24 : : uint8_t len;
25 : : };
26 : :
27 : : struct nvme_auth_dhgroup {
28 : : uint8_t id;
29 : : const char *name;
30 : : };
31 : :
32 : : #define NVME_AUTH_DATA_SIZE 4096
33 : : #define NVME_AUTH_DH_KEY_MAX_SIZE 1024
34 : : #define NVME_AUTH_CHAP_KEY_MAX_SIZE 256
35 : :
36 : : #define AUTH_DEBUGLOG(q, fmt, ...) \
37 : : SPDK_DEBUGLOG(nvme_auth, "[%s:%s:%u] " fmt, (q)->ctrlr->trid.subnqn, \
38 : : (q)->ctrlr->opts.hostnqn, (q)->id, ## __VA_ARGS__)
39 : : #define AUTH_ERRLOG(q, fmt, ...) \
40 : : SPDK_ERRLOG("[%s:%s:%u] " fmt, (q)->ctrlr->trid.subnqn, (q)->ctrlr->opts.hostnqn, \
41 : : (q)->id, ## __VA_ARGS__)
42 : : #define AUTH_LOGDUMP(msg, buf, len) \
43 : : SPDK_LOGDUMP(nvme_auth, msg, buf, len)
44 : :
45 : : static const struct nvme_auth_digest g_digests[] = {
46 : : { SPDK_NVMF_DHCHAP_HASH_SHA256, "sha256", 32 },
47 : : { SPDK_NVMF_DHCHAP_HASH_SHA384, "sha384", 48 },
48 : : { SPDK_NVMF_DHCHAP_HASH_SHA512, "sha512", 64 },
49 : : };
50 : :
51 : : static const struct nvme_auth_dhgroup g_dhgroups[] = {
52 : : { SPDK_NVMF_DHCHAP_DHGROUP_NULL, "null" },
53 : : { SPDK_NVMF_DHCHAP_DHGROUP_2048, "ffdhe2048" },
54 : : { SPDK_NVMF_DHCHAP_DHGROUP_3072, "ffdhe3072" },
55 : : { SPDK_NVMF_DHCHAP_DHGROUP_4096, "ffdhe4096" },
56 : : { SPDK_NVMF_DHCHAP_DHGROUP_6144, "ffdhe6144" },
57 : : { SPDK_NVMF_DHCHAP_DHGROUP_8192, "ffdhe8192" },
58 : : };
59 : :
60 : : static const struct nvme_auth_digest *
61 : 25816 : nvme_auth_get_digest(int id)
62 : : {
63 : : size_t i;
64 : :
65 [ + - ]: 59392 : for (i = 0; i < SPDK_COUNTOF(g_digests); ++i) {
66 [ + + + - : 59392 : if (g_digests[i].id == id) {
+ - + - +
+ ]
67 [ - + - + ]: 25816 : return &g_digests[i];
68 : : }
69 : 60 : }
70 : :
71 : 0 : return NULL;
72 : 60 : }
73 : :
74 : : int
75 : 1540 : spdk_nvme_dhchap_get_digest_id(const char *digest)
76 : : {
77 : : size_t i;
78 : :
79 [ + - ]: 3076 : for (i = 0; i < SPDK_COUNTOF(g_digests); ++i) {
80 [ + + + + : 3076 : if (strcmp(g_digests[i].name, digest) == 0) {
+ + + - +
- + - +
+ ]
81 [ - + - + : 1540 : return g_digests[i].id;
- + - + ]
82 : : }
83 : 54 : }
84 : :
85 : 0 : return -EINVAL;
86 : 54 : }
87 : :
88 : : const char *
89 : 16512 : spdk_nvme_dhchap_get_digest_name(int id)
90 : : {
91 : 16512 : const struct nvme_auth_digest *digest = nvme_auth_get_digest(id);
92 : :
93 [ + - - + : 16512 : return digest != NULL ? digest->name : NULL;
- + ]
94 : : }
95 : :
96 : : int
97 : 2448 : spdk_nvme_dhchap_get_dhgroup_id(const char *dhgroup)
98 : : {
99 : : size_t i;
100 : :
101 [ + - ]: 8732 : for (i = 0; i < SPDK_COUNTOF(g_dhgroups); ++i) {
102 [ + + + + : 8732 : if (strcmp(g_dhgroups[i].name, dhgroup) == 0) {
+ + + - +
- + - +
+ ]
103 [ - + - + : 2448 : return g_dhgroups[i].id;
- + - + ]
104 : : }
105 : 270 : }
106 : :
107 : 0 : return -EINVAL;
108 : 108 : }
109 : :
110 : : const char *
111 : 6576 : spdk_nvme_dhchap_get_dhgroup_name(int id)
112 : : {
113 : : size_t i;
114 : :
115 [ + - ]: 27456 : for (i = 0; i < SPDK_COUNTOF(g_dhgroups); ++i) {
116 [ + + + - : 27456 : if (g_dhgroups[i].id == id) {
+ - + - +
+ ]
117 [ - + - + : 6576 : return g_dhgroups[i].name;
- + - + ]
118 : : }
119 : 300 : }
120 : :
121 : 0 : return NULL;
122 : 120 : }
123 : :
124 : : uint8_t
125 : 9304 : spdk_nvme_dhchap_get_digest_length(int id)
126 : : {
127 : 9304 : const struct nvme_auth_digest *digest = nvme_auth_get_digest(id);
128 : :
129 [ + - # # : 9304 : return digest != NULL ? digest->len : 0;
# # ]
130 : : }
131 : :
132 : : #ifdef SPDK_CONFIG_HAVE_EVP_MAC
133 : : static bool
134 : 4120 : nvme_auth_digest_allowed(struct spdk_nvme_qpair *qpair, uint8_t digest)
135 : : {
136 [ # # # # ]: 4120 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
137 : :
138 [ - + # # : 4120 : return ctrlr->opts.dhchap_digests & SPDK_BIT(digest);
# # # # ]
139 : : }
140 : :
141 : : static bool
142 : 7216 : nvme_auth_dhgroup_allowed(struct spdk_nvme_qpair *qpair, uint8_t dhgroup)
143 : : {
144 [ # # # # ]: 7216 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
145 : :
146 [ - + # # : 7216 : return ctrlr->opts.dhchap_dhgroups & SPDK_BIT(dhgroup);
# # # # ]
147 : : }
148 : :
149 : : static void
150 : 6956 : nvme_auth_set_state(struct spdk_nvme_qpair *qpair, enum nvme_qpair_auth_state state)
151 : : {
152 : : static const char *state_names[] __attribute__((unused)) = {
153 : : [NVME_QPAIR_AUTH_STATE_NEGOTIATE] = "negotiate",
154 : : [NVME_QPAIR_AUTH_STATE_AWAIT_NEGOTIATE] = "await-negotiate",
155 : : [NVME_QPAIR_AUTH_STATE_AWAIT_CHALLENGE] = "await-challenge",
156 : : [NVME_QPAIR_AUTH_STATE_AWAIT_REPLY] = "await-reply",
157 : : [NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS1] = "await-success1",
158 : : [NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS2] = "await-success2",
159 : : [NVME_QPAIR_AUTH_STATE_AWAIT_FAILURE2] = "await-failure2",
160 : : [NVME_QPAIR_AUTH_STATE_DONE] = "done",
161 : : };
162 : :
163 [ - + + - : 6956 : AUTH_DEBUGLOG(qpair, "auth state: %s\n", state_names[state]);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
164 [ # # # # : 6956 : qpair->auth.state = state;
# # ]
165 : 6956 : }
166 : :
167 : : static void
168 : 68 : nvme_auth_set_failure(struct spdk_nvme_qpair *qpair, int status, bool failure2)
169 : : {
170 [ + + # # : 68 : if (qpair->auth.status == 0) {
# # # # ]
171 [ # # # # : 52 : qpair->auth.status = status;
# # ]
172 : 0 : }
173 : :
174 [ + + ]: 68 : nvme_auth_set_state(qpair, failure2 ?
175 : : NVME_QPAIR_AUTH_STATE_AWAIT_FAILURE2 :
176 : : NVME_QPAIR_AUTH_STATE_DONE);
177 : 68 : }
178 : :
179 : : static void
180 : 1 : nvme_auth_print_cpl(struct spdk_nvme_qpair *qpair, const char *msg)
181 : : {
182 [ # # # # ]: 1 : struct nvme_completion_poll_status *status = qpair->poll_status;
183 : :
184 [ - + - + : 1 : AUTH_ERRLOG(qpair, "%s failed: sc=%d, sct=%d (timed out: %s)\n", msg, status->cpl.status.sc,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
185 : : status->cpl.status.sct, status->timed_out ? "true" : "false");
186 : 1 : }
187 : :
188 : : static uint32_t
189 : 804 : nvme_auth_get_seqnum(struct spdk_nvme_qpair *qpair)
190 : : {
191 [ # # # # ]: 804 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
192 : : uint32_t seqnum;
193 : : int rc;
194 : :
195 : 804 : nvme_ctrlr_lock(ctrlr);
196 [ + + # # : 804 : if (ctrlr->auth_seqnum == 0) {
# # ]
197 [ # # ]: 500 : rc = RAND_bytes((void *)&ctrlr->auth_seqnum, sizeof(ctrlr->auth_seqnum));
198 [ - + ]: 500 : if (rc != 1) {
199 : 0 : nvme_ctrlr_unlock(ctrlr);
200 : 0 : return 0;
201 : : }
202 : 0 : }
203 [ - + # # ]: 804 : if (++ctrlr->auth_seqnum == 0) {
204 [ # # # # ]: 0 : ctrlr->auth_seqnum = 1;
205 : 0 : }
206 [ # # # # ]: 804 : seqnum = ctrlr->auth_seqnum;
207 : 804 : nvme_ctrlr_unlock(ctrlr);
208 : :
209 : 804 : return seqnum;
210 : 0 : }
211 : :
212 : : static int
213 : 3536 : nvme_auth_transform_key(struct spdk_key *key, int hash, const char *nqn,
214 : : const void *keyin, size_t keylen, void *out, size_t outlen)
215 : : {
216 : 3536 : EVP_MAC *hmac = NULL;
217 : 3536 : EVP_MAC_CTX *ctx = NULL;
218 : 0 : OSSL_PARAM params[2];
219 : : int rc;
220 : :
221 [ + + - ]: 3536 : switch (hash) {
222 : 744 : case SPDK_NVMF_DHCHAP_HASH_NONE:
223 [ - + ]: 744 : if (keylen > outlen) {
224 : 0 : SPDK_ERRLOG("Key buffer too small: %zu < %zu (key=%s)\n", outlen, keylen,
225 : : spdk_key_get_name(key));
226 : 0 : return -ENOBUFS;
227 : : }
228 [ - + - + ]: 744 : memcpy(out, keyin, keylen);
229 : 744 : return keylen;
230 : 2792 : case SPDK_NVMF_DHCHAP_HASH_SHA256:
231 : : case SPDK_NVMF_DHCHAP_HASH_SHA384:
232 : : case SPDK_NVMF_DHCHAP_HASH_SHA512:
233 : 2792 : break;
234 : 0 : default:
235 : 0 : SPDK_ERRLOG("Unsupported key hash: 0x%x (key=%s)\n", hash, spdk_key_get_name(key));
236 : 0 : return -EINVAL;
237 : : }
238 : :
239 : 2792 : hmac = EVP_MAC_fetch(NULL, "hmac", NULL);
240 [ - + ]: 2792 : if (hmac == NULL) {
241 : 0 : return -EIO;
242 : : }
243 : 2792 : ctx = EVP_MAC_CTX_new(hmac);
244 [ - + ]: 2792 : if (ctx == NULL) {
245 : 0 : rc = -EIO;
246 : 0 : goto out;
247 : : }
248 [ # # # # ]: 2792 : params[0] = OSSL_PARAM_construct_utf8_string("digest",
249 : 2792 : (char *)spdk_nvme_dhchap_get_digest_name(hash), 0);
250 [ # # # # ]: 2792 : params[1] = OSSL_PARAM_construct_end();
251 : :
252 [ - + ]: 2792 : if (EVP_MAC_init(ctx, keyin, keylen, params) != 1) {
253 : 0 : rc = -EIO;
254 : 0 : goto out;
255 : : }
256 [ - + - + ]: 2792 : if (EVP_MAC_update(ctx, nqn, strlen(nqn)) != 1) {
257 : 0 : rc = -EIO;
258 : 0 : goto out;
259 : : }
260 [ - + ]: 2792 : if (EVP_MAC_update(ctx, "NVMe-over-Fabrics", strlen("NVMe-over-Fabrics")) != 1) {
261 : 0 : rc = -EIO;
262 : 0 : goto out;
263 : : }
264 [ - + ]: 2792 : if (EVP_MAC_final(ctx, out, &outlen, outlen) != 1) {
265 : 0 : rc = -EIO;
266 : 0 : goto out;
267 : : }
268 : 2792 : rc = (int)outlen;
269 : 2792 : out:
270 : 2792 : EVP_MAC_CTX_free(ctx);
271 : 2792 : EVP_MAC_free(hmac);
272 : :
273 : 2792 : return rc;
274 : 0 : }
275 : :
276 : : static int
277 : 3536 : nvme_auth_get_key(struct spdk_key *key, const char *nqn, void *buf, size_t buflen)
278 : : {
279 : 3536 : char keystr[NVME_AUTH_CHAP_KEY_MAX_SIZE + 1] = {};
280 : 3536 : char keyb64[NVME_AUTH_CHAP_KEY_MAX_SIZE] = {};
281 : : char *tmp, *secret;
282 : 0 : int rc, hash;
283 : 0 : size_t keylen;
284 : :
285 : 3536 : rc = spdk_key_get_key(key, keystr, NVME_AUTH_CHAP_KEY_MAX_SIZE);
286 [ - + ]: 3536 : if (rc < 0) {
287 [ # # ]: 0 : SPDK_ERRLOG("Failed to load key=%s: %s\n", spdk_key_get_name(key),
288 : : spdk_strerror(-rc));
289 : 0 : goto out;
290 : : }
291 : :
292 : 3536 : rc = sscanf(keystr, "DHHC-1:%02x:", &hash);
293 [ - + ]: 3536 : if (rc != 1) {
294 : 0 : SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key));
295 : 0 : rc = -EINVAL;
296 : 0 : goto out;
297 : :
298 : : }
299 : : /* Start at the first character after second ":" and remove the trailing ":" */
300 [ # # # # ]: 3536 : secret = &keystr[10];
301 [ - + # # ]: 3536 : tmp = strstr(secret, ":");
302 [ - + ]: 3536 : if (!tmp) {
303 : 0 : SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key));
304 : 0 : rc = -EINVAL;
305 : 0 : goto out;
306 : : }
307 : :
308 [ # # ]: 3536 : *tmp = '\0';
309 : 3536 : keylen = sizeof(keyb64);
310 : 3536 : rc = spdk_base64_decode(keyb64, &keylen, secret);
311 [ - + ]: 3536 : if (rc != 0) {
312 : 0 : SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key));
313 : 0 : rc = -EINVAL;
314 : 0 : goto out;
315 : : }
316 : : /* Only 32B, 48B, and 64B keys are supported (+ 4B, as they're followed by a crc32) */
317 [ + + + + : 3536 : if (keylen != 36 && keylen != 52 && keylen != 68) {
- + ]
318 : 0 : SPDK_ERRLOG("Invalid key size=%zu (key=%s)\n", keylen, spdk_key_get_name(key));
319 : 0 : rc = -EINVAL;
320 : 0 : goto out;
321 : : }
322 : :
323 : 3536 : keylen -= 4;
324 [ - + # # : 3536 : if (~spdk_crc32_ieee_update(keyb64, keylen, ~0) != from_le32(&keyb64[keylen])) {
# # ]
325 : 0 : SPDK_ERRLOG("Invalid key checksum (key=%s)\n", spdk_key_get_name(key));
326 : 0 : rc = -EINVAL;
327 : 0 : goto out;
328 : : }
329 : :
330 : 3536 : rc = nvme_auth_transform_key(key, hash, nqn, keyb64, keylen, buf, buflen);
331 : 3536 : out:
332 : 3536 : spdk_memset_s(keystr, sizeof(keystr), 0, sizeof(keystr));
333 : 3536 : spdk_memset_s(keyb64, sizeof(keyb64), 0, sizeof(keyb64));
334 : :
335 : 3536 : return rc;
336 : : }
337 : :
338 : : static int
339 : 3536 : nvme_auth_augment_challenge(const void *cval, size_t clen, const void *key, size_t keylen,
340 : : void *caval, size_t *calen, enum spdk_nvmf_dhchap_hash hash)
341 : : {
342 : 3536 : EVP_MAC *hmac = NULL;
343 : 3536 : EVP_MAC_CTX *ctx = NULL;
344 : 3536 : EVP_MD *md = NULL;
345 : 0 : OSSL_PARAM params[2];
346 : 0 : uint8_t keydgst[NVME_AUTH_DIGEST_MAX_SIZE];
347 : 3536 : unsigned int dgstlen = sizeof(keydgst);
348 : 3536 : int rc = 0;
349 : :
350 : : /* If there's no key, there's nothing to augment, cval == caval */
351 [ + + ]: 3536 : if (key == NULL) {
352 [ - + # # : 168 : assert(clen <= *calen);
# # ]
353 [ - + - + ]: 168 : memcpy(caval, cval, clen);
354 [ # # ]: 168 : *calen = clen;
355 : 168 : return 0;
356 : : }
357 : :
358 : 3368 : md = EVP_MD_fetch(NULL, spdk_nvme_dhchap_get_digest_name(hash), NULL);
359 [ - + ]: 3368 : if (!md) {
360 : 0 : SPDK_ERRLOG("Failed to fetch digest function: %d\n", hash);
361 : 0 : return -EINVAL;
362 : : }
363 [ - + ]: 3368 : if (EVP_Digest(key, keylen, keydgst, &dgstlen, md, NULL) != 1) {
364 : 0 : rc = -EIO;
365 : 0 : goto out;
366 : : }
367 : :
368 : 3368 : hmac = EVP_MAC_fetch(NULL, "hmac", NULL);
369 [ - + ]: 3368 : if (hmac == NULL) {
370 : 0 : rc = -EIO;
371 : 0 : goto out;
372 : : }
373 : 3368 : ctx = EVP_MAC_CTX_new(hmac);
374 [ - + ]: 3368 : if (ctx == NULL) {
375 : 0 : rc = -EIO;
376 : 0 : goto out;
377 : : }
378 [ # # # # ]: 3368 : params[0] = OSSL_PARAM_construct_utf8_string("digest",
379 : 3368 : (char *)spdk_nvme_dhchap_get_digest_name(hash), 0);
380 [ # # # # ]: 3368 : params[1] = OSSL_PARAM_construct_end();
381 : :
382 [ - + ]: 3368 : if (EVP_MAC_init(ctx, keydgst, dgstlen, params) != 1) {
383 : 0 : rc = -EIO;
384 : 0 : goto out;
385 : : }
386 [ - + ]: 3368 : if (EVP_MAC_update(ctx, cval, clen) != 1) {
387 : 0 : rc = -EIO;
388 : 0 : goto out;
389 : : }
390 [ + - # # ]: 3368 : if (EVP_MAC_final(ctx, caval, calen, *calen) != 1) {
391 : 0 : rc = -EIO;
392 : 0 : goto out;
393 : : }
394 : 3368 : out:
395 : 3368 : EVP_MD_free(md);
396 : 3368 : EVP_MAC_CTX_free(ctx);
397 : 3368 : EVP_MAC_free(hmac);
398 : :
399 : 3368 : return rc;
400 : 0 : }
401 : :
402 : : int
403 : 3536 : spdk_nvme_dhchap_calculate(struct spdk_key *key, enum spdk_nvmf_dhchap_hash hash,
404 : : const char *type, uint32_t seq, uint16_t tid, uint8_t scc,
405 : : const char *nqn1, const char *nqn2, const void *dhkey, size_t dhlen,
406 : : const void *cval, void *rval)
407 : : {
408 : : EVP_MAC *hmac;
409 : : EVP_MAC_CTX *ctx;
410 : 0 : OSSL_PARAM params[2];
411 : 3536 : uint8_t keybuf[NVME_AUTH_CHAP_KEY_MAX_SIZE], term = 0;
412 : 0 : uint8_t caval[NVME_AUTH_DATA_SIZE];
413 : 3536 : size_t hlen, calen = sizeof(caval);
414 : : int rc, keylen;
415 : :
416 : 3536 : hlen = spdk_nvme_dhchap_get_digest_length(hash);
417 : 3536 : rc = nvme_auth_augment_challenge(cval, hlen, dhkey, dhlen, caval, &calen, hash);
418 [ - + ]: 3536 : if (rc != 0) {
419 : 0 : return rc;
420 : : }
421 : :
422 : 3536 : hmac = EVP_MAC_fetch(NULL, "hmac", NULL);
423 [ - + ]: 3536 : if (hmac == NULL) {
424 : 0 : return -EIO;
425 : : }
426 : :
427 : 3536 : ctx = EVP_MAC_CTX_new(hmac);
428 [ - + ]: 3536 : if (ctx == NULL) {
429 : 0 : rc = -EIO;
430 : 0 : goto out;
431 : : }
432 : :
433 : 3536 : keylen = nvme_auth_get_key(key, nqn1, keybuf, sizeof(keybuf));
434 [ - + ]: 3536 : if (keylen < 0) {
435 : 0 : rc = keylen;
436 : 0 : goto out;
437 : : }
438 : :
439 [ # # # # ]: 3536 : params[0] = OSSL_PARAM_construct_utf8_string("digest",
440 : 3536 : (char *)spdk_nvme_dhchap_get_digest_name(hash), 0);
441 [ # # # # ]: 3536 : params[1] = OSSL_PARAM_construct_end();
442 : :
443 : 3536 : rc = -EIO;
444 [ - + ]: 3536 : if (EVP_MAC_init(ctx, keybuf, (size_t)keylen, params) != 1) {
445 : 0 : goto out;
446 : : }
447 [ - + ]: 3536 : if (EVP_MAC_update(ctx, caval, calen) != 1) {
448 : 0 : goto out;
449 : : }
450 [ - + ]: 3536 : if (EVP_MAC_update(ctx, (void *)&seq, sizeof(seq)) != 1) {
451 : 0 : goto out;
452 : : }
453 [ - + ]: 3536 : if (EVP_MAC_update(ctx, (void *)&tid, sizeof(tid)) != 1) {
454 : 0 : goto out;
455 : : }
456 [ - + ]: 3536 : if (EVP_MAC_update(ctx, (void *)&scc, sizeof(scc)) != 1) {
457 : 0 : goto out;
458 : : }
459 [ - + - + ]: 3536 : if (EVP_MAC_update(ctx, (void *)type, strlen(type)) != 1) {
460 : 0 : goto out;
461 : : }
462 [ - + - + ]: 3536 : if (EVP_MAC_update(ctx, (void *)nqn1, strlen(nqn1)) != 1) {
463 : 0 : goto out;
464 : : }
465 [ - + ]: 3536 : if (EVP_MAC_update(ctx, (void *)&term, sizeof(term)) != 1) {
466 : 0 : goto out;
467 : : }
468 [ - + - + ]: 3536 : if (EVP_MAC_update(ctx, (void *)nqn2, strlen(nqn2)) != 1) {
469 : 0 : goto out;
470 : : }
471 [ - + ]: 3536 : if (EVP_MAC_final(ctx, rval, &hlen, hlen) != 1) {
472 : 0 : goto out;
473 : : }
474 : 3536 : rc = 0;
475 : 3536 : out:
476 : 3536 : spdk_memset_s(keybuf, sizeof(keybuf), 0, sizeof(keybuf));
477 : 3536 : EVP_MAC_CTX_free(ctx);
478 : 3536 : EVP_MAC_free(hmac);
479 : :
480 : 3536 : return rc;
481 : 0 : }
482 : :
483 : : struct spdk_nvme_dhchap_dhkey *
484 : 1916 : spdk_nvme_dhchap_generate_dhkey(enum spdk_nvmf_dhchap_dhgroup dhgroup)
485 : : {
486 : 1916 : EVP_PKEY_CTX *ctx = NULL;
487 : 1916 : EVP_PKEY *key = NULL;
488 : 0 : OSSL_PARAM params[2];
489 : :
490 : 1916 : ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL);
491 [ - + ]: 1916 : if (ctx == NULL) {
492 : 0 : goto error;
493 : : }
494 [ - + ]: 1916 : if (EVP_PKEY_keygen_init(ctx) != 1) {
495 : 0 : goto error;
496 : : }
497 : :
498 [ # # # # ]: 1916 : params[0] = OSSL_PARAM_construct_utf8_string("group",
499 : 1916 : (char *)spdk_nvme_dhchap_get_dhgroup_name(dhgroup), 0);
500 [ # # # # ]: 1916 : params[1] = OSSL_PARAM_construct_end();
501 [ - + ]: 1916 : if (EVP_PKEY_CTX_set_params(ctx, params) != 1) {
502 : 0 : SPDK_ERRLOG("Failed to set dhkey's dhgroup: %s\n",
503 : : spdk_nvme_dhchap_get_dhgroup_name(dhgroup));
504 : 0 : goto error;
505 : : }
506 [ + - ]: 1916 : if (EVP_PKEY_generate(ctx, &key) != 1) {
507 : 0 : goto error;
508 : : }
509 : 1916 : error:
510 : 1916 : EVP_PKEY_CTX_free(ctx);
511 : 1916 : return (void *)key;
512 : : }
513 : :
514 : : void
515 : 2896 : spdk_nvme_dhchap_dhkey_free(struct spdk_nvme_dhchap_dhkey **key)
516 : : {
517 [ - + ]: 2896 : if (key == NULL) {
518 : 0 : return;
519 : : }
520 : :
521 [ # # ]: 2896 : EVP_PKEY_free(*(EVP_PKEY **)key);
522 [ # # ]: 2896 : *key = NULL;
523 : 0 : }
524 : :
525 : : int
526 : 1916 : spdk_nvme_dhchap_dhkey_get_pubkey(struct spdk_nvme_dhchap_dhkey *dhkey, void *pub, size_t *len)
527 : : {
528 : 1916 : EVP_PKEY *key = (EVP_PKEY *)dhkey;
529 : 1916 : BIGNUM *bn = NULL;
530 : : int rc;
531 : 1916 : const size_t num_bytes = (size_t)spdk_divide_round_up(EVP_PKEY_get_bits(key), 8);
532 : :
533 [ - + ]: 1916 : if (num_bytes == 0) {
534 : 0 : SPDK_ERRLOG("Failed to get key size\n");
535 : 0 : return -EIO;
536 : : }
537 : :
538 [ - + # # ]: 1916 : if (num_bytes > *len) {
539 [ # # ]: 0 : SPDK_ERRLOG("Insufficient key buffer size=%zu (needed=%zu)",
540 : : *len, num_bytes);
541 : 0 : return -EINVAL;
542 : : }
543 [ # # ]: 1916 : *len = num_bytes;
544 : :
545 [ - + ]: 1916 : if (EVP_PKEY_get_bn_param(key, "pub", &bn) != 1) {
546 : 0 : rc = -EIO;
547 : 0 : goto error;
548 : : }
549 : :
550 [ # # ]: 1916 : rc = BN_bn2binpad(bn, pub, *len);
551 [ - + ]: 1916 : if (rc <= 0) {
552 : 0 : rc = -EIO;
553 : 0 : goto error;
554 : : }
555 : 1916 : rc = 0;
556 : 1916 : error:
557 : 1916 : BN_free(bn);
558 : 1916 : return rc;
559 : 0 : }
560 : :
561 : : static EVP_PKEY *
562 : 1912 : nvme_auth_get_peerkey(const void *peerkey, size_t len, const char *dhgroup)
563 : : {
564 : 1912 : EVP_PKEY_CTX *ctx = NULL;
565 : 1912 : EVP_PKEY *result = NULL, *key = NULL;
566 : 1912 : OSSL_PARAM_BLD *bld = NULL;
567 : 1912 : OSSL_PARAM *params = NULL;
568 : 1912 : BIGNUM *bn = NULL;
569 : :
570 : 1912 : ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL);
571 [ - + ]: 1912 : if (ctx == NULL) {
572 : 0 : goto error;
573 : : }
574 [ - + ]: 1912 : if (EVP_PKEY_fromdata_init(ctx) != 1) {
575 : 0 : goto error;
576 : : }
577 : :
578 : 1912 : bn = BN_bin2bn(peerkey, len, NULL);
579 [ - + ]: 1912 : if (bn == NULL) {
580 : 0 : goto error;
581 : : }
582 : :
583 : 1912 : bld = OSSL_PARAM_BLD_new();
584 [ - + ]: 1912 : if (bld == NULL) {
585 : 0 : goto error;
586 : : }
587 [ - + ]: 1912 : if (OSSL_PARAM_BLD_push_BN(bld, "pub", bn) != 1) {
588 : 0 : goto error;
589 : : }
590 [ - + ]: 1912 : if (OSSL_PARAM_BLD_push_utf8_string(bld, "group", dhgroup, 0) != 1) {
591 : 0 : goto error;
592 : : }
593 : :
594 : 1912 : params = OSSL_PARAM_BLD_to_param(bld);
595 [ - + ]: 1912 : if (params == NULL) {
596 : 0 : goto error;
597 : : }
598 [ - + ]: 1912 : if (EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_PUBLIC_KEY, params) != 1) {
599 : 0 : SPDK_ERRLOG("Failed to create dhkey peer key\n");
600 : 0 : goto error;
601 : : }
602 : :
603 : 1912 : result = EVP_PKEY_dup(key);
604 : 1912 : error:
605 : 1912 : EVP_PKEY_free(key);
606 : 1912 : EVP_PKEY_CTX_free(ctx);
607 : 1912 : OSSL_PARAM_BLD_free(bld);
608 : 1912 : OSSL_PARAM_free(params);
609 : 1912 : BN_free(bn);
610 : :
611 : 1912 : return result;
612 : : }
613 : :
614 : : int
615 : 1912 : spdk_nvme_dhchap_dhkey_derive_secret(struct spdk_nvme_dhchap_dhkey *dhkey,
616 : : const void *peer, size_t peerlen, void *secret, size_t *seclen)
617 : : {
618 : 1912 : EVP_PKEY *key = (EVP_PKEY *)dhkey;
619 : 1912 : EVP_PKEY_CTX *ctx = NULL;
620 : 1912 : EVP_PKEY *peerkey = NULL;
621 : 1912 : char dhgroup[64] = {};
622 : 1912 : int rc = 0;
623 : :
624 [ - + # # ]: 1912 : if (EVP_PKEY_get_utf8_string_param(key, "group", dhgroup,
625 : 0 : sizeof(dhgroup), NULL) != 1) {
626 : 0 : return -EIO;
627 : : }
628 : 1912 : peerkey = nvme_auth_get_peerkey(peer, peerlen, dhgroup);
629 [ - + ]: 1912 : if (peerkey == NULL) {
630 : 0 : return -EINVAL;
631 : : }
632 : 1912 : ctx = EVP_PKEY_CTX_new(key, NULL);
633 [ - + ]: 1912 : if (ctx == NULL) {
634 : 0 : rc = -ENOMEM;
635 : 0 : goto out;
636 : : }
637 [ - + ]: 1912 : if (EVP_PKEY_derive_init(ctx) != 1) {
638 : 0 : rc = -EIO;
639 : 0 : goto out;
640 : : }
641 [ - + ]: 1912 : if (EVP_PKEY_CTX_set_dh_pad(ctx, 1) <= 0) {
642 : 0 : rc = -EIO;
643 : 0 : goto out;
644 : : }
645 [ - + ]: 1912 : if (EVP_PKEY_derive_set_peer(ctx, peerkey) != 1) {
646 : 0 : SPDK_ERRLOG("Failed to set dhsecret's peer key\n");
647 : 0 : rc = -EINVAL;
648 : 0 : goto out;
649 : : }
650 [ + - ]: 1912 : if (EVP_PKEY_derive(ctx, secret, seclen) != 1) {
651 : 0 : SPDK_ERRLOG("Failed to derive dhsecret\n");
652 : 0 : rc = -ENOBUFS;
653 : 0 : goto out;
654 : : }
655 : 1912 : out:
656 : 1912 : EVP_PKEY_free(peerkey);
657 : 1912 : EVP_PKEY_CTX_free(ctx);
658 : :
659 : 1912 : return rc;
660 : 0 : }
661 : :
662 : : static int
663 : 4892 : nvme_auth_submit_request(struct spdk_nvme_qpair *qpair,
664 : : enum spdk_nvmf_fabric_cmd_types type, uint32_t len)
665 : : {
666 [ # # # # ]: 4892 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
667 [ # # # # ]: 4892 : struct nvme_request *req = qpair->reserved_req;
668 [ # # # # ]: 4892 : struct nvme_completion_poll_status *status = qpair->poll_status;
669 : 4892 : struct spdk_nvmf_fabric_auth_recv_cmd rcmd = {};
670 : 4892 : struct spdk_nvmf_fabric_auth_send_cmd scmd = {};
671 : :
672 [ - + # # ]: 4892 : assert(len <= NVME_AUTH_DATA_SIZE);
673 [ - + # # ]: 4892 : memset(&status->cpl, 0, sizeof(status->cpl));
674 [ # # # # : 9784 : status->timeout_tsc = ctrlr->opts.admin_timeout_ms * spdk_get_ticks_hz() / 1000 +
# # # # #
# # # #
# ]
675 : 4892 : spdk_get_ticks();
676 [ # # # # ]: 4892 : status->done = false;
677 [ # # # # : 4892 : NVME_INIT_REQUEST(req, nvme_completion_poll_cb, status,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
678 : : NVME_PAYLOAD_CONTIG(status->dma_data, NULL), len, 0);
679 [ + + - ]: 4892 : switch (type) {
680 : 2836 : case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND:
681 : 2836 : scmd.opcode = SPDK_NVME_OPC_FABRIC;
682 : 2836 : scmd.fctype = type;
683 : 2836 : scmd.spsp0 = 1;
684 : 2836 : scmd.spsp1 = 1;
685 : 2836 : scmd.secp = SPDK_NVMF_AUTH_SECP_NVME;
686 : 2836 : scmd.tl = len;
687 [ # # # # : 2836 : memcpy(&req->cmd, &scmd, sizeof(scmd));
# # ]
688 : 2836 : break;
689 : 2056 : case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV:
690 : 2056 : rcmd.opcode = SPDK_NVME_OPC_FABRIC;
691 : 2056 : rcmd.fctype = type;
692 : 2056 : rcmd.spsp0 = 1;
693 : 2056 : rcmd.spsp1 = 1;
694 : 2056 : rcmd.secp = SPDK_NVMF_AUTH_SECP_NVME;
695 : 2056 : rcmd.al = len;
696 [ # # # # : 2056 : memcpy(&req->cmd, &rcmd, sizeof(rcmd));
# # ]
697 : 2056 : break;
698 : 0 : default:
699 [ # # ]: 0 : assert(0 && "invalid command");
700 : : return -EINVAL;
701 : : }
702 : :
703 : 4892 : return nvme_qpair_submit_request(qpair, req);
704 : : }
705 : :
706 : : static int
707 : 2056 : nvme_auth_recv_message(struct spdk_nvme_qpair *qpair)
708 : : {
709 [ - + # # : 2056 : memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE);
# # # # #
# ]
710 : 2056 : return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV,
711 : : NVME_AUTH_DATA_SIZE);
712 : : }
713 : :
714 : : static bool
715 : 24 : nvme_auth_send_failure2(struct spdk_nvme_qpair *qpair, enum spdk_nvmf_auth_failure_reason reason)
716 : : {
717 [ # # # # : 24 : struct spdk_nvmf_auth_failure *msg = qpair->poll_status->dma_data;
# # # # ]
718 [ # # ]: 24 : struct nvme_auth *auth = &qpair->auth;
719 : :
720 [ - + # # : 24 : memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE);
# # # # #
# ]
721 [ # # # # ]: 24 : msg->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE;
722 [ # # # # ]: 24 : msg->auth_id = SPDK_NVMF_AUTH_ID_FAILURE2;
723 [ # # # # : 24 : msg->t_id = auth->tid;
# # # # ]
724 [ # # # # ]: 24 : msg->rc = SPDK_NVMF_AUTH_FAILURE;
725 [ # # # # ]: 24 : msg->rce = reason;
726 : :
727 : 24 : return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND,
728 : 24 : sizeof(*msg)) == 0;
729 : : }
730 : :
731 : : static int
732 : 2055 : nvme_auth_check_message(struct spdk_nvme_qpair *qpair, enum spdk_nvmf_auth_id auth_id)
733 : : {
734 [ # # # # : 2055 : struct spdk_nvmf_auth_failure *msg = qpair->poll_status->dma_data;
# # # # ]
735 : 2055 : const char *reason = NULL;
736 : 2055 : const char *reasons[] = {
737 : : [SPDK_NVMF_AUTH_FAILED] = "authentication failed",
738 : : [SPDK_NVMF_AUTH_PROTOCOL_UNUSABLE] = "protocol not usable",
739 : : [SPDK_NVMF_AUTH_SCC_MISMATCH] = "secure channel concatenation mismatch",
740 : : [SPDK_NVMF_AUTH_HASH_UNUSABLE] = "hash not usable",
741 : : [SPDK_NVMF_AUTH_DHGROUP_UNUSABLE] = "dhgroup not usable",
742 : : [SPDK_NVMF_AUTH_INCORRECT_PAYLOAD] = "incorrect payload",
743 : : [SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE] = "incorrect protocol message",
744 : : };
745 : :
746 [ + + - # : 2055 : switch (msg->auth_type) {
# # # ]
747 : 2012 : case SPDK_NVMF_AUTH_TYPE_DHCHAP:
748 [ + - # # : 2012 : if (msg->auth_id == auth_id) {
# # ]
749 : 2012 : return 0;
750 : : }
751 [ # # # # : 0 : AUTH_ERRLOG(qpair, "received unexpected DH-HMAC-CHAP message id: %u (expected: %u)\n",
# # # # #
# # # # #
# # # # #
# # # #
# ]
752 : : msg->auth_id, auth_id);
753 : 0 : break;
754 : 43 : case SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE:
755 : : /* The only common message that we can expect to receive is AUTH_failure1 */
756 [ - + # # : 43 : if (msg->auth_id != SPDK_NVMF_AUTH_ID_FAILURE1) {
# # ]
757 [ # # # # : 0 : AUTH_ERRLOG(qpair, "received unexpected common message id: %u\n",
# # # # #
# # # # #
# # # # #
# # # #
# ]
758 : : msg->auth_id);
759 : 0 : break;
760 : : }
761 [ + - + - : 43 : if (msg->rc == SPDK_NVMF_AUTH_FAILURE && msg->rce < SPDK_COUNTOF(reasons)) {
# # # # #
# # # ]
762 [ # # # # : 43 : reason = reasons[msg->rce];
# # # # #
# ]
763 : 0 : }
764 [ # # # # : 43 : AUTH_ERRLOG(qpair, "received AUTH_failure1: rc=%d, rce=%d (%s)\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
765 : : msg->rc, msg->rce, reason);
766 : 43 : nvme_auth_set_failure(qpair, -EACCES, false);
767 : 43 : return -EACCES;
768 : 0 : default:
769 [ # # # # : 0 : AUTH_ERRLOG(qpair, "received unknown message type: %u\n", msg->auth_type);
# # # # #
# # # # #
# # # # #
# # # #
# ]
770 : 0 : break;
771 : : }
772 : :
773 : 0 : nvme_auth_set_failure(qpair, -EACCES,
774 : 0 : nvme_auth_send_failure2(qpair,
775 : : SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE));
776 : 0 : return -EACCES;
777 : 0 : }
778 : :
779 : : static int
780 : 1032 : nvme_auth_send_negotiate(struct spdk_nvme_qpair *qpair)
781 : : {
782 [ # # ]: 1032 : struct nvme_auth *auth = &qpair->auth;
783 [ # # # # : 1032 : struct spdk_nvmf_auth_negotiate *msg = qpair->poll_status->dma_data;
# # # # ]
784 [ # # ]: 1032 : struct spdk_nvmf_auth_descriptor *desc = msg->descriptors;
785 : : size_t i;
786 : :
787 [ - + # # : 1032 : memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE);
# # # # #
# ]
788 [ # # # # ]: 1032 : desc->auth_id = SPDK_NVMF_AUTH_TYPE_DHCHAP;
789 : : assert(SPDK_COUNTOF(g_digests) <= sizeof(desc->hash_id_list));
790 : : assert(SPDK_COUNTOF(g_dhgroups) <= sizeof(desc->dhg_id_list));
791 : :
792 [ + + ]: 4128 : for (i = 0; i < SPDK_COUNTOF(g_digests); ++i) {
793 [ + + # # : 3096 : if (!nvme_auth_digest_allowed(qpair, g_digests[i].id)) {
# # # # #
# ]
794 : 1872 : continue;
795 : : }
796 [ - + + - : 1224 : AUTH_DEBUGLOG(qpair, "digest: %u (%s)\n", g_digests[i].id,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
797 : : spdk_nvme_dhchap_get_digest_name(g_digests[i].id));
798 [ # # # # : 1224 : desc->hash_id_list[desc->halen++] = g_digests[i].id;
# # # # #
# # # # #
# # # # ]
799 : 0 : }
800 [ + + ]: 7224 : for (i = 0; i < SPDK_COUNTOF(g_dhgroups); ++i) {
801 [ + + # # : 6192 : if (!nvme_auth_dhgroup_allowed(qpair, g_dhgroups[i].id)) {
# # # # #
# ]
802 : 4688 : continue;
803 : : }
804 [ - + + - : 1504 : AUTH_DEBUGLOG(qpair, "dhgroup: %u (%s)\n", g_dhgroups[i].id,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
805 : : spdk_nvme_dhchap_get_dhgroup_name(g_dhgroups[i].id));
806 [ # # # # : 1504 : desc->dhg_id_list[desc->dhlen++] = g_dhgroups[i].id;
# # # # #
# # # # #
# # ]
807 : 0 : }
808 : :
809 [ # # # # ]: 1032 : msg->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE;
810 [ # # # # ]: 1032 : msg->auth_id = SPDK_NVMF_AUTH_ID_NEGOTIATE;
811 [ # # # # : 1032 : msg->t_id = auth->tid;
# # # # ]
812 [ # # # # ]: 1032 : msg->sc_c = SPDK_NVMF_AUTH_SCC_DISABLED;
813 [ # # # # ]: 1032 : msg->napd = 1;
814 : :
815 : 2064 : return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND,
816 [ # # # # ]: 1032 : sizeof(*msg) + msg->napd * sizeof(*desc));
817 : : }
818 : :
819 : : static int
820 : 1032 : nvme_auth_check_challenge(struct spdk_nvme_qpair *qpair)
821 : : {
822 [ # # # # : 1032 : struct spdk_nvmf_dhchap_challenge *challenge = qpair->poll_status->dma_data;
# # # # ]
823 [ # # ]: 1032 : struct nvme_auth *auth = &qpair->auth;
824 : : uint8_t hl;
825 : : int rc;
826 : :
827 : 1032 : rc = nvme_auth_check_message(qpair, SPDK_NVMF_AUTH_ID_DHCHAP_CHALLENGE);
828 [ + + ]: 1032 : if (rc != 0) {
829 : 8 : return rc;
830 : : }
831 : :
832 [ - + # # : 1024 : if (challenge->t_id != auth->tid) {
# # # # #
# ]
833 [ # # # # : 0 : AUTH_ERRLOG(qpair, "unexpected tid: received=%u, expected=%u\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
834 : : challenge->t_id, auth->tid);
835 : 0 : goto error;
836 : : }
837 : :
838 [ - + # # : 1024 : if (challenge->seqnum == 0) {
# # ]
839 [ # # # # : 0 : AUTH_ERRLOG(qpair, "received challenge with seqnum=0\n");
# # # # #
# # # # #
# # # # #
# ]
840 : 0 : goto error;
841 : : }
842 : :
843 [ # # # # ]: 1024 : hl = spdk_nvme_dhchap_get_digest_length(challenge->hash_id);
844 [ - + ]: 1024 : if (hl == 0) {
845 [ # # # # : 0 : AUTH_ERRLOG(qpair, "unsupported hash function: 0x%x\n", challenge->hash_id);
# # # # #
# # # # #
# # # # #
# # # #
# ]
846 : 0 : goto error;
847 : : }
848 : :
849 [ - + # # : 1024 : if (challenge->hl != hl) {
# # ]
850 [ # # # # : 0 : AUTH_ERRLOG(qpair, "unexpected hash length: received=%u, expected=%u\n",
# # # # #
# # # # #
# # # # #
# # # #
# ]
851 : : challenge->hl, hl);
852 : 0 : goto error;
853 : : }
854 : :
855 [ + + - # : 1024 : switch (challenge->dhg_id) {
# # # ]
856 : 48 : case SPDK_NVMF_DHCHAP_DHGROUP_NULL:
857 [ - + # # : 48 : if (challenge->dhvlen != 0) {
# # ]
858 [ # # # # : 0 : AUTH_ERRLOG(qpair, "unexpected dhvlen=%u for dhgroup 0\n",
# # # # #
# # # # #
# # # # #
# # # #
# ]
859 : : challenge->dhvlen);
860 : 0 : goto error;
861 : : }
862 : 48 : break;
863 : 976 : case SPDK_NVMF_DHCHAP_DHGROUP_2048:
864 : : case SPDK_NVMF_DHCHAP_DHGROUP_3072:
865 : : case SPDK_NVMF_DHCHAP_DHGROUP_4096:
866 : : case SPDK_NVMF_DHCHAP_DHGROUP_6144:
867 : : case SPDK_NVMF_DHCHAP_DHGROUP_8192:
868 [ + - # # : 976 : if (sizeof(*challenge) + hl + challenge->dhvlen > NVME_AUTH_DATA_SIZE ||
# # # # ]
869 [ - + # # ]: 976 : challenge->dhvlen == 0) {
870 [ # # # # : 0 : AUTH_ERRLOG(qpair, "invalid dhvlen=%u for dhgroup %u\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
871 : : challenge->dhvlen, challenge->dhg_id);
872 : 0 : goto error;
873 : : }
874 : 976 : break;
875 : 0 : default:
876 [ # # # # : 0 : AUTH_ERRLOG(qpair, "unsupported dhgroup: 0x%x\n", challenge->dhg_id);
# # # # #
# # # # #
# # # # #
# # # #
# ]
877 : 0 : goto error;
878 : : }
879 : :
880 [ - + # # : 1024 : if (!nvme_auth_digest_allowed(qpair, challenge->hash_id)) {
# # ]
881 [ # # # # : 0 : AUTH_ERRLOG(qpair, "received disallowed digest: %u (%s)\n", challenge->hash_id,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
882 : : spdk_nvme_dhchap_get_digest_name(challenge->hash_id));
883 : 0 : goto error;
884 : : }
885 : :
886 [ - + # # : 1024 : if (!nvme_auth_dhgroup_allowed(qpair, challenge->dhg_id)) {
# # ]
887 [ # # # # : 0 : AUTH_ERRLOG(qpair, "received disallowed dhgroup: %u (%s)\n", challenge->dhg_id,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
888 : : spdk_nvme_dhchap_get_dhgroup_name(challenge->dhg_id));
889 : 0 : goto error;
890 : : }
891 : :
892 : 1024 : return 0;
893 : 0 : error:
894 : 0 : nvme_auth_set_failure(qpair, -EACCES,
895 : 0 : nvme_auth_send_failure2(qpair, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD));
896 : 0 : return -EACCES;
897 : 0 : }
898 : :
899 : : static int
900 : 1024 : nvme_auth_send_reply(struct spdk_nvme_qpair *qpair)
901 : : {
902 [ # # # # ]: 1024 : struct nvme_completion_poll_status *status = qpair->poll_status;
903 [ # # # # ]: 1024 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
904 [ # # # # ]: 1024 : struct spdk_nvmf_dhchap_challenge *challenge = status->dma_data;
905 [ # # # # ]: 1024 : struct spdk_nvmf_dhchap_reply *reply = status->dma_data;
906 [ # # ]: 1024 : struct nvme_auth *auth = &qpair->auth;
907 : 0 : struct spdk_nvme_dhchap_dhkey *dhkey;
908 : 1024 : struct spdk_key *key = NULL, *ckey = NULL;
909 : 0 : uint8_t hl, response[NVME_AUTH_DATA_SIZE];
910 : 0 : uint8_t pubkey[NVME_AUTH_DH_KEY_MAX_SIZE];
911 : 0 : uint8_t dhsec[NVME_AUTH_DH_KEY_MAX_SIZE];
912 : 1024 : uint8_t ctrlr_challenge[NVME_AUTH_DIGEST_MAX_SIZE] = {};
913 : 1024 : size_t dhseclen = 0, publen = 0;
914 : 1024 : uint32_t seqnum = 0;
915 : : int rc;
916 : :
917 [ # # # # : 1024 : auth->hash = challenge->hash_id;
# # # # ]
918 [ # # # # ]: 1024 : hl = spdk_nvme_dhchap_get_digest_length(challenge->hash_id);
919 [ + + # # : 1024 : if (challenge->dhg_id != SPDK_NVMF_DHCHAP_DHGROUP_NULL) {
# # ]
920 : 976 : dhseclen = sizeof(dhsec);
921 : 976 : publen = sizeof(pubkey);
922 [ - + + - : 976 : AUTH_LOGDUMP("ctrlr pubkey:", &challenge->cval[hl], challenge->dhvlen);
# # # # #
# # # #
# ]
923 : 1952 : dhkey = spdk_nvme_dhchap_generate_dhkey(
924 [ # # # # ]: 976 : (enum spdk_nvmf_dhchap_dhgroup)challenge->dhg_id);
925 [ - + ]: 976 : if (dhkey == NULL) {
926 : 0 : rc = -EINVAL;
927 : 0 : goto out;
928 : : }
929 : 976 : rc = spdk_nvme_dhchap_dhkey_get_pubkey(dhkey, pubkey, &publen);
930 [ - + ]: 976 : if (rc != 0) {
931 : 0 : spdk_nvme_dhchap_dhkey_free(&dhkey);
932 : 0 : goto out;
933 : : }
934 [ - + + - : 976 : AUTH_LOGDUMP("host pubkey:", pubkey, publen);
# # ]
935 : 1952 : rc = spdk_nvme_dhchap_dhkey_derive_secret(dhkey,
936 [ # # # # : 976 : &challenge->cval[hl], challenge->dhvlen, dhsec, &dhseclen);
# # # # ]
937 : 976 : spdk_nvme_dhchap_dhkey_free(&dhkey);
938 [ - + ]: 976 : if (rc != 0) {
939 : 0 : goto out;
940 : : }
941 : :
942 [ - + + - : 976 : AUTH_LOGDUMP("dh secret:", dhsec, dhseclen);
# # ]
943 : 0 : }
944 : :
945 : 1024 : nvme_ctrlr_lock(ctrlr);
946 [ + - # # : 1024 : key = ctrlr->opts.dhchap_key ? spdk_key_dup(ctrlr->opts.dhchap_key) : NULL;
# # # # #
# # # #
# ]
947 [ + + # # : 1024 : ckey = ctrlr->opts.dhchap_ctrlr_key ? spdk_key_dup(ctrlr->opts.dhchap_ctrlr_key) : NULL;
# # # # #
# # # #
# ]
948 : 1024 : nvme_ctrlr_unlock(ctrlr);
949 : :
950 [ - + + - : 1024 : AUTH_DEBUGLOG(qpair, "key=%s, hash=%u, dhgroup=%u, seq=%u, tid=%u, subnqn=%s, hostnqn=%s, "
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
951 : : "len=%u\n", spdk_key_get_name(key), challenge->hash_id, challenge->dhg_id,
952 : : challenge->seqnum, auth->tid, ctrlr->trid.subnqn, ctrlr->opts.hostnqn, hl);
953 [ # # # # ]: 2048 : rc = spdk_nvme_dhchap_calculate(key, (enum spdk_nvmf_dhchap_hash)challenge->hash_id,
954 [ # # # # : 1024 : "HostHost", challenge->seqnum, auth->tid, 0,
# # # # ]
955 [ # # # # : 1024 : ctrlr->opts.hostnqn, ctrlr->trid.subnqn,
# # # # ]
956 [ # # ]: 1024 : dhseclen > 0 ? dhsec : NULL, dhseclen,
957 [ + + ]: 1024 : challenge->cval, response);
958 [ - + ]: 1024 : if (rc != 0) {
959 [ # # # # : 0 : AUTH_ERRLOG(qpair, "failed to calculate response: %s\n", spdk_strerror(-rc));
# # # # #
# # # # #
# # # # #
# # # ]
960 : 0 : goto out;
961 : : }
962 : :
963 [ + + ]: 1024 : if (ckey != NULL) {
964 : 804 : seqnum = nvme_auth_get_seqnum(qpair);
965 [ - + ]: 804 : if (seqnum == 0) {
966 : 0 : rc = -EIO;
967 : 0 : goto out;
968 : : }
969 : :
970 [ - + # # ]: 804 : assert(sizeof(ctrlr_challenge) >= hl);
971 : 804 : rc = RAND_bytes(ctrlr_challenge, hl);
972 [ - + ]: 804 : if (rc != 1) {
973 : 0 : rc = -EIO;
974 : 0 : goto out;
975 : : }
976 : :
977 : 804 : rc = spdk_nvme_dhchap_calculate(ckey,
978 [ # # # # ]: 804 : (enum spdk_nvmf_dhchap_hash)challenge->hash_id,
979 [ # # # # ]: 804 : "Controller", seqnum, auth->tid, 0,
980 [ # # # # : 804 : ctrlr->trid.subnqn, ctrlr->opts.hostnqn,
# # # # ]
981 [ # # ]: 804 : dhseclen > 0 ? dhsec : NULL, dhseclen,
982 [ + + ]: 804 : ctrlr_challenge, auth->challenge);
983 [ - + ]: 804 : if (rc != 0) {
984 [ # # # # : 0 : AUTH_ERRLOG(qpair, "failed to calculate controller's response: %s\n",
# # # # #
# # # # #
# # # # #
# # # ]
985 : : spdk_strerror(-rc));
986 : 0 : goto out;
987 : : }
988 : 0 : }
989 : :
990 : : /* Now that the response has been calculated, send the reply */
991 [ - + # # : 1024 : memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE);
# # # # #
# ]
992 [ - + # # : 1024 : assert(sizeof(*reply) + 2 * hl + publen <= NVME_AUTH_DATA_SIZE);
# # ]
993 [ - + - + : 1024 : memcpy(reply->rval, response, hl);
# # ]
994 [ - + - + : 1024 : memcpy(&reply->rval[1 * hl], ctrlr_challenge, hl);
# # # # #
# ]
995 [ - + - + : 1024 : memcpy(&reply->rval[2 * hl], pubkey, publen);
# # # # #
# ]
996 : :
997 [ # # # # ]: 1024 : reply->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP;
998 [ # # # # ]: 1024 : reply->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_REPLY;
999 [ # # # # : 1024 : reply->t_id = auth->tid;
# # # # ]
1000 [ # # # # ]: 1024 : reply->hl = hl;
1001 [ # # # # ]: 1024 : reply->cvalid = ckey != NULL;
1002 [ # # # # ]: 1024 : reply->dhvlen = publen;
1003 [ # # # # ]: 1024 : reply->seqnum = seqnum;
1004 : :
1005 : : /* The 2 * reply->hl below is because the spec says that both rval[hl] and cval[hl] must
1006 : : * always be part of the reply message, even cvalid is zero.
1007 : : */
1008 : 1024 : rc = nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND,
1009 [ # # # # : 1024 : sizeof(*reply) + 2 * reply->hl + publen);
# # ]
1010 : 1024 : out:
1011 : 1024 : spdk_keyring_put_key(key);
1012 : 1024 : spdk_keyring_put_key(ckey);
1013 : :
1014 : 1024 : return rc;
1015 : : }
1016 : :
1017 : : static int
1018 : 1023 : nvme_auth_check_success1(struct spdk_nvme_qpair *qpair)
1019 : : {
1020 [ # # # # : 1023 : struct spdk_nvmf_dhchap_success1 *msg = qpair->poll_status->dma_data;
# # # # ]
1021 [ # # # # ]: 1023 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
1022 [ # # ]: 1023 : struct nvme_auth *auth = &qpair->auth;
1023 : : uint8_t hl;
1024 : : int rc, status;
1025 : :
1026 : 1023 : rc = nvme_auth_check_message(qpair, SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS1);
1027 [ + + ]: 1023 : if (rc != 0) {
1028 : 35 : return rc;
1029 : : }
1030 : :
1031 [ - + # # : 988 : if (msg->t_id != auth->tid) {
# # # # #
# ]
1032 [ # # # # : 0 : AUTH_ERRLOG(qpair, "unexpected tid: received=%u, expected=%u\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
1033 : : msg->t_id, auth->tid);
1034 : 0 : status = SPDK_NVMF_AUTH_INCORRECT_PAYLOAD;
1035 : 0 : goto error;
1036 : : }
1037 : :
1038 [ + + # # : 988 : if (ctrlr->opts.dhchap_ctrlr_key != NULL) {
# # # # ]
1039 [ - + # # : 780 : if (!msg->rvalid) {
# # ]
1040 [ # # # # : 0 : AUTH_ERRLOG(qpair, "received rvalid=0, expected response\n");
# # # # #
# # # # #
# # # # #
# ]
1041 : 0 : status = SPDK_NVMF_AUTH_INCORRECT_PAYLOAD;
1042 : 0 : goto error;
1043 : : }
1044 : :
1045 [ # # # # ]: 780 : hl = spdk_nvme_dhchap_get_digest_length(auth->hash);
1046 [ - + # # : 780 : if (msg->hl != hl) {
# # ]
1047 [ # # # # : 0 : AUTH_ERRLOG(qpair, "received invalid hl=%u, expected=%u\n", msg->hl, hl);
# # # # #
# # # # #
# # # # #
# # # #
# ]
1048 : 0 : status = SPDK_NVMF_AUTH_INCORRECT_PAYLOAD;
1049 : 0 : goto error;
1050 : : }
1051 : :
1052 [ - + - + : 780 : if (memcmp(msg->rval, auth->challenge, hl) != 0) {
+ + # # #
# ]
1053 [ # # # # : 24 : AUTH_ERRLOG(qpair, "controller challenge mismatch\n");
# # # # #
# # # # #
# # # # #
# ]
1054 [ - + + - : 24 : AUTH_LOGDUMP("received:", msg->rval, hl);
# # # # ]
1055 [ - + + - : 24 : AUTH_LOGDUMP("expected:", auth->challenge, hl);
# # # # ]
1056 : 24 : status = SPDK_NVMF_AUTH_FAILED;
1057 : 24 : goto error;
1058 : : }
1059 : 0 : }
1060 : :
1061 : 964 : return 0;
1062 : 24 : error:
1063 : 24 : nvme_auth_set_failure(qpair, -EACCES, nvme_auth_send_failure2(qpair, status));
1064 : :
1065 : 24 : return -EACCES;
1066 : 0 : }
1067 : :
1068 : : static int
1069 : 756 : nvme_auth_send_success2(struct spdk_nvme_qpair *qpair)
1070 : : {
1071 [ # # # # : 756 : struct spdk_nvmf_dhchap_success2 *msg = qpair->poll_status->dma_data;
# # # # ]
1072 [ # # ]: 756 : struct nvme_auth *auth = &qpair->auth;
1073 : :
1074 [ - + # # : 756 : memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE);
# # # # #
# ]
1075 [ # # # # ]: 756 : msg->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP;
1076 [ # # # # ]: 756 : msg->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS2;
1077 [ # # # # : 756 : msg->t_id = auth->tid;
# # # # ]
1078 : :
1079 : 756 : return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND,
1080 : : sizeof(*msg));
1081 : : }
1082 : :
1083 : : int
1084 : 1026271 : nvme_fabric_qpair_authenticate_poll(struct spdk_nvme_qpair *qpair)
1085 : : {
1086 [ # # # # ]: 1026271 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
1087 [ # # ]: 1026271 : struct nvme_auth *auth = &qpair->auth;
1088 [ # # # # ]: 1026271 : struct nvme_completion_poll_status *status = qpair->poll_status;
1089 : : enum nvme_qpair_auth_state prev_state;
1090 : : int rc;
1091 : :
1092 : 0 : do {
1093 [ # # # # ]: 1032195 : prev_state = auth->state;
1094 : :
1095 [ + + + + : 1032195 : switch (auth->state) {
+ + + - #
# # # ]
1096 : 1032 : case NVME_QPAIR_AUTH_STATE_NEGOTIATE:
1097 : 1032 : rc = nvme_auth_send_negotiate(qpair);
1098 [ - + ]: 1032 : if (rc != 0) {
1099 : 0 : nvme_auth_set_failure(qpair, rc, false);
1100 [ # # # # : 0 : AUTH_ERRLOG(qpair, "failed to send AUTH_negotiate: %s\n",
# # # # #
# # # # #
# # # # #
# # # ]
1101 : : spdk_strerror(-rc));
1102 : 0 : break;
1103 : : }
1104 : 1032 : nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_NEGOTIATE);
1105 : 1032 : break;
1106 : 2971 : case NVME_QPAIR_AUTH_STATE_AWAIT_NEGOTIATE:
1107 : 2971 : rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL);
1108 [ + + ]: 2971 : if (rc != 0) {
1109 [ - + ]: 1939 : if (rc != -EAGAIN) {
1110 : 0 : nvme_auth_print_cpl(qpair, "AUTH_negotiate");
1111 : 0 : nvme_auth_set_failure(qpair, rc, false);
1112 : 0 : }
1113 : 1939 : break;
1114 : : }
1115 : : /* Negotiate has been sent, try to receive the challenge */
1116 : 1032 : rc = nvme_auth_recv_message(qpair);
1117 [ - + ]: 1032 : if (rc != 0) {
1118 : 0 : nvme_auth_set_failure(qpair, rc, false);
1119 [ # # # # : 0 : AUTH_ERRLOG(qpair, "failed to recv DH-HMAC-CHAP_challenge: %s\n",
# # # # #
# # # # #
# # # # #
# # # ]
1120 : : spdk_strerror(-rc));
1121 : 0 : break;
1122 : : }
1123 : 1032 : nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_CHALLENGE);
1124 : 1032 : break;
1125 : 29295 : case NVME_QPAIR_AUTH_STATE_AWAIT_CHALLENGE:
1126 : 29295 : rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL);
1127 [ + + ]: 29295 : if (rc != 0) {
1128 [ - + ]: 28263 : if (rc != -EAGAIN) {
1129 : 0 : nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_challenge");
1130 : 0 : nvme_auth_set_failure(qpair, rc, false);
1131 : 0 : }
1132 : 28263 : break;
1133 : : }
1134 : 1032 : rc = nvme_auth_check_challenge(qpair);
1135 [ + + ]: 1032 : if (rc != 0) {
1136 : 8 : break;
1137 : : }
1138 : 1024 : rc = nvme_auth_send_reply(qpair);
1139 [ - + ]: 1024 : if (rc != 0) {
1140 : 0 : nvme_auth_set_failure(qpair, rc, false);
1141 [ # # # # : 0 : AUTH_ERRLOG(qpair, "failed to send DH-HMAC-CHAP_reply: %s\n",
# # # # #
# # # # #
# # # # #
# # # ]
1142 : : spdk_strerror(-rc));
1143 : 0 : break;
1144 : : }
1145 : 1024 : nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_REPLY);
1146 : 1024 : break;
1147 : 992769 : case NVME_QPAIR_AUTH_STATE_AWAIT_REPLY:
1148 : 992769 : rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL);
1149 [ + + ]: 992769 : if (rc != 0) {
1150 [ - + ]: 991745 : if (rc != -EAGAIN) {
1151 : 0 : nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_reply");
1152 : 0 : nvme_auth_set_failure(qpair, rc, false);
1153 : 0 : }
1154 : 991745 : break;
1155 : : }
1156 : : /* Reply has been sent, try to receive response */
1157 : 1024 : rc = nvme_auth_recv_message(qpair);
1158 [ - + ]: 1024 : if (rc != 0) {
1159 : 0 : nvme_auth_set_failure(qpair, rc, false);
1160 [ # # # # : 0 : AUTH_ERRLOG(qpair, "failed to recv DH-HMAC-CHAP_success1: %s\n",
# # # # #
# # # # #
# # # # #
# # # ]
1161 : : spdk_strerror(-rc));
1162 : 0 : break;
1163 : : }
1164 : 1024 : nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS1);
1165 : 1024 : break;
1166 : 2936 : case NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS1:
1167 : 2936 : rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL);
1168 [ + + ]: 2936 : if (rc != 0) {
1169 [ + + ]: 1913 : if (rc != -EAGAIN) {
1170 : 1 : nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_success1");
1171 : 1 : nvme_auth_set_failure(qpair, rc, false);
1172 : 0 : }
1173 : 1913 : break;
1174 : : }
1175 : 1023 : rc = nvme_auth_check_success1(qpair);
1176 [ + + ]: 1023 : if (rc != 0) {
1177 : 59 : break;
1178 : : }
1179 [ - + + - : 964 : AUTH_DEBUGLOG(qpair, "authentication completed successfully\n");
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1180 [ + + # # : 964 : if (ctrlr->opts.dhchap_ctrlr_key != NULL) {
# # # # ]
1181 : 756 : rc = nvme_auth_send_success2(qpair);
1182 [ - + ]: 756 : if (rc != 0) {
1183 [ # # # # : 0 : AUTH_ERRLOG(qpair, "failed to send DH-HMAC-CHAP_success2: "
# # # # #
# # # # #
# # # # #
# ]
1184 : : "%s\n", spdk_strerror(rc));
1185 : 0 : nvme_auth_set_failure(qpair, rc, false);
1186 : 0 : break;
1187 : : }
1188 : 756 : nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS2);
1189 : 756 : break;
1190 : : }
1191 : 208 : nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_DONE);
1192 : 208 : break;
1193 : 1937 : case NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS2:
1194 : : case NVME_QPAIR_AUTH_STATE_AWAIT_FAILURE2:
1195 : 1937 : rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL);
1196 [ + + ]: 1937 : if (rc == -EAGAIN) {
1197 : 1157 : break;
1198 : : }
1199 : 780 : nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_DONE);
1200 : 780 : break;
1201 : 1255 : case NVME_QPAIR_AUTH_STATE_DONE:
1202 [ + + - + : 1255 : if (qpair->poll_status != NULL && !status->timed_out) {
+ - # # #
# # # #
# ]
1203 [ # # # # ]: 1032 : qpair->poll_status = NULL;
1204 [ # # # # ]: 1032 : spdk_free(status->dma_data);
1205 : 1032 : free(status);
1206 : 0 : }
1207 [ + + # # : 1255 : if (auth->cb_fn != NULL) {
# # ]
1208 [ # # # # : 18 : auth->cb_fn(auth->cb_ctx, auth->status);
# # # # #
# # # # #
# # ]
1209 [ # # # # ]: 18 : auth->cb_fn = NULL;
1210 : 0 : }
1211 [ # # # # ]: 1255 : return auth->status;
1212 : 0 : default:
1213 [ # # ]: 0 : assert(0 && "invalid state");
1214 : : return -EINVAL;
1215 : : }
1216 [ + + # # : 1030940 : } while (auth->state != prev_state);
# # ]
1217 : :
1218 : 1025016 : return -EAGAIN;
1219 : 0 : }
1220 : :
1221 : : int
1222 : 1036 : nvme_fabric_qpair_authenticate_async(struct spdk_nvme_qpair *qpair)
1223 : : {
1224 [ # # # # ]: 1036 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
1225 : : struct nvme_completion_poll_status *status;
1226 [ # # ]: 1036 : struct nvme_auth *auth = &qpair->auth;
1227 : : int rc;
1228 : :
1229 [ + + # # : 1036 : if (ctrlr->opts.dhchap_key == NULL) {
# # # # ]
1230 [ # # # # : 4 : AUTH_ERRLOG(qpair, "missing DH-HMAC-CHAP key\n");
# # # # #
# # # # #
# # # # #
# ]
1231 : 4 : return -ENOKEY;
1232 : : }
1233 : :
1234 [ - + # # : 1032 : if (qpair->auth.flags & NVME_QPAIR_AUTH_FLAG_ASCR) {
# # # # #
# # # ]
1235 [ # # # # : 0 : AUTH_ERRLOG(qpair, "secure channel concatenation is not supported\n");
# # # # #
# # # # #
# # # # #
# ]
1236 : 0 : return -EINVAL;
1237 : : }
1238 : :
1239 : 1032 : status = calloc(1, sizeof(*qpair->poll_status));
1240 [ - + ]: 1032 : if (!status) {
1241 [ # # # # : 0 : AUTH_ERRLOG(qpair, "failed to allocate poll status\n");
# # # # #
# # # # #
# # # # #
# ]
1242 : 0 : return -ENOMEM;
1243 : : }
1244 : :
1245 [ # # # # ]: 1032 : status->dma_data = spdk_zmalloc(NVME_AUTH_DATA_SIZE, 0, NULL, SPDK_ENV_LCORE_ID_ANY,
1246 : : SPDK_MALLOC_DMA);
1247 [ - + # # : 1032 : if (!status->dma_data) {
# # ]
1248 [ # # # # : 0 : AUTH_ERRLOG(qpair, "failed to allocate poll status\n");
# # # # #
# # # # #
# # # # #
# ]
1249 : 0 : free(status);
1250 : 0 : return -ENOMEM;
1251 : : }
1252 : :
1253 [ - + # # : 1032 : assert(qpair->poll_status == NULL);
# # # # ]
1254 [ # # # # ]: 1032 : qpair->poll_status = status;
1255 : :
1256 : 1032 : nvme_ctrlr_lock(ctrlr);
1257 [ # # # # : 1032 : auth->tid = ctrlr->auth_tid++;
# # ]
1258 : 1032 : nvme_ctrlr_unlock(ctrlr);
1259 : :
1260 : 1032 : nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_NEGOTIATE);
1261 : :
1262 : : /* Do the initial poll to kick-start the state machine */
1263 : 1032 : rc = nvme_fabric_qpair_authenticate_poll(qpair);
1264 [ + + ]: 1032 : return rc != -EAGAIN ? rc : 0;
1265 : 0 : }
1266 : :
1267 : : int
1268 : 24 : spdk_nvme_qpair_authenticate(struct spdk_nvme_qpair *qpair,
1269 : : spdk_nvme_authenticate_cb cb_fn, void *cb_ctx)
1270 : : {
1271 [ # # # # ]: 24 : struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
1272 : : int rc;
1273 : :
1274 [ - + # # : 24 : if (qpair->auth.cb_fn != NULL) {
# # # # ]
1275 : 0 : SPDK_ERRLOG("authentication already in-progress\n");
1276 : 0 : return -EALREADY;
1277 : : }
1278 : :
1279 [ - + # # : 24 : if (ctrlr->opts.dhchap_key == NULL) {
# # # # ]
1280 : 0 : SPDK_ERRLOG("missing DH-HMAC-CHAP key\n");
1281 : 0 : return -ENOKEY;
1282 : : }
1283 : :
1284 : 24 : rc = nvme_transport_qpair_authenticate(qpair);
1285 [ + + ]: 24 : if (rc == 0) {
1286 [ # # # # : 18 : qpair->auth.cb_fn = cb_fn;
# # ]
1287 [ # # # # : 18 : qpair->auth.cb_ctx = cb_ctx;
# # ]
1288 : 0 : }
1289 : :
1290 : 24 : return rc;
1291 : 0 : }
1292 : : #endif /* SPDK_CONFIG_EVP_MAC */
1293 : :
1294 : 2565 : SPDK_LOG_REGISTER_COMPONENT(nvme_auth)
|