Logo Search packages:      
Sourcecode: strongswan version File versions  Download package

fetch.c

/* 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 LDAP_VER
#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 LDAP_VER
/*
 * 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_VER == 2)? LDAP_VERSION2 : 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   /* !LDAP_VER */
static err_t
fetch_ldap_url(char *url, chunk_t *blob)
{
    return "LDAP URL fetching not activated in pluto source code";
}
#endif  /* !LDAP_VER */

/*
 * 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_FILE, (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 != 0)
    {
      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");

}

Generated by  Doxygen 1.6.0   Back to index