diff options
Diffstat (limited to 'src/libstrongswan/crypto/ca.c')
-rw-r--r-- | src/libstrongswan/crypto/ca.c | 813 |
1 files changed, 0 insertions, 813 deletions
diff --git a/src/libstrongswan/crypto/ca.c b/src/libstrongswan/crypto/ca.c deleted file mode 100644 index 510e3528e..000000000 --- a/src/libstrongswan/crypto/ca.c +++ /dev/null @@ -1,813 +0,0 @@ -/** - * @file ca.c - * - * @brief Implementation of ca_info_t. - * - */ - -/* - * Copyright (C) 2007 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * 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. - */ - -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> -#include <stdio.h> -#include <pthread.h> - -#include "x509.h" -#include "crl.h" -#include "ca.h" -#include "ac.h" -#include "certinfo.h" -#include "ocsp.h" - -#include <library.h> -#include <debug.h> -#include <utils/linked_list.h> -#include <utils/identification.h> -#include <utils/fetcher.h> - -typedef struct private_ca_info_t private_ca_info_t; - -/** - * Private data of a ca_info_t object. - */ -struct private_ca_info_t { - /** - * Public interface for this ca info record - */ - ca_info_t public; - - /** - * Name of the ca info record - */ - char *name; - - /** - * Time when ca info record was installed - */ - time_t installed; - - /** - * Distinguished Name of the CA - */ - x509_t *cacert; - - /** - * List of attribute certificates - */ - linked_list_t *attrcerts; - - /** - * List of crl URIs - */ - linked_list_t *crluris; - - /** - * List of ocsp URIs - */ - linked_list_t *ocspuris; - - /** - * CRL issued by this ca - */ - crl_t *crl; - - /** - * List of certificate info records - */ - linked_list_t *certinfos; - - /** - * mutex controls access to the elements: - * name, crluris, ocspuris, crl, and certinfos - */ - pthread_mutex_t mutex; -}; - -/** - * static options set by ca_info_set_options() - */ -static strict_t strict_crl_policy = STRICT_NO; -static bool cache_crls = FALSE; -static u_int crl_check_interval = 0; - -/** - * Implements ca_info_t.equals - */ -static bool equals(const private_ca_info_t *this, const private_ca_info_t *that) -{ - return chunk_equals(this->cacert->get_keyid(this->cacert), - that->cacert->get_keyid(that->cacert)); -} - -/** - * Implements ca_info_t.equals_name_release_info - */ -static bool equals_name_release_info(private_ca_info_t *this, const char *name) -{ - bool found; - - pthread_mutex_lock(&(this->mutex)); - found = this->name != NULL && streq(this->name, name); - - if (found) - { - this->crluris->destroy_offset(this->crluris, - offsetof(identification_t, destroy)); - this->crluris = linked_list_create(); - - this->ocspuris->destroy_offset(this->ocspuris, - offsetof(identification_t, destroy)); - this->ocspuris = linked_list_create(); - - free(this->name); - this->name = NULL; - } - - pthread_mutex_unlock(&(this->mutex)); - return found; -} - -/** - * Implements ca_info_t.is_crl_issuer - */ -static bool is_cert_issuer(private_ca_info_t *this, const x509_t *cert) -{ - return cert->is_issuer(cert, this->cacert); -} - -/** - * Implements ca_info_t.is_crl_issuer - */ -static bool is_crl_issuer(private_ca_info_t *this, const crl_t *crl) -{ - return crl->is_issuer(crl, this->cacert); -} - -/** - * Implements ca_info_t.is_ca - */ -static bool is_ca(private_ca_info_t *this) -{ - return this->cacert->is_ca(this->cacert); -} - -/** - * Implements ca_info_t.is_strict - */ -static bool is_strict(private_ca_info_t *this) -{ - bool strict = strict_crl_policy != STRICT_NO; - - if (strict_crl_policy == STRICT_IFURI) - { - pthread_mutex_lock(&(this->mutex)); - strict = this->crluris->get_count(this->crluris) > 0 || - this->ocspuris->get_count(this->ocspuris) > 0; - pthread_mutex_unlock(&(this->mutex)); - } - return strict; -} - -/** - * Implements ca_info_t.has_crl - */ -static bool has_crl(private_ca_info_t *this) -{ - bool found; - - pthread_mutex_lock(&(this->mutex)); - found = this->crl != NULL; - pthread_mutex_unlock(&(this->mutex)); - - return found; -} - -/** - * Implements ca_info_t.has_certinfos - */ -static bool has_certinfos(private_ca_info_t *this) -{ - bool found; - - pthread_mutex_lock(&(this->mutex)); - found = this->certinfos->get_count(this->certinfos) > 0; - pthread_mutex_unlock(&(this->mutex)); - - return found; -} - -/** - * Implements ca_info_t.add_crl - */ -static void add_crl(private_ca_info_t *this, crl_t *crl) -{ - pthread_mutex_lock(&(this->mutex)); - - if (this->crl) - { - if (crl->is_newer(crl, this->crl)) - { - this->crl->destroy(this->crl); - this->crl = crl; - DBG1(" this crl is newer - existing crl replaced"); - } - else - { - crl->destroy(crl); - DBG1(" this crl is not newer - existing crl retained"); - } - } - else - { - this->crl = crl; - DBG2(" crl added"); - } - - pthread_mutex_unlock(&(this->mutex)); -} - -/** - * Implements ca_info_t.list_crl - */ -static void list_crl(private_ca_info_t *this, FILE *out, bool utc) -{ - pthread_mutex_lock(&this->mutex); - this->crl->list(this->crl, out, utc); - pthread_mutex_unlock(&this->mutex); -} - -/** - * Implements ca_info_t.list_certinfos - */ -static void list_certinfos(private_ca_info_t *this, FILE *out, bool utc) -{ - iterator_t *iterator; - certinfo_t *certinfo; - chunk_t authkey; - - pthread_mutex_lock(&this->mutex); - - authkey = this->cacert->get_subjectKeyID(this->cacert); - fprintf(out," authname: '%D'\n", this->cacert->get_subject(this->cacert)); - fprintf(out," authkey: %#B\n", &authkey); - - iterator = this->certinfos->create_iterator(this->certinfos, TRUE); - while (iterator->iterate(iterator, (void**)&certinfo)) - { - time_t nextUpdate, thisUpdate, now; - chunk_t serial; - - now = time(NULL); - nextUpdate = certinfo->get_nextUpdate(certinfo); - thisUpdate = certinfo->get_thisUpdate(certinfo); - serial = certinfo->get_serialNumber(certinfo); - - fprintf(out, "%#T, until %#T, ", &thisUpdate, utc, &nextUpdate, utc); - if (now > nextUpdate) - { - fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate); - } - else - { - fprintf(out, "ok (expires in %#V)\n", &now, &nextUpdate); - } - fprintf(out, " serial: %#B, %N\n", &serial, - cert_status_names, certinfo->get_status(certinfo)); - } - iterator->destroy(iterator); - - pthread_mutex_unlock(&this->mutex); -} - -/** - * Find an exact copy of an identification in a linked list - */ -static identification_t* find_identification(linked_list_t *list, identification_t *id) -{ - identification_t *found_id = NULL, *current_id; - - iterator_t *iterator = list->create_iterator(list, TRUE); - - while (iterator->iterate(iterator, (void**)¤t_id)) - { - if (id->equals(id, current_id)) - { - found_id = current_id; - break; - } - } - iterator->destroy(iterator); - - return found_id; -} - -/** - * Add a unique identification to a linked list - */ -static identification_t *add_identification(linked_list_t *list, identification_t *id) -{ - identification_t *found_id = find_identification(list, id); - - if (found_id) - { - id->destroy(id); - return found_id; - } - else - { - list->insert_last(list, (void*)id); - return id; - } -} - -/** - * Implements ca_info_t.add_crluri - */ -static void add_crluri(private_ca_info_t *this, chunk_t uri) -{ - if (uri.len < 6 || - (strncasecmp(uri.ptr, "http", 4) != 0 && - strncasecmp(uri.ptr, "ldap", 4) != 0 && - strncasecmp(uri.ptr, "file", 4) != 0 && - strncasecmp(uri.ptr, "ftp", 3) != 0)) - { - DBG1(" invalid crl uri '%.*s'", uri.len, uri.ptr); - return; - } - else - { - identification_t *crluri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri); - - pthread_mutex_lock(&(this->mutex)); - add_identification(this->crluris, crluri); - pthread_mutex_unlock(&(this->mutex)); - } -} - -/** - * Implements ca_info_t.add_ocspuri - */ -static void add_ocspuri(private_ca_info_t *this, chunk_t uri) -{ - if (uri.len < 7 || strncasecmp(uri.ptr, "http", 4) != 0) - { - DBG1(" invalid ocsp uri '%.*s'", uri.len, uri.ptr); - return; - } - else - { - identification_t *ocspuri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri); - - pthread_mutex_lock(&(this->mutex)); - add_identification(this->ocspuris, ocspuri); - pthread_mutex_unlock(&(this->mutex)); - } -} - -/** - * Implements ca_info_t.add_info. - */ -void add_info (private_ca_info_t *this, const private_ca_info_t *that) -{ - pthread_mutex_lock(&(this->mutex)); - - if (this->name == NULL && that->name != NULL) - { - this->name = strdup(that->name); - } - - pthread_mutex_unlock(&(this->mutex)); - - { - identification_t *uri; - - iterator_t *iterator = that->crluris->create_iterator(that->crluris, TRUE); - - while (iterator->iterate(iterator, (void**)&uri)) - { - if (uri->get_type(uri) == ID_DER_ASN1_GN_URI) - { - add_crluri(this, uri->get_encoding(uri)); - } - } - iterator->destroy(iterator); - } - - { - identification_t *uri; - - iterator_t *iterator = that->ocspuris->create_iterator(that->ocspuris, TRUE); - - while (iterator->iterate(iterator, (void**)&uri)) - { - if (uri->get_type(uri) == ID_DER_ASN1_GN_URI) - { - add_ocspuri(this, uri->get_encoding(uri)); - } - } - iterator->destroy(iterator); - } -} - -/** - * Implements ca_info_t.get_certificate. - */ -static x509_t* get_certificate(private_ca_info_t* this) -{ - return this->cacert; -} - -/** - * caches a crl by saving it to a given crl directory - */ -void cache_crl(private_ca_info_t* this, const char *crl_dir, crl_t *crl) -{ - char buffer[BUF_LEN]; - char *path; - char *pos = buffer; - int len = BUF_LEN; - int n; - - chunk_t authKeyID = this->cacert->get_subjectKeyID(this->cacert); - chunk_t uri; - - uri.ptr = buffer; - uri.len = 7 + strlen(crl_dir) + 1 + 2*authKeyID.len + 4; - - if (uri.len >= BUF_LEN) - { - DBG1("file uri exceeds buffer length of %d bytes - crl not saved", BUF_LEN); - return; - } - - /* print the file uri prefix */ - n = snprintf(pos, len, "file://"); - pos += n; len -= n; - - /* remember the start of the path string */ - path = pos; - - /* print the default crl directory path */ - n = snprintf(pos, len, "%s/", crl_dir); - pos += n; len -= n; - - /* create and print a unique crl filename derived from the authKeyID */ - while (authKeyID.len-- > 0) - { - n = snprintf(pos, len, "%02x", *authKeyID.ptr++); - pos += n; len -= n; - } - - /* add the file suffix */ - n = snprintf(pos, len, ".crl"); - - if (crl->write_to_file(crl, path, 0022, TRUE)) - { - identification_t *crluri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri); - - add_identification(this->crluris, crluri); - } -} - -/** - * Implements ca_info_t.verify_by_crl. - */ -static cert_status_t verify_by_crl(private_ca_info_t* this, certinfo_t *certinfo, - const char *crl_dir) -{ - rsa_public_key_t *issuer_public_key = this->cacert->get_public_key(this->cacert); - bool stale; - - pthread_mutex_lock(&(this->mutex)); - if (this->crl == NULL) - { - stale = TRUE; - DBG1("no crl is locally available"); - } - else - { - stale = !this->crl->is_valid(this->crl); - DBG1("crl is %s", stale? "stale":"valid"); - } - - if (stale && crl_check_interval > 0) - { - iterator_t *iterator = this->crluris->create_iterator(this->crluris, TRUE); - identification_t *uri; - - while (iterator->iterate(iterator, (void**)&uri)) - { - fetcher_t *fetcher; - char uri_string[BUF_LEN]; - chunk_t uri_chunk = uri->get_encoding(uri); - chunk_t response_chunk; - - snprintf(uri_string, BUF_LEN, "%.*s", uri_chunk.len, uri_chunk.ptr); - fetcher = fetcher_create(uri_string); - - response_chunk = fetcher->get(fetcher); - fetcher->destroy(fetcher); - if (response_chunk.ptr != NULL) - { - crl_t *crl = crl_create_from_chunk(response_chunk); - - if (crl == NULL) - { - free(response_chunk.ptr); - continue; - } - if (!is_crl_issuer(this, crl)) - { - DBG1(" fetched crl has wrong issuer"); - crl->destroy(crl); - continue; - } - if (!crl->verify(crl, issuer_public_key)) - { - DBG1("fetched crl signature is invalid"); - crl->destroy(crl); - continue; - } - DBG2("fetched crl signature is valid"); - - if (this->crl == NULL) - { - this->crl = crl; - } - else if (crl->is_newer(crl, this->crl)) - { - this->crl->destroy(this->crl); - this->crl = crl; - DBG1("this crl is newer - existing crl replaced"); - } - else - { - crl->destroy(crl); - DBG1("this crl is not newer - existing crl retained"); - continue; - } - if (crl->is_valid(crl)) - { - if (cache_crls && strncasecmp(uri_string, "file", 4) != 0) - { - cache_crl(this, crl_dir, crl); - } - /* we found a valid crl and therefore exit the fetch loop */ - break; - } - else - { - DBG1("fetched crl is stale"); - } - } - } - iterator->destroy(iterator); - } - - if (this->crl) - { - if (!this->crl->verify(this->crl, issuer_public_key)) - { - DBG1("crl signature is invalid"); - goto ret; - } - DBG2("crl signature is valid"); - - this->crl->get_status(this->crl, certinfo); - } - -ret: - pthread_mutex_unlock(&(this->mutex)); - return certinfo->get_status(certinfo); -} - -/** - * Implements ca_info_t.verify_by_ocsp. - */ -static cert_status_t verify_by_ocsp(private_ca_info_t* this, - certinfo_t *certinfo, - credential_store_t *credentials) -{ - bool stale; - iterator_t *iterator; - certinfo_t *cached_certinfo = NULL; - int comparison = 1; - - pthread_mutex_lock(&(this->mutex)); - - /* do we support OCSP at all? */ - if (this->ocspuris->get_count(this->ocspuris) == 0) - { - goto ret; - } - - iterator = this->certinfos->create_iterator(this->certinfos, TRUE); - - /* find the list insertion point in alphabetical order */ - while(iterator->iterate(iterator, (void**)&cached_certinfo)) - { - comparison = certinfo->compare_serialNumber(certinfo, cached_certinfo); - - if (comparison <= 0) - { - break; - } - } - - /* do we have a valid certinfo_t for this serial number in our cache? */ - if (comparison == 0) - { - stale = cached_certinfo->get_nextUpdate(cached_certinfo) < time(NULL); - DBG1("ocsp status in cache is %s", stale ? "stale":"fresh"); - } - else - { - stale = TRUE; - DBG1("ocsp status is not in cache"); - } - - if (stale) - { - ocsp_t *ocsp; - - ocsp = ocsp_create(this->cacert, this->ocspuris); - ocsp->fetch(ocsp, certinfo, credentials); - if (certinfo->get_status(certinfo) != CERT_UNDEFINED) - { - if (comparison != 0) - { - cached_certinfo = certinfo_create(certinfo->get_serialNumber(certinfo)); - - if (comparison > 0) - { - this->certinfos->insert_last(this->certinfos, (void *)cached_certinfo); - } - else - { - iterator->insert_before(iterator, (void *)cached_certinfo); - } - } - cached_certinfo->update(cached_certinfo, certinfo); - } - ocsp->destroy(ocsp); - } - else - { - certinfo->update(certinfo, cached_certinfo); - } - - iterator->destroy(iterator); - -ret: - pthread_mutex_unlock(&(this->mutex)); - return certinfo->get_status(certinfo); -} - -/** - * Implements ca_info_t.purge_ocsp - */ -static void purge_ocsp(private_ca_info_t *this) -{ - pthread_mutex_lock(&(this->mutex)); - - this->certinfos->destroy_offset(this->certinfos, - offsetof(certinfo_t, destroy)); - this->certinfos = linked_list_create(); - - pthread_mutex_unlock(&(this->mutex)); -} - -/** - * Implements ca_info_t.destroy - */ -static void destroy(private_ca_info_t *this) -{ - this->attrcerts->destroy_offset(this->attrcerts, - offsetof(x509ac_t, destroy)); - this->crluris->destroy_offset(this->crluris, - offsetof(identification_t, destroy)); - this->ocspuris->destroy_offset(this->ocspuris, - offsetof(identification_t, destroy)); - this->certinfos->destroy_offset(this->certinfos, - offsetof(certinfo_t, destroy)); - DESTROY_IF(this->crl); - free(this->name); - free(this); -} - -/** - * list the info of this CA - */ -static void list(private_ca_info_t* this, FILE* out, bool utc) -{ - chunk_t chunk; - identification_t *uri; - iterator_t *iterator; - bool first; - - pthread_mutex_lock(&(this->mutex)); - fprintf(out, "%#T", &this->installed, utc); - - if (this->name) - { - fprintf(out, ", \"%s\"\n", this->name); - } - else - { - fprintf(out, "\n"); - } - - fprintf(out, " authname: '%D'\n", this->cacert->get_subject(this->cacert)); - chunk = this->cacert->get_subjectKeyID(this->cacert); - fprintf(out, " authkey: %#B\n", &chunk); - chunk = this->cacert->get_keyid(this->cacert); - fprintf(out, " keyid: %#B\n", &chunk); - - first = TRUE; - iterator = this->crluris->create_iterator(this->crluris, TRUE); - while (iterator->iterate(iterator, (void**)&uri)) - { - fprintf(out, " %s '%D'\n", first ? "crluris:":" ", uri); - first = FALSE; - } - iterator->destroy(iterator); - - first = TRUE; - iterator = this->ocspuris->create_iterator(this->ocspuris, TRUE); - while (iterator->iterate(iterator, (void**)&uri)) - { - fprintf(out, " %s '%D'\n", first ? "ocspuris:":" ", uri); - first = FALSE; - } - iterator->destroy(iterator); - pthread_mutex_unlock(&(this->mutex)); -} - -/* - * Described in header. - */ -void ca_info_set_options(strict_t strict, bool cache, u_int interval) -{ - strict_crl_policy = strict; - cache_crls = cache; - crl_check_interval = interval; -} - -/* - * Described in header. - */ -ca_info_t *ca_info_create(const char *name, x509_t *cacert) -{ - private_ca_info_t *this = malloc_thing(private_ca_info_t); - - /* initialize */ - this->installed = time(NULL); - this->name = (name == NULL)? NULL:strdup(name); - this->cacert = cacert; - this->attrcerts = linked_list_create(); - this->crluris = linked_list_create(); - this->ocspuris = linked_list_create(); - this->certinfos = linked_list_create(); - this->crl = NULL; - - /* initialize the mutex */ - pthread_mutex_init(&(this->mutex), NULL); - - /* public functions */ - this->public.equals = (bool (*) (const ca_info_t*,const ca_info_t*))equals; - this->public.equals_name_release_info = (bool (*) (ca_info_t*,const char*))equals_name_release_info; - this->public.is_cert_issuer = (bool (*) (ca_info_t*,const x509_t*))is_cert_issuer; - this->public.is_crl_issuer = (bool (*) (ca_info_t*,const crl_t*))is_crl_issuer; - this->public.is_ca = (bool (*) (ca_info_t*))is_ca; - this->public.is_strict = (bool (*) (ca_info_t*))is_strict; - this->public.add_info = (void (*) (ca_info_t*,const ca_info_t*))add_info; - this->public.add_crl = (void (*) (ca_info_t*,crl_t*))add_crl; - this->public.has_crl = (bool (*) (ca_info_t*))has_crl; - this->public.has_certinfos = (bool (*) (ca_info_t*))has_certinfos; - this->public.list = (void (*) (ca_info_t*,FILE*,bool))list; - this->public.list_crl = (void (*) (ca_info_t*,FILE*,bool))list_crl; - this->public.list_certinfos = (void (*) (ca_info_t*,FILE*,bool))list_certinfos; - this->public.add_crluri = (void (*) (ca_info_t*,chunk_t))add_crluri; - this->public.add_ocspuri = (void (*) (ca_info_t*,chunk_t))add_ocspuri; - this->public.get_certificate = (x509_t* (*) (ca_info_t*))get_certificate; - this->public.verify_by_crl = (cert_status_t (*) (ca_info_t*,certinfo_t*, const char*))verify_by_crl; - this->public.verify_by_ocsp = (cert_status_t (*) (ca_info_t*,certinfo_t*,credential_store_t*))verify_by_ocsp; - this->public.purge_ocsp = (void (*) (ca_info_t*))purge_ocsp; - this->public.destroy = (void (*) (ca_info_t*))destroy; - - return &this->public; -} |