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