@@ -578,6 +578,110 @@ int test_wc_ecc_shared_secret(void)
578578 return EXPECT_RESULT ();
579579} /* END tests_wc_ecc_shared_secret */
580580
581+ #if defined(HAVE_ECC ) && defined(HAVE_ECC_DHE ) && !defined(WC_NO_RNG ) && \
582+ (defined(HAVE_ECC384 ) || defined(HAVE_ECC521 ) || defined(HAVE_ALL_CURVES ))
583+ /* Verify the output-buffer size contract of wc_ecc_shared_secret() at the
584+ * field-size boundary. The single-precision (SP) math secret generators for
585+ * P-384/P-521 historically validated the caller's buffer against the wrong
586+ * length (e.g. P-521 checked 65 but writes 66), so a buffer declared one byte
587+ * short of the field size slipped past the check and was overwritten. Assert
588+ * that fieldSz-1 is rejected with BUFFER_E and fieldSz succeeds, for whichever
589+ * math backend is built.
590+ *
591+ * Coverage note: this drives the blocking generators only (wc_ecc_shared_secret
592+ * is synchronous). The fix also corrected the non-blocking (_nb) variants
593+ * (sp_ecc_secret_gen_384_nb / _521_nb), which need WOLFSSL_SP_NONBLOCK plus the
594+ * specialized SP build and are not exercised here. Of the blocking cases only
595+ * P-521 (65->66) actually fails without the fix; P-384 already used 48, so its
596+ * case is a guard against regression rather than a reproduction. */
597+ static int ecc_shared_secret_size_bound (WC_RNG * rng , int curveId , int fieldSz )
598+ {
599+ EXPECT_DECLS ;
600+ ecc_key key ;
601+ ecc_key pub ;
602+ byte out [80 ]; /* >= P-521 field size (66) */
603+ word32 outlen ;
604+ int keyInit = 0 , pubInit = 0 ;
605+ int ret ;
606+
607+ XMEMSET (& key , 0 , sizeof (key ));
608+ XMEMSET (& pub , 0 , sizeof (pub ));
609+
610+ ExpectIntEQ (wc_ecc_init (& key ), 0 );
611+ if (EXPECT_SUCCESS ()) keyInit = 1 ;
612+ ExpectIntEQ (wc_ecc_init (& pub ), 0 );
613+ if (EXPECT_SUCCESS ()) pubInit = 1 ;
614+
615+ ret = wc_ecc_make_key_ex (rng , fieldSz , & key , curveId );
616+ #if defined(WOLFSSL_ASYNC_CRYPT )
617+ ret = wc_AsyncWait (ret , & key .asyncDev , WC_ASYNC_FLAG_NONE );
618+ #endif
619+ ExpectIntEQ (ret , 0 );
620+
621+ ret = wc_ecc_make_key_ex (rng , fieldSz , & pub , curveId );
622+ #if defined(WOLFSSL_ASYNC_CRYPT )
623+ ret = wc_AsyncWait (ret , & pub .asyncDev , WC_ASYNC_FLAG_NONE );
624+ #endif
625+ ExpectIntEQ (ret , 0 );
626+
627+ #if defined(ECC_TIMING_RESISTANT ) && (!defined(HAVE_FIPS ) || \
628+ (!defined(HAVE_FIPS_VERSION ) || (HAVE_FIPS_VERSION != 2 ))) && \
629+ !defined(HAVE_SELFTEST )
630+ ExpectIntEQ (wc_ecc_set_rng (& key , rng ), 0 );
631+ #endif
632+
633+ /* One byte short of the field size: must be rejected, not written past. */
634+ outlen = (word32 )(fieldSz - 1 );
635+ ExpectIntEQ (wc_ecc_shared_secret (& key , & pub , out , & outlen ),
636+ WC_NO_ERR_TRACE (BUFFER_E ));
637+
638+ /* Exactly the field size: must succeed and report the field size. */
639+ outlen = (word32 )fieldSz ;
640+ ExpectIntEQ (wc_ecc_shared_secret (& key , & pub , out , & outlen ), 0 );
641+ ExpectIntEQ (outlen , (word32 )fieldSz );
642+
643+ if (pubInit )
644+ wc_ecc_free (& pub );
645+ if (keyInit )
646+ wc_ecc_free (& key );
647+ return EXPECT_RESULT ();
648+ }
649+ #endif
650+
651+ /*
652+ * Testing wc_ecc_shared_secret() output buffer bounds at the field-size edge.
653+ */
654+ int test_wc_ecc_shared_secret_size_bounds (void )
655+ {
656+ EXPECT_DECLS ;
657+ #if defined(HAVE_ECC ) && defined(HAVE_ECC_DHE ) && !defined(WC_NO_RNG ) && \
658+ (defined(HAVE_ECC384 ) || defined(HAVE_ECC521 ) || defined(HAVE_ALL_CURVES ))
659+ WC_RNG rng ;
660+ int rngInit = 0 ;
661+
662+ XMEMSET (& rng , 0 , sizeof (rng ));
663+ PRIVATE_KEY_UNLOCK ();
664+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
665+ if (EXPECT_SUCCESS ())
666+ rngInit = 1 ;
667+
668+ #if defined(HAVE_ECC384 ) || defined(HAVE_ALL_CURVES )
669+ ExpectIntEQ (ecc_shared_secret_size_bound (& rng , ECC_SECP384R1 , 48 ), 1 );
670+ #endif
671+ #if defined(HAVE_ECC521 ) || defined(HAVE_ALL_CURVES )
672+ ExpectIntEQ (ecc_shared_secret_size_bound (& rng , ECC_SECP521R1 , 66 ), 1 );
673+ #endif
674+
675+ if (rngInit )
676+ DoExpectIntEQ (wc_FreeRng (& rng ), 0 );
677+ #ifdef FP_ECC
678+ wc_ecc_fp_free ();
679+ #endif
680+ PRIVATE_KEY_LOCK ();
681+ #endif
682+ return EXPECT_RESULT ();
683+ }
684+
581685/*
582686 * testint wc_ecc_export_x963()
583687 */
0 commit comments