diff options
Diffstat (limited to 'src/pluto/fetch.c')
-rw-r--r-- | src/pluto/fetch.c | 1081 |
1 files changed, 1081 insertions, 0 deletions
diff --git a/src/pluto/fetch.c b/src/pluto/fetch.c new file mode 100644 index 000000000..e3e56d3a8 --- /dev/null +++ b/src/pluto/fetch.c @@ -0,0 +1,1081 @@ +/* Dynamic fetching of X.509 CRLs + * Copyright (C) 2002 Stephane Laroche <stephane.laroche@colubris.com> + * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * RCSID $Id: fetch.c,v 1.12 2006/05/16 14:19:27 as Exp $ + */ + +#include <stdlib.h> +#include <errno.h> +#include <sys/time.h> +#include <time.h> +#include <string.h> + +#ifdef THREADS +#include <pthread.h> +#endif + +#ifdef LIBCURL +#include <curl/curl.h> +#endif + +#include <freeswan.h> + +#ifdef LIBLDAP +#include <ldap.h> +#endif + +#include "constants.h" +#include "defs.h" +#include "log.h" +#include "id.h" +#include "asn1.h" +#include "pem.h" +#include "x509.h" +#include "ca.h" +#include "whack.h" +#include "ocsp.h" +#include "crl.h" +#include "fetch.h" + +fetch_req_t empty_fetch_req = { + NULL , /* next */ + 0 , /* installed */ + 0 , /* trials */ + { NULL, 0}, /* issuer */ + { NULL, 0}, /* authKeyID */ + { NULL, 0}, /* authKeySerialNumber */ + NULL /* distributionPoints */ +}; + +/* chained list of crl fetch requests */ +static fetch_req_t *crl_fetch_reqs = NULL; + +/* chained list of ocsp fetch requests */ +static ocsp_location_t *ocsp_fetch_reqs = NULL; + +#ifdef THREADS +static pthread_t thread; +static pthread_mutex_t certs_and_keys_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t authcert_list_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t crl_list_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t ocsp_cache_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t ca_info_list_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t crl_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t ocsp_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t fetch_wake_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t fetch_wake_cond = PTHREAD_COND_INITIALIZER; + +/* + * lock access to my certs and keys + */ +void +lock_certs_and_keys(const char *who) +{ + pthread_mutex_lock(&certs_and_keys_mutex); + DBG(DBG_CONTROLMORE, + DBG_log("certs and keys locked by '%s'", who) + ) +} + +/* + * unlock access to my certs and keys + */ +void +unlock_certs_and_keys(const char *who) +{ + DBG(DBG_CONTROLMORE, + DBG_log("certs and keys unlocked by '%s'", who) + ) + pthread_mutex_unlock(&certs_and_keys_mutex); +} + +/* + * lock access to the chained authcert list + */ +void +lock_authcert_list(const char *who) +{ + pthread_mutex_lock(&authcert_list_mutex); + DBG(DBG_CONTROLMORE, + DBG_log("authcert list locked by '%s'", who) + ) +} + +/* + * unlock access to the chained authcert list + */ +void +unlock_authcert_list(const char *who) +{ + DBG(DBG_CONTROLMORE, + DBG_log("authcert list unlocked by '%s'", who) + ) + pthread_mutex_unlock(&authcert_list_mutex); +} + +/* + * lock access to the chained crl list + */ +void +lock_crl_list(const char *who) +{ + pthread_mutex_lock(&crl_list_mutex); + DBG(DBG_CONTROLMORE, + DBG_log("crl list locked by '%s'", who) + ) +} + +/* + * unlock access to the chained crl list + */ +void +unlock_crl_list(const char *who) +{ + DBG(DBG_CONTROLMORE, + DBG_log("crl list unlocked by '%s'", who) + ) + pthread_mutex_unlock(&crl_list_mutex); +} + +/* + * lock access to the ocsp cache + */ +extern void +lock_ocsp_cache(const char *who) +{ + pthread_mutex_lock(&ocsp_cache_mutex); + DBG(DBG_CONTROLMORE, + DBG_log("ocsp cache locked by '%s'", who) + ) +} + +/* + * unlock access to the ocsp cache + */ +extern void +unlock_ocsp_cache(const char *who) +{ + DBG(DBG_CONTROLMORE, + DBG_log("ocsp cache unlocked by '%s'", who) + ) + pthread_mutex_unlock(&ocsp_cache_mutex); +} + +/* + * lock access to the ca info list + */ +extern void +lock_ca_info_list(const char *who) +{ + pthread_mutex_lock(&ca_info_list_mutex); + DBG(DBG_CONTROLMORE, + DBG_log("ca info list locked by '%s'", who) + ) +} + +/* + * unlock access to the ca info list + */ +extern void +unlock_ca_info_list(const char *who) +{ + DBG(DBG_CONTROLMORE, + DBG_log("ca info list unlocked by '%s'", who) + ) + pthread_mutex_unlock(&ca_info_list_mutex); +} + +/* + * lock access to the chained crl fetch request list + */ +static void +lock_crl_fetch_list(const char *who) +{ + pthread_mutex_lock(&crl_fetch_list_mutex); + DBG(DBG_CONTROLMORE, + DBG_log("crl fetch request list locked by '%s'", who) + ) +} + +/* + * unlock access to the chained crl fetch request list + */ +static void +unlock_crl_fetch_list(const char *who) +{ + DBG(DBG_CONTROLMORE, + DBG_log("crl fetch request list unlocked by '%s'", who) + ) + pthread_mutex_unlock(&crl_fetch_list_mutex); +} + +/* + * lock access to the chained ocsp fetch request list + */ +static void +lock_ocsp_fetch_list(const char *who) +{ + pthread_mutex_lock(&ocsp_fetch_list_mutex); + DBG(DBG_CONTROLMORE, + DBG_log("ocsp fetch request list locked by '%s'", who) + ) +} + +/* + * unlock access to the chained ocsp fetch request list + */ +static void +unlock_ocsp_fetch_list(const char *who) +{ + DBG(DBG_CONTROLMORE, + DBG_log("ocsp fetch request list unlocked by '%s'", who) + ) + pthread_mutex_unlock(&ocsp_fetch_list_mutex); +} + +/* + * wakes up the sleeping fetch thread + */ +void +wake_fetch_thread(const char *who) +{ + if (crl_check_interval > 0) + { + DBG(DBG_CONTROLMORE, + DBG_log("fetch thread wake call by '%s'", who) + ) + pthread_mutex_lock(&fetch_wake_mutex); + pthread_cond_signal(&fetch_wake_cond); + pthread_mutex_unlock(&fetch_wake_mutex); + } +} +#else /* !THREADS */ +#define lock_crl_fetch_list(who) /* do nothing */ +#define unlock_crl_fetch_list(who) /* do nothing */ +#define lock_ocsp_fetch_list(who) /* do nothing */ +#define unlock_ocsp_fetch_list(who) /* do nothing */ +#endif /* !THREADS */ + +/* + * free the dynamic memory used to store fetch requests + */ +static void +free_fetch_request(fetch_req_t *req) +{ + pfree(req->issuer.ptr); + pfreeany(req->authKeySerialNumber.ptr); + pfreeany(req->authKeyID.ptr); + free_generalNames(req->distributionPoints, TRUE); + pfree(req); +} + +/* writes data into a dynamically resizeable chunk_t + * needed for libcurl responses + */ +size_t +write_buffer(void *ptr, size_t size, size_t nmemb, void *data) +{ + size_t realsize = size * nmemb; + chunk_t *mem = (chunk_t*)data; + + mem->ptr = (u_char *)realloc(mem->ptr, mem->len + realsize); + if (mem->ptr) { + memcpy(&(mem->ptr[mem->len]), ptr, realsize); + mem->len += realsize; + } + return realsize; +} + +#ifdef THREADS +/* + * fetches a binary blob from a url with libcurl + */ +static err_t +fetch_curl(char *url, chunk_t *blob) +{ +#ifdef LIBCURL + char errorbuffer[CURL_ERROR_SIZE] = ""; + chunk_t response = empty_chunk; + CURLcode res; + + /* get it with libcurl */ + CURL *curl = curl_easy_init(); + + if (curl != NULL) + { + DBG(DBG_CONTROL, + DBG_log("Trying cURL '%s'", url) + ) + + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &errorbuffer); + curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT); + + res = curl_easy_perform(curl); + + if (res == CURLE_OK) + { + blob->len = response.len; + blob->ptr = alloc_bytes(response.len, "curl blob"); + memcpy(blob->ptr, response.ptr, response.len); + } + else + { + plog("fetching uri (%s) with libcurl failed: %s", url, errorbuffer); + } + curl_easy_cleanup(curl); + /* not using freeanychunk because of realloc (no leak detective) */ + curl_free(response.ptr); + } + return strlen(errorbuffer) > 0 ? "libcurl error" : NULL; +#else /* !LIBCURL */ + return "warning: not compiled with libcurl support"; +#endif /* !LIBCURL */ +} + +#ifdef LIBLDAP +/* + * parses the result returned by an ldap query + */ +static err_t +parse_ldap_result(LDAP * ldap, LDAPMessage *result, chunk_t *blob) +{ + err_t ugh = NULL; + + LDAPMessage * entry = ldap_first_entry(ldap, result); + + if (entry != NULL) + { + BerElement *ber = NULL; + char *attr; + + attr = ldap_first_attribute(ldap, entry, &ber); + + if (attr != NULL) + { + struct berval **values = ldap_get_values_len(ldap, entry, attr); + + if (values != NULL) + { + if (values[0] != NULL) + { + blob->len = values[0]->bv_len; + blob->ptr = alloc_bytes(blob->len, "ldap blob"); + memcpy(blob->ptr, values[0]->bv_val, blob->len); + if (values[1] != NULL) + { + plog("warning: more than one value was fetched from LDAP URL"); + } + } + else + { + ugh = "no values in attribute"; + } + ldap_value_free_len(values); + } + else + { + ugh = ldap_err2string(ldap_result2error(ldap, entry, 0)); + } + ldap_memfree(attr); + } + else + { + ugh = ldap_err2string(ldap_result2error(ldap, entry, 0)); + } + ber_free(ber, 0); + } + else + { + ugh = ldap_err2string(ldap_result2error(ldap, result, 0)); + } + return ugh; +} + +/* + * fetches a binary blob from an ldap url + */ +static err_t +fetch_ldap_url(char *url, chunk_t *blob) +{ + LDAPURLDesc *lurl; + err_t ugh = NULL; + int rc; + + DBG(DBG_CONTROL, + DBG_log("Trying LDAP URL '%s'", url) + ) + + rc = ldap_url_parse(url, &lurl); + + if (rc == LDAP_SUCCESS) + { + LDAP *ldap = ldap_init(lurl->lud_host, lurl->lud_port); + + if (ldap != NULL) + { + int ldap_version = LDAP_VERSION3; + struct timeval timeout; + + timeout.tv_sec = FETCH_CMD_TIMEOUT; + timeout.tv_usec = 0; + ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version); + ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout); + + rc = ldap_simple_bind_s(ldap, NULL, NULL); + + if (rc == LDAP_SUCCESS) + { + LDAPMessage *result; + + timeout.tv_sec = FETCH_CMD_TIMEOUT; + timeout.tv_usec = 0; + + rc = ldap_search_st(ldap, lurl->lud_dn + , lurl->lud_scope + , lurl->lud_filter + , lurl->lud_attrs + , 0, &timeout, &result); + + if (rc == LDAP_SUCCESS) + { + ugh = parse_ldap_result(ldap, result, blob); + ldap_msgfree(result); + } + else + { + ugh = ldap_err2string(rc); + } + } + else + { + ugh = ldap_err2string(rc); + } + ldap_unbind_s(ldap); + } + else + { + ugh = "ldap init"; + } + ldap_free_urldesc(lurl); + } + else + { + ugh = ldap_err2string(rc); + } + return ugh; +} +#else /* !LIBLDAP */ +static err_t +fetch_ldap_url(char *url, chunk_t *blob) +{ + return "LDAP URL fetching not activated in pluto source code"; +} +#endif /* !LIBLDAP */ + +/* + * fetch an ASN.1 blob coded in PEM or DER format from a URL + */ +static err_t +fetch_asn1_blob(char *url, chunk_t *blob) +{ + err_t ugh = NULL; + + if (strlen(url) >= 4 && strncasecmp(url, "ldap", 4) == 0) + { + ugh = fetch_ldap_url(url, blob); + } + else + { + ugh = fetch_curl(url, blob); + } + if (ugh != NULL) + return ugh; + + if (is_asn1(*blob)) + { + DBG(DBG_PARSING, + DBG_log(" fetched blob coded in DER format") + ) + } + else + { + bool pgp = FALSE; + + ugh = pemtobin(blob, NULL, "", &pgp); + if (ugh == NULL) + { + if (is_asn1(*blob)) + { + DBG(DBG_PARSING, + DBG_log(" fetched blob coded in PEM format") + ) + } + else + { + ugh = "blob coded in unknown format"; + pfree(blob->ptr); + } + } + else + { + pfree(blob->ptr); + } + } + return ugh; +} + +/* + * complete a distributionPoint URI with ca information + */ +static char* +complete_uri(chunk_t distPoint, const char *ldaphost) +{ + char *uri; + char *ptr = distPoint.ptr; + size_t len = distPoint.len; + + char *symbol = memchr(ptr, ':', len); + + if (symbol != NULL) + { + size_t type_len = symbol - ptr; + + if (type_len >= 4 && strncasecmp(ptr, "ldap", 4) == 0) + { + ptr = symbol + 1; + len -= (type_len + 1); + + if (len > 2 && *ptr++ == '/' && *ptr++ == '/') + { + len -= 2; + symbol = memchr(ptr, '/', len); + + if (symbol != NULL && symbol - ptr == 0 && ldaphost != NULL) + { + uri = alloc_bytes(distPoint.len+strlen(ldaphost)+1, "uri"); + + /* insert the ldaphost into the uri */ + sprintf(uri, "%.*s%s%.*s" + , (int)(distPoint.len - len), distPoint.ptr + , ldaphost + , (int)len, symbol); + return uri; + } + } + } + } + + /* default action: copy distributionPoint without change */ + uri = alloc_bytes(distPoint.len+1, "uri"); + sprintf(uri, "%.*s", (int)distPoint.len, distPoint.ptr); + return uri; +} + +/* + * try to fetch the crls defined by the fetch requests + */ +static void +fetch_crls(bool cache_crls) +{ + fetch_req_t *req; + fetch_req_t **reqp; + + lock_crl_fetch_list("fetch_crls"); + req = crl_fetch_reqs; + reqp = &crl_fetch_reqs; + + while (req != NULL) + { + bool valid_crl = FALSE; + chunk_t blob = empty_chunk; + generalName_t *gn = req->distributionPoints; + const char *ldaphost; + ca_info_t *ca; + + lock_ca_info_list("fetch_crls"); + + ca = get_ca_info(req->issuer, req->authKeySerialNumber, req->authKeyID); + ldaphost = (ca == NULL)? NULL : ca->ldaphost; + + while (gn != NULL) + { + char *uri = complete_uri(gn->name, ldaphost); + + err_t ugh = fetch_asn1_blob(uri, &blob); + pfree(uri); + + if (ugh != NULL) + { + plog("fetch failed: %s", ugh); + } + else + { + chunk_t crl_uri; + + clonetochunk(crl_uri, gn->name.ptr, gn->name.len, "crl uri"); + if (insert_crl(blob, crl_uri, cache_crls)) + { + DBG(DBG_CONTROL, + DBG_log("we have a valid crl") + ) + valid_crl = TRUE; + break; + } + } + gn = gn->next; + } + + unlock_ca_info_list("fetch_crls"); + + if (valid_crl) + { + /* delete fetch request */ + fetch_req_t *req_free = req; + + req = req->next; + *reqp = req; + free_fetch_request(req_free); + } + else + { + /* try again next time */ + req->trials++; + reqp = &req->next; + req = req->next; + } + } + unlock_crl_fetch_list("fetch_crls"); +} + +static void +fetch_ocsp_status(ocsp_location_t* location) +{ +#ifdef LIBCURL + chunk_t request; + chunk_t response = empty_chunk; + + CURL* curl; + CURLcode res; + + request = build_ocsp_request(location); + + DBG(DBG_CONTROL, + DBG_log("sending ocsp request to location '%.*s'" + , (int)location->uri.len, location->uri.ptr) + ) + DBG(DBG_RAW, + DBG_dump_chunk("OCSP request", request) + ) + + /* send via http post using libcurl */ + curl = curl_easy_init(); + + if (curl != NULL) + { + char errorbuffer[CURL_ERROR_SIZE]; + struct curl_slist *headers = NULL; + char* uri = alloc_bytes(location->uri.len+1, "ocsp uri"); + + /* we need a null terminated string for curl */ + memcpy(uri, location->uri.ptr, location->uri.len); + *(uri + location->uri.len) = '\0'; + + /* set content type header */ + headers = curl_slist_append(headers, "Content-Type: application/ocsp-request"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + curl_easy_setopt(curl, CURLOPT_URL, uri); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request.ptr); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request.len); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &errorbuffer); + curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT); + + res = curl_easy_perform(curl); + + if (res == CURLE_OK) + { + DBG(DBG_CONTROL, + DBG_log("received ocsp response") + ) + DBG(DBG_RAW, + DBG_dump_chunk("OCSP response:\n", response) + ) + parse_ocsp(location, response); + } + else + { + plog("failed to fetch ocsp status from '%s': %s", uri, errorbuffer); + } + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + pfree(uri); + /* not using freeanychunk because of realloc (no leak detective) */ + curl_free(response.ptr); + } + freeanychunk(location->nonce); + freeanychunk(request); + + /* increment the trial counter of the unresolved fetch requests */ + { + ocsp_certinfo_t *certinfo = location->certinfo; + + while (certinfo != NULL) + { + certinfo->trials++; + certinfo = certinfo->next; + } + } + return; +#else /* !LIBCURL */ + plog("ocsp error: pluto wasn't compiled with libcurl support"); +#endif /* !LIBCURL */ +} + +/* + * try to fetch the necessary ocsp information + */ +static void +fetch_ocsp(void) +{ + ocsp_location_t *location; + + lock_ocsp_fetch_list("fetch_ocsp"); + location = ocsp_fetch_reqs; + + /* fetch the ocps status for all locations */ + while (location != NULL) + { + if (location->certinfo != NULL) + fetch_ocsp_status(location); + location = location->next; + } + + unlock_ocsp_fetch_list("fetch_ocsp"); +} + +static void* +fetch_thread(void *arg) +{ + struct timespec wait_interval; + + DBG(DBG_CONTROL, + DBG_log("fetch thread started") + ) + + pthread_mutex_lock(&fetch_wake_mutex); + + while(1) + { + int status; + + wait_interval.tv_nsec = 0; + wait_interval.tv_sec = time(NULL) + crl_check_interval; + + DBG(DBG_CONTROL, + DBG_log("next regular crl check in %ld seconds", crl_check_interval) + ) + status = pthread_cond_timedwait(&fetch_wake_cond, &fetch_wake_mutex + , &wait_interval); + + if (status == ETIMEDOUT) + { + DBG(DBG_CONTROL, + DBG_log(" "); + DBG_log("*time to check crls and the ocsp cache") + ) + check_ocsp(); + check_crls(); + } + else + { + DBG(DBG_CONTROL, + DBG_log("fetch thread was woken up") + ) + } + fetch_ocsp(); + fetch_crls(cache_crls); + } +} +#endif /* THREADS*/ + +/* + * initializes curl and starts the fetching thread + */ +void +init_fetch(void) +{ + int status; + +#ifdef LIBCURL + /* init curl */ + status = curl_global_init(CURL_GLOBAL_NOTHING); + if (status != CURLE_OK) + { + plog("libcurl could not be initialized, status = %d", status); + } +#endif /* LIBCURL */ + + if (crl_check_interval > 0) + { +#ifdef THREADS + status = pthread_create( &thread, NULL, fetch_thread, NULL); + if (status != 0) + { + plog("fetching thread could not be started, status = %d", status); + } +#else /* !THREADS */ + plog("warning: not compiled with pthread support"); +#endif /* !THREADS */ + } +} + +void +free_crl_fetch(void) +{ + lock_crl_fetch_list("free_crl_fetch"); + + while (crl_fetch_reqs != NULL) + { + fetch_req_t *req = crl_fetch_reqs; + crl_fetch_reqs = req->next; + free_fetch_request(req); + } + + unlock_crl_fetch_list("free_crl_fetch"); + +#ifdef LIBCURL + if (crl_check_interval > 0) + { + /* cleanup curl */ + curl_global_cleanup(); + } +#endif /* LIBCURL */ +} + +/* + * free the chained list of ocsp requests + */ +void +free_ocsp_fetch(void) +{ + lock_ocsp_fetch_list("free_ocsp_fetch"); + free_ocsp_locations(&ocsp_fetch_reqs); + unlock_ocsp_fetch_list("free_ocsp_fetch"); +} + + +/* + * add additional distribution points + */ +void +add_distribution_points(const generalName_t *newPoints ,generalName_t **distributionPoints) +{ + while (newPoints != NULL) + { + /* skip empty distribution point */ + if (newPoints->name.len > 0) + { + bool add = TRUE; + generalName_t *gn = *distributionPoints; + + while (gn != NULL) + { + if (gn->kind == newPoints->kind + && gn->name.len == newPoints->name.len + && memcmp(gn->name.ptr, newPoints->name.ptr, gn->name.len) == 0) + { + /* skip if the distribution point is already present */ + add = FALSE; + break; + } + gn = gn->next; + } + + if (add) + { + /* clone additional distribution point */ + gn = clone_thing(*newPoints, "generalName"); + clonetochunk(gn->name, newPoints->name.ptr, newPoints->name.len + , "crl uri"); + + /* insert additional CRL distribution point */ + gn->next = *distributionPoints; + *distributionPoints = gn; + } + } + newPoints = newPoints->next; + } +} + +fetch_req_t* +build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber +, chunk_t authKeyID, const generalName_t *gn) +{ + fetch_req_t *req = alloc_thing(fetch_req_t, "fetch request"); + *req = empty_fetch_req; + + /* note current time */ + req->installed = time(NULL); + + /* clone fields */ + clonetochunk(req->issuer, issuer.ptr, issuer.len, "issuer"); + if (authKeySerialNumber.ptr != NULL) + { + clonetochunk(req->authKeySerialNumber, authKeySerialNumber.ptr + , authKeySerialNumber.len, "authKeySerialNumber"); + } + if (authKeyID.ptr != NULL) + { + clonetochunk(req->authKeyID, authKeyID.ptr, authKeyID.len, "authKeyID"); + } + + /* copy distribution points */ + add_distribution_points(gn, &req->distributionPoints); + + return req; +} + +/* + * add a crl fetch request to the chained list + */ +void +add_crl_fetch_request(fetch_req_t *req) +{ + fetch_req_t *r; + + lock_crl_fetch_list("add_crl_fetch_request"); + r = crl_fetch_reqs; + + while (r != NULL) + { + if ((req->authKeyID.ptr != NULL)? same_keyid(req->authKeyID, r->authKeyID) + : (same_dn(req->issuer, r->issuer) + && same_serial(req->authKeySerialNumber, r->authKeySerialNumber))) + { + /* there is already a fetch request */ + DBG(DBG_CONTROL, + DBG_log("crl fetch request already exists") + ) + + /* there might be new distribution points */ + add_distribution_points(req->distributionPoints, &r->distributionPoints); + + unlock_crl_fetch_list("add_crl_fetch_request"); + free_fetch_request(req); + return; + } + r = r->next; + } + + /* insert new fetch request at the head of the queue */ + req->next = crl_fetch_reqs; + crl_fetch_reqs = req; + + DBG(DBG_CONTROL, + DBG_log("crl fetch request added") + ) + unlock_crl_fetch_list("add_crl_fetch_request"); +} + +/* + * add an ocsp fetch request to the chained list + */ +void +add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber) +{ + ocsp_certinfo_t certinfo; + + certinfo.serialNumber = serialNumber; + + lock_ocsp_fetch_list("add_ocsp_fetch_request"); + add_certinfo(location, &certinfo, &ocsp_fetch_reqs, TRUE); + unlock_ocsp_fetch_list("add_ocsp_fetch_request"); +} + +/* + * list all distribution points + */ +void +list_distribution_points(const generalName_t *gn) +{ + bool first_gn = TRUE; + + while (gn != NULL) + { + whack_log(RC_COMMENT, " %s '%.*s'", (first_gn)? "distPts: " + :" ", (int)gn->name.len, gn->name.ptr); + first_gn = FALSE; + gn = gn->next; + } +} + +/* + * list all fetch requests in the chained list + */ +void +list_crl_fetch_requests(bool utc) +{ + fetch_req_t *req; + + lock_crl_fetch_list("list_crl_fetch_requests"); + req = crl_fetch_reqs; + + if (req != NULL) + { + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of CRL fetch requests:"); + whack_log(RC_COMMENT, " "); + } + + while (req != NULL) + { + u_char buf[BUF_LEN]; + + whack_log(RC_COMMENT, "%s, trials: %d" + , timetoa(&req->installed, utc), req->trials); + dntoa(buf, BUF_LEN, req->issuer); + whack_log(RC_COMMENT, " issuer: '%s'", buf); + if (req->authKeyID.ptr != NULL) + { + datatot(req->authKeyID.ptr, req->authKeyID.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " authkey: %s", buf); + } + if (req->authKeySerialNumber.ptr != NULL) + { + datatot(req->authKeySerialNumber.ptr, req->authKeySerialNumber.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " aserial: %s", buf); + } + list_distribution_points(req->distributionPoints); + req = req->next; + } + unlock_crl_fetch_list("list_crl_fetch_requests"); +} + +void +list_ocsp_fetch_requests(bool utc) +{ + lock_ocsp_fetch_list("list_ocsp_fetch_requests"); + list_ocsp_locations(ocsp_fetch_reqs, TRUE, utc, FALSE); + unlock_ocsp_fetch_list("list_ocsp_fetch_requests"); + +} |