diff --git a/Documentation/nvme-tls-key.txt b/Documentation/nvme-tls-key.txt new file mode 100644 index 0000000000..15942a409f --- /dev/null +++ b/Documentation/nvme-tls-key.txt @@ -0,0 +1,69 @@ +nvme-tls-key(1) +====================== + +NAME +---- +nvme-tls-key - Manage NVMe TLS PSKs + +SYNOPSIS +-------- +[verse] +'nvme tls-key' [--keyring= | -k ] + [--keytype= | -t ] + [--keyfile= | -f ] + [--import | -i] [--export | -e] + [--verbose | -v] + +DESCRIPTION +----------- +Import or export NVMe TLS pre-shared keys (PSKs) from the +system keystore. When the '--export' option is given, all +NVMe TLS PSKs are exported in the form + + + +where '' is the key description from the +exported key and '' is the key data in PSK interchange +format 'NVMeTLSkey-1:01::'. +Each key is exported in a single line. +When the '--import' option is given key data is read in the +same format and imported into the kernel keystore. + +OPTIONS +------- +-k :: +--keyring=:: + Name of the keyring into which the 'retained' TLS key should be + stored. Default is '.nvme'. + +-t :: +--keytype=:: + Type of the key for resulting TLS key. + Default is 'psk'. + +-k :: +--keyfile=:: + File to read the keys from or write the keys to instead of + stdin / stdout. + +-i:: +--import:: + Read the key data from the file specified by '--keyfile' + or stdin if not present. + +-e:: +--export:: + Write the key data to the file specified by '--keyfile' + or stdou if not present. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +No Examples + +NVME +---- +Part of the nvme-user suite diff --git a/nvme-builtin.h b/nvme-builtin.h index 2d2bead38b..2d1d8e0347 100644 --- a/nvme-builtin.h +++ b/nvme-builtin.h @@ -101,6 +101,7 @@ COMMAND_LIST( ENTRY("check-dhchap-key", "Validate NVMeoF DH-HMAC-CHAP host key", check_dhchap_key) ENTRY("gen-tls-key", "Generate NVMeoF TLS PSK", gen_tls_key) ENTRY("check-tls-key", "Validate NVMeoF TLS PSK", check_tls_key) + ENTRY("tls-key", "Manipulate NVMeoF TLS PSK", tls_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 072ab78eb5..c328749ae2 100644 --- a/nvme.c +++ b/nvme.c @@ -8753,6 +8753,124 @@ static int check_tls_key(int argc, char **argv, struct command *command, struct return 0; } +static void __scan_tls_key(long keyring_id, long key_id, + char *desc, int desc_len, void *data) +{ + FILE *fd = data; + _cleanup_free_ const unsigned char *key_data = NULL; + _cleanup_free_ char *encoded_key = NULL; + int key_len; + + key_data = nvme_read_key(keyring_id, key_id, &key_len); + if (!key_data) + return; + encoded_key = nvme_export_tls_key(key_data, key_len); + if (!encoded_key) + return; + fprintf(fd, "%s %s\n", desc, encoded_key); +} + +static int tls_key(int argc, char **argv, struct command *command, struct plugin *plugin) +{ + const char *desc = "Manipulation of TLS keys.\n"; + const char *keyring = "Keyring for the retained key."; + const char *keytype = "Key type of the retained key."; + const char *keyfile = "File for list of keys."; + const char *import = "Import all keys into the keyring."; + const char *export = "Export all keys from the keyring."; + + FILE *fd; + int err = 0; + + struct config { + char *keyring; + char *keytype; + char *keyfile; + bool import; + bool export; + }; + + struct config cfg = { + .keyring = ".nvme", + .keytype = "psk", + .keyfile = NULL, + .import = false, + .export = false, + }; + + NVME_ARGS(opts, + OPT_STR("keyring", 'k', &cfg.keyring, keyring), + OPT_STR("keytype", 't', &cfg.keytype, keytype), + OPT_STR("keyfile", 'f', &cfg.keyfile, keyfile), + OPT_FLAG("import", 'i', &cfg.import, import), + OPT_FLAG("export", 'e', &cfg.export, export)); + + err = argconfig_parse(argc, argv, desc, opts); + if (err) + return err; + + if (cfg.keyfile) { + fd = fopen(cfg.keyfile, "r"); + if (!fd) { + nvme_show_error("Cannot open keyfile %s, error %d\n", + cfg.keyfile, errno); + return -errno; + } + } else + fd = stdin; + + if (cfg.export && cfg.import) { + nvme_show_error("Cannot specify both --import and --export"); + err = -EINVAL; + } else if (cfg.export) { + nvme_scan_tls_keys(cfg.keyring, __scan_tls_key, fd); + } else if (cfg.import) { + long keyring_id; + char tls_str[512]; + char *tls_key; + unsigned char *psk; + unsigned int hmac; + int linenum = -1, key_len; + + keyring_id = nvme_lookup_keyring(cfg.keyring); + if (!keyring_id) { + nvme_show_error("Invalid keyring '%s'", cfg.keyring); + err = -ENOKEY; + goto out; + } + + while (fgets(tls_str, 512, fd)) { + linenum++; + tls_key = strrchr(tls_str, ' '); + if (!tls_key) { + nvme_show_error("Parse error in line %d", + linenum); + continue; + } + *tls_key = '\0'; + tls_key++; + psk = nvme_import_tls_key(tls_key, &key_len, &hmac); + if (!psk) { + nvme_show_error("Failed to import key in line %d", + linenum); + continue; + } + nvme_update_key(keyring_id, "psk", tls_str, + psk, key_len); + free(psk); + } + } else { + nvme_show_error("Must specify either --import or --export"); + err = -EINVAL; + } + +out: + if (cfg.keyfile) + fclose(fd); + + return err; +} + static int show_topology_cmd(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Show the topology\n";