Branch data Line data Source code
1 : : /* crypto/x509/by_dir.c */
2 : : /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 : : * All rights reserved.
4 : : *
5 : : * This package is an SSL implementation written
6 : : * by Eric Young (eay@cryptsoft.com).
7 : : * The implementation was written so as to conform with Netscapes SSL.
8 : : *
9 : : * This library is free for commercial and non-commercial use as long as
10 : : * the following conditions are aheared to. The following conditions
11 : : * apply to all code found in this distribution, be it the RC4, RSA,
12 : : * lhash, DES, etc., code; not just the SSL code. The SSL documentation
13 : : * included with this distribution is covered by the same copyright terms
14 : : * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 : : *
16 : : * Copyright remains Eric Young's, and as such any Copyright notices in
17 : : * the code are not to be removed.
18 : : * If this package is used in a product, Eric Young should be given attribution
19 : : * as the author of the parts of the library used.
20 : : * This can be in the form of a textual message at program startup or
21 : : * in documentation (online or textual) provided with the package.
22 : : *
23 : : * Redistribution and use in source and binary forms, with or without
24 : : * modification, are permitted provided that the following conditions
25 : : * are met:
26 : : * 1. Redistributions of source code must retain the copyright
27 : : * notice, this list of conditions and the following disclaimer.
28 : : * 2. Redistributions in binary form must reproduce the above copyright
29 : : * notice, this list of conditions and the following disclaimer in the
30 : : * documentation and/or other materials provided with the distribution.
31 : : * 3. All advertising materials mentioning features or use of this software
32 : : * must display the following acknowledgement:
33 : : * "This product includes cryptographic software written by
34 : : * Eric Young (eay@cryptsoft.com)"
35 : : * The word 'cryptographic' can be left out if the rouines from the library
36 : : * being used are not cryptographic related :-).
37 : : * 4. If you include any Windows specific code (or a derivative thereof) from
38 : : * the apps directory (application code) you must include an acknowledgement:
39 : : * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 : : *
41 : : * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 : : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 : : * SUCH DAMAGE.
52 : : *
53 : : * The licence and distribution terms for any publically available version or
54 : : * derivative of this code cannot be changed. i.e. this code cannot simply be
55 : : * copied and put under another distribution licence
56 : : * [including the GNU Public Licence.]
57 : : */
58 : :
59 : : #include <stdio.h>
60 : : #include <time.h>
61 : : #include <errno.h>
62 : :
63 : : #include "cryptlib.h"
64 : :
65 : : #ifndef NO_SYS_TYPES_H
66 : : # include <sys/types.h>
67 : : #endif
68 : : #ifndef OPENSSL_NO_POSIX_IO
69 : : # include <sys/stat.h>
70 : : #endif
71 : :
72 : : #include <openssl/lhash.h>
73 : : #include <openssl/x509.h>
74 : :
75 : :
76 : : typedef struct lookup_dir_hashes_st
77 : : {
78 : : unsigned long hash;
79 : : int suffix;
80 : : } BY_DIR_HASH;
81 : :
82 : : typedef struct lookup_dir_entry_st
83 : : {
84 : : char *dir;
85 : : int dir_type;
86 : : STACK_OF(BY_DIR_HASH) *hashes;
87 : : } BY_DIR_ENTRY;
88 : :
89 : : typedef struct lookup_dir_st
90 : : {
91 : : BUF_MEM *buffer;
92 : : STACK_OF(BY_DIR_ENTRY) *dirs;
93 : : } BY_DIR;
94 : :
95 : : DECLARE_STACK_OF(BY_DIR_HASH)
96 : : DECLARE_STACK_OF(BY_DIR_ENTRY)
97 : :
98 : : static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,
99 : : char **ret);
100 : : static int new_dir(X509_LOOKUP *lu);
101 : : static void free_dir(X509_LOOKUP *lu);
102 : : static int add_cert_dir(BY_DIR *ctx,const char *dir,int type);
103 : : static int get_cert_by_subject(X509_LOOKUP *xl,int type,X509_NAME *name,
104 : : X509_OBJECT *ret);
105 : : X509_LOOKUP_METHOD x509_dir_lookup=
106 : : {
107 : : "Load certs from files in a directory",
108 : : new_dir, /* new */
109 : : free_dir, /* free */
110 : : NULL, /* init */
111 : : NULL, /* shutdown */
112 : : dir_ctrl, /* ctrl */
113 : : get_cert_by_subject, /* get_by_subject */
114 : : NULL, /* get_by_issuer_serial */
115 : : NULL, /* get_by_fingerprint */
116 : : NULL, /* get_by_alias */
117 : : };
118 : :
119 : 645 : X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void)
120 : : {
121 : 645 : return(&x509_dir_lookup);
122 : : }
123 : :
124 : 645 : static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,
125 : : char **retp)
126 : : {
127 : 645 : int ret=0;
128 : : BY_DIR *ld;
129 : 645 : char *dir = NULL;
130 : :
131 : 645 : ld=(BY_DIR *)ctx->method_data;
132 : :
133 [ + - ]: 645 : switch (cmd)
134 : : {
135 : : case X509_L_ADD_DIR:
136 [ + + ]: 645 : if (argl == X509_FILETYPE_DEFAULT)
137 : : {
138 : 590 : dir=(char *)getenv(X509_get_default_cert_dir_env());
139 [ - + ]: 590 : if (dir)
140 : 0 : ret=add_cert_dir(ld,dir,X509_FILETYPE_PEM);
141 : : else
142 : 590 : ret=add_cert_dir(ld,X509_get_default_cert_dir(),
143 : : X509_FILETYPE_PEM);
144 [ - + ]: 590 : if (!ret)
145 : : {
146 : 0 : X509err(X509_F_DIR_CTRL,X509_R_LOADING_CERT_DIR);
147 : : }
148 : : }
149 : : else
150 : 55 : ret=add_cert_dir(ld,argp,(int)argl);
151 : : break;
152 : : }
153 : 645 : return(ret);
154 : : }
155 : :
156 : 645 : static int new_dir(X509_LOOKUP *lu)
157 : : {
158 : : BY_DIR *a;
159 : :
160 [ + - ]: 645 : if ((a=(BY_DIR *)OPENSSL_malloc(sizeof(BY_DIR))) == NULL)
161 : : return(0);
162 [ - + ]: 645 : if ((a->buffer=BUF_MEM_new()) == NULL)
163 : : {
164 : 0 : OPENSSL_free(a);
165 : 0 : return(0);
166 : : }
167 : 645 : a->dirs=NULL;
168 : 645 : lu->method_data=(char *)a;
169 : 645 : return(1);
170 : : }
171 : :
172 : 0 : static void by_dir_hash_free(BY_DIR_HASH *hash)
173 : : {
174 : 0 : OPENSSL_free(hash);
175 : 0 : }
176 : :
177 : 0 : static int by_dir_hash_cmp(const BY_DIR_HASH * const *a,
178 : : const BY_DIR_HASH * const *b)
179 : : {
180 [ # # ]: 0 : if ((*a)->hash > (*b)->hash)
181 : : return 1;
182 [ # # ]: 0 : if ((*a)->hash < (*b)->hash)
183 : : return -1;
184 : 0 : return 0;
185 : : }
186 : :
187 : 645 : static void by_dir_entry_free(BY_DIR_ENTRY *ent)
188 : : {
189 [ + - ]: 645 : if (ent->dir)
190 : 645 : OPENSSL_free(ent->dir);
191 [ + - ]: 645 : if (ent->hashes)
192 : 645 : sk_BY_DIR_HASH_pop_free(ent->hashes, by_dir_hash_free);
193 : 645 : OPENSSL_free(ent);
194 : 645 : }
195 : :
196 : 645 : static void free_dir(X509_LOOKUP *lu)
197 : : {
198 : : BY_DIR *a;
199 : :
200 : 645 : a=(BY_DIR *)lu->method_data;
201 [ + - ]: 645 : if (a->dirs != NULL)
202 : 645 : sk_BY_DIR_ENTRY_pop_free(a->dirs, by_dir_entry_free);
203 [ + - ]: 645 : if (a->buffer != NULL)
204 : 645 : BUF_MEM_free(a->buffer);
205 : 645 : OPENSSL_free(a);
206 : 645 : }
207 : :
208 : 645 : static int add_cert_dir(BY_DIR *ctx, const char *dir, int type)
209 : : {
210 : : int j,len;
211 : : const char *s,*ss,*p;
212 : :
213 [ + - ][ - + ]: 645 : if (dir == NULL || !*dir)
214 : : {
215 : 645 : X509err(X509_F_ADD_CERT_DIR,X509_R_INVALID_DIRECTORY);
216 : : return 0;
217 : : }
218 : :
219 : : s=dir;
220 : : p=s;
221 : : do
222 : : {
223 [ + + ]: 12944 : if ((*p == LIST_SEPARATOR_CHAR) || (*p == '\0'))
224 : : {
225 : : BY_DIR_ENTRY *ent;
226 : 645 : ss=s;
227 : 645 : s=p+1;
228 : 645 : len=(int)(p-ss);
229 [ + - ]: 645 : if (len == 0) continue;
230 [ - + ]: 645 : for (j=0; j < sk_BY_DIR_ENTRY_num(ctx->dirs); j++)
231 : : {
232 : 0 : ent = sk_BY_DIR_ENTRY_value(ctx->dirs, j);
233 [ # # ][ # # ]: 0 : if (strlen(ent->dir) == (size_t)len &&
234 : 0 : strncmp(ent->dir,ss,(unsigned int)len) == 0)
235 : : break;
236 : : }
237 [ - + ]: 645 : if (j < sk_BY_DIR_ENTRY_num(ctx->dirs))
238 : 0 : continue;
239 [ + - ]: 645 : if (ctx->dirs == NULL)
240 : : {
241 : 645 : ctx->dirs = sk_BY_DIR_ENTRY_new_null();
242 [ - + ]: 645 : if (!ctx->dirs)
243 : : {
244 : 0 : X509err(X509_F_ADD_CERT_DIR,ERR_R_MALLOC_FAILURE);
245 : : return 0;
246 : : }
247 : : }
248 : 645 : ent = OPENSSL_malloc(sizeof(BY_DIR_ENTRY));
249 [ + - ]: 645 : if (!ent)
250 : : return 0;
251 : 645 : ent->dir_type = type;
252 : 645 : ent->hashes = sk_BY_DIR_HASH_new(by_dir_hash_cmp);
253 : 645 : ent->dir = OPENSSL_malloc((unsigned int)len+1);
254 [ + - ][ - + ]: 645 : if (!ent->dir || !ent->hashes)
255 : : {
256 : 0 : by_dir_entry_free(ent);
257 : : return 0;
258 : : }
259 : 645 : strncpy(ent->dir,ss,(unsigned int)len);
260 : 645 : ent->dir[len] = '\0';
261 [ - + ]: 645 : if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent))
262 : : {
263 : 0 : by_dir_entry_free(ent);
264 : : return 0;
265 : : }
266 : : }
267 [ + + ]: 12944 : } while (*p++ != '\0');
268 : : return 1;
269 : : }
270 : :
271 : 17 : static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
272 : : X509_OBJECT *ret)
273 : : {
274 : : BY_DIR *ctx;
275 : : union {
276 : : struct {
277 : : X509 st_x509;
278 : : X509_CINF st_x509_cinf;
279 : : } x509;
280 : : struct {
281 : : X509_CRL st_crl;
282 : : X509_CRL_INFO st_crl_info;
283 : : } crl;
284 : : } data;
285 : 17 : int ok=0;
286 : : int i,j,k;
287 : : unsigned long h;
288 : 17 : BUF_MEM *b=NULL;
289 : : X509_OBJECT stmp,*tmp;
290 : 17 : const char *postfix="";
291 : :
292 [ + - ]: 17 : if (name == NULL) return(0);
293 : :
294 : 17 : stmp.type=type;
295 [ + - ]: 17 : if (type == X509_LU_X509)
296 : : {
297 : 17 : data.x509.st_x509.cert_info= &data.x509.st_x509_cinf;
298 : 17 : data.x509.st_x509_cinf.subject=name;
299 : 17 : stmp.data.x509= &data.x509.st_x509;
300 : 17 : postfix="";
301 : : }
302 [ # # ]: 0 : else if (type == X509_LU_CRL)
303 : : {
304 : 0 : data.crl.st_crl.crl= &data.crl.st_crl_info;
305 : 0 : data.crl.st_crl_info.issuer=name;
306 : 0 : stmp.data.crl= &data.crl.st_crl;
307 : 0 : postfix="r";
308 : : }
309 : : else
310 : : {
311 : 0 : X509err(X509_F_GET_CERT_BY_SUBJECT,X509_R_WRONG_LOOKUP_TYPE);
312 : 0 : goto finish;
313 : : }
314 : :
315 [ - + ]: 17 : if ((b=BUF_MEM_new()) == NULL)
316 : : {
317 : 0 : X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_BUF_LIB);
318 : 0 : goto finish;
319 : : }
320 : :
321 : 17 : ctx=(BY_DIR *)xl->method_data;
322 : :
323 : 17 : h=X509_NAME_hash(name);
324 [ + + ]: 32 : for (i=0; i < sk_BY_DIR_ENTRY_num(ctx->dirs); i++)
325 : : {
326 : : BY_DIR_ENTRY *ent;
327 : : int idx;
328 : : BY_DIR_HASH htmp, *hent;
329 : 17 : ent = sk_BY_DIR_ENTRY_value(ctx->dirs, i);
330 : 17 : j=strlen(ent->dir)+1+8+6+1+1;
331 [ - + ]: 17 : if (!BUF_MEM_grow(b,j))
332 : : {
333 : 0 : X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_MALLOC_FAILURE);
334 : 2 : goto finish;
335 : : }
336 [ - + ][ # # ]: 17 : if (type == X509_LU_CRL && ent->hashes)
337 : : {
338 : 0 : htmp.hash = h;
339 : 0 : CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE);
340 : 0 : idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp);
341 [ # # ]: 0 : if (idx >= 0)
342 : : {
343 : 0 : hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
344 : 0 : k = hent->suffix;
345 : : }
346 : : else
347 : : {
348 : : hent = NULL;
349 : : k=0;
350 : : }
351 : 17 : CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
352 : : }
353 : : else
354 : : {
355 : : k = 0;
356 : : hent = NULL;
357 : : }
358 : : for (;;)
359 : : {
360 : 19 : char c = '/';
361 : : #ifdef OPENSSL_SYS_VMS
362 : : c = ent->dir[strlen(ent->dir)-1];
363 : : if (c != ':' && c != '>' && c != ']')
364 : : {
365 : : /* If no separator is present, we assume the
366 : : directory specifier is a logical name, and
367 : : add a colon. We really should use better
368 : : VMS routines for merging things like this,
369 : : but this will do for now...
370 : : -- Richard Levitte */
371 : : c = ':';
372 : : }
373 : : else
374 : : {
375 : : c = '\0';
376 : : }
377 : : #endif
378 : : if (c == '\0')
379 : : {
380 : : /* This is special. When c == '\0', no
381 : : directory separator should be added. */
382 : : BIO_snprintf(b->data,b->max,
383 : : "%s%08lx.%s%d",ent->dir,h,
384 : : postfix,k);
385 : : }
386 : : else
387 : : {
388 : 19 : BIO_snprintf(b->data,b->max,
389 : : "%s%c%08lx.%s%d",ent->dir,c,h,
390 : : postfix,k);
391 : : }
392 : : #ifndef OPENSSL_NO_POSIX_IO
393 : : #ifdef _WIN32
394 : : #define stat _stat
395 : : #endif
396 : : {
397 : : struct stat st;
398 [ + + ]: 19 : if (stat(b->data,&st) < 0)
399 : : break;
400 : : }
401 : : #endif
402 : : /* found one. */
403 [ + - ]: 19 : if (type == X509_LU_X509)
404 : : {
405 [ + - ]: 2 : if ((X509_load_cert_file(xl,b->data,
406 : : ent->dir_type)) == 0)
407 : : break;
408 : : }
409 [ # # ]: 0 : else if (type == X509_LU_CRL)
410 : : {
411 [ # # ]: 0 : if ((X509_load_crl_file(xl,b->data,
412 : : ent->dir_type)) == 0)
413 : : break;
414 : : }
415 : : /* else case will caught higher up */
416 : 2 : k++;
417 : 2 : }
418 : :
419 : : /* we have added it to the cache so now pull
420 : : * it out again */
421 : 17 : CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
422 : 17 : j = sk_X509_OBJECT_find(xl->store_ctx->objs,&stmp);
423 [ + + ]: 17 : if(j != -1) tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,j);
424 : : else tmp = NULL;
425 : 17 : CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
426 : :
427 : :
428 : : /* If a CRL, update the last file suffix added for this */
429 : :
430 [ - + ]: 17 : if (type == X509_LU_CRL)
431 : : {
432 : 0 : CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
433 : : /* Look for entry again in case another thread added
434 : : * an entry first.
435 : : */
436 [ # # ]: 0 : if (!hent)
437 : : {
438 : 0 : htmp.hash = h;
439 : 0 : idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp);
440 [ # # ]: 0 : if (idx >= 0)
441 : 0 : hent =
442 : 0 : sk_BY_DIR_HASH_value(ent->hashes, idx);
443 : : }
444 [ # # ]: 0 : if (!hent)
445 : : {
446 : 0 : hent = OPENSSL_malloc(sizeof(BY_DIR_HASH));
447 : 0 : hent->hash = h;
448 : 0 : hent->suffix = k;
449 [ # # ]: 0 : if (!sk_BY_DIR_HASH_push(ent->hashes, hent))
450 : : {
451 : 0 : CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
452 : 0 : OPENSSL_free(hent);
453 : 0 : ok = 0;
454 : 0 : goto finish;
455 : : }
456 : : }
457 [ # # ]: 0 : else if (hent->suffix < k)
458 : 0 : hent->suffix = k;
459 : :
460 : 0 : CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
461 : :
462 : : }
463 : :
464 [ + + ]: 17 : if (tmp != NULL)
465 : : {
466 : 2 : ok=1;
467 : 2 : ret->type=tmp->type;
468 : 2 : memcpy(&ret->data,&tmp->data,sizeof(ret->data));
469 : : /* If we were going to up the reference count,
470 : : * we would need to do it on a perl 'type'
471 : : * basis */
472 : : /* CRYPTO_add(&tmp->data.x509->references,1,
473 : : CRYPTO_LOCK_X509);*/
474 : : goto finish;
475 : : }
476 : : }
477 : : finish:
478 [ + - ]: 17 : if (b != NULL) BUF_MEM_free(b);
479 : 17 : return(ok);
480 : : }
|