[PATCH nvme-cli 2/3] Add 'check-dhchap-key' function
From: Hannes Reinecke <hare@suse.de>
Date: 2021-11-12 13:16:33
Subsystem:
documentation, the rest · Maintainers:
Jonathan Corbet, Linus Torvalds
Add a function to validate a given DH-HMAC-CHAP key in transport encoding for NVMe in-band authentication. Signed-off-by: Hannes Reinecke <hare@suse.de> --- Documentation/nvme-check-dhchap-key.txt | 31 ++++++++ nvme-builtin.h | 1 + nvme.c | 98 +++++++++++++++++++++++++ util/base64.c | 43 +++++++++++ util/base64.h | 1 + 5 files changed, 174 insertions(+) create mode 100644 Documentation/nvme-check-dhchap-key.txt
diff --git a/Documentation/nvme-check-dhchap-key.txt b/Documentation/nvme-check-dhchap-key.txt
new file mode 100644
index 0000000..75008c7
--- /dev/null
+++ b/Documentation/nvme-check-dhchap-key.txt@@ -0,0 +1,31 @@ +nvme-check-dhchap-key(1) +=================== + +NAME +---- +nvme-check-dhchap-key - Check a generated host DH-HMAC-CHAP key + +SYNOPSIS +-------- +[verse] +'nvme check-dhchap-key' [--key=<key> ] + +DESCRIPTION +----------- +Checks if the key is a valid DH-HMAC-CHAP host key of the form: +DHHC-1:00:ia6zGodOr4SEG0Zzaw398rpY0wqipUWj4jWjUh4HWUz6aQ2n: +and prints it to stdout. + +OPTIONS +------- +-k <key>:: +--key=<key>:: + Key to be checked. + +EXAMPLES +-------- +No Examples + +NVME +---- +Part of the nvme-user suite
diff --git a/nvme-builtin.h b/nvme-builtin.h
index a256f05..c2740bb 100644
--- a/nvme-builtin.h
+++ b/nvme-builtin.h@@ -82,6 +82,7 @@ COMMAND_LIST( ENTRY("gen-hostnqn", "Generate NVMeoF host NQN", gen_hostnqn_cmd) ENTRY("show-hostnqn", "Show NVMeoF host NQN", show_hostnqn_cmd) ENTRY("gen-dhchap-key", "Generate NVMeoF DH-HMAC-CHAP host key", gen_dhchap_key) + ENTRY("check-dhchap-key", "Validate NVMeoF DH-HMAC-CHAP host key", check_dhchap_key) ENTRY("dir-receive", "Submit a Directive Receive command, return results", dir_receive) ENTRY("dir-send", "Submit a Directive Send command, return results", dir_send) ENTRY("virt-mgmt", "Manage Flexible Resources between Primary and Secondary Controller ", virtual_mgmt)
diff --git a/nvme.c b/nvme.c
index 4ad91da..4f8ba8c 100644
--- a/nvme.c
+++ b/nvme.c@@ -6093,6 +6093,104 @@ static int gen_dhchap_key(int argc, char **argv, struct command *command, struct return 0; } +static int check_dhchap_key(int argc, char **argv, struct command *command, struct plugin *plugin) +{ + const char *desc = "Check a DH-HMAC-CHAP host key for usability "\ + "for NVMe In-Band Authentication."; + const char *key = "DH-HMAC-CHAP key (in hexadecimal characters) "\ + "to be validated."; + + unsigned char decoded_key[128]; + unsigned int decoded_len; + u_int32_t crc = crc32(0L, NULL, 0); + u_int32_t key_crc; + int err = 0, hmac; + struct config { + char *key; + }; + + struct config cfg = { + .key = NULL, + }; + + OPT_ARGS(opts) = { + OPT_STR("key", 'k', &cfg.key, key), + OPT_END() + }; + + err = argconfig_parse(argc, argv, desc, opts); + if (err) + return err; + + if (!cfg.key) { + fprintf(stderr, "Key not specified\n"); + return -EINVAL; + } + + if (sscanf(cfg.key, "DHHC-1:%02x:*s", &hmac) != 1) { + fprintf(stderr, "Invalid key header '%s'\n", cfg.key); + return -EINVAL; + } + switch (hmac) { + case 0: + break; + case 1: + if (strlen(cfg.key) != 59) { + fprintf(stderr, "Invalid key length for SHA(256)\n"); + return -EINVAL; + } + break; + case 2: + if (strlen(cfg.key) != 83) { + fprintf(stderr, "Invalid key length for SHA(384)\n"); + return -EINVAL; + } + break; + case 3: + if (strlen(cfg.key) != 103) { + fprintf(stderr, "Invalid key length for SHA(512)\n"); + return -EINVAL; + } + break; + default: + fprintf(stderr, "Invalid HMAC identifier %d\n", hmac); + return -EINVAL; + break; + } + + err = base64_decode(cfg.key + 10, strlen(cfg.key) - 11, + decoded_key); + if (err < 0) { + fprintf(stderr, "Base64 decoding failed, error %d\n", + err); + return err; + } + decoded_len = err; + if (decoded_len < 32) { + fprintf(stderr, "Base64 decoding failed (%s, size %u)\n", + cfg.key + 10, decoded_len); + return -EINVAL; + } + decoded_len -= 4; + if (decoded_len != 32 && decoded_len != 48 && decoded_len != 64) { + fprintf(stderr, "Invalid key length %d\n", decoded_len); + return -EINVAL; + } + crc = crc32(crc, decoded_key, decoded_len); + key_crc = ((u_int32_t)decoded_key[decoded_len]) | + ((u_int32_t)decoded_key[decoded_len + 1] << 8) | + ((u_int32_t)decoded_key[decoded_len + 2] << 16) | + ((u_int32_t)decoded_key[decoded_len + 3] << 24); + if (key_crc != crc) { + fprintf(stderr, "CRC mismatch (key %08x, crc %08x)\n", + key_crc, crc); + return -EINVAL; + } + printf("Key is valid (HMAC %d, length %d, CRC %08x)\n", + hmac, decoded_len, crc); + return 0; +} + static int discover_cmd(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Send Get Log Page request to Discovery Controller.";
diff --git a/util/base64.c b/util/base64.c
index d9b8f01..e386c11 100644
--- a/util/base64.c
+++ b/util/base64.c@@ -20,6 +20,8 @@ */ #include <stdlib.h> +#include <string.h> +#include <errno.h> static const char base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -60,3 +62,44 @@ int base64_encode(const unsigned char *src, int srclen, char *dst) return cp - dst; } + +/** + * base64_decode() - base64-decode some bytes + * @src: the base64-encoded string to decode + * @len: number of bytes to decode + * @dst: (output) the decoded bytes. + * + * Decodes the base64-encoded bytes @src according to RFC 4648. + * + * Return: number of decoded bytes + */ +int base64_decode(const char *src, int srclen, unsigned char *dst) +{ + u_int32_t ac = 0; + int i, bits = 0; + unsigned char *bp = dst; + + for (i = 0; i < srclen; i++) { + const char *p = strchr(base64_table, src[i]); + + if (src[i] == '=') { + ac = (ac << 6); + bits += 6; + if (bits >= 8) + bits -= 8; + continue; + } + if (p == NULL || src[i] == 0) + return -EINVAL; + ac = (ac << 6) | (p - base64_table); + bits += 6; + if (bits >= 8) { + bits -= 8; + *bp++ = (unsigned char)(ac >> bits); + } + } + if (ac && ((1 << bits) - 1)) + return -EAGAIN; + + return bp - dst; +}
diff --git a/util/base64.h b/util/base64.h
index 374f5e6..609a877 100644
--- a/util/base64.h
+++ b/util/base64.h@@ -2,5 +2,6 @@ #define _BASE64_H int base64_encode(const unsigned char *src, int len, char *dst); +int base64_decode(const char *src, int len, unsigned char *dst); #endif /* _BASE64_H */
--
2.31.1