Skip to content

Commit f8c81dd

Browse files
authored
Merge pull request #158 from igaw/nvme_gen_dhchap_key
linux: Add support to generate DH-HMAC-CHAP keys
2 parents 042f5ea + 436898e commit f8c81dd

7 files changed

Lines changed: 271 additions & 0 deletions

File tree

meson.build

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,21 @@ conf.set('CONFIG_LIBUUID', libuuid_dep.found(), description: 'Is libuuid require
4343
json_c_dep = dependency('json-c', version: '>=0.13', fallback : ['json-c', 'json_c_dep'])
4444
conf.set('CONFIG_JSONC', json_c_dep.found(), description: 'Is json-c required?')
4545

46+
# Check for OpenSSL availability
47+
openssl_dep = dependency('openssl',
48+
required: get_option('openssl'),
49+
fallback : ['openssl', 'openssl_dep'])
50+
if openssl_dep.found()
51+
conf.set('CONFIG_OPENSSL', true, description: 'Is OpenSSL available?')
52+
conf.set('CONFIG_OPENSSL_1',
53+
openssl_dep.version().version_compare('<2.0.0') and
54+
openssl_dep.version().version_compare('>=1.1.0'),
55+
description: 'OpenSSL version 1.x')
56+
conf.set('CONFIG_OPENSSL_3',
57+
openssl_dep.version().version_compare('>=3.0.0'),
58+
description: 'OpenSSL version 3.x')
59+
endif
60+
4661
# local (cross-compilable) implementations of ccan configure steps
4762
conf.set10(
4863
'HAVE_BUILTIN_TYPES_COMPATIBLE_P',

meson_options.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ option('pkgconfiglibdir', type : 'string', value : '', description : 'directory
44

55
option('man', type : 'boolean', value : false, description : 'build and install man pages (requires sphinx-build)')
66
option('python', type : 'combo', choices : ['auto', 'true', 'false'], description : 'Generate libnvme python bindings')
7+
option('openssl', type : 'feature', value: 'auto', description : 'OpenSSL support')

src/libnvme.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ LIBNVME_1_0 {
6868
nvme_fw_commit;
6969
nvme_fw_download;
7070
nvme_fw_download_seq;
71+
nvme_gen_dhchap_key;
7172
nvme_get_ana_log_len;
7273
nvme_get_attr;
7374
nvme_get_ctrl_attr;

src/meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ endif
2323
deps = [
2424
libuuid_dep,
2525
json_c_dep,
26+
openssl_dep,
2627
]
2728

2829
source_dir = meson.current_source_dir()
@@ -51,6 +52,7 @@ pkg.generate(libnvme,
5152

5253
libnvme_dep = declare_dependency(
5354
include_directories: incdir,
55+
dependencies: deps,
5456
link_with: libnvme,
5557
)
5658

src/nvme/linux.c

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@
1717
#include <fcntl.h>
1818
#include <unistd.h>
1919

20+
#ifdef CONFIG_OPENSSL
21+
#include <openssl/engine.h>
22+
#include <openssl/evp.h>
23+
#include <openssl/hmac.h>
24+
25+
#ifdef CONFIG_OPENSSL_3
26+
#include <openssl/core_names.h>
27+
#include <openssl/params.h>
28+
#endif
29+
#endif
30+
2031
#include <ccan/endian/endian.h>
2132

2233
#include "linux.h"
@@ -386,3 +397,201 @@ char *nvme_get_path_attr(nvme_path_t p, const char *attr)
386397
{
387398
return nvme_get_attr(nvme_path_get_sysfs_dir(p), attr);
388399
}
400+
401+
#ifndef CONFIG_OPENSSL
402+
int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
403+
unsigned int key_len, unsigned char *secret,
404+
unsigned char *key)
405+
{
406+
if (hmac != NVME_HMAC_ALG_NONE) {
407+
nvme_msg(LOG_ERR, "HMAC transformation not supported; " \
408+
"recompile with OpenSSL support.\n");
409+
errno = -EINVAL;
410+
return -1;
411+
}
412+
413+
memcpy(key, secret, key_len);
414+
return 0;
415+
}
416+
#endif /* !CONFIG_OPENSSL */
417+
418+
#ifdef CONFIG_OPENSSL_1
419+
int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
420+
unsigned int key_len, unsigned char *secret,
421+
unsigned char *key)
422+
{
423+
const char hmac_seed[] = "NVMe-over-Fabrics";
424+
HMAC_CTX *hmac_ctx;
425+
const EVP_MD *md;
426+
int err = -1;
427+
428+
ENGINE_load_builtin_engines();
429+
ENGINE_register_all_complete();
430+
431+
hmac_ctx = HMAC_CTX_new();
432+
if (!hmac_ctx) {
433+
nvme_msg(LOG_ERR, "OpenSSL: could not create HMAC context\n");
434+
errno = ENOENT;
435+
return err;
436+
}
437+
438+
switch (hmac) {
439+
case NVME_HMAC_ALG_NONE:
440+
memcpy(key, secret, key_len);
441+
err = 0;
442+
goto out;
443+
case NVME_HMAC_ALG_SHA2_256:
444+
md = EVP_sha256();
445+
break;
446+
case NVME_HMAC_ALG_SHA2_384:
447+
md = EVP_sha384();
448+
break;
449+
case NVME_HMAC_ALG_SHA2_512:
450+
md = EVP_sha512();
451+
break;
452+
default:
453+
errno = EINVAL;
454+
goto out;
455+
}
456+
457+
if (!md) {
458+
nvme_msg(LOG_ERR, "OpenSSL: could not fetch hash function\n");
459+
errno = ENOENT;
460+
goto out;
461+
}
462+
463+
if (!HMAC_Init_ex(hmac_ctx, secret, key_len, md, NULL)) {
464+
nvme_msg(LOG_ERR, "OpenSSL: initializing HMAC context failed\n");
465+
errno = ENOENT;
466+
goto out;
467+
}
468+
469+
if (!HMAC_Update(hmac_ctx, (unsigned char *)hostnqn,
470+
strlen(hostnqn))) {
471+
nvme_msg(LOG_ERR, "OpenSSL: HMAC for hostnqn failed\n");
472+
errno = ENOENT;
473+
goto out;
474+
}
475+
476+
if (!HMAC_Update(hmac_ctx, (unsigned char *)hmac_seed,
477+
strlen(hmac_seed))) {
478+
nvme_msg(LOG_ERR, "OpenSSL: HMAC for seed failed\n");
479+
errno = ENOENT;
480+
goto out;
481+
}
482+
483+
if (!HMAC_Final(hmac_ctx, key, &key_len)) {
484+
nvme_msg(LOG_ERR, "OpenSSL: finializing MAC failed\n");
485+
errno = ENOENT;
486+
goto out;
487+
}
488+
489+
err = 0;
490+
491+
out:
492+
HMAC_CTX_free(hmac_ctx);
493+
return err;
494+
}
495+
#endif /* !CONFIG_OPENSSL_1 */
496+
497+
#ifdef CONFIG_OPENSSL_3
498+
int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
499+
unsigned int key_len, unsigned char *secret,
500+
unsigned char *key)
501+
{
502+
const char hmac_seed[] = "NVMe-over-Fabrics";
503+
OSSL_PARAM params[2], *p = params;
504+
OSSL_LIB_CTX *lib_ctx;
505+
EVP_MAC_CTX *mac_ctx = NULL;
506+
EVP_MAC *mac = NULL;
507+
char *progq = NULL;
508+
char *digest;
509+
size_t len;
510+
int err = -1;
511+
512+
lib_ctx = OSSL_LIB_CTX_new();
513+
if (!lib_ctx) {
514+
nvme_msg(LOG_ERR, "OpenSSL: Library initializing failed\n");
515+
errno = ENOENT;
516+
return err;
517+
}
518+
519+
mac = EVP_MAC_fetch(lib_ctx, OSSL_MAC_NAME_HMAC, progq);
520+
if (!mac) {
521+
nvme_msg(LOG_ERR, "OpenSSL: could not fetch HMAC algorithm\n");
522+
errno = EINVAL;
523+
goto out;
524+
}
525+
526+
mac_ctx = EVP_MAC_CTX_new(mac);
527+
if (!mac_ctx) {
528+
nvme_msg(LOG_ERR, "OpenSSL: could not create HMAC context\n");
529+
errno = ENOENT;
530+
goto out;
531+
}
532+
533+
switch (hmac) {
534+
case NVME_HMAC_ALG_NONE:
535+
memcpy(key, secret, key_len);
536+
err = 0;
537+
goto out;
538+
case NVME_HMAC_ALG_SHA2_256:
539+
digest = OSSL_DIGEST_NAME_SHA2_256;
540+
break;
541+
case NVME_HMAC_ALG_SHA2_384:
542+
digest = OSSL_DIGEST_NAME_SHA2_384;
543+
break;
544+
case NVME_HMAC_ALG_SHA2_512:
545+
digest = OSSL_DIGEST_NAME_SHA2_512;
546+
break;
547+
default:
548+
errno = EINVAL;
549+
goto out;
550+
}
551+
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
552+
digest,
553+
0);
554+
*p = OSSL_PARAM_construct_end();
555+
556+
if (!EVP_MAC_init(mac_ctx, secret, key_len, params)) {
557+
nvme_msg(LOG_ERR, "OpenSSL: could not initialize HMAC context\n");
558+
errno = EINVAL;
559+
goto out;
560+
}
561+
562+
if (!EVP_MAC_update(mac_ctx, (unsigned char *)hostnqn,
563+
strlen(hostnqn))) {
564+
nvme_msg(LOG_ERR, "OpenSSL: HMAC for hostnqn failed\n");
565+
errno = ENOENT;
566+
goto out;
567+
}
568+
569+
if (!EVP_MAC_update(mac_ctx, (unsigned char *)hmac_seed,
570+
strlen(hmac_seed))) {
571+
nvme_msg(LOG_ERR, "OpenSSL: HMAC for seed failed\n");
572+
errno = ENOENT;
573+
goto out;
574+
}
575+
576+
if (!EVP_MAC_final(mac_ctx, key, &len, key_len)) {
577+
nvme_msg(LOG_ERR, "OpenSSL: finializing MAC failed\n");
578+
errno = ENOENT;
579+
goto out;
580+
}
581+
582+
if (len != key_len) {
583+
nvme_msg(LOG_ERR, "OpenSSL: generated HMAC has an unexpected lenght\n");
584+
errno = EINVAL;
585+
goto out;
586+
}
587+
588+
err = 0;
589+
590+
out:
591+
EVP_MAC_CTX_free(mac_ctx);
592+
EVP_MAC_free(mac);
593+
OSSL_LIB_CTX_free(lib_ctx);
594+
595+
return err;
596+
}
597+
#endif /* !CONFIG_OPENSSL_3 */

src/nvme/linux.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,4 +153,33 @@ int nvme_namespace_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrl
153153
*/
154154
int nvme_open(const char *name);
155155

156+
/**
157+
* enum nvme_hmac_alg - HMAC algorithm
158+
* NVME_HMAC_ALG_NONE: No HMAC algorithm
159+
* NVME_HMAC_ALG_SHA2_256: SHA2-256
160+
* NVME_HMAC_ALG_SHA2_384: SHA2-384
161+
* NVME_HMAC_ALG_SHA2_512: SHA2-512
162+
*/
163+
enum nvme_hmac_alg {
164+
NVME_HMAC_ALG_NONE = 0,
165+
NVME_HMAC_ALG_SHA2_256 = 1,
166+
NVME_HMAC_ALG_SHA2_384 = 2,
167+
NVME_HMAC_ALG_SHA2_512 = 3,
168+
};
169+
170+
/**
171+
* nvme_gen_dhchap_key() - DH-HMAC-CHAP key generation
172+
* @hostnqn: Host NVMe Qualified Name
173+
* @hmac: HMAC algorithm
174+
* @key_len: Output key lenght
175+
* @secret: Secret to used for digest
176+
* @key: Generated DH-HMAC-CHAP key
177+
*
178+
* Return: If key generation was successful the function returns 0 or
179+
* -1 with errno set otherwise.
180+
*/
181+
int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
182+
unsigned int key_len, unsigned char *secret,
183+
unsigned char *key);
184+
156185
#endif /* _LIBNVME_LINUX_H */

subprojects/openssl.wrap

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[wrap-file]
2+
directory = openssl-1.1.1l
3+
source_url = https://www.openssl.org/source/openssl-1.1.1l.tar.gz
4+
source_filename = openssl-1.1.1l.tar.gz
5+
source_hash = 0b7a3e5e59c34827fe0c3a74b7ec8baef302b98fa80088d7f9153aa16fa76bd1
6+
patch_filename = openssl_1.1.1l-2_patch.zip
7+
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_1.1.1l-2/get_patch
8+
patch_hash = 852521fb016fa2deee8ebf9ffeeee0292c6de86a03c775cf72ac04e86f9f177e
9+
10+
[provide]
11+
libcrypto = libcrypto_dep
12+
libssl = libssl_dep
13+
openssl = openssl_dep
14+

0 commit comments

Comments
 (0)