Skip to content

Commit f7584fd

Browse files
committed
linux: add nvme_create_raw_secret
Move helper function to create the raw secret from the input string to the library. This allows to use a common function to consistently create the raw secret in nvme-cli and libnvme. Signed-off-by: Daniel Wagner <[email protected]>
1 parent 3f53169 commit f7584fd

4 files changed

Lines changed: 162 additions & 75 deletions

File tree

libnvme/src/libnvme.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ LIBNVME_3 {
66
nvme_close;
77
nvme_create_ctrl;
88
nvme_create_global_ctx;
9+
nvme_create_raw_secret;
910
nvme_ctrl_first_ns;
1011
nvme_ctrl_first_path;
1112
nvme_ctrl_get_config;

libnvme/src/nvme/linux.c

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
#include <sys/ioctl.h>
2121
#include <sys/param.h>
22+
#if HAVE_SYS_RANDOM
23+
#include <sys/random.h>
24+
#endif
2225
#include <sys/stat.h>
2326

2427
#ifndef _GNU_SOURCE
@@ -163,6 +166,14 @@ __public int nvme_gen_dhchap_key(struct nvme_global_ctx *ctx,
163166
return 0;
164167
}
165168

169+
__public int nvme_create_raw_secret(struct nvme_global_ctx *ctx,
170+
const char *secret, size_t key_len, unsigned char **raw_secret)
171+
{
172+
nvme_msg(ctx, LOG_ERR, "NVMe TLS 2.0 is not supported; "
173+
"recompile with OpenSSL support.\n");
174+
return -ENOTSUP;
175+
}
176+
166177
static int derive_retained_key(struct nvme_global_ctx *ctx,
167178
int hmac, const char *hostnqn, unsigned char *generated,
168179
unsigned char *retained, size_t key_len)
@@ -745,7 +756,130 @@ static int derive_psk_digest(struct nvme_global_ctx *ctx,
745756

746757
return strlen(digest);
747758
}
748-
#endif /* !CONFIG_OPENSSL */
759+
760+
static ssize_t getrandom_bytes(void *buf, size_t buflen)
761+
{
762+
ssize_t result;
763+
#if HAVE_SYS_RANDOM
764+
result = getrandom(buf, buflen, GRND_NONBLOCK);
765+
#else
766+
_cleanup_fd_ int fd = -1;
767+
768+
fd = open("/dev/urandom", O_RDONLY);
769+
if (fd < 0)
770+
return -errno;
771+
result = read(fd, buf, buflen);
772+
#endif
773+
if (result < 0)
774+
return -errno;
775+
return result;
776+
}
777+
778+
static ssize_t getswordfish(struct nvme_global_ctx *ctx,
779+
const char *seed, void *buf, size_t buflen)
780+
{
781+
unsigned char hash[EVP_MAX_MD_SIZE];
782+
EVP_MD_CTX *md_ctx;
783+
size_t copied = 0;
784+
785+
md_ctx = EVP_MD_CTX_new();
786+
if (!md_ctx)
787+
return -ENOMEM;
788+
789+
while (copied < buflen) {
790+
unsigned int counter = 0;
791+
unsigned int hash_len;
792+
size_t to_copy;
793+
794+
if (EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL) != 1)
795+
goto err;
796+
797+
EVP_DigestUpdate(md_ctx, seed, strlen(seed));
798+
EVP_DigestUpdate(md_ctx, &counter, sizeof(counter));
799+
800+
if (EVP_DigestFinal_ex(md_ctx, hash, &hash_len) != 1)
801+
goto err;
802+
803+
to_copy = buflen - copied;
804+
if (to_copy > hash_len)
805+
to_copy = hash_len;
806+
807+
memcpy((unsigned char *)buf + copied, hash, to_copy);
808+
copied += to_copy;
809+
counter++;
810+
}
811+
812+
EVP_MD_CTX_free(md_ctx);
813+
return buflen;
814+
815+
err:
816+
EVP_MD_CTX_free(md_ctx);
817+
return -EIO;
818+
}
819+
820+
__public int nvme_create_raw_secret(struct nvme_global_ctx *ctx,
821+
const char *secret, size_t key_len, unsigned char **raw_secret)
822+
{
823+
_cleanup_free_ unsigned char *buf = NULL;
824+
int secret_len = 0, i, err;
825+
unsigned int c;
826+
827+
if (key_len != 32 && key_len != 48 && key_len != 64) {
828+
nvme_msg(ctx, LOG_ERR, "Invalid key length %ld", key_len);
829+
return -EINVAL;
830+
}
831+
832+
buf = malloc(key_len);
833+
if (!buf)
834+
return -ENOMEM;
835+
836+
if (!secret) {
837+
err = getrandom_bytes(buf, key_len);
838+
if (err < 0)
839+
return err;
840+
841+
goto out;
842+
}
843+
844+
if (strlen(secret) < 4) {
845+
nvme_msg(ctx, LOG_ERR, "Input secret too short\n");
846+
return -EINVAL;
847+
}
848+
849+
if (!strncmp(secret, "pin:", 4)) {
850+
err = getswordfish(ctx, &secret[4], buf, key_len);
851+
if (err < 0)
852+
return err;
853+
854+
goto out;
855+
}
856+
857+
for (i = 0; i < strlen(secret); i += 2) {
858+
if (sscanf(&secret[i], "%02x", &c) != 1) {
859+
nvme_msg(ctx, LOG_ERR,
860+
"Invalid secret '%s'", secret);
861+
return -EINVAL;
862+
}
863+
if (i >= key_len * 2) {
864+
nvme_msg(ctx, LOG_ERR,
865+
"Skipping excess secret bytes\n");
866+
break;
867+
}
868+
buf[secret_len++] = (unsigned char)c;
869+
}
870+
if (secret_len != key_len) {
871+
nvme_msg(ctx, LOG_ERR,
872+
"Invalid key length (%d bytes)\n", secret_len);
873+
return -EINVAL;
874+
}
875+
876+
out:
877+
*raw_secret = buf;
878+
buf = NULL;
879+
return 0;
880+
}
881+
882+
#endif /* CONFIG_OPENSSL */
749883

750884
static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
751885
int version, int cipher, char *digest,

libnvme/src/nvme/linux.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,24 @@ int nvme_lookup_key(struct nvme_global_ctx *ctx, const char *type,
103103
*/
104104
int nvme_set_keyring(struct nvme_global_ctx *ctx, long keyring_id);
105105

106+
/**
107+
* nvme_create_raw_secret - Generate a raw secret buffer from input data
108+
* @ctx: struct nvme_global_ctx object
109+
* @secret: Input secret data
110+
* @key_len: The length of the raw_secret in bytes
111+
* @raw_secret: Return buffer with the generated raw secret
112+
*
113+
* Transforms the provided @secret into a raw secret buffer suitable for
114+
* use with NVMe key management operations.
115+
*
116+
* The generated raw secret can subsequently be passed to nvme_read_key()
117+
* or nvme_update_key().
118+
*
119+
* Return: 0 on success, or a negative error code on failure.
120+
*/
121+
int nvme_create_raw_secret(struct nvme_global_ctx *ctx,
122+
const char *secret, size_t key_len, unsigned char **raw_secret);
123+
106124
/**
107125
* nvme_read_key() - Read key raw data
108126
* @ctx: struct nvme_global_ctx object

nvme.c

Lines changed: 8 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@
4646
#include <sys/stat.h>
4747
#include <sys/types.h>
4848

49-
#if HAVE_SYS_RANDOM
50-
#include <sys/random.h>
51-
#endif
5249

5350
#include <libnvme.h>
5451

@@ -311,24 +308,6 @@ static OPT_VALS(feature_name) = {
311308
VAL_END()
312309
};
313310

314-
static ssize_t getrandom_bytes(void *buf, size_t buflen)
315-
{
316-
ssize_t result;
317-
#if HAVE_SYS_RANDOM
318-
result = getrandom(buf, buflen, GRND_NONBLOCK);
319-
#else
320-
_cleanup_fd_ int fd = -1;
321-
322-
fd = open("/dev/urandom", O_RDONLY);
323-
if (fd < 0)
324-
return -errno;
325-
result = read(fd, buf, buflen);
326-
#endif
327-
if (result < 0)
328-
return -errno;
329-
return result;
330-
}
331-
332311
static int check_arg_dev(int argc, char **argv)
333312
{
334313
if (optind >= argc) {
@@ -9554,7 +9533,6 @@ static int show_hostnqn_cmd(int argc, char **argv, struct command *acmd, struct
95549533
return 0;
95559534
}
95569535

9557-
95589536
static int gen_dhchap_key(int argc, char **argv, struct command *acmd, struct plugin *plugin)
95599537
{
95609538
const char *desc =
@@ -9641,32 +9619,9 @@ static int gen_dhchap_key(int argc, char **argv, struct command *acmd, struct pl
96419619
cfg.key_len = 32;
96429620
}
96439621

9644-
if (cfg.key_len != 32 && cfg.key_len != 48 && cfg.key_len != 64) {
9645-
nvme_show_error("Invalid key length %u", cfg.key_len);
9646-
return -EINVAL;
9647-
}
9648-
raw_secret = malloc(cfg.key_len);
9649-
if (!raw_secret)
9650-
return -ENOMEM;
9651-
if (!cfg.secret) {
9652-
if (getrandom_bytes(raw_secret, cfg.key_len) < 0)
9653-
return -errno;
9654-
} else {
9655-
int secret_len = 0, i;
9656-
unsigned int c;
9657-
9658-
for (i = 0; i < strlen(cfg.secret); i += 2) {
9659-
if (sscanf(&cfg.secret[i], "%02x", &c) != 1) {
9660-
nvme_show_error("Invalid secret '%s'", cfg.secret);
9661-
return -EINVAL;
9662-
}
9663-
raw_secret[secret_len++] = (unsigned char)c;
9664-
}
9665-
if (secret_len != cfg.key_len) {
9666-
nvme_show_error("Invalid key length (%d bytes)", secret_len);
9667-
return -EINVAL;
9668-
}
9669-
}
9622+
err = nvme_create_raw_secret(ctx, cfg.secret, cfg.key_len, &raw_secret);
9623+
if (err)
9624+
return err;
96709625

96719626
if (!cfg.nqn) {
96729627
cfg.nqn = hnqn = nvme_read_hostnqn();
@@ -9854,6 +9809,7 @@ static int append_keyfile(struct nvme_global_ctx *ctx, const char *keyring,
98549809
return err;
98559810
}
98569811

9812+
98579813
static int gen_tls_key(int argc, char **argv, struct command *acmd, struct plugin *plugin)
98589814
{
98599815
const char *desc = "Generate a TLS key in NVMe PSK Interchange format.";
@@ -9943,38 +9899,16 @@ static int gen_tls_key(int argc, char **argv, struct command *acmd, struct plugi
99439899
if (cfg.hmac == 2)
99449900
key_len = 48;
99459901

9902+
99469903
ctx = nvme_create_global_ctx(stderr, log_level);
99479904
if (!ctx) {
99489905
nvme_show_error("Failed to create global context");
99499906
return -ENOMEM;
99509907
}
99519908

9952-
raw_secret = malloc(key_len + 4);
9953-
if (!raw_secret)
9954-
return -ENOMEM;
9955-
if (!cfg.secret) {
9956-
if (getrandom_bytes(raw_secret, key_len) < 0)
9957-
return -errno;
9958-
} else {
9959-
int secret_len = 0, i;
9960-
unsigned int c;
9961-
9962-
for (i = 0; i < strlen(cfg.secret); i += 2) {
9963-
if (sscanf(&cfg.secret[i], "%02x", &c) != 1) {
9964-
nvme_show_error("Invalid secret '%s'", cfg.secret);
9965-
return -EINVAL;
9966-
}
9967-
if (i >= key_len * 2) {
9968-
fprintf(stderr, "Skipping excess secret bytes\n");
9969-
break;
9970-
}
9971-
raw_secret[secret_len++] = (unsigned char)c;
9972-
}
9973-
if (secret_len != key_len) {
9974-
nvme_show_error("Invalid key length (%d bytes)", secret_len);
9975-
return -EINVAL;
9976-
}
9977-
}
9909+
err = nvme_create_raw_secret(ctx, cfg.secret, key_len, &raw_secret);
9910+
if (err)
9911+
return err;
99789912

99799913
err = nvme_export_tls_key(ctx, raw_secret, key_len, &encoded_key);
99809914
if (err) {

0 commit comments

Comments
 (0)