Skip to content

Commit 106e565

Browse files
committed
x509storeissuer: store excess certificates in a pool for later use
Signed-off-by: Eugene Syromiatnikov <esyr@openssl.org>
1 parent d12e9fa commit 106e565

File tree

1 file changed

+153
-27
lines changed

1 file changed

+153
-27
lines changed

source/x509storeissuer.c

Lines changed: 153 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
109174
static X509 *
110175
load_cert_from_file(const char *path)
111176
{
@@ -190,12 +255,17 @@ make_nonce(struct nonce_cfg *cfg)
190255
}
191256

192257
static 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)
230316
static size_t
231317
read_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) */
288376
static size_t
289377
read_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+
*/
337447
static 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

353475
static 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

Comments
 (0)