Loading drivers/nvme/common/auth.c +134 −0 Original line number Diff line number Diff line Loading @@ -558,5 +558,139 @@ int nvme_auth_generate_psk(u8 hmac_id, u8 *skey, size_t skey_len, } EXPORT_SYMBOL_GPL(nvme_auth_generate_psk); /** * nvme_auth_generate_digest - Generate TLS PSK digest * @hmac_id: Hash function identifier * @psk: Generated input PSK * @psk_len: Length of @psk * @subsysnqn: NQN of the subsystem * @hostnqn: NQN of the host * @ret_digest: Pointer to the returned digest * * Generate a TLS PSK digest as specified in TP8018 Section 3.6.1.3: * TLS PSK and PSK identity Derivation * * The PSK digest shall be computed by encoding in Base64 (refer to RFC * 4648) the result of the application of the HMAC function using the hash * function specified in item 4 above (ie the hash function of the cipher * suite associated with the PSK identity) with the PSK as HMAC key to the * concatenation of: * - the NQN of the host (i.e., NQNh) not including the null terminator; * - a space character; * - the NQN of the NVM subsystem (i.e., NQNc) not including the null * terminator; * - a space character; and * - the seventeen ASCII characters "NVMe-over-Fabrics" * (i.e., <PSK digest> = Base64(HMAC(PSK, NQNh || " " || NQNc || " " || * "NVMe-over-Fabrics"))). * The length of the PSK digest depends on the hash function used to compute * it as follows: * - If the SHA-256 hash function is used, the resulting PSK digest is 44 * characters long; or * - If the SHA-384 hash function is used, the resulting PSK digest is 64 * characters long. * * Returns 0 on success with a valid digest pointer in @ret_digest, or a * negative error number on failure. */ int nvme_auth_generate_digest(u8 hmac_id, u8 *psk, size_t psk_len, char *subsysnqn, char *hostnqn, u8 **ret_digest) { struct crypto_shash *tfm; SHASH_DESC_ON_STACK(shash, tfm); u8 *digest, *enc; const char *hmac_name; size_t digest_len, hmac_len; int ret; if (WARN_ON(!subsysnqn || !hostnqn)) return -EINVAL; hmac_name = nvme_auth_hmac_name(hmac_id); if (!hmac_name) { pr_warn("%s: invalid hash algorithm %d\n", __func__, hmac_id); return -EINVAL; } switch (nvme_auth_hmac_hash_len(hmac_id)) { case 32: hmac_len = 44; break; case 48: hmac_len = 64; break; default: pr_warn("%s: invalid hash algorithm '%s'\n", __func__, hmac_name); return -EINVAL; } enc = kzalloc(hmac_len + 1, GFP_KERNEL); if (!enc) return -ENOMEM; tfm = crypto_alloc_shash(hmac_name, 0, 0); if (IS_ERR(tfm)) { ret = PTR_ERR(tfm); goto out_free_enc; } digest_len = crypto_shash_digestsize(tfm); digest = kzalloc(digest_len, GFP_KERNEL); if (!digest) { ret = -ENOMEM; goto out_free_tfm; } shash->tfm = tfm; ret = crypto_shash_setkey(tfm, psk, psk_len); if (ret) goto out_free_digest; ret = crypto_shash_init(shash); if (ret) goto out_free_digest; ret = crypto_shash_update(shash, hostnqn, strlen(hostnqn)); if (ret) goto out_free_digest; ret = crypto_shash_update(shash, " ", 1); if (ret) goto out_free_digest; ret = crypto_shash_update(shash, subsysnqn, strlen(subsysnqn)); if (ret) goto out_free_digest; ret = crypto_shash_update(shash, " NVMe-over-Fabrics", 18); if (ret) goto out_free_digest; ret = crypto_shash_final(shash, digest); if (ret) goto out_free_digest; ret = base64_encode(digest, digest_len, enc); if (ret < hmac_len) { ret = -ENOKEY; goto out_free_digest; } *ret_digest = enc; ret = 0; out_free_digest: kfree_sensitive(digest); out_free_tfm: crypto_free_shash(tfm); out_free_enc: if (ret) kfree_sensitive(enc); return ret; } EXPORT_SYMBOL_GPL(nvme_auth_generate_digest); MODULE_DESCRIPTION("NVMe Authentication framework"); MODULE_LICENSE("GPL v2"); include/linux/nvme-auth.h +2 −0 Original line number Diff line number Diff line Loading @@ -43,5 +43,7 @@ int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm, int nvme_auth_generate_psk(u8 hmac_id, u8 *skey, size_t skey_len, u8 *c1, u8 *c2, size_t hash_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); #endif /* _NVME_AUTH_H */ Loading
drivers/nvme/common/auth.c +134 −0 Original line number Diff line number Diff line Loading @@ -558,5 +558,139 @@ int nvme_auth_generate_psk(u8 hmac_id, u8 *skey, size_t skey_len, } EXPORT_SYMBOL_GPL(nvme_auth_generate_psk); /** * nvme_auth_generate_digest - Generate TLS PSK digest * @hmac_id: Hash function identifier * @psk: Generated input PSK * @psk_len: Length of @psk * @subsysnqn: NQN of the subsystem * @hostnqn: NQN of the host * @ret_digest: Pointer to the returned digest * * Generate a TLS PSK digest as specified in TP8018 Section 3.6.1.3: * TLS PSK and PSK identity Derivation * * The PSK digest shall be computed by encoding in Base64 (refer to RFC * 4648) the result of the application of the HMAC function using the hash * function specified in item 4 above (ie the hash function of the cipher * suite associated with the PSK identity) with the PSK as HMAC key to the * concatenation of: * - the NQN of the host (i.e., NQNh) not including the null terminator; * - a space character; * - the NQN of the NVM subsystem (i.e., NQNc) not including the null * terminator; * - a space character; and * - the seventeen ASCII characters "NVMe-over-Fabrics" * (i.e., <PSK digest> = Base64(HMAC(PSK, NQNh || " " || NQNc || " " || * "NVMe-over-Fabrics"))). * The length of the PSK digest depends on the hash function used to compute * it as follows: * - If the SHA-256 hash function is used, the resulting PSK digest is 44 * characters long; or * - If the SHA-384 hash function is used, the resulting PSK digest is 64 * characters long. * * Returns 0 on success with a valid digest pointer in @ret_digest, or a * negative error number on failure. */ int nvme_auth_generate_digest(u8 hmac_id, u8 *psk, size_t psk_len, char *subsysnqn, char *hostnqn, u8 **ret_digest) { struct crypto_shash *tfm; SHASH_DESC_ON_STACK(shash, tfm); u8 *digest, *enc; const char *hmac_name; size_t digest_len, hmac_len; int ret; if (WARN_ON(!subsysnqn || !hostnqn)) return -EINVAL; hmac_name = nvme_auth_hmac_name(hmac_id); if (!hmac_name) { pr_warn("%s: invalid hash algorithm %d\n", __func__, hmac_id); return -EINVAL; } switch (nvme_auth_hmac_hash_len(hmac_id)) { case 32: hmac_len = 44; break; case 48: hmac_len = 64; break; default: pr_warn("%s: invalid hash algorithm '%s'\n", __func__, hmac_name); return -EINVAL; } enc = kzalloc(hmac_len + 1, GFP_KERNEL); if (!enc) return -ENOMEM; tfm = crypto_alloc_shash(hmac_name, 0, 0); if (IS_ERR(tfm)) { ret = PTR_ERR(tfm); goto out_free_enc; } digest_len = crypto_shash_digestsize(tfm); digest = kzalloc(digest_len, GFP_KERNEL); if (!digest) { ret = -ENOMEM; goto out_free_tfm; } shash->tfm = tfm; ret = crypto_shash_setkey(tfm, psk, psk_len); if (ret) goto out_free_digest; ret = crypto_shash_init(shash); if (ret) goto out_free_digest; ret = crypto_shash_update(shash, hostnqn, strlen(hostnqn)); if (ret) goto out_free_digest; ret = crypto_shash_update(shash, " ", 1); if (ret) goto out_free_digest; ret = crypto_shash_update(shash, subsysnqn, strlen(subsysnqn)); if (ret) goto out_free_digest; ret = crypto_shash_update(shash, " NVMe-over-Fabrics", 18); if (ret) goto out_free_digest; ret = crypto_shash_final(shash, digest); if (ret) goto out_free_digest; ret = base64_encode(digest, digest_len, enc); if (ret < hmac_len) { ret = -ENOKEY; goto out_free_digest; } *ret_digest = enc; ret = 0; out_free_digest: kfree_sensitive(digest); out_free_tfm: crypto_free_shash(tfm); out_free_enc: if (ret) kfree_sensitive(enc); return ret; } EXPORT_SYMBOL_GPL(nvme_auth_generate_digest); MODULE_DESCRIPTION("NVMe Authentication framework"); MODULE_LICENSE("GPL v2");
include/linux/nvme-auth.h +2 −0 Original line number Diff line number Diff line Loading @@ -43,5 +43,7 @@ int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm, int nvme_auth_generate_psk(u8 hmac_id, u8 *skey, size_t skey_len, u8 *c1, u8 *c2, size_t hash_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); #endif /* _NVME_AUTH_H */