Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

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