155714Skris/* crypto/x509/by_dir.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 8296465Sdelphij * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15296465Sdelphij * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 22296465Sdelphij * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 37296465Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40296465Sdelphij * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 52296465Sdelphij * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 5955714Skris#include <stdio.h> 6055714Skris#include <time.h> 6155714Skris#include <errno.h> 6255714Skris 6355714Skris#include "cryptlib.h" 6459191Skris 6559191Skris#ifndef NO_SYS_TYPES_H 6659191Skris# include <sys/types.h> 6759191Skris#endif 6859191Skris#ifdef MAC_OS_pre_X 6959191Skris# include <stat.h> 7059191Skris#else 7159191Skris# include <sys/stat.h> 7259191Skris#endif 7359191Skris 7455714Skris#include <openssl/lhash.h> 7555714Skris#include <openssl/x509.h> 7655714Skris 77194206Ssimon#ifdef _WIN32 78296465Sdelphij# define stat _stat 79194206Ssimon#endif 80194206Ssimon 81296465Sdelphijtypedef struct lookup_dir_st { 82296465Sdelphij BUF_MEM *buffer; 83296465Sdelphij int num_dirs; 84296465Sdelphij char **dirs; 85296465Sdelphij int *dirs_type; 86296465Sdelphij int num_dirs_alloced; 87296465Sdelphij} BY_DIR; 8855714Skris 8955714Skrisstatic int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, 90296465Sdelphij char **ret); 9155714Skrisstatic int new_dir(X509_LOOKUP *lu); 9255714Skrisstatic void free_dir(X509_LOOKUP *lu); 93296465Sdelphijstatic int add_cert_dir(BY_DIR *ctx, const char *dir, int type); 94296465Sdelphijstatic int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, 95296465Sdelphij X509_OBJECT *ret); 96296465SdelphijX509_LOOKUP_METHOD x509_dir_lookup = { 97296465Sdelphij "Load certs from files in a directory", 98296465Sdelphij new_dir, /* new */ 99296465Sdelphij free_dir, /* free */ 100296465Sdelphij NULL, /* init */ 101296465Sdelphij NULL, /* shutdown */ 102296465Sdelphij dir_ctrl, /* ctrl */ 103296465Sdelphij get_cert_by_subject, /* get_by_subject */ 104296465Sdelphij NULL, /* get_by_issuer_serial */ 105296465Sdelphij NULL, /* get_by_fingerprint */ 106296465Sdelphij NULL, /* get_by_alias */ 107296465Sdelphij}; 10855714Skris 10955714SkrisX509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void) 110296465Sdelphij{ 111296465Sdelphij return (&x509_dir_lookup); 112296465Sdelphij} 11355714Skris 11455714Skrisstatic int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, 115296465Sdelphij char **retp) 116296465Sdelphij{ 117296465Sdelphij int ret = 0; 118296465Sdelphij BY_DIR *ld; 119296465Sdelphij char *dir = NULL; 12055714Skris 121296465Sdelphij ld = (BY_DIR *)ctx->method_data; 12255714Skris 123296465Sdelphij switch (cmd) { 124296465Sdelphij case X509_L_ADD_DIR: 125296465Sdelphij if (argl == X509_FILETYPE_DEFAULT) { 126296465Sdelphij dir = (char *)Getenv(X509_get_default_cert_dir_env()); 127296465Sdelphij if (dir) 128296465Sdelphij ret = add_cert_dir(ld, dir, X509_FILETYPE_PEM); 129296465Sdelphij else 130296465Sdelphij ret = add_cert_dir(ld, X509_get_default_cert_dir(), 131296465Sdelphij X509_FILETYPE_PEM); 132296465Sdelphij if (!ret) { 133296465Sdelphij X509err(X509_F_DIR_CTRL, X509_R_LOADING_CERT_DIR); 134296465Sdelphij } 135296465Sdelphij } else 136296465Sdelphij ret = add_cert_dir(ld, argp, (int)argl); 137296465Sdelphij break; 138296465Sdelphij } 139296465Sdelphij return (ret); 140296465Sdelphij} 14155714Skris 14255714Skrisstatic int new_dir(X509_LOOKUP *lu) 143296465Sdelphij{ 144296465Sdelphij BY_DIR *a; 14555714Skris 146296465Sdelphij if ((a = (BY_DIR *)OPENSSL_malloc(sizeof(BY_DIR))) == NULL) 147296465Sdelphij return (0); 148296465Sdelphij if ((a->buffer = BUF_MEM_new()) == NULL) { 149296465Sdelphij OPENSSL_free(a); 150296465Sdelphij return (0); 151296465Sdelphij } 152296465Sdelphij a->num_dirs = 0; 153296465Sdelphij a->dirs = NULL; 154296465Sdelphij a->dirs_type = NULL; 155296465Sdelphij a->num_dirs_alloced = 0; 156296465Sdelphij lu->method_data = (char *)a; 157296465Sdelphij return (1); 158296465Sdelphij} 15955714Skris 16055714Skrisstatic void free_dir(X509_LOOKUP *lu) 161296465Sdelphij{ 162296465Sdelphij BY_DIR *a; 163296465Sdelphij int i; 16455714Skris 165296465Sdelphij a = (BY_DIR *)lu->method_data; 166296465Sdelphij for (i = 0; i < a->num_dirs; i++) 167296465Sdelphij if (a->dirs[i] != NULL) 168296465Sdelphij OPENSSL_free(a->dirs[i]); 169296465Sdelphij if (a->dirs != NULL) 170296465Sdelphij OPENSSL_free(a->dirs); 171296465Sdelphij if (a->dirs_type != NULL) 172296465Sdelphij OPENSSL_free(a->dirs_type); 173296465Sdelphij if (a->buffer != NULL) 174296465Sdelphij BUF_MEM_free(a->buffer); 175296465Sdelphij OPENSSL_free(a); 176296465Sdelphij} 17755714Skris 17855714Skrisstatic int add_cert_dir(BY_DIR *ctx, const char *dir, int type) 179296465Sdelphij{ 180296465Sdelphij int j, len; 181296465Sdelphij int *ip; 182296465Sdelphij const char *s, *ss, *p; 183296465Sdelphij char **pp; 18455714Skris 185296465Sdelphij if (dir == NULL || !*dir) { 186296465Sdelphij X509err(X509_F_ADD_CERT_DIR, X509_R_INVALID_DIRECTORY); 187296465Sdelphij return 0; 188296465Sdelphij } 18955714Skris 190296465Sdelphij s = dir; 191296465Sdelphij p = s; 192296465Sdelphij for (;; p++) { 193296465Sdelphij if ((*p == LIST_SEPARATOR_CHAR) || (*p == '\0')) { 194296465Sdelphij ss = s; 195296465Sdelphij s = p + 1; 196296465Sdelphij len = (int)(p - ss); 197296465Sdelphij if (len == 0) 198296465Sdelphij continue; 199296465Sdelphij for (j = 0; j < ctx->num_dirs; j++) 200296465Sdelphij if (strlen(ctx->dirs[j]) == (size_t)len && 201296465Sdelphij strncmp(ctx->dirs[j], ss, (unsigned int)len) == 0) 202296465Sdelphij break; 203296465Sdelphij if (j < ctx->num_dirs) 204296465Sdelphij continue; 205296465Sdelphij if (ctx->num_dirs_alloced < (ctx->num_dirs + 1)) { 206296465Sdelphij ctx->num_dirs_alloced += 10; 207296465Sdelphij pp = (char **)OPENSSL_malloc(ctx->num_dirs_alloced * 208296465Sdelphij sizeof(char *)); 209296465Sdelphij ip = (int *)OPENSSL_malloc(ctx->num_dirs_alloced * 210296465Sdelphij sizeof(int)); 211296465Sdelphij if ((pp == NULL) || (ip == NULL)) { 212296465Sdelphij X509err(X509_F_ADD_CERT_DIR, ERR_R_MALLOC_FAILURE); 213296465Sdelphij return (0); 214296465Sdelphij } 215296465Sdelphij memcpy(pp, ctx->dirs, (ctx->num_dirs_alloced - 10) * 216296465Sdelphij sizeof(char *)); 217296465Sdelphij memcpy(ip, ctx->dirs_type, (ctx->num_dirs_alloced - 10) * 218296465Sdelphij sizeof(int)); 219296465Sdelphij if (ctx->dirs != NULL) 220296465Sdelphij OPENSSL_free(ctx->dirs); 221296465Sdelphij if (ctx->dirs_type != NULL) 222296465Sdelphij OPENSSL_free(ctx->dirs_type); 223296465Sdelphij ctx->dirs = pp; 224296465Sdelphij ctx->dirs_type = ip; 225296465Sdelphij } 226296465Sdelphij ctx->dirs_type[ctx->num_dirs] = type; 227296465Sdelphij ctx->dirs[ctx->num_dirs] = 228296465Sdelphij (char *)OPENSSL_malloc((unsigned int)len + 1); 229296465Sdelphij if (ctx->dirs[ctx->num_dirs] == NULL) 230296465Sdelphij return (0); 231296465Sdelphij strncpy(ctx->dirs[ctx->num_dirs], ss, (unsigned int)len); 232296465Sdelphij ctx->dirs[ctx->num_dirs][len] = '\0'; 233296465Sdelphij ctx->num_dirs++; 234296465Sdelphij } 235296465Sdelphij if (*p == '\0') 236296465Sdelphij break; 237296465Sdelphij } 238296465Sdelphij return (1); 239296465Sdelphij} 24055714Skris 24155714Skrisstatic int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, 242296465Sdelphij X509_OBJECT *ret) 243296465Sdelphij{ 244296465Sdelphij BY_DIR *ctx; 245296465Sdelphij union { 246296465Sdelphij struct { 247296465Sdelphij X509 st_x509; 248296465Sdelphij X509_CINF st_x509_cinf; 249296465Sdelphij } x509; 250296465Sdelphij struct { 251296465Sdelphij X509_CRL st_crl; 252296465Sdelphij X509_CRL_INFO st_crl_info; 253296465Sdelphij } crl; 254296465Sdelphij } data; 255296465Sdelphij int ok = 0; 256296465Sdelphij int i, j, k; 257296465Sdelphij unsigned long h; 258296465Sdelphij BUF_MEM *b = NULL; 259296465Sdelphij struct stat st; 260296465Sdelphij X509_OBJECT stmp, *tmp; 261296465Sdelphij const char *postfix = ""; 26255714Skris 263296465Sdelphij if (name == NULL) 264296465Sdelphij return (0); 26555714Skris 266296465Sdelphij stmp.type = type; 267296465Sdelphij if (type == X509_LU_X509) { 268296465Sdelphij data.x509.st_x509.cert_info = &data.x509.st_x509_cinf; 269296465Sdelphij data.x509.st_x509_cinf.subject = name; 270296465Sdelphij stmp.data.x509 = &data.x509.st_x509; 271296465Sdelphij postfix = ""; 272296465Sdelphij } else if (type == X509_LU_CRL) { 273296465Sdelphij data.crl.st_crl.crl = &data.crl.st_crl_info; 274296465Sdelphij data.crl.st_crl_info.issuer = name; 275296465Sdelphij stmp.data.crl = &data.crl.st_crl; 276296465Sdelphij postfix = "r"; 277296465Sdelphij } else { 278296465Sdelphij X509err(X509_F_GET_CERT_BY_SUBJECT, X509_R_WRONG_LOOKUP_TYPE); 279296465Sdelphij goto finish; 280296465Sdelphij } 28155714Skris 282296465Sdelphij if ((b = BUF_MEM_new()) == NULL) { 283296465Sdelphij X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_BUF_LIB); 284296465Sdelphij goto finish; 285296465Sdelphij } 28655714Skris 287296465Sdelphij ctx = (BY_DIR *)xl->method_data; 288296465Sdelphij 289296465Sdelphij h = X509_NAME_hash(name); 290296465Sdelphij for (i = 0; i < ctx->num_dirs; i++) { 291296465Sdelphij j = strlen(ctx->dirs[i]) + 1 + 8 + 6 + 1 + 1; 292296465Sdelphij if (!BUF_MEM_grow(b, j)) { 293296465Sdelphij X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_MALLOC_FAILURE); 294296465Sdelphij goto finish; 295296465Sdelphij } 296296465Sdelphij k = 0; 297296465Sdelphij for (;;) { 298296465Sdelphij char c = '/'; 299127128Snectar#ifdef OPENSSL_SYS_VMS 300296465Sdelphij c = ctx->dirs[i][strlen(ctx->dirs[i]) - 1]; 301296465Sdelphij if (c != ':' && c != '>' && c != ']') { 302296465Sdelphij /* 303296465Sdelphij * If no separator is present, we assume the directory 304296465Sdelphij * specifier is a logical name, and add a colon. We really 305296465Sdelphij * should use better VMS routines for merging things like 306296465Sdelphij * this, but this will do for now... -- Richard Levitte 307296465Sdelphij */ 308296465Sdelphij c = ':'; 309296465Sdelphij } else { 310296465Sdelphij c = '\0'; 311296465Sdelphij } 312127128Snectar#endif 313296465Sdelphij if (c == '\0') { 314296465Sdelphij /* 315296465Sdelphij * This is special. When c == '\0', no directory separator 316296465Sdelphij * should be added. 317296465Sdelphij */ 318296465Sdelphij BIO_snprintf(b->data, b->max, 319296465Sdelphij "%s%08lx.%s%d", ctx->dirs[i], h, postfix, k); 320296465Sdelphij } else { 321296465Sdelphij BIO_snprintf(b->data, b->max, 322296465Sdelphij "%s%c%08lx.%s%d", ctx->dirs[i], c, h, 323296465Sdelphij postfix, k); 324296465Sdelphij } 325296465Sdelphij k++; 326296465Sdelphij if (stat(b->data, &st) < 0) 327296465Sdelphij break; 328296465Sdelphij /* found one. */ 329296465Sdelphij if (type == X509_LU_X509) { 330296465Sdelphij if ((X509_load_cert_file(xl, b->data, 331296465Sdelphij ctx->dirs_type[i])) == 0) 332296465Sdelphij break; 333296465Sdelphij } else if (type == X509_LU_CRL) { 334296465Sdelphij if ((X509_load_crl_file(xl, b->data, ctx->dirs_type[i])) == 0) 335296465Sdelphij break; 336296465Sdelphij } 337296465Sdelphij /* else case will caught higher up */ 338296465Sdelphij } 33955714Skris 340296465Sdelphij /* 341296465Sdelphij * we have added it to the cache so now pull it out again 342296465Sdelphij */ 343296465Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE); 344296465Sdelphij j = sk_X509_OBJECT_find(xl->store_ctx->objs, &stmp); 345296465Sdelphij if (j != -1) 346296465Sdelphij tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, j); 347296465Sdelphij else 348296465Sdelphij tmp = NULL; 349296465Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); 35055714Skris 351296465Sdelphij if (tmp != NULL) { 352296465Sdelphij ok = 1; 353296465Sdelphij ret->type = tmp->type; 354296465Sdelphij memcpy(&ret->data, &tmp->data, sizeof(ret->data)); 355296465Sdelphij /* 356296465Sdelphij * If we were going to up the reference count, we would need to 357296465Sdelphij * do it on a perl 'type' basis 358296465Sdelphij */ 359296465Sdelphij /*- CRYPTO_add(&tmp->data.x509->references,1, 360296465Sdelphij CRYPTO_LOCK_X509);*/ 361296465Sdelphij goto finish; 362296465Sdelphij } 363296465Sdelphij } 364296465Sdelphij finish: 365296465Sdelphij if (b != NULL) 366296465Sdelphij BUF_MEM_free(b); 367296465Sdelphij return (ok); 368296465Sdelphij} 369