]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/x509/by_dir.c
Make evp_pkey_ctx_get0_libctx/propq public API
[thirdparty/openssl.git] / crypto / x509 / by_dir.c
CommitLineData
b1322259 1/*
33388b44 2 * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
d02b48c6 3 *
3e4b43b9 4 * Licensed under the Apache License 2.0 (the "License"). You may not use
b1322259
RS
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
d02b48c6
RE
8 */
9
07016a8a
P
10#include "e_os.h"
11#include "internal/cryptlib.h"
d02b48c6
RE
12#include <stdio.h>
13#include <time.h>
14#include <errno.h>
b379fe6c 15#include <sys/types.h>
d02b48c6 16
49e3c9d8 17#ifndef OPENSSL_NO_POSIX_IO
17f389bb
AP
18# include <sys/stat.h>
19#endif
20
ec577822 21#include <openssl/x509.h>
25f2138b 22#include "crypto/x509.h"
706457b7 23#include "x509_local.h"
d02b48c6 24
4a1f3f27 25struct lookup_dir_hashes_st {
0f113f3e
MC
26 unsigned long hash;
27 int suffix;
4a1f3f27 28};
5d20c4fb 29
4a1f3f27 30struct lookup_dir_entry_st {
0f113f3e
MC
31 char *dir;
32 int dir_type;
33 STACK_OF(BY_DIR_HASH) *hashes;
4a1f3f27 34};
5d20c4fb 35
0f113f3e
MC
36typedef struct lookup_dir_st {
37 BUF_MEM *buffer;
38 STACK_OF(BY_DIR_ENTRY) *dirs;
4fc4faa7 39 CRYPTO_RWLOCK *lock;
0f113f3e 40} BY_DIR;
d02b48c6 41
303c0028 42static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,
6725682d
SL
43 char **retp);
44
d02b48c6
RE
45static int new_dir(X509_LOOKUP *lu);
46static void free_dir(X509_LOOKUP *lu);
0f113f3e 47static int add_cert_dir(BY_DIR *ctx, const char *dir, int type);
0946a198 48static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
8cc86b81 49 const X509_NAME *name, X509_OBJECT *ret);
d8652be0
MC
50static int get_cert_by_subject_ex(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
51 const X509_NAME *name, X509_OBJECT *ret,
52 OPENSSL_CTX *libctx, const char *propq);
df2ee0e2 53static X509_LOOKUP_METHOD x509_dir_lookup = {
0f113f3e 54 "Load certs from files in a directory",
6725682d
SL
55 new_dir, /* new_item */
56 free_dir, /* free */
57 NULL, /* init */
58 NULL, /* shutdown */
59 dir_ctrl, /* ctrl */
60 get_cert_by_subject, /* get_by_subject */
61 NULL, /* get_by_issuer_serial */
62 NULL, /* get_by_fingerprint */
63 NULL, /* get_by_alias */
746f3674 64 get_cert_by_subject_ex, /* get_by_subject_ex */
d8652be0 65 NULL, /* ctrl_ex */
0f113f3e 66};
d02b48c6 67
6b691a5c 68X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void)
0f113f3e 69{
26a7d938 70 return &x509_dir_lookup;
0f113f3e 71}
d02b48c6 72
303c0028 73static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,
0f113f3e
MC
74 char **retp)
75{
76 int ret = 0;
7fcdbd83 77 BY_DIR *ld = (BY_DIR *)ctx->method_data;
0f113f3e
MC
78
79 switch (cmd) {
80 case X509_L_ADD_DIR:
81 if (argl == X509_FILETYPE_DEFAULT) {
5c39a55d 82 const char *dir = ossl_safe_getenv(X509_get_default_cert_dir_env());
7fcdbd83 83
0f113f3e
MC
84 if (dir)
85 ret = add_cert_dir(ld, dir, X509_FILETYPE_PEM);
86 else
87 ret = add_cert_dir(ld, X509_get_default_cert_dir(),
88 X509_FILETYPE_PEM);
89 if (!ret) {
90 X509err(X509_F_DIR_CTRL, X509_R_LOADING_CERT_DIR);
91 }
92 } else
93 ret = add_cert_dir(ld, argp, (int)argl);
94 break;
95 }
26a7d938 96 return ret;
0f113f3e 97}
d02b48c6 98
6b691a5c 99static int new_dir(X509_LOOKUP *lu)
0f113f3e 100{
7fcdbd83 101 BY_DIR *a = OPENSSL_malloc(sizeof(*a));
0f113f3e 102
7fcdbd83
F
103 if (a == NULL) {
104 X509err(X509_F_NEW_DIR, ERR_R_MALLOC_FAILURE);
4fc4faa7 105 return 0;
7fcdbd83
F
106 }
107
0f113f3e 108 if ((a->buffer = BUF_MEM_new()) == NULL) {
7fcdbd83
F
109 X509err(X509_F_NEW_DIR, ERR_R_MALLOC_FAILURE);
110 goto err;
0f113f3e
MC
111 }
112 a->dirs = NULL;
4fc4faa7
MC
113 a->lock = CRYPTO_THREAD_lock_new();
114 if (a->lock == NULL) {
115 BUF_MEM_free(a->buffer);
7fcdbd83
F
116 X509err(X509_F_NEW_DIR, ERR_R_MALLOC_FAILURE);
117 goto err;
4fc4faa7 118 }
0124f32a 119 lu->method_data = a;
4fc4faa7 120 return 1;
7fcdbd83
F
121
122 err:
123 OPENSSL_free(a);
124 return 0;
0f113f3e 125}
d02b48c6 126
5d20c4fb 127static void by_dir_hash_free(BY_DIR_HASH *hash)
0f113f3e
MC
128{
129 OPENSSL_free(hash);
130}
131
132static int by_dir_hash_cmp(const BY_DIR_HASH *const *a,
133 const BY_DIR_HASH *const *b)
134{
135 if ((*a)->hash > (*b)->hash)
136 return 1;
137 if ((*a)->hash < (*b)->hash)
138 return -1;
139 return 0;
140}
5d20c4fb
DSH
141
142static void by_dir_entry_free(BY_DIR_ENTRY *ent)
0f113f3e 143{
b548a1f1 144 OPENSSL_free(ent->dir);
25aaa98a 145 sk_BY_DIR_HASH_pop_free(ent->hashes, by_dir_hash_free);
0f113f3e
MC
146 OPENSSL_free(ent);
147}
5d20c4fb 148
6b691a5c 149static void free_dir(X509_LOOKUP *lu)
0f113f3e 150{
7fcdbd83 151 BY_DIR *a = (BY_DIR *)lu->method_data;
d02b48c6 152
25aaa98a
RS
153 sk_BY_DIR_ENTRY_pop_free(a->dirs, by_dir_entry_free);
154 BUF_MEM_free(a->buffer);
4fc4faa7 155 CRYPTO_THREAD_lock_free(a->lock);
0f113f3e
MC
156 OPENSSL_free(a);
157}
d02b48c6 158
6b691a5c 159static int add_cert_dir(BY_DIR *ctx, const char *dir, int type)
0f113f3e 160{
53a73768
P
161 int j;
162 size_t len;
582e2ed2 163 const char *s, *ss, *p;
0f113f3e 164
12a765a5 165 if (dir == NULL || *dir == '\0') {
0f113f3e
MC
166 X509err(X509_F_ADD_CERT_DIR, X509_R_INVALID_DIRECTORY);
167 return 0;
168 }
169
170 s = dir;
171 p = s;
172 do {
173 if ((*p == LIST_SEPARATOR_CHAR) || (*p == '\0')) {
174 BY_DIR_ENTRY *ent;
7fcdbd83 175
582e2ed2 176 ss = s;
0f113f3e 177 s = p + 1;
53a73768 178 len = p - ss;
0f113f3e
MC
179 if (len == 0)
180 continue;
181 for (j = 0; j < sk_BY_DIR_ENTRY_num(ctx->dirs); j++) {
182 ent = sk_BY_DIR_ENTRY_value(ctx->dirs, j);
6ffaf15d 183 if (strlen(ent->dir) == len && strncmp(ent->dir, ss, len) == 0)
0f113f3e
MC
184 break;
185 }
186 if (j < sk_BY_DIR_ENTRY_num(ctx->dirs))
187 continue;
188 if (ctx->dirs == NULL) {
189 ctx->dirs = sk_BY_DIR_ENTRY_new_null();
190 if (!ctx->dirs) {
191 X509err(X509_F_ADD_CERT_DIR, ERR_R_MALLOC_FAILURE);
192 return 0;
193 }
194 }
b4faea50 195 ent = OPENSSL_malloc(sizeof(*ent));
7fcdbd83
F
196 if (ent == NULL) {
197 X509err(X509_F_ADD_CERT_DIR, ERR_R_MALLOC_FAILURE);
0f113f3e 198 return 0;
7fcdbd83 199 }
0f113f3e
MC
200 ent->dir_type = type;
201 ent->hashes = sk_BY_DIR_HASH_new(by_dir_hash_cmp);
6ffaf15d 202 ent->dir = OPENSSL_strndup(ss, len);
90945fa3 203 if (ent->dir == NULL || ent->hashes == NULL) {
0f113f3e
MC
204 by_dir_entry_free(ent);
205 return 0;
206 }
0f113f3e
MC
207 if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) {
208 by_dir_entry_free(ent);
7fcdbd83 209 X509err(X509_F_ADD_CERT_DIR, ERR_R_MALLOC_FAILURE);
0f113f3e
MC
210 return 0;
211 }
212 }
213 } while (*p++ != '\0');
214 return 1;
215}
d02b48c6 216
d8652be0
MC
217static int get_cert_by_subject_ex(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
218 const X509_NAME *name, X509_OBJECT *ret,
219 OPENSSL_CTX *libctx, const char *propq)
0f113f3e
MC
220{
221 BY_DIR *ctx;
222 union {
5cf6abd8 223 X509 st_x509;
7aef39a7 224 X509_CRL crl;
0f113f3e
MC
225 } data;
226 int ok = 0;
227 int i, j, k;
228 unsigned long h;
229 BUF_MEM *b = NULL;
230 X509_OBJECT stmp, *tmp;
231 const char *postfix = "";
232
233 if (name == NULL)
26a7d938 234 return 0;
0f113f3e
MC
235
236 stmp.type = type;
237 if (type == X509_LU_X509) {
8cc86b81 238 data.st_x509.cert_info.subject = (X509_NAME *)name; /* won't modify it */
5cf6abd8 239 stmp.data.x509 = &data.st_x509;
0f113f3e
MC
240 postfix = "";
241 } else if (type == X509_LU_CRL) {
8cc86b81 242 data.crl.crl.issuer = (X509_NAME *)name; /* won't modify it */
7aef39a7 243 stmp.data.crl = &data.crl;
0f113f3e
MC
244 postfix = "r";
245 } else {
6725682d 246 X509err(0, X509_R_WRONG_LOOKUP_TYPE);
0f113f3e
MC
247 goto finish;
248 }
249
250 if ((b = BUF_MEM_new()) == NULL) {
6725682d 251 X509err(0, ERR_R_BUF_LIB);
0f113f3e
MC
252 goto finish;
253 }
254
255 ctx = (BY_DIR *)xl->method_data;
256
257 h = X509_NAME_hash(name);
258 for (i = 0; i < sk_BY_DIR_ENTRY_num(ctx->dirs); i++) {
259 BY_DIR_ENTRY *ent;
260 int idx;
261 BY_DIR_HASH htmp, *hent;
7fcdbd83 262
0f113f3e
MC
263 ent = sk_BY_DIR_ENTRY_value(ctx->dirs, i);
264 j = strlen(ent->dir) + 1 + 8 + 6 + 1 + 1;
265 if (!BUF_MEM_grow(b, j)) {
6725682d 266 X509err(0, ERR_R_MALLOC_FAILURE);
0f113f3e
MC
267 goto finish;
268 }
269 if (type == X509_LU_CRL && ent->hashes) {
270 htmp.hash = h;
4fc4faa7 271 CRYPTO_THREAD_read_lock(ctx->lock);
0f113f3e
MC
272 idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp);
273 if (idx >= 0) {
274 hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
275 k = hent->suffix;
276 } else {
277 hent = NULL;
278 k = 0;
279 }
4fc4faa7 280 CRYPTO_THREAD_unlock(ctx->lock);
0f113f3e
MC
281 } else {
282 k = 0;
283 hent = NULL;
284 }
285 for (;;) {
286 char c = '/';
19431e5e 287
af6dab9b 288#ifdef OPENSSL_SYS_VMS
0f113f3e
MC
289 c = ent->dir[strlen(ent->dir) - 1];
290 if (c != ':' && c != '>' && c != ']') {
291 /*
292 * If no separator is present, we assume the directory
293 * specifier is a logical name, and add a colon. We really
294 * should use better VMS routines for merging things like
295 * this, but this will do for now... -- Richard Levitte
296 */
297 c = ':';
298 } else {
299 c = '\0';
300 }
19431e5e 301
0f113f3e
MC
302 if (c == '\0') {
303 /*
304 * This is special. When c == '\0', no directory separator
305 * should be added.
306 */
307 BIO_snprintf(b->data, b->max,
308 "%s%08lx.%s%d", ent->dir, h, postfix, k);
19431e5e
P
309 } else
310#endif
311 {
a2371fa9
P
312 BIO_snprintf(b->data, b->max,
313 "%s%c%08lx.%s%d", ent->dir, c, h, postfix, k);
0f113f3e 314 }
49e3c9d8 315#ifndef OPENSSL_NO_POSIX_IO
0f113f3e
MC
316# ifdef _WIN32
317# define stat _stat
318# endif
319 {
320 struct stat st;
321 if (stat(b->data, &st) < 0)
322 break;
323 }
49e3c9d8 324#endif
0f113f3e
MC
325 /* found one. */
326 if (type == X509_LU_X509) {
d8652be0
MC
327 if ((X509_load_cert_file_ex(xl, b->data, ent->dir_type, libctx,
328 propq)) == 0)
0f113f3e
MC
329 break;
330 } else if (type == X509_LU_CRL) {
331 if ((X509_load_crl_file(xl, b->data, ent->dir_type)) == 0)
332 break;
333 }
334 /* else case will caught higher up */
335 k++;
336 }
337
338 /*
339 * we have added it to the cache so now pull it out again
340 */
a161738a 341 X509_STORE_lock(xl->store_ctx);
0f113f3e 342 j = sk_X509_OBJECT_find(xl->store_ctx->objs, &stmp);
5b37fef0 343 tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, j);
a161738a 344 X509_STORE_unlock(xl->store_ctx);
0f113f3e
MC
345
346 /* If a CRL, update the last file suffix added for this */
347
348 if (type == X509_LU_CRL) {
4fc4faa7 349 CRYPTO_THREAD_write_lock(ctx->lock);
0f113f3e
MC
350 /*
351 * Look for entry again in case another thread added an entry
352 * first.
353 */
5b37fef0 354 if (hent == NULL) {
0f113f3e
MC
355 htmp.hash = h;
356 idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp);
5b37fef0 357 hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
0f113f3e 358 }
7fcdbd83 359 if (hent == NULL) {
b4faea50 360 hent = OPENSSL_malloc(sizeof(*hent));
0f113f3e 361 if (hent == NULL) {
4fc4faa7 362 CRYPTO_THREAD_unlock(ctx->lock);
6725682d 363 X509err(0, ERR_R_MALLOC_FAILURE);
0f113f3e
MC
364 ok = 0;
365 goto finish;
366 }
367 hent->hash = h;
368 hent->suffix = k;
369 if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) {
4fc4faa7 370 CRYPTO_THREAD_unlock(ctx->lock);
0f113f3e 371 OPENSSL_free(hent);
6725682d 372 X509err(0, ERR_R_MALLOC_FAILURE);
0f113f3e
MC
373 ok = 0;
374 goto finish;
375 }
4fc4faa7 376 } else if (hent->suffix < k) {
0f113f3e 377 hent->suffix = k;
4fc4faa7 378 }
0f113f3e 379
4fc4faa7 380 CRYPTO_THREAD_unlock(ctx->lock);
0f113f3e
MC
381
382 }
383
384 if (tmp != NULL) {
385 ok = 1;
386 ret->type = tmp->type;
387 memcpy(&ret->data, &tmp->data, sizeof(ret->data));
c0452248
RS
388
389 /*
390 * Clear any errors that might have been raised processing empty
391 * or malformed files.
392 */
393 ERR_clear_error();
394
0f113f3e
MC
395 goto finish;
396 }
397 }
398 finish:
25aaa98a 399 BUF_MEM_free(b);
26a7d938 400 return ok;
0f113f3e 401}
6725682d
SL
402
403static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
404 const X509_NAME *name, X509_OBJECT *ret)
405{
d8652be0 406 return get_cert_by_subject_ex(xl, type, name, ret, NULL, NULL);
6725682d 407}