069ef2966f450c397ca5db53102ef7936b8d16f8
[strongswan.git] / src / pluto / fetch.c
1 /* Dynamic fetching of X.509 CRLs
2 * Copyright (C) 2002 Stephane Laroche <stephane.laroche@colubris.com>
3 * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * RCSID $Id$
16 */
17
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <sys/time.h>
21 #include <time.h>
22 #include <string.h>
23
24 #ifdef THREADS
25 #include <pthread.h>
26 #endif
27
28 #ifdef LIBCURL
29 #include <curl/curl.h>
30 #endif
31
32 #include <freeswan.h>
33
34 #ifdef LIBLDAP
35 #ifndef LDAP_DEPRECATED
36 #define LDAP_DEPRECATED 1
37 #endif
38 #include <ldap.h>
39 #endif
40
41 #include "constants.h"
42 #include "defs.h"
43 #include "log.h"
44 #include "id.h"
45 #include "asn1.h"
46 #include "pem.h"
47 #include "x509.h"
48 #include "ca.h"
49 #include "whack.h"
50 #include "ocsp.h"
51 #include "crl.h"
52 #include "fetch.h"
53
54 fetch_req_t empty_fetch_req = {
55 NULL , /* next */
56 0 , /* installed */
57 0 , /* trials */
58 { NULL, 0}, /* issuer */
59 { NULL, 0}, /* authKeyID */
60 { NULL, 0}, /* authKeySerialNumber */
61 NULL /* distributionPoints */
62 };
63
64 /* chained list of crl fetch requests */
65 static fetch_req_t *crl_fetch_reqs = NULL;
66
67 /* chained list of ocsp fetch requests */
68 static ocsp_location_t *ocsp_fetch_reqs = NULL;
69
70 #ifdef THREADS
71 static pthread_t thread;
72 static pthread_mutex_t certs_and_keys_mutex = PTHREAD_MUTEX_INITIALIZER;
73 static pthread_mutex_t authcert_list_mutex = PTHREAD_MUTEX_INITIALIZER;
74 static pthread_mutex_t crl_list_mutex = PTHREAD_MUTEX_INITIALIZER;
75 static pthread_mutex_t ocsp_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
76 static pthread_mutex_t ca_info_list_mutex = PTHREAD_MUTEX_INITIALIZER;
77 static pthread_mutex_t crl_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER;
78 static pthread_mutex_t ocsp_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER;
79 static pthread_mutex_t fetch_wake_mutex = PTHREAD_MUTEX_INITIALIZER;
80 static pthread_cond_t fetch_wake_cond = PTHREAD_COND_INITIALIZER;
81
82 /*
83 * lock access to my certs and keys
84 */
85 void
86 lock_certs_and_keys(const char *who)
87 {
88 pthread_mutex_lock(&certs_and_keys_mutex);
89 DBG(DBG_CONTROLMORE,
90 DBG_log("certs and keys locked by '%s'", who)
91 )
92 }
93
94 /*
95 * unlock access to my certs and keys
96 */
97 void
98 unlock_certs_and_keys(const char *who)
99 {
100 DBG(DBG_CONTROLMORE,
101 DBG_log("certs and keys unlocked by '%s'", who)
102 )
103 pthread_mutex_unlock(&certs_and_keys_mutex);
104 }
105
106 /*
107 * lock access to the chained authcert list
108 */
109 void
110 lock_authcert_list(const char *who)
111 {
112 pthread_mutex_lock(&authcert_list_mutex);
113 DBG(DBG_CONTROLMORE,
114 DBG_log("authcert list locked by '%s'", who)
115 )
116 }
117
118 /*
119 * unlock access to the chained authcert list
120 */
121 void
122 unlock_authcert_list(const char *who)
123 {
124 DBG(DBG_CONTROLMORE,
125 DBG_log("authcert list unlocked by '%s'", who)
126 )
127 pthread_mutex_unlock(&authcert_list_mutex);
128 }
129
130 /*
131 * lock access to the chained crl list
132 */
133 void
134 lock_crl_list(const char *who)
135 {
136 pthread_mutex_lock(&crl_list_mutex);
137 DBG(DBG_CONTROLMORE,
138 DBG_log("crl list locked by '%s'", who)
139 )
140 }
141
142 /*
143 * unlock access to the chained crl list
144 */
145 void
146 unlock_crl_list(const char *who)
147 {
148 DBG(DBG_CONTROLMORE,
149 DBG_log("crl list unlocked by '%s'", who)
150 )
151 pthread_mutex_unlock(&crl_list_mutex);
152 }
153
154 /*
155 * lock access to the ocsp cache
156 */
157 extern void
158 lock_ocsp_cache(const char *who)
159 {
160 pthread_mutex_lock(&ocsp_cache_mutex);
161 DBG(DBG_CONTROLMORE,
162 DBG_log("ocsp cache locked by '%s'", who)
163 )
164 }
165
166 /*
167 * unlock access to the ocsp cache
168 */
169 extern void
170 unlock_ocsp_cache(const char *who)
171 {
172 DBG(DBG_CONTROLMORE,
173 DBG_log("ocsp cache unlocked by '%s'", who)
174 )
175 pthread_mutex_unlock(&ocsp_cache_mutex);
176 }
177
178 /*
179 * lock access to the ca info list
180 */
181 extern void
182 lock_ca_info_list(const char *who)
183 {
184 pthread_mutex_lock(&ca_info_list_mutex);
185 DBG(DBG_CONTROLMORE,
186 DBG_log("ca info list locked by '%s'", who)
187 )
188 }
189
190 /*
191 * unlock access to the ca info list
192 */
193 extern void
194 unlock_ca_info_list(const char *who)
195 {
196 DBG(DBG_CONTROLMORE,
197 DBG_log("ca info list unlocked by '%s'", who)
198 )
199 pthread_mutex_unlock(&ca_info_list_mutex);
200 }
201
202 /*
203 * lock access to the chained crl fetch request list
204 */
205 static void
206 lock_crl_fetch_list(const char *who)
207 {
208 pthread_mutex_lock(&crl_fetch_list_mutex);
209 DBG(DBG_CONTROLMORE,
210 DBG_log("crl fetch request list locked by '%s'", who)
211 )
212 }
213
214 /*
215 * unlock access to the chained crl fetch request list
216 */
217 static void
218 unlock_crl_fetch_list(const char *who)
219 {
220 DBG(DBG_CONTROLMORE,
221 DBG_log("crl fetch request list unlocked by '%s'", who)
222 )
223 pthread_mutex_unlock(&crl_fetch_list_mutex);
224 }
225
226 /*
227 * lock access to the chained ocsp fetch request list
228 */
229 static void
230 lock_ocsp_fetch_list(const char *who)
231 {
232 pthread_mutex_lock(&ocsp_fetch_list_mutex);
233 DBG(DBG_CONTROLMORE,
234 DBG_log("ocsp fetch request list locked by '%s'", who)
235 )
236 }
237
238 /*
239 * unlock access to the chained ocsp fetch request list
240 */
241 static void
242 unlock_ocsp_fetch_list(const char *who)
243 {
244 DBG(DBG_CONTROLMORE,
245 DBG_log("ocsp fetch request list unlocked by '%s'", who)
246 )
247 pthread_mutex_unlock(&ocsp_fetch_list_mutex);
248 }
249
250 /*
251 * wakes up the sleeping fetch thread
252 */
253 void
254 wake_fetch_thread(const char *who)
255 {
256 if (crl_check_interval > 0)
257 {
258 DBG(DBG_CONTROLMORE,
259 DBG_log("fetch thread wake call by '%s'", who)
260 )
261 pthread_mutex_lock(&fetch_wake_mutex);
262 pthread_cond_signal(&fetch_wake_cond);
263 pthread_mutex_unlock(&fetch_wake_mutex);
264 }
265 }
266 #else /* !THREADS */
267 #define lock_crl_fetch_list(who) /* do nothing */
268 #define unlock_crl_fetch_list(who) /* do nothing */
269 #define lock_ocsp_fetch_list(who) /* do nothing */
270 #define unlock_ocsp_fetch_list(who) /* do nothing */
271 #endif /* !THREADS */
272
273 /*
274 * free the dynamic memory used to store fetch requests
275 */
276 static void
277 free_fetch_request(fetch_req_t *req)
278 {
279 pfree(req->issuer.ptr);
280 pfreeany(req->authKeySerialNumber.ptr);
281 pfreeany(req->authKeyID.ptr);
282 free_generalNames(req->distributionPoints, TRUE);
283 pfree(req);
284 }
285
286 /* writes data into a dynamically resizeable chunk_t
287 * needed for libcurl responses
288 */
289 size_t
290 write_buffer(void *ptr, size_t size, size_t nmemb, void *data)
291 {
292 size_t realsize = size * nmemb;
293 chunk_t *mem = (chunk_t*)data;
294
295 mem->ptr = (u_char *)realloc(mem->ptr, mem->len + realsize);
296 if (mem->ptr) {
297 memcpy(&(mem->ptr[mem->len]), ptr, realsize);
298 mem->len += realsize;
299 }
300 return realsize;
301 }
302
303 #ifdef THREADS
304 /*
305 * fetches a binary blob from a url with libcurl
306 */
307 static err_t
308 fetch_curl(char *url, chunk_t *blob)
309 {
310 #ifdef LIBCURL
311 char errorbuffer[CURL_ERROR_SIZE] = "";
312 chunk_t response = empty_chunk;
313 CURLcode res;
314
315 /* get it with libcurl */
316 CURL *curl = curl_easy_init();
317
318 if (curl != NULL)
319 {
320 DBG(DBG_CONTROL,
321 DBG_log("Trying cURL '%s'", url)
322 )
323
324 curl_easy_setopt(curl, CURLOPT_URL, url);
325 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer);
326 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
327 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &errorbuffer);
328 curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE);
329 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT);
330
331 res = curl_easy_perform(curl);
332
333 if (res == CURLE_OK)
334 {
335 blob->len = response.len;
336 blob->ptr = alloc_bytes(response.len, "curl blob");
337 memcpy(blob->ptr, response.ptr, response.len);
338 }
339 else
340 {
341 plog("fetching uri (%s) with libcurl failed: %s", url, errorbuffer);
342 }
343 curl_easy_cleanup(curl);
344 /* not using freeanychunk because of realloc (no leak detective) */
345 curl_free(response.ptr);
346 }
347 return strlen(errorbuffer) > 0 ? "libcurl error" : NULL;
348 #else /* !LIBCURL */
349 return "warning: not compiled with libcurl support";
350 #endif /* !LIBCURL */
351 }
352
353 #ifdef LIBLDAP
354 /*
355 * parses the result returned by an ldap query
356 */
357 static err_t
358 parse_ldap_result(LDAP * ldap, LDAPMessage *result, chunk_t *blob)
359 {
360 err_t ugh = NULL;
361
362 LDAPMessage * entry = ldap_first_entry(ldap, result);
363
364 if (entry != NULL)
365 {
366 BerElement *ber = NULL;
367 char *attr;
368
369 attr = ldap_first_attribute(ldap, entry, &ber);
370
371 if (attr != NULL)
372 {
373 struct berval **values = ldap_get_values_len(ldap, entry, attr);
374
375 if (values != NULL)
376 {
377 if (values[0] != NULL)
378 {
379 blob->len = values[0]->bv_len;
380 blob->ptr = alloc_bytes(blob->len, "ldap blob");
381 memcpy(blob->ptr, values[0]->bv_val, blob->len);
382 if (values[1] != NULL)
383 {
384 plog("warning: more than one value was fetched from LDAP URL");
385 }
386 }
387 else
388 {
389 ugh = "no values in attribute";
390 }
391 ldap_value_free_len(values);
392 }
393 else
394 {
395 ugh = ldap_err2string(ldap_result2error(ldap, entry, 0));
396 }
397 ldap_memfree(attr);
398 }
399 else
400 {
401 ugh = ldap_err2string(ldap_result2error(ldap, entry, 0));
402 }
403 ber_free(ber, 0);
404 }
405 else
406 {
407 ugh = ldap_err2string(ldap_result2error(ldap, result, 0));
408 }
409 return ugh;
410 }
411
412 /*
413 * fetches a binary blob from an ldap url
414 */
415 static err_t
416 fetch_ldap_url(char *url, chunk_t *blob)
417 {
418 LDAPURLDesc *lurl;
419 err_t ugh = NULL;
420 int rc;
421
422 DBG(DBG_CONTROL,
423 DBG_log("Trying LDAP URL '%s'", url)
424 )
425
426 rc = ldap_url_parse(url, &lurl);
427
428 if (rc == LDAP_SUCCESS)
429 {
430 LDAP *ldap = ldap_init(lurl->lud_host, lurl->lud_port);
431
432 if (ldap != NULL)
433 {
434 int ldap_version = LDAP_VERSION3;
435 struct timeval timeout;
436
437 timeout.tv_sec = FETCH_CMD_TIMEOUT;
438 timeout.tv_usec = 0;
439 ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
440 ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
441
442 rc = ldap_simple_bind_s(ldap, NULL, NULL);
443
444 if (rc == LDAP_SUCCESS)
445 {
446 LDAPMessage *result;
447
448 timeout.tv_sec = FETCH_CMD_TIMEOUT;
449 timeout.tv_usec = 0;
450
451 rc = ldap_search_st(ldap, lurl->lud_dn
452 , lurl->lud_scope
453 , lurl->lud_filter
454 , lurl->lud_attrs
455 , 0, &timeout, &result);
456
457 if (rc == LDAP_SUCCESS)
458 {
459 ugh = parse_ldap_result(ldap, result, blob);
460 ldap_msgfree(result);
461 }
462 else
463 {
464 ugh = ldap_err2string(rc);
465 }
466 }
467 else
468 {
469 ugh = ldap_err2string(rc);
470 }
471 ldap_unbind_s(ldap);
472 }
473 else
474 {
475 ugh = "ldap init";
476 }
477 ldap_free_urldesc(lurl);
478 }
479 else
480 {
481 ugh = ldap_err2string(rc);
482 }
483 return ugh;
484 }
485 #else /* !LIBLDAP */
486 static err_t
487 fetch_ldap_url(char *url, chunk_t *blob)
488 {
489 return "LDAP URL fetching not activated in pluto source code";
490 }
491 #endif /* !LIBLDAP */
492
493 /*
494 * fetch an ASN.1 blob coded in PEM or DER format from a URL
495 */
496 static err_t
497 fetch_asn1_blob(char *url, chunk_t *blob)
498 {
499 err_t ugh = NULL;
500
501 if (strlen(url) >= 4 && strncasecmp(url, "ldap", 4) == 0)
502 {
503 ugh = fetch_ldap_url(url, blob);
504 }
505 else
506 {
507 ugh = fetch_curl(url, blob);
508 }
509 if (ugh != NULL)
510 return ugh;
511
512 if (is_asn1(*blob))
513 {
514 DBG(DBG_PARSING,
515 DBG_log(" fetched blob coded in DER format")
516 )
517 }
518 else
519 {
520 bool pgp = FALSE;
521
522 ugh = pemtobin(blob, NULL, "", &pgp);
523 if (ugh == NULL)
524 {
525 if (is_asn1(*blob))
526 {
527 DBG(DBG_PARSING,
528 DBG_log(" fetched blob coded in PEM format")
529 )
530 }
531 else
532 {
533 ugh = "blob coded in unknown format";
534 pfree(blob->ptr);
535 }
536 }
537 else
538 {
539 pfree(blob->ptr);
540 }
541 }
542 return ugh;
543 }
544
545 /*
546 * complete a distributionPoint URI with ca information
547 */
548 static char*
549 complete_uri(chunk_t distPoint, const char *ldaphost)
550 {
551 char *uri;
552 char *ptr = distPoint.ptr;
553 size_t len = distPoint.len;
554
555 char *symbol = memchr(ptr, ':', len);
556
557 if (symbol != NULL)
558 {
559 size_t type_len = symbol - ptr;
560
561 if (type_len >= 4 && strncasecmp(ptr, "ldap", 4) == 0)
562 {
563 ptr = symbol + 1;
564 len -= (type_len + 1);
565
566 if (len > 2 && *ptr++ == '/' && *ptr++ == '/')
567 {
568 len -= 2;
569 symbol = memchr(ptr, '/', len);
570
571 if (symbol != NULL && symbol - ptr == 0 && ldaphost != NULL)
572 {
573 uri = alloc_bytes(distPoint.len+strlen(ldaphost)+1, "uri");
574
575 /* insert the ldaphost into the uri */
576 sprintf(uri, "%.*s%s%.*s"
577 , (int)(distPoint.len - len), distPoint.ptr
578 , ldaphost
579 , (int)len, symbol);
580 return uri;
581 }
582 }
583 }
584 }
585
586 /* default action: copy distributionPoint without change */
587 uri = alloc_bytes(distPoint.len+1, "uri");
588 sprintf(uri, "%.*s", (int)distPoint.len, distPoint.ptr);
589 return uri;
590 }
591
592 /*
593 * try to fetch the crls defined by the fetch requests
594 */
595 static void
596 fetch_crls(bool cache_crls)
597 {
598 fetch_req_t *req;
599 fetch_req_t **reqp;
600
601 lock_crl_fetch_list("fetch_crls");
602 req = crl_fetch_reqs;
603 reqp = &crl_fetch_reqs;
604
605 while (req != NULL)
606 {
607 bool valid_crl = FALSE;
608 chunk_t blob = empty_chunk;
609 generalName_t *gn = req->distributionPoints;
610 const char *ldaphost;
611 ca_info_t *ca;
612
613 lock_ca_info_list("fetch_crls");
614
615 ca = get_ca_info(req->issuer, req->authKeySerialNumber, req->authKeyID);
616 ldaphost = (ca == NULL)? NULL : ca->ldaphost;
617
618 while (gn != NULL)
619 {
620 char *uri = complete_uri(gn->name, ldaphost);
621
622 err_t ugh = fetch_asn1_blob(uri, &blob);
623 pfree(uri);
624
625 if (ugh != NULL)
626 {
627 plog("fetch failed: %s", ugh);
628 }
629 else
630 {
631 chunk_t crl_uri;
632
633 clonetochunk(crl_uri, gn->name.ptr, gn->name.len, "crl uri");
634 if (insert_crl(blob, crl_uri, cache_crls))
635 {
636 DBG(DBG_CONTROL,
637 DBG_log("we have a valid crl")
638 )
639 valid_crl = TRUE;
640 break;
641 }
642 }
643 gn = gn->next;
644 }
645
646 unlock_ca_info_list("fetch_crls");
647
648 if (valid_crl)
649 {
650 /* delete fetch request */
651 fetch_req_t *req_free = req;
652
653 req = req->next;
654 *reqp = req;
655 free_fetch_request(req_free);
656 }
657 else
658 {
659 /* try again next time */
660 req->trials++;
661 reqp = &req->next;
662 req = req->next;
663 }
664 }
665 unlock_crl_fetch_list("fetch_crls");
666 }
667
668 static void
669 fetch_ocsp_status(ocsp_location_t* location)
670 {
671 #ifdef LIBCURL
672 chunk_t request;
673 chunk_t response = empty_chunk;
674
675 CURL* curl;
676 CURLcode res;
677
678 request = build_ocsp_request(location);
679
680 DBG(DBG_CONTROL,
681 DBG_log("sending ocsp request to location '%.*s'"
682 , (int)location->uri.len, location->uri.ptr)
683 )
684 DBG(DBG_RAW,
685 DBG_dump_chunk("OCSP request", request)
686 )
687
688 /* send via http post using libcurl */
689 curl = curl_easy_init();
690
691 if (curl != NULL)
692 {
693 char errorbuffer[CURL_ERROR_SIZE];
694 struct curl_slist *headers = NULL;
695 char* uri = alloc_bytes(location->uri.len+1, "ocsp uri");
696
697 /* we need a null terminated string for curl */
698 memcpy(uri, location->uri.ptr, location->uri.len);
699 *(uri + location->uri.len) = '\0';
700
701 /* set content type header */
702 headers = curl_slist_append(headers, "Content-Type: application/ocsp-request");
703 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
704
705 curl_easy_setopt(curl, CURLOPT_URL, uri);
706 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer);
707 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
708 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request.ptr);
709 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request.len);
710 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &errorbuffer);
711 curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE);
712 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT);
713
714 res = curl_easy_perform(curl);
715
716 if (res == CURLE_OK)
717 {
718 DBG(DBG_CONTROL,
719 DBG_log("received ocsp response")
720 )
721 DBG(DBG_RAW,
722 DBG_dump_chunk("OCSP response:\n", response)
723 )
724 parse_ocsp(location, response);
725 }
726 else
727 {
728 plog("failed to fetch ocsp status from '%s': %s", uri, errorbuffer);
729 }
730 curl_slist_free_all(headers);
731 curl_easy_cleanup(curl);
732 pfree(uri);
733 /* not using freeanychunk because of realloc (no leak detective) */
734 curl_free(response.ptr);
735 }
736 freeanychunk(location->nonce);
737 freeanychunk(request);
738
739 /* increment the trial counter of the unresolved fetch requests */
740 {
741 ocsp_certinfo_t *certinfo = location->certinfo;
742
743 while (certinfo != NULL)
744 {
745 certinfo->trials++;
746 certinfo = certinfo->next;
747 }
748 }
749 return;
750 #else /* !LIBCURL */
751 plog("ocsp error: pluto wasn't compiled with libcurl support");
752 #endif /* !LIBCURL */
753 }
754
755 /*
756 * try to fetch the necessary ocsp information
757 */
758 static void
759 fetch_ocsp(void)
760 {
761 ocsp_location_t *location;
762
763 lock_ocsp_fetch_list("fetch_ocsp");
764 location = ocsp_fetch_reqs;
765
766 /* fetch the ocps status for all locations */
767 while (location != NULL)
768 {
769 if (location->certinfo != NULL)
770 fetch_ocsp_status(location);
771 location = location->next;
772 }
773
774 unlock_ocsp_fetch_list("fetch_ocsp");
775 }
776
777 static void*
778 fetch_thread(void *arg)
779 {
780 struct timespec wait_interval;
781
782 DBG(DBG_CONTROL,
783 DBG_log("fetch thread started")
784 )
785
786 pthread_mutex_lock(&fetch_wake_mutex);
787
788 while(1)
789 {
790 int status;
791
792 wait_interval.tv_nsec = 0;
793 wait_interval.tv_sec = time(NULL) + crl_check_interval;
794
795 DBG(DBG_CONTROL,
796 DBG_log("next regular crl check in %ld seconds", crl_check_interval)
797 )
798 status = pthread_cond_timedwait(&fetch_wake_cond, &fetch_wake_mutex
799 , &wait_interval);
800
801 if (status == ETIMEDOUT)
802 {
803 DBG(DBG_CONTROL,
804 DBG_log(" ");
805 DBG_log("*time to check crls and the ocsp cache")
806 )
807 check_ocsp();
808 check_crls();
809 }
810 else
811 {
812 DBG(DBG_CONTROL,
813 DBG_log("fetch thread was woken up")
814 )
815 }
816 fetch_ocsp();
817 fetch_crls(cache_crls);
818 }
819 }
820 #endif /* THREADS*/
821
822 /*
823 * initializes curl and starts the fetching thread
824 */
825 void
826 init_fetch(void)
827 {
828 int status;
829
830 #ifdef LIBCURL
831 /* init curl */
832 status = curl_global_init(CURL_GLOBAL_NOTHING);
833 if (status != CURLE_OK)
834 {
835 plog("libcurl could not be initialized, status = %d", status);
836 }
837 #endif /* LIBCURL */
838
839 if (crl_check_interval > 0)
840 {
841 #ifdef THREADS
842 status = pthread_create( &thread, NULL, fetch_thread, NULL);
843 if (status != 0)
844 {
845 plog("fetching thread could not be started, status = %d", status);
846 }
847 #else /* !THREADS */
848 plog("warning: not compiled with pthread support");
849 #endif /* !THREADS */
850 }
851 }
852
853 void
854 free_crl_fetch(void)
855 {
856 lock_crl_fetch_list("free_crl_fetch");
857
858 while (crl_fetch_reqs != NULL)
859 {
860 fetch_req_t *req = crl_fetch_reqs;
861 crl_fetch_reqs = req->next;
862 free_fetch_request(req);
863 }
864
865 unlock_crl_fetch_list("free_crl_fetch");
866
867 #ifdef LIBCURL
868 if (crl_check_interval > 0)
869 {
870 /* cleanup curl */
871 curl_global_cleanup();
872 }
873 #endif /* LIBCURL */
874 }
875
876 /*
877 * free the chained list of ocsp requests
878 */
879 void
880 free_ocsp_fetch(void)
881 {
882 lock_ocsp_fetch_list("free_ocsp_fetch");
883 free_ocsp_locations(&ocsp_fetch_reqs);
884 unlock_ocsp_fetch_list("free_ocsp_fetch");
885 }
886
887
888 /*
889 * add additional distribution points
890 */
891 void
892 add_distribution_points(const generalName_t *newPoints ,generalName_t **distributionPoints)
893 {
894 while (newPoints != NULL)
895 {
896 /* skip empty distribution point */
897 if (newPoints->name.len > 0)
898 {
899 bool add = TRUE;
900 generalName_t *gn = *distributionPoints;
901
902 while (gn != NULL)
903 {
904 if (gn->kind == newPoints->kind
905 && gn->name.len == newPoints->name.len
906 && memcmp(gn->name.ptr, newPoints->name.ptr, gn->name.len) == 0)
907 {
908 /* skip if the distribution point is already present */
909 add = FALSE;
910 break;
911 }
912 gn = gn->next;
913 }
914
915 if (add)
916 {
917 /* clone additional distribution point */
918 gn = clone_thing(*newPoints, "generalName");
919 clonetochunk(gn->name, newPoints->name.ptr, newPoints->name.len
920 , "crl uri");
921
922 /* insert additional CRL distribution point */
923 gn->next = *distributionPoints;
924 *distributionPoints = gn;
925 }
926 }
927 newPoints = newPoints->next;
928 }
929 }
930
931 fetch_req_t*
932 build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber
933 , chunk_t authKeyID, const generalName_t *gn)
934 {
935 fetch_req_t *req = alloc_thing(fetch_req_t, "fetch request");
936 *req = empty_fetch_req;
937
938 /* note current time */
939 req->installed = time(NULL);
940
941 /* clone fields */
942 clonetochunk(req->issuer, issuer.ptr, issuer.len, "issuer");
943 if (authKeySerialNumber.ptr != NULL)
944 {
945 clonetochunk(req->authKeySerialNumber, authKeySerialNumber.ptr
946 , authKeySerialNumber.len, "authKeySerialNumber");
947 }
948 if (authKeyID.ptr != NULL)
949 {
950 clonetochunk(req->authKeyID, authKeyID.ptr, authKeyID.len, "authKeyID");
951 }
952
953 /* copy distribution points */
954 add_distribution_points(gn, &req->distributionPoints);
955
956 return req;
957 }
958
959 /*
960 * add a crl fetch request to the chained list
961 */
962 void
963 add_crl_fetch_request(fetch_req_t *req)
964 {
965 fetch_req_t *r;
966
967 lock_crl_fetch_list("add_crl_fetch_request");
968 r = crl_fetch_reqs;
969
970 while (r != NULL)
971 {
972 if ((req->authKeyID.ptr != NULL)? same_keyid(req->authKeyID, r->authKeyID)
973 : (same_dn(req->issuer, r->issuer)
974 && same_serial(req->authKeySerialNumber, r->authKeySerialNumber)))
975 {
976 /* there is already a fetch request */
977 DBG(DBG_CONTROL,
978 DBG_log("crl fetch request already exists")
979 )
980
981 /* there might be new distribution points */
982 add_distribution_points(req->distributionPoints, &r->distributionPoints);
983
984 unlock_crl_fetch_list("add_crl_fetch_request");
985 free_fetch_request(req);
986 return;
987 }
988 r = r->next;
989 }
990
991 /* insert new fetch request at the head of the queue */
992 req->next = crl_fetch_reqs;
993 crl_fetch_reqs = req;
994
995 DBG(DBG_CONTROL,
996 DBG_log("crl fetch request added")
997 )
998 unlock_crl_fetch_list("add_crl_fetch_request");
999 }
1000
1001 /*
1002 * add an ocsp fetch request to the chained list
1003 */
1004 void
1005 add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber)
1006 {
1007 ocsp_certinfo_t certinfo;
1008
1009 certinfo.serialNumber = serialNumber;
1010
1011 lock_ocsp_fetch_list("add_ocsp_fetch_request");
1012 add_certinfo(location, &certinfo, &ocsp_fetch_reqs, TRUE);
1013 unlock_ocsp_fetch_list("add_ocsp_fetch_request");
1014 }
1015
1016 /*
1017 * list all distribution points
1018 */
1019 void
1020 list_distribution_points(const generalName_t *gn)
1021 {
1022 bool first_gn = TRUE;
1023
1024 while (gn != NULL)
1025 {
1026 whack_log(RC_COMMENT, " %s '%.*s'", (first_gn)? "distPts: "
1027 :" ", (int)gn->name.len, gn->name.ptr);
1028 first_gn = FALSE;
1029 gn = gn->next;
1030 }
1031 }
1032
1033 /*
1034 * list all fetch requests in the chained list
1035 */
1036 void
1037 list_crl_fetch_requests(bool utc)
1038 {
1039 fetch_req_t *req;
1040
1041 lock_crl_fetch_list("list_crl_fetch_requests");
1042 req = crl_fetch_reqs;
1043
1044 if (req != NULL)
1045 {
1046 whack_log(RC_COMMENT, " ");
1047 whack_log(RC_COMMENT, "List of CRL fetch requests:");
1048 whack_log(RC_COMMENT, " ");
1049 }
1050
1051 while (req != NULL)
1052 {
1053 u_char buf[BUF_LEN];
1054
1055 whack_log(RC_COMMENT, "%s, trials: %d"
1056 , timetoa(&req->installed, utc), req->trials);
1057 dntoa(buf, BUF_LEN, req->issuer);
1058 whack_log(RC_COMMENT, " issuer: '%s'", buf);
1059 if (req->authKeyID.ptr != NULL)
1060 {
1061 datatot(req->authKeyID.ptr, req->authKeyID.len, ':'
1062 , buf, BUF_LEN);
1063 whack_log(RC_COMMENT, " authkey: %s", buf);
1064 }
1065 if (req->authKeySerialNumber.ptr != NULL)
1066 {
1067 datatot(req->authKeySerialNumber.ptr, req->authKeySerialNumber.len, ':'
1068 , buf, BUF_LEN);
1069 whack_log(RC_COMMENT, " aserial: %s", buf);
1070 }
1071 list_distribution_points(req->distributionPoints);
1072 req = req->next;
1073 }
1074 unlock_crl_fetch_list("list_crl_fetch_requests");
1075 }
1076
1077 void
1078 list_ocsp_fetch_requests(bool utc)
1079 {
1080 lock_ocsp_fetch_list("list_ocsp_fetch_requests");
1081 list_ocsp_locations(ocsp_fetch_reqs, TRUE, utc, FALSE);
1082 unlock_ocsp_fetch_list("list_ocsp_fetch_requests");
1083
1084 }