mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-04-13 09:59:31 +00:00
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>
This commit is contained in:
parent
71972b9ffe
commit
9d5c0fffee
3 changed files with 119 additions and 0 deletions
|
@ -12,3 +12,4 @@ config NVME_AUTH
|
|||
select CRYPTO_SHA512
|
||||
select CRYPTO_DH
|
||||
select CRYPTO_DH_RFC7919_GROUPS
|
||||
select CRYPTO_HKDF
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <linux/nvme.h>
|
||||
#include <linux/nvme-auth.h>
|
||||
|
||||
#define HKDF_MAX_HASHLEN 64
|
||||
|
||||
static u32 nvme_dhchap_seqnum;
|
||||
static DEFINE_MUTEX(nvme_dhchap_mutex);
|
||||
|
||||
|
@ -692,5 +694,119 @@ out_free_enc:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nvme_auth_generate_digest);
|
||||
|
||||
/**
|
||||
* nvme_auth_derive_tls_psk - Derive TLS PSK
|
||||
* @hmac_id: Hash function identifier
|
||||
* @psk: generated input PSK
|
||||
* @psk_len: size of @psk
|
||||
* @psk_digest: TLS PSK digest
|
||||
* @ret_psk: Pointer to the resulting TLS PSK
|
||||
*
|
||||
* Derive a TLS PSK as specified in TP8018 Section 3.6.1.3:
|
||||
* TLS PSK and PSK identity Derivation
|
||||
*
|
||||
* The TLS PSK shall be derived as follows from an input PSK
|
||||
* (i.e., either a retained PSK or a generated PSK) and a PSK
|
||||
* identity using the HKDF-Extract and HKDF-Expand-Label operations
|
||||
* (refer to RFC 5869 and RFC 8446) where the hash function is the
|
||||
* one specified by the hash specifier of the PSK identity:
|
||||
* 1. PRK = HKDF-Extract(0, Input PSK); and
|
||||
* 2. TLS PSK = HKDF-Expand-Label(PRK, "nvme-tls-psk", PskIdentityContext, L),
|
||||
* where PskIdentityContext is the hash identifier indicated in
|
||||
* the PSK identity concatenated to a space character and to the
|
||||
* Base64 PSK digest (i.e., "<hash> <PSK digest>") and L is the
|
||||
* output size in bytes of the hash function (i.e., 32 for SHA-256
|
||||
* and 48 for SHA-384).
|
||||
*
|
||||
* Returns 0 on success with a valid psk pointer in @ret_psk or a negative
|
||||
* error number otherwise.
|
||||
*/
|
||||
int nvme_auth_derive_tls_psk(int hmac_id, u8 *psk, size_t psk_len,
|
||||
u8 *psk_digest, u8 **ret_psk)
|
||||
{
|
||||
struct crypto_shash *hmac_tfm;
|
||||
const char *hmac_name;
|
||||
const char *psk_prefix = "tls13 nvme-tls-psk";
|
||||
static const char default_salt[HKDF_MAX_HASHLEN];
|
||||
size_t info_len, prk_len;
|
||||
char *info;
|
||||
unsigned char *prk, *tls_key;
|
||||
int ret;
|
||||
|
||||
hmac_name = nvme_auth_hmac_name(hmac_id);
|
||||
if (!hmac_name) {
|
||||
pr_warn("%s: invalid hash algorithm %d\n",
|
||||
__func__, hmac_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (hmac_id == NVME_AUTH_HASH_SHA512) {
|
||||
pr_warn("%s: unsupported hash algorithm %s\n",
|
||||
__func__, hmac_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hmac_tfm = crypto_alloc_shash(hmac_name, 0, 0);
|
||||
if (IS_ERR(hmac_tfm))
|
||||
return PTR_ERR(hmac_tfm);
|
||||
|
||||
prk_len = crypto_shash_digestsize(hmac_tfm);
|
||||
prk = kzalloc(prk_len, GFP_KERNEL);
|
||||
if (!prk) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free_shash;
|
||||
}
|
||||
|
||||
if (WARN_ON(prk_len > HKDF_MAX_HASHLEN)) {
|
||||
ret = -EINVAL;
|
||||
goto out_free_prk;
|
||||
}
|
||||
ret = hkdf_extract(hmac_tfm, psk, psk_len,
|
||||
default_salt, prk_len, prk);
|
||||
if (ret)
|
||||
goto out_free_prk;
|
||||
|
||||
ret = crypto_shash_setkey(hmac_tfm, prk, prk_len);
|
||||
if (ret)
|
||||
goto out_free_prk;
|
||||
|
||||
/*
|
||||
* 2 addtional bytes for the length field from HDKF-Expand-Label,
|
||||
* 2 addtional bytes for the HMAC ID, and one byte for the space
|
||||
* separator.
|
||||
*/
|
||||
info_len = strlen(psk_digest) + strlen(psk_prefix) + 5;
|
||||
info = kzalloc(info_len + 1, GFP_KERNEL);
|
||||
if (!info) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free_prk;
|
||||
}
|
||||
|
||||
put_unaligned_be16(psk_len, info);
|
||||
memcpy(info + 2, psk_prefix, strlen(psk_prefix));
|
||||
sprintf(info + 2 + strlen(psk_prefix), "%02d %s", hmac_id, psk_digest);
|
||||
|
||||
tls_key = kzalloc(psk_len, GFP_KERNEL);
|
||||
if (!tls_key) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free_info;
|
||||
}
|
||||
ret = hkdf_expand(hmac_tfm, info, info_len, tls_key, psk_len);
|
||||
if (ret) {
|
||||
kfree(tls_key);
|
||||
goto out_free_info;
|
||||
}
|
||||
*ret_psk = tls_key;
|
||||
|
||||
out_free_info:
|
||||
kfree(info);
|
||||
out_free_prk:
|
||||
kfree(prk);
|
||||
out_free_shash:
|
||||
crypto_free_shash(hmac_tfm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nvme_auth_derive_tls_psk);
|
||||
|
||||
MODULE_DESCRIPTION("NVMe Authentication framework");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -45,5 +45,7 @@ int nvme_auth_generate_psk(u8 hmac_id, u8 *skey, size_t skey_len,
|
|||
u8 **ret_psk, size_t *ret_len);
|
||||
int nvme_auth_generate_digest(u8 hmac_id, u8 *psk, size_t psk_len,
|
||||
char *subsysnqn, char *hostnqn, u8 **ret_digest);
|
||||
int nvme_auth_derive_tls_psk(int hmac_id, u8 *psk, size_t psk_len,
|
||||
u8 *psk_digest, u8 **ret_psk);
|
||||
|
||||
#endif /* _NVME_AUTH_H */
|
||||
|
|
Loading…
Add table
Reference in a new issue