|
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 © Portions copyright (c) 2006 Nokia Corporation. All rights reserved. |
|
60 */ |
|
61 |
|
62 #include <stdio.h> |
|
63 #include <time.h> |
|
64 #include <errno.h> |
|
65 |
|
66 #include "cryptlib.h" |
|
67 |
|
68 #ifndef NO_SYS_TYPES_H |
|
69 # include <sys/types.h> |
|
70 #endif |
|
71 #ifdef MAC_OS_pre_X |
|
72 # include <stat.h> |
|
73 #else |
|
74 # include <sys/stat.h> |
|
75 #endif |
|
76 |
|
77 #include <openssl/lhash.h> |
|
78 #include <openssl/x509.h> |
|
79 #if (defined(SYMBIAN) && (defined(__WINSCW__) || defined(__WINS__))) |
|
80 #include "libcrypto_wsd_macros.h" |
|
81 #include "libcrypto_wsd.h" |
|
82 #endif |
|
83 |
|
84 |
|
85 typedef struct lookup_dir_st |
|
86 { |
|
87 BUF_MEM *buffer; |
|
88 int num_dirs; |
|
89 char **dirs; |
|
90 int *dirs_type; |
|
91 int num_dirs_alloced; |
|
92 } BY_DIR; |
|
93 |
|
94 static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, |
|
95 char **ret); |
|
96 static int new_dir(X509_LOOKUP *lu); |
|
97 static void free_dir(X509_LOOKUP *lu); |
|
98 static int add_cert_dir(BY_DIR *ctx,const char *dir,int type); |
|
99 static int get_cert_by_subject(X509_LOOKUP *xl,int type,X509_NAME *name, |
|
100 X509_OBJECT *ret); |
|
101 #ifndef EMULATOR |
|
102 X509_LOOKUP_METHOD x509_dir_lookup= |
|
103 { |
|
104 "Load certs from files in a directory", |
|
105 new_dir, /* new */ |
|
106 free_dir, /* free */ |
|
107 NULL, /* init */ |
|
108 NULL, /* shutdown */ |
|
109 dir_ctrl, /* ctrl */ |
|
110 get_cert_by_subject, /* get_by_subject */ |
|
111 NULL, /* get_by_issuer_serial */ |
|
112 NULL, /* get_by_fingerprint */ |
|
113 NULL, /* get_by_alias */ |
|
114 }; |
|
115 #else |
|
116 GET_GLOBAL_VAR_FROM_TLS(x509_dir_lookup,by_dir,X509_LOOKUP_METHOD) |
|
117 #define x509_dir_lookup (*GET_WSD_VAR_NAME(x509_dir_lookup,by_dir, g)()) |
|
118 const X509_LOOKUP_METHOD temp_g_x509_dir_lookup= |
|
119 { |
|
120 "Load certs from files in a directory", |
|
121 new_dir, /* new */ |
|
122 free_dir, /* free */ |
|
123 NULL, /* init */ |
|
124 NULL, /* shutdown */ |
|
125 dir_ctrl, /* ctrl */ |
|
126 get_cert_by_subject, /* get_by_subject */ |
|
127 NULL, /* get_by_issuer_serial */ |
|
128 NULL, /* get_by_fingerprint */ |
|
129 NULL, /* get_by_alias */ |
|
130 }; |
|
131 #endif |
|
132 |
|
133 EXPORT_C X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void) |
|
134 { |
|
135 return(&x509_dir_lookup); |
|
136 } |
|
137 |
|
138 static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, |
|
139 char **retp) |
|
140 { |
|
141 int ret=0; |
|
142 BY_DIR *ld; |
|
143 char *dir = NULL; |
|
144 |
|
145 ld=(BY_DIR *)ctx->method_data; |
|
146 |
|
147 switch (cmd) |
|
148 { |
|
149 case X509_L_ADD_DIR: |
|
150 if (argl == X509_FILETYPE_DEFAULT) |
|
151 { |
|
152 dir=(char *)Getenv(X509_get_default_cert_dir_env()); |
|
153 if (dir) |
|
154 ret=add_cert_dir(ld,dir,X509_FILETYPE_PEM); |
|
155 else |
|
156 ret=add_cert_dir(ld,X509_get_default_cert_dir(), |
|
157 X509_FILETYPE_PEM); |
|
158 if (!ret) |
|
159 { |
|
160 X509err(X509_F_DIR_CTRL,X509_R_LOADING_CERT_DIR); |
|
161 } |
|
162 } |
|
163 else |
|
164 ret=add_cert_dir(ld,argp,(int)argl); |
|
165 break; |
|
166 } |
|
167 return(ret); |
|
168 } |
|
169 |
|
170 static int new_dir(X509_LOOKUP *lu) |
|
171 { |
|
172 BY_DIR *a; |
|
173 |
|
174 if ((a=(BY_DIR *)OPENSSL_malloc(sizeof(BY_DIR))) == NULL) |
|
175 return(0); |
|
176 if ((a->buffer=BUF_MEM_new()) == NULL) |
|
177 { |
|
178 OPENSSL_free(a); |
|
179 return(0); |
|
180 } |
|
181 a->num_dirs=0; |
|
182 a->dirs=NULL; |
|
183 a->dirs_type=NULL; |
|
184 a->num_dirs_alloced=0; |
|
185 lu->method_data=(char *)a; |
|
186 return(1); |
|
187 } |
|
188 |
|
189 static void free_dir(X509_LOOKUP *lu) |
|
190 { |
|
191 BY_DIR *a; |
|
192 int i; |
|
193 |
|
194 a=(BY_DIR *)lu->method_data; |
|
195 for (i=0; i<a->num_dirs; i++) |
|
196 if (a->dirs[i] != NULL) OPENSSL_free(a->dirs[i]); |
|
197 if (a->dirs != NULL) OPENSSL_free(a->dirs); |
|
198 if (a->dirs_type != NULL) OPENSSL_free(a->dirs_type); |
|
199 if (a->buffer != NULL) BUF_MEM_free(a->buffer); |
|
200 OPENSSL_free(a); |
|
201 } |
|
202 |
|
203 static int add_cert_dir(BY_DIR *ctx, const char *dir, int type) |
|
204 { |
|
205 int j,len; |
|
206 int *ip; |
|
207 const char *s,*ss,*p; |
|
208 char **pp; |
|
209 |
|
210 if (dir == NULL || !*dir) |
|
211 { |
|
212 X509err(X509_F_ADD_CERT_DIR,X509_R_INVALID_DIRECTORY); |
|
213 return 0; |
|
214 } |
|
215 |
|
216 s=dir; |
|
217 p=s; |
|
218 for (;;p++) |
|
219 { |
|
220 if ((*p == LIST_SEPARATOR_CHAR) || (*p == '\0')) |
|
221 { |
|
222 ss=s; |
|
223 s=p+1; |
|
224 len=(int)(p-ss); |
|
225 if (len == 0) continue; |
|
226 for (j=0; j<ctx->num_dirs; j++) |
|
227 if (strlen(ctx->dirs[j]) == (size_t)len && |
|
228 strncmp(ctx->dirs[j],ss,(unsigned int)len) == 0) |
|
229 break; |
|
230 if (j<ctx->num_dirs) |
|
231 continue; |
|
232 if (ctx->num_dirs_alloced < (ctx->num_dirs+1)) |
|
233 { |
|
234 ctx->num_dirs_alloced+=10; |
|
235 pp=(char **)OPENSSL_malloc(ctx->num_dirs_alloced* |
|
236 sizeof(char *)); |
|
237 ip=(int *)OPENSSL_malloc(ctx->num_dirs_alloced* |
|
238 sizeof(int)); |
|
239 if ((pp == NULL) || (ip == NULL)) |
|
240 { |
|
241 X509err(X509_F_ADD_CERT_DIR,ERR_R_MALLOC_FAILURE); |
|
242 return(0); |
|
243 } |
|
244 memcpy(pp,ctx->dirs,(ctx->num_dirs_alloced-10)* |
|
245 sizeof(char *)); |
|
246 memcpy(ip,ctx->dirs_type,(ctx->num_dirs_alloced-10)* |
|
247 sizeof(int)); |
|
248 if (ctx->dirs != NULL) |
|
249 OPENSSL_free(ctx->dirs); |
|
250 if (ctx->dirs_type != NULL) |
|
251 OPENSSL_free(ctx->dirs_type); |
|
252 ctx->dirs=pp; |
|
253 ctx->dirs_type=ip; |
|
254 } |
|
255 ctx->dirs_type[ctx->num_dirs]=type; |
|
256 ctx->dirs[ctx->num_dirs]=(char *)OPENSSL_malloc((unsigned int)len+1); |
|
257 if (ctx->dirs[ctx->num_dirs] == NULL) return(0); |
|
258 strncpy(ctx->dirs[ctx->num_dirs],ss,(unsigned int)len); |
|
259 ctx->dirs[ctx->num_dirs][len]='\0'; |
|
260 ctx->num_dirs++; |
|
261 } |
|
262 if (*p == '\0') break; |
|
263 } |
|
264 return(1); |
|
265 } |
|
266 |
|
267 static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, |
|
268 X509_OBJECT *ret) |
|
269 { |
|
270 BY_DIR *ctx; |
|
271 union { |
|
272 struct { |
|
273 X509 st_x509; |
|
274 X509_CINF st_x509_cinf; |
|
275 } x509; |
|
276 struct { |
|
277 X509_CRL st_crl; |
|
278 X509_CRL_INFO st_crl_info; |
|
279 } crl; |
|
280 } data; |
|
281 int ok=0; |
|
282 int i,j,k; |
|
283 unsigned long h; |
|
284 BUF_MEM *b=NULL; |
|
285 struct stat st; |
|
286 X509_OBJECT stmp,*tmp; |
|
287 const char *postfix=""; |
|
288 |
|
289 if (name == NULL) return(0); |
|
290 |
|
291 stmp.type=type; |
|
292 if (type == X509_LU_X509) |
|
293 { |
|
294 data.x509.st_x509.cert_info= &data.x509.st_x509_cinf; |
|
295 data.x509.st_x509_cinf.subject=name; |
|
296 stmp.data.x509= &data.x509.st_x509; |
|
297 postfix=""; |
|
298 } |
|
299 else if (type == X509_LU_CRL) |
|
300 { |
|
301 data.crl.st_crl.crl= &data.crl.st_crl_info; |
|
302 data.crl.st_crl_info.issuer=name; |
|
303 stmp.data.crl= &data.crl.st_crl; |
|
304 postfix="r"; |
|
305 } |
|
306 else |
|
307 { |
|
308 X509err(X509_F_GET_CERT_BY_SUBJECT,X509_R_WRONG_LOOKUP_TYPE); |
|
309 goto finish; |
|
310 } |
|
311 |
|
312 if ((b=BUF_MEM_new()) == NULL) |
|
313 { |
|
314 X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_BUF_LIB); |
|
315 goto finish; |
|
316 } |
|
317 |
|
318 ctx=(BY_DIR *)xl->method_data; |
|
319 |
|
320 h=X509_NAME_hash(name); |
|
321 for (i=0; i<ctx->num_dirs; i++) |
|
322 { |
|
323 j=strlen(ctx->dirs[i])+1+8+6+1+1; |
|
324 if (!BUF_MEM_grow(b,j)) |
|
325 { |
|
326 X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_MALLOC_FAILURE); |
|
327 goto finish; |
|
328 } |
|
329 k=0; |
|
330 for (;;) |
|
331 { |
|
332 char c = '/'; |
|
333 #ifdef OPENSSL_SYS_VMS |
|
334 c = ctx->dirs[i][strlen(ctx->dirs[i])-1]; |
|
335 if (c != ':' && c != '>' && c != ']') |
|
336 { |
|
337 /* If no separator is present, we assume the |
|
338 directory specifier is a logical name, and |
|
339 add a colon. We really should use better |
|
340 VMS routines for merging things like this, |
|
341 but this will do for now... |
|
342 -- Richard Levitte */ |
|
343 c = ':'; |
|
344 } |
|
345 else |
|
346 { |
|
347 c = '\0'; |
|
348 } |
|
349 #endif |
|
350 if (c == '\0') |
|
351 { |
|
352 /* This is special. When c == '\0', no |
|
353 directory separator should be added. */ |
|
354 BIO_snprintf(b->data,b->max, |
|
355 "%s%08lx.%s%d",ctx->dirs[i],h, |
|
356 postfix,k); |
|
357 } |
|
358 else |
|
359 { |
|
360 BIO_snprintf(b->data,b->max, |
|
361 "%s%c%08lx.%s%d",ctx->dirs[i],c,h, |
|
362 postfix,k); |
|
363 } |
|
364 k++; |
|
365 if (stat(b->data,&st) < 0) |
|
366 break; |
|
367 /* found one. */ |
|
368 if (type == X509_LU_X509) |
|
369 { |
|
370 if ((X509_load_cert_file(xl,b->data, |
|
371 ctx->dirs_type[i])) == 0) |
|
372 break; |
|
373 } |
|
374 else if (type == X509_LU_CRL) |
|
375 { |
|
376 if ((X509_load_crl_file(xl,b->data, |
|
377 ctx->dirs_type[i])) == 0) |
|
378 break; |
|
379 } |
|
380 /* else case will caught higher up */ |
|
381 } |
|
382 |
|
383 /* we have added it to the cache so now pull |
|
384 * it out again */ |
|
385 CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE); |
|
386 j = sk_X509_OBJECT_find(xl->store_ctx->objs,&stmp); |
|
387 if(j != -1) tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,j); |
|
388 else tmp = NULL; |
|
389 CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE); |
|
390 |
|
391 if (tmp != NULL) |
|
392 { |
|
393 ok=1; |
|
394 ret->type=tmp->type; |
|
395 memcpy(&ret->data,&tmp->data,sizeof(ret->data)); |
|
396 /* If we were going to up the reference count, |
|
397 * we would need to do it on a perl 'type' |
|
398 * basis */ |
|
399 /* CRYPTO_add(&tmp->data.x509->references,1, |
|
400 CRYPTO_LOCK_X509);*/ |
|
401 goto finish; |
|
402 } |
|
403 } |
|
404 finish: |
|
405 if (b != NULL) BUF_MEM_free(b); |
|
406 return(ok); |
|
407 } |
|
408 |