2023-08-24 16:39:08 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2023 Hannes Reinecke, SUSE Labs
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/seq_file.h>
|
2023-08-24 16:39:12 +02:00
|
|
|
#include <linux/key.h>
|
2023-08-24 16:39:08 +02:00
|
|
|
#include <linux/key-type.h>
|
|
|
|
#include <keys/user-type.h>
|
|
|
|
#include <linux/nvme.h>
|
2023-08-24 16:39:09 +02:00
|
|
|
#include <linux/nvme-tcp.h>
|
|
|
|
#include <linux/nvme-keyring.h>
|
2023-08-24 16:39:08 +02:00
|
|
|
|
|
|
|
static struct key *nvme_keyring;
|
|
|
|
|
|
|
|
key_serial_t nvme_keyring_id(void)
|
|
|
|
{
|
|
|
|
return nvme_keyring->serial;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nvme_keyring_id);
|
|
|
|
|
2023-08-24 16:39:09 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-08-24 16:39:12 +02:00
|
|
|
/*
|
|
|
|
* NVMe PSK priority list
|
|
|
|
*
|
|
|
|
* 'Retained' PSKs (ie 'generated == false')
|
|
|
|
* should be preferred to 'generated' PSKs,
|
|
|
|
* and SHA-384 should be preferred to SHA-256.
|
|
|
|
*/
|
|
|
|
struct nvme_tls_psk_priority_list {
|
|
|
|
bool generated;
|
|
|
|
enum nvme_tcp_tls_cipher cipher;
|
|
|
|
} nvme_tls_psk_prio[] = {
|
|
|
|
{ .generated = false,
|
|
|
|
.cipher = NVME_TCP_TLS_CIPHER_SHA384, },
|
|
|
|
{ .generated = false,
|
|
|
|
.cipher = NVME_TCP_TLS_CIPHER_SHA256, },
|
|
|
|
{ .generated = true,
|
|
|
|
.cipher = NVME_TCP_TLS_CIPHER_SHA384, },
|
|
|
|
{ .generated = true,
|
|
|
|
.cipher = NVME_TCP_TLS_CIPHER_SHA256, },
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* nvme_tls_psk_default - Return the preferred PSK to use for TLS ClientHello
|
|
|
|
*/
|
|
|
|
key_serial_t nvme_tls_psk_default(struct key *keyring,
|
|
|
|
const char *hostnqn, const char *subnqn)
|
|
|
|
{
|
|
|
|
struct key *tls_key;
|
|
|
|
key_serial_t tls_key_id;
|
|
|
|
int prio;
|
|
|
|
|
|
|
|
for (prio = 0; prio < ARRAY_SIZE(nvme_tls_psk_prio); prio++) {
|
|
|
|
bool generated = nvme_tls_psk_prio[prio].generated;
|
|
|
|
enum nvme_tcp_tls_cipher cipher = nvme_tls_psk_prio[prio].cipher;
|
|
|
|
|
|
|
|
tls_key = nvme_tls_psk_lookup(keyring, hostnqn, subnqn,
|
|
|
|
cipher, generated);
|
|
|
|
if (!IS_ERR(tls_key)) {
|
|
|
|
tls_key_id = tls_key->serial;
|
|
|
|
key_put(tls_key);
|
|
|
|
return tls_key_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nvme_tls_psk_default);
|
|
|
|
|
2023-10-26 15:08:04 +02:00
|
|
|
static int __init nvme_keyring_init(void)
|
2023-08-24 16:39:08 +02:00
|
|
|
{
|
2023-08-24 16:39:09 +02:00
|
|
|
int err;
|
|
|
|
|
2023-08-24 16:39:08 +02:00
|
|
|
nvme_keyring = keyring_alloc(".nvme",
|
|
|
|
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
|
|
|
|
current_cred(),
|
|
|
|
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
|
|
|
(KEY_USR_ALL & ~KEY_USR_SETATTR),
|
|
|
|
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
|
|
|
|
if (IS_ERR(nvme_keyring))
|
|
|
|
return PTR_ERR(nvme_keyring);
|
|
|
|
|
2023-08-24 16:39:09 +02:00
|
|
|
err = register_key_type(&nvme_tls_psk_key_type);
|
|
|
|
if (err) {
|
|
|
|
key_put(nvme_keyring);
|
|
|
|
return err;
|
|
|
|
}
|
2023-08-24 16:39:08 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-10-26 15:08:04 +02:00
|
|
|
static void __exit nvme_keyring_exit(void)
|
2023-08-24 16:39:08 +02:00
|
|
|
{
|
2023-08-24 16:39:09 +02:00
|
|
|
unregister_key_type(&nvme_tls_psk_key_type);
|
2023-08-24 16:39:08 +02:00
|
|
|
key_revoke(nvme_keyring);
|
|
|
|
key_put(nvme_keyring);
|
|
|
|
}
|
2023-10-26 15:08:03 +02:00
|
|
|
|
|
|
|
MODULE_LICENSE("GPL v2");
|
2023-10-26 15:08:04 +02:00
|
|
|
MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>");
|
|
|
|
module_init(nvme_keyring_init);
|
|
|
|
module_exit(nvme_keyring_exit);
|