@@ -75,6 +75,12 @@ struct nonce_cfg {
7575 size_t num_dirs ;
7676};
7777
78+ struct x509_pool {
79+ size_t size ;
80+ size_t capacity ;
81+ X509 * * entries ;
82+ };
83+
7884/* Cache line size is either 32 or 64 bytes on most arches of interest */
7985#if defined(__GNUC__ ) || defined(__clang__ )
8086# define ALIGN64 __attribute((aligned(64)))
@@ -106,6 +112,65 @@ OSSL_TIME max_time;
106112#define OSSL_MIN (p , q ) ((p) < (q) ? (p) : (q))
107113#define OSSL_MAX (p , q ) ((p) > (q) ? (p) : (q))
108114
115+ /**
116+ * Extend the x509_pool, by the increment, if inc is 0, the increment size
117+ * is decided automatically.
118+ */
119+ static struct x509_pool *
120+ x509_pool_extend (struct x509_pool * pool , size_t inc )
121+ {
122+ X509 * * realloc_ptr ;
123+
124+ if (inc == 0 ) {
125+ inc = OSSL_MIN (OSSL_MAX (64 , pool -> capacity ),
126+ OSSL_MAX (65536 , pool -> capacity / 16 ));
127+ }
128+
129+ if (inc >= SIZE_MAX / sizeof (pool -> entries [0 ]) - pool -> capacity )
130+ errx (EXIT_FAILURE , "x509_pool_extend: the increment is too big"
131+ " (capacity %zu, increment %zu)" ,
132+ pool -> capacity , inc );
133+
134+ realloc_ptr = OPENSSL_realloc (pool -> entries , (pool -> capacity + inc )
135+ * sizeof (pool -> entries [0 ]));
136+ if (realloc_ptr == NULL )
137+ errx (EXIT_FAILURE , "x509_pool_extend: realloc() failed ()"
138+ " (capacity %zu, increment %zu)" ,
139+ pool -> capacity , inc );
140+
141+ pool -> entries = realloc_ptr ;
142+ pool -> capacity += inc ;
143+
144+ return pool ;
145+ }
146+
147+ /**
148+ * Returns a pointer to a next entry in the pool, automatically extending (and,
149+ * thusly, potentially reallocating) the pool if needed.
150+ */
151+ static X509 * *
152+ x509_pool_next (struct x509_pool * pool )
153+ {
154+ if (pool -> size >= pool -> capacity )
155+ x509_pool_extend (pool , 0 );
156+
157+ return pool -> entries + pool -> size ++ ;
158+ }
159+
160+ static void
161+ x509_pool_empty (struct x509_pool * pool )
162+ {
163+ if (pool -> entries != NULL ) {
164+ for (size_t i = 0 ; i < pool -> size ; i ++ )
165+ X509_free (pool -> entries [i ]);
166+ }
167+
168+ OPENSSL_free (pool -> entries );
169+
170+ pool -> entries = NULL ;
171+ pool -> size = pool -> capacity = 0 ;
172+ }
173+
109174static X509 *
110175load_cert_from_file (const char * path )
111176{
@@ -190,12 +255,17 @@ make_nonce(struct nonce_cfg *cfg)
190255}
191256
192257static size_t
193- read_cert (const char * const dir , const char * const name , X509_STORE * const store )
258+ read_cert (const char * const dir , const char * const name ,
259+ X509_STORE * const store ,
260+ struct x509_pool * const pool , size_t * const pool_cnt )
194261{
195262 X509 * x509 = NULL ;
196263 char * path = NULL ;
197264 size_t ret = 0 ;
198265
266+ if (store == NULL && pool == NULL )
267+ return 0 ;
268+
199269 path = perflib_mk_file_path (dir , name );
200270 if (path == NULL ) {
201271 warn ("Failed to allocate cert name in directory \"%s\" for file \"%s\"" ,
@@ -208,19 +278,35 @@ read_cert(const char * const dir, const char * const name, X509_STORE * const st
208278 goto out ;
209279 }
210280
211- if (!X509_STORE_add_cert (store , x509 )) {
212- warnx ("Failed to add a certificate from \"%s\" to the store\n" , path );
213- goto out ;
214- }
281+ if (store != NULL ) {
282+ if (!X509_STORE_add_cert (store , x509 )) {
283+ warnx ("Failed to add a certificate from \"%s\" to the store\n" ,
284+ path );
285+ goto out ;
286+ }
287+
288+ if (verbosity >= VERBOSITY_DEBUG )
289+ fprintf (stderr , "Successfully added a certificate from \"%s\""
290+ " to the store\n" , path );
291+ } else {
292+ X509 * * ptr = x509_pool_next (pool );
215293
216- if (verbosity >= VERBOSITY_DEBUG )
217- fprintf (stderr , "Successfully added a certificate from \"%s\""
218- " to the store\n" , path );
294+ * ptr = x509 ;
295+
296+ if (verbosity >= VERBOSITY_DEBUG ) {
297+ fprintf (stderr , "Added a certificate from \"%s\" to the pool\n" ,
298+ path );
299+ }
300+
301+ if (pool_cnt != NULL )
302+ * pool_cnt += 1 ;
303+ }
219304
220305 ret = 1 ;
221306
222307 out :
223- X509_free (x509 );
308+ if (store != NULL )
309+ X509_free (x509 );
224310 OPENSSL_free (path );
225311
226312 return ret ;
@@ -229,7 +315,8 @@ read_cert(const char * const dir, const char * const name, X509_STORE * const st
229315#if defined(_WIN32 )
230316static size_t
231317read_certsdir (char * const dir , const size_t max_certs ,
232- X509_STORE * const store )
318+ X509_STORE * const store ,
319+ struct x509_pool * const pool , size_t * const pool_cnt )
233320{
234321 const size_t dir_len = strlen (dir );
235322 const size_t glob_len = dir_len + sizeof ("\\*" );
@@ -239,7 +326,7 @@ read_certsdir(char * const dir, const size_t max_certs,
239326 WIN32_FIND_DATA find_data ;
240327 DWORD last_err ;
241328
242- if (max_certs == 0 )
329+ if (pool == NULL && max_certs == 0 )
243330 return 0 ;
244331
245332 search_glob = OPENSSL_malloc (glob_len );
@@ -267,9 +354,10 @@ read_certsdir(char * const dir, const size_t max_certs,
267354 continue ;
268355 }
269356
270- cnt += read_cert (dir , find_data .cFileName , store );
357+ cnt += read_cert (dir , find_data .cFileName ,
358+ cnt < max_certs ? store : NULL , pool , pool_cnt );
271359
272- if (cnt >= max_certs )
360+ if (pool == NULL && cnt >= max_certs )
273361 break ;
274362 } while (FindNextFileA (find_handle , & find_data ) != 0 );
275363
@@ -287,14 +375,15 @@ read_certsdir(char * const dir, const size_t max_certs,
287375#else /* !defined(_WIN32) */
288376static size_t
289377read_certsdir (char * const dir , const size_t max_certs ,
290- X509_STORE * const store )
378+ X509_STORE * const store ,
379+ struct x509_pool * const pool , size_t * const pool_cnt )
291380{
292381 struct stat st ;
293382 struct dirent * e ;
294383 DIR * d ;
295384 size_t cnt = 0 ;
296385
297- if (max_certs == 0 )
386+ if (pool == NULL && max_certs == 0 )
298387 return 0 ;
299388
300389 d = opendir (dir );
@@ -322,9 +411,10 @@ read_certsdir(char * const dir, const size_t max_certs,
322411 continue ;
323412 }
324413
325- cnt += read_cert (dir , e -> d_name , store );
414+ cnt += read_cert (dir , e -> d_name , cnt < max_certs ? store : NULL ,
415+ pool , pool_cnt );
326416
327- if (cnt >= max_certs )
417+ if (pool == NULL && cnt >= max_certs )
328418 break ;
329419 }
330420
@@ -334,20 +424,52 @@ read_certsdir(char * const dir, const size_t max_certs,
334424}
335425#endif /* defined(_WIN32) */
336426
427+ /**
428+ * Reads certificates (up to max_certs) from dirs (up to max_cert_dirs) into
429+ * store, and stores the rest in pool for the later use (unless it is NULL,
430+ * in which case certificate reading stops as soon as one of the aforementioned
431+ * limit is reached).
432+ *
433+ * @param dirs Array of directory paths (dir_cnt in size)
434+ * to (non-recursively) read certificates from.
435+ * @param dir_cnt Number of elements in dirs parameter.
436+ * @param max_certs Maximum number of certificates to read to store,
437+ * the rest will be read to pool, if it is non-NULL.
438+ * @param max_cert_dirs Maximum number of directories to read to the store,
439+ * the rest will be read to pool, if it is non-NULL.
440+ * @param store X509_STORE to read certificates to.
441+ * @param pool Certificate pool where certificates are stored
442+ * for later use.
443+ * @param total_read If non-NULL, total number of certificates read
444+ * in stored there.
445+ * @return Number of certificates read into the store.
446+ */
337447static size_t
338- read_certsdirs (char * const * const dirs , const size_t max_certs ,
339- const int dir_cnt , X509_STORE * const store )
448+ read_certsdirs (char * const * const dirs , const int dir_cnt ,
449+ const size_t max_certs , const int max_cert_dirs ,
450+ X509_STORE * const store , struct x509_pool * pool ,
451+ size_t * const total_read )
340452{
453+ /*
454+ * For the ease of accounting, we count total and pool counts,
455+ * but for the ease of reporting, we return store and total counts.
456+ */
341457 size_t cnt = 0 ;
458+ size_t pool_cnt = 0 ;
342459
343460 for (int i = 0 ; i < dir_cnt ; i ++ ) {
344- cnt += read_certsdir (dirs [i ], max_certs - cnt , store );
461+ cnt += read_certsdir (dirs [i ], max_certs > cnt ? max_certs - cnt : 0 ,
462+ i < max_cert_dirs ? store : NULL ,
463+ pool , pool ? & pool_cnt : NULL );
345464
346- if (cnt >= max_certs )
465+ if (pool == NULL && cnt >= max_certs )
347466 break ;
348467 }
349468
350- return cnt ;
469+ if (total_read != NULL )
470+ * total_read = cnt ;
471+
472+ return cnt - pool_cnt ;
351473}
352474
353475static void
@@ -634,9 +756,11 @@ main(int argc, char *argv[])
634756 int opt ;
635757 int dirs_start ;
636758 size_t num_certs = 0 ;
759+ size_t total_certs_read = 0 ;
637760 size_t max_load_certs = MAX_LOAD_CERTS ;
638761 int max_load_cert_dirs = MAX_LOAD_CERT_DIRS ;
639762 bool skip_default_paths = false;
763+ struct x509_pool cert_pool = { 0 };
640764 struct nonce_cfg nonce_cfg ;
641765
642766 parse_nonce_cfg (NONCE_CFG , & nonce_cfg );
@@ -729,13 +853,14 @@ main(int argc, char *argv[])
729853 errx (EXIT_FAILURE , "Failed to load certificates from default paths" );
730854 }
731855
732- num_certs += read_certsdirs (argv + dirs_start , max_load_certs ,
733- OSSL_MIN (argc - dirs_start - 1 ,
734- max_load_cert_dirs ),
735- store );
856+ num_certs += read_certsdirs (argv + dirs_start , argc - dirs_start - 1 ,
857+ max_load_certs , max_load_cert_dirs ,
858+ store , & cert_pool , & total_certs_read );
736859
737860 if (verbosity >= VERBOSITY_DEBUG_STATS )
738- fprintf (stderr , "Added %zu certificates to the store\n" , num_certs );
861+ fprintf (stderr , "Added %zu certificates to the store"
862+ " (%zu certificates read in total)\n" ,
863+ num_certs , total_certs_read );
739864
740865 report_store_size (store , "before the test run" , verbosity );
741866
@@ -770,6 +895,7 @@ main(int argc, char *argv[])
770895
771896 err :
772897 X509_free (x509_nonce );
898+ x509_pool_empty (& cert_pool );
773899 X509_STORE_free (store );
774900 if (thread_data != NULL ) {
775901 for (size_t i = 0 ; i < threadcount ; i ++ ) {
0 commit comments