Cast size_t len arguments to %.*s to int
[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-2009 Andreas Steffen - Hochschule fuer Technik Rapperswil
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
16 #include <stdlib.h>
17 #include <errno.h>
18 #include <sys/time.h>
19 #include <time.h>
20 #include <string.h>
21
22 #ifdef THREADS
23 #include <pthread.h>
24 #endif
25
26 #include <freeswan.h>
27
28 #include <library.h>
29 #include <debug.h>
30 #include <asn1/asn1.h>
31 #include <credentials/certificates/certificate.h>
32 #ifdef THREADS
33 #include <threading/thread.h>
34 #endif
35
36 #include "constants.h"
37 #include "defs.h"
38 #include "log.h"
39 #include "x509.h"
40 #include "ca.h"
41 #include "whack.h"
42 #include "ocsp.h"
43 #include "crl.h"
44 #include "fetch.h"
45 #include "builder.h"
46
47 fetch_req_t empty_fetch_req = {
48 NULL , /* next */
49 0 , /* trials */
50 NULL , /* issuer */
51 { NULL, 0}, /* authKeyID */
52 NULL /* distributionPoints */
53 };
54
55 /* chained list of crl fetch requests */
56 static fetch_req_t *crl_fetch_reqs = NULL;
57
58 /* chained list of ocsp fetch requests */
59 static ocsp_location_t *ocsp_fetch_reqs = NULL;
60
61 #ifdef THREADS
62 static thread_t *thread;
63 static pthread_mutex_t certs_and_keys_mutex = PTHREAD_MUTEX_INITIALIZER;
64 static pthread_mutex_t authcert_list_mutex = PTHREAD_MUTEX_INITIALIZER;
65 static pthread_mutex_t crl_list_mutex = PTHREAD_MUTEX_INITIALIZER;
66 static pthread_mutex_t ocsp_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
67 static pthread_mutex_t ca_info_list_mutex = PTHREAD_MUTEX_INITIALIZER;
68 static pthread_mutex_t crl_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER;
69 static pthread_mutex_t ocsp_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER;
70 static pthread_mutex_t fetch_wake_mutex = PTHREAD_MUTEX_INITIALIZER;
71 static pthread_cond_t fetch_wake_cond = PTHREAD_COND_INITIALIZER;
72
73 /**
74 * lock access to my certs and keys
75 */
76 void lock_certs_and_keys(const char *who)
77 {
78 pthread_mutex_lock(&certs_and_keys_mutex);
79 DBG(DBG_CONTROLMORE,
80 DBG_log("certs and keys locked by '%s'", who)
81 )
82 }
83
84 /**
85 * Unlock access to my certs and keys
86 */
87 void unlock_certs_and_keys(const char *who)
88 {
89 DBG(DBG_CONTROLMORE,
90 DBG_log("certs and keys unlocked by '%s'", who)
91 )
92 pthread_mutex_unlock(&certs_and_keys_mutex);
93 }
94
95 /**
96 * Lock access to the chained authcert list
97 */
98 void lock_authcert_list(const char *who)
99 {
100 pthread_mutex_lock(&authcert_list_mutex);
101 DBG(DBG_CONTROLMORE,
102 DBG_log("authcert list locked by '%s'", who)
103 )
104 }
105
106 /**
107 * Unlock access to the chained authcert list
108 */
109 void unlock_authcert_list(const char *who)
110 {
111 DBG(DBG_CONTROLMORE,
112 DBG_log("authcert list unlocked by '%s'", who)
113 )
114 pthread_mutex_unlock(&authcert_list_mutex);
115 }
116
117 /**
118 * Lock access to the chained crl list
119 */
120 void lock_crl_list(const char *who)
121 {
122 pthread_mutex_lock(&crl_list_mutex);
123 DBG(DBG_CONTROLMORE,
124 DBG_log("crl list locked by '%s'", who)
125 )
126 }
127
128 /**
129 * Unlock access to the chained crl list
130 */
131 void unlock_crl_list(const char *who)
132 {
133 DBG(DBG_CONTROLMORE,
134 DBG_log("crl list unlocked by '%s'", who)
135 )
136 pthread_mutex_unlock(&crl_list_mutex);
137 }
138
139 /**
140 * Lock access to the ocsp cache
141 */
142 extern void lock_ocsp_cache(const char *who)
143 {
144 pthread_mutex_lock(&ocsp_cache_mutex);
145 DBG(DBG_CONTROLMORE,
146 DBG_log("ocsp cache locked by '%s'", who)
147 )
148 }
149
150 /**
151 * Unlock access to the ocsp cache
152 */
153 extern void unlock_ocsp_cache(const char *who)
154 {
155 DBG(DBG_CONTROLMORE,
156 DBG_log("ocsp cache unlocked by '%s'", who)
157 )
158 pthread_mutex_unlock(&ocsp_cache_mutex);
159 }
160
161 /**
162 * Lock access to the ca info list
163 */
164 extern void lock_ca_info_list(const char *who)
165 {
166 pthread_mutex_lock(&ca_info_list_mutex);
167 DBG(DBG_CONTROLMORE,
168 DBG_log("ca info list locked by '%s'", who)
169 )
170 }
171
172 /**
173 * Unlock access to the ca info list
174 */
175 extern void unlock_ca_info_list(const char *who)
176 {
177 DBG(DBG_CONTROLMORE,
178 DBG_log("ca info list unlocked by '%s'", who)
179 )
180 pthread_mutex_unlock(&ca_info_list_mutex);
181 }
182
183 /**
184 * Lock access to the chained crl fetch request list
185 */
186 static void lock_crl_fetch_list(const char *who)
187 {
188 pthread_mutex_lock(&crl_fetch_list_mutex);
189 DBG(DBG_CONTROLMORE,
190 DBG_log("crl fetch request list locked by '%s'", who)
191 )
192 }
193
194 /**
195 * Unlock access to the chained crl fetch request list
196 */
197 static void unlock_crl_fetch_list(const char *who)
198 {
199 DBG(DBG_CONTROLMORE,
200 DBG_log("crl fetch request list unlocked by '%s'", who)
201 )
202 pthread_mutex_unlock(&crl_fetch_list_mutex);
203 }
204
205 /**
206 * Lock access to the chained ocsp fetch request list
207 */
208 static void lock_ocsp_fetch_list(const char *who)
209 {
210 pthread_mutex_lock(&ocsp_fetch_list_mutex);
211 DBG(DBG_CONTROLMORE,
212 DBG_log("ocsp fetch request list locked by '%s'", who)
213 )
214 }
215
216 /**
217 * Unlock access to the chained ocsp fetch request list
218 */
219 static void unlock_ocsp_fetch_list(const char *who)
220 {
221 DBG(DBG_CONTROLMORE,
222 DBG_log("ocsp fetch request list unlocked by '%s'", who)
223 )
224 pthread_mutex_unlock(&ocsp_fetch_list_mutex);
225 }
226
227 /**
228 * Wakes up the sleeping fetch thread
229 */
230 void wake_fetch_thread(const char *who)
231 {
232 if (crl_check_interval > 0)
233 {
234 DBG(DBG_CONTROLMORE,
235 DBG_log("fetch thread wake call by '%s'", who)
236 )
237 pthread_mutex_lock(&fetch_wake_mutex);
238 pthread_cond_signal(&fetch_wake_cond);
239 pthread_mutex_unlock(&fetch_wake_mutex);
240 }
241 }
242 #else /* !THREADS */
243 #define lock_crl_fetch_list(who) /* do nothing */
244 #define unlock_crl_fetch_list(who) /* do nothing */
245 #define lock_ocsp_fetch_list(who) /* do nothing */
246 #define unlock_ocsp_fetch_list(who) /* do nothing */
247 #endif /* !THREADS */
248
249 /**
250 * Free the dynamic memory used to store fetch requests
251 */
252 static void free_fetch_request(fetch_req_t *req)
253 {
254 req->distributionPoints->destroy_function(req->distributionPoints, free);
255 DESTROY_IF(req->issuer);
256 free(req->authKeyID.ptr);
257 free(req);
258 }
259
260 #ifdef THREADS
261 /**
262 * Fetch an ASN.1 blob coded in PEM or DER format from a URL
263 */
264 x509crl_t* fetch_crl(char *url)
265 {
266 x509crl_t *crl;
267 chunk_t blob;
268
269 DBG1(DBG_LIB, " fetching crl from '%s' ...", url);
270 if (lib->fetcher->fetch(lib->fetcher, url, &blob, FETCH_END) != SUCCESS)
271 {
272 DBG1(DBG_LIB, "crl fetching failed");
273 return FALSE;
274 }
275 crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CRL,
276 BUILD_BLOB_PEM, blob, BUILD_END);
277 free(blob.ptr);
278 if (!crl)
279 {
280 DBG1(DBG_LIB, "crl fetched successfully but data coded in unknown "
281 "format");
282 }
283 return crl;
284 }
285
286 /**
287 * Complete a distributionPoint URI with ca information
288 */
289 static char* complete_uri(char *distPoint, const char *ldaphost)
290 {
291 char *symbol = strchr(distPoint, ':');
292
293 if (symbol)
294 {
295 int type_len = symbol - distPoint;
296
297 if (type_len >= 4 && strncasecmp(distPoint, "ldap", 4) == 0)
298 {
299 char *ptr = symbol + 1;
300 int len = strlen(distPoint) - (type_len + 1);
301
302 if (len > 2 && *ptr++ == '/' && *ptr++ == '/')
303 {
304 len -= 2;
305 symbol = strchr(ptr, '/');
306
307 if (symbol && symbol - ptr == 0 && ldaphost)
308 {
309 char uri[BUF_LEN];
310
311 /* insert the ldaphost into the uri */
312 snprintf(uri, BUF_LEN, "%.*s%s%.*s",
313 (int)strlen(distPoint) - len, distPoint, ldaphost,
314 len, symbol);
315 return strdup(uri);
316 }
317 }
318 }
319 }
320
321 /* default action: copy distributionPoint without change */
322 return strdup(distPoint);
323 }
324
325 /**
326 * Try to fetch the crls defined by the fetch requests
327 */
328 static void fetch_crls(bool cache_crls)
329 {
330 fetch_req_t *req;
331 fetch_req_t **reqp;
332
333 lock_crl_fetch_list("fetch_crls");
334 req = crl_fetch_reqs;
335 reqp = &crl_fetch_reqs;
336
337 while (req != NULL)
338 {
339 enumerator_t *enumerator;
340 char *point;
341 bool valid_crl = FALSE;
342 const char *ldaphost;
343 ca_info_t *ca;
344
345 lock_ca_info_list("fetch_crls");
346
347 ca = get_ca_info(req->issuer, req->authKeyID);
348 ldaphost = (ca == NULL)? NULL : ca->ldaphost;
349
350 enumerator = req->distributionPoints->create_enumerator(req->distributionPoints);
351 while (enumerator->enumerate(enumerator, &point))
352 {
353 x509crl_t *crl;
354 char *uri;
355
356 uri = complete_uri(point, ldaphost);
357 crl = fetch_crl(uri);
358 free(uri);
359
360 if (crl)
361 {
362 if (insert_crl(crl, point, cache_crls))
363 {
364 DBG(DBG_CONTROL,
365 DBG_log("we have a valid crl")
366 )
367 valid_crl = TRUE;
368 break;
369 }
370 }
371 }
372 enumerator->destroy(enumerator);
373 unlock_ca_info_list("fetch_crls");
374
375 if (valid_crl)
376 {
377 /* delete fetch request */
378 fetch_req_t *req_free = req;
379
380 req = req->next;
381 *reqp = req;
382 free_fetch_request(req_free);
383 }
384 else
385 {
386 /* try again next time */
387 req->trials++;
388 reqp = &req->next;
389 req = req->next;
390 }
391 }
392 unlock_crl_fetch_list("fetch_crls");
393 }
394
395 static void fetch_ocsp_status(ocsp_location_t* location)
396 {
397 chunk_t request = build_ocsp_request(location);
398 chunk_t response = chunk_empty;
399
400 DBG1(DBG_LIB, " requesting ocsp status from '%s' ...", location->uri);
401 if (lib->fetcher->fetch(lib->fetcher, location->uri, &response,
402 FETCH_REQUEST_DATA, request,
403 FETCH_REQUEST_TYPE, "application/ocsp-request",
404 FETCH_END) == SUCCESS)
405 {
406 parse_ocsp(location, response);
407 }
408 else
409 {
410 DBG1(DBG_LIB, "ocsp request to %s failed", location->uri);
411 }
412
413 free(request.ptr);
414 chunk_free(&location->nonce);
415
416 /* increment the trial counter of the unresolved fetch requests */
417 {
418 ocsp_certinfo_t *certinfo = location->certinfo;
419
420 while (certinfo != NULL)
421 {
422 certinfo->trials++;
423 certinfo = certinfo->next;
424 }
425 }
426 }
427
428 /**
429 * Try to fetch the necessary ocsp information
430 */
431 static void fetch_ocsp(void)
432 {
433 ocsp_location_t *location;
434
435 lock_ocsp_fetch_list("fetch_ocsp");
436 location = ocsp_fetch_reqs;
437
438 /* fetch the ocps status for all locations */
439 while (location != NULL)
440 {
441 if (location->certinfo != NULL)
442 {
443 fetch_ocsp_status(location);
444 }
445 location = location->next;
446 }
447
448 unlock_ocsp_fetch_list("fetch_ocsp");
449 }
450
451 static void* fetch_thread(void *arg)
452 {
453 struct timespec wait_interval;
454
455 /* the fetching thread is only cancellable while waiting for new events */
456 thread_cancelability(FALSE);
457
458 DBG(DBG_CONTROL,
459 DBG_log("fetch thread started")
460 )
461
462 pthread_mutex_lock(&fetch_wake_mutex);
463
464 while(1)
465 {
466 int status;
467
468 wait_interval.tv_nsec = 0;
469 wait_interval.tv_sec = time(NULL) + crl_check_interval;
470
471 DBG(DBG_CONTROL,
472 DBG_log("next regular crl check in %ld seconds", crl_check_interval)
473 )
474
475 thread_cancelability(TRUE);
476 status = pthread_cond_timedwait(&fetch_wake_cond, &fetch_wake_mutex
477 , &wait_interval);
478 thread_cancelability(FALSE);
479
480 if (status == ETIMEDOUT)
481 {
482 DBG(DBG_CONTROL,
483 DBG_log(" ");
484 DBG_log("*time to check crls and the ocsp cache")
485 )
486 check_ocsp();
487 check_crls();
488 }
489 else
490 {
491 DBG(DBG_CONTROL,
492 DBG_log("fetch thread was woken up")
493 )
494 }
495 fetch_ocsp();
496 fetch_crls(cache_crls);
497 }
498 return NULL;
499 }
500 #endif /* THREADS*/
501
502 /**
503 * Initializes curl and starts the fetching thread
504 */
505 void fetch_initialize(void)
506 {
507 if (crl_check_interval > 0)
508 {
509 #ifdef THREADS
510 thread = thread_create((thread_main_t)fetch_thread, NULL);
511 if (thread == NULL)
512 {
513 plog("fetching thread could not be started");
514 }
515 #else /* !THREADS */
516 plog("warning: not compiled with pthread support");
517 #endif /* !THREADS */
518 }
519 }
520
521 /**
522 * Terminates the fetching thread
523 */
524 void fetch_finalize(void)
525 {
526 if (crl_check_interval > 0)
527 {
528 #ifdef THREADS
529 if (thread)
530 {
531 thread->cancel(thread);
532 thread->join(thread);
533 }
534 #endif
535 }
536 }
537
538 void free_crl_fetch(void)
539 {
540 lock_crl_fetch_list("free_crl_fetch");
541
542 while (crl_fetch_reqs != NULL)
543 {
544 fetch_req_t *req = crl_fetch_reqs;
545 crl_fetch_reqs = req->next;
546 free_fetch_request(req);
547 }
548
549 unlock_crl_fetch_list("free_crl_fetch");
550 }
551
552 /**
553 * Free the chained list of ocsp requests
554 */
555 void free_ocsp_fetch(void)
556 {
557 lock_ocsp_fetch_list("free_ocsp_fetch");
558 free_ocsp_locations(&ocsp_fetch_reqs);
559 unlock_ocsp_fetch_list("free_ocsp_fetch");
560 }
561
562
563 /**
564 * Add an additional distribution point
565 */
566 void add_distribution_point(linked_list_t *points, char *new_point)
567 {
568 char *point;
569 bool add = TRUE;
570 enumerator_t *enumerator;
571
572 if (new_point == NULL || *new_point == '\0')
573 {
574 return;
575 }
576
577 enumerator = points->create_enumerator(points);
578 while (enumerator->enumerate(enumerator, &point))
579 {
580 if (streq(point, new_point))
581 {
582 add = FALSE;
583 break;
584 }
585 }
586 enumerator->destroy(enumerator);
587
588 if (add)
589 {
590 points->insert_last(points, strdup(new_point));
591 }
592 }
593
594 /**
595 * Add additional distribution points
596 */
597 void add_distribution_points(linked_list_t *points, linked_list_t *new_points)
598 {
599 char *new_point;
600 enumerator_t *enumerator;
601
602 enumerator = new_points->create_enumerator(new_points);
603 while (enumerator->enumerate(enumerator, &new_point))
604 {
605 bool add = TRUE;
606 char *point;
607 enumerator_t *enumerator;
608
609 enumerator = points->create_enumerator(points);
610 while (enumerator->enumerate(enumerator, &point))
611 {
612 if (streq(point, new_point))
613 {
614 add = FALSE;
615 break;
616 }
617 }
618 enumerator->destroy(enumerator);
619
620 if (add)
621 {
622 points->insert_last(points, strdup(new_point));
623 }
624 }
625 enumerator->destroy(enumerator);
626 }
627
628 fetch_req_t* build_crl_fetch_request(identification_t *issuer,
629 chunk_t authKeyID,
630 linked_list_t *distributionPoints)
631 {
632 char *point;
633 enumerator_t *enumerator;
634 fetch_req_t *req = malloc_thing(fetch_req_t);
635
636 memset(req, 0, sizeof(fetch_req_t));
637 req->distributionPoints = linked_list_create();
638
639 /* clone fields */
640 req->issuer = issuer->clone(issuer);
641 req->authKeyID = chunk_clone(authKeyID);
642
643 /* copy distribution points */
644 enumerator = distributionPoints->create_enumerator(distributionPoints);
645 while (enumerator->enumerate(enumerator, &point))
646 {
647 req->distributionPoints->insert_last(req->distributionPoints,
648 strdup(point));
649 }
650 enumerator->destroy(enumerator);
651
652 return req;
653 }
654
655 /**
656 * Add a crl fetch request to the chained list
657 */
658 void add_crl_fetch_request(fetch_req_t *req)
659 {
660 fetch_req_t *r;
661
662 lock_crl_fetch_list("add_crl_fetch_request");
663 r = crl_fetch_reqs;
664
665 while (r != NULL)
666 {
667 if (req->authKeyID.ptr ? same_keyid(req->authKeyID, r->authKeyID) :
668 req->issuer->equals(req->issuer, r->issuer))
669 {
670 /* there is already a fetch request */
671 DBG(DBG_CONTROL,
672 DBG_log("crl fetch request already exists")
673 )
674
675 /* there might be new distribution points */
676 add_distribution_points(r->distributionPoints,
677 req->distributionPoints);
678
679 unlock_crl_fetch_list("add_crl_fetch_request");
680 free_fetch_request(req);
681 return;
682 }
683 r = r->next;
684 }
685
686 /* insert new fetch request at the head of the queue */
687 req->next = crl_fetch_reqs;
688 crl_fetch_reqs = req;
689
690 DBG(DBG_CONTROL,
691 DBG_log("crl fetch request added")
692 )
693 unlock_crl_fetch_list("add_crl_fetch_request");
694 }
695
696 /**
697 * Add an ocsp fetch request to the chained list
698 */
699 void add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber)
700 {
701 ocsp_certinfo_t certinfo;
702
703 certinfo.serialNumber = serialNumber;
704
705 lock_ocsp_fetch_list("add_ocsp_fetch_request");
706 add_certinfo(location, &certinfo, &ocsp_fetch_reqs, TRUE);
707 unlock_ocsp_fetch_list("add_ocsp_fetch_request");
708 }
709
710 /**
711 * List all distribution points
712 */
713 void list_distribution_points(linked_list_t *distributionPoints)
714 {
715 char *point;
716 bool first_point = TRUE;
717 enumerator_t *enumerator;
718
719 enumerator = distributionPoints->create_enumerator(distributionPoints);
720 while (enumerator->enumerate(enumerator, &point))
721 {
722 whack_log(RC_COMMENT, " %s '%s'",
723 (first_point)? "distPts: " : " ", point);
724 first_point = FALSE;
725 }
726 enumerator->destroy(enumerator);
727 }
728
729 /**
730 * List all fetch requests in the chained list
731 */
732 void list_crl_fetch_requests(bool utc)
733 {
734 fetch_req_t *req;
735
736 lock_crl_fetch_list("list_crl_fetch_requests");
737 req = crl_fetch_reqs;
738
739 if (req != NULL)
740 {
741 whack_log(RC_COMMENT, " ");
742 whack_log(RC_COMMENT, "List of CRL Fetch Requests:");
743 }
744
745 while (req != NULL)
746 {
747 whack_log(RC_COMMENT, " ");
748 whack_log(RC_COMMENT, " trials: %d", req->trials);
749 whack_log(RC_COMMENT, " issuer: \"%Y\"", req->issuer);
750 if (req->authKeyID.ptr)
751 {
752 whack_log(RC_COMMENT, " authkey: %#B", &req->authKeyID);
753 }
754 list_distribution_points(req->distributionPoints);
755 req = req->next;
756 }
757 unlock_crl_fetch_list("list_crl_fetch_requests");
758 }
759
760 void list_ocsp_fetch_requests(bool utc)
761 {
762 lock_ocsp_fetch_list("list_ocsp_fetch_requests");
763 list_ocsp_locations(ocsp_fetch_reqs, TRUE, utc, FALSE);
764 unlock_ocsp_fetch_list("list_ocsp_fetch_requests");
765
766 }