Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 
 

492 rindas
12 KiB

  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. #include <string.h>
  58. #include <sys/stat.h>
  59. #include <sys/types.h>
  60. #include <openssl/buf.h>
  61. #include <openssl/err.h>
  62. #include <openssl/lhash.h>
  63. #include <openssl/mem.h>
  64. #include <openssl/thread.h>
  65. #include <openssl/x509.h>
  66. #include "../internal.h"
  67. typedef struct lookup_dir_hashes_st
  68. {
  69. unsigned long hash;
  70. int suffix;
  71. } BY_DIR_HASH;
  72. typedef struct lookup_dir_entry_st
  73. {
  74. char *dir;
  75. int dir_type;
  76. STACK_OF(BY_DIR_HASH) *hashes;
  77. } BY_DIR_ENTRY;
  78. typedef struct lookup_dir_st
  79. {
  80. BUF_MEM *buffer;
  81. STACK_OF(BY_DIR_ENTRY) *dirs;
  82. } BY_DIR;
  83. DECLARE_STACK_OF(BY_DIR_HASH)
  84. DECLARE_STACK_OF(BY_DIR_ENTRY)
  85. static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,
  86. char **ret);
  87. static int new_dir(X509_LOOKUP *lu);
  88. static void free_dir(X509_LOOKUP *lu);
  89. static int add_cert_dir(BY_DIR *ctx,const char *dir,int type);
  90. static int get_cert_by_subject(X509_LOOKUP *xl,int type,X509_NAME *name,
  91. X509_OBJECT *ret);
  92. X509_LOOKUP_METHOD x509_dir_lookup=
  93. {
  94. "Load certs from files in a directory",
  95. new_dir, /* new */
  96. free_dir, /* free */
  97. NULL, /* init */
  98. NULL, /* shutdown */
  99. dir_ctrl, /* ctrl */
  100. get_cert_by_subject, /* get_by_subject */
  101. NULL, /* get_by_issuer_serial */
  102. NULL, /* get_by_fingerprint */
  103. NULL, /* get_by_alias */
  104. };
  105. X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void)
  106. {
  107. return(&x509_dir_lookup);
  108. }
  109. static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,
  110. char **retp)
  111. {
  112. int ret=0;
  113. BY_DIR *ld;
  114. char *dir = NULL;
  115. ld=(BY_DIR *)ctx->method_data;
  116. switch (cmd)
  117. {
  118. case X509_L_ADD_DIR:
  119. if (argl == X509_FILETYPE_DEFAULT)
  120. {
  121. dir=(char *)getenv(X509_get_default_cert_dir_env());
  122. if (dir)
  123. ret=add_cert_dir(ld,dir,X509_FILETYPE_PEM);
  124. else
  125. ret=add_cert_dir(ld,X509_get_default_cert_dir(),
  126. X509_FILETYPE_PEM);
  127. if (!ret)
  128. {
  129. OPENSSL_PUT_ERROR(X509, dir_ctrl, X509_R_LOADING_CERT_DIR);
  130. }
  131. }
  132. else
  133. ret=add_cert_dir(ld,argp,(int)argl);
  134. break;
  135. }
  136. return(ret);
  137. }
  138. static int new_dir(X509_LOOKUP *lu)
  139. {
  140. BY_DIR *a;
  141. if ((a=(BY_DIR *)OPENSSL_malloc(sizeof(BY_DIR))) == NULL)
  142. return(0);
  143. if ((a->buffer=BUF_MEM_new()) == NULL)
  144. {
  145. OPENSSL_free(a);
  146. return(0);
  147. }
  148. a->dirs=NULL;
  149. lu->method_data=(char *)a;
  150. return(1);
  151. }
  152. static void by_dir_hash_free(BY_DIR_HASH *hash)
  153. {
  154. OPENSSL_free(hash);
  155. }
  156. static int by_dir_hash_cmp(const BY_DIR_HASH **a,
  157. const BY_DIR_HASH **b)
  158. {
  159. if ((*a)->hash > (*b)->hash)
  160. return 1;
  161. if ((*a)->hash < (*b)->hash)
  162. return -1;
  163. return 0;
  164. }
  165. static void by_dir_entry_free(BY_DIR_ENTRY *ent)
  166. {
  167. if (ent->dir)
  168. OPENSSL_free(ent->dir);
  169. if (ent->hashes)
  170. sk_BY_DIR_HASH_pop_free(ent->hashes, by_dir_hash_free);
  171. OPENSSL_free(ent);
  172. }
  173. static void free_dir(X509_LOOKUP *lu)
  174. {
  175. BY_DIR *a;
  176. a=(BY_DIR *)lu->method_data;
  177. if (a->dirs != NULL)
  178. sk_BY_DIR_ENTRY_pop_free(a->dirs, by_dir_entry_free);
  179. if (a->buffer != NULL)
  180. BUF_MEM_free(a->buffer);
  181. OPENSSL_free(a);
  182. }
  183. static int add_cert_dir(BY_DIR *ctx, const char *dir, int type)
  184. {
  185. size_t j,len;
  186. const char *s,*ss,*p;
  187. if (dir == NULL || !*dir)
  188. {
  189. OPENSSL_PUT_ERROR(X509, add_cert_dir, X509_R_INVALID_DIRECTORY);
  190. return 0;
  191. }
  192. s=dir;
  193. p=s;
  194. do
  195. {
  196. if ((*p == ':') || (*p == '\0'))
  197. {
  198. BY_DIR_ENTRY *ent;
  199. ss=s;
  200. s=p+1;
  201. len=p-ss;
  202. if (len == 0) continue;
  203. for (j=0; j < sk_BY_DIR_ENTRY_num(ctx->dirs); j++)
  204. {
  205. ent = sk_BY_DIR_ENTRY_value(ctx->dirs, j);
  206. if (strlen(ent->dir) == len &&
  207. strncmp(ent->dir,ss,len) == 0)
  208. break;
  209. }
  210. if (j < sk_BY_DIR_ENTRY_num(ctx->dirs))
  211. continue;
  212. if (ctx->dirs == NULL)
  213. {
  214. ctx->dirs = sk_BY_DIR_ENTRY_new_null();
  215. if (!ctx->dirs)
  216. {
  217. OPENSSL_PUT_ERROR(X509, add_cert_dir, ERR_R_MALLOC_FAILURE);
  218. return 0;
  219. }
  220. }
  221. ent = OPENSSL_malloc(sizeof(BY_DIR_ENTRY));
  222. if (!ent)
  223. return 0;
  224. ent->dir_type = type;
  225. ent->hashes = sk_BY_DIR_HASH_new(by_dir_hash_cmp);
  226. ent->dir = OPENSSL_malloc(len+1);
  227. if (!ent->dir || !ent->hashes)
  228. {
  229. by_dir_entry_free(ent);
  230. return 0;
  231. }
  232. strncpy(ent->dir,ss,len);
  233. ent->dir[len] = '\0';
  234. if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent))
  235. {
  236. by_dir_entry_free(ent);
  237. return 0;
  238. }
  239. }
  240. } while (*p++ != '\0');
  241. return 1;
  242. }
  243. /* g_ent_hashes_lock protects the |hashes| member of all |BY_DIR_ENTRY|
  244. * objects. */
  245. static struct CRYPTO_STATIC_MUTEX g_ent_hashes_lock = CRYPTO_STATIC_MUTEX_INIT;
  246. static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
  247. X509_OBJECT *ret)
  248. {
  249. BY_DIR *ctx;
  250. union {
  251. struct {
  252. X509 st_x509;
  253. X509_CINF st_x509_cinf;
  254. } x509;
  255. struct {
  256. X509_CRL st_crl;
  257. X509_CRL_INFO st_crl_info;
  258. } crl;
  259. } data;
  260. int ok=0;
  261. size_t i;
  262. int j,k;
  263. unsigned long h;
  264. unsigned long hash_array[2];
  265. int hash_index;
  266. BUF_MEM *b=NULL;
  267. X509_OBJECT stmp,*tmp;
  268. const char *postfix="";
  269. if (name == NULL) return(0);
  270. stmp.type=type;
  271. if (type == X509_LU_X509)
  272. {
  273. data.x509.st_x509.cert_info= &data.x509.st_x509_cinf;
  274. data.x509.st_x509_cinf.subject=name;
  275. stmp.data.x509= &data.x509.st_x509;
  276. postfix="";
  277. }
  278. else if (type == X509_LU_CRL)
  279. {
  280. data.crl.st_crl.crl= &data.crl.st_crl_info;
  281. data.crl.st_crl_info.issuer=name;
  282. stmp.data.crl= &data.crl.st_crl;
  283. postfix="r";
  284. }
  285. else
  286. {
  287. OPENSSL_PUT_ERROR(X509, get_cert_by_subject, X509_R_WRONG_LOOKUP_TYPE);
  288. goto finish;
  289. }
  290. if ((b=BUF_MEM_new()) == NULL)
  291. {
  292. OPENSSL_PUT_ERROR(X509, get_cert_by_subject, ERR_R_BUF_LIB);
  293. goto finish;
  294. }
  295. ctx=(BY_DIR *)xl->method_data;
  296. hash_array[0]=X509_NAME_hash(name);
  297. hash_array[1]=X509_NAME_hash_old(name);
  298. for (hash_index=0; hash_index < 2; ++hash_index)
  299. {
  300. h=hash_array[hash_index];
  301. for (i=0; i < sk_BY_DIR_ENTRY_num(ctx->dirs); i++)
  302. {
  303. BY_DIR_ENTRY *ent;
  304. size_t idx;
  305. BY_DIR_HASH htmp, *hent;
  306. ent = sk_BY_DIR_ENTRY_value(ctx->dirs, i);
  307. j=strlen(ent->dir)+1+8+6+1+1;
  308. if (!BUF_MEM_grow(b,j))
  309. {
  310. OPENSSL_PUT_ERROR(X509, get_cert_by_subject, ERR_R_MALLOC_FAILURE);
  311. goto finish;
  312. }
  313. if (type == X509_LU_CRL && ent->hashes)
  314. {
  315. htmp.hash = h;
  316. CRYPTO_STATIC_MUTEX_lock_read(&g_ent_hashes_lock);
  317. if (sk_BY_DIR_HASH_find(ent->hashes, &idx, &htmp))
  318. {
  319. hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
  320. k = hent->suffix;
  321. }
  322. else
  323. {
  324. hent = NULL;
  325. k=0;
  326. }
  327. CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock);
  328. }
  329. else
  330. {
  331. k = 0;
  332. hent = NULL;
  333. }
  334. for (;;)
  335. {
  336. char c = '/';
  337. #ifdef OPENSSL_SYS_VMS
  338. c = ent->dir[strlen(ent->dir)-1];
  339. if (c != ':' && c != '>' && c != ']')
  340. {
  341. /* If no separator is present, we assume the
  342. directory specifier is a logical name, and
  343. add a colon. We really should use better
  344. VMS routines for merging things like this,
  345. but this will do for now...
  346. -- Richard Levitte */
  347. c = ':';
  348. }
  349. else
  350. {
  351. c = '\0';
  352. }
  353. #endif
  354. if (c == '\0')
  355. {
  356. /* This is special. When c == '\0', no
  357. directory separator should be added. */
  358. BIO_snprintf(b->data,b->max,
  359. "%s%08lx.%s%d",ent->dir,h,
  360. postfix,k);
  361. }
  362. else
  363. {
  364. BIO_snprintf(b->data,b->max,
  365. "%s%c%08lx.%s%d",ent->dir,c,h,
  366. postfix,k);
  367. }
  368. #ifndef OPENSSL_NO_POSIX_IO
  369. #ifdef _WIN32
  370. #define stat _stat
  371. #endif
  372. {
  373. struct stat st;
  374. if (stat(b->data,&st) < 0)
  375. break;
  376. }
  377. #endif
  378. /* found one. */
  379. if (type == X509_LU_X509)
  380. {
  381. if ((X509_load_cert_file(xl,b->data,
  382. ent->dir_type)) == 0)
  383. break;
  384. }
  385. else if (type == X509_LU_CRL)
  386. {
  387. if ((X509_load_crl_file(xl,b->data,
  388. ent->dir_type)) == 0)
  389. break;
  390. }
  391. /* else case will caught higher up */
  392. k++;
  393. }
  394. /* we have added it to the cache so now pull
  395. * it out again */
  396. CRYPTO_MUTEX_lock_write(&xl->store_ctx->objs_lock);
  397. tmp = NULL;
  398. if (sk_X509_OBJECT_find(xl->store_ctx->objs, &idx, &stmp)) {
  399. tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,idx);
  400. }
  401. CRYPTO_MUTEX_unlock(&xl->store_ctx->objs_lock);
  402. /* If a CRL, update the last file suffix added for this */
  403. if (type == X509_LU_CRL)
  404. {
  405. CRYPTO_STATIC_MUTEX_lock_write(&g_ent_hashes_lock);
  406. /* Look for entry again in case another thread added
  407. * an entry first.
  408. */
  409. if (!hent)
  410. {
  411. htmp.hash = h;
  412. if (sk_BY_DIR_HASH_find(ent->hashes, &idx, &htmp))
  413. hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
  414. }
  415. if (!hent)
  416. {
  417. hent = OPENSSL_malloc(sizeof(BY_DIR_HASH));
  418. if (hent == NULL)
  419. {
  420. CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock);
  421. ok = 0;
  422. goto finish;
  423. }
  424. hent->hash = h;
  425. hent->suffix = k;
  426. if (!sk_BY_DIR_HASH_push(ent->hashes, hent))
  427. {
  428. CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock);
  429. OPENSSL_free(hent);
  430. ok = 0;
  431. goto finish;
  432. }
  433. }
  434. else if (hent->suffix < k)
  435. hent->suffix = k;
  436. CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock);
  437. }
  438. if (tmp != NULL)
  439. {
  440. ok=1;
  441. ret->type=tmp->type;
  442. memcpy(&ret->data,&tmp->data,sizeof(ret->data));
  443. /* If we were going to up the reference count,
  444. * we would need to do it on a perl 'type'
  445. * basis */
  446. /* CRYPTO_add(&tmp->data.x509->references,1,
  447. CRYPTO_LOCK_X509);*/
  448. goto finish;
  449. }
  450. }
  451. }
  452. finish:
  453. if (b != NULL) BUF_MEM_free(b);
  454. return(ok);
  455. }