| OLD | NEW |
| (Empty) |
| 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 X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void) | |
| 120 { | |
| 121 return(&x509_dir_lookup); | |
| 122 } | |
| 123 | |
| 124 static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, | |
| 125 char **retp) | |
| 126 { | |
| 127 int ret=0; | |
| 128 BY_DIR *ld; | |
| 129 char *dir = NULL; | |
| 130 | |
| 131 ld=(BY_DIR *)ctx->method_data; | |
| 132 | |
| 133 switch (cmd) | |
| 134 { | |
| 135 case X509_L_ADD_DIR: | |
| 136 if (argl == X509_FILETYPE_DEFAULT) | |
| 137 { | |
| 138 dir=(char *)getenv(X509_get_default_cert_dir_env()); | |
| 139 if (dir) | |
| 140 ret=add_cert_dir(ld,dir,X509_FILETYPE_PEM); | |
| 141 else | |
| 142 ret=add_cert_dir(ld,X509_get_default_cert_dir(), | |
| 143 X509_FILETYPE_PEM); | |
| 144 if (!ret) | |
| 145 { | |
| 146 X509err(X509_F_DIR_CTRL,X509_R_LOADING_CERT_DIR)
; | |
| 147 } | |
| 148 } | |
| 149 else | |
| 150 ret=add_cert_dir(ld,argp,(int)argl); | |
| 151 break; | |
| 152 } | |
| 153 return(ret); | |
| 154 } | |
| 155 | |
| 156 static int new_dir(X509_LOOKUP *lu) | |
| 157 { | |
| 158 BY_DIR *a; | |
| 159 | |
| 160 if ((a=(BY_DIR *)OPENSSL_malloc(sizeof(BY_DIR))) == NULL) | |
| 161 return(0); | |
| 162 if ((a->buffer=BUF_MEM_new()) == NULL) | |
| 163 { | |
| 164 OPENSSL_free(a); | |
| 165 return(0); | |
| 166 } | |
| 167 a->dirs=NULL; | |
| 168 lu->method_data=(char *)a; | |
| 169 return(1); | |
| 170 } | |
| 171 | |
| 172 static void by_dir_hash_free(BY_DIR_HASH *hash) | |
| 173 { | |
| 174 OPENSSL_free(hash); | |
| 175 } | |
| 176 | |
| 177 static int by_dir_hash_cmp(const BY_DIR_HASH * const *a, | |
| 178 const BY_DIR_HASH * const *b) | |
| 179 { | |
| 180 if ((*a)->hash > (*b)->hash) | |
| 181 return 1; | |
| 182 if ((*a)->hash < (*b)->hash) | |
| 183 return -1; | |
| 184 return 0; | |
| 185 } | |
| 186 | |
| 187 static void by_dir_entry_free(BY_DIR_ENTRY *ent) | |
| 188 { | |
| 189 if (ent->dir) | |
| 190 OPENSSL_free(ent->dir); | |
| 191 if (ent->hashes) | |
| 192 sk_BY_DIR_HASH_pop_free(ent->hashes, by_dir_hash_free); | |
| 193 OPENSSL_free(ent); | |
| 194 } | |
| 195 | |
| 196 static void free_dir(X509_LOOKUP *lu) | |
| 197 { | |
| 198 BY_DIR *a; | |
| 199 | |
| 200 a=(BY_DIR *)lu->method_data; | |
| 201 if (a->dirs != NULL) | |
| 202 sk_BY_DIR_ENTRY_pop_free(a->dirs, by_dir_entry_free); | |
| 203 if (a->buffer != NULL) | |
| 204 BUF_MEM_free(a->buffer); | |
| 205 OPENSSL_free(a); | |
| 206 } | |
| 207 | |
| 208 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 if (dir == NULL || !*dir) | |
| 214 { | |
| 215 X509err(X509_F_ADD_CERT_DIR,X509_R_INVALID_DIRECTORY); | |
| 216 return 0; | |
| 217 } | |
| 218 | |
| 219 s=dir; | |
| 220 p=s; | |
| 221 for (;;p++) | |
| 222 { | |
| 223 if ((*p == LIST_SEPARATOR_CHAR) || (*p == '\0')) | |
| 224 { | |
| 225 BY_DIR_ENTRY *ent; | |
| 226 ss=s; | |
| 227 s=p+1; | |
| 228 len=(int)(p-ss); | |
| 229 if (len == 0) continue; | |
| 230 for (j=0; j < sk_BY_DIR_ENTRY_num(ctx->dirs); j++) | |
| 231 { | |
| 232 ent = sk_BY_DIR_ENTRY_value(ctx->dirs, j); | |
| 233 if (strlen(ent->dir) == (size_t)len && | |
| 234 strncmp(ent->dir,ss,(unsigned int)len) == 0) | |
| 235 break; | |
| 236 } | |
| 237 if (j < sk_BY_DIR_ENTRY_num(ctx->dirs)) | |
| 238 continue; | |
| 239 if (ctx->dirs == NULL) | |
| 240 { | |
| 241 ctx->dirs = sk_BY_DIR_ENTRY_new_null(); | |
| 242 if (!ctx->dirs) | |
| 243 { | |
| 244 X509err(X509_F_ADD_CERT_DIR,ERR_R_MALLOC
_FAILURE); | |
| 245 return 0; | |
| 246 } | |
| 247 } | |
| 248 ent = OPENSSL_malloc(sizeof(BY_DIR_ENTRY)); | |
| 249 if (!ent) | |
| 250 return 0; | |
| 251 ent->dir_type = type; | |
| 252 ent->hashes = sk_BY_DIR_HASH_new(by_dir_hash_cmp); | |
| 253 ent->dir = OPENSSL_malloc((unsigned int)len+1); | |
| 254 if (!ent->dir || !ent->hashes) | |
| 255 { | |
| 256 by_dir_entry_free(ent); | |
| 257 return 0; | |
| 258 } | |
| 259 strncpy(ent->dir,ss,(unsigned int)len); | |
| 260 ent->dir[len] = '\0'; | |
| 261 if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) | |
| 262 { | |
| 263 by_dir_entry_free(ent); | |
| 264 return 0; | |
| 265 } | |
| 266 } | |
| 267 if (*p == '\0') | |
| 268 break; | |
| 269 } | |
| 270 return 1; | |
| 271 } | |
| 272 | |
| 273 static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, | |
| 274 X509_OBJECT *ret) | |
| 275 { | |
| 276 BY_DIR *ctx; | |
| 277 union { | |
| 278 struct { | |
| 279 X509 st_x509; | |
| 280 X509_CINF st_x509_cinf; | |
| 281 } x509; | |
| 282 struct { | |
| 283 X509_CRL st_crl; | |
| 284 X509_CRL_INFO st_crl_info; | |
| 285 } crl; | |
| 286 } data; | |
| 287 int ok=0; | |
| 288 int i,j,k; | |
| 289 unsigned long h; | |
| 290 unsigned long hash_array[2]; | |
| 291 int hash_index; | |
| 292 BUF_MEM *b=NULL; | |
| 293 X509_OBJECT stmp,*tmp; | |
| 294 const char *postfix=""; | |
| 295 | |
| 296 if (name == NULL) return(0); | |
| 297 | |
| 298 stmp.type=type; | |
| 299 if (type == X509_LU_X509) | |
| 300 { | |
| 301 data.x509.st_x509.cert_info= &data.x509.st_x509_cinf; | |
| 302 data.x509.st_x509_cinf.subject=name; | |
| 303 stmp.data.x509= &data.x509.st_x509; | |
| 304 postfix=""; | |
| 305 } | |
| 306 else if (type == X509_LU_CRL) | |
| 307 { | |
| 308 data.crl.st_crl.crl= &data.crl.st_crl_info; | |
| 309 data.crl.st_crl_info.issuer=name; | |
| 310 stmp.data.crl= &data.crl.st_crl; | |
| 311 postfix="r"; | |
| 312 } | |
| 313 else | |
| 314 { | |
| 315 X509err(X509_F_GET_CERT_BY_SUBJECT,X509_R_WRONG_LOOKUP_TYPE); | |
| 316 goto finish; | |
| 317 } | |
| 318 | |
| 319 if ((b=BUF_MEM_new()) == NULL) | |
| 320 { | |
| 321 X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_BUF_LIB); | |
| 322 goto finish; | |
| 323 } | |
| 324 | |
| 325 ctx=(BY_DIR *)xl->method_data; | |
| 326 | |
| 327 hash_array[0]=X509_NAME_hash(name); | |
| 328 hash_array[1]=X509_NAME_hash_old(name); | |
| 329 for (hash_index=0; hash_index < 2; ++hash_index) | |
| 330 { | |
| 331 h=hash_array[hash_index]; | |
| 332 for (i=0; i < sk_BY_DIR_ENTRY_num(ctx->dirs); i++) | |
| 333 { | |
| 334 BY_DIR_ENTRY *ent; | |
| 335 int idx; | |
| 336 BY_DIR_HASH htmp, *hent; | |
| 337 ent = sk_BY_DIR_ENTRY_value(ctx->dirs, i); | |
| 338 j=strlen(ent->dir)+1+8+6+1+1; | |
| 339 if (!BUF_MEM_grow(b,j)) | |
| 340 { | |
| 341 X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_MALLOC_FAILURE)
; | |
| 342 goto finish; | |
| 343 } | |
| 344 if (type == X509_LU_CRL && ent->hashes) | |
| 345 { | |
| 346 htmp.hash = h; | |
| 347 CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE); | |
| 348 idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp); | |
| 349 if (idx >= 0) | |
| 350 { | |
| 351 hent = sk_BY_DIR_HASH_value(ent->hashes, idx); | |
| 352 k = hent->suffix; | |
| 353 } | |
| 354 else | |
| 355 { | |
| 356 hent = NULL; | |
| 357 k=0; | |
| 358 } | |
| 359 CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE); | |
| 360 } | |
| 361 else | |
| 362 { | |
| 363 k = 0; | |
| 364 hent = NULL; | |
| 365 } | |
| 366 for (;;) | |
| 367 { | |
| 368 char c = '/'; | |
| 369 #ifdef OPENSSL_SYS_VMS | |
| 370 c = ent->dir[strlen(ent->dir)-1]; | |
| 371 if (c != ':' && c != '>' && c != ']') | |
| 372 { | |
| 373 /* If no separator is present, we assume the | |
| 374 directory specifier is a logical name, and | |
| 375 add a colon. We really should use better | |
| 376 VMS routines for merging things like this, | |
| 377 but this will do for now... | |
| 378 -- Richard Levitte */ | |
| 379 c = ':'; | |
| 380 } | |
| 381 else | |
| 382 { | |
| 383 c = '\0'; | |
| 384 } | |
| 385 #endif | |
| 386 if (c == '\0') | |
| 387 { | |
| 388 /* This is special. When c == '\0', no | |
| 389 directory separator should be added. */ | |
| 390 BIO_snprintf(b->data,b->max, | |
| 391 "%s%08lx.%s%d",ent->dir,h, | |
| 392 postfix,k); | |
| 393 } | |
| 394 else | |
| 395 { | |
| 396 BIO_snprintf(b->data,b->max, | |
| 397 "%s%c%08lx.%s%d",ent->dir,c,h, | |
| 398 postfix,k); | |
| 399 } | |
| 400 #ifndef OPENSSL_NO_POSIX_IO | |
| 401 #ifdef _WIN32 | |
| 402 #define stat _stat | |
| 403 #endif | |
| 404 { | |
| 405 struct stat st; | |
| 406 if (stat(b->data,&st) < 0) | |
| 407 break; | |
| 408 } | |
| 409 #endif | |
| 410 /* found one. */ | |
| 411 if (type == X509_LU_X509) | |
| 412 { | |
| 413 if ((X509_load_cert_file(xl,b->data, | |
| 414 ent->dir_type)) == 0) | |
| 415 break; | |
| 416 } | |
| 417 else if (type == X509_LU_CRL) | |
| 418 { | |
| 419 if ((X509_load_crl_file(xl,b->data, | |
| 420 ent->dir_type)) == 0) | |
| 421 break; | |
| 422 } | |
| 423 /* else case will caught higher up */ | |
| 424 k++; | |
| 425 } | |
| 426 | |
| 427 /* we have added it to the cache so now pull | |
| 428 * it out again */ | |
| 429 CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE); | |
| 430 j = sk_X509_OBJECT_find(xl->store_ctx->objs,&stmp); | |
| 431 if(j != -1) tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,j); | |
| 432 else tmp = NULL; | |
| 433 CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); | |
| 434 | |
| 435 | |
| 436 /* If a CRL, update the last file suffix added for this */ | |
| 437 | |
| 438 if (type == X509_LU_CRL) | |
| 439 { | |
| 440 CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE); | |
| 441 /* Look for entry again in case another thread added | |
| 442 * an entry first. | |
| 443 */ | |
| 444 if (!hent) | |
| 445 { | |
| 446 htmp.hash = h; | |
| 447 idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp); | |
| 448 if (idx >= 0) | |
| 449 hent = | |
| 450 sk_BY_DIR_HASH_value(ent->hashes, idx); | |
| 451 } | |
| 452 if (!hent) | |
| 453 { | |
| 454 hent = OPENSSL_malloc(sizeof(BY_DIR_HASH)); | |
| 455 hent->hash = h; | |
| 456 hent->suffix = k; | |
| 457 if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) | |
| 458 { | |
| 459 CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); | |
| 460 OPENSSL_free(hent); | |
| 461 ok = 0; | |
| 462 goto finish; | |
| 463 } | |
| 464 } | |
| 465 else if (hent->suffix < k) | |
| 466 hent->suffix = k; | |
| 467 | |
| 468 CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); | |
| 469 | |
| 470 } | |
| 471 | |
| 472 if (tmp != NULL) | |
| 473 { | |
| 474 ok=1; | |
| 475 ret->type=tmp->type; | |
| 476 memcpy(&ret->data,&tmp->data,sizeof(ret->data)); | |
| 477 /* If we were going to up the reference count, | |
| 478 * we would need to do it on a perl 'type' | |
| 479 * basis */ | |
| 480 /* CRYPTO_add(&tmp->data.x509->references,1, | |
| 481 CRYPTO_LOCK_X509);*/ | |
| 482 goto finish; | |
| 483 } | |
| 484 } | |
| 485 } | |
| 486 finish: | |
| 487 if (b != NULL) BUF_MEM_free(b); | |
| 488 return(ok); | |
| 489 } | |
| OLD | NEW |