Skip to content

Commit 691e131

Browse files
committed
x509storeissuer: add ability to add certificates to the store during the run
Signed-off-by: Eugene Syromiatnikov <[email protected]>
1 parent cdebce4 commit 691e131

File tree

1 file changed

+108
-10
lines changed

1 file changed

+108
-10
lines changed

source/x509storeissuer.c

Lines changed: 108 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,17 @@
3434
#define NUM_LOAD_CERTS 128
3535
#define NUM_KEYS 16
3636
#define KEY_ALGO "rsa:2048"
37+
#define W_PROBABILITY 50
38+
#define MAX_WRITERS 0
3739
#define RUN_TIME 5
3840
#define QUANTILES 5
3941
#define NONCE_CFG "file:servercert.pem"
4042
#define CTX_SHARE_THREADS 1
4143

4244
static size_t timeout_us = RUN_TIME * 1000000;
4345
static size_t quantiles = QUANTILES;
46+
static size_t max_writers = MAX_WRITERS;
47+
static size_t w_probability = W_PROBABILITY * 65536 / 100;
4448

4549
enum verbosity {
4650
VERBOSITY_TERSE,
@@ -52,6 +56,11 @@ enum verbosity {
5256
VERBOSITY_MAX__
5357
};
5458

59+
static enum mode {
60+
MODE_R,
61+
MODE_RW, /* "MODE_W" is just MODE_RW with 100% write probability */
62+
} mode = MODE_R;
63+
5564
enum nonce_type {
5665
NONCE_GENERATED,
5766
NONCE_PATH,
@@ -61,6 +70,7 @@ struct call_times {
6170
uint64_t duration;
6271
uint64_t total_count;
6372
uint64_t total_found;
73+
uint64_t total_added;
6474
uint64_t min_count;
6575
uint64_t max_count;
6676
double avg;
@@ -84,8 +94,11 @@ struct thread_data {
8494
struct {
8595
uint64_t count;
8696
uint64_t found;
97+
uint64_t added_certs;
8798
OSSL_TIME end_time;
8899
} *q_data;
100+
size_t cert_count;
101+
X509 **certs;
89102
X509_STORE_CTX *ctx;
90103
} *thread_data;
91104

@@ -718,24 +731,38 @@ do_x509storeissuer(size_t num)
718731
OSSL_TIME q_end;
719732
size_t q = 0;
720733
size_t count = 0;
734+
size_t add = 0;
721735
size_t found = 0;
722736

723737
td->start_time = ossl_time_now();
724738
duration.t = max_time.t - td->start_time.t;
725739
q_end.t = duration.t / quantiles + td->start_time.t;
726740

727741
do {
728-
if (X509_STORE_CTX_get1_issuer(&issuer, td->ctx, x509_nonce) != 0) {
729-
found++;
730-
X509_free(issuer);
742+
if (td->cert_count > 0 && (rand() % 65536 < w_probability)) {
743+
size_t cert_id = add % td->cert_count;
744+
745+
if (!X509_STORE_add_cert(store, td->certs[cert_id])) {
746+
warnx("thread %zu: Failed to add generated certificate %zu"
747+
" to the store", num, cert_id);
748+
} else {
749+
add++;
750+
}
751+
} else {
752+
if (X509_STORE_CTX_get1_issuer(&issuer, td->ctx, x509_nonce) != 0) {
753+
found++;
754+
X509_free(issuer);
755+
}
756+
issuer = NULL;
731757
}
732-
issuer = NULL;
758+
733759
count++;
734760
if ((count & 0x3f) == 0) {
735761
time = ossl_time_now();
736762
if (time.t >= q_end.t) {
737763
td->q_data[q].count = count;
738764
td->q_data[q].found = found;
765+
td->q_data[q].added_certs = add;
739766
td->q_data[q].end_time = time;
740767
q_end.t = (duration.t * (++q + 1)) / quantiles + td->start_time.t;
741768
}
@@ -744,6 +771,7 @@ do_x509storeissuer(size_t num)
744771

745772
td->q_data[quantiles - 1].count = count;
746773
td->q_data[quantiles - 1].found = found;
774+
td->q_data[quantiles - 1].added_certs = add;
747775
td->q_data[quantiles - 1].end_time = time;
748776
}
749777

@@ -790,17 +818,21 @@ get_calltimes(struct call_times *times, int verbosity)
790818
(q ? thread_data[i].q_data[q - 1].count : 0);
791819
uint64_t found = thread_data[i].q_data[q].found -
792820
(q ? thread_data[i].q_data[q - 1].found : 0);
821+
uint64_t add = thread_data[i].q_data[q].added_certs -
822+
(q ? thread_data[i].q_data[q - 1].added_certs : 0);
793823

794824
times[q].duration += thread_data[i].q_data[q].end_time.t - start_t;
795825
times[q].total_count += count;
796826
times[q].total_found += found;
827+
times[q].total_added += add;
797828
}
798829
}
799830

800831
for (size_t q = 0; q < quantiles; q++) {
801832
times[quantiles].duration += times[q].duration;
802833
times[quantiles].total_count += times[q].total_count;
803834
times[quantiles].total_found += times[q].total_found;
835+
times[quantiles].total_added += times[q].total_added;
804836
}
805837

806838
for (size_t q = (quantiles == 1); q <= quantiles; q++)
@@ -885,14 +917,18 @@ report_result(int verbosity)
885917
printf(": avg: %9.3lf us, median: %9.3lf us"
886918
", min: %9.3lf us @thread %3zu, max: %9.3lf us @thread %3zu"
887919
", stddev: %9.3lf us (%8.4lf%%)"
888-
", hits %9zu of %9zu (%8.4lf%%)\n",
920+
", hits %9zu of %9zu (%8.4lf%%)"
921+
", added certs: %zu\n",
889922
times[i].avg, times[i].median,
890923
times[i].min, times[i].min_idx,
891924
times[i].max, times[i].max_idx,
892925
times[i].stddev,
893926
100.0 * times[i].stddev / times[i].avg,
894-
times[i].total_found, times[i].total_count,
895-
100.0 * times[i].total_found / (times[i].total_count));
927+
times[i].total_found,
928+
(times[i].total_count - times[i].total_added),
929+
100.0 * times[i].total_found
930+
/ (times[i].total_count - times[i].total_added),
931+
times[i].total_added);
896932
}
897933
break;
898934
}
@@ -904,8 +940,8 @@ usage(char * const argv[])
904940
fprintf(stderr,
905941
"Usage: %s [-t] [-v] [-q N] [-T time] [-G num] [-g num] "
906942
"[-k num_keys] [-K keyalg[:bits][:param=value...]] "
907-
"[-n nonce_type:type_args] "
908-
"[-C threads] certsdir [certsdir...] threadcount\n"
943+
"[-n nonce_type:type_args] [-m mode] [-w writer_threads] "
944+
"[-W percentage] [-C threads] certsdir [certsdir...] threadcount\n"
909945
"\t-t\tTerse output\n"
910946
"\t-v\tVerbose output. Multiple usage increases verbosity.\n"
911947
"\t-q\tGather information about temporal N-quantiles.\n"
@@ -928,6 +964,13 @@ usage(char * const argv[])
928964
"\t\t\tfile:PATH - load nonce certificate from PATH;\n"
929965
"\t\t\tif PATH is relative, the provided certsdir's are searched.\n"
930966
"\t\tDefault: " NONCE_CFG "\n"
967+
"\t-m\tTest mode, can be one of r, rw. Default: r\n"
968+
"\t-w\tMaximum number of threads that attempt addition\n"
969+
"\t\tof the new certificates to the store in rw mode,\n"
970+
"\t\t0 is unlimited. Default: " OPENSSL_MSTR(MAX_WRITERS) "\n"
971+
"\t-W\tProbability of a certificate being written\n"
972+
"\t\tto the store, instead of being queried,\n"
973+
"\t\tin percents. Default: " OPENSSL_MSTR(W_PROBABILITY) "\n"
931974
"\t-C\tNumber of threads that share the same X.509\n"
932975
"\t\tstore context object. Default: "
933976
OPENSSL_MSTR(CTX_SHARE_THREADS) "\n"
@@ -951,8 +994,23 @@ parse_timeout(const char * const optarg)
951994
return timeout_s * 1e6;
952995
}
953996

997+
static double
998+
parse_probability(const char * const optarg)
999+
{
1000+
char *endptr = NULL;
1001+
double prob;
1002+
1003+
prob = strtod(optarg, &endptr);
1004+
1005+
if (endptr == NULL || *endptr != '\0' || prob < 0 || prob > 100)
1006+
errx(EXIT_FAILURE, "incorrect probability value: \"%s\"", optarg);
1007+
1008+
return prob;
1009+
}
1010+
9541011
/**
9551012
* Parse nonce configuration string. Currently supported formats:
1013+
* * "gen" - generate a nonce certificate
9561014
* * "file:PATH" - where PATH is either a relative path (that will be then
9571015
* checked against the list of directories provided),
9581016
* or an absolute one.
@@ -1014,7 +1072,7 @@ main(int argc, char *argv[])
10141072

10151073
parse_nonce_cfg(NONCE_CFG, &nonce_cfg);
10161074

1017-
while ((opt = getopt(argc, argv, "tvq:T:G:g:k:K:n:C:")) != -1) {
1075+
while ((opt = getopt(argc, argv, "tvq:T:G:g:k:K:m:n:w:W:C:")) != -1) {
10181076
switch (opt) {
10191077
case 't': /* terse */
10201078
verbosity = VERBOSITY_TERSE;
@@ -1051,9 +1109,24 @@ main(int argc, char *argv[])
10511109
case 'K': /* key type */
10521110
gen_key_algo = optarg;
10531111
break;
1112+
case 'm': /* mode */
1113+
if (strcasecmp(optarg, "r") == 0) {
1114+
mode = MODE_R;
1115+
} else if (strcasecmp(optarg, "rw") == 0) {
1116+
mode = MODE_RW;
1117+
} else {
1118+
errx(EXIT_FAILURE, "Unknown mode: \"%s\"", optarg);
1119+
}
1120+
break;
10541121
case 'n': /* nonce */
10551122
parse_nonce_cfg(optarg, &nonce_cfg);
10561123
break;
1124+
case 'w': /* maximum writers */
1125+
max_writers = parse_int(optarg, 0, INT_MAX,
1126+
"maximum number of writers");
1127+
case 'W': /* percent of writes */
1128+
w_probability = (size_t) (parse_probability(optarg) * 65536 / 100);
1129+
break;
10571130
case 'C': /* how many threads share X509_STORE_CTX */
10581131
ctx_share_cnt = parse_int(optarg, 1, INT_MAX,
10591132
"X509_STORE_CTX share degree");
@@ -1074,6 +1147,11 @@ main(int argc, char *argv[])
10741147
if (num_gen_certs < num_gen_load_certs)
10751148
errx(EXIT_FAILURE, "Cannot load more certificates than generate");
10761149

1150+
if (num_gen_certs == num_gen_load_certs && mode == MODE_RW)
1151+
errx(EXIT_FAILURE, "No generated certificates to use after"
1152+
" the initially loaded ones, please increase"
1153+
" -G to be more than -g");
1154+
10771155
if (argv[optind] == NULL)
10781156
errx(EXIT_FAILURE, "certsdir is missing");
10791157

@@ -1177,6 +1255,23 @@ main(int argc, char *argv[])
11771255
}
11781256
}
11791257

1258+
if (mode == MODE_RW) {
1259+
size_t writers = max_writers ? OSSL_MIN(max_writers, threadcount)
1260+
: threadcount;
1261+
size_t cnt = num_gen_certs - num_gen_load_certs;
1262+
1263+
/*
1264+
* Point each writer thread at the part of the generated certs
1265+
* array it uses for store population.
1266+
*/
1267+
for (size_t i = 0; i < writers; i++) {
1268+
size_t offs = (cnt * i) / writers;
1269+
1270+
thread_data[i].certs = gen_certs + num_gen_load_certs + offs;
1271+
thread_data[i].cert_count = OSSL_MAX(cnt / writers, 1);
1272+
}
1273+
}
1274+
11801275
max_time = ossl_time_add(ossl_time_now(), ossl_us2time(timeout_us));
11811276

11821277
if (!perflib_run_multi_thread_test(do_x509storeissuer, threadcount, &duration))
@@ -1185,6 +1280,9 @@ main(int argc, char *argv[])
11851280
if (error)
11861281
errx(EXIT_FAILURE, "Error during test");
11871282

1283+
if (mode == MODE_RW)
1284+
report_store_size(store, "after the test run", verbosity);
1285+
11881286
report_result(verbosity);
11891287

11901288
ret = EXIT_SUCCESS;

0 commit comments

Comments
 (0)