@@ -351,18 +351,29 @@ struct nvme_dhchap_key *nvme_auth_transform_key(
351351}
352352EXPORT_SYMBOL_GPL (nvme_auth_transform_key );
353353
354+ /**
355+ * nvme_auth_augmented_challenge() - Compute the augmented DH-HMAC-CHAP challenge
356+ * @hmac_id: Hash algorithm identifier
357+ * @skey: Session key
358+ * @skey_len: Length of @skey
359+ * @challenge: Challenge value
360+ * @aug: Output buffer for the augmented challenge
361+ * @hlen: Hash output length (length of @challenge and @aug)
362+ *
363+ * NVMe base specification 8.3.5.5.4: The augmented challenge is computed
364+ * applying the HMAC function using the hash function H() selected by the
365+ * HashID parameter ... with the hash of the ephemeral DH key ... as HMAC key
366+ * to the challenge C (i.e., Ca = HMAC(H(g^xy mod p), C)).
367+ *
368+ * As the session key skey is already H(g^xy mod p) per section 8.3.5.5.9, use
369+ * it directly as the HMAC key without additional hashing.
370+ *
371+ * Return: 0 on success, negative errno on failure.
372+ */
354373int nvme_auth_augmented_challenge (u8 hmac_id , const u8 * skey , size_t skey_len ,
355374 const u8 * challenge , u8 * aug , size_t hlen )
356375{
357- u8 hashed_key [NVME_AUTH_MAX_DIGEST_SIZE ];
358- int ret ;
359-
360- ret = nvme_auth_hash (hmac_id , skey , skey_len , hashed_key );
361- if (ret )
362- return ret ;
363- ret = nvme_auth_hmac (hmac_id , hashed_key , hlen , challenge , hlen , aug );
364- memzero_explicit (hashed_key , sizeof (hashed_key ));
365- return ret ;
376+ return nvme_auth_hmac (hmac_id , skey , skey_len , challenge , hlen , aug );
366377}
367378EXPORT_SYMBOL_GPL (nvme_auth_augmented_challenge );
368379
@@ -403,33 +414,76 @@ int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm,
403414}
404415EXPORT_SYMBOL_GPL (nvme_auth_gen_pubkey );
405416
406- int nvme_auth_gen_shared_secret (struct crypto_kpp * dh_tfm ,
407- const u8 * ctrl_key , size_t ctrl_key_len ,
408- u8 * sess_key , size_t sess_key_len )
417+ /**
418+ * nvme_auth_gen_session_key() - Generate an ephemeral session key
419+ * @dh_tfm: Diffie-Hellman transform with local private key already set
420+ * @public_key: Peer's public key
421+ * @public_key_len: Length of @public_key
422+ * @sess_key: Output buffer for the session key
423+ * @sess_key_len: Size of @sess_key buffer
424+ * @hash_id: Hash algorithm identifier
425+ *
426+ * NVMe base specification 8.3.5.5.9: The session key Ks shall be computed from
427+ * the ephemeral DH key (i.e., g^xy mod p) ... by applying the hash function
428+ * H() selected by the HashID parameter ... (i.e., Ks = H(g^xy mod p)).
429+ *
430+ * Return: 0 on success, negative errno on failure.
431+ */
432+ int nvme_auth_gen_session_key (struct crypto_kpp * dh_tfm ,
433+ const u8 * public_key , size_t public_key_len ,
434+ u8 * sess_key , size_t sess_key_len , u8 hash_id )
409435{
410436 struct kpp_request * req ;
411437 struct crypto_wait wait ;
412438 struct scatterlist src , dst ;
439+ u8 * dh_secret ;
440+ size_t dh_secret_len , hash_len ;
413441 int ret ;
414442
415- req = kpp_request_alloc (dh_tfm , GFP_KERNEL );
416- if (!req )
443+ hash_len = nvme_auth_hmac_hash_len (hash_id );
444+ if (!hash_len ) {
445+ pr_warn ("%s: invalid hash algorithm %d\n" , __func__ , hash_id );
446+ return - EINVAL ;
447+ }
448+
449+ if (sess_key_len != hash_len ) {
450+ pr_warn ("%s: sess_key buffer missized (%zu != %zu)\n" ,
451+ __func__ , sess_key_len , hash_len );
452+ return - EINVAL ;
453+ }
454+
455+ dh_secret_len = crypto_kpp_maxsize (dh_tfm );
456+ dh_secret = kzalloc (dh_secret_len , GFP_KERNEL );
457+ if (!dh_secret )
417458 return - ENOMEM ;
418459
460+ req = kpp_request_alloc (dh_tfm , GFP_KERNEL );
461+ if (!req ) {
462+ ret = - ENOMEM ;
463+ goto out_free_secret ;
464+ }
465+
419466 crypto_init_wait (& wait );
420- sg_init_one (& src , ctrl_key , ctrl_key_len );
421- kpp_request_set_input (req , & src , ctrl_key_len );
422- sg_init_one (& dst , sess_key , sess_key_len );
423- kpp_request_set_output (req , & dst , sess_key_len );
467+ sg_init_one (& src , public_key , public_key_len );
468+ kpp_request_set_input (req , & src , public_key_len );
469+ sg_init_one (& dst , dh_secret , dh_secret_len );
470+ kpp_request_set_output (req , & dst , dh_secret_len );
424471 kpp_request_set_callback (req , CRYPTO_TFM_REQ_MAY_BACKLOG ,
425472 crypto_req_done , & wait );
426473
427474 ret = crypto_wait_req (crypto_kpp_compute_shared_secret (req ), & wait );
428-
429475 kpp_request_free (req );
476+
477+ if (ret )
478+ goto out_free_secret ;
479+
480+ ret = nvme_auth_hash (hash_id , dh_secret , dh_secret_len , sess_key );
481+
482+ out_free_secret :
483+ kfree_sensitive (dh_secret );
430484 return ret ;
431485}
432- EXPORT_SYMBOL_GPL (nvme_auth_gen_shared_secret );
486+ EXPORT_SYMBOL_GPL (nvme_auth_gen_session_key );
433487
434488int nvme_auth_parse_key (const char * secret , struct nvme_dhchap_key * * ret_key )
435489{
0 commit comments