77 * https://www.openssl.org/source/license.html
88 */
99
10- #include <stdlib .h>
10+ #include <stdbool .h>
1111#include <stdio.h>
12+ #include <stdlib.h>
1213#include <string.h>
1314#ifndef _WIN32
1415# include <libgen.h>
2425#include "perflib/perflib.h"
2526
2627#define RUN_TIME 5
28+ #define NONCE_CFG "file:servercert.pem"
29+
30+ enum nonce_type {
31+ NONCE_PATH ,
32+ };
33+
34+ struct nonce_cfg {
35+ enum nonce_type type ;
36+ const char * path ;
37+ char * * dirs ;
38+ size_t num_dirs ;
39+ };
2740
2841static int error = 0 ;
2942static X509_STORE * store = NULL ;
30- static X509 * x509 = NULL ;
43+ static X509 * x509_nonce = NULL ;
3144
3245static int threadcount ;
3346
3447size_t * counts ;
3548OSSL_TIME max_time ;
3649
50+ static X509 *
51+ load_nonce_from_file (const char * path )
52+ {
53+ BIO * bio = BIO_new_file (path , "rb" );
54+ X509 * x509_nonce = NULL ;
55+
56+ if (bio == NULL ) {
57+ warnx ("Unable to create BIO for reading \"%s\"" , path );
58+ return NULL ;
59+ }
60+
61+ x509_nonce = PEM_read_bio_X509 (bio , NULL , NULL , NULL );
62+ if (x509_nonce == NULL )
63+ warnx ("Failed to read certificate \"%s\"" , path );
64+
65+ BIO_free (bio );
66+
67+ return x509_nonce ;
68+ }
69+
70+ static bool
71+ is_abs_path (const char * path )
72+ {
73+ if (path == NULL )
74+ return false;
75+
76+ #if defined(_WIN32 )
77+ /*
78+ * So, we don't try to concatenate the provided path with the directory
79+ * paths if the path start with the following:
80+ * - volume character and a colon ("C:"): it is either absolute path
81+ * (if followed by a backslash), or a relative path to a current
82+ * directory of that volume (and we don't want to implement any logic
83+ * that handles that);
84+ * - backslash ("\"): it is an "absolute path" on the "current" drive,
85+ * or (if there are two backslashes in the beginning) an UNC path.
86+ */
87+ return (isalpha (path [0 ]) && path [1 ] == ':' ) || path [0 ] == '\\' ;
88+ #else /* !_WIN32 */
89+ return path [0 ] == '/' ;
90+ #endif
91+ }
92+
93+ static X509 *
94+ load_nonce_from_path (struct nonce_cfg * cfg )
95+ {
96+ if (is_abs_path (cfg -> path ))
97+ return load_nonce_from_file (cfg -> path );
98+
99+ for (size_t i = 0 ; i < cfg -> num_dirs ; i ++ ) {
100+ char * cert ;
101+ X509 * ret ;
102+
103+ cert = perflib_mk_file_path (cfg -> dirs [i ], cfg -> path );
104+ if (cert == NULL ) {
105+ warnx ("Failed to allocate file path for directory \"%s\""
106+ " and path \"%s\"" , cfg -> dirs [i ], cfg -> path );
107+ continue ;
108+ }
109+
110+ ret = load_nonce_from_file (cert );
111+ OPENSSL_free (cert );
112+
113+ if (ret != NULL )
114+ return ret ;
115+ }
116+
117+ return NULL ;
118+ }
119+
120+ static X509 *
121+ make_nonce (struct nonce_cfg * cfg )
122+ {
123+ switch (cfg -> type ) {
124+ case NONCE_PATH :
125+ return load_nonce_from_path (cfg );
126+ default :
127+ errx (EXIT_FAILURE , "Unknown nonce type: %lld" , (long long ) cfg -> type );
128+ }
129+ }
130+
37131static void do_x509storeissuer (size_t num )
38132{
39133 X509_STORE_CTX * ctx = X509_STORE_CTX_new ();
40134 X509 * issuer = NULL ;
41135 OSSL_TIME time ;
42136
43- if (ctx == NULL || !X509_STORE_CTX_init (ctx , store , x509 , NULL )) {
137+ if (ctx == NULL || !X509_STORE_CTX_init (ctx , store , x509_nonce , NULL )) {
44138 warnx ("Failed to initialise X509_STORE_CTX" );
45139 error = 1 ;
46140 goto err ;
@@ -54,7 +148,7 @@ static void do_x509storeissuer(size_t num)
54148 * certificates inside our store. We're just testing calling this
55149 * against an empty store.
56150 */
57- if (X509_STORE_CTX_get1_issuer (& issuer , ctx , x509 ) != 0 ) {
151+ if (X509_STORE_CTX_get1_issuer (& issuer , ctx , x509_nonce ) != 0 ) {
58152 warnx ("Unexpected result from X509_STORE_CTX_get1_issuer" );
59153 error = 1 ;
60154 X509_free (issuer );
@@ -73,9 +167,32 @@ static void
73167usage (char * const argv [])
74168{
75169 fprintf (stderr ,
76- "Usage: %s [-t] certsdir threadcount\n"
77- "-t - terse output\n" ,
78- basename (argv [0 ]));
170+ "Usage: %s [-t] [-n nonce_type:type_args] certsdir threadcount\n"
171+ "\t-t\tTerse output\n"
172+ "\t-n\tNonce configuration, supported options:\n"
173+ "\t\t\tfile:PATH - load nonce certificate from PATH;\n"
174+ "\t\t\tif PATH is relative, the provided certsdir's are searched.\n"
175+ "\t\tDefault: " NONCE_CFG "\n"
176+ , basename (argv [0 ]));
177+ }
178+
179+ /**
180+ * Parse nonce configuration string. Currently supported formats:
181+ * * "file:PATH" - where PATH is either a relative path (that will be then
182+ * checked against the list of directories provided),
183+ * or an absolute one.
184+ */
185+ static void
186+ parse_nonce_cfg (const char * const optarg , struct nonce_cfg * cfg )
187+ {
188+ static const char file_pfx [] = "file:" ;
189+
190+ if (strncmp (optarg , file_pfx , sizeof (file_pfx ) - 1 ) == 0 ) {
191+ cfg -> type = NONCE_PATH ;
192+ cfg -> path = optarg + sizeof (file_pfx ) - 1 ;
193+ } else {
194+ errx (EXIT_FAILURE , "incorrect nonce configuration: \"%s\"" , optarg );
195+ }
79196}
80197
81198static long long
@@ -106,12 +223,19 @@ int main(int argc, char *argv[])
106223 int ret = EXIT_FAILURE ;
107224 BIO * bio = NULL ;
108225 int opt ;
226+ int dirs_start ;
227+ struct nonce_cfg nonce_cfg ;
109228
110- while ((opt = getopt (argc , argv , "t" )) != -1 ) {
229+ parse_nonce_cfg (NONCE_CFG , & nonce_cfg );
230+
231+ while ((opt = getopt (argc , argv , "tn:" )) != -1 ) {
111232 switch (opt ) {
112233 case 't' :
113234 terse = 1 ;
114235 break ;
236+ case 'n' : /* nonce */
237+ parse_nonce_cfg (optarg , & nonce_cfg );
238+ break ;
115239 default :
116240 usage (argv );
117241 return EXIT_FAILURE ;
@@ -121,11 +245,14 @@ int main(int argc, char *argv[])
121245 if (argv [optind ] == NULL )
122246 errx (EXIT_FAILURE , "certsdir is missing" );
123247
124- cert = perflib_mk_file_path (argv [optind ], "servercert.pem" );
125- if (cert == NULL )
126- errx (EXIT_FAILURE , "Failed to allocate cert path" );
248+ dirs_start = optind ++ ;
127249
128- optind ++ ;
250+ /*
251+ * Store the part of argv containing directories to nonce_cfg so
252+ * load_nonce_from_path can use it later.
253+ */
254+ nonce_cfg .dirs = argv + dirs_start ;
255+ nonce_cfg .num_dirs = 1 ;
129256
130257 if (argv [optind ] == NULL )
131258 errx (EXIT_FAILURE , "threadcount is missing" );
@@ -136,21 +263,14 @@ int main(int argc, char *argv[])
136263 if (store == NULL || !X509_STORE_set_default_paths (store ))
137264 errx (EXIT_FAILURE , "Failed to create X509_STORE" );
138265
139- bio = BIO_new_file (cert , "rb" );
140- if (bio == NULL )
141- errx (EXIT_FAILURE , "Unable to load certificate\n" );
142-
143- x509 = PEM_read_bio_X509 (bio , NULL , NULL , NULL );
144- if (x509 == NULL )
145- errx (EXIT_FAILURE , "Failed to read certificate" );
146-
147- BIO_free (bio );
148- bio = NULL ;
149-
150266 counts = OPENSSL_malloc (sizeof (size_t ) * threadcount );
151267 if (counts == NULL )
152268 errx (EXIT_FAILURE , "Failed to create counts array" );
153269
270+ x509_nonce = make_nonce (& nonce_cfg );
271+ if (x509_nonce == NULL )
272+ errx (EXIT_FAILURE , "Unable to create the nonce X509 object" );
273+
154274 max_time = ossl_time_add (ossl_time_now (), ossl_seconds2time (RUN_TIME ));
155275
156276 if (!perflib_run_multi_thread_test (do_x509storeissuer , threadcount , & duration ))
@@ -173,8 +293,8 @@ int main(int argc, char *argv[])
173293 ret = EXIT_SUCCESS ;
174294
175295 err :
296+ X509_free (x509_nonce );
176297 X509_STORE_free (store );
177- X509_free (x509 );
178298 BIO_free (bio );
179299 OPENSSL_free (cert );
180300 OPENSSL_free (counts );
0 commit comments