Skip to content

Commit 71972b9

Browse files
Hannes Reineckekeithbusch
authored andcommitted
nvme: add nvme_auth_generate_digest()
Add a function to calculate the PSK digest as specified in TP8018. Signed-off-by: Hannes Reinecke <[email protected]> Reviewed-by: Sagi Grimberg <[email protected]> Signed-off-by: Keith Busch <[email protected]>
1 parent 5c12a9c commit 71972b9

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed

drivers/nvme/common/auth.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,5 +558,139 @@ int nvme_auth_generate_psk(u8 hmac_id, u8 *skey, size_t skey_len,
558558
}
559559
EXPORT_SYMBOL_GPL(nvme_auth_generate_psk);
560560

561+
/**
562+
* nvme_auth_generate_digest - Generate TLS PSK digest
563+
* @hmac_id: Hash function identifier
564+
* @psk: Generated input PSK
565+
* @psk_len: Length of @psk
566+
* @subsysnqn: NQN of the subsystem
567+
* @hostnqn: NQN of the host
568+
* @ret_digest: Pointer to the returned digest
569+
*
570+
* Generate a TLS PSK digest as specified in TP8018 Section 3.6.1.3:
571+
* TLS PSK and PSK identity Derivation
572+
*
573+
* The PSK digest shall be computed by encoding in Base64 (refer to RFC
574+
* 4648) the result of the application of the HMAC function using the hash
575+
* function specified in item 4 above (ie the hash function of the cipher
576+
* suite associated with the PSK identity) with the PSK as HMAC key to the
577+
* concatenation of:
578+
* - the NQN of the host (i.e., NQNh) not including the null terminator;
579+
* - a space character;
580+
* - the NQN of the NVM subsystem (i.e., NQNc) not including the null
581+
* terminator;
582+
* - a space character; and
583+
* - the seventeen ASCII characters "NVMe-over-Fabrics"
584+
* (i.e., <PSK digest> = Base64(HMAC(PSK, NQNh || " " || NQNc || " " ||
585+
* "NVMe-over-Fabrics"))).
586+
* The length of the PSK digest depends on the hash function used to compute
587+
* it as follows:
588+
* - If the SHA-256 hash function is used, the resulting PSK digest is 44
589+
* characters long; or
590+
* - If the SHA-384 hash function is used, the resulting PSK digest is 64
591+
* characters long.
592+
*
593+
* Returns 0 on success with a valid digest pointer in @ret_digest, or a
594+
* negative error number on failure.
595+
*/
596+
int nvme_auth_generate_digest(u8 hmac_id, u8 *psk, size_t psk_len,
597+
char *subsysnqn, char *hostnqn, u8 **ret_digest)
598+
{
599+
struct crypto_shash *tfm;
600+
SHASH_DESC_ON_STACK(shash, tfm);
601+
u8 *digest, *enc;
602+
const char *hmac_name;
603+
size_t digest_len, hmac_len;
604+
int ret;
605+
606+
if (WARN_ON(!subsysnqn || !hostnqn))
607+
return -EINVAL;
608+
609+
hmac_name = nvme_auth_hmac_name(hmac_id);
610+
if (!hmac_name) {
611+
pr_warn("%s: invalid hash algorithm %d\n",
612+
__func__, hmac_id);
613+
return -EINVAL;
614+
}
615+
616+
switch (nvme_auth_hmac_hash_len(hmac_id)) {
617+
case 32:
618+
hmac_len = 44;
619+
break;
620+
case 48:
621+
hmac_len = 64;
622+
break;
623+
default:
624+
pr_warn("%s: invalid hash algorithm '%s'\n",
625+
__func__, hmac_name);
626+
return -EINVAL;
627+
}
628+
629+
enc = kzalloc(hmac_len + 1, GFP_KERNEL);
630+
if (!enc)
631+
return -ENOMEM;
632+
633+
tfm = crypto_alloc_shash(hmac_name, 0, 0);
634+
if (IS_ERR(tfm)) {
635+
ret = PTR_ERR(tfm);
636+
goto out_free_enc;
637+
}
638+
639+
digest_len = crypto_shash_digestsize(tfm);
640+
digest = kzalloc(digest_len, GFP_KERNEL);
641+
if (!digest) {
642+
ret = -ENOMEM;
643+
goto out_free_tfm;
644+
}
645+
646+
shash->tfm = tfm;
647+
ret = crypto_shash_setkey(tfm, psk, psk_len);
648+
if (ret)
649+
goto out_free_digest;
650+
651+
ret = crypto_shash_init(shash);
652+
if (ret)
653+
goto out_free_digest;
654+
655+
ret = crypto_shash_update(shash, hostnqn, strlen(hostnqn));
656+
if (ret)
657+
goto out_free_digest;
658+
659+
ret = crypto_shash_update(shash, " ", 1);
660+
if (ret)
661+
goto out_free_digest;
662+
663+
ret = crypto_shash_update(shash, subsysnqn, strlen(subsysnqn));
664+
if (ret)
665+
goto out_free_digest;
666+
667+
ret = crypto_shash_update(shash, " NVMe-over-Fabrics", 18);
668+
if (ret)
669+
goto out_free_digest;
670+
671+
ret = crypto_shash_final(shash, digest);
672+
if (ret)
673+
goto out_free_digest;
674+
675+
ret = base64_encode(digest, digest_len, enc);
676+
if (ret < hmac_len) {
677+
ret = -ENOKEY;
678+
goto out_free_digest;
679+
}
680+
*ret_digest = enc;
681+
ret = 0;
682+
683+
out_free_digest:
684+
kfree_sensitive(digest);
685+
out_free_tfm:
686+
crypto_free_shash(tfm);
687+
out_free_enc:
688+
if (ret)
689+
kfree_sensitive(enc);
690+
691+
return ret;
692+
}
693+
EXPORT_SYMBOL_GPL(nvme_auth_generate_digest);
694+
561695
MODULE_DESCRIPTION("NVMe Authentication framework");
562696
MODULE_LICENSE("GPL v2");

include/linux/nvme-auth.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,7 @@ int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm,
4343
int nvme_auth_generate_psk(u8 hmac_id, u8 *skey, size_t skey_len,
4444
u8 *c1, u8 *c2, size_t hash_len,
4545
u8 **ret_psk, size_t *ret_len);
46+
int nvme_auth_generate_digest(u8 hmac_id, u8 *psk, size_t psk_len,
47+
char *subsysnqn, char *hostnqn, u8 **ret_digest);
4648

4749
#endif /* _NVME_AUTH_H */

0 commit comments

Comments
 (0)