@@ -572,6 +572,53 @@ TPM_RC FwGenerateEccKey(WC_RNG* rng,
572572/* ================================================================== */
573573
574574#ifdef HAVE_ECC
575+ /* Constant-time compare of two big-endian byte arrays of equal length.
576+ * Returns 1 when a < b, otherwise 0. */
577+ static int FwCtLessBE (const byte * a , const byte * b , int len )
578+ {
579+ int i ;
580+ unsigned int borrow = 0 ;
581+ for (i = len - 1 ; i >= 0 ; i -- ) {
582+ unsigned int diff = (unsigned int )a [i ] - (unsigned int )b [i ] - borrow ;
583+ borrow = (diff >> 8 ) & 1u ;
584+ }
585+ return (int )borrow ;
586+ }
587+
588+ /* Load the curve order into a big-endian, keySz-padded buffer and report its
589+ * bit length, used to bound and mask the derived scalar. */
590+ static TPM_RC FwEccGetCurveOrder (int wcCurve , byte * orderBuf , int keySz ,
591+ int * orderBits )
592+ {
593+ TPM_RC rc = TPM_RC_SUCCESS ;
594+ int idx ;
595+ const ecc_set_type * dp ;
596+ mp_int order ;
597+
598+ idx = wc_ecc_get_curve_idx (wcCurve );
599+ if (idx < 0 ) {
600+ return TPM_RC_CURVE ;
601+ }
602+ dp = wc_ecc_get_curve_params (idx );
603+ if (dp == NULL ) {
604+ return TPM_RC_CURVE ;
605+ }
606+ if (mp_init (& order ) != MP_OKAY ) {
607+ return TPM_RC_FAILURE ;
608+ }
609+ if (mp_read_radix (& order , dp -> order , MP_RADIX_HEX ) != MP_OKAY ) {
610+ rc = TPM_RC_FAILURE ;
611+ }
612+ if (rc == 0 ) {
613+ * orderBits = mp_count_bits (& order );
614+ if (mp_to_unsigned_bin_len (& order , orderBuf , keySz ) != MP_OKAY ) {
615+ rc = TPM_RC_FAILURE ;
616+ }
617+ }
618+ mp_clear (& order );
619+ return rc ;
620+ }
621+
575622/* Derive ECC primary key from hierarchy seed per TPM 2.0 Part 1 Section 26.3.
576623 * d = KDFa(nameAlg, seed, "ECC", hashUnique, counter, keySz*8)
577624 * Q = d * G
@@ -596,6 +643,8 @@ TPM_RC FwDeriveEccPrimaryKey(TPMI_ALG_HASH nameAlg,
596643 int i ;
597644 int allZero ;
598645 volatile byte orAccum ;
646+ byte orderBuf [MAX_ECC_BYTES ];
647+ int orderBits = 0 ;
599648
600649 FWTPM_ALLOC_VAR (eccKey , ecc_key );
601650
@@ -604,6 +653,12 @@ TPM_RC FwDeriveEccPrimaryKey(TPMI_ALG_HASH nameAlg,
604653 return TPM_RC_CURVE ;
605654 }
606655
656+ rc = FwEccGetCurveOrder (wcCurve , orderBuf , keySz , & orderBits );
657+ if (rc != 0 ) {
658+ FWTPM_FREE_VAR (eccKey );
659+ return rc ;
660+ }
661+
607662 /* Derive private scalar d via KDFa, retry if out of range */
608663 while (!valid && counter < 100 ) {
609664 FwStoreU32BE (counterBuf , counter );
@@ -615,14 +670,18 @@ TPM_RC FwDeriveEccPrimaryKey(TPMI_ALG_HASH nameAlg,
615670 rc = TPM_RC_FAILURE ;
616671 break ;
617672 }
618- /* Constant-time check d != 0 (all zeros) */
673+ /* Mask unused high bits so the candidate matches the order bit length */
674+ if ((orderBits & 7 ) != 0 ) {
675+ dBuf [0 ] &= (byte )((1u << (orderBits & 7 )) - 1u );
676+ }
677+ /* Constant-time check 0 < d < order */
619678 orAccum = 0 ;
620679 for (i = 0 ; i < keySz ; i ++ ) {
621680 orAccum |= dBuf [i ];
622681 }
623682 allZero = (orAccum == 0 );
624- if (!allZero ) {
625- valid = 1 ; /* Accept — range check done by import */
683+ if (!allZero && FwCtLessBE ( dBuf , orderBuf , keySz ) ) {
684+ valid = 1 ;
626685 }
627686 counter ++ ;
628687 }
0 commit comments