summaryrefslogtreecommitdiff
path: root/src/libstrongswan/credentials
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/credentials')
-rw-r--r--src/libstrongswan/credentials/auth_cfg.c830
-rw-r--r--src/libstrongswan/credentials/auth_cfg.h255
-rw-r--r--src/libstrongswan/credentials/builder.c1
-rw-r--r--src/libstrongswan/credentials/builder.h2
-rw-r--r--src/libstrongswan/credentials/cert_validator.h51
-rw-r--r--src/libstrongswan/credentials/certificates/certificate.c22
-rw-r--r--src/libstrongswan/credentials/certificates/certificate.h26
-rw-r--r--src/libstrongswan/credentials/certificates/crl.c28
-rw-r--r--src/libstrongswan/credentials/certificates/crl.h10
-rw-r--r--src/libstrongswan/credentials/certificates/x509.h1
-rw-r--r--src/libstrongswan/credentials/cred_encoding.c (renamed from src/libstrongswan/credentials/keys/key_encoding.c)121
-rw-r--r--src/libstrongswan/credentials/cred_encoding.h224
-rw-r--r--src/libstrongswan/credentials/credential_manager.c1097
-rw-r--r--src/libstrongswan/credentials/credential_manager.h270
-rw-r--r--src/libstrongswan/credentials/credential_set.h108
-rw-r--r--src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c13
-rw-r--r--src/libstrongswan/credentials/keys/key_encoding.h203
-rw-r--r--src/libstrongswan/credentials/keys/private_key.c12
-rw-r--r--src/libstrongswan/credentials/keys/private_key.h9
-rw-r--r--src/libstrongswan/credentials/keys/public_key.c8
-rw-r--r--src/libstrongswan/credentials/keys/public_key.h11
-rw-r--r--src/libstrongswan/credentials/sets/auth_cfg_wrapper.c223
-rw-r--r--src/libstrongswan/credentials/sets/auth_cfg_wrapper.h53
-rw-r--r--src/libstrongswan/credentials/sets/cert_cache.c389
-rw-r--r--src/libstrongswan/credentials/sets/cert_cache.h71
-rw-r--r--src/libstrongswan/credentials/sets/ocsp_response_wrapper.c146
-rw-r--r--src/libstrongswan/credentials/sets/ocsp_response_wrapper.h53
27 files changed, 3940 insertions, 297 deletions
diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c
new file mode 100644
index 000000000..2573d0327
--- /dev/null
+++ b/src/libstrongswan/credentials/auth_cfg.c
@@ -0,0 +1,830 @@
+/*
+ * Copyright (C) 2007-2009 Martin Willi
+ * Copyright (C) 2008 Tobias Brunner
+ * 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 "auth_cfg.h"
+
+#include <library.h>
+#include <debug.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+#include <credentials/certificates/certificate.h>
+
+ENUM(auth_class_names, AUTH_CLASS_ANY, AUTH_CLASS_EAP,
+ "any",
+ "public key",
+ "pre-shared key",
+ "EAP",
+);
+
+ENUM_BEGIN(eap_type_names, EAP_IDENTITY, EAP_GTC,
+ "EAP_IDENTITY",
+ "EAP_NOTIFICATION",
+ "EAP_NAK",
+ "EAP_MD5",
+ "EAP_OTP",
+ "EAP_GTC");
+ENUM_NEXT(eap_type_names, EAP_SIM, EAP_SIM, EAP_GTC,
+ "EAP_SIM");
+ENUM_NEXT(eap_type_names, EAP_AKA, EAP_AKA, EAP_SIM,
+ "EAP_AKA");
+ENUM_NEXT(eap_type_names, EAP_MSCHAPV2, EAP_MSCHAPV2, EAP_AKA,
+ "EAP_MSCHAPV2");
+ENUM_NEXT(eap_type_names, EAP_RADIUS, EAP_EXPERIMENTAL, EAP_MSCHAPV2,
+ "EAP_RADIUS",
+ "EAP_EXPANDED",
+ "EAP_EXPERIMENTAL");
+ENUM_END(eap_type_names, EAP_EXPERIMENTAL);
+
+ENUM_BEGIN(eap_type_short_names, EAP_IDENTITY, EAP_GTC,
+ "ID",
+ "NTF",
+ "NAK",
+ "MD5",
+ "OTP",
+ "GTC");
+ENUM_NEXT(eap_type_short_names, EAP_SIM, EAP_SIM, EAP_GTC,
+ "SIM");
+ENUM_NEXT(eap_type_short_names, EAP_AKA, EAP_AKA, EAP_SIM,
+ "AKA");
+ENUM_NEXT(eap_type_short_names, EAP_MSCHAPV2, EAP_MSCHAPV2, EAP_AKA,
+ "MSCHAPV2");
+ENUM_NEXT(eap_type_short_names, EAP_RADIUS, EAP_EXPERIMENTAL, EAP_MSCHAPV2,
+ "RAD",
+ "EXP",
+ "XP");
+ENUM_END(eap_type_short_names, EAP_EXPERIMENTAL);
+
+ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_SUBJECT_HASH_URL,
+ "RULE_IDENTITY",
+ "RULE_AUTH_CLASS",
+ "RULE_EAP_IDENTITY",
+ "RULE_EAP_TYPE",
+ "RULE_EAP_VENDOR",
+ "RULE_CA_CERT",
+ "RULE_IM_CERT",
+ "RULE_SUBJECT_CERT",
+ "RULE_CRL_VALIDATION",
+ "RULE_OCSP_VALIDATION",
+ "RULE_GROUP",
+ "HELPER_IM_CERT",
+ "HELPER_SUBJECT_CERT",
+ "HELPER_IM_HASH_URL",
+ "HELPER_SUBJECT_HASH_URL",
+);
+
+typedef struct private_auth_cfg_t private_auth_cfg_t;
+
+/**
+ * private data of item_set
+ */
+struct private_auth_cfg_t {
+
+ /**
+ * public functions
+ */
+ auth_cfg_t public;
+
+ /**
+ * list of entry_t
+ */
+ linked_list_t *entries;
+};
+
+typedef struct entry_t entry_t;
+
+struct entry_t {
+ /** rule type */
+ auth_rule_t type;
+ /** associated value */
+ void *value;
+};
+
+/**
+ * enumerator for auth_cfg_t.create_enumerator()
+ */
+typedef struct {
+ /** implements enumerator_t */
+ enumerator_t public;
+ /** inner enumerator from linked_list_t */
+ enumerator_t *inner;
+ /** current entry */
+ entry_t *current;
+} entry_enumerator_t;
+
+/**
+ * enumerate function for item_enumerator_t
+ */
+static bool enumerate(entry_enumerator_t *this, auth_rule_t *type, void **value)
+{
+ entry_t *entry;
+
+ if (this->inner->enumerate(this->inner, &entry))
+ {
+ this->current = entry;
+ *type = entry->type;
+ *value = entry->value;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * destroy function for item_enumerator_t
+ */
+static void entry_enumerator_destroy(entry_enumerator_t *this)
+{
+ this->inner->destroy(this->inner);
+ free(this);
+}
+
+/**
+ * Implementation of auth_cfg_t.create_enumerator.
+ */
+static enumerator_t* create_enumerator(private_auth_cfg_t *this)
+{
+ entry_enumerator_t *enumerator;
+
+ enumerator = malloc_thing(entry_enumerator_t);
+ enumerator->inner = this->entries->create_enumerator(this->entries);
+ enumerator->public.enumerate = (void*)enumerate;
+ enumerator->public.destroy = (void*)entry_enumerator_destroy;
+ enumerator->current = NULL;
+ return &enumerator->public;
+}
+
+/**
+ * Destroy the value associated with an entry
+ */
+static void destroy_entry_value(entry_t *entry)
+{
+ switch (entry->type)
+ {
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_GROUP:
+ {
+ identification_t *id = (identification_t*)entry->value;
+ id->destroy(id);
+ break;
+ }
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ {
+ certificate_t *cert = (certificate_t*)entry->value;
+ cert->destroy(cert);
+ break;
+ }
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ {
+ free(entry->value);
+ break;
+ }
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ break;
+ }
+}
+
+/**
+ * Implementation of auth_cfg_t.replace.
+ */
+static void replace(auth_cfg_t *this, entry_enumerator_t *enumerator,
+ auth_rule_t type, ...)
+{
+ if (enumerator->current)
+ {
+ va_list args;
+
+ va_start(args, type);
+
+ destroy_entry_value(enumerator->current);
+ enumerator->current->type = type;
+ switch (type)
+ {
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ /* integer type */
+ enumerator->current->value = (void*)(uintptr_t)va_arg(args, u_int);
+ break;
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_GROUP:
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ /* pointer type */
+ enumerator->current->value = va_arg(args, void*);
+ break;
+ }
+ va_end(args);
+ }
+}
+
+/**
+ * Implementation of auth_cfg_t.get.
+ */
+static void* get(private_auth_cfg_t *this, auth_rule_t type)
+{
+ enumerator_t *enumerator;
+ void *current_value, *best_value = NULL;
+ auth_rule_t current_type;
+ bool found = FALSE;
+
+ enumerator = create_enumerator(this);
+ while (enumerator->enumerate(enumerator, &current_type, &current_value))
+ {
+ if (type == current_type)
+ {
+ if (type == AUTH_RULE_CRL_VALIDATION ||
+ type == AUTH_RULE_OCSP_VALIDATION)
+ { /* for CRL/OCSP validation, always get() the highest value */
+ if (!found || current_value > best_value)
+ {
+ best_value = current_value;
+ }
+ found = TRUE;
+ continue;
+ }
+ best_value = current_value;
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (found)
+ {
+ return best_value;
+ }
+ switch (type)
+ {
+ /* use some sane defaults if we don't find an entry */
+ case AUTH_RULE_AUTH_CLASS:
+ return (void*)AUTH_CLASS_ANY;
+ case AUTH_RULE_EAP_TYPE:
+ return (void*)EAP_NAK;
+ case AUTH_RULE_EAP_VENDOR:
+ return (void*)0;
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ return (void*)VALIDATION_FAILED;
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_GROUP:
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * Implementation of auth_cfg_t.add.
+ */
+static void add(private_auth_cfg_t *this, auth_rule_t type, ...)
+{
+ entry_t *entry = malloc_thing(entry_t);
+ va_list args;
+
+ va_start(args, type);
+ entry->type = type;
+ switch (type)
+ {
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ /* integer type */
+ entry->value = (void*)(uintptr_t)va_arg(args, u_int);
+ break;
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_GROUP:
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ /* pointer type */
+ entry->value = va_arg(args, void*);
+ break;
+ }
+ va_end(args);
+ this->entries->insert_last(this->entries, entry);
+}
+
+/**
+ * Implementation of auth_cfg_t.complies.
+ */
+static bool complies(private_auth_cfg_t *this, auth_cfg_t *constraints,
+ bool log_error)
+{
+ enumerator_t *e1, *e2;
+ bool success = TRUE, has_group = FALSE, group_match = FALSE;
+ auth_rule_t t1, t2;
+ void *value;
+
+ e1 = constraints->create_enumerator(constraints);
+ while (e1->enumerate(e1, &t1, &value))
+ {
+ switch (t1)
+ {
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ {
+ certificate_t *c1, *c2;
+
+ c1 = (certificate_t*)value;
+
+ success = FALSE;
+ e2 = create_enumerator(this);
+ while (e2->enumerate(e2, &t2, &c2))
+ {
+ if ((t2 == AUTH_RULE_CA_CERT || t2 == AUTH_RULE_IM_CERT) &&
+ c1->equals(c1, c2))
+ {
+ success = TRUE;
+ }
+ }
+ e2->destroy(e2);
+ if (!success && log_error)
+ {
+ DBG1(DBG_CFG, "constraint check failed: peer not "
+ "authenticated by CA '%Y'.", c1->get_subject(c1));
+ }
+ break;
+ }
+ case AUTH_RULE_SUBJECT_CERT:
+ {
+ certificate_t *c1, *c2;
+
+ c1 = (certificate_t*)value;
+ c2 = get(this, AUTH_RULE_SUBJECT_CERT);
+ if (!c2 || !c1->equals(c1, c2))
+ {
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint check failed: peer not "
+ "authenticated with peer cert '%Y'.",
+ c1->get_subject(c1));
+ }
+ }
+ break;
+ }
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ {
+ cert_validation_t validated, required;
+
+ required = (uintptr_t)value;
+ validated = (uintptr_t)get(this, t1);
+ switch (required)
+ {
+ case VALIDATION_FAILED:
+ /* no constraint */
+ break;
+ case VALIDATION_SKIPPED:
+ if (validated == VALIDATION_SKIPPED)
+ {
+ break;
+ }
+ /* FALL */
+ case VALIDATION_GOOD:
+ if (validated == VALIDATION_GOOD)
+ {
+ break;
+ }
+ /* FALL */
+ default:
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint check failed: %N is %N, "
+ "but requires at least %N", auth_rule_names,
+ t1, cert_validation_names, validated,
+ cert_validation_names, required);
+ }
+ break;
+ }
+ break;
+ }
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ {
+ identification_t *id1, *id2;
+
+ id1 = (identification_t*)value;
+ id2 = get(this, t1);
+ if (!id2 || !id2->matches(id2, id1))
+ {
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint check failed: %sidentity '%Y'"
+ " required ", t1 == AUTH_RULE_IDENTITY ? "" :
+ "EAP ", id1);
+ }
+ }
+ break;
+ }
+ case AUTH_RULE_AUTH_CLASS:
+ {
+ if ((uintptr_t)value != AUTH_CLASS_ANY &&
+ (uintptr_t)value != (uintptr_t)get(this, t1))
+ {
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint requires %N authentication, "
+ "but %N was used", auth_class_names, (uintptr_t)value,
+ auth_class_names, (uintptr_t)get(this, t1));
+ }
+ }
+ break;
+ }
+ case AUTH_RULE_EAP_TYPE:
+ {
+ if ((uintptr_t)value != (uintptr_t)get(this, t1))
+ {
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint requires %N, "
+ "but %N was used", eap_type_names, (uintptr_t)value,
+ eap_type_names, (uintptr_t)get(this, t1));
+ }
+ }
+ break;
+ }
+ case AUTH_RULE_EAP_VENDOR:
+ {
+ if ((uintptr_t)value != (uintptr_t)get(this, t1))
+ {
+ success = FALSE;
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint requires EAP vendor %d, "
+ "but %d was used", (uintptr_t)value,
+ (uintptr_t)get(this, t1));
+ }
+ }
+ break;
+ }
+ case AUTH_RULE_GROUP:
+ {
+ identification_t *id1, *id2;
+
+ /* for groups, a match of a single group is sufficient */
+ has_group = TRUE;
+ id1 = (identification_t*)value;
+ e2 = create_enumerator(this);
+ while (e2->enumerate(e2, &t2, &id2))
+ {
+ if (t2 == AUTH_RULE_GROUP && id2->matches(id2, id1))
+ {
+ group_match = TRUE;
+ }
+ }
+ e2->destroy(e2);
+ break;
+ }
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ /* skip helpers */
+ continue;
+ }
+ if (!success)
+ {
+ break;
+ }
+ }
+ e1->destroy(e1);
+
+ if (has_group && !group_match)
+ {
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint check failed: group membership required");
+ }
+ return FALSE;
+ }
+ return success;
+}
+
+/**
+ * Implementation of auth_cfg_t.merge.
+ */
+static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy)
+{
+ if (!other)
+ { /* nothing to merge */
+ return;
+ }
+ if (copy)
+ {
+ enumerator_t *enumerator;
+ auth_rule_t type;
+ void *value;
+
+ enumerator = create_enumerator(other);
+ while (enumerator->enumerate(enumerator, &type, &value))
+ {
+ switch (type)
+ {
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ {
+ certificate_t *cert = (certificate_t*)value;
+
+ add(this, type, cert->get_ref(cert));
+ break;
+ }
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ {
+ add(this, type, (uintptr_t)value);
+ break;
+ }
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_GROUP:
+ {
+ identification_t *id = (identification_t*)value;
+
+ add(this, type, id->clone(id));
+ break;
+ }
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ {
+ add(this, type, strdup((char*)value));
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ else
+ {
+ entry_t *entry;
+
+ while (other->entries->remove_first(other->entries,
+ (void**)&entry) == SUCCESS)
+ {
+ this->entries->insert_last(this->entries, entry);
+ }
+ }
+}
+
+/**
+ * Implementation of auth_cfg_t.equals.
+ */
+static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other)
+{
+ enumerator_t *e1, *e2;
+ entry_t *i1, *i2;
+ bool equal = TRUE, found;
+
+ if (this->entries->get_count(this->entries) !=
+ other->entries->get_count(other->entries))
+ {
+ return FALSE;
+ }
+ e1 = this->entries->create_enumerator(this->entries);
+ while (e1->enumerate(e1, &i1))
+ {
+ found = FALSE;
+ e2 = other->entries->create_enumerator(other->entries);
+ while (e2->enumerate(e2, &i2))
+ {
+ if (i1->type == i2->type)
+ {
+ switch (i1->type)
+ {
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ {
+ if (i1->value == i2->value)
+ {
+ found = TRUE;
+ break;
+ }
+ continue;
+ }
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ {
+ certificate_t *c1, *c2;
+
+ c1 = (certificate_t*)i1->value;
+ c2 = (certificate_t*)i2->value;
+
+ if (c1->equals(c1, c2))
+ {
+ found = TRUE;
+ break;
+ }
+ continue;
+ }
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_GROUP:
+ {
+ identification_t *id1, *id2;
+
+ id1 = (identification_t*)i1->value;
+ id2 = (identification_t*)i2->value;
+
+ if (id1->equals(id1, id2))
+ {
+ found = TRUE;
+ break;
+ }
+ continue;
+ }
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ {
+ if (streq(i1->value, i2->value))
+ {
+ found = TRUE;
+ break;
+ }
+ continue;
+ }
+ }
+ break;
+ }
+ }
+ e2->destroy(e2);
+ if (!found)
+ {
+ equal = FALSE;
+ break;
+ }
+ }
+ e1->destroy(e1);
+ return equal;
+}
+
+/**
+ * Implementation of auth_cfg_t.purge
+ */
+static void purge(private_auth_cfg_t *this, bool keep_ca)
+{
+ entry_t *entry;
+ linked_list_t *cas;
+
+ cas = linked_list_create();
+ while (this->entries->remove_last(this->entries, (void**)&entry) == SUCCESS)
+ {
+ if (keep_ca && entry->type == AUTH_RULE_CA_CERT)
+ {
+ cas->insert_first(cas, entry);
+ }
+ else
+ {
+ destroy_entry_value(entry);
+ free(entry);
+ }
+ }
+ while (cas->remove_last(cas, (void**)&entry) == SUCCESS)
+ {
+ this->entries->insert_first(this->entries, entry);
+ }
+ cas->destroy(cas);
+}
+
+/**
+ * Implementation of auth_cfg_t.clone
+ */
+static auth_cfg_t* clone_(private_auth_cfg_t *this)
+{
+ enumerator_t *enumerator;
+ auth_cfg_t *clone;
+ entry_t *entry;
+
+ clone = auth_cfg_create();
+ enumerator = this->entries->create_enumerator(this->entries);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ switch (entry->type)
+ {
+ case AUTH_RULE_IDENTITY:
+ case AUTH_RULE_EAP_IDENTITY:
+ case AUTH_RULE_GROUP:
+ {
+ identification_t *id = (identification_t*)entry->value;
+ clone->add(clone, entry->type, id->clone(id));
+ break;
+ }
+ case AUTH_RULE_CA_CERT:
+ case AUTH_RULE_IM_CERT:
+ case AUTH_RULE_SUBJECT_CERT:
+ case AUTH_HELPER_IM_CERT:
+ case AUTH_HELPER_SUBJECT_CERT:
+ {
+ certificate_t *cert = (certificate_t*)entry->value;
+ clone->add(clone, entry->type, cert->get_ref(cert));
+ break;
+ }
+ case AUTH_HELPER_IM_HASH_URL:
+ case AUTH_HELPER_SUBJECT_HASH_URL:
+ {
+ clone->add(clone, entry->type, strdup(entry->value));
+ break;
+ }
+ case AUTH_RULE_AUTH_CLASS:
+ case AUTH_RULE_EAP_TYPE:
+ case AUTH_RULE_EAP_VENDOR:
+ case AUTH_RULE_CRL_VALIDATION:
+ case AUTH_RULE_OCSP_VALIDATION:
+ clone->add(clone, entry->type, (uintptr_t)entry->value);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return clone;
+}
+
+/**
+ * Implementation of auth_cfg_t.destroy
+ */
+static void destroy(private_auth_cfg_t *this)
+{
+ purge(this, FALSE);
+ this->entries->destroy(this->entries);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+auth_cfg_t *auth_cfg_create()
+{
+ private_auth_cfg_t *this = malloc_thing(private_auth_cfg_t);
+
+ this->public.add = (void(*)(auth_cfg_t*, auth_rule_t type, ...))add;
+ this->public.get = (void*(*)(auth_cfg_t*, auth_rule_t type))get;
+ this->public.create_enumerator = (enumerator_t*(*)(auth_cfg_t*))create_enumerator;
+ this->public.replace = (void(*)(auth_cfg_t*,enumerator_t*,auth_rule_t,...))replace;
+ this->public.complies = (bool(*)(auth_cfg_t*, auth_cfg_t *,bool))complies;
+ this->public.merge = (void(*)(auth_cfg_t*, auth_cfg_t *other,bool))merge;
+ this->public.purge = (void(*)(auth_cfg_t*,bool))purge;
+ this->public.equals = (bool(*)(auth_cfg_t*, auth_cfg_t *other))equals;
+ this->public.clone = (auth_cfg_t*(*)(auth_cfg_t*))clone_;
+ this->public.destroy = (void(*)(auth_cfg_t*))destroy;
+
+ this->entries = linked_list_create();
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h
new file mode 100644
index 000000000..713e16372
--- /dev/null
+++ b/src/libstrongswan/credentials/auth_cfg.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2007-2009 Martin Willi
+ * Copyright (C) 2008 Tobias Brunner
+ * 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.
+ */
+
+/**
+ * @defgroup auth_cfg auth_cfg
+ * @{ @ingroup credentials
+ */
+
+#ifndef AUTH_CFG_H_
+#define AUTH_CFG_H_
+
+#include <utils/enumerator.h>
+
+typedef struct auth_cfg_t auth_cfg_t;
+typedef enum auth_rule_t auth_rule_t;
+typedef enum auth_class_t auth_class_t;
+typedef enum eap_type_t eap_type_t;
+
+/**
+ * Class of authentication to use. This is different to auth_method_t in that
+ * it does not specify a method, but a class of acceptable methods. The found
+ * certificate finally dictates wich method is used.
+ */
+enum auth_class_t {
+ /** any class acceptable */
+ AUTH_CLASS_ANY = 0,
+ /** authentication using public keys (RSA, ECDSA) */
+ AUTH_CLASS_PUBKEY = 1,
+ /** authentication using a pre-shared secrets */
+ AUTH_CLASS_PSK = 2,
+ /** authentication using EAP */
+ AUTH_CLASS_EAP = 3,
+};
+
+/**
+ * enum strings for auth_class_t
+ */
+extern enum_name_t *auth_class_names;
+
+/**
+ * EAP types, defines the EAP method implementation
+ */
+enum eap_type_t {
+ EAP_IDENTITY = 1,
+ EAP_NOTIFICATION = 2,
+ EAP_NAK = 3,
+ EAP_MD5 = 4,
+ EAP_OTP = 5,
+ EAP_GTC = 6,
+ EAP_SIM = 18,
+ EAP_AKA = 23,
+ EAP_MSCHAPV2 = 26,
+ /** not a method, but an implementation providing different methods */
+ EAP_RADIUS = 253,
+ EAP_EXPANDED = 254,
+ EAP_EXPERIMENTAL = 255,
+};
+
+/**
+ * enum names for eap_type_t.
+ */
+extern enum_name_t *eap_type_names;
+
+/**
+ * short string enum names for eap_type_t.
+ */
+extern enum_name_t *eap_type_short_names;
+
+/**
+ * Authentication config to use during authentication process.
+ *
+ * Each authentication config contains a set of rules. These rule-sets are used
+ * in two ways:
+ * - For configs specifying local authentication behavior, the rules define
+ * which authentication method in which way.
+ * - For configs specifying remote peer authentication, the rules define
+ * constraints the peer has to fullfill.
+ *
+ * Additionally to the rules, there is a set of helper items. These are used
+ * to transport credentials during the authentication process.
+ */
+enum auth_rule_t {
+
+ /** identity to use for IKEv2 authentication exchange, identification_t* */
+ AUTH_RULE_IDENTITY,
+ /** authentication class, auth_class_t */
+ AUTH_RULE_AUTH_CLASS,
+ /** EAP identity to use within EAP-Identity exchange, identification_t* */
+ AUTH_RULE_EAP_IDENTITY,
+ /** EAP type to propose for peer authentication, eap_type_t */
+ AUTH_RULE_EAP_TYPE,
+ /** EAP vendor for vendor specific type, u_int32_t */
+ AUTH_RULE_EAP_VENDOR,
+ /** certificate authority, certificate_t* */
+ AUTH_RULE_CA_CERT,
+ /** intermediate certificate in trustchain, certificate_t* */
+ AUTH_RULE_IM_CERT,
+ /** subject certificate, certificate_t* */
+ AUTH_RULE_SUBJECT_CERT,
+ /** result of a CRL validation, cert_validation_t */
+ AUTH_RULE_CRL_VALIDATION,
+ /** result of a OCSP validation, cert_validation_t */
+ AUTH_RULE_OCSP_VALIDATION,
+ /** subject is member of a group, identification_t*
+ * The group membership constraint is fulfilled if the subject is member of
+ * one group defined in the constraints. */
+ AUTH_RULE_GROUP,
+
+ /** intermediate certificate, certificate_t* */
+ AUTH_HELPER_IM_CERT,
+ /** subject certificate, certificate_t* */
+ AUTH_HELPER_SUBJECT_CERT,
+ /** Hash and URL of a intermediate certificate, char* */
+ AUTH_HELPER_IM_HASH_URL,
+ /** Hash and URL of a end-entity certificate, char* */
+ AUTH_HELPER_SUBJECT_HASH_URL,
+};
+
+/**
+ * enum name for auth_rule_t.
+ */
+extern enum_name_t *auth_rule_names;
+
+/**
+ * Authentication/Authorization round.
+ *
+ * RFC4739 defines multiple authentication rounds. This class defines such
+ * a round from a configuration perspective, either for the local or the remote
+ * peer. Local config are called "rulesets", as they define how we authenticate.
+ * Remote peer configs are called "constraits", they define what is needed to
+ * complete the authentication round successfully.
+ *
+ * @verbatim
+
+ [Repeat for each configuration]
+ +--------------------------------------------------+
+ | |
+ | |
+ | +----------+ IKE_AUTH +--------- + |
+ | | config | -----------> | | |
+ | | ruleset | | | |
+ | +----------+ [ <----------- ] | | |
+ | [ optional EAP ] | Peer | |
+ | +----------+ [ -----------> ] | | |
+ | | config | | | |
+ | | constr. | <----------- | | |
+ | +----------+ IKE_AUTH +--------- + |
+ | |
+ | |
+ +--------------------------------------------------+
+
+ @endverbatim
+ *
+ * Values for each items are either pointers (casted to void*) or short
+ * integers (use uintptr_t cast).
+ */
+struct auth_cfg_t {
+
+ /**
+ * Add an rule to the set.
+ *
+ * @param rule rule type
+ * @param ... associated value to rule
+ */
+ void (*add)(auth_cfg_t *this, auth_rule_t rule, ...);
+
+ /**
+ * Get an rule value.
+ *
+ * @param rule rule type
+ * @return bool if item has been found
+ */
+ void* (*get)(auth_cfg_t *this, auth_rule_t rule);
+
+ /**
+ * Create an enumerator over added rules.
+ *
+ * @return enumerator over (auth_rule_t, union{void*,uintpr_t})
+ */
+ enumerator_t* (*create_enumerator)(auth_cfg_t *this);
+
+ /**
+ * Replace an rule at enumerator position.
+ *
+ * @param pos enumerator position position
+ * @param rule rule type
+ * @param ... associated value to rule
+ */
+ void (*replace)(auth_cfg_t *this, enumerator_t *pos,
+ auth_rule_t rule, ...);
+
+ /**
+ * Check if a used config fulfills a set of configured constraints.
+ *
+ * @param constraints required authorization rules
+ * @param log_error wheter to log compliance errors
+ * @return TRUE if this complies with constraints
+ */
+ bool (*complies)(auth_cfg_t *this, auth_cfg_t *constraints, bool log_error);
+
+ /**
+ * Merge items from other into this.
+ *
+ * @param other items to read for merge
+ * @param copy TRUE to copy items, FALSE to move them
+ */
+ void (*merge)(auth_cfg_t *this, auth_cfg_t *other, bool copy);
+
+ /**
+ * Purge all rules in a config.
+ *
+ * @param keep_ca wheter to keep AUTH_RULE_CA_CERT entries
+ */
+ void (*purge)(auth_cfg_t *this, bool keep_ca);
+
+ /**
+ * Check two configs for equality.
+ *
+ * @param other other config to compaire against this
+ * @return TRUE if auth infos identical
+ */
+ bool (*equals)(auth_cfg_t *this, auth_cfg_t *other);
+
+ /**
+ * Clone a authentication config, including all rules.
+ *
+ * @return cloned configuration
+ */
+ auth_cfg_t* (*clone)(auth_cfg_t *this);
+
+ /**
+ * Destroy a config with all associated rules/values.
+ */
+ void (*destroy)(auth_cfg_t *this);
+};
+
+/**
+ * Create a authentication config.
+ */
+auth_cfg_t *auth_cfg_create();
+
+#endif /** AUTH_CFG_H_ @}*/
diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c
index 8be1c1576..cfb708e33 100644
--- a/src/libstrongswan/credentials/builder.c
+++ b/src/libstrongswan/credentials/builder.c
@@ -44,6 +44,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
"BUILD_OCSP_ACCESS_LOCATIONS",
"BUILD_PATHLEN",
"BUILD_X509_FLAG",
+ "BUILD_REVOKED_ENUMERATOR",
"BUILD_SMARTCARD_KEYID",
"BUILD_SMARTCARD_PIN",
"BUILD_RSA_MODULUS",
diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h
index 62a6ffaaf..ffb09f72a 100644
--- a/src/libstrongswan/credentials/builder.h
+++ b/src/libstrongswan/credentials/builder.h
@@ -101,6 +101,8 @@ enum builder_part_t {
BUILD_PATHLEN,
/** enforce an additional X509 flag, x509_flag_t */
BUILD_X509_FLAG,
+ /** enumerator_t over (chunk_t serial, time_t date, crl_reason_t reason) */
+ BUILD_REVOKED_ENUMERATOR,
/** key ID of a key on a smartcard, null terminated char* ([slot:]keyid) */
BUILD_SMARTCARD_KEYID,
/** pin to access a key on a smartcard, null terminated char* */
diff --git a/src/libstrongswan/credentials/cert_validator.h b/src/libstrongswan/credentials/cert_validator.h
new file mode 100644
index 000000000..1e67c23ab
--- /dev/null
+++ b/src/libstrongswan/credentials/cert_validator.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup cert_validator cert_validator
+ * @{ @ingroup credentials
+ */
+
+#ifndef CERT_VALIDATOR_H_
+#define CERT_VALIDATOR_H_
+
+typedef struct cert_validator_t cert_validator_t;
+
+#include <library.h>
+
+/**
+ * Certificate validator interface.
+ *
+ * A certificate validator checks constraints or revocation in a certificate
+ * or its issuing CA certificate. The interface allows plugins to do
+ * revocation checking or similar tasks.
+ */
+struct cert_validator_t {
+
+ /**
+ * Validate a subject certificate in relation to its issuer.
+ *
+ * @param subject subject certificate to check
+ * @param issuer issuer of subject
+ * @param online wheter to do online revocation checking
+ * @param pathlen the current length of the path up to the root CA
+ * @param auth container for resulting authentication info
+ */
+ bool (*validate)(cert_validator_t *this, certificate_t *subject,
+ certificate_t *issuer, bool online, int pathlen,
+ auth_cfg_t *auth);
+};
+
+#endif /** CERT_VALIDATOR_H_ @}*/
diff --git a/src/libstrongswan/credentials/certificates/certificate.c b/src/libstrongswan/credentials/certificates/certificate.c
index 156d12358..661b69e36 100644
--- a/src/libstrongswan/credentials/certificates/certificate.c
+++ b/src/libstrongswan/credentials/certificates/certificate.c
@@ -15,6 +15,7 @@
#include "certificate.h"
+#include <debug.h>
#include <credentials/certificates/x509.h>
ENUM(certificate_type_names, CERT_ANY, CERT_PLUTO_CRL,
@@ -40,3 +41,24 @@ ENUM(cert_validation_names, VALIDATION_GOOD, VALIDATION_REVOKED,
"REVOKED",
);
+/**
+ * See header
+ */
+bool certificate_is_newer(certificate_t *this, certificate_t *other)
+{
+ time_t this_update, that_update;
+ char *type = "certificate";
+ bool newer;
+
+ if (this->get_type(this) == CERT_X509_CRL)
+ {
+ type = "crl";
+ }
+ this->get_validity(this, NULL, &this_update, NULL);
+ other->get_validity(other, NULL, &that_update, NULL);
+ newer = this_update > that_update;
+ DBG1(DBG_LIB, " %s from %T is %s - existing %s from %T %s",
+ type, &this_update, FALSE, newer ? "newer" : "not newer",
+ type, &that_update, FALSE, newer ? "replaced" : "retained");
+ return newer;
+}
diff --git a/src/libstrongswan/credentials/certificates/certificate.h b/src/libstrongswan/credentials/certificates/certificate.h
index a4f9aa3e0..43bfe3dc1 100644
--- a/src/libstrongswan/credentials/certificates/certificate.h
+++ b/src/libstrongswan/credentials/certificates/certificate.h
@@ -28,6 +28,7 @@ typedef enum cert_validation_t cert_validation_t;
#include <library.h>
#include <utils/identification.h>
#include <credentials/keys/public_key.h>
+#include <credentials/cred_encoding.h>
/**
* Kind of a certificate_t
@@ -163,18 +164,14 @@ struct certificate_t {
time_t *not_before, time_t *not_after);
/**
- * Is this newer than that?
+ * Get the certificate in an encoded form as a chunk.
*
- * @return TRUE if newer, FALSE otherwise
+ * @param type type of the encoding, one of CERT_*
+ * @param encoding encoding of the key, allocated
+ * @return TRUE if encoding supported
*/
- bool (*is_newer)(certificate_t *this, certificate_t *that);
-
- /**
- * Get the certificate in an encoded form.
- *
- * @return allocated chunk of encoded cert
- */
- chunk_t (*get_encoding)(certificate_t *this);
+ bool (*get_encoding)(certificate_t *this, cred_encoding_type_t type,
+ chunk_t *encoding);
/**
* Check if two certificates are equal.
@@ -197,4 +194,13 @@ struct certificate_t {
void (*destroy)(certificate_t *this);
};
+/**
+ * Generic check if a given certificate is newer than another.
+ *
+ * @param this first certificate to check
+ * @param other second certificate
+ * @return TRUE if this newer than other
+ */
+bool certificate_is_newer(certificate_t *this, certificate_t *other);
+
#endif /** CERTIFICATE_H_ @}*/
diff --git a/src/libstrongswan/credentials/certificates/crl.c b/src/libstrongswan/credentials/certificates/crl.c
index 085ad16cc..69bd80b84 100644
--- a/src/libstrongswan/credentials/certificates/crl.c
+++ b/src/libstrongswan/credentials/certificates/crl.c
@@ -16,6 +16,8 @@
#include "crl.h"
+#include <debug.h>
+
ENUM(crl_reason_names, CRL_REASON_UNSPECIFIED, CRL_REASON_REMOVE_FROM_CRL,
"unspecified",
"key compromise",
@@ -27,3 +29,29 @@ ENUM(crl_reason_names, CRL_REASON_UNSPECIFIED, CRL_REASON_REMOVE_FROM_CRL,
"reason #7",
"remove from crl",
);
+
+/**
+ * Check if this CRL is newer
+ */
+bool crl_is_newer(crl_t *this, crl_t *other)
+{
+ chunk_t this_num, other_num;
+ bool newer;
+
+ this_num = this->get_serial(this);
+ other_num = other->get_serial(other);
+
+ /* compare crlNumbers if available - otherwise use generic cert compare */
+ if (this_num.ptr != NULL && other_num.ptr != NULL)
+ {
+ newer = chunk_compare(this_num, other_num) > 0;
+ DBG1(DBG_LIB, " crl #%#B is %s - existing crl #%#B %s",
+ &this_num, newer ? "newer" : "not newer",
+ &other_num, newer ? "replaced" : "retained");
+ }
+ else
+ {
+ newer = certificate_is_newer(&this->certificate, &other->certificate);
+ }
+ return newer;
+}
diff --git a/src/libstrongswan/credentials/certificates/crl.h b/src/libstrongswan/credentials/certificates/crl.h
index 4b612390c..9425311fb 100644
--- a/src/libstrongswan/credentials/certificates/crl.h
+++ b/src/libstrongswan/credentials/certificates/crl.h
@@ -80,7 +80,15 @@ struct crl_t {
* @return enumerator over revoked certificates.
*/
enumerator_t* (*create_enumerator)(crl_t *this);
-
};
+/**
+ * Generic check if a given CRL is newer than another.
+ *
+ * @param this first CRL to check
+ * @param other second CRL
+ * @return TRUE if this newer than other
+ */
+bool crl_is_newer(crl_t *this, crl_t *other);
+
#endif /** CRL_H_ @}*/
diff --git a/src/libstrongswan/credentials/certificates/x509.h b/src/libstrongswan/credentials/certificates/x509.h
index 172bd9696..6e0a5002a 100644
--- a/src/libstrongswan/credentials/certificates/x509.h
+++ b/src/libstrongswan/credentials/certificates/x509.h
@@ -25,7 +25,6 @@
#include <credentials/certificates/certificate.h>
#define X509_NO_PATH_LEN_CONSTRAINT -1
-#define X509_MAX_PATH_LEN 7
typedef struct x509_t x509_t;
typedef enum x509_flag_t x509_flag_t;
diff --git a/src/libstrongswan/credentials/keys/key_encoding.c b/src/libstrongswan/credentials/cred_encoding.c
index 89b25226c..edd76205b 100644
--- a/src/libstrongswan/credentials/keys/key_encoding.c
+++ b/src/libstrongswan/credentials/cred_encoding.c
@@ -13,7 +13,7 @@
* for more details.
*/
-#include "key_encoding.h"
+#include "cred_encoding.h"
#include <stdint.h>
@@ -21,25 +21,25 @@
#include <utils/hashtable.h>
#include <threading/rwlock.h>
-typedef struct private_key_encoding_t private_key_encoding_t;
+typedef struct private_cred_encoding_t private_cred_encoding_t;
/**
- * Private data of an key_encoding_t object.
+ * Private data of an cred_encoding_t object.
*/
-struct private_key_encoding_t {
+struct private_cred_encoding_t {
/**
- * Public key_encoding_t interface.
+ * Public cred_encoding_t interface.
*/
- key_encoding_t public;
+ cred_encoding_t public;
/**
* cached encodings, a table for each encoding_type_t, containing chunk_t*
*/
- hashtable_t *cache[KEY_ENCODING_MAX];
+ hashtable_t *cache[CRED_ENCODING_MAX];
/**
- * Registered encoding fuctions, key_encoder_t
+ * Registered encoding fuctions, cred_encoder_t
*/
linked_list_t *encoders;
@@ -52,7 +52,7 @@ struct private_key_encoding_t {
/**
* See header.
*/
-bool key_encoding_args(va_list args, ...)
+bool cred_encoding_args(va_list args, ...)
{
va_list parts, copy;
bool failed = FALSE;
@@ -61,12 +61,12 @@ bool key_encoding_args(va_list args, ...)
while (!failed)
{
- key_encoding_part_t current, target;
+ cred_encoding_part_t current, target;
chunk_t *out, data;
/* get the part we are looking for */
- target = va_arg(parts, key_encoding_part_t);
- if (target == KEY_PART_END)
+ target = va_arg(parts, cred_encoding_part_t);
+ if (target == CRED_PART_END)
{
break;
}
@@ -75,8 +75,8 @@ bool key_encoding_args(va_list args, ...)
va_copy(copy, args);
while (!failed)
{
- current = va_arg(copy, key_encoding_part_t);
- if (current == KEY_PART_END)
+ current = va_arg(copy, cred_encoding_part_t);
+ if (current == CRED_PART_END)
{
failed = TRUE;
break;
@@ -111,14 +111,14 @@ static bool equals(void *key1, void *key2)
}
/**
- * Implementation of key_encoding_t.get_cache
+ * Implementation of cred_encoding_t.get_cache
*/
-static bool get_cache(private_key_encoding_t *this, key_encoding_type_t type,
+static bool get_cache(private_cred_encoding_t *this, cred_encoding_type_t type,
void *cache, chunk_t *encoding)
{
chunk_t *chunk;
- if (type >= KEY_ENCODING_MAX || type < 0)
+ if (type >= CRED_ENCODING_MAX || type < 0)
{
return FALSE;
}
@@ -133,18 +133,18 @@ static bool get_cache(private_key_encoding_t *this, key_encoding_type_t type,
}
/**
- * Implementation of key_encoding_t.encode
+ * Implementation of cred_encoding_t.encode
*/
-static bool encode(private_key_encoding_t *this, key_encoding_type_t type,
+static bool encode(private_cred_encoding_t *this, cred_encoding_type_t type,
void *cache, chunk_t *encoding, ...)
{
enumerator_t *enumerator;
va_list args, copy;
- key_encoder_t encode;
+ cred_encoder_t encode;
bool success = FALSE;
chunk_t *chunk;
- if (type >= KEY_ENCODING_MAX || type < 0)
+ if (type >= CRED_ENCODING_MAX || type < 0)
{
return FALSE;
}
@@ -168,32 +168,33 @@ static bool encode(private_key_encoding_t *this, key_encoding_type_t type,
va_end(copy);
if (success)
{
- if (cache)
- {
- chunk = malloc_thing(chunk_t);
- *chunk = *encoding;
- this->lock->unlock(this->lock);
- this->lock->write_lock(this->lock);
- this->cache[type]->put(this->cache[type], cache, chunk);
- }
break;
}
}
enumerator->destroy(enumerator);
- va_end(args);
this->lock->unlock(this->lock);
+ va_end(args);
+
+ if (success && cache)
+ {
+ chunk = malloc_thing(chunk_t);
+ *chunk = *encoding;
+ this->lock->write_lock(this->lock);
+ this->cache[type]->put(this->cache[type], cache, chunk);
+ this->lock->unlock(this->lock);
+ }
return success;
}
/**
- * Implementation of key_encoding_t.cache
+ * Implementation of cred_encoding_t.cache
*/
-static void cache(private_key_encoding_t *this, key_encoding_type_t type,
+static void cache(private_cred_encoding_t *this, cred_encoding_type_t type,
void *cache, chunk_t encoding)
{
chunk_t *chunk;
- if (type >= KEY_ENCODING_MAX || type < 0)
+ if (type >= CRED_ENCODING_MAX || type < 0)
{
return free(encoding.ptr);
}
@@ -211,15 +212,15 @@ static void cache(private_key_encoding_t *this, key_encoding_type_t type,
}
/**
- * Implementation of key_encoding_t.clear_cache
+ * Implementation of cred_encoding_t.clear_cache
*/
-static void clear_cache(private_key_encoding_t *this, void *cache)
+static void clear_cache(private_cred_encoding_t *this, void *cache)
{
- key_encoding_type_t type;
+ cred_encoding_type_t type;
chunk_t *chunk;
this->lock->write_lock(this->lock);
- for (type = 0; type < KEY_ENCODING_MAX; type++)
+ for (type = 0; type < CRED_ENCODING_MAX; type++)
{
chunk = this->cache[type]->remove(this->cache[type], cache);
if (chunk)
@@ -232,9 +233,9 @@ static void clear_cache(private_key_encoding_t *this, void *cache)
}
/**
- * Implementation of key_encoding_t.add_encoder
+ * Implementation of cred_encoding_t.add_encoder
*/
-static void add_encoder(private_key_encoding_t *this, key_encoder_t encoder)
+static void add_encoder(private_cred_encoding_t *this, cred_encoder_t encoder)
{
this->lock->write_lock(this->lock);
this->encoders->insert_last(this->encoders, encoder);
@@ -242,9 +243,9 @@ static void add_encoder(private_key_encoding_t *this, key_encoder_t encoder)
}
/**
- * Implementation of key_encoding_t.remove_encoder
+ * Implementation of cred_encoding_t.remove_encoder
*/
-static void remove_encoder(private_key_encoding_t *this, key_encoder_t encoder)
+static void remove_encoder(private_cred_encoding_t *this, cred_encoder_t encoder)
{
this->lock->write_lock(this->lock);
this->encoders->remove(this->encoders, encoder, NULL);
@@ -252,18 +253,18 @@ static void remove_encoder(private_key_encoding_t *this, key_encoder_t encoder)
}
/**
- * Implementation of key_encoder_t.destroy.
+ * Implementation of cred_encoder_t.destroy.
*/
-static void destroy(private_key_encoding_t *this)
+static void destroy(private_cred_encoding_t *this)
{
- key_encoding_type_t type;
+ cred_encoding_type_t type;
- for (type = 0; type < KEY_ENCODING_MAX; type++)
+ for (type = 0; type < CRED_ENCODING_MAX; type++)
{
- /* We explicitly do not free remaining encodings. All keys should
+ /* We explicitly do not free remaining encodings. All creds should
* have gone now, and they are responsible for cleaning out their
* cache entries. Not flushing here allows the leak detective to
- * complain if a key did not flush cached encodings. */
+ * complain if a credential did not flush cached encodings. */
this->cache[type]->destroy(this->cache[type]);
}
this->encoders->destroy(this->encoders);
@@ -274,20 +275,20 @@ static void destroy(private_key_encoding_t *this)
/**
* See header
*/
-key_encoding_t *key_encoding_create()
+cred_encoding_t *cred_encoding_create()
{
- private_key_encoding_t *this = malloc_thing(private_key_encoding_t);
- key_encoding_type_t type;
-
- this->public.encode = (bool(*)(key_encoding_t*, key_encoding_type_t type, void *cache, chunk_t *encoding, ...))encode;
- this->public.get_cache = (bool(*)(key_encoding_t*, key_encoding_type_t type, void *cache, chunk_t *encoding))get_cache;
- this->public.cache = (void(*)(key_encoding_t*, key_encoding_type_t type, void *cache, chunk_t encoding))cache;
- this->public.clear_cache = (void(*)(key_encoding_t*, void *cache))clear_cache;
- this->public.add_encoder = (void(*)(key_encoding_t*, key_encoder_t encoder))add_encoder;
- this->public.remove_encoder = (void(*)(key_encoding_t*, key_encoder_t encoder))remove_encoder;
- this->public.destroy = (void(*)(key_encoding_t*))destroy;
-
- for (type = 0; type < KEY_ENCODING_MAX; type++)
+ private_cred_encoding_t *this = malloc_thing(private_cred_encoding_t);
+ cred_encoding_type_t type;
+
+ this->public.encode = (bool(*)(cred_encoding_t*, cred_encoding_type_t type, void *cache, chunk_t *encoding, ...))encode;
+ this->public.get_cache = (bool(*)(cred_encoding_t*, cred_encoding_type_t type, void *cache, chunk_t *encoding))get_cache;
+ this->public.cache = (void(*)(cred_encoding_t*, cred_encoding_type_t type, void *cache, chunk_t encoding))cache;
+ this->public.clear_cache = (void(*)(cred_encoding_t*, void *cache))clear_cache;
+ this->public.add_encoder = (void(*)(cred_encoding_t*, cred_encoder_t encoder))add_encoder;
+ this->public.remove_encoder = (void(*)(cred_encoding_t*, cred_encoder_t encoder))remove_encoder;
+ this->public.destroy = (void(*)(cred_encoding_t*))destroy;
+
+ for (type = 0; type < CRED_ENCODING_MAX; type++)
{
this->cache[type] = hashtable_create(hash, equals, 8);
}
diff --git a/src/libstrongswan/credentials/cred_encoding.h b/src/libstrongswan/credentials/cred_encoding.h
new file mode 100644
index 000000000..e2d69691e
--- /dev/null
+++ b/src/libstrongswan/credentials/cred_encoding.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * 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.
+ */
+
+/**
+ * @defgroup cred_encoding cred_encoding
+ * @{ @ingroup credentials
+ */
+
+#ifndef CRED_ENCODING_H_
+#define CRED_ENCODING_H_
+
+typedef struct cred_encoding_t cred_encoding_t;
+typedef enum cred_encoding_type_t cred_encoding_type_t;
+typedef enum cred_encoding_part_t cred_encoding_part_t;
+
+#include <library.h>
+
+/**
+ * Credential encoder function implementing encoding/fingerprinting.
+ *
+ * The variable argument list takes cred_encoding_part_t, followed by part
+ * specific arguments, terminated by KEY_PART_END.
+ *
+ * @param type format to encode the credential to
+ * @param args list of (cred_encoding_part_t, data)
+ * @param encoding encoding result, allocated
+ * @return TRUE if encoding successful
+ */
+typedef bool (*cred_encoder_t)(cred_encoding_type_t type, chunk_t *encoding,
+ va_list args);
+
+/**
+ * Helper function for cred_encoder_t implementations to parse argument list.
+ *
+ * Credential encoder functions get a variable argument list to parse. To
+ * simplify the job, this function reads the arguments and returns chunks for
+ * each part.
+ * The argument list of this function takes a cred_encoding_part_t, followed
+ * by a data pointer receiving the value, terminated by CRED_PART_END.
+ *
+ * @param args argument list passed to credential encoder function
+ * @param ... list of (cred_encoding_part_t, data*)
+ * @return TRUE if all parts found, FALSE otherwise
+ */
+bool cred_encoding_args(va_list args, ...);
+
+/**
+ * Encoding type of a fingerprint/credential.
+ *
+ * Fingerprints have have the KEYID_*, public keys the PUBKEY_* and
+ * private keys the PRIVKEY_* prefix.
+ */
+enum cred_encoding_type_t {
+ /** SHA1 fingerprint over subjectPublicKeyInfo */
+ KEYID_PUBKEY_INFO_SHA1 = 0,
+ /** SHA1 fingerprint over subjectPublicKey */
+ KEYID_PUBKEY_SHA1,
+ /** PGPv3 fingerprint */
+ KEYID_PGPV3,
+ /** PGPv4 fingerprint */
+ KEYID_PGPV4,
+
+ KEYID_MAX,
+
+ /** PKCS#1 and similar ASN.1 key encoding */
+ PUBKEY_ASN1_DER,
+ PRIVKEY_ASN1_DER,
+ /** subjectPublicKeyInfo encoding */
+ PUBKEY_SPKI_ASN1_DER,
+ /** PEM encoded PKCS#1 key */
+ PUBKEY_PEM,
+ PRIVKEY_PEM,
+ /** PGP key encoding */
+ PUBKEY_PGP,
+ PRIVKEY_PGP,
+
+ /** ASN.1 DER encoded certificate */
+ CERT_ASN1_DER,
+ /** PEM encoded certificate */
+ CERT_PEM,
+ /** PGP Packet encoded certificate */
+ CERT_PGP_PKT,
+
+ CRED_ENCODING_MAX,
+};
+
+/**
+ * Parts of a credential to encode.
+ */
+enum cred_encoding_part_t {
+ /** modulus of a RSA key, n */
+ CRED_PART_RSA_MODULUS,
+ /** public exponent of a RSA key, e */
+ CRED_PART_RSA_PUB_EXP,
+ /** private exponent of a RSA key, d */
+ CRED_PART_RSA_PRIV_EXP,
+ /** prime1 a RSA key, p */
+ CRED_PART_RSA_PRIME1,
+ /** prime2 a RSA key, q */
+ CRED_PART_RSA_PRIME2,
+ /** exponent1 a RSA key, exp1 */
+ CRED_PART_RSA_EXP1,
+ /** exponent1 a RSA key, exp2 */
+ CRED_PART_RSA_EXP2,
+ /** coefficient of RSA key, coeff */
+ CRED_PART_RSA_COEFF,
+ /** a DER encoded RSA public key */
+ CRED_PART_RSA_PUB_ASN1_DER,
+ /** a DER encoded RSA private key */
+ CRED_PART_RSA_PRIV_ASN1_DER,
+ /** a DER encoded ECDSA public key */
+ CRED_PART_ECDSA_PUB_ASN1_DER,
+ /** a DER encoded ECDSA private key */
+ CRED_PART_ECDSA_PRIV_ASN1_DER,
+ /** a DER encoded X509 certificate */
+ CRED_PART_X509_ASN1_DER,
+ /** a DER encoded X509 CRL */
+ CRED_PART_X509_CRL_ASN1_DER,
+ /** a DER encoded X509 OCSP request */
+ CRED_PART_X509_OCSP_REQ_ASN1_DER,
+ /** a DER encoded X509 OCSP response */
+ CRED_PART_X509_OCSP_RES_ASN1_DER,
+ /** a DER encoded X509 attribute certificate */
+ CRED_PART_X509_AC_ASN1_DER,
+ /** a DER encoded PKCS10 certificate request */
+ CRED_PART_PKCS10_ASN1_DER,
+ /** a PGP encoded certificate */
+ CRED_PART_PGP_CERT,
+
+ CRED_PART_END,
+};
+
+/**
+ * Credential encoding and fingerprinting facility.
+ */
+struct cred_encoding_t {
+
+ /**
+ * Encode a credential in a format using several parts, optional caching.
+ *
+ * The variable argument list takes cred_encoding_part_t, followed by part
+ * specific arguments, terminated by CRED_PART_END.
+ * If a cache key is given, the returned encoding points to internal data:
+ * do not free or modify. If no cache key is given, the encoding is
+ * allocated and must be freed by the caller.
+ *
+ * @param type format the credential should be encoded to
+ * @param cache key to use for caching, NULL to not cache
+ * @param encoding encoding result, allocated if caching disabled
+ * @param ... list of (cred_encoding_part_t, data)
+ * @return TRUE if encoding successful
+ */
+ bool (*encode)(cred_encoding_t *this, cred_encoding_type_t type, void *cache,
+ chunk_t *encoding, ...);
+
+ /**
+ * Clear all cached encodings of a given cache key.
+ *
+ * @param cache key used in encode() for caching
+ */
+ void (*clear_cache)(cred_encoding_t *this, void *cache);
+
+ /**
+ * Check for a cached encoding.
+ *
+ * @param type format of the credential encoding
+ * @param cache key to use for caching, as given to encode()
+ * @param encoding encoding result, internal data
+ * @return TRUE if cache entry found
+ */
+ bool (*get_cache)(cred_encoding_t *this, cred_encoding_type_t type,
+ void *cache, chunk_t *encoding);
+
+ /**
+ * Cache a credential encoding created externally.
+ *
+ * After calling cache(), the passed encoding is owned by the cred encoding
+ * facility.
+ *
+ * @param type format of the credential encoding
+ * @param cache key to use for caching, as given to encode()
+ * @param encoding encoding to cache, gets owned by this
+ */
+ void (*cache)(cred_encoding_t *this, cred_encoding_type_t type, void *cache,
+ chunk_t encoding);
+
+ /**
+ * Register a credential encoder function.
+ *
+ * @param encoder credential encoder function to add
+ */
+ void (*add_encoder)(cred_encoding_t *this, cred_encoder_t encoder);
+
+ /**
+ * Unregister a previously registered credential encoder function.
+ *
+ * @param encoder credential encoder function to remove
+ */
+ void (*remove_encoder)(cred_encoding_t *this, cred_encoder_t encoder);
+
+ /**
+ * Destroy a cred_encoding_t.
+ */
+ void (*destroy)(cred_encoding_t *this);
+};
+
+/**
+ * Create a cred_encoding instance.
+ */
+cred_encoding_t *cred_encoding_create();
+
+#endif /** CRED_ENCODING_H_ @}*/
diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c
new file mode 100644
index 000000000..46c36c941
--- /dev/null
+++ b/src/libstrongswan/credentials/credential_manager.c
@@ -0,0 +1,1097 @@
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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 "credential_manager.h"
+
+#include <library.h>
+#include <debug.h>
+#include <threading/thread_value.h>
+#include <threading/mutex.h>
+#include <threading/rwlock.h>
+#include <utils/linked_list.h>
+#include <credentials/sets/cert_cache.h>
+#include <credentials/sets/auth_cfg_wrapper.h>
+#include <credentials/certificates/x509.h>
+
+/**
+ * Maximum length of a certificate trust chain
+ */
+#define MAX_TRUST_PATH_LEN 7
+
+typedef struct private_credential_manager_t private_credential_manager_t;
+
+/**
+ * private data of credential_manager
+ */
+struct private_credential_manager_t {
+
+ /**
+ * public functions
+ */
+ credential_manager_t public;
+
+ /**
+ * list of credential sets
+ */
+ linked_list_t *sets;
+
+ /**
+ * thread local set of credentials, linked_list_t with credential_set_t's
+ */
+ thread_value_t *local_sets;
+
+ /**
+ * trust relationship and certificate cache
+ */
+ cert_cache_t *cache;
+
+ /**
+ * certificates queued for persistent caching
+ */
+ linked_list_t *cache_queue;
+
+ /**
+ * list of certificate validators, cert_validator_t
+ */
+ linked_list_t *validators;
+
+ /**
+ * read-write lock to sets list
+ */
+ rwlock_t *lock;
+
+ /**
+ * mutex for cache queue
+ */
+ mutex_t *queue_mutex;
+};
+
+/** data to pass to create_private_enumerator */
+typedef struct {
+ private_credential_manager_t *this;
+ key_type_t type;
+ identification_t* keyid;
+} private_data_t;
+
+/** data to pass to create_cert_enumerator */
+typedef struct {
+ private_credential_manager_t *this;
+ certificate_type_t cert;
+ key_type_t key;
+ identification_t *id;
+ bool trusted;
+} cert_data_t;
+
+/** data to pass to create_cdp_enumerator */
+typedef struct {
+ private_credential_manager_t *this;
+ certificate_type_t type;
+ identification_t *id;
+} cdp_data_t;
+
+/** data to pass to create_shared_enumerator */
+typedef struct {
+ private_credential_manager_t *this;
+ shared_key_type_t type;
+ identification_t *me;
+ identification_t *other;
+} shared_data_t;
+
+/** enumerator over local and global sets */
+typedef struct {
+ /** implements enumerator_t */
+ enumerator_t public;
+ /** enumerator over global sets */
+ enumerator_t *global;
+ /** enumerator over local sets */
+ enumerator_t *local;
+} sets_enumerator_t;
+
+
+METHOD(enumerator_t, sets_enumerate, bool,
+ sets_enumerator_t *this, credential_set_t **set)
+{
+ if (this->global)
+ {
+ if (this->global->enumerate(this->global, set))
+ {
+ return TRUE;
+ }
+ /* end of global sets, look for local */
+ this->global->destroy(this->global);
+ this->global = NULL;
+ }
+ if (this->local)
+ {
+ return this->local->enumerate(this->local, set);
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, sets_destroy, void,
+ sets_enumerator_t *this)
+{
+ DESTROY_IF(this->global);
+ DESTROY_IF(this->local);
+ free(this);
+}
+
+/**
+ * create an enumerator over both, global and local sets
+ */
+static enumerator_t *create_sets_enumerator(private_credential_manager_t *this)
+{
+ sets_enumerator_t *enumerator;
+ linked_list_t *local;
+
+ INIT(enumerator,
+ .public.enumerate = (void*)_sets_enumerate,
+ .public.destroy = _sets_destroy,
+ .global = this->sets->create_enumerator(this->sets),
+ );
+ local = this->local_sets->get(this->local_sets);
+ if (local)
+ {
+ enumerator->local = local->create_enumerator(local);
+ }
+ return &enumerator->public;
+}
+
+/**
+ * cleanup function for cert data
+ */
+static void destroy_cert_data(cert_data_t *data)
+{
+ data->this->lock->unlock(data->this->lock);
+ free(data);
+}
+
+/**
+ * enumerator constructor for certificates
+ */
+static enumerator_t *create_cert(credential_set_t *set, cert_data_t *data)
+{
+ return set->create_cert_enumerator(set, data->cert, data->key,
+ data->id, data->trusted);
+}
+
+METHOD(credential_manager_t, create_cert_enumerator, enumerator_t*,
+ private_credential_manager_t *this, certificate_type_t certificate,
+ key_type_t key, identification_t *id, bool trusted)
+{
+ cert_data_t *data = malloc_thing(cert_data_t);
+ data->this = this;
+ data->cert = certificate;
+ data->key = key;
+ data->id = id;
+ data->trusted = trusted;
+
+ this->lock->read_lock(this->lock);
+ return enumerator_create_nested(create_sets_enumerator(this),
+ (void*)create_cert, data,
+ (void*)destroy_cert_data);
+}
+
+METHOD(credential_manager_t, get_cert, certificate_t*,
+ private_credential_manager_t *this, certificate_type_t cert, key_type_t key,
+ identification_t *id, bool trusted)
+{
+ certificate_t *current, *found = NULL;
+ enumerator_t *enumerator;
+
+ enumerator = create_cert_enumerator(this, cert, key, id, trusted);
+ if (enumerator->enumerate(enumerator, &current))
+ {
+ /* TODO: best match? order by keyid, subject, sualtname */
+ found = current->get_ref(current);
+ }
+ enumerator->destroy(enumerator);
+ return found;
+}
+
+
+/**
+ * cleanup function for cdp data
+ */
+static void destroy_cdp_data(cdp_data_t *data)
+{
+ data->this->lock->unlock(data->this->lock);
+ free(data);
+}
+
+/**
+ * enumerator constructor for CDPs
+ */
+static enumerator_t *create_cdp(credential_set_t *set, cdp_data_t *data)
+{
+ return set->create_cdp_enumerator(set, data->type, data->id);
+}
+
+METHOD(credential_manager_t, create_cdp_enumerator, enumerator_t*,
+ private_credential_manager_t *this, certificate_type_t type,
+ identification_t *id)
+{
+ cdp_data_t *data;
+
+ INIT(data,
+ .this = this,
+ .type = type,
+ .id = id,
+ );
+ this->lock->read_lock(this->lock);
+ return enumerator_create_nested(create_sets_enumerator(this),
+ (void*)create_cdp, data,
+ (void*)destroy_cdp_data);
+}
+
+/**
+ * cleanup function for private data
+ */
+static void destroy_private_data(private_data_t *data)
+{
+ data->this->lock->unlock(data->this->lock);
+ free(data);
+}
+
+/**
+ * enumerator constructor for private keys
+ */
+static enumerator_t *create_private(credential_set_t *set, private_data_t *data)
+{
+ return set->create_private_enumerator(set, data->type, data->keyid);
+}
+
+/**
+ * Create an enumerator over private keys
+ */
+static enumerator_t *create_private_enumerator(
+ private_credential_manager_t *this, key_type_t key, identification_t *keyid)
+{
+ private_data_t *data;
+
+ INIT(data,
+ .this = this,
+ .type = key,
+ .keyid = keyid,
+ );
+ this->lock->read_lock(this->lock);
+ return enumerator_create_nested(create_sets_enumerator(this),
+ (void*)create_private, data,
+ (void*)destroy_private_data);
+}
+
+/**
+ * Look up a private key by its key identifier
+ */
+static private_key_t* get_private_by_keyid(private_credential_manager_t *this,
+ key_type_t key, identification_t *keyid)
+{
+ private_key_t *found = NULL;
+ enumerator_t *enumerator;
+
+ enumerator = create_private_enumerator(this, key, keyid);
+ if (enumerator->enumerate(enumerator, &found))
+ {
+ found->get_ref(found);
+ }
+ enumerator->destroy(enumerator);
+ return found;
+}
+
+/**
+ * cleanup function for shared data
+ */
+static void destroy_shared_data(shared_data_t *data)
+{
+ data->this->lock->unlock(data->this->lock);
+ free(data);
+}
+
+/**
+ * enumerator constructor for shared keys
+ */
+static enumerator_t *create_shared(credential_set_t *set, shared_data_t *data)
+{
+ return set->create_shared_enumerator(set, data->type, data->me, data->other);
+}
+
+METHOD(credential_manager_t, create_shared_enumerator, enumerator_t*,
+ private_credential_manager_t *this, shared_key_type_t type,
+ identification_t *me, identification_t *other)
+{
+ shared_data_t *data;
+
+ INIT(data,
+ .this = this,
+ .type = type,
+ .me = me,
+ .other = other,
+ );
+ this->lock->read_lock(this->lock);
+ return enumerator_create_nested(create_sets_enumerator(this),
+ (void*)create_shared, data,
+ (void*)destroy_shared_data);
+}
+
+METHOD(credential_manager_t, get_shared, shared_key_t*,
+ private_credential_manager_t *this, shared_key_type_t type,
+ identification_t *me, identification_t *other)
+{
+ shared_key_t *current, *found = NULL;
+ id_match_t *best_me = ID_MATCH_NONE, *best_other = ID_MATCH_NONE;
+ id_match_t *match_me, *match_other;
+ enumerator_t *enumerator;
+
+ enumerator = create_shared_enumerator(this, type, me, other);
+ while (enumerator->enumerate(enumerator, &current, &match_me, &match_other))
+ {
+ if (match_other > best_other ||
+ (match_other == best_other && match_me > best_me))
+ {
+ DESTROY_IF(found);
+ found = current->get_ref(current);
+ best_me = match_me;
+ best_other = match_other;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found;
+}
+
+METHOD(credential_manager_t, add_local_set, void,
+ private_credential_manager_t *this, credential_set_t *set)
+{
+ linked_list_t *sets;
+
+ sets = this->local_sets->get(this->local_sets);
+ if (!sets)
+ { /* first invocation */
+ sets = linked_list_create();
+ this->local_sets->set(this->local_sets, sets);
+ }
+ sets->insert_last(sets, set);
+}
+
+METHOD(credential_manager_t, remove_local_set, void,
+ private_credential_manager_t *this, credential_set_t *set)
+{
+ linked_list_t *sets;
+
+ sets = this->local_sets->get(this->local_sets);
+ sets->remove(sets, set, NULL);
+}
+
+METHOD(credential_manager_t, cache_cert, void,
+ private_credential_manager_t *this, certificate_t *cert)
+{
+ credential_set_t *set;
+ enumerator_t *enumerator;
+
+ if (this->lock->try_write_lock(this->lock))
+ {
+ enumerator = this->sets->create_enumerator(this->sets);
+ while (enumerator->enumerate(enumerator, &set))
+ {
+ set->cache_cert(set, cert);
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ }
+ else
+ { /* we can't cache now as other threads are active, queue for later */
+ this->queue_mutex->lock(this->queue_mutex);
+ this->cache_queue->insert_last(this->cache_queue, cert->get_ref(cert));
+ this->queue_mutex->unlock(this->queue_mutex);
+ }
+}
+
+/**
+ * Try to cache certificates queued for caching
+ */
+static void cache_queue(private_credential_manager_t *this)
+{
+ credential_set_t *set;
+ certificate_t *cert;
+ enumerator_t *enumerator;
+
+ this->queue_mutex->lock(this->queue_mutex);
+ if (this->cache_queue->get_count(this->cache_queue) > 0 &&
+ this->lock->try_write_lock(this->lock))
+ {
+ while (this->cache_queue->remove_last(this->cache_queue,
+ (void**)&cert) == SUCCESS)
+ {
+ enumerator = this->sets->create_enumerator(this->sets);
+ while (enumerator->enumerate(enumerator, &set))
+ {
+ set->cache_cert(set, cert);
+ }
+ enumerator->destroy(enumerator);
+ cert->destroy(cert);
+ }
+ this->lock->unlock(this->lock);
+ }
+ this->queue_mutex->unlock(this->queue_mutex);
+}
+
+/**
+ * check a certificate for its lifetime
+ */
+static bool check_certificate(private_credential_manager_t *this,
+ certificate_t *subject, certificate_t *issuer,
+ bool online, int pathlen, auth_cfg_t *auth)
+{
+ time_t not_before, not_after;
+ cert_validator_t *validator;
+ enumerator_t *enumerator;
+
+ if (!subject->get_validity(subject, NULL, &not_before, &not_after))
+ {
+ DBG1(DBG_CFG, "subject certificate invalid (valid from %T to %T)",
+ &not_before, FALSE, &not_after, FALSE);
+ return FALSE;
+ }
+ if (!issuer->get_validity(issuer, NULL, &not_before, &not_after))
+ {
+ DBG1(DBG_CFG, "issuer certificate invalid (valid from %T to %T)",
+ &not_before, FALSE, &not_after, FALSE);
+ return FALSE;
+ }
+ if (issuer->get_type(issuer) == CERT_X509 &&
+ subject->get_type(subject) == CERT_X509)
+ {
+ int pathlen_constraint;
+ x509_t *x509;
+
+ /* check path length constraint */
+ x509 = (x509_t*)issuer;
+ pathlen_constraint = x509->get_pathLenConstraint(x509);
+ if (pathlen_constraint != X509_NO_PATH_LEN_CONSTRAINT &&
+ pathlen > pathlen_constraint)
+ {
+ DBG1(DBG_CFG, "path length of %d violates constraint of %d",
+ pathlen, pathlen_constraint);
+ return FALSE;
+ }
+ }
+
+ enumerator = this->validators->create_enumerator(this->validators);
+ while (enumerator->enumerate(enumerator, &validator))
+ {
+ if (!validator->validate(validator, subject, issuer,
+ online, pathlen, auth))
+ {
+ enumerator->destroy(enumerator);
+ return FALSE;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return TRUE;
+}
+
+/**
+ * Get a trusted certificate from a credential set
+ */
+static certificate_t *get_pretrusted_cert(private_credential_manager_t *this,
+ key_type_t type, identification_t *id)
+{
+ certificate_t *subject;
+ public_key_t *public;
+
+ subject = get_cert(this, CERT_ANY, type, id, TRUE);
+ if (!subject)
+ {
+ return NULL;
+ }
+ public = subject->get_public_key(subject);
+ if (!public)
+ {
+ subject->destroy(subject);
+ return NULL;
+ }
+ public->destroy(public);
+ return subject;
+}
+
+/**
+ * Get the issuing certificate of a subject certificate
+ */
+static certificate_t *get_issuer_cert(private_credential_manager_t *this,
+ certificate_t *subject, bool trusted)
+{
+ enumerator_t *enumerator;
+ certificate_t *issuer = NULL, *candidate;
+
+ enumerator = create_cert_enumerator(this, subject->get_type(subject), KEY_ANY,
+ subject->get_issuer(subject), trusted);
+ while (enumerator->enumerate(enumerator, &candidate))
+ {
+ if (this->cache->issued_by(this->cache, subject, candidate))
+ {
+ issuer = candidate->get_ref(candidate);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return issuer;
+}
+
+/**
+ * try to verify the trust chain of subject, return TRUE if trusted
+ */
+static bool verify_trust_chain(private_credential_manager_t *this,
+ certificate_t *subject, auth_cfg_t *result,
+ bool trusted, bool online)
+{
+ certificate_t *current, *issuer;
+ auth_cfg_t *auth;
+ int pathlen;
+
+ auth = auth_cfg_create();
+ current = subject->get_ref(subject);
+
+ for (pathlen = 0; pathlen <= MAX_TRUST_PATH_LEN; pathlen++)
+ {
+ issuer = get_issuer_cert(this, current, TRUE);
+ if (issuer)
+ {
+ /* accept only self-signed CAs as trust anchor */
+ if (this->cache->issued_by(this->cache, issuer, issuer))
+ {
+ auth->add(auth, AUTH_RULE_CA_CERT, issuer->get_ref(issuer));
+ DBG1(DBG_CFG, " using trusted ca certificate \"%Y\"",
+ issuer->get_subject(issuer));
+ trusted = TRUE;
+ }
+ else
+ {
+ auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer));
+ DBG1(DBG_CFG, " using trusted intermediate ca certificate "
+ "\"%Y\"", issuer->get_subject(issuer));
+ }
+ }
+ else
+ {
+ issuer = get_issuer_cert(this, current, FALSE);
+ if (issuer)
+ {
+ if (current->equals(current, issuer))
+ {
+ DBG1(DBG_CFG, " self-signed certificate \"%Y\" is not trusted",
+ current->get_subject(current));
+ issuer->destroy(issuer);
+ break;
+ }
+ auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer));
+ DBG1(DBG_CFG, " using untrusted intermediate certificate "
+ "\"%Y\"", issuer->get_subject(issuer));
+ }
+ else
+ {
+ DBG1(DBG_CFG, "no issuer certificate found for \"%Y\"",
+ current->get_subject(current));
+ break;
+ }
+ }
+ if (!check_certificate(this, current, issuer, online, pathlen,
+ current == subject ? auth : NULL))
+ {
+ trusted = FALSE;
+ issuer->destroy(issuer);
+ break;
+ }
+ current->destroy(current);
+ current = issuer;
+ if (trusted)
+ {
+ DBG1(DBG_CFG, " reached self-signed root ca with a path length of %d",
+ pathlen);
+ break;
+ }
+ }
+ current->destroy(current);
+ if (pathlen > MAX_TRUST_PATH_LEN)
+ {
+ DBG1(DBG_CFG, "maximum path length of %d exceeded", MAX_TRUST_PATH_LEN);
+ }
+ if (trusted)
+ {
+ result->merge(result, auth, FALSE);
+ }
+ auth->destroy(auth);
+ return trusted;
+}
+
+/**
+ * enumerator for trusted certificates
+ */
+typedef struct {
+ /** implements enumerator_t interface */
+ enumerator_t public;
+ /** enumerator over candidate peer certificates */
+ enumerator_t *candidates;
+ /** reference to the credential_manager */
+ private_credential_manager_t *this;
+ /** type of the requested key */
+ key_type_t type;
+ /** identity the requested key belongs to */
+ identification_t *id;
+ /** TRUE to do CRL/OCSP checking */
+ bool online;
+ /** pretrusted certificate we have served at first invocation */
+ certificate_t *pretrusted;
+ /** currently enumerating auth config */
+ auth_cfg_t *auth;
+} trusted_enumerator_t;
+
+METHOD(enumerator_t, trusted_enumerate, bool,
+ trusted_enumerator_t *this, certificate_t **cert, auth_cfg_t **auth)
+{
+ certificate_t *current;
+
+ DESTROY_IF(this->auth);
+ this->auth = auth_cfg_create();
+
+ if (!this->candidates)
+ {
+ /* first invocation, build enumerator for next one */
+ this->candidates = create_cert_enumerator(this->this, CERT_ANY,
+ this->type, this->id, FALSE);
+ /* check if we have a trusted certificate for that peer */
+ this->pretrusted = get_pretrusted_cert(this->this, this->type, this->id);
+ if (this->pretrusted)
+ {
+ /* if we find a trusted self signed certificate, we just accept it.
+ * However, in order to fulfill authorization rules, we try to build
+ * the trust chain if it is not self signed */
+ if (this->this->cache->issued_by(this->this->cache,
+ this->pretrusted, this->pretrusted) ||
+ verify_trust_chain(this->this, this->pretrusted, this->auth,
+ TRUE, this->online))
+ {
+ this->auth->add(this->auth, AUTH_RULE_SUBJECT_CERT,
+ this->pretrusted->get_ref(this->pretrusted));
+ DBG1(DBG_CFG, " using trusted certificate \"%Y\"",
+ this->pretrusted->get_subject(this->pretrusted));
+ *cert = this->pretrusted;
+ if (auth)
+ {
+ *auth = this->auth;
+ }
+ return TRUE;
+ }
+ }
+ }
+ /* try to verify the trust chain for each certificate found */
+ while (this->candidates->enumerate(this->candidates, &current))
+ {
+ if (this->pretrusted &&
+ this->pretrusted->equals(this->pretrusted, current))
+ { /* skip pretrusted certificate we already served */
+ continue;
+ }
+
+ DBG1(DBG_CFG, " using certificate \"%Y\"",
+ current->get_subject(current));
+ if (verify_trust_chain(this->this, current, this->auth, FALSE,
+ this->online))
+ {
+ *cert = current;
+ if (auth)
+ {
+ *auth = this->auth;
+ }
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, trusted_destroy, void,
+ trusted_enumerator_t *this)
+{
+ DESTROY_IF(this->pretrusted);
+ DESTROY_IF(this->auth);
+ DESTROY_IF(this->candidates);
+ free(this);
+}
+
+METHOD(credential_manager_t, create_trusted_enumerator, enumerator_t*,
+ private_credential_manager_t *this, key_type_t type,
+ identification_t *id, bool online)
+{
+ trusted_enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_trusted_enumerate,
+ .destroy = _trusted_destroy,
+ },
+ .this = this,
+ .type = type,
+ .id = id,
+ .online = online,
+ );
+ return &enumerator->public;
+}
+
+/**
+ * enumerator for public keys
+ */
+typedef struct {
+ /** implements enumerator_t interface */
+ enumerator_t public;
+ /** enumerator over candidate peer certificates */
+ enumerator_t *inner;
+ /** reference to the credential_manager */
+ private_credential_manager_t *this;
+ /** currently enumerating key */
+ public_key_t *current;
+ /** credset wrapper around auth config */
+ auth_cfg_wrapper_t *wrapper;
+} public_enumerator_t;
+
+METHOD(enumerator_t, public_enumerate, bool,
+ public_enumerator_t *this, public_key_t **key, auth_cfg_t **auth)
+{
+ certificate_t *cert;
+
+ while (this->inner->enumerate(this->inner, &cert, auth))
+ {
+ DESTROY_IF(this->current);
+ this->current = cert->get_public_key(cert);
+ if (this->current)
+ {
+ *key = this->current;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, public_destroy, void,
+ public_enumerator_t *this)
+{
+ DESTROY_IF(this->current);
+ this->inner->destroy(this->inner);
+ if (this->wrapper)
+ {
+ remove_local_set(this->this, &this->wrapper->set);
+ this->wrapper->destroy(this->wrapper);
+ }
+ this->this->lock->unlock(this->this->lock);
+
+ /* check for delayed certificate cache queue */
+ cache_queue(this->this);
+ free(this);
+}
+
+METHOD(credential_manager_t, create_public_enumerator, enumerator_t*,
+ private_credential_manager_t *this, key_type_t type, identification_t *id,
+ auth_cfg_t *auth)
+{
+ public_enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_public_enumerate,
+ .destroy = _public_destroy,
+ },
+ .inner = create_trusted_enumerator(this, type, id, TRUE),
+ .this = this,
+ );
+ if (auth)
+ {
+ enumerator->wrapper = auth_cfg_wrapper_create(auth);
+ add_local_set(this, &enumerator->wrapper->set);
+ }
+ this->lock->read_lock(this->lock);
+ return &enumerator->public;
+}
+
+/**
+ * Check if a certificate's keyid is contained in the auth helper
+ */
+static bool auth_contains_cacert(auth_cfg_t *auth, certificate_t *cert)
+{
+ enumerator_t *enumerator;
+ identification_t *value;
+ auth_rule_t type;
+ bool found = FALSE;
+
+ enumerator = auth->create_enumerator(auth);
+ while (enumerator->enumerate(enumerator, &type, &value))
+ {
+ if (type == AUTH_RULE_CA_CERT &&
+ cert->equals(cert, (certificate_t*)value))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found;
+}
+
+/**
+ * build a trustchain from subject up to a trust anchor in trusted
+ */
+static auth_cfg_t *build_trustchain(private_credential_manager_t *this,
+ certificate_t *subject, auth_cfg_t *auth)
+{
+ certificate_t *issuer, *current;
+ auth_cfg_t *trustchain;
+ int pathlen = 0;
+
+ trustchain = auth_cfg_create();
+
+ current = auth->get(auth, AUTH_RULE_CA_CERT);
+ if (!current)
+ {
+ /* no trust anchor specified, return this cert only */
+ trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT,
+ subject->get_ref(subject));
+ return trustchain;
+ }
+ current = subject->get_ref(subject);
+ while (TRUE)
+ {
+ if (auth_contains_cacert(auth, current))
+ {
+ trustchain->add(trustchain, AUTH_RULE_CA_CERT, current);
+ return trustchain;
+ }
+ if (subject == current)
+ {
+ trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT, current);
+ }
+ else
+ {
+ trustchain->add(trustchain, AUTH_RULE_IM_CERT, current);
+ }
+ issuer = get_issuer_cert(this, current, FALSE);
+ if (!issuer || issuer->equals(issuer, current) ||
+ pathlen > MAX_TRUST_PATH_LEN)
+ {
+ DESTROY_IF(issuer);
+ break;
+ }
+ current = issuer;
+ pathlen++;
+ }
+ trustchain->destroy(trustchain);
+ return NULL;
+}
+
+/**
+ * find a private key of a give certificate
+ */
+static private_key_t *get_private_by_cert(private_credential_manager_t *this,
+ certificate_t *cert, key_type_t type)
+{
+ private_key_t *private = NULL;
+ identification_t *keyid;
+ chunk_t chunk;
+ public_key_t *public;
+
+ public = cert->get_public_key(cert);
+ if (public)
+ {
+ if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
+ {
+ keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
+ private = get_private_by_keyid(this, type, keyid);
+ keyid->destroy(keyid);
+ }
+ public->destroy(public);
+ }
+ return private;
+}
+
+METHOD(credential_manager_t, get_private, private_key_t*,
+ private_credential_manager_t *this, key_type_t type, identification_t *id,
+ auth_cfg_t *auth)
+{
+ enumerator_t *enumerator;
+ certificate_t *cert;
+ private_key_t *private = NULL;
+ auth_cfg_t *trustchain;
+
+ /* check if this is a lookup by key ID, and do it if so */
+ if (id && id->get_type(id) == ID_KEY_ID)
+ {
+ private = get_private_by_keyid(this, type, id);
+ if (private)
+ {
+ return private;
+ }
+ }
+
+ /* if a specific certificate is preferred, check for a matching key */
+ cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
+ if (cert)
+ {
+ private = get_private_by_cert(this, cert, type);
+ if (private)
+ {
+ trustchain = build_trustchain(this, cert, auth);
+ if (trustchain)
+ {
+ auth->merge(auth, trustchain, FALSE);
+ trustchain->destroy(trustchain);
+ }
+ return private;
+ }
+ }
+
+ /* try to build a trust chain for each certificate found */
+ enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE);
+ while (enumerator->enumerate(enumerator, &cert))
+ {
+ private = get_private_by_cert(this, cert, type);
+ if (private)
+ {
+ trustchain = build_trustchain(this, cert, auth);
+ if (trustchain)
+ {
+ auth->merge(auth, trustchain, FALSE);
+ trustchain->destroy(trustchain);
+ break;
+ }
+ private->destroy(private);
+ private = NULL;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ /* if no valid trustchain was found, fall back to the first usable cert */
+ if (!private)
+ {
+ enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE);
+ while (enumerator->enumerate(enumerator, &cert))
+ {
+ private = get_private_by_cert(this, cert, type);
+ if (private)
+ {
+ auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert));
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ return private;
+}
+
+METHOD(credential_manager_t, flush_cache, void,
+ private_credential_manager_t *this, certificate_type_t type)
+{
+ this->cache->flush(this->cache, type);
+}
+
+METHOD(credential_manager_t, issued_by, bool,
+ private_credential_manager_t *this, certificate_t *subject,
+ certificate_t *issuer)
+{
+ return this->cache->issued_by(this->cache, subject, issuer);
+}
+
+METHOD(credential_manager_t, add_set, void,
+ private_credential_manager_t *this, credential_set_t *set)
+{
+ this->lock->write_lock(this->lock);
+ this->sets->insert_last(this->sets, set);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(credential_manager_t, remove_set, void,
+ private_credential_manager_t *this, credential_set_t *set)
+{
+ this->lock->write_lock(this->lock);
+ this->sets->remove(this->sets, set, NULL);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(credential_manager_t, add_validator, void,
+ private_credential_manager_t *this, cert_validator_t *vdtr)
+{
+ this->lock->write_lock(this->lock);
+ this->sets->insert_last(this->validators, vdtr);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(credential_manager_t, remove_validator, void,
+ private_credential_manager_t *this, cert_validator_t *vdtr)
+{
+ this->lock->write_lock(this->lock);
+ this->validators->remove(this->validators, vdtr, NULL);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(credential_manager_t, destroy, void,
+ private_credential_manager_t *this)
+{
+ cache_queue(this);
+ this->cache_queue->destroy(this->cache_queue);
+ this->sets->remove(this->sets, this->cache, NULL);
+ this->sets->destroy(this->sets);
+ this->local_sets->destroy(this->local_sets);
+ this->cache->destroy(this->cache);
+ this->validators->destroy(this->validators);
+ this->lock->destroy(this->lock);
+ this->queue_mutex->destroy(this->queue_mutex);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+credential_manager_t *credential_manager_create()
+{
+ private_credential_manager_t *this;
+
+ INIT(this,
+ .public = {
+ .create_cert_enumerator = _create_cert_enumerator,
+ .create_shared_enumerator = _create_shared_enumerator,
+ .create_cdp_enumerator = _create_cdp_enumerator,
+ .get_cert = _get_cert,
+ .get_shared = _get_shared,
+ .get_private = _get_private,
+ .create_trusted_enumerator = _create_trusted_enumerator,
+ .create_public_enumerator = _create_public_enumerator,
+ .flush_cache = _flush_cache,
+ .cache_cert = _cache_cert,
+ .issued_by = _issued_by,
+ .add_set = _add_set,
+ .remove_set = _remove_set,
+ .add_local_set = _add_local_set,
+ .remove_local_set = _remove_local_set,
+ .add_validator = _add_validator,
+ .remove_validator = _remove_validator,
+ .destroy = _destroy,
+ },
+ .sets = linked_list_create(),
+ .validators = linked_list_create(),
+ .cache = cert_cache_create(),
+ .cache_queue = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .queue_mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
+
+ this->local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy);
+ this->sets->insert_first(this->sets, this->cache);
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/credentials/credential_manager.h b/src/libstrongswan/credentials/credential_manager.h
new file mode 100644
index 000000000..04269cfbf
--- /dev/null
+++ b/src/libstrongswan/credentials/credential_manager.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2007-2009 Martin Willi
+ * 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.
+ */
+
+/**
+ * @defgroup credential_manager credential_manager
+ * @{ @ingroup credentials
+ */
+
+#ifndef CREDENTIAL_MANAGER_H_
+#define CREDENTIAL_MANAGER_H_
+
+typedef struct credential_manager_t credential_manager_t;
+
+#include <utils/identification.h>
+#include <utils/enumerator.h>
+#include <credentials/auth_cfg.h>
+#include <credentials/credential_set.h>
+#include <credentials/keys/private_key.h>
+#include <credentials/keys/shared_key.h>
+#include <credentials/certificates/certificate.h>
+#include <credentials/cert_validator.h>
+
+/**
+ * Manages credentials using credential_sets.
+ *
+ * The credential manager is the entry point of the credential framework. It
+ * uses so called "sets" to access credentials in a modular fashion, these
+ * are implemented through the credential_set_t interface.
+ * The manager additionally does trust chain verification and trust status
+ * chaching. A set may call the managers methods if it needs credentials itself,
+ * the manager uses recursive locking.
+ *
+ * @verbatim
+
+ +-------+ +----------------+
+ | A | | | +------------------+
+ | u | -----> | | ------> | +------------------+
+ | t | | credential- | | | +------------------+
+ | h | -----> | manager | ------> +--| | credential- | => IPC
+ | e | | | +--| sets |
+ | n | +--> | | ------> +------------------+
+ | t | | | | |
+ | i | | | | |
+ | c | | +----------------+ |
+ | a | | |
+ | t | +----------------------------------------------+
+ | o | may be recursive
+ | r |
+ +-------+
+
+ @endverbatim
+ *
+ * The credential manager uses rwlocks for performance reasons, credential
+ * sets must be fully thread save.
+ */
+struct credential_manager_t {
+
+ /**
+ * Create an enumerator over all certificates.
+ *
+ * @param cert kind of certificate
+ * @param key kind of key in certificate
+ * @param id subject this certificate belongs to
+ * @param trusted TRUE to list trusted certificates only
+ * @return enumerator over the certificates
+ */
+ enumerator_t *(*create_cert_enumerator)(credential_manager_t *this,
+ certificate_type_t cert, key_type_t key,
+ identification_t *id, bool trusted);
+ /**
+ * Create an enumerator over all shared keys.
+ *
+ * The enumerator enumerates over:
+ * shared_key_t*, id_match_t me, id_match_t other
+ * But must accepts values for the id_matches.
+ *
+ * @param type kind of requested shared key
+ * @param first first subject between key is shared
+ * @param second second subject between key is shared
+ * @return enumerator over shared keys
+ */
+ enumerator_t *(*create_shared_enumerator)(credential_manager_t *this,
+ shared_key_type_t type,
+ identification_t *first, identification_t *second);
+ /**
+ * Create an enumerator over all Certificate Distribution Points.
+ *
+ * @param type kind of certificate the point distributes
+ * @param id identification of the distributed certificate
+ * @return enumerator of CDPs as char*
+ */
+ enumerator_t *(*create_cdp_enumerator)(credential_manager_t *this,
+ certificate_type_t type, identification_t *id);
+ /**
+ * Get a trusted or untrusted certificate.
+ *
+ * @param cert kind of certificate
+ * @param key kind of key in certificate
+ * @param id subject this certificate belongs to
+ * @param trusted TRUE to get a trusted certificate only
+ * @return certificate, if found, NULL otherwise
+ */
+ certificate_t *(*get_cert)(credential_manager_t *this,
+ certificate_type_t cert, key_type_t key,
+ identification_t *id, bool trusted);
+ /**
+ * Get the best matching shared key for two IDs.
+ *
+ * @param type kind of requested shared key
+ * @param me own identity
+ * @param other peers identity
+ * @return shared_key_t, NULL if none found
+ */
+ shared_key_t *(*get_shared)(credential_manager_t *this, shared_key_type_t type,
+ identification_t *me, identification_t *other);
+ /**
+ * Get a private key to create a signature.
+ *
+ * The get_private() method gets a secret private key identified by either
+ * the keyid itself or an id the key belongs to.
+ * The auth parameter contains additional information, such as receipients
+ * trusted CA certs. Auth gets filled with subject and CA certificates
+ * needed to validate a created signature.
+ *
+ * @param type type of the key to get
+ * @param id identification the key belongs to
+ * @param auth auth config, including trusted CA certificates
+ * @return private_key_t, NULL if none found
+ */
+ private_key_t* (*get_private)(credential_manager_t *this, key_type_t type,
+ identification_t *id, auth_cfg_t *auth);
+
+ /**
+ * Create an enumerator over trusted certificates.
+ *
+ * This method creates an enumerator over trusted certificates. The auth
+ * parameter (if given) recevies the trustchain used to validate
+ * the certificate. The resulting enumerator enumerates over
+ * certificate_t*, auth_cfg_t*.
+ * If online is set, revocations are checked online for the whole
+ * trustchain.
+ *
+ * @param type type of the key we want a certificate for
+ * @param id subject of the certificate
+ * @param online whether revocations should be checked online
+ * @return enumerator
+ */
+ enumerator_t* (*create_trusted_enumerator)(credential_manager_t *this,
+ key_type_t type, identification_t *id, bool online);
+
+ /**
+ * Create an enumerator over trusted public keys.
+ *
+ * This method gets a an enumerator over trusted public keys to verify a
+ * signature created by id. The auth parameter contains additional
+ * authentication infos, e.g. peer and intermediate certificates.
+ * The resulting enumerator enumerates over public_key_t *, auth_cfg_t *,
+ * where the auth config helper contains rules for constraint checks.
+ * This function is very similar to create_trusted_enumerator(), but
+ * gets public keys directly.
+ *
+ * @param type type of the key to get
+ * @param id owner of the key, signer of the signature
+ * @param auth authentication infos
+ * @return enumerator
+ */
+ enumerator_t* (*create_public_enumerator)(credential_manager_t *this,
+ key_type_t type, identification_t *id, auth_cfg_t *auth);
+
+ /**
+ * Cache a certificate by invoking cache_cert() on all registerd sets.
+ *
+ * @param cert certificate to cache
+ */
+ void (*cache_cert)(credential_manager_t *this, certificate_t *cert);
+
+ /**
+ * Flush the certificate cache.
+ *
+ * Only the managers local cache is flushed, but not the sets cache filled
+ * by the cache_cert() method.
+ *
+ * @param type type of certificate to flush, or CERT_ANY
+ */
+ void (*flush_cache)(credential_manager_t *this, certificate_type_t type);
+
+ /**
+ * Check if a given subject certificate is issued by an issuer certificate.
+ *
+ * This operation does signature verification, but uses the credential
+ * managers cache for to speed up the operation.
+ *
+ * @param subject subject certificate to check
+ * @param issuer issuer certificate that potentially has signed subject
+ * @return TRUE if issuer signed subject
+ */
+ bool (*issued_by)(credential_manager_t *this,
+ certificate_t *subject, certificate_t *issuer);
+
+ /**
+ * Register a credential set to the manager.
+ *
+ * @param set set to register
+ */
+ void (*add_set)(credential_manager_t *this, credential_set_t *set);
+
+ /**
+ * Unregister a credential set from the manager.
+ *
+ * @param set set to unregister
+ */
+ void (*remove_set)(credential_manager_t *this, credential_set_t *set);
+
+ /**
+ * Register a thread local credential set to the manager.
+ *
+ * To add a credential set for the current trustchain verification
+ * operation, sets may be added for the calling thread only. This
+ * does not require a write lock and is therefore a much less expensive
+ * operation.
+ *
+ * @param set set to register
+ */
+ void (*add_local_set)(credential_manager_t *this, credential_set_t *set);
+
+ /**
+ * Unregister a thread local credential set from the manager.
+ *
+ * @param set set to unregister
+ */
+ void (*remove_local_set)(credential_manager_t *this, credential_set_t *set);
+
+ /**
+ * Register a certificate validator to the manager.
+ *
+ * @param vdtr validator to register
+ */
+ void (*add_validator)(credential_manager_t *this, cert_validator_t *vdtr);
+
+ /**
+ * Remove a certificate validator from the manager.
+ *
+ * @param vdtr validator to unregister
+ */
+ void (*remove_validator)(credential_manager_t *this, cert_validator_t *vdtr);
+
+ /**
+ * Destroy a credential_manager instance.
+ */
+ void (*destroy)(credential_manager_t *this);
+};
+
+/**
+ * Create a credential_manager instance.
+ */
+credential_manager_t *credential_manager_create();
+
+#endif /** CREDENTIAL_MANAGER_H_ @}*/
diff --git a/src/libstrongswan/credentials/credential_set.h b/src/libstrongswan/credentials/credential_set.h
new file mode 100644
index 000000000..0eee237cb
--- /dev/null
+++ b/src/libstrongswan/credentials/credential_set.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2007 Martin Willi
+ * 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.
+ */
+
+/**
+ * @defgroup credential_set credential_set
+ * @{ @ingroup credentials
+ */
+
+#ifndef CREDENTIAL_SET_H_
+#define CREDENTIAL_SET_H_
+
+typedef struct credential_set_t credential_set_t;
+
+#include <credentials/keys/public_key.h>
+#include <credentials/keys/shared_key.h>
+#include <credentials/certificates/certificate.h>
+
+/**
+ * A set of credentials.
+ *
+ * Contains private keys, shared keys and different kinds of certificates.
+ * Enumerators are used because queries might return multiple matches.
+ * Filter parameters restrict enumeration over specific items only.
+ * See credential_manager_t for an overview of the credential framework.
+ *
+ * A credential set enumerator may not block the credential set, i.e. multiple
+ * threads must be able to hold multiple enumerators, as the credential manager
+ * is higly parallelized. The best way to achieve this is by using shared
+ * read locks for the enumerators only. Otherwiese deadlocks will occur.
+ * The writing cache_cert() routine is called by the manager only if no
+ * enumerator is alive, so it is save to use a write lock there.
+ */
+struct credential_set_t {
+
+ /**
+ * Create an enumerator over private keys (private_key_t).
+ *
+ * The id is either a key identifier of the requested key, or an identity
+ * of the key owner.
+ *
+ * @param type type of requested private key
+ * @param id key identifier/owner
+ * @return enumerator over private_key_t's.
+ */
+ enumerator_t *(*create_private_enumerator)(credential_set_t *this,
+ key_type_t type, identification_t *id);
+ /**
+ * Create an enumerator over certificates (certificate_t).
+ *
+ * @param cert kind of certificate
+ * @param key kind of key in certificate
+ * @param id identity (subject) this certificate belongs to
+ * @param trusted whether the certificate must be trustworthy
+ * @return enumerator as described above
+ */
+ enumerator_t *(*create_cert_enumerator)(credential_set_t *this,
+ certificate_type_t cert, key_type_t key,
+ identification_t *id, bool trusted);
+ /**
+ * Create an enumerator over shared keys (shared_key_t).
+ *
+ * The enumerator enumerates over:
+ * shared_key_t*, id_match_t me, id_match_t other
+ * But must accept NULL values for the id_matches.
+ *
+ * @param type kind of requested shared key
+ * @param me own identity
+ * @param other other identity who owns that secret
+ * @return enumerator as described above
+ */
+ enumerator_t *(*create_shared_enumerator)(credential_set_t *this,
+ shared_key_type_t type,
+ identification_t *me, identification_t *other);
+
+ /**
+ * Create an enumerator over certificate distribution points.
+ *
+ * @param type type of the certificate to get a CDP
+ * @param id identification of the distributed certificate
+ * @return an enumerator over CDPs as char*
+ */
+ enumerator_t *(*create_cdp_enumerator)(credential_set_t *this,
+ certificate_type_t type, identification_t *id);
+
+ /**
+ * Cache a certificate in the credential set.
+ *
+ * The caching policy is implementation dependent, the sets may cache the
+ * certificate in-memory, persistent on disk or not at all.
+ *
+ * @param cert certificate to cache
+ */
+ void (*cache_cert)(credential_set_t *this, certificate_t *cert);
+};
+
+#endif /** CREDENTIAL_SET_H_ @}*/
diff --git a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
index ff3ddeb6f..de5b85bae 100644
--- a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
+++ b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c
@@ -159,7 +159,7 @@ static char* get_string(private_ietf_attributes_t *this)
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &attr))
{
- int written = 0;
+ int written;
if (first)
{
@@ -168,8 +168,12 @@ static char* get_string(private_ietf_attributes_t *this)
else
{
written = snprintf(pos, len, ", ");
+ if (written < 0 || written >= len)
+ {
+ break;
+ }
pos += written;
- len -= written;
+ len -= written;
}
switch (attr->type)
@@ -194,8 +198,13 @@ static char* get_string(private_ietf_attributes_t *this)
break;
}
default:
+ written = 0;
break;
}
+ if (written < 0 || written >= len)
+ {
+ break;
+ }
pos += written;
len -= written;
}
diff --git a/src/libstrongswan/credentials/keys/key_encoding.h b/src/libstrongswan/credentials/keys/key_encoding.h
deleted file mode 100644
index d8435f4b4..000000000
--- a/src/libstrongswan/credentials/keys/key_encoding.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2009 Martin Willi
- * 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.
- */
-
-/**
- * @defgroup key_encoding key_encoding
- * @{ @ingroup keys
- */
-
-#ifndef KEY_ENCODING_H_
-#define KEY_ENCODING_H_
-
-typedef struct key_encoding_t key_encoding_t;
-typedef enum key_encoding_type_t key_encoding_type_t;
-typedef enum key_encoding_part_t key_encoding_part_t;
-
-#include <library.h>
-
-/**
- * Key encoder function implementing encoding/fingerprinting.
- *
- * The variable argument list takes key_encoding_part_t, followed by part
- * specific arguments, terminated by KEY_PART_END.
- *
- * @param type format to encode the key to
- * @param args list of (key_encoding_part_t, data)
- * @param encoding encoding result, allocated
- * @return TRUE if encoding successful
- */
-typedef bool (*key_encoder_t)(key_encoding_type_t type, chunk_t *encoding,
- va_list args);
-
-/**
- * Helper function for key_encoder_t implementations to parse argument list.
- *
- * Key encoder functions get a variable argument list to parse. To simplify
- * the job, this function reads the arguments and returns chunks for each
- * part.
- * The argument list of this function takes a key_encoding_part_t, followed
- * by a data pointer receiving the value, terminated by KEY_PART_END.
- *
- * @param args argument list passed to key encoder function
- * @param ... list of (key_encoding_part_t, data*)
- * @return TRUE if all parts found, FALSE otherwise
- */
-bool key_encoding_args(va_list args, ...);
-
-/**
- * Encoding type of a fingerprint/private-/public-key.
- *
- * Fingerprints have have the KEY_ID_*, public keys the KEY_PUB_* and
- * private keys the KEY_PRIV_* prefix.
- */
-enum key_encoding_type_t {
- /** SHA1 fingerprint over subjectPublicKeyInfo */
- KEY_ID_PUBKEY_INFO_SHA1 = 0,
- /** SHA1 fingerprint over subjectPublicKey */
- KEY_ID_PUBKEY_SHA1,
- /** PGPv3 fingerprint */
- KEY_ID_PGPV3,
- /** PGPv4 fingerprint */
- KEY_ID_PGPV4,
-
- KEY_ID_MAX,
-
- /** PKCS#1 and similar ASN.1 key encoding */
- KEY_PUB_ASN1_DER,
- KEY_PRIV_ASN1_DER,
- /** subjectPublicKeyInfo encoding */
- KEY_PUB_SPKI_ASN1_DER,
- /** PEM encoded PKCS#1 key */
- KEY_PUB_PEM,
- KEY_PRIV_PEM,
- /** PGP key encoding */
- KEY_PUB_PGP,
- KEY_PRIV_PGP,
-
- KEY_ENCODING_MAX,
-};
-
-/**
- * Parts of a key to encode.
- */
-enum key_encoding_part_t {
- /** modulus of a RSA key, n */
- KEY_PART_RSA_MODULUS,
- /** public exponent of a RSA key, e */
- KEY_PART_RSA_PUB_EXP,
- /** private exponent of a RSA key, d */
- KEY_PART_RSA_PRIV_EXP,
- /** prime1 a RSA key, p */
- KEY_PART_RSA_PRIME1,
- /** prime2 a RSA key, q */
- KEY_PART_RSA_PRIME2,
- /** exponent1 a RSA key, exp1 */
- KEY_PART_RSA_EXP1,
- /** exponent1 a RSA key, exp2 */
- KEY_PART_RSA_EXP2,
- /** coefficient of RSA key, coeff */
- KEY_PART_RSA_COEFF,
- /** a DER encoded RSA public key */
- KEY_PART_RSA_PUB_ASN1_DER,
- /** a DER encoded RSA private key */
- KEY_PART_RSA_PRIV_ASN1_DER,
- /** a DER encoded ECDSA public key */
- KEY_PART_ECDSA_PUB_ASN1_DER,
- /** a DER encoded ECDSA private key */
- KEY_PART_ECDSA_PRIV_ASN1_DER,
-
- KEY_PART_END,
-};
-
-/**
- * Private/Public key encoding and fingerprinting facility.
- */
-struct key_encoding_t {
-
- /**
- * Encode a key into a format using several key parts, optional caching.
- *
- * The variable argument list takes key_encoding_part_t, followed by part
- * specific arguments, terminated by KEY_PART_END.
- * If a cache key is given, the returned encoding points to internal data:
- * do not free or modify. If no cache key is given, the encoding is
- * allocated and must be freed by the caller.
- *
- * @param type format the key should be encoded to
- * @param cache key to use for caching, NULL to not cache
- * @param encoding encoding result, allocated if caching disabled
- * @param ... list of (key_encoding_part_t, data)
- * @return TRUE if encoding successful
- */
- bool (*encode)(key_encoding_t *this, key_encoding_type_t type, void *cache,
- chunk_t *encoding, ...);
-
- /**
- * Clear all cached encodings of a given cache key.
- *
- * @param cache key used in encode() for caching
- */
- void (*clear_cache)(key_encoding_t *this, void *cache);
-
- /**
- * Check for a cached encoding.
- *
- * @param type format of the key encoding
- * @param cache key to use for caching, as given to encode()
- * @param encoding encoding result, internal data
- * @return TRUE if cache entry found
- */
- bool (*get_cache)(key_encoding_t *this, key_encoding_type_t type,
- void *cache, chunk_t *encoding);
-
- /**
- * Cache a key encoding created externally.
- *
- * After calling cache(), the passed encoding is owned by the key encoding
- * facility.
- *
- * @param type format of the key encoding
- * @param cache key to use for caching, as given to encode()
- * @param encoding encoding to cache, gets owned by this
- */
- void (*cache)(key_encoding_t *this, key_encoding_type_t type, void *cache,
- chunk_t encoding);
-
- /**
- * Register a key encoder function.
- *
- * @param encoder key encoder function to add
- */
- void (*add_encoder)(key_encoding_t *this, key_encoder_t encoder);
-
- /**
- * Unregister a previously registered key encoder function.
- *
- * @param encoder key encoder function to remove
- */
- void (*remove_encoder)(key_encoding_t *this, key_encoder_t encoder);
-
- /**
- * Destroy a key_encoding_t.
- */
- void (*destroy)(key_encoding_t *this);
-};
-
-/**
- * Create a key_encoding instance.
- */
-key_encoding_t *key_encoding_create();
-
-#endif /** KEY_ENCODING_H_ @}*/
diff --git a/src/libstrongswan/credentials/keys/private_key.c b/src/libstrongswan/credentials/keys/private_key.c
index c3b5ac55b..8292af495 100644
--- a/src/libstrongswan/credentials/keys/private_key.c
+++ b/src/libstrongswan/credentials/keys/private_key.c
@@ -20,7 +20,7 @@
*/
bool private_key_equals(private_key_t *this, private_key_t *other)
{
- key_encoding_type_t type;
+ cred_encoding_type_t type;
chunk_t a, b;
if (this == other)
@@ -28,7 +28,7 @@ bool private_key_equals(private_key_t *this, private_key_t *other)
return TRUE;
}
- for (type = 0; type < KEY_ENCODING_MAX; type++)
+ for (type = 0; type < CRED_ENCODING_MAX; type++)
{
if (this->get_fingerprint(this, type, &a) &&
other->get_fingerprint(other, type, &b))
@@ -44,10 +44,10 @@ bool private_key_equals(private_key_t *this, private_key_t *other)
*/
bool private_key_belongs_to(private_key_t *private, public_key_t *public)
{
- key_encoding_type_t type;
+ cred_encoding_type_t type;
chunk_t a, b;
- for (type = 0; type < KEY_ENCODING_MAX; type++)
+ for (type = 0; type < CRED_ENCODING_MAX; type++)
{
if (private->get_fingerprint(private, type, &a) &&
public->get_fingerprint(public, type, &b))
@@ -63,10 +63,10 @@ bool private_key_belongs_to(private_key_t *private, public_key_t *public)
*/
bool private_key_has_fingerprint(private_key_t *private, chunk_t fingerprint)
{
- key_encoding_type_t type;
+ cred_encoding_type_t type;
chunk_t current;
- for (type = 0; type < KEY_ID_MAX; type++)
+ for (type = 0; type < KEYID_MAX; type++)
{
if (private->get_fingerprint(private, type, &current) &&
chunk_equals(current, fingerprint))
diff --git a/src/libstrongswan/credentials/keys/private_key.h b/src/libstrongswan/credentials/keys/private_key.h
index d4517f296..27f4ab098 100644
--- a/src/libstrongswan/credentials/keys/private_key.h
+++ b/src/libstrongswan/credentials/keys/private_key.h
@@ -23,6 +23,7 @@
typedef struct private_key_t private_key_t;
+#include <credentials/cred_encoding.h>
#include <credentials/keys/public_key.h>
/**
@@ -89,11 +90,11 @@ struct private_key_t {
/**
* Get the fingerprint of the key.
*
- * @param type type of fingerprint, one of KEY_ID_*
+ * @param type type of fingerprint, one of KEYID_*
* @param fp fingerprint, points to internal data
* @return TRUE if fingerprint type supported
*/
- bool (*get_fingerprint)(private_key_t *this, key_encoding_type_t type,
+ bool (*get_fingerprint)(private_key_t *this, cred_encoding_type_t type,
chunk_t *fp);
/**
@@ -107,11 +108,11 @@ struct private_key_t {
/**
* Get the key in an encoded form as a chunk.
*
- * @param type type of the encoding, one of KEY_PRIV_*
+ * @param type type of the encoding, one of PRIVKEY_*
* @param encoding encoding of the key, allocated
* @return TRUE if encoding supported
*/
- bool (*get_encoding)(private_key_t *this, key_encoding_type_t type,
+ bool (*get_encoding)(private_key_t *this, cred_encoding_type_t type,
chunk_t *encoding);
/**
diff --git a/src/libstrongswan/credentials/keys/public_key.c b/src/libstrongswan/credentials/keys/public_key.c
index ba3036793..ce342de33 100644
--- a/src/libstrongswan/credentials/keys/public_key.c
+++ b/src/libstrongswan/credentials/keys/public_key.c
@@ -47,7 +47,7 @@ ENUM(signature_scheme_names, SIGN_UNKNOWN, SIGN_ECDSA_521,
*/
bool public_key_equals(public_key_t *this, public_key_t *other)
{
- key_encoding_type_t type;
+ cred_encoding_type_t type;
chunk_t a, b;
if (this == other)
@@ -55,7 +55,7 @@ bool public_key_equals(public_key_t *this, public_key_t *other)
return TRUE;
}
- for (type = 0; type < KEY_ENCODING_MAX; type++)
+ for (type = 0; type < CRED_ENCODING_MAX; type++)
{
if (this->get_fingerprint(this, type, &a) &&
other->get_fingerprint(other, type, &b))
@@ -71,10 +71,10 @@ bool public_key_equals(public_key_t *this, public_key_t *other)
*/
bool public_key_has_fingerprint(public_key_t *public, chunk_t fingerprint)
{
- key_encoding_type_t type;
+ cred_encoding_type_t type;
chunk_t current;
- for (type = 0; type < KEY_ID_MAX; type++)
+ for (type = 0; type < KEYID_MAX; type++)
{
if (public->get_fingerprint(public, type, &current) &&
chunk_equals(current, fingerprint))
diff --git a/src/libstrongswan/credentials/keys/public_key.h b/src/libstrongswan/credentials/keys/public_key.h
index a421e7b5b..ff827a189 100644
--- a/src/libstrongswan/credentials/keys/public_key.h
+++ b/src/libstrongswan/credentials/keys/public_key.h
@@ -23,12 +23,11 @@
typedef struct public_key_t public_key_t;
typedef enum key_type_t key_type_t;
-typedef enum key_id_type_t key_id_type_t;
typedef enum signature_scheme_t signature_scheme_t;
#include <library.h>
#include <utils/identification.h>
-#include <credentials/keys/key_encoding.h>
+#include <credentials/cred_encoding.h>
/**
* Type of a key pair, the used crypto system
@@ -147,11 +146,11 @@ struct public_key_t {
/**
* Get the fingerprint of the key.
*
- * @param type type of fingerprint, one of KEY_ID_*
+ * @param type type of fingerprint, one of KEYID_*
* @param fp fingerprint, points to internal data
* @return TRUE if fingerprint type supported
*/
- bool (*get_fingerprint)(public_key_t *this, key_encoding_type_t type,
+ bool (*get_fingerprint)(public_key_t *this, cred_encoding_type_t type,
chunk_t *fp);
/**
@@ -165,11 +164,11 @@ struct public_key_t {
/**
* Get the key in an encoded form as a chunk.
*
- * @param type type of the encoding, one of KEY_PRIV_*
+ * @param type type of the encoding, one of PRIVKEY_*
* @param encoding encoding of the key, allocated
* @return TRUE if encoding supported
*/
- bool (*get_encoding)(public_key_t *this, key_encoding_type_t type,
+ bool (*get_encoding)(public_key_t *this, cred_encoding_type_t type,
chunk_t *encoding);
/**
diff --git a/src/libstrongswan/credentials/sets/auth_cfg_wrapper.c b/src/libstrongswan/credentials/sets/auth_cfg_wrapper.c
new file mode 100644
index 000000000..5e8458616
--- /dev/null
+++ b/src/libstrongswan/credentials/sets/auth_cfg_wrapper.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2008-2009 Martin Willi
+ * Copyright (C) 2008 Tobias Brunner
+ * 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 <library.h>
+#include <debug.h>
+
+#include "auth_cfg_wrapper.h"
+
+typedef struct private_auth_cfg_wrapper_t private_auth_cfg_wrapper_t;
+
+/**
+ * private data of auth_cfg_wrapper
+ */
+struct private_auth_cfg_wrapper_t {
+
+ /**
+ * public functions
+ */
+ auth_cfg_wrapper_t public;
+
+ /**
+ * wrapped auth info
+ */
+ auth_cfg_t *auth;
+};
+
+/**
+ * enumerator for auth_cfg_wrapper_t.create_cert_enumerator()
+ */
+typedef struct {
+ /** implements enumerator_t */
+ enumerator_t public;
+ /** inner enumerator from auth_cfg */
+ enumerator_t *inner;
+ /** wrapped auth round */
+ auth_cfg_t *auth;
+ /** enumerated cert type */
+ certificate_type_t cert;
+ /** enumerated key type */
+ key_type_t key;
+ /** enumerated id */
+ identification_t *id;
+} wrapper_enumerator_t;
+
+/**
+ * Tries to fetch a certificate that was supplied as "Hash and URL"
+ * (replaces rule type and value in place).
+ */
+static bool fetch_cert(wrapper_enumerator_t *enumerator,
+ auth_rule_t *rule, void **value)
+{
+ char *url = (char*)*value;
+ if (!url)
+ {
+ /* fetching the certificate previously failed */
+ return FALSE;
+ }
+
+ chunk_t data;
+ certificate_t *cert;
+
+ DBG1(DBG_CFG, " fetching certificate from '%s' ...", url);
+ if (lib->fetcher->fetch(lib->fetcher, url, &data, FETCH_END) != SUCCESS)
+ {
+ DBG1(DBG_CFG, " fetching certificate failed");
+ /* we set the item to NULL, so we can skip it */
+ enumerator->auth->replace(enumerator->auth, enumerator->inner,
+ *rule, NULL);
+ return FALSE;
+ }
+
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+ BUILD_BLOB_ASN1_DER, data, BUILD_END);
+ free(data.ptr);
+
+ if (!cert)
+ {
+ DBG1(DBG_CFG, " parsing fetched certificate failed");
+ /* we set the item to NULL, so we can skip it */
+ enumerator->auth->replace(enumerator->auth, enumerator->inner,
+ *rule, NULL);
+ return FALSE;
+ }
+
+ DBG1(DBG_CFG, " fetched certificate \"%Y\"", cert->get_subject(cert));
+ lib->credmgr->cache_cert(lib->credmgr, cert);
+
+ if (*rule == AUTH_HELPER_IM_HASH_URL)
+ {
+ *rule = AUTH_HELPER_IM_CERT;
+ }
+ else
+ {
+ *rule = AUTH_HELPER_SUBJECT_CERT;
+ }
+ *value = cert;
+ enumerator->auth->replace(enumerator->auth, enumerator->inner,
+ *rule, cert->get_ref(cert));
+ return TRUE;
+}
+
+/**
+ * enumerate function for wrapper_enumerator_t
+ */
+static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
+{
+ auth_rule_t rule;
+ certificate_t *current;
+ public_key_t *public;
+
+ while (this->inner->enumerate(this->inner, &rule, &current))
+ {
+ if (rule == AUTH_HELPER_IM_HASH_URL ||
+ rule == AUTH_HELPER_SUBJECT_HASH_URL)
+ { /* on-demand fetching of hash and url certificates */
+ if (!fetch_cert(this, &rule, (void**)&current))
+ {
+ continue;
+ }
+ }
+ else if (rule != AUTH_HELPER_SUBJECT_CERT &&
+ rule != AUTH_HELPER_IM_CERT)
+ { /* handle only HELPER certificates */
+ continue;
+ }
+ if (this->cert != CERT_ANY && this->cert != current->get_type(current))
+ { /* CERT type requested, but does not match */
+ continue;
+ }
+ public = current->get_public_key(current);
+ if (this->key != KEY_ANY && !public)
+ { /* key type requested, but no public key */
+ DESTROY_IF(public);
+ continue;
+ }
+ if (this->key != KEY_ANY && public && this->key != public->get_type(public))
+ { /* key type requested, but public key has another type */
+ DESTROY_IF(public);
+ continue;
+ }
+ DESTROY_IF(public);
+ if (this->id && !current->has_subject(current, this->id))
+ { /* subject requested, but does not match */
+ continue;
+ }
+ *cert = current;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * destroy function for wrapper_enumerator_t
+ */
+static void wrapper_enumerator_destroy(wrapper_enumerator_t *this)
+{
+ this->inner->destroy(this->inner);
+ free(this);
+}
+
+/**
+ * implementation of auth_cfg_wrapper_t.set.create_cert_enumerator
+ */
+static enumerator_t *create_enumerator(private_auth_cfg_wrapper_t *this,
+ certificate_type_t cert, key_type_t key,
+ identification_t *id, bool trusted)
+{
+ wrapper_enumerator_t *enumerator;
+
+ if (trusted)
+ {
+ return NULL;
+ }
+ enumerator = malloc_thing(wrapper_enumerator_t);
+ enumerator->auth = this->auth;
+ enumerator->cert = cert;
+ enumerator->key = key;
+ enumerator->id = id;
+ enumerator->inner = this->auth->create_enumerator(this->auth);
+ enumerator->public.enumerate = (void*)enumerate;
+ enumerator->public.destroy = (void*)wrapper_enumerator_destroy;
+ return &enumerator->public;
+}
+
+/**
+ * Implementation of auth_cfg_wrapper_t.destroy
+ */
+static void destroy(private_auth_cfg_wrapper_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+auth_cfg_wrapper_t *auth_cfg_wrapper_create(auth_cfg_t *auth)
+{
+ private_auth_cfg_wrapper_t *this = malloc_thing(private_auth_cfg_wrapper_t);
+
+ this->public.set.create_private_enumerator = (void*)return_null;
+ this->public.set.create_cert_enumerator = (void*)create_enumerator;
+ this->public.set.create_shared_enumerator = (void*)return_null;
+ this->public.set.create_cdp_enumerator = (void*)return_null;
+ this->public.set.cache_cert = (void*)nop;
+ this->public.destroy = (void(*)(auth_cfg_wrapper_t*))destroy;
+
+ this->auth = auth;
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/credentials/sets/auth_cfg_wrapper.h b/src/libstrongswan/credentials/sets/auth_cfg_wrapper.h
new file mode 100644
index 000000000..3a4b197ac
--- /dev/null
+++ b/src/libstrongswan/credentials/sets/auth_cfg_wrapper.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008-2009 Martin Willi
+ * 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.
+ */
+
+/**
+ * @defgroup auth_cfg_wrapper auth_cfg_wrapper
+ * @{ @ingroup sets
+ */
+
+#ifndef AUTH_CFG_WRAPPER_H_
+#define AUTH_CFG_WRAPPER_H_
+
+#include <credentials/auth_cfg.h>
+#include <credentials/credential_set.h>
+
+typedef struct auth_cfg_wrapper_t auth_cfg_wrapper_t;
+
+/**
+ * A wrapper around auth_cfg_t to handle it as a credential set.
+ */
+struct auth_cfg_wrapper_t {
+
+ /**
+ * implements credential_set_t
+ */
+ credential_set_t set;
+
+ /**
+ * Destroy a auth_cfg_wrapper instance.
+ */
+ void (*destroy)(auth_cfg_wrapper_t *this);
+};
+
+/**
+ * Create a auth_cfg_wrapper instance.
+ *
+ * @param auth the wrapped auth info
+ * @return wrapper around auth
+ */
+auth_cfg_wrapper_t *auth_cfg_wrapper_create(auth_cfg_t *auth);
+
+#endif /** AUTH_CFG_WRAPPER_H_ @}*/
diff --git a/src/libstrongswan/credentials/sets/cert_cache.c b/src/libstrongswan/credentials/sets/cert_cache.c
new file mode 100644
index 000000000..7161ac9ac
--- /dev/null
+++ b/src/libstrongswan/credentials/sets/cert_cache.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * 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 "cert_cache.h"
+
+#include <time.h>
+#include <sched.h>
+
+#include <library.h>
+#include <threading/rwlock.h>
+#include <utils/linked_list.h>
+
+/** cache size, a power of 2 for fast modulo */
+#define CACHE_SIZE 32
+
+/** attempts to acquire a cache lock */
+#define REPLACE_TRIES 5
+
+typedef struct private_cert_cache_t private_cert_cache_t;
+typedef struct relation_t relation_t;
+
+/**
+ * A trusted relation between subject and issuer
+ */
+struct relation_t {
+
+ /**
+ * subject of this relation
+ */
+ certificate_t *subject;
+
+ /**
+ * issuer of this relation
+ */
+ certificate_t *issuer;
+
+ /**
+ * Cache hits
+ */
+ u_int hits;
+
+ /**
+ * Lock for this relation
+ */
+ rwlock_t *lock;
+};
+
+/**
+ * private data of cert_cache
+ */
+struct private_cert_cache_t {
+
+ /**
+ * public functions
+ */
+ cert_cache_t public;
+
+ /**
+ * array of trusted subject-issuer relations
+ */
+ relation_t relations[CACHE_SIZE];
+};
+
+/**
+ * Cache relation in a free slot/replace an other
+ */
+static void cache(private_cert_cache_t *this,
+ certificate_t *subject, certificate_t *issuer)
+{
+ relation_t *rel;
+ int i, offset, try;
+ u_int total_hits = 0;
+
+ /* check for a unused relation slot first */
+ for (i = 0; i < CACHE_SIZE; i++)
+ {
+ rel = &this->relations[i];
+
+ if (!rel->subject && rel->lock->try_write_lock(rel->lock))
+ {
+ /* double-check having lock */
+ if (!rel->subject)
+ {
+ rel->subject = subject->get_ref(subject);
+ rel->issuer = issuer->get_ref(issuer);
+ return rel->lock->unlock(rel->lock);
+ }
+ rel->lock->unlock(rel->lock);
+ }
+ total_hits += rel->hits;
+ }
+ /* run several attempts to replace a random slot, never block. */
+ for (try = 0; try < REPLACE_TRIES; try++)
+ {
+ /* replace a random relation */
+ offset = random();
+ for (i = 0; i < CACHE_SIZE; i++)
+ {
+ rel = &this->relations[(i + offset) % CACHE_SIZE];
+
+ if (rel->hits > total_hits / CACHE_SIZE)
+ { /* skip often used slots */
+ continue;
+ }
+ if (rel->lock->try_write_lock(rel->lock))
+ {
+ if (rel->subject)
+ {
+ rel->subject->destroy(rel->subject);
+ rel->issuer->destroy(rel->issuer);
+ }
+ rel->subject = subject->get_ref(subject);
+ rel->issuer = issuer->get_ref(issuer);
+ rel->hits = 0;
+ return rel->lock->unlock(rel->lock);
+ }
+ }
+ /* give other threads a chance to release locks */
+ sched_yield();
+ }
+}
+
+/**
+ * Implementation of cert_cache_t.issued_by.
+ */
+static bool issued_by(private_cert_cache_t *this,
+ certificate_t *subject, certificate_t *issuer)
+{
+ relation_t *found = NULL, *current;
+ int i;
+
+ for (i = 0; i < CACHE_SIZE; i++)
+ {
+ current = &this->relations[i];
+
+ current->lock->read_lock(current->lock);
+ if (current->subject)
+ {
+ /* check for equal issuer */
+ if (issuer->equals(issuer, current->issuer))
+ {
+ /* reuse issuer instance in cache() */
+ issuer = current->issuer;
+ if (subject->equals(subject, current->subject))
+ {
+ /* write hit counter is not locked, but not critical */
+ current->hits++;
+ found = current;
+ }
+ }
+ }
+ current->lock->unlock(current->lock);
+ if (found)
+ {
+ return TRUE;
+ }
+ }
+ /* no cache hit, check and cache signature */
+ if (subject->issued_by(subject, issuer))
+ {
+ cache(this, subject, issuer);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * certificate enumerator implemenation
+ */
+typedef struct {
+ /** implements enumerator_t interface */
+ enumerator_t public;
+ /** type of requested certificate */
+ certificate_type_t cert;
+ /** type of requested key */
+ key_type_t key;
+ /** ID to get a cert for */
+ identification_t *id;
+ /** cache */
+ relation_t *relations;
+ /** current position in array cache */
+ int index;
+ /** currently locked relation */
+ int locked;
+} cert_enumerator_t;
+
+/**
+ * filter function for certs enumerator
+ */
+static bool cert_enumerate(cert_enumerator_t *this, certificate_t **out)
+{
+ public_key_t *public;
+ relation_t *rel;
+
+ if (this->locked >= 0)
+ {
+ rel = &this->relations[this->locked];
+ rel->lock->unlock(rel->lock);
+ this->locked = -1;
+ }
+
+ while (++this->index < CACHE_SIZE)
+ {
+ rel = &this->relations[this->index];
+ rel->lock->read_lock(rel->lock);
+ this->locked = this->index;
+ if (rel->subject)
+ {
+ /* CRL lookup is done using issuer/authkeyidentifier */
+ if (this->key == KEY_ANY && this->id &&
+ (this->cert == CERT_ANY || this->cert == CERT_X509_CRL) &&
+ rel->subject->get_type(rel->subject) == CERT_X509_CRL &&
+ rel->subject->has_issuer(rel->subject, this->id))
+ {
+ *out = rel->subject;
+ return TRUE;
+ }
+ if ((this->cert == CERT_ANY ||
+ rel->subject->get_type(rel->subject) == this->cert) &&
+ (!this->id || rel->subject->has_subject(rel->subject, this->id)))
+ {
+ if (this->key == KEY_ANY)
+ {
+ *out = rel->subject;
+ return TRUE;
+ }
+ public = rel->subject->get_public_key(rel->subject);
+ if (public)
+ {
+ if (public->get_type(public) == this->key)
+ {
+ public->destroy(public);
+ *out = rel->subject;
+ return TRUE;
+ }
+ public->destroy(public);
+ }
+ }
+ }
+ this->locked = -1;
+ rel->lock->unlock(rel->lock);
+ }
+ return FALSE;
+}
+
+/**
+ * clean up enumeration data
+ */
+static void cert_enumerator_destroy(cert_enumerator_t *this)
+{
+ relation_t *rel;
+
+ if (this->locked >= 0)
+ {
+ rel = &this->relations[this->locked];
+ rel->lock->unlock(rel->lock);
+ }
+ free(this);
+}
+
+/**
+ * implementation of credential_set_t.create_cert_enumerator
+ */
+static enumerator_t *create_enumerator(private_cert_cache_t *this,
+ certificate_type_t cert, key_type_t key,
+ identification_t *id, bool trusted)
+{
+ cert_enumerator_t *enumerator;
+
+ if (trusted)
+ {
+ return NULL;
+ }
+ enumerator = malloc_thing(cert_enumerator_t);
+ enumerator->public.enumerate = (void*)cert_enumerate;
+ enumerator->public.destroy = (void*)cert_enumerator_destroy;
+ enumerator->cert = cert;
+ enumerator->key = key;
+ enumerator->id = id;
+ enumerator->relations = this->relations;
+ enumerator->index = -1;
+ enumerator->locked = -1;
+
+ return &enumerator->public;
+}
+
+/**
+ * Implementation of cert_cache_t.flush.
+ */
+static void flush(private_cert_cache_t *this, certificate_type_t type)
+{
+ relation_t *rel;
+ int i;
+
+ for (i = 0; i < CACHE_SIZE; i++)
+ {
+ rel = &this->relations[i];
+ if (!rel->subject)
+ {
+ continue;
+ }
+ /* check with cheap read lock first */
+ if (type != CERT_ANY)
+ {
+ rel->lock->read_lock(rel->lock);
+ if (!rel->subject || type != rel->subject->get_type(rel->subject))
+ {
+ rel->lock->unlock(rel->lock);
+ continue;
+ }
+ rel->lock->unlock(rel->lock);
+ }
+ /* double check in write lock */
+ rel->lock->write_lock(rel->lock);
+ if (rel->subject)
+ {
+ if (type == CERT_ANY || type == rel->subject->get_type(rel->subject))
+ {
+ rel->subject->destroy(rel->subject);
+ rel->issuer->destroy(rel->issuer);
+ rel->subject = NULL;
+ rel->issuer = NULL;
+ rel->hits = 0;
+ }
+ }
+ rel->lock->unlock(rel->lock);
+ }
+}
+
+/**
+ * Implementation of cert_cache_t.destroy
+ */
+static void destroy(private_cert_cache_t *this)
+{
+ relation_t *rel;
+ int i;
+
+ for (i = 0; i < CACHE_SIZE; i++)
+ {
+ rel = &this->relations[i];
+ if (rel->subject)
+ {
+ rel->subject->destroy(rel->subject);
+ rel->issuer->destroy(rel->issuer);
+ }
+ rel->lock->destroy(rel->lock);
+ }
+ free(this);
+}
+
+/*
+ * see header file
+ */
+cert_cache_t *cert_cache_create()
+{
+ private_cert_cache_t *this;
+ int i;
+
+ this = malloc_thing(private_cert_cache_t);
+ this->public.set.create_private_enumerator = (void*)return_null;
+ this->public.set.create_cert_enumerator = (void*)create_enumerator;
+ this->public.set.create_shared_enumerator = (void*)return_null;
+ this->public.set.create_cdp_enumerator = (void*)return_null;
+ this->public.set.cache_cert = (void*)nop;
+ this->public.issued_by = (bool(*)(cert_cache_t*, certificate_t *subject, certificate_t *issuer))issued_by;
+ this->public.flush = (void(*)(cert_cache_t*, certificate_type_t type))flush;
+ this->public.destroy = (void(*)(cert_cache_t*))destroy;
+
+ for (i = 0; i < CACHE_SIZE; i++)
+ {
+ this->relations[i].subject = NULL;
+ this->relations[i].issuer = NULL;
+ this->relations[i].hits = 0;
+ this->relations[i].lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+ }
+ return &this->public;
+}
diff --git a/src/libstrongswan/credentials/sets/cert_cache.h b/src/libstrongswan/credentials/sets/cert_cache.h
new file mode 100644
index 000000000..d2721866e
--- /dev/null
+++ b/src/libstrongswan/credentials/sets/cert_cache.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * 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.
+ */
+
+/**
+ * @defgroup cert_cache cert_cache
+ * @{ @ingroup sets
+ */
+
+#ifndef CERT_CACHE_H_
+#define CERT_CACHE_H_
+
+#include <credentials/credential_set.h>
+
+typedef struct cert_cache_t cert_cache_t;
+
+/**
+ * Certificate signature verification and certificate cache.
+ *
+ * This cache serves all certificates seen in its issued_by method
+ * and serves them as untrusted through the credential set interface. Further,
+ * it caches valid subject-issuer relationships to speed up the issued_by
+ * method.
+ */
+struct cert_cache_t {
+
+ /**
+ * Implements credential_set_t.
+ */
+ credential_set_t set;
+
+ /**
+ * Caching wrapper around certificate_t.issued_by.
+ *
+ * @param subject certificate to verify
+ * @param issuer issuing certificate to verify subject
+ * @return TRUE if subject issued by issuer
+ */
+ bool (*issued_by)(cert_cache_t *this,
+ certificate_t *subject, certificate_t *issuer);
+
+ /**
+ * Flush the certificate cache.
+ *
+ * @param type type of certificate to flush, or CERT_ANY
+ */
+ void (*flush)(cert_cache_t *this, certificate_type_t type);
+
+ /**
+ * Destroy a cert_cache instance.
+ */
+ void (*destroy)(cert_cache_t *this);
+};
+
+/**
+ * Create a cert_cache instance.
+ */
+cert_cache_t *cert_cache_create();
+
+#endif /** CERT_CACHE_H_ @}*/
diff --git a/src/libstrongswan/credentials/sets/ocsp_response_wrapper.c b/src/libstrongswan/credentials/sets/ocsp_response_wrapper.c
new file mode 100644
index 000000000..4786495da
--- /dev/null
+++ b/src/libstrongswan/credentials/sets/ocsp_response_wrapper.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * 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 "ocsp_response_wrapper.h"
+
+typedef struct private_ocsp_response_wrapper_t private_ocsp_response_wrapper_t;
+
+/**
+ * private data of ocsp_response_wrapper
+ */
+struct private_ocsp_response_wrapper_t {
+
+ /**
+ * public functions
+ */
+ ocsp_response_wrapper_t public;
+
+ /**
+ * wrapped OCSP response
+ */
+ ocsp_response_t *response;
+};
+
+/**
+ * enumerator for ocsp_response_wrapper_t.create_cert_enumerator()
+ */
+typedef struct {
+ /** implements enumerator_t */
+ enumerator_t public;
+ /** enumerator over ocsp response */
+ enumerator_t *inner;
+ /** type of cert */
+ certificate_type_t cert;
+ /** type of key */
+ key_type_t key;
+ /** filtering identity */
+ identification_t *id;
+} wrapper_enumerator_t;
+
+/**
+ * enumerate function wrapper_enumerator_t
+ */
+static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
+{
+ certificate_t *current;
+ public_key_t *public;
+
+ while (this->inner->enumerate(this->inner, &current))
+ {
+ if (this->cert != CERT_ANY && this->cert != current->get_type(current))
+ { /* CERT type requested, but does not match */
+ continue;
+ }
+ public = current->get_public_key(current);
+ if (this->key != KEY_ANY && !public)
+ { /* key type requested, but no public key */
+ DESTROY_IF(public);
+ continue;
+ }
+ if (this->key != KEY_ANY && public && this->key != public->get_type(public))
+ { /* key type requested, but public key has another type */
+ DESTROY_IF(public);
+ continue;
+ }
+ DESTROY_IF(public);
+ if (this->id && !current->has_subject(current, this->id))
+ { /* subject requested, but does not match */
+ continue;
+ }
+ *cert = current;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * destroy function for wrapper_enumerator_t
+ */
+static void enumerator_destroy(wrapper_enumerator_t *this)
+{
+ this->inner->destroy(this->inner);
+ free(this);
+}
+
+/**
+ * implementation of ocsp_response_wrapper_t.set.create_cert_enumerator
+ */
+static enumerator_t *create_enumerator(private_ocsp_response_wrapper_t *this,
+ certificate_type_t cert, key_type_t key,
+ identification_t *id, bool trusted)
+{
+ wrapper_enumerator_t *enumerator;
+
+ if (trusted)
+ {
+ return NULL;
+ }
+
+ enumerator = malloc_thing(wrapper_enumerator_t);
+ enumerator->cert = cert;
+ enumerator->key = key;
+ enumerator->id = id;
+ enumerator->inner = this->response->create_cert_enumerator(this->response);
+ enumerator->public.enumerate = (void*)enumerate;
+ enumerator->public.destroy = (void*)enumerator_destroy;
+ return &enumerator->public;
+}
+
+/**
+ * Implementation of ocsp_response_wrapper_t.destroy
+ */
+static void destroy(private_ocsp_response_wrapper_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+ocsp_response_wrapper_t *ocsp_response_wrapper_create(ocsp_response_t *response)
+{
+ private_ocsp_response_wrapper_t *this = malloc_thing(private_ocsp_response_wrapper_t);
+
+ this->public.set.create_private_enumerator = (void*)return_null;
+ this->public.set.create_cert_enumerator = (void*)create_enumerator;
+ this->public.set.create_shared_enumerator = (void*)return_null;
+ this->public.set.create_cdp_enumerator = (void*)return_null;
+ this->public.set.cache_cert = (void*)nop;
+ this->public.destroy = (void(*)(ocsp_response_wrapper_t*))destroy;
+
+ this->response = response;
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/credentials/sets/ocsp_response_wrapper.h b/src/libstrongswan/credentials/sets/ocsp_response_wrapper.h
new file mode 100644
index 000000000..dc4b451df
--- /dev/null
+++ b/src/libstrongswan/credentials/sets/ocsp_response_wrapper.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * 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.
+ */
+
+/**
+ * @defgroup ocsp_response_wrapper ocsp_response_wrapper
+ * @{ @ingroup sets
+ */
+
+#ifndef OCSP_RESPONSE_WRAPPER_H_
+#define OCSP_RESPONSE_WRAPPER_H_
+
+#include <credentials/credential_set.h>
+#include <credentials/certificates/ocsp_response.h>
+
+typedef struct ocsp_response_wrapper_t ocsp_response_wrapper_t;
+
+/**
+ * A wrapper around ocsp_response_t to handle it like a credential set.
+ */
+struct ocsp_response_wrapper_t {
+
+ /**
+ * implements credential_set_t
+ */
+ credential_set_t set;
+
+ /**
+ * Destroy a ocsp_response_wrapper instance.
+ */
+ void (*destroy)(ocsp_response_wrapper_t *this);
+};
+
+/**
+ * Create a ocsp_response_wrapper instance.
+ *
+ * @param response the wrapped OCSP response
+ * @return wrapper around response
+ */
+ocsp_response_wrapper_t *ocsp_response_wrapper_create(ocsp_response_t *response);
+
+#endif /** OCSP_RESPONSE_WRAPPER_H_ @}*/