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