diff options
| -rw-r--r-- | drivers/nvme/common/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/nvme/common/auth.c | 66 | ||||
| -rw-r--r-- | include/linux/nvme-auth.h | 14 |
3 files changed, 82 insertions, 0 deletions
diff --git a/drivers/nvme/common/Kconfig b/drivers/nvme/common/Kconfig index d19988c13af5..1ec507d1f9b5 100644 --- a/drivers/nvme/common/Kconfig +++ b/drivers/nvme/common/Kconfig @@ -13,6 +13,8 @@ config NVME_AUTH select CRYPTO_DH select CRYPTO_DH_RFC7919_GROUPS select CRYPTO_HKDF + select CRYPTO_LIB_SHA256 + select CRYPTO_LIB_SHA512 config NVME_AUTH_KUNIT_TEST tristate "KUnit tests for NVMe authentication" if !KUNIT_ALL_TESTS diff --git a/drivers/nvme/common/auth.c b/drivers/nvme/common/auth.c index 9e33fc02cf51..00f21176181f 100644 --- a/drivers/nvme/common/auth.c +++ b/drivers/nvme/common/auth.c @@ -12,6 +12,7 @@ #include <crypto/hash.h> #include <crypto/dh.h> #include <crypto/hkdf.h> +#include <crypto/sha2.h> #include <linux/nvme.h> #include <linux/nvme-auth.h> @@ -234,6 +235,71 @@ void nvme_auth_free_key(struct nvme_dhchap_key *key) } EXPORT_SYMBOL_GPL(nvme_auth_free_key); +/* + * Start computing an HMAC value, given the algorithm ID and raw key. + * + * The context should be zeroized at the end of its lifetime. The caller can do + * that implicitly by calling nvme_auth_hmac_final(), or explicitly (needed when + * a context is abandoned without finalizing it) by calling memzero_explicit(). + */ +int nvme_auth_hmac_init(struct nvme_auth_hmac_ctx *hmac, u8 hmac_id, + const u8 *key, size_t key_len) +{ + hmac->hmac_id = hmac_id; + switch (hmac_id) { + case NVME_AUTH_HASH_SHA256: + hmac_sha256_init_usingrawkey(&hmac->sha256, key, key_len); + return 0; + case NVME_AUTH_HASH_SHA384: + hmac_sha384_init_usingrawkey(&hmac->sha384, key, key_len); + return 0; + case NVME_AUTH_HASH_SHA512: + hmac_sha512_init_usingrawkey(&hmac->sha512, key, key_len); + return 0; + } + pr_warn("%s: invalid hash algorithm %d\n", __func__, hmac_id); + return -EINVAL; +} +EXPORT_SYMBOL_GPL(nvme_auth_hmac_init); + +void nvme_auth_hmac_update(struct nvme_auth_hmac_ctx *hmac, const u8 *data, + size_t data_len) +{ + switch (hmac->hmac_id) { + case NVME_AUTH_HASH_SHA256: + hmac_sha256_update(&hmac->sha256, data, data_len); + return; + case NVME_AUTH_HASH_SHA384: + hmac_sha384_update(&hmac->sha384, data, data_len); + return; + case NVME_AUTH_HASH_SHA512: + hmac_sha512_update(&hmac->sha512, data, data_len); + return; + } + /* Unreachable because nvme_auth_hmac_init() validated hmac_id */ + WARN_ON_ONCE(1); +} +EXPORT_SYMBOL_GPL(nvme_auth_hmac_update); + +/* Finish computing an HMAC value. Note that this zeroizes the HMAC context. */ +void nvme_auth_hmac_final(struct nvme_auth_hmac_ctx *hmac, u8 *out) +{ + switch (hmac->hmac_id) { + case NVME_AUTH_HASH_SHA256: + hmac_sha256_final(&hmac->sha256, out); + return; + case NVME_AUTH_HASH_SHA384: + hmac_sha384_final(&hmac->sha384, out); + return; + case NVME_AUTH_HASH_SHA512: + hmac_sha512_final(&hmac->sha512, out); + return; + } + /* Unreachable because nvme_auth_hmac_init() validated hmac_id */ + WARN_ON_ONCE(1); +} +EXPORT_SYMBOL_GPL(nvme_auth_hmac_final); + struct nvme_dhchap_key *nvme_auth_transform_key( const struct nvme_dhchap_key *key, const char *nqn) { diff --git a/include/linux/nvme-auth.h b/include/linux/nvme-auth.h index 02ca9a716256..940d0703eb1d 100644 --- a/include/linux/nvme-auth.h +++ b/include/linux/nvme-auth.h @@ -7,6 +7,7 @@ #define _NVME_AUTH_H #include <crypto/kpp.h> +#include <crypto/sha2.h> struct nvme_dhchap_key { size_t len; @@ -23,6 +24,19 @@ const char *nvme_auth_hmac_name(u8 hmac_id); const char *nvme_auth_digest_name(u8 hmac_id); size_t nvme_auth_hmac_hash_len(u8 hmac_id); u8 nvme_auth_hmac_id(const char *hmac_name); +struct nvme_auth_hmac_ctx { + u8 hmac_id; + union { + struct hmac_sha256_ctx sha256; + struct hmac_sha384_ctx sha384; + struct hmac_sha512_ctx sha512; + }; +}; +int nvme_auth_hmac_init(struct nvme_auth_hmac_ctx *hmac, u8 hmac_id, + const u8 *key, size_t key_len); +void nvme_auth_hmac_update(struct nvme_auth_hmac_ctx *hmac, const u8 *data, + size_t data_len); +void nvme_auth_hmac_final(struct nvme_auth_hmac_ctx *hmac, u8 *out); u32 nvme_auth_key_struct_size(u32 key_len); struct nvme_dhchap_key *nvme_auth_extract_key(const char *secret, u8 key_hash); |
