auth.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2020 Hannes Reinecke, SUSE Linux
  4. */
  5. #include <linux/module.h>
  6. #include <linux/crc32.h>
  7. #include <linux/base64.h>
  8. #include <linux/prandom.h>
  9. #include <linux/scatterlist.h>
  10. #include <linux/unaligned.h>
  11. #include <crypto/hash.h>
  12. #include <crypto/dh.h>
  13. #include <crypto/hkdf.h>
  14. #include <linux/nvme.h>
  15. #include <linux/nvme-auth.h>
  16. #define HKDF_MAX_HASHLEN 64
  17. static u32 nvme_dhchap_seqnum;
  18. static DEFINE_MUTEX(nvme_dhchap_mutex);
  19. u32 nvme_auth_get_seqnum(void)
  20. {
  21. u32 seqnum;
  22. mutex_lock(&nvme_dhchap_mutex);
  23. if (!nvme_dhchap_seqnum)
  24. nvme_dhchap_seqnum = get_random_u32();
  25. else {
  26. nvme_dhchap_seqnum++;
  27. if (!nvme_dhchap_seqnum)
  28. nvme_dhchap_seqnum++;
  29. }
  30. seqnum = nvme_dhchap_seqnum;
  31. mutex_unlock(&nvme_dhchap_mutex);
  32. return seqnum;
  33. }
  34. EXPORT_SYMBOL_GPL(nvme_auth_get_seqnum);
  35. static struct nvme_auth_dhgroup_map {
  36. const char name[16];
  37. const char kpp[16];
  38. } dhgroup_map[] = {
  39. [NVME_AUTH_DHGROUP_NULL] = {
  40. .name = "null", .kpp = "null" },
  41. [NVME_AUTH_DHGROUP_2048] = {
  42. .name = "ffdhe2048", .kpp = "ffdhe2048(dh)" },
  43. [NVME_AUTH_DHGROUP_3072] = {
  44. .name = "ffdhe3072", .kpp = "ffdhe3072(dh)" },
  45. [NVME_AUTH_DHGROUP_4096] = {
  46. .name = "ffdhe4096", .kpp = "ffdhe4096(dh)" },
  47. [NVME_AUTH_DHGROUP_6144] = {
  48. .name = "ffdhe6144", .kpp = "ffdhe6144(dh)" },
  49. [NVME_AUTH_DHGROUP_8192] = {
  50. .name = "ffdhe8192", .kpp = "ffdhe8192(dh)" },
  51. };
  52. const char *nvme_auth_dhgroup_name(u8 dhgroup_id)
  53. {
  54. if (dhgroup_id >= ARRAY_SIZE(dhgroup_map))
  55. return NULL;
  56. return dhgroup_map[dhgroup_id].name;
  57. }
  58. EXPORT_SYMBOL_GPL(nvme_auth_dhgroup_name);
  59. const char *nvme_auth_dhgroup_kpp(u8 dhgroup_id)
  60. {
  61. if (dhgroup_id >= ARRAY_SIZE(dhgroup_map))
  62. return NULL;
  63. return dhgroup_map[dhgroup_id].kpp;
  64. }
  65. EXPORT_SYMBOL_GPL(nvme_auth_dhgroup_kpp);
  66. u8 nvme_auth_dhgroup_id(const char *dhgroup_name)
  67. {
  68. int i;
  69. if (!dhgroup_name || !strlen(dhgroup_name))
  70. return NVME_AUTH_DHGROUP_INVALID;
  71. for (i = 0; i < ARRAY_SIZE(dhgroup_map); i++) {
  72. if (!strlen(dhgroup_map[i].name))
  73. continue;
  74. if (!strncmp(dhgroup_map[i].name, dhgroup_name,
  75. strlen(dhgroup_map[i].name)))
  76. return i;
  77. }
  78. return NVME_AUTH_DHGROUP_INVALID;
  79. }
  80. EXPORT_SYMBOL_GPL(nvme_auth_dhgroup_id);
  81. static struct nvme_dhchap_hash_map {
  82. int len;
  83. const char hmac[15];
  84. const char digest[8];
  85. } hash_map[] = {
  86. [NVME_AUTH_HASH_SHA256] = {
  87. .len = 32,
  88. .hmac = "hmac(sha256)",
  89. .digest = "sha256",
  90. },
  91. [NVME_AUTH_HASH_SHA384] = {
  92. .len = 48,
  93. .hmac = "hmac(sha384)",
  94. .digest = "sha384",
  95. },
  96. [NVME_AUTH_HASH_SHA512] = {
  97. .len = 64,
  98. .hmac = "hmac(sha512)",
  99. .digest = "sha512",
  100. },
  101. };
  102. const char *nvme_auth_hmac_name(u8 hmac_id)
  103. {
  104. if (hmac_id >= ARRAY_SIZE(hash_map))
  105. return NULL;
  106. return hash_map[hmac_id].hmac;
  107. }
  108. EXPORT_SYMBOL_GPL(nvme_auth_hmac_name);
  109. const char *nvme_auth_digest_name(u8 hmac_id)
  110. {
  111. if (hmac_id >= ARRAY_SIZE(hash_map))
  112. return NULL;
  113. return hash_map[hmac_id].digest;
  114. }
  115. EXPORT_SYMBOL_GPL(nvme_auth_digest_name);
  116. u8 nvme_auth_hmac_id(const char *hmac_name)
  117. {
  118. int i;
  119. if (!hmac_name || !strlen(hmac_name))
  120. return NVME_AUTH_HASH_INVALID;
  121. for (i = 0; i < ARRAY_SIZE(hash_map); i++) {
  122. if (!strlen(hash_map[i].hmac))
  123. continue;
  124. if (!strncmp(hash_map[i].hmac, hmac_name,
  125. strlen(hash_map[i].hmac)))
  126. return i;
  127. }
  128. return NVME_AUTH_HASH_INVALID;
  129. }
  130. EXPORT_SYMBOL_GPL(nvme_auth_hmac_id);
  131. size_t nvme_auth_hmac_hash_len(u8 hmac_id)
  132. {
  133. if (hmac_id >= ARRAY_SIZE(hash_map))
  134. return 0;
  135. return hash_map[hmac_id].len;
  136. }
  137. EXPORT_SYMBOL_GPL(nvme_auth_hmac_hash_len);
  138. u32 nvme_auth_key_struct_size(u32 key_len)
  139. {
  140. struct nvme_dhchap_key key;
  141. return struct_size(&key, key, key_len);
  142. }
  143. EXPORT_SYMBOL_GPL(nvme_auth_key_struct_size);
  144. struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
  145. u8 key_hash)
  146. {
  147. struct nvme_dhchap_key *key;
  148. unsigned char *p;
  149. u32 crc;
  150. int ret, key_len;
  151. size_t allocated_len = strlen(secret);
  152. /* Secret might be affixed with a ':' */
  153. p = strrchr(secret, ':');
  154. if (p)
  155. allocated_len = p - secret;
  156. key = nvme_auth_alloc_key(allocated_len, 0);
  157. if (!key)
  158. return ERR_PTR(-ENOMEM);
  159. key_len = base64_decode(secret, allocated_len, key->key, true, BASE64_STD);
  160. if (key_len < 0) {
  161. pr_debug("base64 key decoding error %d\n",
  162. key_len);
  163. ret = key_len;
  164. goto out_free_secret;
  165. }
  166. if (key_len != 36 && key_len != 52 &&
  167. key_len != 68) {
  168. pr_err("Invalid key len %d\n", key_len);
  169. ret = -EINVAL;
  170. goto out_free_secret;
  171. }
  172. /* The last four bytes is the CRC in little-endian format */
  173. key_len -= 4;
  174. /*
  175. * The linux implementation doesn't do pre- and post-increments,
  176. * so we have to do it manually.
  177. */
  178. crc = ~crc32(~0, key->key, key_len);
  179. if (get_unaligned_le32(key->key + key_len) != crc) {
  180. pr_err("key crc mismatch (key %08x, crc %08x)\n",
  181. get_unaligned_le32(key->key + key_len), crc);
  182. ret = -EKEYREJECTED;
  183. goto out_free_secret;
  184. }
  185. key->len = key_len;
  186. key->hash = key_hash;
  187. return key;
  188. out_free_secret:
  189. nvme_auth_free_key(key);
  190. return ERR_PTR(ret);
  191. }
  192. EXPORT_SYMBOL_GPL(nvme_auth_extract_key);
  193. struct nvme_dhchap_key *nvme_auth_alloc_key(u32 len, u8 hash)
  194. {
  195. u32 num_bytes = nvme_auth_key_struct_size(len);
  196. struct nvme_dhchap_key *key = kzalloc(num_bytes, GFP_KERNEL);
  197. if (key) {
  198. key->len = len;
  199. key->hash = hash;
  200. }
  201. return key;
  202. }
  203. EXPORT_SYMBOL_GPL(nvme_auth_alloc_key);
  204. void nvme_auth_free_key(struct nvme_dhchap_key *key)
  205. {
  206. if (!key)
  207. return;
  208. kfree_sensitive(key);
  209. }
  210. EXPORT_SYMBOL_GPL(nvme_auth_free_key);
  211. struct nvme_dhchap_key *nvme_auth_transform_key(
  212. struct nvme_dhchap_key *key, char *nqn)
  213. {
  214. const char *hmac_name;
  215. struct crypto_shash *key_tfm;
  216. SHASH_DESC_ON_STACK(shash, key_tfm);
  217. struct nvme_dhchap_key *transformed_key;
  218. int ret, key_len;
  219. if (!key) {
  220. pr_warn("No key specified\n");
  221. return ERR_PTR(-ENOKEY);
  222. }
  223. if (key->hash == 0) {
  224. key_len = nvme_auth_key_struct_size(key->len);
  225. transformed_key = kmemdup(key, key_len, GFP_KERNEL);
  226. if (!transformed_key)
  227. return ERR_PTR(-ENOMEM);
  228. return transformed_key;
  229. }
  230. hmac_name = nvme_auth_hmac_name(key->hash);
  231. if (!hmac_name) {
  232. pr_warn("Invalid key hash id %d\n", key->hash);
  233. return ERR_PTR(-EINVAL);
  234. }
  235. key_tfm = crypto_alloc_shash(hmac_name, 0, 0);
  236. if (IS_ERR(key_tfm))
  237. return ERR_CAST(key_tfm);
  238. key_len = crypto_shash_digestsize(key_tfm);
  239. transformed_key = nvme_auth_alloc_key(key_len, key->hash);
  240. if (!transformed_key) {
  241. ret = -ENOMEM;
  242. goto out_free_key;
  243. }
  244. shash->tfm = key_tfm;
  245. ret = crypto_shash_setkey(key_tfm, key->key, key->len);
  246. if (ret < 0)
  247. goto out_free_transformed_key;
  248. ret = crypto_shash_init(shash);
  249. if (ret < 0)
  250. goto out_free_transformed_key;
  251. ret = crypto_shash_update(shash, nqn, strlen(nqn));
  252. if (ret < 0)
  253. goto out_free_transformed_key;
  254. ret = crypto_shash_update(shash, "NVMe-over-Fabrics", 17);
  255. if (ret < 0)
  256. goto out_free_transformed_key;
  257. ret = crypto_shash_final(shash, transformed_key->key);
  258. if (ret < 0)
  259. goto out_free_transformed_key;
  260. crypto_free_shash(key_tfm);
  261. return transformed_key;
  262. out_free_transformed_key:
  263. nvme_auth_free_key(transformed_key);
  264. out_free_key:
  265. crypto_free_shash(key_tfm);
  266. return ERR_PTR(ret);
  267. }
  268. EXPORT_SYMBOL_GPL(nvme_auth_transform_key);
  269. static int nvme_auth_hash_skey(int hmac_id, u8 *skey, size_t skey_len, u8 *hkey)
  270. {
  271. const char *digest_name;
  272. struct crypto_shash *tfm;
  273. int ret;
  274. digest_name = nvme_auth_digest_name(hmac_id);
  275. if (!digest_name) {
  276. pr_debug("%s: failed to get digest for %d\n", __func__,
  277. hmac_id);
  278. return -EINVAL;
  279. }
  280. tfm = crypto_alloc_shash(digest_name, 0, 0);
  281. if (IS_ERR(tfm))
  282. return -ENOMEM;
  283. ret = crypto_shash_tfm_digest(tfm, skey, skey_len, hkey);
  284. if (ret < 0)
  285. pr_debug("%s: Failed to hash digest len %zu\n", __func__,
  286. skey_len);
  287. crypto_free_shash(tfm);
  288. return ret;
  289. }
  290. int nvme_auth_augmented_challenge(u8 hmac_id, u8 *skey, size_t skey_len,
  291. u8 *challenge, u8 *aug, size_t hlen)
  292. {
  293. struct crypto_shash *tfm;
  294. u8 *hashed_key;
  295. const char *hmac_name;
  296. int ret;
  297. hashed_key = kmalloc(hlen, GFP_KERNEL);
  298. if (!hashed_key)
  299. return -ENOMEM;
  300. ret = nvme_auth_hash_skey(hmac_id, skey,
  301. skey_len, hashed_key);
  302. if (ret < 0)
  303. goto out_free_key;
  304. hmac_name = nvme_auth_hmac_name(hmac_id);
  305. if (!hmac_name) {
  306. pr_warn("%s: invalid hash algorithm %d\n",
  307. __func__, hmac_id);
  308. ret = -EINVAL;
  309. goto out_free_key;
  310. }
  311. tfm = crypto_alloc_shash(hmac_name, 0, 0);
  312. if (IS_ERR(tfm)) {
  313. ret = PTR_ERR(tfm);
  314. goto out_free_key;
  315. }
  316. ret = crypto_shash_setkey(tfm, hashed_key, hlen);
  317. if (ret)
  318. goto out_free_hash;
  319. ret = crypto_shash_tfm_digest(tfm, challenge, hlen, aug);
  320. out_free_hash:
  321. crypto_free_shash(tfm);
  322. out_free_key:
  323. kfree_sensitive(hashed_key);
  324. return ret;
  325. }
  326. EXPORT_SYMBOL_GPL(nvme_auth_augmented_challenge);
  327. int nvme_auth_gen_privkey(struct crypto_kpp *dh_tfm, u8 dh_gid)
  328. {
  329. int ret;
  330. ret = crypto_kpp_set_secret(dh_tfm, NULL, 0);
  331. if (ret)
  332. pr_debug("failed to set private key, error %d\n", ret);
  333. return ret;
  334. }
  335. EXPORT_SYMBOL_GPL(nvme_auth_gen_privkey);
  336. int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm,
  337. u8 *host_key, size_t host_key_len)
  338. {
  339. struct kpp_request *req;
  340. struct crypto_wait wait;
  341. struct scatterlist dst;
  342. int ret;
  343. req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
  344. if (!req)
  345. return -ENOMEM;
  346. crypto_init_wait(&wait);
  347. kpp_request_set_input(req, NULL, 0);
  348. sg_init_one(&dst, host_key, host_key_len);
  349. kpp_request_set_output(req, &dst, host_key_len);
  350. kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
  351. crypto_req_done, &wait);
  352. ret = crypto_wait_req(crypto_kpp_generate_public_key(req), &wait);
  353. kpp_request_free(req);
  354. return ret;
  355. }
  356. EXPORT_SYMBOL_GPL(nvme_auth_gen_pubkey);
  357. int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm,
  358. u8 *ctrl_key, size_t ctrl_key_len,
  359. u8 *sess_key, size_t sess_key_len)
  360. {
  361. struct kpp_request *req;
  362. struct crypto_wait wait;
  363. struct scatterlist src, dst;
  364. int ret;
  365. req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
  366. if (!req)
  367. return -ENOMEM;
  368. crypto_init_wait(&wait);
  369. sg_init_one(&src, ctrl_key, ctrl_key_len);
  370. kpp_request_set_input(req, &src, ctrl_key_len);
  371. sg_init_one(&dst, sess_key, sess_key_len);
  372. kpp_request_set_output(req, &dst, sess_key_len);
  373. kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
  374. crypto_req_done, &wait);
  375. ret = crypto_wait_req(crypto_kpp_compute_shared_secret(req), &wait);
  376. kpp_request_free(req);
  377. return ret;
  378. }
  379. EXPORT_SYMBOL_GPL(nvme_auth_gen_shared_secret);
  380. int nvme_auth_generate_key(u8 *secret, struct nvme_dhchap_key **ret_key)
  381. {
  382. struct nvme_dhchap_key *key;
  383. u8 key_hash;
  384. if (!secret) {
  385. *ret_key = NULL;
  386. return 0;
  387. }
  388. if (sscanf(secret, "DHHC-1:%hhd:%*s:", &key_hash) != 1)
  389. return -EINVAL;
  390. /* Pass in the secret without the 'DHHC-1:XX:' prefix */
  391. key = nvme_auth_extract_key(secret + 10, key_hash);
  392. if (IS_ERR(key)) {
  393. *ret_key = NULL;
  394. return PTR_ERR(key);
  395. }
  396. *ret_key = key;
  397. return 0;
  398. }
  399. EXPORT_SYMBOL_GPL(nvme_auth_generate_key);
  400. /**
  401. * nvme_auth_generate_psk - Generate a PSK for TLS
  402. * @hmac_id: Hash function identifier
  403. * @skey: Session key
  404. * @skey_len: Length of @skey
  405. * @c1: Value of challenge C1
  406. * @c2: Value of challenge C2
  407. * @hash_len: Hash length of the hash algorithm
  408. * @ret_psk: Pointer to the resulting generated PSK
  409. * @ret_len: length of @ret_psk
  410. *
  411. * Generate a PSK for TLS as specified in NVMe base specification, section
  412. * 8.13.5.9: Generated PSK for TLS
  413. *
  414. * The generated PSK for TLS shall be computed applying the HMAC function
  415. * using the hash function H( ) selected by the HashID parameter in the
  416. * DH-HMAC-CHAP_Challenge message with the session key KS as key to the
  417. * concatenation of the two challenges C1 and C2 (i.e., generated
  418. * PSK = HMAC(KS, C1 || C2)).
  419. *
  420. * Returns 0 on success with a valid generated PSK pointer in @ret_psk and
  421. * the length of @ret_psk in @ret_len, or a negative error number otherwise.
  422. */
  423. int nvme_auth_generate_psk(u8 hmac_id, u8 *skey, size_t skey_len,
  424. u8 *c1, u8 *c2, size_t hash_len, u8 **ret_psk, size_t *ret_len)
  425. {
  426. struct crypto_shash *tfm;
  427. SHASH_DESC_ON_STACK(shash, tfm);
  428. u8 *psk;
  429. const char *hmac_name;
  430. int ret, psk_len;
  431. if (!c1 || !c2)
  432. return -EINVAL;
  433. hmac_name = nvme_auth_hmac_name(hmac_id);
  434. if (!hmac_name) {
  435. pr_warn("%s: invalid hash algorithm %d\n",
  436. __func__, hmac_id);
  437. return -EINVAL;
  438. }
  439. tfm = crypto_alloc_shash(hmac_name, 0, 0);
  440. if (IS_ERR(tfm))
  441. return PTR_ERR(tfm);
  442. psk_len = crypto_shash_digestsize(tfm);
  443. psk = kzalloc(psk_len, GFP_KERNEL);
  444. if (!psk) {
  445. ret = -ENOMEM;
  446. goto out_free_tfm;
  447. }
  448. shash->tfm = tfm;
  449. ret = crypto_shash_setkey(tfm, skey, skey_len);
  450. if (ret)
  451. goto out_free_psk;
  452. ret = crypto_shash_init(shash);
  453. if (ret)
  454. goto out_free_psk;
  455. ret = crypto_shash_update(shash, c1, hash_len);
  456. if (ret)
  457. goto out_free_psk;
  458. ret = crypto_shash_update(shash, c2, hash_len);
  459. if (ret)
  460. goto out_free_psk;
  461. ret = crypto_shash_final(shash, psk);
  462. if (!ret) {
  463. *ret_psk = psk;
  464. *ret_len = psk_len;
  465. }
  466. out_free_psk:
  467. if (ret)
  468. kfree_sensitive(psk);
  469. out_free_tfm:
  470. crypto_free_shash(tfm);
  471. return ret;
  472. }
  473. EXPORT_SYMBOL_GPL(nvme_auth_generate_psk);
  474. /**
  475. * nvme_auth_generate_digest - Generate TLS PSK digest
  476. * @hmac_id: Hash function identifier
  477. * @psk: Generated input PSK
  478. * @psk_len: Length of @psk
  479. * @subsysnqn: NQN of the subsystem
  480. * @hostnqn: NQN of the host
  481. * @ret_digest: Pointer to the returned digest
  482. *
  483. * Generate a TLS PSK digest as specified in TP8018 Section 3.6.1.3:
  484. * TLS PSK and PSK identity Derivation
  485. *
  486. * The PSK digest shall be computed by encoding in Base64 (refer to RFC
  487. * 4648) the result of the application of the HMAC function using the hash
  488. * function specified in item 4 above (ie the hash function of the cipher
  489. * suite associated with the PSK identity) with the PSK as HMAC key to the
  490. * concatenation of:
  491. * - the NQN of the host (i.e., NQNh) not including the null terminator;
  492. * - a space character;
  493. * - the NQN of the NVM subsystem (i.e., NQNc) not including the null
  494. * terminator;
  495. * - a space character; and
  496. * - the seventeen ASCII characters "NVMe-over-Fabrics"
  497. * (i.e., <PSK digest> = Base64(HMAC(PSK, NQNh || " " || NQNc || " " ||
  498. * "NVMe-over-Fabrics"))).
  499. * The length of the PSK digest depends on the hash function used to compute
  500. * it as follows:
  501. * - If the SHA-256 hash function is used, the resulting PSK digest is 44
  502. * characters long; or
  503. * - If the SHA-384 hash function is used, the resulting PSK digest is 64
  504. * characters long.
  505. *
  506. * Returns 0 on success with a valid digest pointer in @ret_digest, or a
  507. * negative error number on failure.
  508. */
  509. int nvme_auth_generate_digest(u8 hmac_id, u8 *psk, size_t psk_len,
  510. char *subsysnqn, char *hostnqn, u8 **ret_digest)
  511. {
  512. struct crypto_shash *tfm;
  513. SHASH_DESC_ON_STACK(shash, tfm);
  514. u8 *digest, *enc;
  515. const char *hmac_name;
  516. size_t digest_len, hmac_len;
  517. int ret;
  518. if (WARN_ON(!subsysnqn || !hostnqn))
  519. return -EINVAL;
  520. hmac_name = nvme_auth_hmac_name(hmac_id);
  521. if (!hmac_name) {
  522. pr_warn("%s: invalid hash algorithm %d\n",
  523. __func__, hmac_id);
  524. return -EINVAL;
  525. }
  526. switch (nvme_auth_hmac_hash_len(hmac_id)) {
  527. case 32:
  528. hmac_len = 44;
  529. break;
  530. case 48:
  531. hmac_len = 64;
  532. break;
  533. default:
  534. pr_warn("%s: invalid hash algorithm '%s'\n",
  535. __func__, hmac_name);
  536. return -EINVAL;
  537. }
  538. enc = kzalloc(hmac_len + 1, GFP_KERNEL);
  539. if (!enc)
  540. return -ENOMEM;
  541. tfm = crypto_alloc_shash(hmac_name, 0, 0);
  542. if (IS_ERR(tfm)) {
  543. ret = PTR_ERR(tfm);
  544. goto out_free_enc;
  545. }
  546. digest_len = crypto_shash_digestsize(tfm);
  547. digest = kzalloc(digest_len, GFP_KERNEL);
  548. if (!digest) {
  549. ret = -ENOMEM;
  550. goto out_free_tfm;
  551. }
  552. shash->tfm = tfm;
  553. ret = crypto_shash_setkey(tfm, psk, psk_len);
  554. if (ret)
  555. goto out_free_digest;
  556. ret = crypto_shash_init(shash);
  557. if (ret)
  558. goto out_free_digest;
  559. ret = crypto_shash_update(shash, hostnqn, strlen(hostnqn));
  560. if (ret)
  561. goto out_free_digest;
  562. ret = crypto_shash_update(shash, " ", 1);
  563. if (ret)
  564. goto out_free_digest;
  565. ret = crypto_shash_update(shash, subsysnqn, strlen(subsysnqn));
  566. if (ret)
  567. goto out_free_digest;
  568. ret = crypto_shash_update(shash, " NVMe-over-Fabrics", 18);
  569. if (ret)
  570. goto out_free_digest;
  571. ret = crypto_shash_final(shash, digest);
  572. if (ret)
  573. goto out_free_digest;
  574. ret = base64_encode(digest, digest_len, enc, true, BASE64_STD);
  575. if (ret < hmac_len) {
  576. ret = -ENOKEY;
  577. goto out_free_digest;
  578. }
  579. *ret_digest = enc;
  580. ret = 0;
  581. out_free_digest:
  582. kfree_sensitive(digest);
  583. out_free_tfm:
  584. crypto_free_shash(tfm);
  585. out_free_enc:
  586. if (ret)
  587. kfree_sensitive(enc);
  588. return ret;
  589. }
  590. EXPORT_SYMBOL_GPL(nvme_auth_generate_digest);
  591. /**
  592. * hkdf_expand_label - HKDF-Expand-Label (RFC 8846 section 7.1)
  593. * @hmac_tfm: hash context keyed with pseudorandom key
  594. * @label: ASCII label without "tls13 " prefix
  595. * @labellen: length of @label
  596. * @context: context bytes
  597. * @contextlen: length of @context
  598. * @okm: output keying material
  599. * @okmlen: length of @okm
  600. *
  601. * Build the TLS 1.3 HkdfLabel structure and invoke hkdf_expand().
  602. *
  603. * Returns 0 on success with output keying material stored in @okm,
  604. * or a negative errno value otherwise.
  605. */
  606. static int hkdf_expand_label(struct crypto_shash *hmac_tfm,
  607. const u8 *label, unsigned int labellen,
  608. const u8 *context, unsigned int contextlen,
  609. u8 *okm, unsigned int okmlen)
  610. {
  611. int err;
  612. u8 *info;
  613. unsigned int infolen;
  614. const char *tls13_prefix = "tls13 ";
  615. unsigned int prefixlen = strlen(tls13_prefix);
  616. if (WARN_ON(labellen > (255 - prefixlen)))
  617. return -EINVAL;
  618. if (WARN_ON(contextlen > 255))
  619. return -EINVAL;
  620. infolen = 2 + (1 + prefixlen + labellen) + (1 + contextlen);
  621. info = kzalloc(infolen, GFP_KERNEL);
  622. if (!info)
  623. return -ENOMEM;
  624. /* HkdfLabel.Length */
  625. put_unaligned_be16(okmlen, info);
  626. /* HkdfLabel.Label */
  627. info[2] = prefixlen + labellen;
  628. memcpy(info + 3, tls13_prefix, prefixlen);
  629. memcpy(info + 3 + prefixlen, label, labellen);
  630. /* HkdfLabel.Context */
  631. info[3 + prefixlen + labellen] = contextlen;
  632. memcpy(info + 4 + prefixlen + labellen, context, contextlen);
  633. err = hkdf_expand(hmac_tfm, info, infolen, okm, okmlen);
  634. kfree_sensitive(info);
  635. return err;
  636. }
  637. /**
  638. * nvme_auth_derive_tls_psk - Derive TLS PSK
  639. * @hmac_id: Hash function identifier
  640. * @psk: generated input PSK
  641. * @psk_len: size of @psk
  642. * @psk_digest: TLS PSK digest
  643. * @ret_psk: Pointer to the resulting TLS PSK
  644. *
  645. * Derive a TLS PSK as specified in TP8018 Section 3.6.1.3:
  646. * TLS PSK and PSK identity Derivation
  647. *
  648. * The TLS PSK shall be derived as follows from an input PSK
  649. * (i.e., either a retained PSK or a generated PSK) and a PSK
  650. * identity using the HKDF-Extract and HKDF-Expand-Label operations
  651. * (refer to RFC 5869 and RFC 8446) where the hash function is the
  652. * one specified by the hash specifier of the PSK identity:
  653. * 1. PRK = HKDF-Extract(0, Input PSK); and
  654. * 2. TLS PSK = HKDF-Expand-Label(PRK, "nvme-tls-psk", PskIdentityContext, L),
  655. * where PskIdentityContext is the hash identifier indicated in
  656. * the PSK identity concatenated to a space character and to the
  657. * Base64 PSK digest (i.e., "<hash> <PSK digest>") and L is the
  658. * output size in bytes of the hash function (i.e., 32 for SHA-256
  659. * and 48 for SHA-384).
  660. *
  661. * Returns 0 on success with a valid psk pointer in @ret_psk or a negative
  662. * error number otherwise.
  663. */
  664. int nvme_auth_derive_tls_psk(int hmac_id, u8 *psk, size_t psk_len,
  665. u8 *psk_digest, u8 **ret_psk)
  666. {
  667. struct crypto_shash *hmac_tfm;
  668. const char *hmac_name;
  669. const char *label = "nvme-tls-psk";
  670. static const char default_salt[HKDF_MAX_HASHLEN];
  671. size_t prk_len;
  672. const char *ctx;
  673. unsigned char *prk, *tls_key;
  674. int ret;
  675. hmac_name = nvme_auth_hmac_name(hmac_id);
  676. if (!hmac_name) {
  677. pr_warn("%s: invalid hash algorithm %d\n",
  678. __func__, hmac_id);
  679. return -EINVAL;
  680. }
  681. if (hmac_id == NVME_AUTH_HASH_SHA512) {
  682. pr_warn("%s: unsupported hash algorithm %s\n",
  683. __func__, hmac_name);
  684. return -EINVAL;
  685. }
  686. hmac_tfm = crypto_alloc_shash(hmac_name, 0, 0);
  687. if (IS_ERR(hmac_tfm))
  688. return PTR_ERR(hmac_tfm);
  689. prk_len = crypto_shash_digestsize(hmac_tfm);
  690. prk = kzalloc(prk_len, GFP_KERNEL);
  691. if (!prk) {
  692. ret = -ENOMEM;
  693. goto out_free_shash;
  694. }
  695. if (WARN_ON(prk_len > HKDF_MAX_HASHLEN)) {
  696. ret = -EINVAL;
  697. goto out_free_prk;
  698. }
  699. ret = hkdf_extract(hmac_tfm, psk, psk_len,
  700. default_salt, prk_len, prk);
  701. if (ret)
  702. goto out_free_prk;
  703. ret = crypto_shash_setkey(hmac_tfm, prk, prk_len);
  704. if (ret)
  705. goto out_free_prk;
  706. ctx = kasprintf(GFP_KERNEL, "%02d %s", hmac_id, psk_digest);
  707. if (!ctx) {
  708. ret = -ENOMEM;
  709. goto out_free_prk;
  710. }
  711. tls_key = kzalloc(psk_len, GFP_KERNEL);
  712. if (!tls_key) {
  713. ret = -ENOMEM;
  714. goto out_free_ctx;
  715. }
  716. ret = hkdf_expand_label(hmac_tfm,
  717. label, strlen(label),
  718. ctx, strlen(ctx),
  719. tls_key, psk_len);
  720. if (ret) {
  721. kfree(tls_key);
  722. goto out_free_ctx;
  723. }
  724. *ret_psk = tls_key;
  725. out_free_ctx:
  726. kfree(ctx);
  727. out_free_prk:
  728. kfree(prk);
  729. out_free_shash:
  730. crypto_free_shash(hmac_tfm);
  731. return ret;
  732. }
  733. EXPORT_SYMBOL_GPL(nvme_auth_derive_tls_psk);
  734. MODULE_DESCRIPTION("NVMe Authentication framework");
  735. MODULE_LICENSE("GPL v2");