1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2023 Hannes Reinecke, SUSE Labs 4 */ 5 6 #include <linux/module.h> 7 #include <linux/seq_file.h> 8 #include <linux/key.h> 9 #include <linux/key-type.h> 10 #include <keys/user-type.h> 11 #include <linux/nvme.h> 12 #include <linux/nvme-tcp.h> 13 #include <linux/nvme-keyring.h> 14 15 static struct key *nvme_keyring; 16 17 key_serial_t nvme_keyring_id(void) 18 { 19 return nvme_keyring->serial; 20 } 21 EXPORT_SYMBOL_GPL(nvme_keyring_id); 22 23 static void nvme_tls_psk_describe(const struct key *key, struct seq_file *m) 24 { 25 seq_puts(m, key->description); 26 seq_printf(m, ": %u", key->datalen); 27 } 28 29 static bool nvme_tls_psk_match(const struct key *key, 30 const struct key_match_data *match_data) 31 { 32 const char *match_id; 33 size_t match_len; 34 35 if (!key->description) { 36 pr_debug("%s: no key description\n", __func__); 37 return false; 38 } 39 match_len = strlen(key->description); 40 pr_debug("%s: id %s len %zd\n", __func__, key->description, match_len); 41 42 if (!match_data->raw_data) { 43 pr_debug("%s: no match data\n", __func__); 44 return false; 45 } 46 match_id = match_data->raw_data; 47 pr_debug("%s: match '%s' '%s' len %zd\n", 48 __func__, match_id, key->description, match_len); 49 return !memcmp(key->description, match_id, match_len); 50 } 51 52 static int nvme_tls_psk_match_preparse(struct key_match_data *match_data) 53 { 54 match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE; 55 match_data->cmp = nvme_tls_psk_match; 56 return 0; 57 } 58 59 static struct key_type nvme_tls_psk_key_type = { 60 .name = "psk", 61 .flags = KEY_TYPE_NET_DOMAIN, 62 .preparse = user_preparse, 63 .free_preparse = user_free_preparse, 64 .match_preparse = nvme_tls_psk_match_preparse, 65 .instantiate = generic_key_instantiate, 66 .revoke = user_revoke, 67 .destroy = user_destroy, 68 .describe = nvme_tls_psk_describe, 69 .read = user_read, 70 }; 71 72 static struct key *nvme_tls_psk_lookup(struct key *keyring, 73 const char *hostnqn, const char *subnqn, 74 int hmac, bool generated) 75 { 76 char *identity; 77 size_t identity_len = (NVMF_NQN_SIZE) * 2 + 11; 78 key_ref_t keyref; 79 key_serial_t keyring_id; 80 81 identity = kzalloc(identity_len, GFP_KERNEL); 82 if (!identity) 83 return ERR_PTR(-ENOMEM); 84 85 snprintf(identity, identity_len, "NVMe0%c%02d %s %s", 86 generated ? 'G' : 'R', hmac, hostnqn, subnqn); 87 88 if (!keyring) 89 keyring = nvme_keyring; 90 keyring_id = key_serial(keyring); 91 pr_debug("keyring %x lookup tls psk '%s'\n", 92 keyring_id, identity); 93 keyref = keyring_search(make_key_ref(keyring, true), 94 &nvme_tls_psk_key_type, 95 identity, false); 96 if (IS_ERR(keyref)) { 97 pr_debug("lookup tls psk '%s' failed, error %ld\n", 98 identity, PTR_ERR(keyref)); 99 kfree(identity); 100 return ERR_PTR(-ENOKEY); 101 } 102 kfree(identity); 103 104 return key_ref_to_ptr(keyref); 105 } 106 107 /* 108 * NVMe PSK priority list 109 * 110 * 'Retained' PSKs (ie 'generated == false') 111 * should be preferred to 'generated' PSKs, 112 * and SHA-384 should be preferred to SHA-256. 113 */ 114 struct nvme_tls_psk_priority_list { 115 bool generated; 116 enum nvme_tcp_tls_cipher cipher; 117 } nvme_tls_psk_prio[] = { 118 { .generated = false, 119 .cipher = NVME_TCP_TLS_CIPHER_SHA384, }, 120 { .generated = false, 121 .cipher = NVME_TCP_TLS_CIPHER_SHA256, }, 122 { .generated = true, 123 .cipher = NVME_TCP_TLS_CIPHER_SHA384, }, 124 { .generated = true, 125 .cipher = NVME_TCP_TLS_CIPHER_SHA256, }, 126 }; 127 128 /* 129 * nvme_tls_psk_default - Return the preferred PSK to use for TLS ClientHello 130 */ 131 key_serial_t nvme_tls_psk_default(struct key *keyring, 132 const char *hostnqn, const char *subnqn) 133 { 134 struct key *tls_key; 135 key_serial_t tls_key_id; 136 int prio; 137 138 for (prio = 0; prio < ARRAY_SIZE(nvme_tls_psk_prio); prio++) { 139 bool generated = nvme_tls_psk_prio[prio].generated; 140 enum nvme_tcp_tls_cipher cipher = nvme_tls_psk_prio[prio].cipher; 141 142 tls_key = nvme_tls_psk_lookup(keyring, hostnqn, subnqn, 143 cipher, generated); 144 if (!IS_ERR(tls_key)) { 145 tls_key_id = tls_key->serial; 146 key_put(tls_key); 147 return tls_key_id; 148 } 149 } 150 return 0; 151 } 152 EXPORT_SYMBOL_GPL(nvme_tls_psk_default); 153 154 static int __init nvme_keyring_init(void) 155 { 156 int err; 157 158 nvme_keyring = keyring_alloc(".nvme", 159 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 160 current_cred(), 161 (KEY_POS_ALL & ~KEY_POS_SETATTR) | 162 (KEY_USR_ALL & ~KEY_USR_SETATTR), 163 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); 164 if (IS_ERR(nvme_keyring)) 165 return PTR_ERR(nvme_keyring); 166 167 err = register_key_type(&nvme_tls_psk_key_type); 168 if (err) { 169 key_put(nvme_keyring); 170 return err; 171 } 172 return 0; 173 } 174 175 static void __exit nvme_keyring_exit(void) 176 { 177 unregister_key_type(&nvme_tls_psk_key_type); 178 key_revoke(nvme_keyring); 179 key_put(nvme_keyring); 180 } 181 182 MODULE_LICENSE("GPL v2"); 183 MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>"); 184 module_init(nvme_keyring_init); 185 module_exit(nvme_keyring_exit); 186