Bug Summary

File:.build-ci/../libnvme/src/nvme/crypto.c
Warning:line 952, column 11
Potential leak of memory pointed to by 'identity'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name crypto.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/bin/../lib/clang/22 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I libnvme/src/libnvme3.so.1.0.0.p -I libnvme/src -I ../libnvme/src -I ccan -I ../ccan -I . -I .. -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-10-24-125112-639-1 -x c ../libnvme/src/nvme/crypto.c
1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * This file is part of libnvme.
4 * Copyright (c) 2020 Western Digital Corporation or its affiliates.
5 *
6 * Authors: Keith Busch <keith.busch@wdc.com>
7 * Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
8 */
9
10#include <arpa/inet.h>
11#include <errno(*__errno_location ()).h>
12#include <fcntl.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17
18#if NVME_HAVE_SYS_RANDOM1
19#include <sys/random.h>
20#endif
21#include <sys/param.h>
22#include <sys/stat.h>
23
24#ifdef CONFIG_OPENSSL
25#include <openssl/evp.h>
26#include <openssl/hmac.h>
27#include <openssl/kdf.h>
28#include <openssl/core_names.h>
29#include <openssl/params.h>
30#endif
31
32#ifdef CONFIG_KEYUTILS
33#include <keyutils.h>
34
35#define NVME_TLS_DEFAULT_KEYRING".nvme" ".nvme"
36#endif
37
38#include <ccan/endian/endian.h>
39
40#include <shared/base64-util.h>
41#include <shared/crc32-util.h>
42#include <shared/hex-util.h>
43#include <shared/compiler-attributes-util.h>
44
45#include <libnvme.h>
46
47#include "cleanup.h"
48#include "cleanup-linux.h"
49#include "private.h"
50
51/*
52 * A buffer for key material: any PSK, derived key or hash handled here
53 * fits. The cleanup clears it on every return path.
54 */
55#define KEY_BUF_LEN128 128
56
57static void clear_key_buf(unsigned char (*buf)[KEY_BUF_LEN128])
58{
59 explicit_bzero(*buf, sizeof(*buf));
60}
61#define __cleanup_key_buf__attribute__((cleanup(clear_key_buf))) __cleanup(clear_key_buf)__attribute__((cleanup(clear_key_buf)))
62
63#ifndef CONFIG_OPENSSL
64static unsigned char default_hmac(size_t key_len)
65{
66 return LIBNVMF_HMAC_ALG_NONE;
67}
68
69__shr_public__attribute__((visibility("default"))) int libnvmf_gen_kxchap_key(struct libnvme_global_ctx *ctx,
70 char *hostnqn, enum libnvmf_hmac_alg hmac,
71 unsigned int key_len, unsigned char *secret,
72 unsigned char *key)
73{
74 if (hmac != LIBNVMF_HMAC_ALG_NONE) {
75 libnvme_msg(ctx, LIBNVME_LOG_ERR, "HMAC transformation not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "HMAC transformation not supported; "
"recompile with OpenSSL support.\n")
76 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "HMAC transformation not supported; "
"recompile with OpenSSL support.\n")
;
77 return -EINVAL22;
78 }
79
80 memcpy(key, secret, key_len);
81 return 0;
82}
83
84__shr_public__attribute__((visibility("default"))) int libnvmf_create_raw_secret(struct libnvme_global_ctx *ctx,
85 const char *secret, size_t key_len, unsigned char **raw_secret)
86{
87 libnvme_msg(ctx, LIBNVME_LOG_ERR, "NVMe TLS is not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
88 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
;
89 return -ENOTSUP95;
90}
91
92static int derive_retained_key(struct libnvme_global_ctx *ctx,
93 int hmac, const char *hostnqn, unsigned char *generated,
94 unsigned char *retained, size_t key_len)
95{
96 libnvme_msg(ctx, LIBNVME_LOG_ERR, "NVMe TLS is not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
97 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
;
98 return -ENOTSUP95;
99}
100
101static int derive_retained_key_compat(struct libnvme_global_ctx *ctx,
102 int hmac, const char *hostnqn, unsigned char *generated,
103 unsigned char *retained, size_t key_len)
104{
105 libnvme_msg(ctx, LIBNVME_LOG_ERR, "NVMe TLS is not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
106 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
;
107 return -ENOTSUP95;
108}
109
110static int derive_psk_digest(struct libnvme_global_ctx *ctx,
111 const char *hostnqn, const char *subsysnqn,
112 int version, int cipher,
113 unsigned char *retained, size_t key_len,
114 char *digest, size_t digest_len)
115{
116 libnvme_msg(ctx, LIBNVME_LOG_ERR, "TLS PSK identity version 1 is not "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "TLS PSK identity version 1 is not "
"supported; recompile with OpenSSL support.\n")
117 "supported; recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "TLS PSK identity version 1 is not "
"supported; recompile with OpenSSL support.\n")
;
118 return -ENOTSUP95;
119}
120
121static int derive_tls_key(struct libnvme_global_ctx *ctx,
122 int version, unsigned char cipher, const char *context,
123 unsigned char *retained, unsigned char *psk, size_t key_len)
124{
125 libnvme_msg(ctx, LIBNVME_LOG_ERR, "NVMe TLS is not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
126 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
;
127 return -ENOTSUP95;
128}
129
130static int derive_tls_key_compat(struct libnvme_global_ctx *ctx,
131 int version, unsigned char cipher, const char *context,
132 unsigned char *retained, unsigned char *psk, size_t key_len)
133{
134 libnvme_msg(ctx, LIBNVME_LOG_ERR, "NVMe TLS is not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
135 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
;
136 return -ENOTSUP95;
137}
138#else /* CONFIG_OPENSSL */
139static unsigned char default_hmac(size_t key_len)
140{
141 unsigned char hmac = LIBNVMF_HMAC_ALG_NONE;
142
143 switch (key_len) {
144 case 32:
145 hmac = LIBNVMF_HMAC_ALG_SHA2_256;
146 break;
147 case 48:
148 hmac = LIBNVMF_HMAC_ALG_SHA2_384;
149 break;
150 case 64:
151 hmac = LIBNVMF_HMAC_ALG_SHA2_512;
152 break;
153 default:
154 break;
155 }
156 return hmac;
157}
158
159static const EVP_MD *select_hmac(int hmac, size_t *hmac_len)
160{
161 const EVP_MD *md = NULL((void*)0);
162
163 switch (hmac) {
164 case LIBNVMF_HMAC_ALG_SHA2_256:
165 md = EVP_sha256();
166 *hmac_len = 32;
167 break;
168 case LIBNVMF_HMAC_ALG_SHA2_384:
169 md = EVP_sha384();
170 *hmac_len = 48;
171 break;
172 default:
173 *hmac_len = 0;
174 break;
175 }
176 return md;
177}
178
179static DEFINE_CLEANUP_FUNC(void cleanup_evp_pkey_ctx(EVP_PKEY_CTX * *__p) { if (*__p) EVP_PKEY_CTX_free
(*__p); }
180 cleanup_evp_pkey_ctx, EVP_PKEY_CTX *, EVP_PKEY_CTX_free)void cleanup_evp_pkey_ctx(EVP_PKEY_CTX * *__p) { if (*__p) EVP_PKEY_CTX_free
(*__p); }
181#define __cleanup_evp_pkey_ctx__attribute__((cleanup(cleanup_evp_pkey_ctx))) __cleanup(cleanup_evp_pkey_ctx)__attribute__((cleanup(cleanup_evp_pkey_ctx)))
182
183/* NVMe is using the TLS 1.3 HkdfLabel structure */
184#define HKDF_INFO_MAX_LEN514 514
185#define HKDF_INFO_LABEL_MAX256 256
186#define HKDF_INFO_CONTEXT_MAX256 256
187
188/*
189 * derive_retained_key()
190 *
191 * Derive a retained PSK according to the NVMe TCP Transport
192 * Specification 1.3, section 3.6.1.3:
193 *
194 * The retained PSK is derived from the configured PSK. The configured PSK
195 * shall be destroyed as soon as the retained PSK is generated and stored.
196 * Each NVMe/TCP entity shall support:
197 * 1) transforming the configured PSK into a retained PSK before it is stored
198 * by the NVMe/TCP entity for repeated use with another NVMe/TCP entity; and
199 * 2) using the configured PSK as a retained PSK.
200 *
201 * The method to derive a retained PSK from a configured PSK shall be using
202 * the HKDF-Extract and HKDF-Expand-Label operations (refer to RFC 5869 and
203 * RFC 8446):
204 * 1. PRK = HKDF-Extract(0, Configured PSK); and
205 * 2. Retained PSK = HKDF-Expand-Label(PRK, “HostNQN”, NQNh,
206 * Length(Configured PSK)),
207 * where NQNh is the NQN of the host.
208 *
209 * 'hmac' indicates the hash function to be used to transform the configured
210 * PSK in a retained PSK, encoded as follows:
211 *
212 * - 0 indicates no transform (i.e., the configured PSK is used as a
213 * retained PSK)
214 * - 1 indicates SHA-256
215 * - 2 indicates SHA-384
216 */
217static int derive_retained_key(struct libnvme_global_ctx *ctx,
218 int hmac, const char *hostnqn,
219 unsigned char *configured, unsigned char *retained,
220 size_t key_len)
221{
222 __cleanup_evp_pkey_ctx__attribute__((cleanup(cleanup_evp_pkey_ctx))) EVP_PKEY_CTX *ectx = NULL((void*)0);
223 __cleanup_free__attribute__((cleanup(shr_freep))) uint8_t *hkdf_info = NULL((void*)0);
224 char *hkdf_label;
225 const EVP_MD *md;
226 size_t hmac_len;
227 char *pos;
228 int ret;
229
230 /* +1 byte so that the snprintf terminating null can not overflow */
231 hkdf_info = malloc(HKDF_INFO_MAX_LEN514 + 1);
232 if (!hkdf_info)
233 return -ENOMEM12;
234
235 if (hmac == LIBNVMF_HMAC_ALG_NONE) {
236 memcpy(retained, configured, key_len);
237 return key_len;
238 }
239
240 md = select_hmac(hmac, &hmac_len);
241 if (!md || !hmac_len)
242 return -EINVAL22;
243
244 ectx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF1036, NULL((void*)0));
245 if (!ectx)
246 return -ENOMEM12;
247
248 if (EVP_PKEY_derive_init(ectx) <= 0)
249 return -ENOMEM12;
250
251 if (EVP_PKEY_CTX_set_hkdf_md(ectx, md) <= 0)
252 return -ENOKEY126;
253
254 if (EVP_PKEY_CTX_set1_hkdf_key(ectx, configured, key_len) <= 0)
255 return -ENOKEY126;
256
257 if (key_len > USHRT_MAX(32767 * 2 + 1))
258 return -EINVAL22;
259
260 pos = (char *)hkdf_info;
261 *(uint16_t *)pos = htons(key_len & 0xFFFF)__bswap_16 (key_len & 0xFFFF);
262 pos += sizeof(uint16_t);
263
264 hkdf_label = "tls13 HostNQN";
265 ret = snprintf(pos, HKDF_INFO_LABEL_MAX256 + 1, "%c%s",
266 (int)strlen(hkdf_label), hkdf_label);
267 if (ret <= 0 || ret > HKDF_INFO_LABEL_MAX256)
268 return -ENOKEY126;
269 pos += ret;
270
271 ret = snprintf(pos, HKDF_INFO_CONTEXT_MAX256 + 1, "%c%s",
272 (int)strlen(hostnqn), hostnqn);
273 if (ret <= 0 || ret > HKDF_INFO_CONTEXT_MAX256)
274 return -ENOKEY126;
275 pos += ret;
276
277 if (EVP_PKEY_CTX_add1_hkdf_info(ectx, hkdf_info,
278 (pos - (char *)hkdf_info)) <= 0)
279 return -ENOKEY126;
280
281 if (EVP_PKEY_derive(ectx, retained, &key_len) <= 0)
282 return -ENOKEY126;
283
284 return key_len;
285}
286
287static int derive_retained_key_compat(struct libnvme_global_ctx *ctx,
288 int hmac, const char *hostnqn, unsigned char *configured,
289 unsigned char *retained, size_t key_len)
290{
291 __cleanup_evp_pkey_ctx__attribute__((cleanup(cleanup_evp_pkey_ctx))) EVP_PKEY_CTX *ectx = NULL((void*)0);
292 __cleanup_free__attribute__((cleanup(shr_freep))) uint8_t *hkdf_info = NULL((void*)0);
293 const EVP_MD *md;
294 size_t hmac_len;
295 char *pos;
296 int ret;
297
298 if (hmac == LIBNVMF_HMAC_ALG_NONE) {
299 memcpy(retained, configured, key_len);
300 return key_len;
301 }
302
303 md = select_hmac(hmac, &hmac_len);
304 if (!md || !hmac_len)
305 return -EINVAL22;
306
307 ectx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF1036, NULL((void*)0));
308 if (!ectx)
309 return -ENOMEM12;
310
311 if (EVP_PKEY_derive_init(ectx) <= 0)
312 return -ENOMEM12;
313
314 if (EVP_PKEY_CTX_set_hkdf_md(ectx, md) <= 0)
315 return -ENOKEY126;
316
317 if (EVP_PKEY_CTX_set1_hkdf_key(ectx, configured, key_len) <= 0)
318 return -ENOKEY126;
319
320 /* +1 byte so that the snprintf terminating null can not overflow */
321 hkdf_info = malloc(HKDF_INFO_MAX_LEN514 + 1);
322 if (!hkdf_info)
323 return -ENOMEM12;
324
325 pos = (char *)hkdf_info;
326 *(uint16_t *)pos = cpu_to_le16(key_len);
327 pos += sizeof(uint16_t);
328
329 ret = snprintf(pos, HKDF_INFO_LABEL_MAX256 + 1,
330 "tls13 HostNQN%s", hostnqn);
331 if (ret <= 0 || ret > HKDF_INFO_LABEL_MAX256)
332 return -ENOKEY126;
333 pos += ret;
334
335 if (EVP_PKEY_CTX_add1_hkdf_info(ectx, hkdf_info,
336 (pos - (char *)hkdf_info)) <= 0)
337 return -ENOKEY126;
338
339 if (EVP_PKEY_derive(ectx, retained, &key_len) <= 0)
340 return -ENOKEY126;
341
342 return key_len;
343}
344
345/*
346 * derive_tls_key()
347 *
348 * Derive a TLS PSK from a retained PSK.
349 *
350 * The TLS PSK shall be derived as follows from an input PSK (i.e., either
351 * a retained PSK or a generated PSK) and a PSK identity using the HKDF-Extract
352 * and HKDF-Expand-Label operations (refer to RFC 5869 and RFC 8446) where the
353 * hash function is the one specified by the hash specifier of the PSK identity:
354 * 1. PRK = HKDF-Extract(0, Input PSK); and
355 * 2. TLS PSK = HKDF-Expand-Label(PRK, “nvme-tls-psk”, PskIdentity, L),
356 * where PskIdentity is the PSK identity and L is the output size in bytes of
357 * the hash function (i.e., 32 for SHA-256 and 48 for SHA-384).
358 *
359 * Note that this is _not_ the hash value as specified by the configured PSK,
360 * but rather the hash function of the cipher suite associated with the
361 * PSK:
362 * - 1 indicates SHA-256 (for the TLS_AES_128_GCM_SHA256 cipher suite)
363 * - 2 indicates SHA-384 (for the TLS_AES_256_GCM_SHA384 cipher suite)
364 *
365 * and the value '0' is invalid here.
366 */
367
368static int derive_tls_key(struct libnvme_global_ctx *ctx,
369 int version, unsigned char cipher, const char *context,
370 unsigned char *retained, unsigned char *psk, size_t key_len)
371{
372 __cleanup_evp_pkey_ctx__attribute__((cleanup(cleanup_evp_pkey_ctx))) EVP_PKEY_CTX *ectx = NULL((void*)0);
373 __cleanup_free__attribute__((cleanup(shr_freep))) uint8_t *hkdf_info = NULL((void*)0);
374 char *hkdf_label;
375 const EVP_MD *md;
376 size_t hmac_len;
377 char *pos;
378 int ret;
379
380 /* +1 byte so that the snprintf terminating null can not overflow */
381 hkdf_info = malloc(HKDF_INFO_MAX_LEN514 + 1);
382 if (!hkdf_info)
383 return -ENOMEM12;
384
385 md = select_hmac(cipher, &hmac_len);
386 if (!md || !hmac_len)
387 return -EINVAL22;
388
389 ectx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF1036, NULL((void*)0));
390 if (!ectx)
391 return -ENOMEM12;
392
393 if (EVP_PKEY_derive_init(ectx) <= 0)
394 return -ENOMEM12;
395
396 if (EVP_PKEY_CTX_set_hkdf_md(ectx, md) <= 0)
397 return -ENOKEY126;
398
399 if (EVP_PKEY_CTX_set1_hkdf_key(ectx, retained, key_len) <= 0)
400 return -ENOKEY126;
401
402 if (key_len > USHRT_MAX(32767 * 2 + 1))
403 return -EINVAL22;
404
405 pos = (char *)hkdf_info;
406 *(uint16_t *)pos = htons(key_len & 0xFFFF)__bswap_16 (key_len & 0xFFFF);
407 pos += sizeof(uint16_t);
408
409 hkdf_label = "tls13 nvme-tls-psk";
410 ret = snprintf(pos, HKDF_INFO_LABEL_MAX256 + 1, "%c%s",
411 (int)strlen(hkdf_label), hkdf_label);
412 if (ret <= 0 || ret > HKDF_INFO_LABEL_MAX256)
413 return -ENOKEY126;
414 pos += ret;
415
416 switch (version) {
417 case 0:
418 ret = snprintf(pos, HKDF_INFO_CONTEXT_MAX256 + 1, "%c%s",
419 (int)strlen(context), context);
420 if (ret <= 0 || ret > HKDF_INFO_CONTEXT_MAX256)
421 return -ENOKEY126;
422 pos += ret;
423 break;
424 case 1:
425 ret = snprintf(pos, HKDF_INFO_CONTEXT_MAX256 + 1, "%c%02d %s",
426 (int)strlen(context) + 3, cipher, context);
427 if (ret <= 0 || ret > HKDF_INFO_CONTEXT_MAX256)
428 return -ENOKEY126;
429 pos += ret;
430 break;
431 default:
432 return -ENOKEY126;
433 }
434
435 if (EVP_PKEY_CTX_add1_hkdf_info(ectx, hkdf_info,
436 (pos - (char *)hkdf_info)) <= 0)
437 return -ENOKEY126;
438
439 if (EVP_PKEY_derive(ectx, psk, &key_len) <= 0)
440 return -ENOKEY126;
441
442 return key_len;
443}
444
445static int derive_tls_key_compat(struct libnvme_global_ctx *ctx,
446 int version, unsigned char cipher, const char *context,
447 unsigned char *retained, unsigned char *psk, size_t key_len)
448{
449 __cleanup_evp_pkey_ctx__attribute__((cleanup(cleanup_evp_pkey_ctx))) EVP_PKEY_CTX *ectx = NULL((void*)0);
450 __cleanup_free__attribute__((cleanup(shr_freep))) uint8_t *hkdf_info = NULL((void*)0);
451 const EVP_MD *md;
452 size_t hmac_len;
453 char *pos;
454 int ret;
455
456 md = select_hmac(cipher, &hmac_len);
457 if (!md || !hmac_len)
458 return -EINVAL22;
459
460 ectx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF1036, NULL((void*)0));
461 if (!ectx)
462 return -ENOMEM12;
463
464 if (EVP_PKEY_derive_init(ectx) <= 0)
465 return -ENOMEM12;
466
467 if (EVP_PKEY_CTX_set_hkdf_md(ectx, md) <= 0)
468 return -ENOKEY126;
469
470 if (EVP_PKEY_CTX_set1_hkdf_key(ectx, retained, key_len) <= 0)
471 return -ENOKEY126;
472
473 /* +1 byte so that the snprintf terminating null can not overflow */
474 hkdf_info = malloc(HKDF_INFO_MAX_LEN514 + 1);
475 if (!hkdf_info)
476 return -ENOMEM12;
477
478 pos = (char *)hkdf_info;
479 *(uint16_t *)pos = cpu_to_le16(key_len);
480 pos += sizeof(uint16_t);
481
482 ret = snprintf(pos, HKDF_INFO_LABEL_MAX256 + 1, "tls13 nvme-tls-psk");
483 if (ret <= 0 || ret > HKDF_INFO_LABEL_MAX256)
484 return -ENOKEY126;
485 pos += ret;
486
487 switch (version) {
488 case 0:
489 ret = snprintf(pos, HKDF_INFO_CONTEXT_MAX256 + 1, "%s", context);
490 if (ret <= 0 || ret > HKDF_INFO_CONTEXT_MAX256)
491 return -ENOKEY126;
492 pos += ret;
493 break;
494 case 1:
495 ret = snprintf(pos, HKDF_INFO_CONTEXT_MAX256 + 1, "%02d %s",
496 cipher, context);
497 if (ret <= 0 || ret > HKDF_INFO_CONTEXT_MAX256)
498 return -ENOKEY126;
499 pos += ret;
500 break;
501 default:
502 return -ENOKEY126;
503 }
504
505 if (EVP_PKEY_CTX_add1_hkdf_info(ectx, hkdf_info,
506 (pos - (char *)hkdf_info)) <= 0)
507 return -ENOKEY126;
508
509 if (EVP_PKEY_derive(ectx, psk, &key_len) <= 0)
510 return -ENOKEY126;
511
512 return key_len;
513}
514
515static DEFINE_CLEANUP_FUNC(void cleanup_ossl_lib_ctx(OSSL_LIB_CTX * *__p) { if (*__p) OSSL_LIB_CTX_free
(*__p); }
516 cleanup_ossl_lib_ctx, OSSL_LIB_CTX *, OSSL_LIB_CTX_free)void cleanup_ossl_lib_ctx(OSSL_LIB_CTX * *__p) { if (*__p) OSSL_LIB_CTX_free
(*__p); }
517#define __cleanup_ossl_lib_ctx__attribute__((cleanup(cleanup_ossl_lib_ctx))) __cleanup(cleanup_ossl_lib_ctx)__attribute__((cleanup(cleanup_ossl_lib_ctx)))
518static DEFINE_CLEANUP_FUNC(cleanup_evp_mac_ctx, EVP_MAC_CTX *, EVP_MAC_CTX_free)void cleanup_evp_mac_ctx(EVP_MAC_CTX * *__p) { if (*__p) EVP_MAC_CTX_free
(*__p); }
519#define __cleanup_evp_mac_ctx__attribute__((cleanup(cleanup_evp_mac_ctx))) __cleanup(cleanup_evp_mac_ctx)__attribute__((cleanup(cleanup_evp_mac_ctx)))
520static DEFINE_CLEANUP_FUNC(cleanup_evp_mac, EVP_MAC *, EVP_MAC_free)void cleanup_evp_mac(EVP_MAC * *__p) { if (*__p) EVP_MAC_free
(*__p); }
521#define __cleanup_evp_mac__attribute__((cleanup(cleanup_evp_mac))) __cleanup(cleanup_evp_mac)__attribute__((cleanup(cleanup_evp_mac)))
522
523__shr_public__attribute__((visibility("default"))) int libnvmf_gen_kxchap_key(struct libnvme_global_ctx *ctx,
524 char *hostnqn, enum libnvmf_hmac_alg hmac,
525 unsigned int key_len, unsigned char *secret,
526 unsigned char *key)
527{
528 const char hmac_seed[] = "NVMe-over-Fabrics";
529 __cleanup_ossl_lib_ctx__attribute__((cleanup(cleanup_ossl_lib_ctx))) OSSL_LIB_CTX *lib_ctx = NULL((void*)0);
530 __cleanup_evp_mac_ctx__attribute__((cleanup(cleanup_evp_mac_ctx))) EVP_MAC_CTX *mac_ctx = NULL((void*)0);
531 __cleanup_evp_mac__attribute__((cleanup(cleanup_evp_mac))) EVP_MAC *mac = NULL((void*)0);
532 OSSL_PARAM params[2], *p = params;
533 char *progq = NULL((void*)0);
534 char *digest;
535 size_t len;
536
537 lib_ctx = OSSL_LIB_CTX_new();
538 if (!lib_ctx)
539 return -ENOMEM12;
540
541 mac = EVP_MAC_fetch(lib_ctx, OSSL_MAC_NAME_HMAC"HMAC", progq);
542 if (!mac)
543 return -ENOMEM12;
544
545 mac_ctx = EVP_MAC_CTX_new(mac);
546 if (!mac_ctx)
547 return -ENOMEM12;
548
549 switch (hmac) {
550 case LIBNVMF_HMAC_ALG_NONE:
551 memcpy(key, secret, key_len);
552 return 0;
553 case LIBNVMF_HMAC_ALG_SHA2_256:
554 digest = OSSL_DIGEST_NAME_SHA2_256"SHA2-256";
555 break;
556 case LIBNVMF_HMAC_ALG_SHA2_384:
557 digest = OSSL_DIGEST_NAME_SHA2_384"SHA2-384";
558 break;
559 case LIBNVMF_HMAC_ALG_SHA2_512:
560 digest = OSSL_DIGEST_NAME_SHA2_512"SHA2-512";
561 break;
562 default:
563 return -EINVAL22;
564 }
565 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST"digest",
566 digest,
567 0);
568 *p = OSSL_PARAM_construct_end();
569
570 if (!EVP_MAC_init(mac_ctx, secret, key_len, params))
571 return -ENOKEY126;
572
573 if (!EVP_MAC_update(mac_ctx, (unsigned char *)hostnqn,
574 strlen(hostnqn)))
575 return -ENOKEY126;
576
577 if (!EVP_MAC_update(mac_ctx, (unsigned char *)hmac_seed,
578 strlen(hmac_seed)))
579 return -ENOKEY126;
580
581 if (!EVP_MAC_final(mac_ctx, key, &len, key_len))
582 return -ENOKEY126;
583
584 if (len != key_len)
585 return -EMSGSIZE90;
586
587 return 0;
588}
589
590static int derive_psk_digest(struct libnvme_global_ctx *ctx,
591 const char *hostnqn, const char *subsysnqn,
592 int version, int cipher,
593 unsigned char *retained, size_t key_len,
594 char *digest, size_t digest_len)
595{
596 static const char hmac_seed[] = "NVMe-over-Fabrics";
597 __cleanup_ossl_lib_ctx__attribute__((cleanup(cleanup_ossl_lib_ctx))) OSSL_LIB_CTX *lib_ctx = NULL((void*)0);
598 __cleanup_evp_mac_ctx__attribute__((cleanup(cleanup_evp_mac_ctx))) EVP_MAC_CTX *mac_ctx = NULL((void*)0);
599 __cleanup_free__attribute__((cleanup(shr_freep))) unsigned char *psk_ctx = NULL((void*)0);
600 __cleanup_evp_mac__attribute__((cleanup(cleanup_evp_mac))) EVP_MAC *mac = NULL((void*)0);
601 OSSL_PARAM params[2], *p = params;
602 size_t hmac_len;
603 char *progq = NULL((void*)0);
604 char *dig = NULL((void*)0);
605 int len;
606
607 lib_ctx = OSSL_LIB_CTX_new();
608 if (!lib_ctx)
609 return -ENOMEM12;
610
611 mac = EVP_MAC_fetch(lib_ctx, OSSL_MAC_NAME_HMAC"HMAC", progq);
612 if (!mac)
613 return -ENOMEM12;
614
615 mac_ctx = EVP_MAC_CTX_new(mac);
616 if (!mac_ctx)
617 return -ENOMEM12;
618
619 switch (cipher) {
620 case LIBNVMF_HMAC_ALG_SHA2_256:
621 dig = OSSL_DIGEST_NAME_SHA2_256"SHA2-256";
622 break;
623 case LIBNVMF_HMAC_ALG_SHA2_384:
624 dig = OSSL_DIGEST_NAME_SHA2_384"SHA2-384";
625 break;
626 default:
627 return -EINVAL22;
628 }
629
630 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST"digest",
631 dig, 0);
632 *p = OSSL_PARAM_construct_end();
633
634 psk_ctx = malloc(key_len);
635 if (!psk_ctx)
636 return -ENOMEM12;
637
638 if (!EVP_MAC_init(mac_ctx, retained, key_len, params))
639 return -ENOKEY126;
640
641 if (!EVP_MAC_update(mac_ctx, (unsigned char *)hostnqn,
642 strlen(hostnqn)))
643 return -ENOKEY126;
644
645 if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1))
646 return -ENOKEY126;
647
648 if (!EVP_MAC_update(mac_ctx, (unsigned char *)subsysnqn,
649 strlen(subsysnqn)))
650 return -ENOKEY126;
651
652 if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1))
653 return -ENOKEY126;
654
655 if (!EVP_MAC_update(mac_ctx, (unsigned char *)hmac_seed,
656 strlen(hmac_seed)))
657 return -ENOKEY126;
658
659 if (!EVP_MAC_final(mac_ctx, psk_ctx, &hmac_len, key_len))
660 return -ENOKEY126;
661
662 if (hmac_len > key_len)
663 return -EMSGSIZE90;
664
665 if (hmac_len * 2 > digest_len)
666 return -EINVAL22;
667
668 memset(digest, 0, digest_len);
669 len = shr_base64_encode(psk_ctx, hmac_len, digest);
670 if (len < 0)
671 return len;
672
673 return strlen(digest);
674}
675
676static ssize_t getrandom_bytes(void *buf, size_t buflen)
677{
678 ssize_t result;
679#if NVME_HAVE_SYS_RANDOM1
680 result = getrandom(buf, buflen, GRND_NONBLOCK0x01);
681#else
682 __cleanup_fd__attribute__((cleanup(shr_cleanup_fd))) int fd = -1;
683
684 fd = open("/dev/urandom", O_RDONLY00);
685 if (fd < 0)
686 return -errno(*__errno_location ());
687 result = read(fd, buf, buflen);
688#endif
689 if (result < 0)
690 return -errno(*__errno_location ());
691 return result;
692}
693
694static ssize_t getswordfish(struct libnvme_global_ctx *ctx,
695 const char *seed, void *buf, size_t buflen)
696{
697 __cleanup_key_buf__attribute__((cleanup(clear_key_buf))) unsigned char hash[KEY_BUF_LEN128];
698 unsigned int counter = 0;
699 EVP_MD_CTX *md_ctx;
700 size_t copied = 0;
701
702 md_ctx = EVP_MD_CTX_new();
703 if (!md_ctx)
704 return -ENOMEM12;
705
706 while (copied < buflen) {
707 beint32_t be_counter;
708 unsigned int hash_len;
709 size_t to_copy;
710
711 if (EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL((void*)0)) != 1)
712 goto err;
713
714 be_counter = cpu_to_be32(counter);
715
716 EVP_DigestUpdate(md_ctx, seed, strlen(seed));
717 EVP_DigestUpdate(md_ctx, &be_counter, sizeof(be_counter));
718
719 if (EVP_DigestFinal_ex(md_ctx, hash, &hash_len) != 1)
720 goto err;
721
722 to_copy = buflen - copied;
723 if (to_copy > hash_len)
724 to_copy = hash_len;
725
726 memcpy((unsigned char *)buf + copied, hash, to_copy);
727 copied += to_copy;
728 counter++;
729 }
730
731 EVP_MD_CTX_free(md_ctx);
732 return buflen;
733
734err:
735 EVP_MD_CTX_free(md_ctx);
736 return -EIO5;
737}
738
739__shr_public__attribute__((visibility("default"))) int libnvmf_create_raw_secret(struct libnvme_global_ctx *ctx,
740 const char *secret, size_t key_len, unsigned char **raw_secret)
741{
742 __cleanup_key_buf__attribute__((cleanup(clear_key_buf))) unsigned char buf[KEY_BUF_LEN128];
743 int secret_len = 0, i, err;
744
745 if (key_len != 32 && key_len != 48 && key_len != 64) {
746 libnvme_msg(ctx, LIBNVME_LOG_ERR,__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid key length %zu"
, key_len)
747 "Invalid key length %zu", key_len)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid key length %zu"
, key_len)
;
748 return -EINVAL22;
749 }
750
751 if (!secret) {
752 err = getrandom_bytes(buf, key_len);
753 if (err < 0)
754 return err;
755
756 goto out;
757 }
758
759 if (strlen(secret) < 4) {
760 libnvme_msg(ctx, LIBNVME_LOG_ERR, "Input secret too short\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Input secret too short\n"
)
;
761 return -EINVAL22;
762 }
763
764 if (!strncmp(secret, "pin:", 4)) {
765 err = getswordfish(ctx, &secret[4], buf, key_len);
766 if (err < 0)
767 return err;
768
769 goto out;
770 }
771
772 for (i = 0; i < strlen(secret); i += 2) {
773 int hi = shr_hex_to_int(secret[i]);
774 int lo = shr_hex_to_int(secret[i + 1]);
775
776 if (hi < 0 || lo < 0) {
777 libnvme_msg(ctx, LIBNVME_LOG_ERR,__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid secret '%s'"
, secret)
778 "Invalid secret '%s'", secret)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid secret '%s'"
, secret)
;
779 return -EINVAL22;
780 }
781 if (i >= key_len * 2) {
782 libnvme_msg(ctx, LIBNVME_LOG_ERR,__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Skipping excess secret bytes\n"
)
783 "Skipping excess secret bytes\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Skipping excess secret bytes\n"
)
;
784 break;
785 }
786 buf[secret_len++] = (unsigned char)(hi << 4 | lo);
787 }
788 if (secret_len != key_len) {
789 libnvme_msg(ctx, LIBNVME_LOG_ERR,__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid key length (%d bytes)\n"
, secret_len)
790 "Invalid key length (%d bytes)\n", secret_len)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid key length (%d bytes)\n"
, secret_len)
;
791 return -EINVAL22;
792 }
793
794out:
795 *raw_secret = malloc(key_len);
796 if (!*raw_secret)
797 return -ENOMEM12;
798 memcpy(*raw_secret, buf, key_len);
799
800 return 0;
801}
802
803#endif /* CONFIG_OPENSSL */
804
805static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
806 int version, int cipher, char *digest,
807 char *identity)
808{
809 if (version == 0) {
810 sprintf(identity, "NVMe%01dR%02d %s %s",
811 version, cipher, hostnqn, subsysnqn);
812 return strlen(identity);
813 }
814 if (version > 1 || !digest)
815 return -EINVAL22;
816
817 sprintf(identity, "NVMe%01dR%02d %s %s %s",
818 version, cipher, hostnqn, subsysnqn, digest);
819 return strlen(identity);
820}
821
822static int derive_nvme_keys(struct libnvme_global_ctx *ctx,
823 const char *hostnqn, const char *subsysnqn,
824 char *identity, int version,
825 int hmac, unsigned char *configured,
826 unsigned char *psk, int key_len, bool_Bool compat)
827{
828 __cleanup_key_buf__attribute__((cleanup(clear_key_buf))) unsigned char retained[KEY_BUF_LEN128];
829 __cleanup_free__attribute__((cleanup(shr_freep))) char *digest = NULL((void*)0);
830 char *context = identity;
831 unsigned char cipher;
832 int ret = -1;
833
834 if (!hostnqn || !subsysnqn || !identity || !psk)
835 return -EINVAL22;
836 if (key_len <= 0 || key_len > KEY_BUF_LEN128)
837 return -EINVAL22;
838
839 if (compat)
840 ret = derive_retained_key_compat(ctx, hmac, hostnqn, configured,
841 retained, key_len);
842 else
843 ret = derive_retained_key(ctx, hmac, hostnqn, configured,
844 retained, key_len);
845 if (ret < 0)
846 return ret;
847
848 if (hmac == LIBNVMF_HMAC_ALG_NONE)
849 cipher = default_hmac(key_len);
850 else
851 cipher = hmac;
852
853 if (version == 1) {
854 size_t digest_len = 2 * key_len;
855
856 digest = malloc(digest_len);
857 if (!digest)
858 return -ENOMEM12;
859
860 ret = derive_psk_digest(ctx, hostnqn, subsysnqn, version,
861 cipher, retained, key_len, digest,
862 digest_len);
863 if (ret < 0)
864 return ret;
865 context = digest;
866 }
867 ret = gen_tls_identity(hostnqn, subsysnqn, version, cipher,
868 digest, identity);
869 if (ret < 0)
870 return ret;
871 if (compat)
872 return derive_tls_key_compat(ctx, version, cipher, context,
873 retained, psk, key_len);
874 return derive_tls_key(ctx, version, cipher, context, retained,
875 psk, key_len);
876}
877
878static ssize_t nvme_identity_len(int hmac, int version, const char *hostnqn,
879 const char *subsysnqn)
880{
881 ssize_t len;
882
883 if (!hostnqn || !subsysnqn)
884 return -EINVAL22;
885
886 len = strlen(hostnqn) + strlen(subsysnqn) + 12;
887 if (version == 1) {
888 len += 66;
889 if (hmac == LIBNVMF_HMAC_ALG_SHA2_384)
890 len += 32;
891 } else if (version > 1) {
892 return -EINVAL22;
893 }
894 return len;
895}
896
897__shr_public__attribute__((visibility("default"))) int libnvmf_generate_tls_key_identity(
898 struct libnvme_global_ctx *ctx, const char *hostnqn,
899 const char *subsysnqn, int version, enum libnvmf_hmac_alg hmac,
900 unsigned char *configured_key, int key_len, char **ident)
901{
902 __cleanup_key_buf__attribute__((cleanup(clear_key_buf))) unsigned char psk[KEY_BUF_LEN128];
903 __cleanup_free__attribute__((cleanup(shr_freep))) char *identity = NULL((void*)0);
904 ssize_t identity_len;
905 int ret;
906
907 identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn);
908 if (identity_len < 0)
909 return -EINVAL22;
910
911 identity = malloc(identity_len);
912 if (!identity)
913 return -ENOMEM12;
914
915 if (key_len <= 0 || key_len > KEY_BUF_LEN128)
916 return -EINVAL22;
917
918 memset(psk, 0, key_len);
919 ret = derive_nvme_keys(ctx, hostnqn, subsysnqn, identity, version, hmac,
920 configured_key, psk, key_len, false0);
921 if (ret != key_len) {
922 if (ret < 0)
923 return ret;
924 return -ENOKEY126;
925 }
926
927 *ident = identity;
928 identity = NULL((void*)0);
929
930 return 0;
931}
932
933__shr_public__attribute__((visibility("default"))) int libnvmf_generate_tls_key_identity_compat(
934 struct libnvme_global_ctx *ctx, const char *hostnqn,
935 const char *subsysnqn, int version, enum libnvmf_hmac_alg hmac,
936 unsigned char *configured_key, int key_len, char **ident)
937{
938 __cleanup_key_buf__attribute__((cleanup(clear_key_buf))) unsigned char psk[KEY_BUF_LEN128];
939 __cleanup_free__attribute__((cleanup(shr_freep))) char *identity = NULL((void*)0);
940 ssize_t identity_len;
941 int ret;
942
943 identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn);
944 if (identity_len < 0)
1
Assuming 'identity_len' is >= 0
2
Taking false branch
945 return -EINVAL22;
946
947 identity = malloc(identity_len);
3
Memory is allocated
948 if (!identity)
4
Assuming 'identity' is non-null
949 return -ENOMEM12;
950
951 if (key_len <= 0 || key_len > KEY_BUF_LEN128)
5
Assuming 'key_len' is <= 0
952 return -EINVAL22;
6
Potential leak of memory pointed to by 'identity'
953
954 memset(psk, 0, key_len);
955 ret = derive_nvme_keys(ctx, hostnqn, subsysnqn, identity, version, hmac,
956 configured_key, psk, key_len, true1);
957 if (ret != key_len) {
958 if (ret < 0)
959 return ret;
960 return -ENOKEY126;
961 }
962
963 *ident = identity;
964 identity = NULL((void*)0);
965
966 return 0;
967}
968
969#ifdef CONFIG_KEYUTILS
970__shr_public__attribute__((visibility("default"))) int libnvmf_lookup_keyring(
971 struct libnvme_global_ctx *ctx, const char *keyring, long *key)
972{
973 key_serial_t keyring_id;
974
975 if (!keyring)
976 keyring = NVME_TLS_DEFAULT_KEYRING".nvme";
977 keyring_id = find_key_by_type_and_desc("keyring", keyring, 0);
978 if (keyring_id < 0)
979 return -errno(*__errno_location ());
980
981 *key = keyring_id;
982 return 0;
983}
984
985__shr_public__attribute__((visibility("default"))) char *libnvmf_describe_key_serial(
986 struct libnvme_global_ctx *ctx, long key_id)
987{
988 __cleanup_free__attribute__((cleanup(shr_freep))) char *str = NULL((void*)0);
989 char *last;
990
991 if (keyctl_describe_alloc(key_id, &str) < 0)
992 return NULL((void*)0);
993
994 last = strrchr(str, ';')_Generic (0 ? (str) : (void *) 1, const void *: (const char *
) (strrchr (str, ';')), default: strrchr (str, ';'))
;
995 if (!last)
996 return NULL((void*)0);
997
998 last++;
999 if (strlen(last) == 0)
1000 return NULL((void*)0);
1001
1002 return strdup(last);
1003}
1004
1005__shr_public__attribute__((visibility("default"))) int libnvmf_lookup_key(
1006 struct libnvme_global_ctx *ctx, const char *type,
1007 const char *identity, long *keyp)
1008{
1009 key_serial_t key;
1010
1011 key = keyctl_search(KEY_SPEC_SESSION_KEYRING-3, type, identity, 0);
1012 if (key < 0)
1013 return -errno(*__errno_location ());
1014
1015 *keyp = key;
1016 return 0;
1017}
1018
1019__shr_public__attribute__((visibility("default"))) int libnvmf_set_keyring(
1020 struct libnvme_global_ctx *ctx, long key_id)
1021{
1022 long err;
1023
1024 if (key_id == 0) {
1025 if (libnvmf_lookup_keyring(ctx, NULL((void*)0), &key_id))
1026 return -ENOKEY126;
1027 }
1028
1029 err = keyctl_link(key_id, KEY_SPEC_SESSION_KEYRING-3);
1030 if (err < 0)
1031 return -errno(*__errno_location ());
1032 return 0;
1033}
1034
1035__shr_public__attribute__((visibility("default"))) int libnvmf_read_key(
1036 struct libnvme_global_ctx *ctx, long keyring_id, long key_id,
1037 int *len, unsigned char **key)
1038{
1039 void *buffer;
1040 int ret;
1041
1042 ret = libnvmf_set_keyring(ctx, keyring_id);
1043 if (ret < 0)
1044 return ret;
1045
1046 ret = keyctl_read_alloc(key_id, &buffer);
1047 if (ret < 0)
1048 return ret;
1049
1050 *len = ret;
1051 *key = buffer;
1052 return 0;
1053}
1054
1055__shr_public__attribute__((visibility("default"))) int libnvmf_update_key(
1056 struct libnvme_global_ctx *ctx, long keyring_id,
1057 const char *key_type, const char *identity,
1058 unsigned char *key_data, int key_len, long *keyp)
1059{
1060 long key;
1061
1062 key = keyctl_search(keyring_id, key_type, identity, 0);
1063 if (key > 0) {
1064 if (keyctl_revoke(key) < 0)
1065 return -errno(*__errno_location ());
1066 }
1067 key = add_key(key_type, identity,
1068 key_data, key_len, keyring_id);
1069 if (key < 0)
1070 return -errno(*__errno_location ());
1071
1072 *keyp = key;
1073 return 0;
1074}
1075
1076struct __scan_keys_data {
1077 struct libnvme_global_ctx *ctx;
1078 libnvmf_scan_tls_keys_cb_t cb;
1079 key_serial_t keyring;
1080 void *data;
1081};
1082
1083int __scan_keys_cb(key_serial_t parent, key_serial_t key, char *desc,
1084 int desc_len, void *data)
1085{
1086 struct __scan_keys_data *d = data;
1087 int ver, hmac, uid, gid, perm;
1088 char type, *ptr;
1089
1090 if (desc_len < 6)
1091 return 0;
1092 if (sscanf(desc, "psk;%d;%d;%08x;NVMe%01d%c%02d %*s",
1093 &uid, &gid, &perm, &ver, &type, &hmac) != 6)
1094 return 0;
1095 /* skip key type */
1096 ptr = strchr(desc, ';')_Generic (0 ? (desc) : (void *) 1, const void *: (const char *
) (strchr (desc, ';')), default: strchr (desc, ';'))
;
1097 if (!ptr)
1098 return 0;
1099 /* skip key uid */
1100 ptr = strchr(ptr + 1, ';')_Generic (0 ? (ptr + 1) : (void *) 1, const void *: (const char
*) (strchr (ptr + 1, ';')), default: strchr (ptr + 1, ';'))
;
1101 if (!ptr)
1102 return 0;
1103 /* skip key gid */
1104 ptr = strchr(ptr + 1, ';')_Generic (0 ? (ptr + 1) : (void *) 1, const void *: (const char
*) (strchr (ptr + 1, ';')), default: strchr (ptr + 1, ';'))
;
1105 if (!ptr)
1106 return 0;
1107 /* skip key permissions */
1108 ptr = strchr(ptr + 1, ';')_Generic (0 ? (ptr + 1) : (void *) 1, const void *: (const char
*) (strchr (ptr + 1, ';')), default: strchr (ptr + 1, ';'))
;
1109 if (!ptr)
1110 return 0;
1111 /* Only use the key description for the callback */
1112 (d->cb)(d->ctx, d->keyring, key, ptr + 1, strlen(ptr) - 1, d->data);
1113 return 1;
1114}
1115
1116__shr_public__attribute__((visibility("default"))) int libnvmf_scan_tls_keys(
1117 struct libnvme_global_ctx *ctx, const char *keyring,
1118 libnvmf_scan_tls_keys_cb_t cb, void *data)
1119{
1120 struct __scan_keys_data d;
1121 long keyring_id = 0;
1122 int ret;
1123
1124 ret = libnvmf_lookup_keyring(ctx, keyring, &keyring_id);
1125 if (ret)
1126 return ret;
1127
1128 if (!keyring_id)
1129 return -EINVAL22;
1130
1131 ret = libnvmf_set_keyring(ctx, keyring_id);
1132 if (ret < 0)
1133 return ret;
1134
1135 d.ctx = ctx;
1136 d.keyring = keyring_id;
1137 d.cb = cb;
1138 d.data = data;
1139 ret = recursive_key_scan(keyring_id, __scan_keys_cb, &d);
1140 return ret;
1141}
1142
1143static int __nvme_insert_tls_key(struct libnvme_global_ctx *ctx,
1144 key_serial_t keyring_id, const char *key_type,
1145 const char *hostnqn, const char *subsysnqn,
1146 int version, int hmac, unsigned char *configured_key,
1147 int key_len, bool_Bool compat, long *keyp)
1148{
1149 __cleanup_key_buf__attribute__((cleanup(clear_key_buf))) unsigned char psk[KEY_BUF_LEN128];
1150 __cleanup_free__attribute__((cleanup(shr_freep))) char *identity = NULL((void*)0);
1151 ssize_t identity_len;
1152 long key = 0;
1153 int ret;
1154
1155 identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn);
1156 if (identity_len < 0)
1157 return identity_len;
1158
1159 identity = malloc(identity_len);
1160 if (!identity)
1161 return -ENOMEM12;
1162 memset(identity, 0, identity_len);
1163
1164 if (key_len <= 0 || key_len > KEY_BUF_LEN128)
1165 return -EINVAL22;
1166 memset(psk, 0, key_len);
1167 ret = derive_nvme_keys(ctx, hostnqn, subsysnqn, identity, version, hmac,
1168 configured_key, psk, key_len, compat);
1169 if (ret != key_len) {
1170 if (ret < 0)
1171 return ret;
1172 return -ENOKEY126;
1173 }
1174
1175 ret = libnvmf_update_key(ctx, keyring_id, key_type, identity,
1176 psk, key_len, &key);
1177 if (ret)
1178 return ret;
1179
1180 *keyp = key;
1181 return 0;
1182}
1183
1184__shr_public__attribute__((visibility("default"))) int libnvmf_insert_tls_key_versioned(
1185 struct libnvme_global_ctx *ctx,
1186 const char *keyring, const char *key_type,
1187 const char *hostnqn, const char *subsysnqn,
1188 int version, enum libnvmf_hmac_alg hmac,
1189 unsigned char *configured_key, int key_len,
1190 long *key)
1191{
1192 long keyring_id = 0;
1193 int ret;
1194
1195 ret = libnvmf_lookup_keyring(ctx, keyring, &keyring_id);
1196 if (ret)
1197 return ret;
1198
1199 ret = libnvmf_set_keyring(ctx, keyring_id);
1200 if (ret < 0)
1201 return ret;
1202
1203 return __nvme_insert_tls_key(ctx, keyring_id, key_type,
1204 hostnqn, subsysnqn, version, hmac,
1205 configured_key, key_len, false0, key);
1206}
1207
1208__shr_public__attribute__((visibility("default"))) int libnvmf_insert_tls_key_compat(
1209 struct libnvme_global_ctx *ctx,
1210 const char *keyring, const char *key_type,
1211 const char *hostnqn, const char *subsysnqn,
1212 int version, enum libnvmf_hmac_alg hmac,
1213 unsigned char *configured_key, int key_len,
1214 long *key)
1215{
1216 long keyring_id = 0;
1217 int ret;
1218
1219 ret = libnvmf_lookup_keyring(ctx, keyring, &keyring_id);
1220 if (ret)
1221 return ret;
1222
1223 ret = libnvmf_set_keyring(ctx, keyring_id);
1224 if (ret < 0)
1225 return ret;
1226
1227 return __nvme_insert_tls_key(ctx, keyring_id, key_type,
1228 hostnqn, subsysnqn, version, hmac,
1229 configured_key, key_len, true1, key);
1230}
1231
1232__shr_public__attribute__((visibility("default"))) int libnvmf_revoke_tls_key(struct libnvme_global_ctx *ctx,
1233 const char *keyring, const char *key_type,
1234 const char *identity)
1235{
1236 long keyring_id = 0, key;
1237 int ret;
1238
1239 ret = libnvmf_lookup_keyring(ctx, keyring, &keyring_id);
1240 if (ret)
1241 return ret;
1242
1243 key = keyctl_search(keyring_id, key_type, identity, 0);
1244 if (key < 0)
1245 return -errno(*__errno_location ());
1246
1247 key = keyctl_revoke(key);
1248 if (key < 0)
1249 return -errno(*__errno_location ());
1250
1251 return 0;
1252}
1253
1254static int __nvme_import_tls_key(struct libnvme_global_ctx *ctx, long keyring_id,
1255 const char *hostnqn, const char *subsysnqn,
1256 const char *identity, const char *key,
1257 long *keyp)
1258{
1259 unsigned char *key_data = NULL((void*)0);
1260 unsigned char version;
1261 enum libnvmf_hmac_alg hmac;
1262 size_t key_len;
1263 int ret;
1264
1265 ret = libnvmf_import_tls_key_versioned(ctx, key, &version,
1266 &hmac, &key_len, &key_data);
1267 if (ret)
1268 return ret;
1269
1270 if (hmac == LIBNVMF_HMAC_ALG_NONE || !identity) {
1271 /*
1272 * This is a configured PSK (hmac 0) or we don't know the
1273 * identity and so the assumption is it is also a
1274 * configured PSK. Derive a TLS PSK from it and load the
1275 * newly created key into the keystore.
1276 */
1277 ret = __nvme_insert_tls_key(ctx, keyring_id, "psk",
1278 hostnqn, subsysnqn, version, hmac,
1279 key_data, key_len, false0, keyp);
1280 } else {
1281 ret = libnvmf_update_key(ctx, keyring_id, "psk", identity,
1282 key_data, key_len, keyp);
1283 }
1284
1285 explicit_bzero(key_data, key_len);
1286 free(key_data);
1287
1288 return ret;
1289}
1290
1291int __libnvmf_import_keys_from_config(struct libnvme_host *h, struct libnvme_ctrl *c,
1292 long *keyring_id, long *key_id)
1293{
1294 const char *hostnqn = libnvme_host_get_hostnqn(h);
1295 const char *subsysnqn = libnvme_ctrl_get_subsysnqn(c);
1296 const char *keyring, *key, *identity;
1297 long kr_id = 0, id = 0;
1298 int ret;
1299
1300 if (!hostnqn || !subsysnqn) {
1301 libnvme_msg(h->ctx, LIBNVME_LOG_ERR, "Invalid NQNs (%s, %s)\n",__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid NQNs (%s, %s)\n"
, hostnqn, subsysnqn)
1302 hostnqn, subsysnqn)__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid NQNs (%s, %s)\n"
, hostnqn, subsysnqn)
;
1303 return -EINVAL22;
1304 }
1305
1306 if (libnvme_ctrl_get_keyring(c, &keyring, NULL((void*)0)) == 0) {
1307 ret = libnvmf_lookup_keyring(h->ctx, keyring, &kr_id);
1308 if (ret)
1309 return ret;
1310 } else
1311 kr_id = c->cfg.keyring_id;
1312
1313 /*
1314 * Without a key, the kernel looks up the PSK in the keyring, so the
1315 * keyring is still passed on.
1316 */
1317 key = libnvme_ctrl_get_tls_key(c);
1318 if (!key)
1319 goto out;
1320
1321 /*
1322 * Fallback to the default keyring. This makes the keyring
1323 * explicit on the ctrl rather than left unset, which matters
1324 * to anything downstream that inspects this connection's
1325 * parameters.
1326 */
1327 if (!kr_id) {
1328 ret = libnvmf_lookup_keyring(h->ctx, ".nvme", &kr_id);
1329 if (ret)
1330 return ret;
1331 }
1332
1333 if (libnvmf_set_keyring(h->ctx, kr_id) < 0) {
1334 libnvme_msg(h->ctx, LIBNVME_LOG_ERR, "Failed to set keyring\n")__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to set keyring\n"
)
;
1335 return -errno(*__errno_location ());
1336 }
1337
1338 identity = libnvme_ctrl_get_tls_key_identity(c);
1339 if (identity) {
1340 ret = libnvmf_lookup_key(h->ctx, "psk", identity, &id);
1341 if (ret && !(ret == -ENOKEY126 || ret == -EKEYREVOKED128)) {
1342 libnvme_msg(h->ctx, LIBNVME_LOG_ERR,__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup key for identity %s, error %d\n"
, identity, ret)
1343 "Failed to lookup key for identity %s, error %d\n",__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup key for identity %s, error %d\n"
, identity, ret)
1344 identity, ret)__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup key for identity %s, error %d\n"
, identity, ret)
;
1345 return ret;
1346 }
1347 }
1348
1349 if (!id) {
1350 ret = __nvme_import_tls_key(h->ctx, kr_id, hostnqn,
1351 subsysnqn, identity, key, &id);
1352 if (ret) {
1353 libnvme_msg(h->ctx, LIBNVME_LOG_ERR,__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to insert TLS PSK, error %d\n"
, ret)
1354 "Failed to insert TLS PSK, error %d\n", ret)__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to insert TLS PSK, error %d\n"
, ret)
;
1355 return ret;
1356 }
1357 }
1358
1359out:
1360 *keyring_id = kr_id;
1361 *key_id = id;
1362
1363 return 0;
1364}
1365#else
1366__shr_public__attribute__((visibility("default"))) int libnvmf_lookup_keyring(
1367 struct libnvme_global_ctx *ctx, const char *keyring, long *key)
1368{
1369 libnvme_msg(ctx, LIBNVME_LOG_ERR, "key operations not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
1370 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1371 return -ENOTSUP95;
1372}
1373
1374__shr_public__attribute__((visibility("default"))) char *libnvmf_describe_key_serial(
1375 struct libnvme_global_ctx *ctx, long key_id)
1376{
1377 libnvme_msg(ctx, LIBNVME_LOG_ERR, "key operations not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
1378 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1379 return NULL((void*)0);
1380}
1381
1382__shr_public__attribute__((visibility("default"))) int libnvmf_lookup_key(
1383 struct libnvme_global_ctx *ctx, const char *type,
1384 const char *identity, long *key)
1385{
1386 libnvme_msg(ctx, LIBNVME_LOG_ERR, "key operations not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
1387 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1388 return -ENOTSUP95;
1389}
1390
1391__shr_public__attribute__((visibility("default"))) int libnvmf_set_keyring(
1392 struct libnvme_global_ctx *ctx, long key_id)
1393{
1394 libnvme_msg(ctx, LIBNVME_LOG_ERR, "key operations not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
1395 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1396 return -ENOTSUP95;
1397}
1398
1399__shr_public__attribute__((visibility("default"))) int libnvmf_read_key(
1400 struct libnvme_global_ctx *ctx, long keyring_id, long key_id,
1401 int *len, unsigned char **key)
1402{
1403 libnvme_msg(ctx, LIBNVME_LOG_ERR, "key operations not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
1404 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1405 return -ENOTSUP95;
1406}
1407
1408__shr_public__attribute__((visibility("default"))) int libnvmf_update_key(
1409 struct libnvme_global_ctx *ctx, long keyring_id,
1410 const char *key_type, const char *identity,
1411 unsigned char *key_data, int key_len, long *key)
1412{
1413 libnvme_msg(ctx, LIBNVME_LOG_ERR, "key operations not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
1414 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1415 return -ENOTSUP95;
1416}
1417
1418__shr_public__attribute__((visibility("default"))) int libnvmf_scan_tls_keys(
1419 struct libnvme_global_ctx *ctx, const char *keyring,
1420 libnvmf_scan_tls_keys_cb_t cb, void *data)
1421{
1422 libnvme_msg(ctx, LIBNVME_LOG_ERR, "key operations not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
1423 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1424 return -ENOTSUP95;
1425}
1426
1427__shr_public__attribute__((visibility("default"))) int libnvmf_insert_tls_key_versioned(
1428 struct libnvme_global_ctx *ctx,
1429 const char *keyring, const char *key_type,
1430 const char *hostnqn, const char *subsysnqn,
1431 int version, enum libnvmf_hmac_alg hmac,
1432 unsigned char *configured_key, int key_len,
1433 long *keyp)
1434{
1435 libnvme_msg(ctx, LIBNVME_LOG_ERR, "key operations not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
1436 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1437 return -ENOTSUP95;
1438}
1439
1440__shr_public__attribute__((visibility("default"))) int libnvmf_insert_tls_key_compat(
1441 struct libnvme_global_ctx *ctx,
1442 const char *keyring, const char *key_type,
1443 const char *hostnqn, const char *subsysnqn,
1444 int version, enum libnvmf_hmac_alg hmac,
1445 unsigned char *configured_key, int key_len,
1446 long *keyp)
1447{
1448 libnvme_msg(ctx, LIBNVME_LOG_ERR, "key operations not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
1449 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1450 return -ENOTSUP95;
1451}
1452
1453__shr_public__attribute__((visibility("default"))) int libnvmf_revoke_tls_key(struct libnvme_global_ctx *ctx,
1454 const char *keyring, const char *key_type,
1455 const char *identity)
1456{
1457 libnvme_msg(ctx, LIBNVME_LOG_ERR, "key operations not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
1458 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1459 return -ENOTSUP95;
1460}
1461
1462int __libnvmf_import_keys_from_config(struct libnvme_host *h, struct libnvme_ctrl *c,
1463 long *keyring_id, long *key_id)
1464{
1465 *keyring_id = 0;
1466 *key_id = 0;
1467
1468 return 0;
1469}
1470#endif
1471
1472__shr_public__attribute__((visibility("default"))) int libnvmf_insert_tls_key(struct libnvme_global_ctx *ctx,
1473 const char *keyring, const char *key_type,
1474 const char *hostnqn, const char *subsysnqn,
1475 enum libnvmf_hmac_alg hmac,
1476 unsigned char *configured_key, int key_len, long *key)
1477{
1478 return libnvmf_insert_tls_key_versioned(ctx, keyring, key_type,
1479 hostnqn, subsysnqn, 0, hmac,
1480 configured_key, key_len, key);
1481}
1482
1483/*
1484 * PSK Interchange Format
1485 * NVMeTLSkey-<v>:<xx>:<s>:
1486 *
1487 * x: version as one ASCII char
1488 * yy: hmac encoded as two ASCII chars
1489 * 00: no transform ('configured PSK')
1490 * 01: SHA-256
1491 * 02: SHA-384
1492 * s: 32 or 48 bytes binary followed by a CRC-32 of the configured PSK
1493 * (4 bytes) encoded as base64
1494 */
1495__shr_public__attribute__((visibility("default"))) int libnvmf_export_tls_key_versioned(
1496 struct libnvme_global_ctx *ctx, unsigned char version,
1497 enum libnvmf_hmac_alg hmac, const unsigned char *key_data,
1498 size_t key_len, char **encoded_keyp)
1499{
1500 unsigned int raw_len, encoded_len, len;
1501 unsigned long crc = shr_crc32(0L, NULL((void*)0), 0);
1502 __cleanup_key_buf__attribute__((cleanup(clear_key_buf))) unsigned char raw_secret[KEY_BUF_LEN128];
1503 char *encoded_key;
1504
1505 switch (hmac) {
1506 case LIBNVMF_HMAC_ALG_NONE:
1507 if (key_len != 32 && key_len != 48)
1508 return -EINVAL22;
1509 break;
1510 case LIBNVMF_HMAC_ALG_SHA2_256:
1511 if (key_len != 32)
1512 return -EINVAL22;
1513 break;
1514 case LIBNVMF_HMAC_ALG_SHA2_384:
1515 if (key_len != 48)
1516 return -EINVAL22;
1517 break;
1518 default:
1519 return -EINVAL22;
1520 }
1521 raw_len = key_len;
1522
1523 memcpy(raw_secret, key_data, raw_len);
1524 crc = shr_crc32(crc, raw_secret, raw_len);
1525 raw_secret[raw_len++] = crc & 0xff;
1526 raw_secret[raw_len++] = (crc >> 8) & 0xff;
1527 raw_secret[raw_len++] = (crc >> 16) & 0xff;
1528 raw_secret[raw_len++] = (crc >> 24) & 0xff;
1529
1530 encoded_len = (raw_len * 2) + 20;
1531 encoded_key = malloc(encoded_len);
1532 if (!encoded_key)
1533 return -ENOMEM12;
1534
1535 memset(encoded_key, 0, encoded_len);
1536 len = sprintf(encoded_key, "NVMeTLSkey-%x:%02x:", version, hmac);
1537 len += shr_base64_encode(raw_secret, raw_len, encoded_key + len);
1538 encoded_key[len++] = ':';
1539 encoded_key[len++] = '\0';
1540
1541 *encoded_keyp = encoded_key;
1542 return 0;
1543}
1544
1545__shr_public__attribute__((visibility("default"))) int libnvmf_export_tls_key(struct libnvme_global_ctx *ctx,
1546 const unsigned char *key_data, int key_len, char **encoded_keyp)
1547{
1548 enum libnvmf_hmac_alg hmac;
1549
1550 if (key_len == 32)
1551 hmac = LIBNVMF_HMAC_ALG_SHA2_256;
1552 else
1553 hmac = LIBNVMF_HMAC_ALG_SHA2_384;
1554
1555 return libnvmf_export_tls_key_versioned(ctx, 1, hmac, key_data,
1556 key_len, encoded_keyp);
1557}
1558
1559__shr_public__attribute__((visibility("default"))) int libnvmf_import_tls_key_versioned(
1560 struct libnvme_global_ctx *ctx, const char *encoded_key,
1561 unsigned char *version, enum libnvmf_hmac_alg *hmac,
1562 size_t *key_len, unsigned char **keyp)
1563{
1564 __cleanup_key_buf__attribute__((cleanup(clear_key_buf))) unsigned char decoded_key[KEY_BUF_LEN128];
1565 unsigned char *key_data;
1566 unsigned int crc = shr_crc32(0L, NULL((void*)0), 0);
1567 unsigned int key_crc;
1568 int err, _version, _hmac, decoded_len;
1569 size_t len;
1570
1571 if (sscanf(encoded_key, "NVMeTLSkey-%d:%02x:*s",
1572 &_version, &_hmac) != 2)
1573 return -EINVAL22;
1574
1575 if (_version != 1)
1576 return -EINVAL22;
1577
1578 *version = _version;
1579
1580 len = strlen(encoded_key);
1581 switch (_hmac) {
1582 case LIBNVMF_HMAC_ALG_NONE:
1583 if (len != 65 && len != 89)
1584 return -EINVAL22;
1585 break;
1586 case LIBNVMF_HMAC_ALG_SHA2_256:
1587 if (len != 65)
1588 return -EINVAL22;
1589 break;
1590 case LIBNVMF_HMAC_ALG_SHA2_384:
1591 if (len != 89)
1592 return -EINVAL22;
1593 break;
1594 default:
1595 return -EINVAL22;
1596 }
1597 *hmac = _hmac;
1598
1599 err = shr_base64_decode(encoded_key + 16, len - 17, decoded_key);
1600 if (err < 0)
1601 return -ENOKEY126;
1602
1603 decoded_len = err;
1604 decoded_len -= 4;
1605 if (decoded_len != 32 && decoded_len != 48)
1606 return -ENOKEY126;
1607
1608 crc = shr_crc32(crc, decoded_key, decoded_len);
1609 key_crc = ((uint32_t)decoded_key[decoded_len]) |
1610 ((uint32_t)decoded_key[decoded_len + 1] << 8) |
1611 ((uint32_t)decoded_key[decoded_len + 2] << 16) |
1612 ((uint32_t)decoded_key[decoded_len + 3] << 24);
1613 if (key_crc != crc) {
1614 libnvme_msg(ctx, LIBNVME_LOG_ERR, "CRC mismatch (key %08x, crc %08x)",__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "CRC mismatch (key %08x, crc %08x)"
, key_crc, crc)
1615 key_crc, crc)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "CRC mismatch (key %08x, crc %08x)"
, key_crc, crc)
;
1616 return -ENOKEY126;
1617 }
1618
1619 key_data = malloc(decoded_len);
1620 if (!key_data)
1621 return -ENOMEM12;
1622 memcpy(key_data, decoded_key, decoded_len);
1623
1624 *key_len = decoded_len;
1625 *keyp = key_data;
1626 return 0;
1627}
1628
1629__shr_public__attribute__((visibility("default"))) int libnvmf_import_tls_key(
1630 struct libnvme_global_ctx *ctx, const char *encoded_key,
1631 int *key_len, enum libnvmf_hmac_alg *hmac, unsigned char **keyp)
1632{
1633 unsigned char version;
1634 enum libnvmf_hmac_alg _hmac;
1635 unsigned char *psk;
1636 size_t len;
1637 int ret;
1638
1639 ret = libnvmf_import_tls_key_versioned(ctx, encoded_key, &version,
1640 &_hmac, &len, &psk);
1641 if (ret)
1642 return ret;
1643
1644 *hmac = _hmac;
1645 *key_len = len;
1646 *keyp = psk;
1647 return 0;
1648}
1649