Bug Summary

File:.build-ci/../libnvme/src/nvme/crypto.c
Warning:line 1209, column 8
2nd function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -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/lib/llvm-19/lib/clang/19 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I libnvme/src/libnvme3.so.3.0.0.p -I libnvme/src -I ../libnvme/src -I ccan -I ../ccan -I . -I .. -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -std=gnu99 -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 -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-06-24-175442-590-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 <libnvme.h>
41
42#include "crc32.h"
43#include "base64.h"
44#include "cleanup.h"
45#include "cleanup-linux.h"
46#include "private.h"
47#include "compiler-attributes.h"
48
49
50#ifndef CONFIG_OPENSSL
51static unsigned char default_hmac(size_t key_len)
52{
53 return LIBNVME_HMAC_ALG_NONE;
54}
55
56__libnvme_public__attribute__((visibility("default"))) int libnvme_gen_dhchap_key(struct libnvme_global_ctx *ctx,
57 char *hostnqn, enum libnvme_hmac_alg hmac,
58 unsigned int key_len, unsigned char *secret,
59 unsigned char *key)
60{
61 if (hmac != LIBNVME_HMAC_ALG_NONE) {
62 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")
63 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "HMAC transformation not supported; "
"recompile with OpenSSL support.\n")
;
64 return -EINVAL22;
65 }
66
67 memcpy(key, secret, key_len);
68 return 0;
69}
70
71__libnvme_public__attribute__((visibility("default"))) int libnvme_create_raw_secret(struct libnvme_global_ctx *ctx,
72 const char *secret, size_t key_len, unsigned char **raw_secret)
73{
74 libnvme_msg(ctx, LIBNVME_LOG_ERR, "NVMe TLS 2.0 is not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS 2.0 is not supported; "
"recompile with OpenSSL support.\n")
75 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS 2.0 is not supported; "
"recompile with OpenSSL support.\n")
;
76 return -ENOTSUP95;
77}
78
79static int derive_retained_key(struct libnvme_global_ctx *ctx,
80 int hmac, const char *hostnqn, unsigned char *generated,
81 unsigned char *retained, size_t key_len)
82{
83 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")
84 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
;
85 return -ENOTSUP95;
86}
87
88static int derive_retained_key_compat(struct libnvme_global_ctx *ctx,
89 int hmac, const char *hostnqn, unsigned char *generated,
90 unsigned char *retained, size_t key_len)
91{
92 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")
93 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
;
94 return -ENOTSUP95;
95}
96
97static int derive_psk_digest(struct libnvme_global_ctx *ctx,
98 const char *hostnqn, const char *subsysnqn,
99 int version, int cipher,
100 unsigned char *retained, size_t key_len,
101 char *digest, size_t digest_len)
102{
103 libnvme_msg(ctx, LIBNVME_LOG_ERR, "NVMe TLS 2.0 is not supported; "__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS 2.0 is not supported; "
"recompile with OpenSSL support.\n")
104 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS 2.0 is not supported; "
"recompile with OpenSSL support.\n")
;
105 return -ENOTSUP95;
106}
107
108static int derive_tls_key(struct libnvme_global_ctx *ctx,
109 int version, unsigned char cipher, const char *context,
110 unsigned char *retained, unsigned char *psk, size_t key_len)
111{
112 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")
113 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
;
114 return -ENOTSUP95;
115}
116
117static int derive_tls_key_compat(struct libnvme_global_ctx *ctx,
118 int version, unsigned char cipher, const char *context,
119 unsigned char *retained, unsigned char *psk, size_t key_len)
120{
121 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")
122 "recompile with OpenSSL support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "NVMe TLS is not supported; "
"recompile with OpenSSL support.\n")
;
123 return -ENOTSUP95;
124}
125#else /* CONFIG_OPENSSL */
126static unsigned char default_hmac(size_t key_len)
127{
128 unsigned char hmac = LIBNVME_HMAC_ALG_NONE;
129
130 switch (key_len) {
131 case 32:
132 hmac = LIBNVME_HMAC_ALG_SHA2_256;
133 break;
134 case 48:
135 hmac = LIBNVME_HMAC_ALG_SHA2_384;
136 break;
137 case 64:
138 hmac = LIBNVME_HMAC_ALG_SHA2_512;
139 break;
140 default:
141 break;
142 }
143 return hmac;
144}
145
146static const EVP_MD *select_hmac(int hmac, size_t *hmac_len)
147{
148 const EVP_MD *md = NULL((void*)0);
149
150 switch (hmac) {
151 case LIBNVME_HMAC_ALG_SHA2_256:
152 md = EVP_sha256();
153 *hmac_len = 32;
154 break;
155 case LIBNVME_HMAC_ALG_SHA2_384:
156 md = EVP_sha384();
157 *hmac_len = 48;
158 break;
159 default:
160 *hmac_len = 0;
161 break;
162 }
163 return md;
164}
165
166static DEFINE_CLEANUP_FUNC(void cleanup_evp_pkey_ctx(EVP_PKEY_CTX * *__p) { if (*__p) EVP_PKEY_CTX_free
(*__p); }
167 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); }
168#define __cleanup_evp_pkey_ctx__attribute__((cleanup(cleanup_evp_pkey_ctx))) __cleanup(cleanup_evp_pkey_ctx)__attribute__((cleanup(cleanup_evp_pkey_ctx)))
169
170/* NVMe is using the TLS 1.3 HkdfLabel structure */
171#define HKDF_INFO_MAX_LEN514 514
172#define HKDF_INFO_LABEL_MAX256 256
173#define HKDF_INFO_CONTEXT_MAX256 256
174
175/*
176 * derive_retained_key()
177 *
178 * Derive a retained key according to NVMe TCP Transport specification:
179 *
180 * The retained PSK is derived from the configured PSK. The configured PSK
181 * shall be destroyed as soon as the retained PSK is generated and stored.
182 * Each NVMe/TCP entity shall support:
183 * 1) transforming the configured PSK into a retained PSK before it is stored
184 * by the NVMe/TCP entity for repeated use with another NVMe/TCP entity; and
185 * 2) using the configured PSK as a retained PSK.
186 *
187 * The method to derive a retained PSK from a configured PSK shall be using
188 * the HKDF-Extract and HKDF-Expand-Label operations (refer to RFC 5869 and
189 * RFC 8446):
190 * 1. PRK = HKDF-Extract(0, Configured PSK); and
191 * 2. Retained PSK = HKDF-Expand-Label(PRK, “HostNQN”, NQNh,
192 * Length(Configured PSK)),
193 * where NQNh is the NQN of the host.
194 *
195 * 'hmac' indicates the hash function to be used to transform the configured
196 * PSK in a retained PSK, encoded as follows:
197 *
198 * - 0 indicates no transform (i.e., the configured PSK is used as a
199 * retained PSK)
200 * - 1 indicates SHA-256
201 * - 2 indicates SHA-384
202 */
203static int derive_retained_key(struct libnvme_global_ctx *ctx,
204 int hmac, const char *hostnqn,
205 unsigned char *configured, unsigned char *retained,
206 size_t key_len)
207{
208 __cleanup_evp_pkey_ctx__attribute__((cleanup(cleanup_evp_pkey_ctx))) EVP_PKEY_CTX *ectx = NULL((void*)0);
209 __cleanup_free__attribute__((cleanup(freep))) uint8_t *hkdf_info = NULL((void*)0);
210 char *hkdf_label;
211 const EVP_MD *md;
212 size_t hmac_len;
213 char *pos;
214 int ret;
215
216 /* +1 byte so that the snprintf terminating null can not overflow */
217 hkdf_info = malloc(HKDF_INFO_MAX_LEN514 + 1);
218 if (!hkdf_info)
219 return -ENOMEM12;
220
221 if (hmac == LIBNVME_HMAC_ALG_NONE) {
222 memcpy(retained, configured, key_len);
223 return key_len;
224 }
225
226 md = select_hmac(hmac, &hmac_len);
227 if (!md || !hmac_len)
228 return -EINVAL22;
229
230 ectx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF1036, NULL((void*)0));
231 if (!ectx)
232 return -ENOMEM12;
233
234 if (EVP_PKEY_derive_init(ectx) <= 0)
235 return -ENOMEM12;
236
237 if (EVP_PKEY_CTX_set_hkdf_md(ectx, md) <= 0)
238 return -ENOKEY126;
239
240 if (EVP_PKEY_CTX_set1_hkdf_key(ectx, configured, key_len) <= 0)
241 return -ENOKEY126;
242
243 if (key_len > USHRT_MAX(32767 * 2 + 1))
244 return -EINVAL22;
245
246 pos = (char *)hkdf_info;
247 *(uint16_t *)pos = htons(key_len & 0xFFFF)__bswap_16 (key_len & 0xFFFF);
248 pos += sizeof(uint16_t);
249
250 hkdf_label = "tls13 HostNQN";
251 ret = snprintf(pos, HKDF_INFO_LABEL_MAX256 + 1, "%c%s",
252 (int)strlen(hkdf_label), hkdf_label);
253 if (ret <= 0 || ret > HKDF_INFO_LABEL_MAX256)
254 return -ENOKEY126;
255 pos += ret;
256
257 ret = snprintf(pos, HKDF_INFO_CONTEXT_MAX256 + 1, "%c%s",
258 (int)strlen(hostnqn), hostnqn);
259 if (ret <= 0 || ret > HKDF_INFO_CONTEXT_MAX256)
260 return -ENOKEY126;
261 pos += ret;
262
263 if (EVP_PKEY_CTX_add1_hkdf_info(ectx, hkdf_info,
264 (pos - (char *)hkdf_info)) <= 0)
265 return -ENOKEY126;
266
267 if (EVP_PKEY_derive(ectx, retained, &key_len) <= 0)
268 return -ENOKEY126;
269
270 return key_len;
271}
272
273static int derive_retained_key_compat(struct libnvme_global_ctx *ctx,
274 int hmac, const char *hostnqn, unsigned char *configured,
275 unsigned char *retained, size_t key_len)
276{
277 __cleanup_evp_pkey_ctx__attribute__((cleanup(cleanup_evp_pkey_ctx))) EVP_PKEY_CTX *ectx = NULL((void*)0);
278 __cleanup_free__attribute__((cleanup(freep))) uint8_t *hkdf_info = NULL((void*)0);
279 const EVP_MD *md;
280 size_t hmac_len;
281 char *pos;
282 int ret;
283
284 if (hmac == LIBNVME_HMAC_ALG_NONE) {
285 memcpy(retained, configured, key_len);
286 return key_len;
287 }
288
289 md = select_hmac(hmac, &hmac_len);
290 if (!md || !hmac_len)
291 return -EINVAL22;
292
293 ectx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF1036, NULL((void*)0));
294 if (!ectx)
295 return -ENOMEM12;
296
297 if (EVP_PKEY_derive_init(ectx) <= 0)
298 return -ENOMEM12;
299
300 if (EVP_PKEY_CTX_set_hkdf_md(ectx, md) <= 0)
301 return -ENOKEY126;
302
303 if (EVP_PKEY_CTX_set1_hkdf_key(ectx, configured, key_len) <= 0)
304 return -ENOKEY126;
305
306 /* +1 byte so that the snprintf terminating null can not overflow */
307 hkdf_info = malloc(HKDF_INFO_MAX_LEN514 + 1);
308 if (!hkdf_info)
309 return -ENOMEM12;
310
311 pos = (char *)hkdf_info;
312 *(uint16_t *)pos = cpu_to_le16(key_len);
313 pos += sizeof(uint16_t);
314
315 ret = snprintf(pos, HKDF_INFO_LABEL_MAX256 + 1,
316 "tls13 HostNQN%s", hostnqn);
317 if (ret <= 0 || ret > HKDF_INFO_LABEL_MAX256)
318 return -ENOKEY126;
319 pos += ret;
320
321 if (EVP_PKEY_CTX_add1_hkdf_info(ectx, hkdf_info,
322 (pos - (char *)hkdf_info)) <= 0)
323 return -ENOKEY126;
324
325 if (EVP_PKEY_derive(ectx, retained, &key_len) <= 0)
326 return -ENOKEY126;
327
328 return key_len;
329}
330
331/*
332 * derive_tls_key()
333 *
334 * Derive a TLS PSK from a retained PSK.
335 *
336 * The TLS PSK shall be derived as follows from an input PSK (i.e., either
337 * a retained PSK or a generated PSK) and a PSK identity using the HKDF-Extract
338 * and HKDF-Expand-Label operations (refer to RFC 5869 and RFC 8446) where the
339 * hash function is the one specified by the hash specifier of the PSK identity:
340 * 1. PRK = HKDF-Extract(0, Input PSK); and
341 * 2. TLS PSK = HKDF-Expand-Label(PRK, “nvme-tls-psk”, PskIdentity, L),
342 * where PskIdentity is the PSK identity and L is the output size in bytes of
343 * the hash function (i.e., 32 for SHA-256 and 48 for SHA-384).
344 *
345 * Note that this is _not_ the hash value as specified by the configured key,
346 * but rather the hash function of the cipher suite associated with the
347 * PSK:
348 * - 1 indicates SHA-245 (for the TLS_AES_128_GCM_SHA256 cipher suite)
349 * - 2 indicates SHA-384 (for the TLS_AES_256_GCM_SHA384 cipher suite)
350 *
351 * and the value '0' is invalid here.
352 */
353
354static int derive_tls_key(struct libnvme_global_ctx *ctx,
355 int version, unsigned char cipher, const char *context,
356 unsigned char *retained, unsigned char *psk, size_t key_len)
357{
358 __cleanup_evp_pkey_ctx__attribute__((cleanup(cleanup_evp_pkey_ctx))) EVP_PKEY_CTX *ectx = NULL((void*)0);
359 __cleanup_free__attribute__((cleanup(freep))) uint8_t *hkdf_info = NULL((void*)0);
360 char *hkdf_label;
361 const EVP_MD *md;
362 size_t hmac_len;
363 char *pos;
364 int ret;
365
366 /* +1 byte so that the snprintf terminating null can not overflow */
367 hkdf_info = malloc(HKDF_INFO_MAX_LEN514 + 1);
368 if (!hkdf_info)
369 return -ENOMEM12;
370
371 md = select_hmac(cipher, &hmac_len);
372 if (!md || !hmac_len)
373 return -EINVAL22;
374
375 ectx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF1036, NULL((void*)0));
376 if (!ectx)
377 return -ENOMEM12;
378
379 if (EVP_PKEY_derive_init(ectx) <= 0)
380 return -ENOMEM12;
381
382 if (EVP_PKEY_CTX_set_hkdf_md(ectx, md) <= 0)
383 return -ENOKEY126;
384
385 if (EVP_PKEY_CTX_set1_hkdf_key(ectx, retained, key_len) <= 0)
386 return -ENOKEY126;
387
388 if (key_len > USHRT_MAX(32767 * 2 + 1))
389 return -EINVAL22;
390
391 pos = (char *)hkdf_info;
392 *(uint16_t *)pos = htons(key_len & 0xFFFF)__bswap_16 (key_len & 0xFFFF);
393 pos += sizeof(uint16_t);
394
395 hkdf_label = "tls13 nvme-tls-psk";
396 ret = snprintf(pos, HKDF_INFO_LABEL_MAX256 + 1, "%c%s",
397 (int)strlen(hkdf_label), hkdf_label);
398 if (ret <= 0 || ret > HKDF_INFO_LABEL_MAX256)
399 return -ENOKEY126;
400 pos += ret;
401
402 switch (version) {
403 case 0:
404 ret = snprintf(pos, HKDF_INFO_CONTEXT_MAX256 + 1, "%c%s",
405 (int)strlen(context), context);
406 if (ret <= 0 || ret > HKDF_INFO_CONTEXT_MAX256)
407 return -ENOKEY126;
408 pos += ret;
409 break;
410 case 1:
411 ret = snprintf(pos, HKDF_INFO_CONTEXT_MAX256 + 1, "%c%02d %s",
412 (int)strlen(context) + 3, cipher, context);
413 if (ret <= 0 || ret > HKDF_INFO_CONTEXT_MAX256)
414 return -ENOKEY126;
415 pos += ret;
416 break;
417 default:
418 return -ENOKEY126;
419 }
420
421 if (EVP_PKEY_CTX_add1_hkdf_info(ectx, hkdf_info,
422 (pos - (char *)hkdf_info)) <= 0)
423 return -ENOKEY126;
424
425 if (EVP_PKEY_derive(ectx, psk, &key_len) <= 0)
426 return -ENOKEY126;
427
428 return key_len;
429}
430
431static int derive_tls_key_compat(struct libnvme_global_ctx *ctx,
432 int version, unsigned char cipher, const char *context,
433 unsigned char *retained, unsigned char *psk, size_t key_len)
434{
435 __cleanup_evp_pkey_ctx__attribute__((cleanup(cleanup_evp_pkey_ctx))) EVP_PKEY_CTX *ectx = NULL((void*)0);
436 __cleanup_free__attribute__((cleanup(freep))) uint8_t *hkdf_info = NULL((void*)0);
437 const EVP_MD *md;
438 size_t hmac_len;
439 char *pos;
440 int ret;
441
442 md = select_hmac(cipher, &hmac_len);
443 if (!md || !hmac_len)
444 return -EINVAL22;
445
446 ectx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF1036, NULL((void*)0));
447 if (!ectx)
448 return -ENOMEM12;
449
450 if (EVP_PKEY_derive_init(ectx) <= 0)
451 return -ENOMEM12;
452
453 if (EVP_PKEY_CTX_set_hkdf_md(ectx, md) <= 0)
454 return -ENOKEY126;
455
456 if (EVP_PKEY_CTX_set1_hkdf_key(ectx, retained, key_len) <= 0)
457 return -ENOKEY126;
458
459 /* +1 byte so that the snprintf terminating null can not overflow */
460 hkdf_info = malloc(HKDF_INFO_MAX_LEN514 + 1);
461 if (!hkdf_info)
462 return -ENOMEM12;
463
464 pos = (char *)hkdf_info;
465 *(uint16_t *)pos = cpu_to_le16(key_len);
466 pos += sizeof(uint16_t);
467
468 ret = snprintf(pos, HKDF_INFO_LABEL_MAX256 + 1, "tls13 nvme-tls-psk");
469 if (ret <= 0 || ret > HKDF_INFO_LABEL_MAX256)
470 return -ENOKEY126;
471 pos += ret;
472
473 switch (version) {
474 case 0:
475 ret = snprintf(pos, HKDF_INFO_CONTEXT_MAX256 + 1, "%s", context);
476 if (ret <= 0 || ret > HKDF_INFO_CONTEXT_MAX256)
477 return -ENOKEY126;
478 pos += ret;
479 break;
480 case 1:
481 ret = snprintf(pos, HKDF_INFO_CONTEXT_MAX256 + 1, "%02d %s",
482 cipher, context);
483 if (ret <= 0 || ret > HKDF_INFO_CONTEXT_MAX256)
484 return -ENOKEY126;
485 pos += ret;
486 break;
487 default:
488 return -ENOKEY126;
489 }
490
491 if (EVP_PKEY_CTX_add1_hkdf_info(ectx, hkdf_info,
492 (pos - (char *)hkdf_info)) <= 0)
493 return -ENOKEY126;
494
495 if (EVP_PKEY_derive(ectx, psk, &key_len) <= 0)
496 return -ENOKEY126;
497
498 return key_len;
499}
500
501static DEFINE_CLEANUP_FUNC(void cleanup_ossl_lib_ctx(OSSL_LIB_CTX * *__p) { if (*__p) OSSL_LIB_CTX_free
(*__p); }
502 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); }
503#define __cleanup_ossl_lib_ctx__attribute__((cleanup(cleanup_ossl_lib_ctx))) __cleanup(cleanup_ossl_lib_ctx)__attribute__((cleanup(cleanup_ossl_lib_ctx)))
504static 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); }
505#define __cleanup_evp_mac_ctx__attribute__((cleanup(cleanup_evp_mac_ctx))) __cleanup(cleanup_evp_mac_ctx)__attribute__((cleanup(cleanup_evp_mac_ctx)))
506static DEFINE_CLEANUP_FUNC(cleanup_evp_mac, EVP_MAC *, EVP_MAC_free)void cleanup_evp_mac(EVP_MAC * *__p) { if (*__p) EVP_MAC_free
(*__p); }
507#define __cleanup_evp_mac__attribute__((cleanup(cleanup_evp_mac))) __cleanup(cleanup_evp_mac)__attribute__((cleanup(cleanup_evp_mac)))
508
509__libnvme_public__attribute__((visibility("default"))) int libnvme_gen_dhchap_key(struct libnvme_global_ctx *ctx,
510 char *hostnqn, enum libnvme_hmac_alg hmac,
511 unsigned int key_len, unsigned char *secret,
512 unsigned char *key)
513{
514 const char hmac_seed[] = "NVMe-over-Fabrics";
515 __cleanup_ossl_lib_ctx__attribute__((cleanup(cleanup_ossl_lib_ctx))) OSSL_LIB_CTX *lib_ctx = NULL((void*)0);
516 __cleanup_evp_mac_ctx__attribute__((cleanup(cleanup_evp_mac_ctx))) EVP_MAC_CTX *mac_ctx = NULL((void*)0);
517 __cleanup_evp_mac__attribute__((cleanup(cleanup_evp_mac))) EVP_MAC *mac = NULL((void*)0);
518 OSSL_PARAM params[2], *p = params;
519 char *progq = NULL((void*)0);
520 char *digest;
521 size_t len;
522
523 lib_ctx = OSSL_LIB_CTX_new();
524 if (!lib_ctx)
525 return -ENOMEM12;
526
527 mac = EVP_MAC_fetch(lib_ctx, OSSL_MAC_NAME_HMAC"HMAC", progq);
528 if (!mac)
529 return -ENOMEM12;
530
531 mac_ctx = EVP_MAC_CTX_new(mac);
532 if (!mac_ctx)
533 return -ENOMEM12;
534
535 switch (hmac) {
536 case LIBNVME_HMAC_ALG_NONE:
537 memcpy(key, secret, key_len);
538 return 0;
539 case LIBNVME_HMAC_ALG_SHA2_256:
540 digest = OSSL_DIGEST_NAME_SHA2_256"SHA2-256";
541 break;
542 case LIBNVME_HMAC_ALG_SHA2_384:
543 digest = OSSL_DIGEST_NAME_SHA2_384"SHA2-384";
544 break;
545 case LIBNVME_HMAC_ALG_SHA2_512:
546 digest = OSSL_DIGEST_NAME_SHA2_512"SHA2-512";
547 break;
548 default:
549 return -EINVAL22;
550 }
551 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST"digest",
552 digest,
553 0);
554 *p = OSSL_PARAM_construct_end();
555
556 if (!EVP_MAC_init(mac_ctx, secret, key_len, params))
557 return -ENOKEY126;
558
559 if (!EVP_MAC_update(mac_ctx, (unsigned char *)hostnqn,
560 strlen(hostnqn)))
561 return -ENOKEY126;
562
563 if (!EVP_MAC_update(mac_ctx, (unsigned char *)hmac_seed,
564 strlen(hmac_seed)))
565 return -ENOKEY126;
566
567 if (!EVP_MAC_final(mac_ctx, key, &len, key_len))
568 return -ENOKEY126;
569
570 if (len != key_len)
571 return -EMSGSIZE90;
572
573 return 0;
574}
575
576static int derive_psk_digest(struct libnvme_global_ctx *ctx,
577 const char *hostnqn, const char *subsysnqn,
578 int version, int cipher,
579 unsigned char *retained, size_t key_len,
580 char *digest, size_t digest_len)
581{
582 static const char hmac_seed[] = "NVMe-over-Fabrics";
583 __cleanup_ossl_lib_ctx__attribute__((cleanup(cleanup_ossl_lib_ctx))) OSSL_LIB_CTX *lib_ctx = NULL((void*)0);
584 __cleanup_evp_mac_ctx__attribute__((cleanup(cleanup_evp_mac_ctx))) EVP_MAC_CTX *mac_ctx = NULL((void*)0);
585 __cleanup_free__attribute__((cleanup(freep))) unsigned char *psk_ctx = NULL((void*)0);
586 __cleanup_evp_mac__attribute__((cleanup(cleanup_evp_mac))) EVP_MAC *mac = NULL((void*)0);
587 OSSL_PARAM params[2], *p = params;
588 size_t hmac_len;
589 char *progq = NULL((void*)0);
590 char *dig = NULL((void*)0);
591 size_t len;
592
593 lib_ctx = OSSL_LIB_CTX_new();
594 if (!lib_ctx)
595 return -ENOMEM12;
596
597 mac = EVP_MAC_fetch(lib_ctx, OSSL_MAC_NAME_HMAC"HMAC", progq);
598 if (!mac)
599 return -ENOMEM12;
600
601 mac_ctx = EVP_MAC_CTX_new(mac);
602 if (!mac_ctx)
603 return -ENOMEM12;
604
605 switch (cipher) {
606 case LIBNVME_HMAC_ALG_SHA2_256:
607 dig = OSSL_DIGEST_NAME_SHA2_256"SHA2-256";
608 break;
609 case LIBNVME_HMAC_ALG_SHA2_384:
610 dig = OSSL_DIGEST_NAME_SHA2_384"SHA2-384";
611 break;
612 default:
613 return -EINVAL22;
614 }
615
616 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST"digest",
617 dig, 0);
618 *p = OSSL_PARAM_construct_end();
619
620 psk_ctx = malloc(key_len);
621 if (!psk_ctx)
622 return -ENOMEM12;
623
624 if (!EVP_MAC_init(mac_ctx, retained, key_len, params))
625 return -ENOKEY126;
626
627 if (!EVP_MAC_update(mac_ctx, (unsigned char *)hostnqn,
628 strlen(hostnqn)))
629 return -ENOKEY126;
630
631 if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1))
632 return -ENOKEY126;
633
634 if (!EVP_MAC_update(mac_ctx, (unsigned char *)subsysnqn,
635 strlen(subsysnqn)))
636 return -ENOKEY126;
637
638 if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1))
639 return -ENOKEY126;
640
641 if (!EVP_MAC_update(mac_ctx, (unsigned char *)hmac_seed,
642 strlen(hmac_seed)))
643 return -ENOKEY126;
644
645 if (!EVP_MAC_final(mac_ctx, psk_ctx, &hmac_len, key_len))
646 return -ENOKEY126;
647
648 if (hmac_len > key_len)
649 return -EMSGSIZE90;
650
651 if (hmac_len * 2 > digest_len)
652 return -EINVAL22;
653
654 memset(digest, 0, digest_len);
655 len = base64_encode(psk_ctx, hmac_len, digest);
656 if (len < 0)
657 return len;
658
659 return strlen(digest);
660}
661
662static ssize_t getrandom_bytes(void *buf, size_t buflen)
663{
664 ssize_t result;
665#if NVME_HAVE_SYS_RANDOM1
666 result = getrandom(buf, buflen, GRND_NONBLOCK0x01);
667#else
668 __cleanup_fd__attribute__((cleanup(cleanup_fd))) int fd = -1;
669
670 fd = open("/dev/urandom", O_RDONLY00);
671 if (fd < 0)
672 return -errno(*__errno_location ());
673 result = read(fd, buf, buflen);
674#endif
675 if (result < 0)
676 return -errno(*__errno_location ());
677 return result;
678}
679
680static ssize_t getswordfish(struct libnvme_global_ctx *ctx,
681 const char *seed, void *buf, size_t buflen)
682{
683 unsigned char hash[EVP_MAX_MD_SIZE64];
684 EVP_MD_CTX *md_ctx;
685 size_t copied = 0;
686
687 md_ctx = EVP_MD_CTX_new();
688 if (!md_ctx)
689 return -ENOMEM12;
690
691 while (copied < buflen) {
692 unsigned int counter = 0;
693 unsigned int hash_len;
694 size_t to_copy;
695
696 if (EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL((void*)0)) != 1)
697 goto err;
698
699 EVP_DigestUpdate(md_ctx, seed, strlen(seed));
700 EVP_DigestUpdate(md_ctx, &counter, sizeof(counter));
701
702 if (EVP_DigestFinal_ex(md_ctx, hash, &hash_len) != 1)
703 goto err;
704
705 to_copy = buflen - copied;
706 if (to_copy > hash_len)
707 to_copy = hash_len;
708
709 memcpy((unsigned char *)buf + copied, hash, to_copy);
710 copied += to_copy;
711 counter++;
712 }
713
714 EVP_MD_CTX_free(md_ctx);
715 return buflen;
716
717err:
718 EVP_MD_CTX_free(md_ctx);
719 return -EIO5;
720}
721
722__libnvme_public__attribute__((visibility("default"))) int libnvme_create_raw_secret(struct libnvme_global_ctx *ctx,
723 const char *secret, size_t key_len, unsigned char **raw_secret)
724{
725 __cleanup_free__attribute__((cleanup(freep))) unsigned char *buf = NULL((void*)0);
726 int secret_len = 0, i, err;
727 unsigned int c;
728
729 if (key_len != 32 && key_len != 48 && key_len != 64) {
730 libnvme_msg(ctx, LIBNVME_LOG_ERR, "Invalid key length %ld", key_len)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid key length %ld"
, key_len)
;
731 return -EINVAL22;
732 }
733
734 buf = malloc(key_len);
735 if (!buf)
736 return -ENOMEM12;
737
738 if (!secret) {
739 err = getrandom_bytes(buf, key_len);
740 if (err < 0)
741 return err;
742
743 goto out;
744 }
745
746 if (strlen(secret) < 4) {
747 libnvme_msg(ctx, LIBNVME_LOG_ERR, "Input secret too short\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Input secret too short\n"
)
;
748 return -EINVAL22;
749 }
750
751 if (!strncmp(secret, "pin:", 4)) {
752 err = getswordfish(ctx, &secret[4], buf, key_len);
753 if (err < 0)
754 return err;
755
756 goto out;
757 }
758
759 for (i = 0; i < strlen(secret); i += 2) {
760 if (sscanf(&secret[i], "%02x", &c) != 1) {
761 libnvme_msg(ctx, LIBNVME_LOG_ERR,__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid secret '%s'"
, secret)
762 "Invalid secret '%s'", secret)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid secret '%s'"
, secret)
;
763 return -EINVAL22;
764 }
765 if (i >= key_len * 2) {
766 libnvme_msg(ctx, LIBNVME_LOG_ERR,__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Skipping excess secret bytes\n"
)
767 "Skipping excess secret bytes\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Skipping excess secret bytes\n"
)
;
768 break;
769 }
770 buf[secret_len++] = (unsigned char)c;
771 }
772 if (secret_len != key_len) {
773 libnvme_msg(ctx, LIBNVME_LOG_ERR,__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid key length (%d bytes)\n"
, secret_len)
774 "Invalid key length (%d bytes)\n", secret_len)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid key length (%d bytes)\n"
, secret_len)
;
775 return -EINVAL22;
776 }
777
778out:
779 *raw_secret = buf;
780 buf = NULL((void*)0);
781 return 0;
782}
783
784#endif /* CONFIG_OPENSSL */
785
786static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
787 int version, int cipher, char *digest,
788 char *identity)
789{
790 if (version == 0) {
791 sprintf(identity, "NVMe%01dR%02d %s %s",
792 version, cipher, hostnqn, subsysnqn);
793 return strlen(identity);
794 }
795 if (version > 1 || !digest)
796 return -EINVAL22;
797
798 sprintf(identity, "NVMe%01dR%02d %s %s %s",
799 version, cipher, hostnqn, subsysnqn, digest);
800 return strlen(identity);
801}
802
803static int derive_nvme_keys(struct libnvme_global_ctx *ctx,
804 const char *hostnqn, const char *subsysnqn,
805 char *identity, int version,
806 int hmac, unsigned char *configured,
807 unsigned char *psk, int key_len, bool_Bool compat)
808{
809 __cleanup_free__attribute__((cleanup(freep))) unsigned char *retained = NULL((void*)0);
810 __cleanup_free__attribute__((cleanup(freep))) char *digest = NULL((void*)0);
811 char *context = identity;
812 unsigned char cipher;
813 int ret = -1;
814
815 if (!hostnqn || !subsysnqn || !identity || !psk)
816 return -EINVAL22;
817
818 retained = malloc(key_len);
819 if (!retained)
820 return -ENOMEM12;
821
822 if (compat)
823 ret = derive_retained_key_compat(ctx, hmac, hostnqn, configured,
824 retained, key_len);
825 else
826 ret = derive_retained_key(ctx, hmac, hostnqn, configured,
827 retained, key_len);
828 if (ret < 0)
829 return ret;
830
831 if (hmac == LIBNVME_HMAC_ALG_NONE)
832 cipher = default_hmac(key_len);
833 else
834 cipher = hmac;
835
836 if (version == 1) {
837 size_t digest_len = 2 * key_len;
838
839 digest = malloc(digest_len);
840 if (!digest)
841 return -ENOMEM12;
842
843 ret = derive_psk_digest(ctx, hostnqn, subsysnqn, version,
844 cipher, retained, key_len, digest,
845 digest_len);
846 if (ret < 0)
847 return ret;
848 context = digest;
849 }
850 ret = gen_tls_identity(hostnqn, subsysnqn, version, cipher,
851 digest, identity);
852 if (ret < 0)
853 return ret;
854 if (compat)
855 return derive_tls_key_compat(ctx, version, cipher, context,
856 retained, psk, key_len);
857 return derive_tls_key(ctx, version, cipher, context, retained,
858 psk, key_len);
859}
860
861static ssize_t nvme_identity_len(int hmac, int version, const char *hostnqn,
862 const char *subsysnqn)
863{
864 ssize_t len;
865
866 if (!hostnqn || !subsysnqn)
867 return -EINVAL22;
868
869 len = strlen(hostnqn) + strlen(subsysnqn) + 12;
870 if (version == 1) {
871 len += 66;
872 if (hmac == LIBNVME_HMAC_ALG_SHA2_384)
873 len += 32;
874 } else if (version > 1) {
875 return -EINVAL22;
876 }
877 return len;
878}
879
880__libnvme_public__attribute__((visibility("default"))) int libnvme_generate_tls_key_identity(
881 struct libnvme_global_ctx *ctx, const char *hostnqn,
882 const char *subsysnqn, int version, int hmac,
883 unsigned char *configured_key, int key_len, char **ident)
884{
885 __cleanup_free__attribute__((cleanup(freep))) unsigned char *psk = NULL((void*)0);
886 __cleanup_free__attribute__((cleanup(freep))) char *identity = NULL((void*)0);
887 ssize_t identity_len;
888 int ret;
889
890 identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn);
891 if (identity_len < 0)
892 return -EINVAL22;
893
894 identity = malloc(identity_len);
895 if (!identity)
896 return -ENOMEM12;
897
898 psk = malloc(key_len);
899 if (!psk)
900 return -ENOMEM12;
901
902 memset(psk, 0, key_len);
903 ret = derive_nvme_keys(ctx, hostnqn, subsysnqn, identity, version, hmac,
904 configured_key, psk, key_len, false0);
905 if (ret != key_len) {
906 if (ret < 0)
907 return ret;
908 return -ENOKEY126;
909 }
910
911 *ident = identity;
912 identity = NULL((void*)0);
913
914 return 0;
915}
916
917__libnvme_public__attribute__((visibility("default"))) int libnvme_generate_tls_key_identity_compat(
918 struct libnvme_global_ctx *ctx, const char *hostnqn,
919 const char *subsysnqn, int version, int hmac,
920 unsigned char *configured_key, int key_len, char **ident)
921{
922 __cleanup_free__attribute__((cleanup(freep))) unsigned char *psk = NULL((void*)0);
923 __cleanup_free__attribute__((cleanup(freep))) char *identity = NULL((void*)0);
924 ssize_t identity_len;
925 int ret;
926
927 identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn);
928 if (identity_len < 0)
929 return -EINVAL22;
930
931 identity = malloc(identity_len);
932 if (!identity)
933 return -ENOMEM12;
934
935 psk = malloc(key_len);
936 if (!psk)
937 return -ENOMEM12;
938
939 memset(psk, 0, key_len);
940 ret = derive_nvme_keys(ctx, hostnqn, subsysnqn, identity, version, hmac,
941 configured_key, psk, key_len, true1);
942 if (ret != key_len) {
943 if (ret < 0)
944 return ret;
945 return -ENOKEY126;
946 }
947
948 *ident = identity;
949 identity = NULL((void*)0);
950
951 return 0;
952}
953
954#ifdef CONFIG_KEYUTILS
955__libnvme_public__attribute__((visibility("default"))) int libnvme_lookup_keyring(
956 struct libnvme_global_ctx *ctx, const char *keyring, long *key)
957{
958 key_serial_t keyring_id;
959
960 if (!keyring)
3
Assuming 'keyring' is non-null
4
Taking false branch
961 keyring = NVME_TLS_DEFAULT_KEYRING".nvme";
962 keyring_id = find_key_by_type_and_desc("keyring", keyring, 0);
963 if (keyring_id < 0)
5
Assuming 'keyring_id' is < 0
6
Taking true branch
964 return -errno(*__errno_location ());
7
Returning without writing to '*key'
8
Returning value, which participates in a condition later
965
966 *key = keyring_id;
967 return 0;
968}
969
970__libnvme_public__attribute__((visibility("default"))) char *libnvme_describe_key_serial(
971 struct libnvme_global_ctx *ctx, long key_id)
972{
973 __cleanup_free__attribute__((cleanup(freep))) char *str = NULL((void*)0);
974 char *last;
975
976 if (keyctl_describe_alloc(key_id, &str) < 0)
977 return NULL((void*)0);
978
979 last = strrchr(str, ';');
980 if (!last)
981 return NULL((void*)0);
982
983 last++;
984 if (strlen(last) == 0)
985 return NULL((void*)0);
986
987 return strdup(last);
988}
989
990__libnvme_public__attribute__((visibility("default"))) int libnvme_lookup_key(
991 struct libnvme_global_ctx *ctx, const char *type,
992 const char *identity, long *keyp)
993{
994 key_serial_t key;
995
996 key = keyctl_search(KEY_SPEC_SESSION_KEYRING-3, type, identity, 0);
997 if (key < 0)
998 return -errno(*__errno_location ());
999
1000 *keyp = key;
1001 return 0;
1002}
1003
1004__libnvme_public__attribute__((visibility("default"))) int libnvme_set_keyring(
1005 struct libnvme_global_ctx *ctx, long key_id)
1006{
1007 long err;
1008
1009 if (key_id == 0) {
1010 if (libnvme_lookup_keyring(ctx, NULL((void*)0), &key_id))
1011 return -ENOKEY126;
1012 }
1013
1014 err = keyctl_link(key_id, KEY_SPEC_SESSION_KEYRING-3);
1015 if (err < 0)
1016 return -errno(*__errno_location ());
1017 return 0;
1018}
1019
1020__libnvme_public__attribute__((visibility("default"))) int libnvme_read_key(
1021 struct libnvme_global_ctx *ctx, long keyring_id, long key_id,
1022 int *len, unsigned char **key)
1023{
1024 void *buffer;
1025 int ret;
1026
1027 ret = libnvme_set_keyring(ctx, keyring_id);
1028 if (ret < 0)
1029 return ret;
1030
1031 ret = keyctl_read_alloc(key_id, &buffer);
1032 if (ret < 0)
1033 return ret;
1034
1035 *len = ret;
1036 *key = buffer;
1037 return 0;
1038}
1039
1040__libnvme_public__attribute__((visibility("default"))) int libnvme_update_key(
1041 struct libnvme_global_ctx *ctx, long keyring_id,
1042 const char *key_type, const char *identity,
1043 unsigned char *key_data, int key_len, long *keyp)
1044{
1045 long key;
1046
1047 key = keyctl_search(keyring_id, key_type, identity, 0);
1048 if (key > 0) {
1049 if (keyctl_revoke(key) < 0)
1050 return -errno(*__errno_location ());
1051 }
1052 key = add_key(key_type, identity,
1053 key_data, key_len, keyring_id);
1054 if (key < 0)
1055 return -errno(*__errno_location ());
1056
1057 *keyp = key;
1058 return 0;
1059}
1060
1061struct __scan_keys_data {
1062 struct libnvme_global_ctx *ctx;
1063 libnvme_scan_tls_keys_cb_t cb;
1064 key_serial_t keyring;
1065 void *data;
1066};
1067
1068int __scan_keys_cb(key_serial_t parent, key_serial_t key, char *desc,
1069 int desc_len, void *data)
1070{
1071 struct __scan_keys_data *d = data;
1072 int ver, hmac, uid, gid, perm;
1073 char type, *ptr;
1074
1075 if (desc_len < 6)
1076 return 0;
1077 if (sscanf(desc, "psk;%d;%d;%08x;NVMe%01d%c%02d %*s",
1078 &uid, &gid, &perm, &ver, &type, &hmac) != 6)
1079 return 0;
1080 /* skip key type */
1081 ptr = strchr(desc, ';');
1082 if (!ptr)
1083 return 0;
1084 /* skip key uid */
1085 ptr = strchr(ptr + 1, ';');
1086 if (!ptr)
1087 return 0;
1088 /* skip key gid */
1089 ptr = strchr(ptr + 1, ';');
1090 if (!ptr)
1091 return 0;
1092 /* skip key permissions */
1093 ptr = strchr(ptr + 1, ';');
1094 if (!ptr)
1095 return 0;
1096 /* Only use the key description for the callback */
1097 (d->cb)(d->ctx, d->keyring, key, ptr + 1, strlen(ptr) - 1, d->data);
1098 return 1;
1099}
1100
1101__libnvme_public__attribute__((visibility("default"))) int libnvme_scan_tls_keys(
1102 struct libnvme_global_ctx *ctx, const char *keyring,
1103 libnvme_scan_tls_keys_cb_t cb, void *data)
1104{
1105 struct __scan_keys_data d;
1106 long keyring_id;
1107 int ret;
1108
1109 ret = libnvme_lookup_keyring(ctx, keyring, &keyring_id);
1110 if (ret)
1111 return ret;
1112
1113 if (!keyring_id)
1114 return -EINVAL22;
1115
1116 ret = libnvme_set_keyring(ctx, keyring_id);
1117 if (ret < 0)
1118 return ret;
1119
1120 d.ctx = ctx;
1121 d.keyring = keyring_id;
1122 d.cb = cb;
1123 d.data = data;
1124 ret = recursive_key_scan(keyring_id, __scan_keys_cb, &d);
1125 return ret;
1126}
1127
1128static int __nvme_insert_tls_key(struct libnvme_global_ctx *ctx,
1129 key_serial_t keyring_id, const char *key_type,
1130 const char *hostnqn, const char *subsysnqn,
1131 int version, int hmac, unsigned char *configured_key,
1132 int key_len, bool_Bool compat, long *keyp)
1133{
1134 __cleanup_free__attribute__((cleanup(freep))) unsigned char *psk = NULL((void*)0);
1135 __cleanup_free__attribute__((cleanup(freep))) char *identity = NULL((void*)0);
1136 ssize_t identity_len;
1137 long key;
1138 int ret;
1139
1140 identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn);
1141 if (identity_len < 0)
1142 return identity_len;
1143
1144 identity = malloc(identity_len);
1145 if (!identity)
1146 return -ENOMEM12;
1147 memset(identity, 0, identity_len);
1148
1149 psk = malloc(key_len);
1150 if (!psk)
1151 return -ENOMEM12;
1152 memset(psk, 0, key_len);
1153 ret = derive_nvme_keys(ctx, hostnqn, subsysnqn, identity, version, hmac,
1154 configured_key, psk, key_len, compat);
1155 if (ret != key_len) {
1156 if (ret < 0)
1157 return ret;
1158 return -ENOKEY126;
1159 }
1160
1161 ret = libnvme_update_key(ctx, keyring_id, key_type, identity,
1162 psk, key_len, &key);
1163 if (ret)
1164 return ret;
1165
1166 *keyp = key;
1167 return 0;
1168}
1169
1170__libnvme_public__attribute__((visibility("default"))) int libnvme_insert_tls_key_versioned(
1171 struct libnvme_global_ctx *ctx,
1172 const char *keyring, const char *key_type,
1173 const char *hostnqn, const char *subsysnqn,
1174 int version, int hmac,
1175 unsigned char *configured_key, int key_len,
1176 long *key)
1177{
1178 long keyring_id;
1179 int ret;
1180
1181 ret = libnvme_lookup_keyring(ctx, keyring, &keyring_id);
1182 if (ret)
1183 return ret;
1184
1185 ret = libnvme_set_keyring(ctx, keyring_id);
1186 if (ret < 0)
1187 return 0;
1188
1189 return __nvme_insert_tls_key(ctx, keyring_id, key_type,
1190 hostnqn, subsysnqn, version, hmac,
1191 configured_key, key_len, false0, key);
1192}
1193
1194__libnvme_public__attribute__((visibility("default"))) int libnvme_insert_tls_key_compat(
1195 struct libnvme_global_ctx *ctx,
1196 const char *keyring, const char *key_type,
1197 const char *hostnqn, const char *subsysnqn,
1198 int version, int hmac,
1199 unsigned char *configured_key, int key_len,
1200 long *key)
1201{
1202 long keyring_id;
1
'keyring_id' declared without an initial value
1203 int ret;
1204
1205 ret = libnvme_lookup_keyring(ctx, keyring, &keyring_id);
2
Calling 'libnvme_lookup_keyring'
9
Returning from 'libnvme_lookup_keyring'
1206 if (ret)
10
Assuming 'ret' is 0
11
Taking false branch
1207 return ret;
1208
1209 ret = libnvme_set_keyring(ctx, keyring_id);
12
2nd function call argument is an uninitialized value
1210 if (ret < 0)
1211 return 0;
1212
1213 return __nvme_insert_tls_key(ctx, keyring_id, key_type,
1214 hostnqn, subsysnqn, version, hmac,
1215 configured_key, key_len, true1, key);
1216}
1217
1218__libnvme_public__attribute__((visibility("default"))) int libnvme_revoke_tls_key(struct libnvme_global_ctx *ctx,
1219 const char *keyring, const char *key_type,
1220 const char *identity)
1221{
1222 long keyring_id, key;
1223 int ret;
1224
1225 ret = libnvme_lookup_keyring(ctx, keyring, &keyring_id);
1226 if (ret)
1227 return ret;
1228
1229 key = keyctl_search(keyring_id, key_type, identity, 0);
1230 if (key < 0)
1231 return -errno(*__errno_location ());
1232
1233 key = keyctl_revoke(key);
1234 if (key < 0)
1235 return -errno(*__errno_location ());
1236
1237 return 0;
1238}
1239
1240static int __nvme_import_tls_key(struct libnvme_global_ctx *ctx, long keyring_id,
1241 const char *hostnqn, const char *subsysnqn,
1242 const char *identity, const char *key,
1243 long *keyp)
1244{
1245 __cleanup_free__attribute__((cleanup(freep))) unsigned char *key_data = NULL((void*)0);
1246 unsigned char version;
1247 unsigned char hmac;
1248 size_t key_len;
1249 int ret;
1250
1251 ret = libnvme_import_tls_key_versioned(ctx, key, &version,
1252 &hmac, &key_len, &key_data);
1253 if (ret)
1254 return ret;
1255
1256 if (hmac == LIBNVME_HMAC_ALG_NONE || !identity) {
1257 /*
1258 * This is a configured key (hmac 0) or we don't know the
1259 * identity and so the assumtion is it is also a
1260 * configured key. Derive a new key and load the newly
1261 * created key into the keystore.
1262 */
1263 return __nvme_insert_tls_key(ctx, keyring_id, "psk",
1264 hostnqn, subsysnqn, version, hmac,
1265 key_data, key_len, false0, keyp);
1266 }
1267
1268 return libnvme_update_key(ctx, keyring_id, "psk", identity,
1269 key_data, key_len, keyp);
1270}
1271
1272int __libnvme_import_keys_from_config(libnvme_host_t h, libnvme_ctrl_t c,
1273 long *keyring_id, long *key_id)
1274{
1275 const char *hostnqn = libnvme_host_get_hostnqn(h);
1276 const char *subsysnqn = libnvme_ctrl_get_subsysnqn(c);
1277 const char *keyring, *key, *identity;
1278 long kr_id = 0, id = 0;
1279 int ret;
1280
1281 if (!hostnqn || !subsysnqn) {
1282 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)
1283 hostnqn, subsysnqn)__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Invalid NQNs (%s, %s)\n"
, hostnqn, subsysnqn)
;
1284 return -EINVAL22;
1285 }
1286
1287 /* If we don't have a key avoid all keyring operations */
1288 key = libnvme_ctrl_get_tls_key(c);
1289 if (!key)
1290 goto out;
1291
1292 keyring = libnvme_ctrl_get_keyring(c);
1293 if (keyring) {
1294 ret = libnvme_lookup_keyring(h->ctx, keyring, &kr_id);
1295 if (ret)
1296 return ret;
1297 } else
1298 kr_id = c->cfg.keyring_id;
1299
1300 /*
1301 * Fallback to the default keyring. Note this will also add the
1302 * keyring to connect command line and to the JSON config output.
1303 * That means we are explicitly selecting the keyring.
1304 */
1305 if (!kr_id) {
1306 ret = libnvme_lookup_keyring(h->ctx, ".nvme", &kr_id);
1307 if (ret)
1308 return ret;
1309 }
1310
1311 if (libnvme_set_keyring(h->ctx, kr_id) < 0) {
1312 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"
)
;
1313 return -errno(*__errno_location ());
1314 }
1315
1316 identity = libnvme_ctrl_get_tls_key_identity(c);
1317 if (identity) {
1318 ret = libnvme_lookup_key(h->ctx, "psk", identity, &id);
1319 if (ret && !(ret == -ENOKEY126 || ret == -EKEYREVOKED128)) {
1320 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)
1321 "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)
1322 identity, ret)__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup key for identity %s, error %d\n"
, identity, ret)
;
1323 return ret;
1324 }
1325 }
1326
1327 if (!id) {
1328 ret = __nvme_import_tls_key(h->ctx, kr_id, hostnqn,
1329 subsysnqn, identity, key, &id);
1330 if (ret) {
1331 libnvme_msg(h->ctx, LIBNVME_LOG_ERR,__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to insert TLS KEY, error %d\n"
, ret)
1332 "Failed to insert TLS KEY, error %d\n", ret)__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to insert TLS KEY, error %d\n"
, ret)
;
1333 return ret;
1334 }
1335 }
1336
1337out:
1338 *keyring_id = kr_id;
1339 *key_id = id;
1340
1341 return 0;
1342}
1343#else
1344__libnvme_public__attribute__((visibility("default"))) int libnvme_lookup_keyring(
1345 struct libnvme_global_ctx *ctx, const char *keyring, long *key)
1346{
1347 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")
1348 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1349 return -ENOTSUP95;
1350}
1351
1352__libnvme_public__attribute__((visibility("default"))) char *libnvme_describe_key_serial(
1353 struct libnvme_global_ctx *ctx, long key_id)
1354{
1355 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")
1356 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1357 return NULL((void*)0);
1358}
1359
1360__libnvme_public__attribute__((visibility("default"))) int libnvme_lookup_key(
1361 struct libnvme_global_ctx *ctx, const char *type,
1362 const char *identity, long *key)
1363{
1364 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")
1365 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1366 return -ENOTSUP95;
1367}
1368
1369__libnvme_public__attribute__((visibility("default"))) int libnvme_set_keyring(
1370 struct libnvme_global_ctx *ctx, long key_id)
1371{
1372 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")
1373 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1374 return -ENOTSUP95;
1375}
1376
1377__libnvme_public__attribute__((visibility("default"))) int libnvme_read_key(
1378 struct libnvme_global_ctx *ctx, long keyring_id, long key_id,
1379 int *len, unsigned char **key)
1380{
1381 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")
1382 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1383 return -ENOTSUP95;
1384}
1385
1386__libnvme_public__attribute__((visibility("default"))) int libnvme_update_key(
1387 struct libnvme_global_ctx *ctx, long keyring_id,
1388 const char *key_type, const char *identity,
1389 unsigned char *key_data, int key_len, long *key)
1390{
1391 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")
1392 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1393 return -ENOTSUP95;
1394}
1395
1396__libnvme_public__attribute__((visibility("default"))) int libnvme_scan_tls_keys(
1397 struct libnvme_global_ctx *ctx, const char *keyring,
1398 libnvme_scan_tls_keys_cb_t cb, void *data)
1399{
1400 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")
1401 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1402 return -ENOTSUP95;
1403}
1404
1405__libnvme_public__attribute__((visibility("default"))) int libnvme_insert_tls_key_versioned(
1406 struct libnvme_global_ctx *ctx,
1407 const char *keyring, const char *key_type,
1408 const char *hostnqn, const char *subsysnqn,
1409 int version, int hmac,
1410 unsigned char *configured_key, int key_len,
1411 long *keyp)
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__libnvme_public__attribute__((visibility("default"))) int libnvme_insert_tls_key_compat(
1419 struct libnvme_global_ctx *ctx,
1420 const char *keyring, const char *key_type,
1421 const char *hostnqn, const char *subsysnqn,
1422 int version, int hmac,
1423 unsigned char *configured_key, int key_len,
1424 long *keyp)
1425{
1426 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")
1427 "recompile with keyutils support.\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "key operations not supported; "
"recompile with keyutils support.\n")
;
1428 return -ENOTSUP95;
1429}
1430
1431__libnvme_public__attribute__((visibility("default"))) int libnvme_revoke_tls_key(struct libnvme_global_ctx *ctx,
1432 const char *keyring, const char *key_type,
1433 const char *identity)
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
1440int __libnvme_import_keys_from_config(libnvme_host_t h, libnvme_ctrl_t c,
1441 long *keyring_id, long *key_id)
1442{
1443 *keyring_id = 0;
1444 *key_id = 0;
1445
1446 return 0;
1447}
1448#endif
1449
1450__libnvme_public__attribute__((visibility("default"))) int libnvme_insert_tls_key(struct libnvme_global_ctx *ctx,
1451 const char *keyring, const char *key_type,
1452 const char *hostnqn, const char *subsysnqn, int hmac,
1453 unsigned char *configured_key, int key_len, long *key)
1454{
1455 return libnvme_insert_tls_key_versioned(ctx, keyring, key_type,
1456 hostnqn, subsysnqn, 0, hmac,
1457 configured_key, key_len, key);
1458}
1459
1460/*
1461 * PSK Interchange Format
1462 * NVMeTLSkey-<v>:<xx>:<s>:
1463 *
1464 * x: version as one ASCII char
1465 * yy: hmac encoded as two ASCII chars
1466 * 00: no transform ('configured PSK')
1467 * 01: SHA-256
1468 * 02: SHA-384
1469 * s: 32 or 48 bytes binary followed by a CRC-32 of the configured PSK
1470 * (4 bytes) encoded as base64
1471 */
1472__libnvme_public__attribute__((visibility("default"))) int libnvme_export_tls_key_versioned(
1473 struct libnvme_global_ctx *ctx, unsigned char version,
1474 unsigned char hmac, const unsigned char *key_data,
1475 size_t key_len, char **encoded_keyp)
1476{
1477 unsigned int raw_len, encoded_len, len;
1478 unsigned long crc = crc32(0L, NULL((void*)0), 0);
1479 unsigned char raw_secret[52];
1480 char *encoded_key;
1481
1482 switch (hmac) {
1483 case LIBNVME_HMAC_ALG_NONE:
1484 if (key_len != 32 && key_len != 48)
1485 return -EINVAL22;
1486 break;
1487 case LIBNVME_HMAC_ALG_SHA2_256:
1488 if (key_len != 32)
1489 return -EINVAL22;
1490 break;
1491 case LIBNVME_HMAC_ALG_SHA2_384:
1492 if (key_len != 48)
1493 return -EINVAL22;
1494 break;
1495 default:
1496 return -EINVAL22;
1497 }
1498 raw_len = key_len;
1499
1500 memcpy(raw_secret, key_data, raw_len);
1501 crc = crc32(crc, raw_secret, raw_len);
1502 raw_secret[raw_len++] = crc & 0xff;
1503 raw_secret[raw_len++] = (crc >> 8) & 0xff;
1504 raw_secret[raw_len++] = (crc >> 16) & 0xff;
1505 raw_secret[raw_len++] = (crc >> 24) & 0xff;
1506
1507 encoded_len = (raw_len * 2) + 20;
1508 encoded_key = malloc(encoded_len);
1509 if (!encoded_key)
1510 return -ENOMEM12;
1511
1512 memset(encoded_key, 0, encoded_len);
1513 len = sprintf(encoded_key, "NVMeTLSkey-%x:%02x:", version, hmac);
1514 len += base64_encode(raw_secret, raw_len, encoded_key + len);
1515 encoded_key[len++] = ':';
1516 encoded_key[len++] = '\0';
1517
1518 *encoded_keyp = encoded_key;
1519 return 0;
1520}
1521
1522__libnvme_public__attribute__((visibility("default"))) int libnvme_export_tls_key(struct libnvme_global_ctx *ctx,
1523 const unsigned char *key_data, int key_len, char **key)
1524{
1525 unsigned char hmac;
1526
1527 if (key_len == 32)
1528 hmac = LIBNVME_HMAC_ALG_SHA2_256;
1529 else
1530 hmac = LIBNVME_HMAC_ALG_SHA2_384;
1531
1532 return libnvme_export_tls_key_versioned(ctx, 1, hmac, key_data,
1533 key_len, key);
1534}
1535
1536__libnvme_public__attribute__((visibility("default"))) int libnvme_import_tls_key_versioned(
1537 struct libnvme_global_ctx *ctx, const char *encoded_key,
1538 unsigned char *version, unsigned char *hmac, size_t *key_len,
1539 unsigned char **keyp)
1540{
1541 unsigned char decoded_key[128], *key_data;
1542 unsigned int crc = crc32(0L, NULL((void*)0), 0);
1543 unsigned int key_crc;
1544 int err, _version, _hmac, decoded_len;
1545 size_t len;
1546
1547 if (sscanf(encoded_key, "NVMeTLSkey-%d:%02x:*s",
1548 &_version, &_hmac) != 2)
1549 return -EINVAL22;
1550
1551 if (_version != 1)
1552 return -EINVAL22;
1553
1554 *version = _version;
1555
1556 len = strlen(encoded_key);
1557 switch (_hmac) {
1558 case LIBNVME_HMAC_ALG_NONE:
1559 if (len != 65 && len != 89)
1560 return -EINVAL22;
1561 break;
1562 case LIBNVME_HMAC_ALG_SHA2_256:
1563 if (len != 65)
1564 return -EINVAL22;
1565 break;
1566 case LIBNVME_HMAC_ALG_SHA2_384:
1567 if (len != 89)
1568 return -EINVAL22;
1569 break;
1570 default:
1571 return -EINVAL22;
1572 }
1573 *hmac = _hmac;
1574
1575 err = base64_decode(encoded_key + 16, len - 17, decoded_key);
1576 if (err < 0)
1577 return -ENOKEY126;
1578
1579 decoded_len = err;
1580 decoded_len -= 4;
1581 if (decoded_len != 32 && decoded_len != 48)
1582 return -ENOKEY126;
1583
1584 crc = crc32(crc, decoded_key, decoded_len);
1585 key_crc = ((uint32_t)decoded_key[decoded_len]) |
1586 ((uint32_t)decoded_key[decoded_len + 1] << 8) |
1587 ((uint32_t)decoded_key[decoded_len + 2] << 16) |
1588 ((uint32_t)decoded_key[decoded_len + 3] << 24);
1589 if (key_crc != crc) {
1590 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)
1591 key_crc, crc)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "CRC mismatch (key %08x, crc %08x)"
, key_crc, crc)
;
1592 return -ENOKEY126;
1593 }
1594
1595 key_data = malloc(decoded_len);
1596 if (!key_data)
1597 return -ENOMEM12;
1598 memcpy(key_data, decoded_key, decoded_len);
1599
1600 *key_len = decoded_len;
1601 *keyp = key_data;
1602 return 0;
1603}
1604
1605__libnvme_public__attribute__((visibility("default"))) int libnvme_import_tls_key(
1606 struct libnvme_global_ctx *ctx, const char *encoded_key,
1607 int *key_len, unsigned int *hmac, unsigned char **keyp)
1608{
1609 unsigned char version, _hmac;
1610 unsigned char *psk;
1611 size_t len;
1612 int ret;
1613
1614 ret = libnvme_import_tls_key_versioned(ctx, encoded_key, &version,
1615 &_hmac, &len, &psk);
1616 if (ret)
1617 return ret;
1618
1619 *hmac = _hmac;
1620 *key_len = len;
1621 *keyp = psk;
1622 return 0;
1623}
1624
1625#define NVMF_HOSTID_SIZE37 37
1626
1627#define NVMF_HOSTNQN_FILE"/usr/local/etc" "/nvme/hostnqn" SYSCONFDIR"/usr/local/etc" "/nvme/hostnqn"
1628#define NVMF_HOSTID_FILE"/usr/local/etc" "/nvme/hostid" SYSCONFDIR"/usr/local/etc" "/nvme/hostid"
1629
1630static int uuid_from_device_tree(char *system_uuid)
1631{
1632 __cleanup_fd__attribute__((cleanup(cleanup_fd))) int f = -1;
1633 ssize_t len;
1634
1635 f = open(libnvme_uuid_ibm_filename(), O_RDONLY00);
1636 if (f < 0)
1637 return -ENXIO6;
1638
1639 memset(system_uuid, 0, NVME_UUID_LEN_STRING37);
1640 len = read(f, system_uuid, NVME_UUID_LEN_STRING37 - 1);
1641 if (len < 0)
1642 return -ENXIO6;
1643
1644 return strlen(system_uuid) ? 0 : -ENXIO6;
1645}
1646
1647/*
1648 * See System Management BIOS (SMBIOS) Reference Specification
1649 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.2.0.pdf
1650 */
1651#define DMI_SYSTEM_INFORMATION1 1
1652
1653static bool_Bool is_dmi_uuid_valid(const char *buf, size_t len)
1654{
1655 int i;
1656
1657 /* UUID bytes are from byte 8 to 23 */
1658 if (len < 24)
1659 return false0;
1660
1661 /* Test it's a invalid UUID with all zeros */
1662 for (i = 8; i < 24; i++) {
1663 if (buf[i])
1664 break;
1665 }
1666 if (i == 24)
1667 return false0;
1668
1669 return true1;
1670}
1671
1672static int uuid_from_dmi_entries(char *system_uuid)
1673{
1674 __cleanup_dir__attribute__((cleanup(cleanup_dir))) DIR *d = NULL((void*)0);
1675 const char *entries_dir = libnvme_dmi_entries_dir();
1676 int f;
1677 struct dirent *de;
1678 char buf[512] = {0};
1679
1680 system_uuid[0] = '\0';
1681 d = opendir(entries_dir);
1682 if (!d)
1683 return -ENXIO6;
1684 while ((de = readdir(d))) {
1685 char filename[PATH_MAX4096];
1686 int len, type;
1687
1688 if (de->d_name[0] == '.')
1689 continue;
1690 sprintf(filename, "%s/%s/type", entries_dir, de->d_name);
1691 f = open(filename, O_RDONLY00);
1692 if (f < 0)
1693 continue;
1694 len = read(f, buf, 512);
1695 close(f);
1696 if (len <= 0)
1697 continue;
1698 if (sscanf(buf, "%d", &type) != 1)
1699 continue;
1700 if (type != DMI_SYSTEM_INFORMATION1)
1701 continue;
1702 sprintf(filename, "%s/%s/raw", entries_dir, de->d_name);
1703 f = open(filename, O_RDONLY00);
1704 if (f < 0)
1705 continue;
1706 len = read(f, buf, 512);
1707 close(f);
1708 if (len <= 0)
1709 continue;
1710
1711 if (!is_dmi_uuid_valid(buf, len))
1712 continue;
1713
1714 /* Sigh. https://en.wikipedia.org/wiki/Overengineering */
1715 /* DMTF SMBIOS 3.0 Section 7.2.1 System UUID */
1716 sprintf(system_uuid,
1717 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
1718 "%02x%02x%02x%02x%02x%02x",
1719 (uint8_t)buf[8 + 3], (uint8_t)buf[8 + 2],
1720 (uint8_t)buf[8 + 1], (uint8_t)buf[8 + 0],
1721 (uint8_t)buf[8 + 5], (uint8_t)buf[8 + 4],
1722 (uint8_t)buf[8 + 7], (uint8_t)buf[8 + 6],
1723 (uint8_t)buf[8 + 8], (uint8_t)buf[8 + 9],
1724 (uint8_t)buf[8 + 10], (uint8_t)buf[8 + 11],
1725 (uint8_t)buf[8 + 12], (uint8_t)buf[8 + 13],
1726 (uint8_t)buf[8 + 14], (uint8_t)buf[8 + 15]);
1727 break;
1728 }
1729 return strlen(system_uuid) ? 0 : -ENXIO6;
1730}
1731
1732#define PATH_DMI_PROD_UUID"/sys/class/dmi/id/product_uuid" "/sys/class/dmi/id/product_uuid"
1733
1734/**
1735 * uuid_from_product_uuid() - Get system UUID from product_uuid
1736 * @system_uuid: Where to save the system UUID.
1737 *
1738 * Return: 0 on success, -ENXIO otherwise.
1739 */
1740static int uuid_from_product_uuid(char *system_uuid)
1741{
1742 __cleanup_file__attribute__((cleanup(cleanup_file))) FILE *stream = NULL((void*)0);
1743
1744 stream = fopen(PATH_DMI_PROD_UUID"/sys/class/dmi/id/product_uuid", "re");
1745 if (!stream)
1746 return -ENXIO6;
1747
1748 system_uuid[0] = '\0';
1749
1750 /* The kernel is handling the byte swapping according DMTF
1751 * SMBIOS 3.0 Section 7.2.1 System UUID */
1752
1753 /*
1754 * Expect exactly:
1755 * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
1756 */
1757 if (!fgets(system_uuid, NVME_UUID_LEN_STRING37, stream))
1758 return -ENXIO6;
1759
1760 if (strlen(system_uuid) != NVME_UUID_LEN_STRING37 - 1)
1761 return -ENXIO6;
1762
1763 if (system_uuid[8] != '-' || system_uuid[13] != '-' ||
1764 system_uuid[18] != '-' || system_uuid[23] != '-')
1765 return -ENXIO6;
1766
1767 system_uuid[NVME_UUID_LEN_STRING37 - 1] = '\0';
1768
1769 return 0;
1770}
1771
1772/**
1773 * uuid_from_dmi() - read system UUID
1774 * @system_uuid: buffer for the UUID
1775 *
1776 * The system UUID can be read from two different locations:
1777 *
1778 * 1) /sys/class/dmi/id/product_uuid
1779 * 2) /sys/firmware/dmi/entries
1780 *
1781 * Note that the second location is not present on Debian-based systems.
1782 *
1783 * Return: 0 on success, negative errno otherwise.
1784 */
1785static int uuid_from_dmi(char *system_uuid)
1786{
1787 int ret = uuid_from_product_uuid(system_uuid);
1788 if (ret != 0)
1789 ret = uuid_from_dmi_entries(system_uuid);
1790 return ret;
1791}
1792
1793__libnvme_public__attribute__((visibility("default"))) char *libnvme_generate_hostid(void)
1794{
1795 int ret;
1796 char uuid_str[NVME_UUID_LEN_STRING37];
1797 unsigned char uuid[NVME_UUID_LEN16];
1798
1799 ret = uuid_from_dmi(uuid_str);
1800 if (ret < 0)
1801 ret = uuid_from_device_tree(uuid_str);
1802 if (ret < 0) {
1803 if (libnvme_random_uuid(uuid) < 0)
1804 memset(uuid, 0, NVME_UUID_LEN16);
1805 libnvme_uuid_to_string(uuid, uuid_str);
1806 }
1807
1808 return strdup(uuid_str);
1809}
1810
1811__libnvme_public__attribute__((visibility("default"))) char *libnvme_generate_hostnqn_from_hostid(char *hostid)
1812{
1813 char *hid = NULL((void*)0);
1814 char *hostnqn;
1815 int ret;
1816
1817 if (!hostid)
1818 hostid = hid = libnvme_generate_hostid();
1819
1820 ret = asprintf(&hostnqn, "nqn.2014-08.org.nvmexpress:uuid:%s", hostid);
1821 free(hid);
1822
1823 return (ret < 0) ? NULL((void*)0) : hostnqn;
1824}
1825
1826__libnvme_public__attribute__((visibility("default"))) char *libnvme_generate_hostnqn(void)
1827{
1828 return libnvme_generate_hostnqn_from_hostid(NULL((void*)0));
1829}
1830
1831static char *nvmf_read_file(const char *f, int len)
1832{
1833 char buf[len];
1834 __cleanup_fd__attribute__((cleanup(cleanup_fd))) int fd = -1;
1835 int ret;
1836
1837 fd = open(f, O_RDONLY00);
1838 if (fd < 0)
1839 return NULL((void*)0);
1840
1841 memset(buf, 0, len);
1842 ret = read(fd, buf, len - 1);
1843
1844 if (ret < 0 || !strlen(buf))
1845 return NULL((void*)0);
1846 return strndup(buf, strcspn(buf, "\n"));
1847}
1848
1849__libnvme_public__attribute__((visibility("default"))) char *libnvme_read_hostnqn(void)
1850{
1851 char *hostnqn = getenv("LIBNVME_HOSTNQN");
1852
1853 if (hostnqn) {
1854 if (!strcmp(hostnqn, ""))
1855 return NULL((void*)0);
1856 return strdup(hostnqn);
1857 }
1858
1859 return nvmf_read_file(NVMF_HOSTNQN_FILE"/usr/local/etc" "/nvme/hostnqn", NVMF_NQN_SIZE223);
1860}
1861
1862__libnvme_public__attribute__((visibility("default"))) char *libnvme_read_hostid(void)
1863{
1864 char *hostid = getenv("LIBNVME_HOSTID");
1865
1866 if (hostid) {
1867 if (!strcmp(hostid, ""))
1868 return NULL((void*)0);
1869 return strdup(hostid);
1870 }
1871
1872 return nvmf_read_file(NVMF_HOSTID_FILE"/usr/local/etc" "/nvme/hostid", NVMF_HOSTID_SIZE37);
1873}