@@ -94,6 +94,60 @@ 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 )
108+ /* FIPS builds keep DRBG_internal opaque (defined only inside the FIPS
109+ * module), so we can't poke reseedCtr directly. Skip under FIPS. */
110+ WC_RNG rng ;
111+ struct DRBG_internal * drbg ;
112+ byte out [32 ];
113+ #ifdef WORD64_AVAILABLE
114+ word64 startCtr ;
115+ #else
116+ word32 startCtr ;
117+ #endif
118+
119+ XMEMSET (& rng , 0 , sizeof (WC_RNG ));
120+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
121+
122+ /* The test requires a regular in-process DRBG. Skip when wc_InitRng
123+ * routes to a bank (status != DRBG_OK), when the backend bypasses the
124+ * DRBG (RDRAND, cryptocb, etc.) and leaves the counter untouched, or
125+ * when drbg is otherwise not a DRBG_internal. */
126+ drbg = (struct DRBG_internal * )rng .drbg ;
127+ if (drbg != NULL && rng .status == WC_DRBG_OK ) {
128+ startCtr = drbg -> reseedCtr ;
129+ ExpectIntEQ (wc_RNG_GenerateBlock (& rng , out , sizeof (out )), 0 );
130+ if (drbg -> reseedCtr == startCtr + 1 ) {
131+ /* Counter advanced, so this backend really is the DRBG. Set to
132+ * WC_RESEED_INTERVAL - 1 and verify the reseed boundary:
133+ * - First generate: counter -> WC_RESEED_INTERVAL.
134+ * - Second generate: counter >= WC_RESEED_INTERVAL triggers
135+ * reseed (counter = 1), then post-increments to 2.
136+ * A `>` mutation of the check would leave the counter at
137+ * WC_RESEED_INTERVAL + 1 instead. */
138+ drbg -> reseedCtr = WC_RESEED_INTERVAL - 1 ;
139+ ExpectIntEQ (wc_RNG_GenerateBlock (& rng , out , sizeof (out )), 0 );
140+ ExpectTrue (drbg -> reseedCtr == WC_RESEED_INTERVAL );
141+ ExpectIntEQ (wc_RNG_GenerateBlock (& rng , out , sizeof (out )), 0 );
142+ ExpectTrue (drbg -> reseedCtr == 2 );
143+ }
144+ }
145+
146+ DoExpectIntEQ (wc_FreeRng (& rng ), 0 );
147+ #endif
148+ return EXPECT_RESULT ();
149+ }
150+
97151int test_wc_RNG_GenerateBlock (void )
98152{
99153 EXPECT_DECLS ;
0 commit comments