@@ -94,6 +94,61 @@ int test_wc_RNG_GenerateBlock_Reseed(void)
9494 return EXPECT_RESULT ();
9595}
9696
97+ /*
98+ * Exercise the exact Hash_DRBG reseed-counter boundary: a mutation of
99+ * `>=` to `>` in the reseed check would survive all existing tests because
100+ * nothing generates WC_RESEED_INTERVAL blocks. Set the counter to the
101+ * boundary, generate, and confirm the next call reseeds (counter resets).
102+ */
103+ int test_wc_RNG_ReseedBoundary (void )
104+ {
105+ EXPECT_DECLS ;
106+ #if defined(HAVE_HASHDRBG ) && !defined(CUSTOM_RAND_GENERATE_BLOCK ) && \
107+ !defined(HAVE_FIPS ) && !defined(HAVE_SELFTEST )
108+ /* FIPS and CAVP-selftest builds substitute an older random.h that does
109+ * not expose struct DRBG_internal or WC_DRBG_OK, so we can't poke
110+ * reseedCtr directly. Skip under either. */
111+ WC_RNG rng ;
112+ struct DRBG_internal * drbg ;
113+ byte out [32 ];
114+ #ifdef WORD64_AVAILABLE
115+ word64 startCtr ;
116+ #else
117+ word32 startCtr ;
118+ #endif
119+
120+ XMEMSET (& rng , 0 , sizeof (WC_RNG ));
121+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
122+
123+ /* The test requires a regular in-process DRBG. Skip when wc_InitRng
124+ * routes to a bank (status != DRBG_OK), when the backend bypasses the
125+ * DRBG (RDRAND, cryptocb, etc.) and leaves the counter untouched, or
126+ * when drbg is otherwise not a DRBG_internal. */
127+ drbg = (struct DRBG_internal * )rng .drbg ;
128+ if (drbg != NULL && rng .status == WC_DRBG_OK ) {
129+ startCtr = drbg -> reseedCtr ;
130+ ExpectIntEQ (wc_RNG_GenerateBlock (& rng , out , sizeof (out )), 0 );
131+ if (drbg -> reseedCtr == startCtr + 1 ) {
132+ /* Counter advanced, so this backend really is the DRBG. Set to
133+ * WC_RESEED_INTERVAL - 1 and verify the reseed boundary:
134+ * - First generate: counter -> WC_RESEED_INTERVAL.
135+ * - Second generate: counter >= WC_RESEED_INTERVAL triggers
136+ * reseed (counter = 1), then post-increments to 2.
137+ * A `>` mutation of the check would leave the counter at
138+ * WC_RESEED_INTERVAL + 1 instead. */
139+ drbg -> reseedCtr = WC_RESEED_INTERVAL - 1 ;
140+ ExpectIntEQ (wc_RNG_GenerateBlock (& rng , out , sizeof (out )), 0 );
141+ ExpectTrue (drbg -> reseedCtr == WC_RESEED_INTERVAL );
142+ ExpectIntEQ (wc_RNG_GenerateBlock (& rng , out , sizeof (out )), 0 );
143+ ExpectTrue (drbg -> reseedCtr == 2 );
144+ }
145+ }
146+
147+ DoExpectIntEQ (wc_FreeRng (& rng ), 0 );
148+ #endif
149+ return EXPECT_RESULT ();
150+ }
151+
97152int test_wc_RNG_GenerateBlock (void )
98153{
99154 EXPECT_DECLS ;
0 commit comments