Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nvme: add nvme_auth_derive_tls_psk()

Add a function to derive the TLS PSK as specified TP8018.

Signed-off-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Keith Busch <kbusch@kernel.org>

authored by

Hannes Reinecke and committed by
Keith Busch
9d5c0fff 71972b9f

+119
+1
drivers/nvme/common/Kconfig
··· 12 12 select CRYPTO_SHA512 13 13 select CRYPTO_DH 14 14 select CRYPTO_DH_RFC7919_GROUPS 15 + select CRYPTO_HKDF
+116
drivers/nvme/common/auth.c
··· 15 15 #include <linux/nvme.h> 16 16 #include <linux/nvme-auth.h> 17 17 18 + #define HKDF_MAX_HASHLEN 64 19 + 18 20 static u32 nvme_dhchap_seqnum; 19 21 static DEFINE_MUTEX(nvme_dhchap_mutex); 20 22 ··· 693 691 return ret; 694 692 } 695 693 EXPORT_SYMBOL_GPL(nvme_auth_generate_digest); 694 + 695 + /** 696 + * nvme_auth_derive_tls_psk - Derive TLS PSK 697 + * @hmac_id: Hash function identifier 698 + * @psk: generated input PSK 699 + * @psk_len: size of @psk 700 + * @psk_digest: TLS PSK digest 701 + * @ret_psk: Pointer to the resulting TLS PSK 702 + * 703 + * Derive a TLS PSK as specified in TP8018 Section 3.6.1.3: 704 + * TLS PSK and PSK identity Derivation 705 + * 706 + * The TLS PSK shall be derived as follows from an input PSK 707 + * (i.e., either a retained PSK or a generated PSK) and a PSK 708 + * identity using the HKDF-Extract and HKDF-Expand-Label operations 709 + * (refer to RFC 5869 and RFC 8446) where the hash function is the 710 + * one specified by the hash specifier of the PSK identity: 711 + * 1. PRK = HKDF-Extract(0, Input PSK); and 712 + * 2. TLS PSK = HKDF-Expand-Label(PRK, "nvme-tls-psk", PskIdentityContext, L), 713 + * where PskIdentityContext is the hash identifier indicated in 714 + * the PSK identity concatenated to a space character and to the 715 + * Base64 PSK digest (i.e., "<hash> <PSK digest>") and L is the 716 + * output size in bytes of the hash function (i.e., 32 for SHA-256 717 + * and 48 for SHA-384). 718 + * 719 + * Returns 0 on success with a valid psk pointer in @ret_psk or a negative 720 + * error number otherwise. 721 + */ 722 + int nvme_auth_derive_tls_psk(int hmac_id, u8 *psk, size_t psk_len, 723 + u8 *psk_digest, u8 **ret_psk) 724 + { 725 + struct crypto_shash *hmac_tfm; 726 + const char *hmac_name; 727 + const char *psk_prefix = "tls13 nvme-tls-psk"; 728 + static const char default_salt[HKDF_MAX_HASHLEN]; 729 + size_t info_len, prk_len; 730 + char *info; 731 + unsigned char *prk, *tls_key; 732 + int ret; 733 + 734 + hmac_name = nvme_auth_hmac_name(hmac_id); 735 + if (!hmac_name) { 736 + pr_warn("%s: invalid hash algorithm %d\n", 737 + __func__, hmac_id); 738 + return -EINVAL; 739 + } 740 + if (hmac_id == NVME_AUTH_HASH_SHA512) { 741 + pr_warn("%s: unsupported hash algorithm %s\n", 742 + __func__, hmac_name); 743 + return -EINVAL; 744 + } 745 + 746 + hmac_tfm = crypto_alloc_shash(hmac_name, 0, 0); 747 + if (IS_ERR(hmac_tfm)) 748 + return PTR_ERR(hmac_tfm); 749 + 750 + prk_len = crypto_shash_digestsize(hmac_tfm); 751 + prk = kzalloc(prk_len, GFP_KERNEL); 752 + if (!prk) { 753 + ret = -ENOMEM; 754 + goto out_free_shash; 755 + } 756 + 757 + if (WARN_ON(prk_len > HKDF_MAX_HASHLEN)) { 758 + ret = -EINVAL; 759 + goto out_free_prk; 760 + } 761 + ret = hkdf_extract(hmac_tfm, psk, psk_len, 762 + default_salt, prk_len, prk); 763 + if (ret) 764 + goto out_free_prk; 765 + 766 + ret = crypto_shash_setkey(hmac_tfm, prk, prk_len); 767 + if (ret) 768 + goto out_free_prk; 769 + 770 + /* 771 + * 2 addtional bytes for the length field from HDKF-Expand-Label, 772 + * 2 addtional bytes for the HMAC ID, and one byte for the space 773 + * separator. 774 + */ 775 + info_len = strlen(psk_digest) + strlen(psk_prefix) + 5; 776 + info = kzalloc(info_len + 1, GFP_KERNEL); 777 + if (!info) { 778 + ret = -ENOMEM; 779 + goto out_free_prk; 780 + } 781 + 782 + put_unaligned_be16(psk_len, info); 783 + memcpy(info + 2, psk_prefix, strlen(psk_prefix)); 784 + sprintf(info + 2 + strlen(psk_prefix), "%02d %s", hmac_id, psk_digest); 785 + 786 + tls_key = kzalloc(psk_len, GFP_KERNEL); 787 + if (!tls_key) { 788 + ret = -ENOMEM; 789 + goto out_free_info; 790 + } 791 + ret = hkdf_expand(hmac_tfm, info, info_len, tls_key, psk_len); 792 + if (ret) { 793 + kfree(tls_key); 794 + goto out_free_info; 795 + } 796 + *ret_psk = tls_key; 797 + 798 + out_free_info: 799 + kfree(info); 800 + out_free_prk: 801 + kfree(prk); 802 + out_free_shash: 803 + crypto_free_shash(hmac_tfm); 804 + 805 + return ret; 806 + } 807 + EXPORT_SYMBOL_GPL(nvme_auth_derive_tls_psk); 696 808 697 809 MODULE_DESCRIPTION("NVMe Authentication framework"); 698 810 MODULE_LICENSE("GPL v2");
+2
include/linux/nvme-auth.h
··· 45 45 u8 **ret_psk, size_t *ret_len); 46 46 int nvme_auth_generate_digest(u8 hmac_id, u8 *psk, size_t psk_len, 47 47 char *subsysnqn, char *hostnqn, u8 **ret_digest); 48 + int nvme_auth_derive_tls_psk(int hmac_id, u8 *psk, size_t psk_len, 49 + u8 *psk_digest, u8 **ret_psk); 48 50 49 51 #endif /* _NVME_AUTH_H */