3232#define RUN_TIME 5
3333#define QUANTILES 5
3434#define NONCE_CFG "file:servercert.pem"
35+ #define MAX_LOAD_CERTS INT_MAX
36+ #define MAX_LOAD_CERT_DIRS 0
3537#define CTX_SHARE_THREADS 1
3638
3739static size_t timeout_us = RUN_TIME * 1000000 ;
@@ -226,7 +228,8 @@ read_cert(const char * const dir, const char * const name, X509_STORE * const st
226228
227229#if defined(_WIN32 )
228230static size_t
229- read_certsdir (char * const dir , X509_STORE * const store )
231+ read_certsdir (char * const dir , const size_t max_certs ,
232+ X509_STORE * const store )
230233{
231234 const size_t dir_len = strlen (dir );
232235 const size_t glob_len = dir_len + sizeof ("\\*" );
@@ -236,6 +239,9 @@ read_certsdir(char * const dir, X509_STORE * const store)
236239 WIN32_FIND_DATA find_data ;
237240 DWORD last_err ;
238241
242+ if (max_certs == 0 )
243+ return 0 ;
244+
239245 search_glob = OPENSSL_malloc (glob_len );
240246 if (search_glob == NULL ) {
241247 warnx ("Error allocating a search glob for \"%s\"" , dir );
@@ -263,6 +269,8 @@ read_certsdir(char * const dir, X509_STORE * const store)
263269
264270 cnt += read_cert (dir , find_data .cFileName , store );
265271
272+ if (cnt >= max_certs )
273+ break ;
266274 } while (FindNextFileA (find_handle , & find_data ) != 0 );
267275
268276 last_err = GetLastError ();
@@ -278,13 +286,18 @@ read_certsdir(char * const dir, X509_STORE * const store)
278286}
279287#else /* !defined(_WIN32) */
280288static size_t
281- read_certsdir (char * const dir , X509_STORE * const store )
289+ read_certsdir (char * const dir , const size_t max_certs ,
290+ X509_STORE * const store )
282291{
283292 struct stat st ;
284293 struct dirent * e ;
285- DIR * d = opendir ( dir ) ;
294+ DIR * d ;
286295 size_t cnt = 0 ;
287296
297+ if (max_certs == 0 )
298+ return 0 ;
299+
300+ d = opendir (dir );
288301 if (d == NULL ) {
289302 warn ("Could not open \"%s\"" , dir );
290303
@@ -310,6 +323,9 @@ read_certsdir(char * const dir, X509_STORE * const store)
310323 }
311324
312325 cnt += read_cert (dir , e -> d_name , store );
326+
327+ if (cnt >= max_certs )
328+ break ;
313329 }
314330
315331 closedir (d );
@@ -319,13 +335,17 @@ read_certsdir(char * const dir, X509_STORE * const store)
319335#endif /* defined(_WIN32) */
320336
321337static size_t
322- read_certsdirs (char * const * const dirs , const int dir_cnt ,
323- X509_STORE * const store )
338+ read_certsdirs (char * const * const dirs , const size_t max_certs ,
339+ const int dir_cnt , X509_STORE * const store )
324340{
325341 size_t cnt = 0 ;
326342
327- for (int i = 0 ; i < dir_cnt ; i ++ )
328- cnt += read_certsdir (dirs [i ], store );
343+ for (int i = 0 ; i < dir_cnt ; i ++ ) {
344+ cnt += read_certsdir (dirs [i ], max_certs - cnt , store );
345+
346+ if (cnt >= max_certs )
347+ break ;
348+ }
329349
330350 return cnt ;
331351}
@@ -525,7 +545,8 @@ usage(char * const argv[])
525545{
526546 fprintf (stderr ,
527547 "Usage: %s [-t] [-v] [-q N] [-T time] [-n nonce_type:type_args]"
528- " [-C threads] [-V] certsdir [certsdir...] threadcount\n"
548+ " [-l max_certs] [-L max_cert_dirs] [-C threads]"
549+ " [-V] certsdir [certsdir...] threadcount\n"
529550 "\t-t\tTerse output\n"
530551 "\t-v\tVerbose output. Multiple usage increases verbosity.\n"
531552 "\t-q\tGather information about temporal N-quantiles.\n"
@@ -538,6 +559,10 @@ usage(char * const argv[])
538559 "\t\t\tfile:PATH - load nonce certificate from PATH;\n"
539560 "\t\t\tif PATH is relative, the provided certsdir's are searched.\n"
540561 "\t\tDefault: " NONCE_CFG "\n"
562+ "\t-l\tLimit on the number of initially loaded certificates.\n"
563+ "\t\tDefault: " OPENSSL_MSTR (MAX_LOAD_CERTS ) "\n"
564+ "\t-L\tLimit on the number of initially loaded certificate\n"
565+ "\t\tdirectories. Default: " OPENSSL_MSTR (MAX_LOAD_CERT_DIRS ) "\n"
541566 "\t-C\tNumber of threads that share the same X.509\n"
542567 "\t\tstore context object. Default: "
543568 OPENSSL_MSTR (CTX_SHARE_THREADS ) "\n"
@@ -608,11 +633,13 @@ main(int argc, char *argv[])
608633 int opt ;
609634 int dirs_start ;
610635 size_t num_certs = 0 ;
636+ size_t max_load_certs = MAX_LOAD_CERTS ;
637+ int max_load_cert_dirs = MAX_LOAD_CERT_DIRS ;
611638 struct nonce_cfg nonce_cfg ;
612639
613640 parse_nonce_cfg (NONCE_CFG , & nonce_cfg );
614641
615- while ((opt = getopt (argc , argv , "tvq:T:n:C:V" )) != -1 ) {
642+ while ((opt = getopt (argc , argv , "tvq:T:n:l:L: C:V" )) != -1 ) {
616643 switch (opt ) {
617644 case 't' : /* terse */
618645 verbosity = VERBOSITY_TERSE ;
@@ -635,6 +662,15 @@ main(int argc, char *argv[])
635662 case 'n' : /* nonce */
636663 parse_nonce_cfg (optarg , & nonce_cfg );
637664 break ;
665+ case 'l' : /* max certs to load */
666+ max_load_certs = parse_int (optarg , 0 , INT_MAX ,
667+ "maximum certificate load count" );
668+ break ;
669+ case 'L' : /* max certs dirs to load*/
670+ max_load_cert_dirs = parse_int (optarg , 0 , INT_MAX ,
671+ "maximum certificate directories"
672+ " load count" );
673+ break ;
638674 case 'C' : /* how many threads share X509_STORE_CTX */
639675 ctx_share_cnt = parse_int (optarg , 1 , INT_MAX ,
640676 "X509_STORE_CTX share degree" );
@@ -684,7 +720,9 @@ main(int argc, char *argv[])
684720 if (store == NULL || !X509_STORE_set_default_paths (store ))
685721 errx (EXIT_FAILURE , "Failed to create X509_STORE" );
686722
687- num_certs += read_certsdirs (argv + dirs_start , argc - dirs_start - 1 ,
723+ num_certs += read_certsdirs (argv + dirs_start , max_load_certs ,
724+ OSSL_MIN (argc - dirs_start - 1 ,
725+ max_load_cert_dirs ),
688726 store );
689727
690728 if (verbosity >= VERBOSITY_DEBUG_STATS )
0 commit comments