diff options
Diffstat (limited to 'src/charon/credentials/auth_info.c')
-rw-r--r-- | src/charon/credentials/auth_info.c | 571 |
1 files changed, 571 insertions, 0 deletions
diff --git a/src/charon/credentials/auth_info.c b/src/charon/credentials/auth_info.c new file mode 100644 index 000000000..cd748bc97 --- /dev/null +++ b/src/charon/credentials/auth_info.c @@ -0,0 +1,571 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * 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. + * + * $Id: auth_info.c 3838 2008-04-18 11:24:45Z tobias $ + */ + + +#include "auth_info.h" + +#include <daemon.h> +#include <utils/linked_list.h> +#include <utils/identification.h> +#include <credentials/certificates/certificate.h> + +ENUM(auth_item_names, AUTHN_CA_CERT, AUTHZ_AC_GROUP, + "AUTHN_CA_CERT", + "AUTHN_CA_CERT_KEYID", + "AUTHN_CA_CERT_NAME", + "AUTHN_IM_CERT", + "AUTHN_SUBJECT_CERT", + "AUTHN_IM_HASH_URL", + "AUTHN_SUBJECT_HASH_URL", + "AUTHZ_PUBKEY", + "AUTHZ_PSK", + "AUTHZ_EAP", + "AUTHZ_CA_CERT", + "AUTHZ_CA_CERT_NAME", + "AUTHZ_IM_CERT", + "AUTHZ_SUBJECT_CERT", + "AUTHZ_CRL_VALIDATION", + "AUTHZ_OCSP_VALIDATION", + "AUTHZ_AC_GROUP", +); + +typedef struct private_auth_info_t private_auth_info_t; + +/** + * private data of item_set + */ +struct private_auth_info_t { + + /** + * public functions + */ + auth_info_t public; + + /** + * list of item_t's + */ + linked_list_t *items; +}; + +typedef struct item_t item_t; + +struct item_t { + /** type of this item */ + auth_item_t type; + /** associated privlege value, if any */ + void *value; +}; + +/** + * enumerator for auth_info_wrapper_t.create_cert_enumerator() + */ +typedef struct { + /** implements enumerator_t */ + enumerator_t public; + /** inner enumerator from linked_list_t */ + enumerator_t *inner; + /** the current item */ + item_t *item; +} item_enumerator_t; + +/** + * enumerate function for item_enumerator_t + */ +static bool enumerate(item_enumerator_t *this, auth_item_t *type, void **value) +{ + if (this->inner->enumerate(this->inner, &this->item)) + { + *type = this->item->type; + *value = this->item->value; + return TRUE; + } + return FALSE; +} + +/** + * destroy function for item_enumerator_t + */ +static void item_enumerator_destroy(item_enumerator_t *this) +{ + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of auth_info_t.create_item_enumerator. + */ +static enumerator_t* create_item_enumerator(private_auth_info_t *this) +{ + item_enumerator_t *enumerator; + + enumerator = malloc_thing(item_enumerator_t); + enumerator->item = NULL; + enumerator->inner = this->items->create_enumerator(this->items); + enumerator->public.enumerate = (void*)enumerate; + enumerator->public.destroy = (void*)item_enumerator_destroy; + return &enumerator->public; +} + +static void destroy_item_value(item_t *item); + +/** + * Implementation of auth_info_t.replace_item. + */ +static void replace_item(item_enumerator_t *enumerator, auth_item_t type, void *value) +{ + destroy_item_value(enumerator->item); + enumerator->item->type = type; + enumerator->item->value = value; +} + +/** + * Implementation of auth_info_t.get_item. + */ +static bool get_item(private_auth_info_t *this, auth_item_t type, void** value) +{ + enumerator_t *enumerator; + void *current_value; + auth_item_t current_type; + bool found = FALSE; + + enumerator = create_item_enumerator(this); + while (enumerator->enumerate(enumerator, ¤t_type, ¤t_value)) + { + if (type == current_type) + { + *value = current_value; + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +/** + * Implementation of auth_info_t.add_item. + */ +static void add_item(private_auth_info_t *this, auth_item_t type, void *value) +{ + item_t *item = malloc_thing(item_t); + + item->type = type; + switch (type) + { + case AUTHZ_PUBKEY: + { + public_key_t *key = (public_key_t*)value; + + item->value = key->get_ref(key); + break; + } + case AUTHZ_PSK: + { + shared_key_t *key = (shared_key_t*)value; + + item->value = key->get_ref(key); + break; + } + case AUTHN_IM_HASH_URL: + case AUTHN_SUBJECT_HASH_URL: + { + item->value = strdup(value); + break; + } + case AUTHN_CA_CERT: + case AUTHN_IM_CERT: + case AUTHN_SUBJECT_CERT: + case AUTHZ_CA_CERT: + case AUTHZ_IM_CERT: + case AUTHZ_SUBJECT_CERT: + { + certificate_t *cert = (certificate_t*)value; + + item->value = cert->get_ref(cert); + break; + } + case AUTHZ_CRL_VALIDATION: + case AUTHZ_OCSP_VALIDATION: + { + cert_validation_t *validation = malloc_thing(cert_validation_t); + + *validation = *(cert_validation_t*)value; + item->value = validation; + break; + } + case AUTHZ_EAP: + { + eap_method_t *method = malloc_thing(eap_method_t); + + *method = *(eap_method_t*)value; + item->value = method; + break; + } + case AUTHN_CA_CERT_KEYID: + case AUTHN_CA_CERT_NAME: + case AUTHZ_CA_CERT_NAME: + case AUTHZ_AC_GROUP: + { + identification_t *id = (identification_t*)value; + + item->value = id->clone(id); + break; + } + } + this->items->insert_last(this->items, item); +} + + +/** + * Implementation of auth_info_t.complies. + */ +static bool complies(private_auth_info_t *this, auth_info_t *constraints) +{ + enumerator_t *enumerator; + bool success = TRUE; + auth_item_t t1, t2; + void *value; + + enumerator = constraints->create_item_enumerator(constraints); + while (enumerator->enumerate(enumerator, &t1, &value)) + { + switch (t1) + { + case AUTHN_CA_CERT_KEYID: + case AUTHN_CA_CERT: + case AUTHN_CA_CERT_NAME: + case AUTHN_IM_CERT: + case AUTHN_SUBJECT_CERT: + case AUTHN_IM_HASH_URL: + case AUTHN_SUBJECT_HASH_URL: + { /* skip non-authorization tokens */ + continue; + } + case AUTHZ_CRL_VALIDATION: + case AUTHZ_OCSP_VALIDATION: + { + cert_validation_t *valid; + + /* OCSP validation is also sufficient for CRL constraint, but + * not vice-versa */ + if (!get_item(this, t1, (void**)&valid) && + t1 == AUTHZ_CRL_VALIDATION && + !get_item(this, AUTHZ_OCSP_VALIDATION, (void**)&valid)) + { + DBG1(DBG_CFG, "constraint check failed: %N requires at " + "least %N, but no check done", auth_item_names, t1, + cert_validation_names, *(cert_validation_t*)value); + success = FALSE; + break; + } + switch (*(cert_validation_t*)value) + { + case VALIDATION_SKIPPED: + if (*valid == VALIDATION_SKIPPED) + { + break; + } /* FALL */ + case VALIDATION_GOOD: + if (*valid == VALIDATION_GOOD) + { + break; + } /* FALL */ + default: + DBG1(DBG_CFG, "constraint check failed: %N is %N, but " + "requires at least %N", auth_item_names, t1, + cert_validation_names, *valid, + cert_validation_names, *(cert_validation_t*)value); + success = FALSE; + break; + } + break; + } + case AUTHZ_CA_CERT: + { + enumerator_t *enumerator; + certificate_t *c1, *c2; + + c1 = (certificate_t*)value; + + success = FALSE; + enumerator = create_item_enumerator(this); + while (enumerator->enumerate(enumerator, &t2, &c2)) + { + if ((t2 == AUTHZ_CA_CERT || t2 == AUTHZ_IM_CERT) && + c1->equals(c1, c2)) + { + success = TRUE; + } + } + enumerator->destroy(enumerator); + if (!success) + { + DBG1(DBG_CFG, "constraint check failed: peer not " + "authenticated by CA '%D'.", c1->get_subject(c1)); + } + break; + } + case AUTHZ_CA_CERT_NAME: + { + enumerator_t *enumerator; + certificate_t *cert; + identification_t *id; + + id = (identification_t*)value; + success = FALSE; + enumerator = create_item_enumerator(this); + while (enumerator->enumerate(enumerator, &t2, &cert)) + { + if ((t2 == AUTHZ_CA_CERT || t2 == AUTHZ_IM_CERT) && + cert->has_subject(cert, id)) + { + success = TRUE; + } + } + enumerator->destroy(enumerator); + if (!success) + { + DBG1(DBG_CFG, "constraint check failed: peer not " + "authenticated by CA '%D'.", id); + } + break; + } + case AUTHZ_PUBKEY: + case AUTHZ_PSK: + case AUTHZ_IM_CERT: + case AUTHZ_SUBJECT_CERT: + case AUTHZ_EAP: + case AUTHZ_AC_GROUP: + { + DBG1(DBG_CFG, "constraint check %N not implemented!", + auth_item_names, t1); + success = FALSE; + break; + } + } + if (!success) + { + break; + } + } + enumerator->destroy(enumerator); + return success; +} + +/** + * Implementation of auth_info_t.merge. + */ +static void merge(private_auth_info_t *this, private_auth_info_t *other) +{ + item_t *item; + + while (other->items->remove_first(other->items, (void**)&item) == SUCCESS) + { + this->items->insert_last(this->items, item); + } +} + +/** + * Implementation of auth_info_t.equals. + */ +static bool equals(private_auth_info_t *this, private_auth_info_t *other) +{ + enumerator_t *e1, *e2; + item_t *i1, *i2; + bool equal = TRUE, found; + + e1 = this->items->create_enumerator(this->items); + while (e1->enumerate(e1, &i1)) + { + found = FALSE; + e2 = other->items->create_enumerator(other->items); + while (e2->enumerate(e2, &i2)) + { + if (i1->type == i2->type) + { + switch (i1->type) + { + case AUTHZ_CRL_VALIDATION: + case AUTHZ_OCSP_VALIDATION: + { + cert_validation_t c1, c2; + + c1 = *(cert_validation_t*)i1->value; + c2 = *(cert_validation_t*)i2->value; + + if (c1 == c2) + { + found = TRUE; + break; + } + continue; + } + case AUTHN_IM_HASH_URL: + case AUTHN_SUBJECT_HASH_URL: + { + if (streq(i1->value, i2->value)) + { + found = TRUE; + break; + } + continue; + } + case AUTHN_CA_CERT: + case AUTHN_IM_CERT: + case AUTHN_SUBJECT_CERT: + case AUTHZ_CA_CERT: + case AUTHZ_IM_CERT: + case AUTHZ_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 AUTHN_CA_CERT_KEYID: + case AUTHN_CA_CERT_NAME: + case AUTHZ_CA_CERT_NAME: + { + identification_t *c1, *c2; + + c1 = (identification_t*)i1->value; + c2 = (identification_t*)i2->value; + + if (c1->equals(c1, c2)) + { + found = TRUE; + break; + } + continue; + } + case AUTHZ_PUBKEY: + case AUTHZ_PSK: + case AUTHZ_EAP: + case AUTHZ_AC_GROUP: + /* TODO: implement value comparison */ + break; + } + break; + } + } + e2->destroy(e2); + if (!found) + { + equal = FALSE; + break; + } + } + e1->destroy(e1); + return equal; +} + +/** + * Destroy the value associated with an item + */ +static void destroy_item_value(item_t *item) +{ + switch (item->type) + { + case AUTHZ_PUBKEY: + { + public_key_t *key = (public_key_t*)item->value; + key->destroy(key); + break; + } + case AUTHZ_PSK: + { + shared_key_t *key = (shared_key_t*)item->value; + key->destroy(key); + break; + } + case AUTHN_CA_CERT: + case AUTHN_IM_CERT: + case AUTHN_SUBJECT_CERT: + case AUTHZ_CA_CERT: + case AUTHZ_IM_CERT: + case AUTHZ_SUBJECT_CERT: + { + certificate_t *cert = (certificate_t*)item->value; + cert->destroy(cert); + break; + } + case AUTHN_IM_HASH_URL: + case AUTHN_SUBJECT_HASH_URL: + case AUTHZ_CRL_VALIDATION: + case AUTHZ_OCSP_VALIDATION: + case AUTHZ_EAP: + { + free(item->value); + break; + } + case AUTHN_CA_CERT_KEYID: + case AUTHN_CA_CERT_NAME: + case AUTHZ_CA_CERT_NAME: + case AUTHZ_AC_GROUP: + { + identification_t *id = (identification_t*)item->value; + id->destroy(id); + break; + } + } +} + +/** + * Implementation of auth_info_t.destroy + */ +static void destroy(private_auth_info_t *this) +{ + item_t *item; + + while (this->items->remove_last(this->items, (void**)&item) == SUCCESS) + { + destroy_item_value(item); + free(item); + } + this->items->destroy(this->items); + free(this); +} + +/* + * see header file + */ +auth_info_t *auth_info_create() +{ + private_auth_info_t *this = malloc_thing(private_auth_info_t); + + this->public.add_item = (void(*)(auth_info_t*, auth_item_t type, void *value))add_item; + this->public.get_item = (bool(*)(auth_info_t*, auth_item_t type, void **value))get_item; + this->public.replace_item = (void(*)(enumerator_t*,auth_item_t,void*))replace_item; + this->public.create_item_enumerator = (enumerator_t*(*)(auth_info_t*))create_item_enumerator; + this->public.complies = (bool(*)(auth_info_t*, auth_info_t *))complies; + this->public.merge = (void(*)(auth_info_t*, auth_info_t *other))merge; + this->public.equals = (bool(*)(auth_info_t*, auth_info_t *other))equals; + this->public.destroy = (void(*)(auth_info_t*))destroy; + + this->items = linked_list_create(); + + return &this->public; +} + |