nvme-keyring: define a 'psk' keytype
authorHannes Reinecke <hare@suse.de>
Thu, 24 Aug 2023 14:39:09 +0000 (16:39 +0200)
committerKeith Busch <kbusch@kernel.org>
Wed, 11 Oct 2023 17:11:54 +0000 (10:11 -0700)
Define a 'psk' keytype to hold the NVMe TLS PSKs.

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/common/keyring.c

index 5cf64b278119c40d6bc2048540e636ad4a4c0082..494dd365052e9253cb1312a4798ff494311d3d44 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/key-type.h>
 #include <keys/user-type.h>
 #include <linux/nvme.h>
+#include <linux/nvme-tcp.h>
+#include <linux/nvme-keyring.h>
 
 static struct key *nvme_keyring;
 
@@ -17,8 +19,94 @@ key_serial_t nvme_keyring_id(void)
 }
 EXPORT_SYMBOL_GPL(nvme_keyring_id);
 
+static void nvme_tls_psk_describe(const struct key *key, struct seq_file *m)
+{
+       seq_puts(m, key->description);
+       seq_printf(m, ": %u", key->datalen);
+}
+
+static bool nvme_tls_psk_match(const struct key *key,
+                              const struct key_match_data *match_data)
+{
+       const char *match_id;
+       size_t match_len;
+
+       if (!key->description) {
+               pr_debug("%s: no key description\n", __func__);
+               return false;
+       }
+       match_len = strlen(key->description);
+       pr_debug("%s: id %s len %zd\n", __func__, key->description, match_len);
+
+       if (!match_data->raw_data) {
+               pr_debug("%s: no match data\n", __func__);
+               return false;
+       }
+       match_id = match_data->raw_data;
+       pr_debug("%s: match '%s' '%s' len %zd\n",
+                __func__, match_id, key->description, match_len);
+       return !memcmp(key->description, match_id, match_len);
+}
+
+static int nvme_tls_psk_match_preparse(struct key_match_data *match_data)
+{
+       match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
+       match_data->cmp = nvme_tls_psk_match;
+       return 0;
+}
+
+static struct key_type nvme_tls_psk_key_type = {
+       .name           = "psk",
+       .flags          = KEY_TYPE_NET_DOMAIN,
+       .preparse       = user_preparse,
+       .free_preparse  = user_free_preparse,
+       .match_preparse = nvme_tls_psk_match_preparse,
+       .instantiate    = generic_key_instantiate,
+       .revoke         = user_revoke,
+       .destroy        = user_destroy,
+       .describe       = nvme_tls_psk_describe,
+       .read           = user_read,
+};
+
+static struct key *nvme_tls_psk_lookup(struct key *keyring,
+               const char *hostnqn, const char *subnqn,
+               int hmac, bool generated)
+{
+       char *identity;
+       size_t identity_len = (NVMF_NQN_SIZE) * 2 + 11;
+       key_ref_t keyref;
+       key_serial_t keyring_id;
+
+       identity = kzalloc(identity_len, GFP_KERNEL);
+       if (!identity)
+               return ERR_PTR(-ENOMEM);
+
+       snprintf(identity, identity_len, "NVMe0%c%02d %s %s",
+                generated ? 'G' : 'R', hmac, hostnqn, subnqn);
+
+       if (!keyring)
+               keyring = nvme_keyring;
+       keyring_id = key_serial(keyring);
+       pr_debug("keyring %x lookup tls psk '%s'\n",
+                keyring_id, identity);
+       keyref = keyring_search(make_key_ref(keyring, true),
+                               &nvme_tls_psk_key_type,
+                               identity, false);
+       if (IS_ERR(keyref)) {
+               pr_debug("lookup tls psk '%s' failed, error %ld\n",
+                        identity, PTR_ERR(keyref));
+               kfree(identity);
+               return ERR_PTR(-ENOKEY);
+       }
+       kfree(identity);
+
+       return key_ref_to_ptr(keyref);
+}
+
 int nvme_keyring_init(void)
 {
+       int err;
+
        nvme_keyring = keyring_alloc(".nvme",
                                     GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
                                     current_cred(),
@@ -28,12 +116,18 @@ int nvme_keyring_init(void)
        if (IS_ERR(nvme_keyring))
                return PTR_ERR(nvme_keyring);
 
+       err = register_key_type(&nvme_tls_psk_key_type);
+       if (err) {
+               key_put(nvme_keyring);
+               return err;
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(nvme_keyring_init);
 
 void nvme_keyring_exit(void)
 {
+       unregister_key_type(&nvme_tls_psk_key_type);
        key_revoke(nvme_keyring);
        key_put(nvme_keyring);
 }