summaryrefslogtreecommitdiff
path: root/src/pluto/ca.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pluto/ca.c')
-rw-r--r--src/pluto/ca.c712
1 files changed, 0 insertions, 712 deletions
diff --git a/src/pluto/ca.c b/src/pluto/ca.c
deleted file mode 100644
index 827b98121..000000000
--- a/src/pluto/ca.c
+++ /dev/null
@@ -1,712 +0,0 @@
-/* Certification Authority (CA) support for IKE authentication
- * 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.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <debug.h>
-#include <utils/enumerator.h>
-#include <credentials/certificates/x509.h>
-
-#include <freeswan.h>
-
-#include "constants.h"
-#include "defs.h"
-#include "log.h"
-#include "x509.h"
-#include "ca.h"
-#include "certs.h"
-#include "whack.h"
-#include "fetch.h"
-#include "smartcard.h"
-
-/* chained list of X.509 authority certificates (ca, aa, and ocsp) */
-
-static cert_t *x509authcerts = NULL;
-
-/* chained list of X.509 certification authority information records */
-
-static ca_info_t *ca_infos = NULL;
-
-/*
- * Checks if CA a is trusted by CA b
- */
-bool trusted_ca(identification_t *a, identification_t *b, int *pathlen)
-{
- bool match = FALSE;
-
- /* no CA b specified -> any CA a is accepted */
- if (b == NULL)
- {
- *pathlen = (a == NULL) ? 0 : X509_MAX_PATH_LEN;
- return TRUE;
- }
-
- /* no CA a specified -> trust cannot be established */
- if (a == NULL)
- {
- *pathlen = X509_MAX_PATH_LEN;
- return FALSE;
- }
-
- *pathlen = 0;
-
- /* CA a equals CA b -> we have a match */
- if (a->equals(a, b))
- {
- return TRUE;
- }
-
- /* CA a might be a subordinate CA of b */
- lock_authcert_list("trusted_ca");
-
- while ((*pathlen)++ < X509_MAX_PATH_LEN)
- {
- certificate_t *certificate;
- identification_t *issuer;
- cert_t *cacert;
-
- cacert = get_authcert(a, chunk_empty, X509_CA);
- if (cacert == NULL)
- {
- break;
- }
- certificate = cacert->cert;
-
- /* is the certificate self-signed? */
- {
- x509_t *x509 = (x509_t*)certificate;
-
- if (x509->get_flags(x509) & X509_SELF_SIGNED)
- {
- break;
- }
- }
-
- /* does the issuer of CA a match CA b? */
- issuer = certificate->get_issuer(certificate);
- match = b->equals(b, issuer);
-
- /* we have a match and exit the loop */
- if (match)
- {
- break;
- }
- /* go one level up in the CA chain */
- a = issuer;
- }
-
- unlock_authcert_list("trusted_ca");
- return match;
-}
-
-/*
- * does our CA match one of the requested CAs?
- */
-bool match_requested_ca(linked_list_t *requested_ca, identification_t *our_ca,
- int *our_pathlen)
-{
- identification_t *ca;
- enumerator_t *enumerator;
-
- /* if no ca is requested than any ca will match */
- if (requested_ca == NULL || requested_ca->get_count(requested_ca) == 0)
- {
- *our_pathlen = 0;
- return TRUE;
- }
-
- *our_pathlen = X509_MAX_PATH_LEN + 1;
-
- enumerator = requested_ca->create_enumerator(requested_ca);
- while (enumerator->enumerate(enumerator, &ca))
- {
- int pathlen;
-
- if (trusted_ca(our_ca, ca, &pathlen) && pathlen < *our_pathlen)
- {
- *our_pathlen = pathlen;
- }
- }
- enumerator->destroy(enumerator);
-
- if (*our_pathlen > X509_MAX_PATH_LEN)
- {
- *our_pathlen = X509_MAX_PATH_LEN;
- return FALSE;
- }
- else
- {
- return TRUE;
- }
-}
-
-/*
- * free the first authority certificate in the chain
- */
-static void free_first_authcert(void)
-{
- cert_t *first = x509authcerts;
-
- x509authcerts = first->next;
- cert_free(first);
-}
-
-/*
- * free all CA certificates
- */
-void free_authcerts(void)
-{
- lock_authcert_list("free_authcerts");
-
- while (x509authcerts != NULL)
- {
- free_first_authcert();
- }
- unlock_authcert_list("free_authcerts");
-}
-
-/*
- * get a X.509 authority certificate with a given subject or keyid
- */
-cert_t* get_authcert(identification_t *subject, chunk_t keyid,
- x509_flag_t auth_flags)
-{
- cert_t *cert, *prev_cert = NULL;
-
- /* the authority certificate list is empty */
- if (x509authcerts == NULL)
- {
- return NULL;
- }
-
- for (cert = x509authcerts; cert != NULL; prev_cert = cert, cert = cert->next)
- {
- certificate_t *certificate = cert->cert;
- x509_t *x509 = (x509_t*)certificate;
-
- /* skip non-matching types of authority certificates */
- if (!(x509->get_flags(x509) & auth_flags))
- {
- continue;
- }
-
- /* compare the keyid with the certificate's subjectKeyIdentifier */
- if (keyid.ptr)
- {
- chunk_t subjectKeyId;
-
- subjectKeyId = x509->get_subjectKeyIdentifier(x509);
- if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId))
- {
- continue;
- }
- }
-
- /* compare the subjectDistinguishedNames */
- if (!(subject && certificate->has_subject(certificate, subject)) &&
- (subject || !keyid.ptr))
- {
- continue;
- }
-
- /* found the authcert */
- if (cert != x509authcerts)
- {
- /* bring the certificate up front */
- prev_cert->next = cert->next;
- cert->next = x509authcerts;
- x509authcerts = cert;
- }
- return cert;
- }
- return NULL;
-}
-
-/*
- * add an authority certificate to the chained list
- */
-cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags)
-{
- certificate_t *certificate = cert->cert;
- x509_t *x509 = (x509_t*)certificate;
- cert_t *old_cert;
-
- lock_authcert_list("add_authcert");
-
- old_cert = get_authcert(certificate->get_subject(certificate),
- x509->get_subjectKeyIdentifier(x509),
- auth_flags);
- if (old_cert)
- {
- if (certificate->equals(certificate, old_cert->cert))
- {
- DBG(DBG_CONTROL | DBG_PARSING ,
- DBG_log(" authcert is already present and identical")
- )
- unlock_authcert_list("add_authcert");
-
- cert_free(cert);
- return old_cert;
- }
- else
- {
- /* cert is already present but will be replaced by new cert */
- free_first_authcert();
- DBG(DBG_CONTROL | DBG_PARSING ,
- DBG_log(" existing authcert deleted")
- )
- }
- }
-
- /* add new authcert to chained list */
- cert->next = x509authcerts;
- x509authcerts = cert;
- cert_share(cert); /* set count to one */
- DBG(DBG_CONTROL | DBG_PARSING,
- DBG_log(" authcert inserted")
- )
- unlock_authcert_list("add_authcert");
- return cert;
-}
-
-/*
- * Loads authority certificates
- */
-void load_authcerts(char *type, char *path, x509_flag_t auth_flags)
-{
- enumerator_t *enumerator;
- struct stat st;
- char *file;
-
- DBG1(DBG_LIB, "loading %s certificates from '%s'", type, path);
-
- enumerator = enumerator_create_directory(path);
- if (!enumerator)
- {
- DBG1(DBG_LIB, " reading directory '%s' failed", path);
- return;
- }
-
- while (enumerator->enumerate(enumerator, NULL, &file, &st))
- {
- cert_t *cert;
-
- if (!S_ISREG(st.st_mode))
- {
- /* skip special file */
- continue;
- }
- cert = load_cert(file, type, auth_flags);
- if (cert)
- {
- add_authcert(cert, auth_flags);
- }
- }
- enumerator->destroy(enumerator);
-}
-
-/*
- * list all X.509 authcerts with given auth flags in a chained list
- */
-void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc)
-{
- lock_authcert_list("list_authcerts");
- list_x509cert_chain(caption, x509authcerts, auth_flags, utc);
- unlock_authcert_list("list_authcerts");
-}
-
-/*
- * get a cacert with a given subject or keyid from an alternative list
- */
-static const cert_t* get_alt_cacert(identification_t *subject, chunk_t keyid,
- const cert_t *cert)
-{
- if (cert == NULL)
- {
- return NULL;
- }
- for (; cert != NULL; cert = cert->next)
- {
- certificate_t *certificate = cert->cert;
-
- /* compare the keyid with the certificate's subjectKeyIdentifier */
- if (keyid.ptr)
- {
- x509_t *x509 = (x509_t*)certificate;
- chunk_t subjectKeyId;
-
- subjectKeyId = x509->get_subjectKeyIdentifier(x509);
- if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId))
- {
- continue;
- }
- }
-
- /* compare the subjectDistinguishedNames */
- if (!certificate->has_subject(certificate, subject))
- {
- continue;
- }
-
- /* we found the cacert */
- return cert;
- }
- return NULL;
-}
-
-/* establish trust into a candidate authcert by going up the trust chain.
- * validity and revocation status are not checked.
- */
-bool trust_authcert_candidate(const cert_t *cert, const cert_t *alt_chain)
-{
- int pathlen;
-
- lock_authcert_list("trust_authcert_candidate");
-
- for (pathlen = 0; pathlen < X509_MAX_PATH_LEN; pathlen++)
- {
- certificate_t *certificate = cert->cert;
- x509_t *x509 = (x509_t*)certificate;
- identification_t *subject = certificate->get_subject(certificate);
- identification_t *issuer = certificate->get_issuer(certificate);
- chunk_t authKeyID = x509->get_authKeyIdentifier(x509);
- const cert_t *authcert = NULL;
-
- DBG(DBG_CONTROL,
- DBG_log("subject: '%Y'", subject);
- DBG_log("issuer: '%Y'", issuer);
- if (authKeyID.ptr != NULL)
- {
- DBG_log("authkey: %#B", &authKeyID);
- }
- )
-
- /* search in alternative chain first */
- authcert = get_alt_cacert(issuer, authKeyID, alt_chain);
-
- if (authcert != NULL)
- {
- DBG(DBG_CONTROL,
- DBG_log("issuer cacert found in alternative chain")
- )
- }
- else
- {
- /* search in trusted chain */
- authcert = get_authcert(issuer, authKeyID, X509_CA);
-
- if (authcert != NULL)
- {
- DBG(DBG_CONTROL,
- DBG_log("issuer cacert found")
- )
- }
- else
- {
- plog("issuer cacert not found");
- unlock_authcert_list("trust_authcert_candidate");
- return FALSE;
- }
- }
-
- if (!certificate->issued_by(certificate, authcert->cert))
- {
- plog("certificate signature is invalid");
- unlock_authcert_list("trust_authcert_candidate");
- return FALSE;
- }
- DBG(DBG_CONTROL,
- DBG_log("certificate signature is valid")
- )
-
- /* check if cert is a self-signed root ca */
- if (pathlen > 0 && (x509->get_flags(x509) & X509_SELF_SIGNED))
- {
- DBG(DBG_CONTROL,
- DBG_log("reached self-signed root ca")
- )
- unlock_authcert_list("trust_authcert_candidate");
- return TRUE;
- }
-
- /* go up one step in the trust chain */
- cert = authcert;
- }
- plog("maximum ca path length of %d levels exceeded", X509_MAX_PATH_LEN);
- unlock_authcert_list("trust_authcert_candidate");
- return FALSE;
-}
-
-/*
- * get a CA info record with a given authName or authKeyID
- */
-ca_info_t* get_ca_info(identification_t *name, chunk_t keyid)
-{
- ca_info_t *ca= ca_infos;
-
- while (ca != NULL)
- {
- if ((keyid.ptr) ? same_keyid(keyid, ca->authKeyID)
- : name->equals(name, ca->authName))
- {
- return ca;
- }
- ca = ca->next;
- }
- return NULL;
-}
-
-
-/*
- * free the dynamic memory used by a ca_info record
- */
-static void
-free_ca_info(ca_info_t* ca_info)
-{
- if (ca_info == NULL)
- {
- return;
- }
- ca_info->crluris->destroy_function(ca_info->crluris, free);
- DESTROY_IF(ca_info->authName);
- free(ca_info->name);
- free(ca_info->ldaphost);
- free(ca_info->ldapbase);
- free(ca_info->ocspuri);
- free(ca_info->authKeyID.ptr);
- free(ca_info);
-}
-
-/*
- * free all CA certificates
- */
-void free_ca_infos(void)
-{
- while (ca_infos != NULL)
- {
- ca_info_t *ca = ca_infos;
-
- ca_infos = ca_infos->next;
- free_ca_info(ca);
- }
-}
-
-/*
- * find a CA information record by name and optionally delete it
- */
-bool find_ca_info_by_name(const char *name, bool delete)
-{
- ca_info_t **ca_p = &ca_infos;
- ca_info_t *ca = *ca_p;
-
- while (ca != NULL)
- {
- /* is there already an entry? */
- if (streq(name, ca->name))
- {
- if (delete)
- {
- lock_ca_info_list("find_ca_info_by_name");
- *ca_p = ca->next;
- free_ca_info(ca);
- plog("deleting ca description \"%s\"", name);
- unlock_ca_info_list("find_ca_info_by_name");
- }
- return TRUE;
- }
- ca_p = &ca->next;
- ca = *ca_p;
- }
- return FALSE;
-}
-
-/*
- * Create an empty ca_info_t record
- */
-ca_info_t* create_ca_info(void)
-{
- ca_info_t *ca_info = malloc_thing(ca_info_t);
-
- memset(ca_info, 0, sizeof(ca_info_t));
- ca_info->crluris = linked_list_create();
-
- return ca_info;
-}
-
-/**
- * Adds a CA description to a chained list
- */
-void add_ca_info(const whack_message_t *msg)
-{
- smartcard_t *sc = NULL;
- cert_t *cert = NULL;
- bool cached_cert = FALSE;
-
- if (find_ca_info_by_name(msg->name, FALSE))
- {
- loglog(RC_DUPNAME, "attempt to redefine ca record \"%s\"", msg->name);
- return;
- }
-
- if (scx_on_smartcard(msg->cacert))
- {
- /* load CA cert from smartcard */
- cert = scx_load_cert(msg->cacert, &sc, &cached_cert);
- }
- else
- {
- /* load CA cert from file */
- cert = load_ca_cert(msg->cacert);
- }
-
- if (cert)
- {
- certificate_t *certificate = cert->cert;
- x509_t *x509 = (x509_t*)certificate;
- identification_t *subject = certificate->get_subject(certificate);
- chunk_t subjectKeyID = x509->get_subjectKeyIdentifier(x509);
- ca_info_t *ca = NULL;
-
- /* does the authname already exist? */
- ca = get_ca_info(subject, subjectKeyID);
-
- if (ca != NULL)
- {
- /* ca_info is already present */
- loglog(RC_DUPNAME, " duplicate ca information in record \"%s\" found,"
- "ignoring \"%s\"", ca->name, msg->name);
- cert_free(cert);
- return;
- }
-
- plog("added ca description \"%s\"", msg->name);
-
- /* create and initialize new ca_info record */
- ca = create_ca_info();
-
- /* name */
- ca->name = clone_str(msg->name);
-
- /* authName */
- ca->authName = subject->clone(subject);
- DBG(DBG_CONTROL,
- DBG_log("authname: '%Y'", subject)
- )
-
- /* authKeyID */
- if (subjectKeyID.ptr)
- {
- ca->authKeyID = chunk_clone(subjectKeyID);
- DBG(DBG_CONTROL | DBG_PARSING ,
- DBG_log("authkey: %#B", &subjectKeyID)
- )
- }
-
- /* ldaphost */
- ca->ldaphost = clone_str(msg->ldaphost);
-
- /* ldapbase */
- ca->ldapbase = clone_str(msg->ldapbase);
-
- /* ocspuri */
- if (msg->ocspuri != NULL)
- {
- if (strncasecmp(msg->ocspuri, "http", 4) == 0)
- ca->ocspuri = clone_str(msg->ocspuri);
- else
- plog(" ignoring ocspuri with unknown protocol");
- }
-
- /* add crl uris */
- add_distribution_point(ca->crluris, msg->crluri);
- add_distribution_point(ca->crluris, msg->crluri2);
-
- /* strictrlpolicy */
- ca->strictcrlpolicy = msg->whack_strict;
-
- /* insert ca_info record into the chained list */
- lock_ca_info_list("add_ca_info");
-
- ca->next = ca_infos;
- ca_infos = ca;
-
- unlock_ca_info_list("add_ca_info");
-
- /* add cacert to list of authcerts */
- cert = add_authcert(cert, X509_CA);
- if (!cached_cert && sc != NULL)
- {
- if (sc->last_cert != NULL)
- {
- sc->last_cert->count--;
- }
- sc->last_cert = cert;
- cert_share(sc->last_cert);
- }
- if (sc != NULL)
- time(&sc->last_load);
- }
-}
-
-/*
- * list all ca_info records in the chained list
- */
-void list_ca_infos(bool utc)
-{
- ca_info_t *ca = ca_infos;
-
- if (ca != NULL)
- {
- whack_log(RC_COMMENT, " ");
- whack_log(RC_COMMENT, "List of X.509 CA Information Records:");
- }
-
- while (ca != NULL)
- {
- /* strictpolicy per CA not supported yet
- *
- whack_log(RC_COMMENT, "%T, \"%s\", strictcrlpolicy: %s"
- , &ca->installed, utc, ca->name
- , ca->strictcrlpolicy? "yes":"no");
- */
- whack_log(RC_COMMENT, " ");
- whack_log(RC_COMMENT, " authname: \"%Y\"", ca->authName);
- if (ca->ldaphost)
- {
- whack_log(RC_COMMENT, " ldaphost: '%s'", ca->ldaphost);
- }
- if (ca->ldapbase)
- {
- whack_log(RC_COMMENT, " ldapbase: '%s'", ca->ldapbase);
- }
- if (ca->ocspuri)
- {
- whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri);
- }
-
- list_distribution_points(ca->crluris);
-
- if (ca->authKeyID.ptr)
- {
- whack_log(RC_COMMENT, " authkey: %#B", &ca->authKeyID);
- }
- ca = ca->next;
- }
-}
-