X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fx509%2Fby_dir.c;h=170cd89608f9646ee9a2b291b512cedeebff27b3;hp=11725ec94c6e4e26facd6f8370e1cc72d66cfbe1;hb=e527201f6be3c295358bcc8b6bafec598f02dc97;hpb=58964a492275ca9a59a0cd9c8155cb2491b4b909 diff --git a/crypto/x509/by_dir.c b/crypto/x509/by_dir.c index 11725ec94c..170cd89608 100644 --- a/crypto/x509/by_dir.c +++ b/crypto/x509/by_dir.c @@ -59,38 +59,49 @@ #include #include #include -#include -#include #include "cryptlib.h" -#include "lhash.h" -#include "x509.h" -#include "pem.h" + +#ifndef NO_SYS_TYPES_H +# include +#endif +#ifndef OPENSSL_NO_POSIX_IO +# include +#endif + +#include +#include + + +typedef struct lookup_dir_hashes_st + { + unsigned long hash; + int suffix; + } BY_DIR_HASH; + +typedef struct lookup_dir_entry_st + { + char *dir; + int dir_type; + STACK_OF(BY_DIR_HASH) *hashes; + } BY_DIR_ENTRY; typedef struct lookup_dir_st { BUF_MEM *buffer; - int num_dirs; - char **dirs; - int *dirs_type; - int num_dirs_alloced; + STACK_OF(BY_DIR_ENTRY) *dirs; } BY_DIR; -#ifndef NOPROTO -static int dir_ctrl(X509_LOOKUP *ctx,int cmd,char *argp,long argl,char **ret); +DECLARE_STACK_OF(BY_DIR_HASH) +DECLARE_STACK_OF(BY_DIR_ENTRY) + +static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, + char **ret); static int new_dir(X509_LOOKUP *lu); static void free_dir(X509_LOOKUP *lu); -static int add_cert_dir(BY_DIR *ctx,char *dir,int type); +static int add_cert_dir(BY_DIR *ctx,const char *dir,int type); static int get_cert_by_subject(X509_LOOKUP *xl,int type,X509_NAME *name, X509_OBJECT *ret); -#else -static int dir_ctrl(); -static int new_dir(); -static void free_dir(); -static int add_cert_dir(); -static int get_cert_by_subject(); -#endif - X509_LOOKUP_METHOD x509_dir_lookup= { "Load certs from files in a directory", @@ -105,21 +116,17 @@ X509_LOOKUP_METHOD x509_dir_lookup= NULL, /* get_by_alias */ }; -X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir() +X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void) { return(&x509_dir_lookup); } -static int dir_ctrl(ctx,cmd,argp,argl,retp) -X509_LOOKUP *ctx; -int cmd; -long argl; -char *argp; -char **retp; +static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, + char **retp) { int ret=0; BY_DIR *ld; - char *dir; + char *dir = NULL; ld=(BY_DIR *)ctx->method_data; @@ -128,17 +135,16 @@ char **retp; case X509_L_ADD_DIR: if (argl == X509_FILETYPE_DEFAULT) { - ret=add_cert_dir(ld,X509_get_default_cert_dir(), - X509_FILETYPE_PEM); + dir=(char *)getenv(X509_get_default_cert_dir_env()); + if (dir) + ret=add_cert_dir(ld,dir,X509_FILETYPE_PEM); + else + ret=add_cert_dir(ld,X509_get_default_cert_dir(), + X509_FILETYPE_PEM); if (!ret) { X509err(X509_F_DIR_CTRL,X509_R_LOADING_CERT_DIR); } - else - { - dir=(char *)Getenv(X509_get_default_cert_dir_env()); - ret=add_cert_dir(ld,dir,X509_FILETYPE_PEM); - } } else ret=add_cert_dir(ld,argp,(int)argl); @@ -147,107 +153,125 @@ char **retp; return(ret); } -static int new_dir(lu) -X509_LOOKUP *lu; +static int new_dir(X509_LOOKUP *lu) { BY_DIR *a; - if ((a=(BY_DIR *)Malloc(sizeof(BY_DIR))) == NULL) + if ((a=(BY_DIR *)OPENSSL_malloc(sizeof(BY_DIR))) == NULL) return(0); if ((a->buffer=BUF_MEM_new()) == NULL) { - Free(a); + OPENSSL_free(a); return(0); } - a->num_dirs=0; a->dirs=NULL; - a->dirs_type=NULL; - a->num_dirs_alloced=0; lu->method_data=(char *)a; return(1); } -static void free_dir(lu) -X509_LOOKUP *lu; +static void by_dir_hash_free(BY_DIR_HASH *hash) + { + OPENSSL_free(hash); + } + +static int by_dir_hash_cmp(const BY_DIR_HASH * const *a, + const BY_DIR_HASH * const *b) + { + if ((*a)->hash > (*b)->hash) + return 1; + if ((*a)->hash < (*b)->hash) + return -1; + return 0; + } + +static void by_dir_entry_free(BY_DIR_ENTRY *ent) + { + if (ent->dir) + OPENSSL_free(ent->dir); + if (ent->hashes) + sk_BY_DIR_HASH_pop_free(ent->hashes, by_dir_hash_free); + OPENSSL_free(ent); + } + +static void free_dir(X509_LOOKUP *lu) { BY_DIR *a; - int i; a=(BY_DIR *)lu->method_data; - for (i=0; inum_dirs; i++) - if (a->dirs[i] != NULL) Free(a->dirs[i]); - if (a->dirs != NULL) Free(a->dirs); - if (a->dirs_type != NULL) Free(a->dirs_type); - if (a->buffer != NULL) BUF_MEM_free(a->buffer); - Free(a); + if (a->dirs != NULL) + sk_BY_DIR_ENTRY_pop_free(a->dirs, by_dir_entry_free); + if (a->buffer != NULL) + BUF_MEM_free(a->buffer); + OPENSSL_free(a); } -static int add_cert_dir(ctx,dir, type) -BY_DIR *ctx; -char *dir; -int type; +static int add_cert_dir(BY_DIR *ctx, const char *dir, int type) { int j,len; - int *ip; - char *s,*ss,*p; - char **pp; + const char *s,*ss,*p; - if (dir == NULL) return(0); + if (dir == NULL || !*dir) + { + X509err(X509_F_ADD_CERT_DIR,X509_R_INVALID_DIRECTORY); + return 0; + } s=dir; p=s; - for (;;) + for (;;p++) { if ((*p == LIST_SEPARATOR_CHAR) || (*p == '\0')) { + BY_DIR_ENTRY *ent; ss=s; s=p+1; len=(int)(p-ss); if (len == 0) continue; - for (j=0; jnum_dirs; j++) - if (strncmp(ctx->dirs[j],ss,(unsigned int)len) == 0) - continue; - if (ctx->num_dirs_alloced < (ctx->num_dirs+1)) + for (j=0; j < sk_BY_DIR_ENTRY_num(ctx->dirs); j++) { - ctx->num_dirs_alloced+=10; - pp=(char **)Malloc(ctx->num_dirs_alloced* - sizeof(char *)); - ip=(int *)Malloc(ctx->num_dirs_alloced* - sizeof(int)); - if ((pp == NULL) || (ip == NULL)) + ent = sk_BY_DIR_ENTRY_value(ctx->dirs, j); + if (strlen(ent->dir) == (size_t)len && + strncmp(ent->dir,ss,(unsigned int)len) == 0) + break; + } + if (j < sk_BY_DIR_ENTRY_num(ctx->dirs)) + continue; + if (ctx->dirs == NULL) + { + ctx->dirs = sk_BY_DIR_ENTRY_new_null(); + if (!ctx->dirs) { X509err(X509_F_ADD_CERT_DIR,ERR_R_MALLOC_FAILURE); - return(0); + return 0; } - memcpy(pp,ctx->dirs,(ctx->num_dirs_alloced-10)* - sizeof(char *)); - memcpy(ip,ctx->dirs_type,(ctx->num_dirs_alloced-10)* - sizeof(int)); - if (ctx->dirs != NULL) - Free((char *)ctx->dirs); - if (ctx->dirs_type != NULL) - Free((char *)ctx->dirs_type); - ctx->dirs=pp; - ctx->dirs_type=ip; } - ctx->dirs_type[ctx->num_dirs]=type; - ctx->dirs[ctx->num_dirs]=(char *)Malloc((unsigned int)len+1); - if (ctx->dirs[ctx->num_dirs] == NULL) return(0); - strncpy(ctx->dirs[ctx->num_dirs],ss,(unsigned int)len); - ctx->dirs[ctx->num_dirs][len]='\0'; - ctx->num_dirs++; + ent = OPENSSL_malloc(sizeof(BY_DIR_ENTRY)); + if (!ent) + return 0; + ent->dir_type = type; + ent->hashes = sk_BY_DIR_HASH_new(by_dir_hash_cmp); + ent->dir = OPENSSL_malloc((unsigned int)len+1); + if (!ent->dir || !ent->hashes) + { + by_dir_entry_free(ent); + return 0; + } + strncpy(ent->dir,ss,(unsigned int)len); + ent->dir[len] = '\0'; + if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) + { + by_dir_entry_free(ent); + return 0; + } } - if (*p == '\0') break; - p++; + if (*p == '\0') + break; } - return(1); + return 1; } -static int get_cert_by_subject(xl,type,name,ret) -X509_LOOKUP *xl; -int type; -X509_NAME *name; -X509_OBJECT *ret; +static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, + X509_OBJECT *ret) { BY_DIR *ctx; union { @@ -264,9 +288,8 @@ X509_OBJECT *ret; int i,j,k; unsigned long h; BUF_MEM *b=NULL; - struct stat st; X509_OBJECT stmp,*tmp; - char *postfix=""; + const char *postfix=""; if (name == NULL) return(0); @@ -300,45 +323,146 @@ X509_OBJECT *ret; ctx=(BY_DIR *)xl->method_data; h=X509_NAME_hash(name); - for (i=0; inum_dirs; i++) + for (i=0; i < sk_BY_DIR_ENTRY_num(ctx->dirs); i++) { - j=strlen(ctx->dirs[i])+1+8+6+1+1; + BY_DIR_ENTRY *ent; + int idx; + BY_DIR_HASH htmp, *hent; + ent = sk_BY_DIR_ENTRY_value(ctx->dirs, i); + j=strlen(ent->dir)+1+8+6+1+1; if (!BUF_MEM_grow(b,j)) { X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_MALLOC_FAILURE); goto finish; } - k=0; + if (type == X509_LU_CRL && ent->hashes) + { + htmp.hash = h; + CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE); + idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp); + if (idx >= 0) + { + hent = sk_BY_DIR_HASH_value(ent->hashes, idx); + k = hent->suffix; + } + else + { + hent = NULL; + k=0; + } + CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE); + } + else + { + k = 0; + hent = NULL; + } for (;;) { - sprintf(b->data,"%s/%08lx.%s%d",ctx->dirs[i],h, - postfix,k); - k++; + char c = '/'; +#ifdef OPENSSL_SYS_VMS + c = ent->dir[strlen(ent->dir)-1]; + if (c != ':' && c != '>' && c != ']') + { + /* If no separator is present, we assume the + directory specifier is a logical name, and + add a colon. We really should use better + VMS routines for merging things like this, + but this will do for now... + -- Richard Levitte */ + c = ':'; + } + else + { + c = '\0'; + } +#endif + if (c == '\0') + { + /* This is special. When c == '\0', no + directory separator should be added. */ + BIO_snprintf(b->data,b->max, + "%s%08lx.%s%d",ent->dir,h, + postfix,k); + } + else + { + BIO_snprintf(b->data,b->max, + "%s%c%08lx.%s%d",ent->dir,c,h, + postfix,k); + } +#ifndef OPENSSL_NO_POSIX_IO +#ifdef _WIN32 +#define stat _stat +#endif + { + struct stat st; if (stat(b->data,&st) < 0) break; + } +#endif /* found one. */ if (type == X509_LU_X509) { if ((X509_load_cert_file(xl,b->data, - ctx->dirs_type[i])) == 0) + ent->dir_type)) == 0) break; } else if (type == X509_LU_CRL) { if ((X509_load_crl_file(xl,b->data, - ctx->dirs_type[i])) == 0) + ent->dir_type)) == 0) break; } /* else case will caught higher up */ + k++; } /* we have added it to the cache so now pull * it out again */ CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE); - tmp=(X509_OBJECT *)lh_retrieve(xl->store_ctx->certs, - (char *)&stmp); + j = sk_X509_OBJECT_find(xl->store_ctx->objs,&stmp); + if(j != -1) tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,j); + else tmp = NULL; CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE); + + /* If a CRL, update the last file suffix added for this */ + + if (type == X509_LU_CRL) + { + CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE); + /* Look for entry again in case another thread added + * an entry first. + */ + if (!hent) + { + htmp.hash = h; + idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp); + if (idx >= 0) + hent = + sk_BY_DIR_HASH_value(ent->hashes, idx); + } + if (!hent) + { + hent = OPENSSL_malloc(sizeof(BY_DIR_HASH)); + hent->hash = h; + hent->suffix = k; + if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) + { + CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); + OPENSSL_free(hent); + ok = 0; + goto finish; + } + } + else if (hent->suffix < k) + hent->suffix = k; + + CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); + + } + if (tmp != NULL) { ok=1;