@@ -558,5 +558,139 @@ int nvme_auth_generate_psk(u8 hmac_id, u8 *skey, size_t skey_len,
558558}
559559EXPORT_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+
561695MODULE_DESCRIPTION ("NVMe Authentication framework" );
562696MODULE_LICENSE ("GPL v2" );
0 commit comments