]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
nvme-fabrics: parse options 'keyring' and 'tls_key'
authorHannes Reinecke <hare@suse.de>
Thu, 24 Aug 2023 14:39:18 +0000 (16:39 +0200)
committerKeith Busch <kbusch@kernel.org>
Wed, 11 Oct 2023 17:29:58 +0000 (10:29 -0700)
Parse the fabrics options 'keyring' and 'tls_key' and store the
referenced keys in the options structure.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Keith Busch <kbusch@kernel.org>
drivers/nvme/host/fabrics.c
drivers/nvme/host/fabrics.h
drivers/nvme/host/tcp.c

index ddad482c353714ea073ed3e8188fa10cf431243c..4673ead69c5f9d9b9e51729ece745b56363989de 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/seq_file.h>
 #include "nvme.h"
 #include "fabrics.h"
+#include <linux/nvme-keyring.h>
 
 static LIST_HEAD(nvmf_transports);
 static DECLARE_RWSEM(nvmf_transports_rwsem);
@@ -622,6 +623,23 @@ static struct nvmf_transport_ops *nvmf_lookup_transport(
        return NULL;
 }
 
+static struct key *nvmf_parse_key(int key_id)
+{
+       struct key *key;
+
+       if (!IS_ENABLED(CONFIG_NVME_TCP_TLS)) {
+               pr_err("TLS is not supported\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       key = key_lookup(key_id);
+       if (!IS_ERR(key))
+               pr_err("key id %08x not found\n", key_id);
+       else
+               pr_debug("Using key id %08x\n", key_id);
+       return key;
+}
+
 static const match_table_t opt_tokens = {
        { NVMF_OPT_TRANSPORT,           "transport=%s"          },
        { NVMF_OPT_TRADDR,              "traddr=%s"             },
@@ -643,6 +661,10 @@ static const match_table_t opt_tokens = {
        { NVMF_OPT_NR_WRITE_QUEUES,     "nr_write_queues=%d"    },
        { NVMF_OPT_NR_POLL_QUEUES,      "nr_poll_queues=%d"     },
        { NVMF_OPT_TOS,                 "tos=%d"                },
+#ifdef CONFIG_NVME_TCP_TLS
+       { NVMF_OPT_KEYRING,             "keyring=%d"            },
+       { NVMF_OPT_TLS_KEY,             "tls_key=%d"            },
+#endif
        { NVMF_OPT_FAIL_FAST_TMO,       "fast_io_fail_tmo=%d"   },
        { NVMF_OPT_DISCOVERY,           "discovery"             },
        { NVMF_OPT_DHCHAP_SECRET,       "dhchap_secret=%s"      },
@@ -660,9 +682,10 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
        char *options, *o, *p;
        int token, ret = 0;
        size_t nqnlen  = 0;
-       int ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO;
+       int ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO, key_id;
        uuid_t hostid;
        char hostnqn[NVMF_NQN_SIZE];
+       struct key *key;
 
        /* Set defaults */
        opts->queue_size = NVMF_DEF_QUEUE_SIZE;
@@ -675,6 +698,8 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
        opts->data_digest = false;
        opts->tos = -1; /* < 0 == use transport default */
        opts->tls = false;
+       opts->tls_key = NULL;
+       opts->keyring = NULL;
 
        options = o = kstrdup(buf, GFP_KERNEL);
        if (!options)
@@ -928,6 +953,32 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
                        }
                        opts->tos = token;
                        break;
+               case NVMF_OPT_KEYRING:
+                       if (match_int(args, &key_id) || key_id <= 0) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       key = nvmf_parse_key(key_id);
+                       if (IS_ERR(key)) {
+                               ret = PTR_ERR(key);
+                               goto out;
+                       }
+                       key_put(opts->keyring);
+                       opts->keyring = key;
+                       break;
+               case NVMF_OPT_TLS_KEY:
+                       if (match_int(args, &key_id) || key_id <= 0) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       key = nvmf_parse_key(key_id);
+                       if (IS_ERR(key)) {
+                               ret = PTR_ERR(key);
+                               goto out;
+                       }
+                       key_put(opts->tls_key);
+                       opts->tls_key = key;
+                       break;
                case NVMF_OPT_DISCOVERY:
                        opts->discovery_nqn = true;
                        break;
@@ -1168,6 +1219,8 @@ static int nvmf_check_allowed_opts(struct nvmf_ctrl_options *opts,
 void nvmf_free_options(struct nvmf_ctrl_options *opts)
 {
        nvmf_host_put(opts->host);
+       key_put(opts->keyring);
+       key_put(opts->tls_key);
        kfree(opts->transport);
        kfree(opts->traddr);
        kfree(opts->trsvcid);
index dac17c3fee26ab6de016dc4b562f20873395a0cf..fbaee5a7be196c08483a41b6673f00e5032bec10 100644 (file)
@@ -71,6 +71,8 @@ enum {
        NVMF_OPT_DHCHAP_SECRET  = 1 << 23,
        NVMF_OPT_DHCHAP_CTRL_SECRET = 1 << 24,
        NVMF_OPT_TLS            = 1 << 25,
+       NVMF_OPT_KEYRING        = 1 << 26,
+       NVMF_OPT_TLS_KEY        = 1 << 27,
 };
 
 /**
@@ -103,6 +105,8 @@ enum {
  * @dhchap_secret: DH-HMAC-CHAP secret
  * @dhchap_ctrl_secret: DH-HMAC-CHAP controller secret for bi-directional
  *              authentication
+ * @keyring:    Keyring to use for key lookups
+ * @tls_key:    TLS key for encrypted connections (TCP)
  * @tls:        Start TLS encrypted connections (TCP)
  * @disable_sqflow: disable controller sq flow control
  * @hdr_digest: generate/verify header digest (TCP)
@@ -130,6 +134,8 @@ struct nvmf_ctrl_options {
        struct nvmf_host        *host;
        char                    *dhchap_secret;
        char                    *dhchap_ctrl_secret;
+       struct key              *keyring;
+       struct key              *tls_key;
        bool                    tls;
        bool                    disable_sqflow;
        bool                    hdr_digest;
index 4656ad20e157ee1e38fc3aab937f93a8f4bd4edd..4714a902f4caa8ac30a9f3091b4011fd5e7df5e7 100644 (file)
@@ -1595,6 +1595,8 @@ static int nvme_tcp_start_tls(struct nvme_ctrl *nctrl,
        args.ta_data = queue;
        args.ta_my_peerids[0] = pskid;
        args.ta_num_peerids = 1;
+       if (nctrl->opts->keyring)
+               keyring = key_serial(nctrl->opts->keyring);
        args.ta_keyring = keyring;
        args.ta_timeout_ms = tls_handshake_timeout * 1000;
        queue->tls_err = -EOPNOTSUPP;
@@ -1914,9 +1916,12 @@ static int nvme_tcp_alloc_admin_queue(struct nvme_ctrl *ctrl)
        key_serial_t pskid = 0;
 
        if (ctrl->opts->tls) {
-               pskid = nvme_tls_psk_default(NULL,
-                                             ctrl->opts->host->nqn,
-                                             ctrl->opts->subsysnqn);
+               if (ctrl->opts->tls_key)
+                       pskid = key_serial(ctrl->opts->tls_key);
+               else
+                       pskid = nvme_tls_psk_default(ctrl->opts->keyring,
+                                                     ctrl->opts->host->nqn,
+                                                     ctrl->opts->subsysnqn);
                if (!pskid) {
                        dev_err(ctrl->device, "no valid PSK found\n");
                        ret = -ENOKEY;
@@ -2777,7 +2782,8 @@ static struct nvmf_transport_ops nvme_tcp_transport = {
                          NVMF_OPT_HOST_TRADDR | NVMF_OPT_CTRL_LOSS_TMO |
                          NVMF_OPT_HDR_DIGEST | NVMF_OPT_DATA_DIGEST |
                          NVMF_OPT_NR_WRITE_QUEUES | NVMF_OPT_NR_POLL_QUEUES |
-                         NVMF_OPT_TOS | NVMF_OPT_HOST_IFACE | NVMF_OPT_TLS,
+                         NVMF_OPT_TOS | NVMF_OPT_HOST_IFACE | NVMF_OPT_TLS |
+                         NVMF_OPT_KEYRING | NVMF_OPT_TLS_KEY,
        .create_ctrl    = nvme_tcp_create_ctrl,
 };