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-type.h> 9 #include <keys/user-type.h> 10 #include <linux/nvme.h> 11 #include <linux/nvme-tcp.h> 12 #include <linux/nvme-keyring.h> 13 14 static struct key *nvme_keyring; 15 16 key_serial_t nvme_keyring_id(void) 17 { 18 return nvme_keyring->serial; 19 } 20 EXPORT_SYMBOL_GPL(nvme_keyring_id); 21 22 static bool nvme_tls_psk_revoked(struct key *psk) 23 { 24 return test_bit(KEY_FLAG_REVOKED, &psk->flags) || 25 test_bit(KEY_FLAG_INVALIDATED, &psk->flags); 26 } 27 28 struct key *nvme_tls_key_lookup(key_serial_t key_id) 29 { 30 struct key *key = key_lookup(key_id); 31 32 if (IS_ERR(key)) { 33 pr_err("key id %08x not found\n", key_id); 34 return key; 35 } 36 if (nvme_tls_psk_revoked(key)) { 37 pr_err("key id %08x revoked\n", key_id); 38 return ERR_PTR(-EKEYREVOKED); 39 } 40 return key; 41 } 42 EXPORT_SYMBOL_GPL(nvme_tls_key_lookup); 43 44 static void nvme_tls_psk_describe(const struct key *key, struct seq_file *m) 45 { 46 seq_puts(m, key->description); 47 seq_printf(m, ": %u", key->datalen); 48 } 49 50 static bool nvme_tls_psk_match(const struct key *key, 51 const struct key_match_data *match_data) 52 { 53 const char *match_id; 54 size_t match_len; 55 56 if (!key->description) { 57 pr_debug("%s: no key description\n", __func__); 58 return false; 59 } 60 if (!match_data->raw_data) { 61 pr_debug("%s: no match data\n", __func__); 62 return false; 63 } 64 match_id = match_data->raw_data; 65 match_len = strlen(match_id); 66 pr_debug("%s: match '%s' '%s' len %zd\n", 67 __func__, match_id, key->description, match_len); 68 return !memcmp(key->description, match_id, match_len); 69 } 70 71 static int nvme_tls_psk_match_preparse(struct key_match_data *match_data) 72 { 73 match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE; 74 match_data->cmp = nvme_tls_psk_match; 75 return 0; 76 } 77 78 static struct key_type nvme_tls_psk_key_type = { 79 .name = "psk", 80 .flags = KEY_TYPE_NET_DOMAIN, 81 .preparse = user_preparse, 82 .free_preparse = user_free_preparse, 83 .match_preparse = nvme_tls_psk_match_preparse, 84 .instantiate = generic_key_instantiate, 85 .revoke = user_revoke, 86 .destroy = user_destroy, 87 .describe = nvme_tls_psk_describe, 88 .read = user_read, 89 }; 90 91 static struct key *nvme_tls_psk_lookup(struct key *keyring, 92 const char *hostnqn, const char *subnqn, 93 u8 hmac, u8 psk_ver, bool generated) 94 { 95 char *identity; 96 size_t identity_len = (NVMF_NQN_SIZE) * 2 + 11; 97 key_ref_t keyref; 98 key_serial_t keyring_id; 99 100 identity = kzalloc(identity_len, GFP_KERNEL); 101 if (!identity) 102 return ERR_PTR(-ENOMEM); 103 104 snprintf(identity, identity_len, "NVMe%u%c%02u %s %s", 105 psk_ver, generated ? 'G' : 'R', hmac, hostnqn, subnqn); 106 107 if (!keyring) 108 keyring = nvme_keyring; 109 keyring_id = key_serial(keyring); 110 pr_debug("keyring %x lookup tls psk '%s'\n", 111 keyring_id, identity); 112 keyref = keyring_search(make_key_ref(keyring, true), 113 &nvme_tls_psk_key_type, 114 identity, false); 115 if (IS_ERR(keyref)) { 116 pr_debug("lookup tls psk '%s' failed, error %ld\n", 117 identity, PTR_ERR(keyref)); 118 kfree(identity); 119 return ERR_PTR(-ENOKEY); 120 } 121 kfree(identity); 122 123 return key_ref_to_ptr(keyref); 124 } 125 126 /** 127 * nvme_tls_psk_refresh - Refresh TLS PSK 128 * @keyring: Keyring holding the TLS PSK 129 * @hostnqn: Host NQN to use 130 * @subnqn: Subsystem NQN to use 131 * @hmac_id: Hash function identifier 132 * @data: TLS PSK key material 133 * @data_len: Length of @data 134 * @digest: TLS PSK digest 135 * 136 * Refresh a generated version 1 TLS PSK with the identity generated 137 * from @hmac_id, @hostnqn, @subnqn, and @digest in the keyring given 138 * by @keyring. 139 * 140 * Returns the updated key success or an error pointer otherwise. 141 */ 142 struct key *nvme_tls_psk_refresh(struct key *keyring, 143 const char *hostnqn, const char *subnqn, u8 hmac_id, 144 u8 *data, size_t data_len, const char *digest) 145 { 146 key_perm_t keyperm = 147 KEY_POS_SEARCH | KEY_POS_VIEW | KEY_POS_READ | 148 KEY_POS_WRITE | KEY_POS_LINK | KEY_POS_SETATTR | 149 KEY_USR_SEARCH | KEY_USR_VIEW | KEY_USR_READ; 150 char *identity; 151 key_ref_t keyref; 152 key_serial_t keyring_id; 153 struct key *key; 154 155 if (!hostnqn || !subnqn || !data || !data_len) 156 return ERR_PTR(-EINVAL); 157 158 identity = kasprintf(GFP_KERNEL, "NVMe1G%02d %s %s %s", 159 hmac_id, hostnqn, subnqn, digest); 160 if (!identity) 161 return ERR_PTR(-ENOMEM); 162 163 if (!keyring) 164 keyring = nvme_keyring; 165 keyring_id = key_serial(keyring); 166 pr_debug("keyring %x refresh tls psk '%s'\n", 167 keyring_id, identity); 168 keyref = key_create_or_update(make_key_ref(keyring, true), 169 "psk", identity, data, data_len, 170 keyperm, KEY_ALLOC_NOT_IN_QUOTA | 171 KEY_ALLOC_BUILT_IN | 172 KEY_ALLOC_BYPASS_RESTRICTION); 173 if (IS_ERR(keyref)) { 174 pr_debug("refresh tls psk '%s' failed, error %ld\n", 175 identity, PTR_ERR(keyref)); 176 kfree(identity); 177 return ERR_PTR(-ENOKEY); 178 } 179 kfree(identity); 180 /* 181 * Set the default timeout to 1 hour 182 * as suggested in TP8018. 183 */ 184 key = key_ref_to_ptr(keyref); 185 key_set_timeout(key, 3600); 186 return key; 187 } 188 EXPORT_SYMBOL_GPL(nvme_tls_psk_refresh); 189 190 /* 191 * NVMe PSK priority list 192 * 193 * 'Retained' PSKs (ie 'generated == false') should be preferred to 'generated' 194 * PSKs, PSKs with hash (psk_ver 1) should be preferred to PSKs without hash 195 * (psk_ver 0), and SHA-384 should be preferred to SHA-256. 196 */ 197 static struct nvme_tls_psk_priority_list { 198 bool generated; 199 u8 psk_ver; 200 enum nvme_tcp_tls_cipher cipher; 201 } nvme_tls_psk_prio[] = { 202 { .generated = false, 203 .psk_ver = 1, 204 .cipher = NVME_TCP_TLS_CIPHER_SHA384, }, 205 { .generated = false, 206 .psk_ver = 1, 207 .cipher = NVME_TCP_TLS_CIPHER_SHA256, }, 208 { .generated = false, 209 .psk_ver = 0, 210 .cipher = NVME_TCP_TLS_CIPHER_SHA384, }, 211 { .generated = false, 212 .psk_ver = 0, 213 .cipher = NVME_TCP_TLS_CIPHER_SHA256, }, 214 { .generated = true, 215 .psk_ver = 1, 216 .cipher = NVME_TCP_TLS_CIPHER_SHA384, }, 217 { .generated = true, 218 .psk_ver = 1, 219 .cipher = NVME_TCP_TLS_CIPHER_SHA256, }, 220 { .generated = true, 221 .psk_ver = 0, 222 .cipher = NVME_TCP_TLS_CIPHER_SHA384, }, 223 { .generated = true, 224 .psk_ver = 0, 225 .cipher = NVME_TCP_TLS_CIPHER_SHA256, }, 226 }; 227 228 /* 229 * nvme_tls_psk_default - Return the preferred PSK to use for TLS ClientHello 230 */ 231 key_serial_t nvme_tls_psk_default(struct key *keyring, 232 const char *hostnqn, const char *subnqn) 233 { 234 struct key *tls_key; 235 key_serial_t tls_key_id; 236 int prio; 237 238 for (prio = 0; prio < ARRAY_SIZE(nvme_tls_psk_prio); prio++) { 239 bool generated = nvme_tls_psk_prio[prio].generated; 240 u8 ver = nvme_tls_psk_prio[prio].psk_ver; 241 enum nvme_tcp_tls_cipher cipher = nvme_tls_psk_prio[prio].cipher; 242 243 tls_key = nvme_tls_psk_lookup(keyring, hostnqn, subnqn, 244 cipher, ver, generated); 245 if (!IS_ERR(tls_key)) { 246 tls_key_id = tls_key->serial; 247 key_put(tls_key); 248 return tls_key_id; 249 } 250 } 251 return 0; 252 } 253 EXPORT_SYMBOL_GPL(nvme_tls_psk_default); 254 255 static int __init nvme_keyring_init(void) 256 { 257 int err; 258 259 nvme_keyring = keyring_alloc(".nvme", 260 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 261 current_cred(), 262 (KEY_POS_ALL & ~KEY_POS_SETATTR) | 263 (KEY_USR_ALL & ~KEY_USR_SETATTR), 264 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); 265 if (IS_ERR(nvme_keyring)) 266 return PTR_ERR(nvme_keyring); 267 268 err = register_key_type(&nvme_tls_psk_key_type); 269 if (err) { 270 key_put(nvme_keyring); 271 return err; 272 } 273 return 0; 274 } 275 276 static void __exit nvme_keyring_exit(void) 277 { 278 unregister_key_type(&nvme_tls_psk_key_type); 279 key_revoke(nvme_keyring); 280 key_put(nvme_keyring); 281 } 282 283 MODULE_LICENSE("GPL v2"); 284 MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>"); 285 MODULE_DESCRIPTION("NVMe Keyring implementation"); 286 module_init(nvme_keyring_init); 287 module_exit(nvme_keyring_exit); 288