diff options
28 files changed, 985 insertions, 1445 deletions
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index f97d4200c..5a53cc57c 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -36,6 +36,7 @@ credentials/certificates/pkcs10.h \ credentials/certificates/ocsp_request.h \ credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \ credentials/certificates/pgp_certificate.h \ +credentials/ietf_attributes/ietf_attributes.c credentials/ietf_attributes/ietf_attributes.h \ database/database.h database/database_factory.h database/database_factory.c \ fetcher/fetcher.h fetcher/fetcher_manager.h fetcher/fetcher_manager.c \ utils.h utils.c \ diff --git a/src/libstrongswan/credentials/certificates/ac.h b/src/libstrongswan/credentials/certificates/ac.h index 50fd78878..fef7f8c65 100644 --- a/src/libstrongswan/credentials/certificates/ac.h +++ b/src/libstrongswan/credentials/certificates/ac.h @@ -1,9 +1,7 @@ /* - * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2003 Martin Berner, Lukas Suter - * Copyright (C) 2002-2008 Andreas Steffen + * Copyright (C) 2002-2009 Andreas Steffen * - * Hochschule fuer Technik Rapperswil + * HSR 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 @@ -26,6 +24,7 @@ #include <library.h> #include <credentials/certificates/certificate.h> +#include <credentials/ietf_attributes/ietf_attributes.h> typedef struct ac_t ac_t; @@ -64,13 +63,20 @@ struct ac_t { identification_t* (*get_holderIssuer)(ac_t *this); /** - * Get the thauthorityKeyIdentifier. + * Get the authorityKeyIdentifier. * * @return authKeyIdentifier as chunk_t, to internal data */ chunk_t (*get_authKeyIdentifier)(ac_t *this); /** + * Get the group memberships as a list of IETF attributes + * + * @return object containing a list of IETF attributes + */ + ietf_attributes_t* (*get_groups)(ac_t *this); + + /** * @brief Checks if two attribute certificates belong to the same holder * * @param this calling attribute certificate diff --git a/src/libstrongswan/credentials/certificates/x509.c b/src/libstrongswan/credentials/certificates/x509.c index 5d53f0c68..0a75056fe 100644 --- a/src/libstrongswan/credentials/certificates/x509.c +++ b/src/libstrongswan/credentials/certificates/x509.c @@ -15,7 +15,8 @@ #include "x509.h" -ENUM(x509_flag_names, X509_CA, X509_SELF_SIGNED, +ENUM(x509_flag_names, X509_NONE, X509_SELF_SIGNED, + "X509_NONE", "X509_CA", "X509_AA", "X509_OCSP_SIGNER", diff --git a/src/libstrongswan/credentials/certificates/x509.h b/src/libstrongswan/credentials/certificates/x509.h index b3253a269..a700238ee 100644 --- a/src/libstrongswan/credentials/certificates/x509.h +++ b/src/libstrongswan/credentials/certificates/x509.h @@ -31,6 +31,8 @@ typedef enum x509_flag_t x509_flag_t; * X.509 certificate flags. */ enum x509_flag_t { + /** cert has no constraints */ + X509_NONE = 0, /** cert has CA constraint */ X509_CA = (1<<0), /** cert has AA constraint */ diff --git a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c new file mode 100644 index 000000000..ff3ddeb6f --- /dev/null +++ b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2007-2009 Andreas Steffen + * + * HSR 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 <asn1/oid.h> +#include <asn1/asn1.h> +#include <asn1/asn1_parser.h> +#include <utils/linked_list.h> +#include <utils/lexparser.h> + +#include "ietf_attributes.h" + +/** + * Private definition of IETF attribute types + */ +typedef enum { + IETF_ATTRIBUTE_OCTETS = 0, + IETF_ATTRIBUTE_OID = 1, + IETF_ATTRIBUTE_STRING = 2 +} ietf_attribute_type_t; + +typedef struct ietf_attr_t ietf_attr_t; + +/** + * Private definition of an IETF attribute + */ +struct ietf_attr_t { + /** + * IETF attribute type + */ + ietf_attribute_type_t type; + + /** + * IETF attribute value + */ + chunk_t value; + + /** + * Compares two IETF attributes + * + * return -1 if this is earlier in the alphabet than other + * return 0 if this equals other + * return +1 if this is later in the alphabet than other + * + * @param other other object + */ + int (*compare) (ietf_attr_t *this, ietf_attr_t *other); + + /** + * Destroys an ietf_attr_t object. + */ + void (*destroy) (ietf_attr_t *this); +}; + +/** + * Implements ietf_attr_t.compare. + */ +static int ietf_attr_compare(ietf_attr_t *this, ietf_attr_t *other) +{ + int cmp_len, len, cmp_value; + + /* OID attributes are appended after STRING and OCTETS attributes */ + if (this->type != IETF_ATTRIBUTE_OID && other->type == IETF_ATTRIBUTE_OID) + { + return -1; + } + if (this->type == IETF_ATTRIBUTE_OID && other->type != IETF_ATTRIBUTE_OID) + { + return 1; + } + + cmp_len = this->value.len - other->value.len; + len = (cmp_len < 0) ? this->value.len : other->value.len; + cmp_value = memcmp(this->value.ptr, other->value.ptr, len); + + return (cmp_value == 0) ? cmp_len : cmp_value; +} + +/** + * Implements ietf_attr_t.destroy. + */ +static void ietf_attr_destroy(ietf_attr_t *this) +{ + free(this->value.ptr); + free(this); +} + +/** + * Creates an ietf_attr_t object. + */ +static ietf_attr_t* ietf_attr_create(ietf_attribute_type_t type, chunk_t value) +{ + ietf_attr_t *this = malloc_thing(ietf_attr_t); + + /* initialize */ + this->type = type; + this->value = chunk_clone(value); + + /* function */ + this->compare = ietf_attr_compare; + this->destroy = ietf_attr_destroy; + + return this; +} + +typedef struct private_ietf_attributes_t private_ietf_attributes_t; + +/** + * Private data of an ietf_attributes_t object. + */ +struct private_ietf_attributes_t { + /** + * Public interface. + */ + ietf_attributes_t public; + + /** + * Printable representation of the IETF attributes + */ + char *string; + + /** + * Linked list of IETF attributes. + */ + linked_list_t *list; + + /** + * reference count + */ + refcount_t ref; +}; + +/** + * Implementation of ietf_attributes_t.get_string. + */ +static char* get_string(private_ietf_attributes_t *this) +{ + if (this->string == NULL) + { + char buf[BUF_LEN]; + char *pos = buf; + int len = BUF_LEN; + bool first = TRUE; + ietf_attr_t *attr; + enumerator_t *enumerator; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &attr)) + { + int written = 0; + + if (first) + { + first = FALSE; + } + else + { + written = snprintf(pos, len, ", "); + pos += written; + len -= written; + } + + switch (attr->type) + { + case IETF_ATTRIBUTE_OCTETS: + case IETF_ATTRIBUTE_STRING: + written = snprintf(pos, len, "%.*s", (int)attr->value.len, + attr->value.ptr); + break; + case IETF_ATTRIBUTE_OID: + { + int oid = asn1_known_oid(attr->value); + + if (oid == OID_UNKNOWN) + { + written = snprintf(pos, len, "0x#B", &attr->value); + } + else + { + written = snprintf(pos, len, "%s", oid_names[oid]); + } + break; + } + default: + break; + } + pos += written; + len -= written; + } + enumerator->destroy(enumerator); + if (len < BUF_LEN) + { + this->string = strdup(buf); + } + } + return this->string; +} + +/** + * Implementation of ietf_attributes_t.get_encoding. + */ +static chunk_t get_encoding(private_ietf_attributes_t *this) +{ + chunk_t values; + size_t size = 0; + u_char *pos; + ietf_attr_t *attr; + enumerator_t *enumerator; + + /* precalculate the total size of all values */ + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &attr)) + { + size_t len = attr->value.len; + + size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len; + } + enumerator->destroy(enumerator); + + pos = asn1_build_object(&values, ASN1_SEQUENCE, size); + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &attr)) + { + chunk_t ietfAttribute; + asn1_t type = ASN1_NULL; + + switch (attr->type) + { + case IETF_ATTRIBUTE_OCTETS: + type = ASN1_OCTET_STRING; + break; + case IETF_ATTRIBUTE_STRING: + type = ASN1_UTF8STRING; + break; + case IETF_ATTRIBUTE_OID: + type = ASN1_OID; + break; + } + ietfAttribute = asn1_simple_object(type, attr->value); + + /* copy ietfAttribute into values chunk */ + memcpy(pos, ietfAttribute.ptr, ietfAttribute.len); + pos += ietfAttribute.len; + free(ietfAttribute.ptr); + } + enumerator->destroy(enumerator); + + return asn1_wrap(ASN1_SEQUENCE, "m", values); +} + +static bool equals(private_ietf_attributes_t *this, private_ietf_attributes_t *other) +{ + bool result = TRUE; + + /* lists must have the same number of attributes */ + if (other == NULL || + this->list->get_count(this->list) != other->list->get_count(other->list)) + { + return FALSE; + } + + /* compare two alphabetically-sorted lists */ + { + ietf_attr_t *attr_a, *attr_b; + enumerator_t *enum_a, *enum_b; + + enum_a = this->list->create_enumerator(this->list); + enum_b = other->list->create_enumerator(other->list); + while (enum_a->enumerate(enum_a, &attr_a) && + enum_b->enumerate(enum_b, &attr_b)) + { + if (attr_a->compare(attr_a, attr_b) != 0) + { + /* we have a mismatch */ + result = FALSE; + break; + } + } + enum_a->destroy(enum_a); + enum_b->destroy(enum_b); + } + return result; +} + +static bool matches(private_ietf_attributes_t *this, private_ietf_attributes_t *other) +{ + bool result = FALSE; + ietf_attr_t *attr_a, *attr_b; + enumerator_t *enum_a, *enum_b; + + /* always match if this->list does not contain any attributes */ + if (this->list->get_count(this->list) == 0) + { + return TRUE; + } + + /* never match if other->list does not contain any attributes */ + if (other == NULL || other->list->get_count(other->list) == 0) + { + return FALSE; + } + + /* get first attribute from both lists */ + enum_a = this->list->create_enumerator(this->list); + enum_a->enumerate(enum_a, &attr_a); + enum_b = other->list->create_enumerator(other->list); + enum_b->enumerate(enum_b, &attr_b); + + /* look for at least one common attribute */ + while (TRUE) + { + bool cmp = attr_a->compare(attr_a, attr_b); + + if (cmp == 0) + { + /* we have a match */ + result = TRUE; + break; + } + if (cmp == -1) + { + /* attr_a is earlier in the alphabet, get next attr_a */ + if (!enum_a->enumerate(enum_a, &attr_a)) + { + /* we have reached the end of enum_a */ + break; + } + } + else + { + /* attr_a is later in the alphabet, get next attr_b */ + if (!enum_b->enumerate(enum_b, &attr_b)) + { + /* we have reached the end of enum_b */ + break; + } + } + } + enum_a->destroy(enum_a); + enum_b->destroy(enum_b); + + return result; +} + +/** + * Implementation of ietf_attributes_t.get_ref + */ +static private_ietf_attributes_t* get_ref(private_ietf_attributes_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of ietf_attributes_t.destroy. + */ +static void destroy(private_ietf_attributes_t *this) +{ + if (ref_put(&this->ref)) + { + this->list->destroy_offset(this->list, offsetof(ietf_attr_t, destroy)); + free(this->string); + free(this); + } +} + +static private_ietf_attributes_t* create_empty(void) +{ + private_ietf_attributes_t *this = malloc_thing(private_ietf_attributes_t); + + this->public.get_string = (char* (*)(ietf_attributes_t*))get_string; + this->public.get_encoding = (chunk_t (*)(ietf_attributes_t*))get_encoding; + this->public.equals = (bool (*)(ietf_attributes_t*,ietf_attributes_t*))equals; + this->public.matches = (bool (*)(ietf_attributes_t*,ietf_attributes_t*))matches; + this->public.get_ref = (ietf_attributes_t* (*)(ietf_attributes_t*))get_ref; + this->public.destroy = (void (*)(ietf_attributes_t*))destroy; + + this->list = linked_list_create(); + this->string = NULL; + this->ref = 1; + return this; +} + +/** + * Adds an ietf_attr_t object to a sorted linked list + */ +static void ietf_attributes_add(private_ietf_attributes_t *this, + ietf_attr_t *attr) +{ + ietf_attr_t *current_attr; + bool found = FALSE; + iterator_t *iterator; + + iterator = this->list->create_iterator(this->list, TRUE); + while (iterator->iterate(iterator, (void **)¤t_attr)) + { + int cmp = attr->compare(attr, current_attr); + + if (cmp > 0) + { + continue; + } + if (cmp == 0) + { + attr->destroy(attr); + } + else + { + iterator->insert_before(iterator, attr); + } + found = TRUE; + break; + } + iterator->destroy(iterator); + if (!found) + { + this->list->insert_last(this->list, attr); + } +} + +/* + * Described in header. + */ +ietf_attributes_t *ietf_attributes_create_from_string(char *string) +{ + private_ietf_attributes_t *this = create_empty(); + + chunk_t line = { string, strlen(string) }; + + while (eat_whitespace(&line)) + { + chunk_t group; + + /* extract the next comma-separated group attribute */ + if (!extract_token(&group, ',', &line)) + { + group = line; + line.len = 0; + } + + /* remove any trailing spaces */ + while (group.len > 0 && *(group.ptr + group.len - 1) == ' ') + { + group.len--; + } + + /* add the group attribute to the list */ + if (group.len > 0) + { + ietf_attr_t *attr = ietf_attr_create(IETF_ATTRIBUTE_STRING, group); + + ietf_attributes_add(this, attr); + } + } + + return &(this->public); +} + +/** + * ASN.1 definition of ietfAttrSyntax + */ +static const asn1Object_t ietfAttrSyntaxObjects[] = +{ + { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | + ASN1_BODY }, /* 1 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ + { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */ + { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT | + ASN1_BODY }, /* 4 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ + { 2, "oid", ASN1_OID, ASN1_OPT | + ASN1_BODY }, /* 6 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ + { 2, "string", ASN1_UTF8STRING, ASN1_OPT | + ASN1_BODY }, /* 8 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ + { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define IETF_ATTR_OCTETS 4 +#define IETF_ATTR_OID 6 +#define IETF_ATTR_STRING 8 + +/* + * Described in header. + */ +ietf_attributes_t *ietf_attributes_create_from_encoding(chunk_t encoded) +{ + private_ietf_attributes_t *this = create_empty(); + asn1_parser_t *parser; + chunk_t object; + int objectID; + + parser = asn1_parser_create(ietfAttrSyntaxObjects, encoded); + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case IETF_ATTR_OCTETS: + case IETF_ATTR_OID: + case IETF_ATTR_STRING: + { + ietf_attribute_type_t type; + ietf_attr_t *attr; + + type = (objectID - IETF_ATTR_OCTETS) / 2; + attr = ietf_attr_create(type, object); + ietf_attributes_add(this, attr); + } + break; + default: + break; + } + } + parser->destroy(parser); + + return &(this->public); +} + diff --git a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h new file mode 100644 index 000000000..ab6bae984 --- /dev/null +++ b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2007-2009 Andreas Steffen + * + * HSR 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 ietf_attributes ietf_attributes + * @{ @ingroup credentials + */ + +#ifndef IETF_ATTRIBUTES_H_ +#define IETF_ATTRIBUTES_H_ + +typedef struct ietf_attributes_t ietf_attributes_t; + +#include <library.h> + +/** + * + */ +struct ietf_attributes_t { + + /** + * Get the an alphabetically sorted list of printable IETF attributes. + * + * Result points to internal data, do not free. + * + * @return a string containing printable attributes + */ + char* (*get_string) (ietf_attributes_t *this); + + /** + * Get the ASN.1 encoding of the IETF attributes. + * + * @return allocated chunk containing the encoded bytes + */ + chunk_t (*get_encoding) (ietf_attributes_t *this); + + /** + * Check for equality between two lists. + * + * @param other attribute list to be checked for equality + * @return TRUE if equal + */ + bool (*equals) (ietf_attributes_t *this, ietf_attributes_t *other); + + /** + * Check for common attributes between two lists. + * + * @param other attribute list to be matched + * @return TRUE if there is at least a common attribute + */ + bool (*matches) (ietf_attributes_t *this, ietf_attributes_t *other); + + /** + * Get a new reference to the IETF attributes. + * + * @return this, with an increased refcount + */ + ietf_attributes_t* (*get_ref)(ietf_attributes_t *this); + + /** + * Destroys an ietf_attributes_t object. + */ + void (*destroy) (ietf_attributes_t *this); +}; + +/** + * @param string input string, which will be converted + * @return ietf_attributes_t + */ +ietf_attributes_t *ietf_attributes_create_from_string(char *string); + +/** + * @param encoded ASN.1 encoded bytes, such as from ietf_attributes.get_encoding + * @return ietf_attributes_t + */ +ietf_attributes_t *ietf_attributes_create_from_encoding(chunk_t encoded); + +#endif /** IETF_ATTRIBUTES_H_ @}*/ + diff --git a/src/libstrongswan/plugins/x509/Makefile.am b/src/libstrongswan/plugins/x509/Makefile.am index 560e186e2..853b1cebc 100644 --- a/src/libstrongswan/plugins/x509/Makefile.am +++ b/src/libstrongswan/plugins/x509/Makefile.am @@ -11,7 +11,6 @@ libstrongswan_x509_la_SOURCES = x509_plugin.h x509_plugin.c \ x509_ac.h x509_ac.c \ x509_pkcs10.h x509_pkcs10.c \ x509_ocsp_request.h x509_ocsp_request.c \ - x509_ocsp_response.h x509_ocsp_response.c \ - ietf_attr_list.h ietf_attr_list.c + x509_ocsp_response.h x509_ocsp_response.c libstrongswan_x509_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/x509/ietf_attr_list.c b/src/libstrongswan/plugins/x509/ietf_attr_list.c deleted file mode 100644 index d1ba7266e..000000000 --- a/src/libstrongswan/plugins/x509/ietf_attr_list.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright (C) 2007 Andreas Steffen, Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <string.h> -#include <stdio.h> - -#include <debug.h> -#include <library.h> - -#include <asn1/oid.h> -#include <asn1/asn1.h> -#include <asn1/asn1_parser.h> -#include <utils/lexparser.h> - -#include "ietf_attr_list.h" - -/** - * Private definition of ietfAttribute kinds - */ -typedef enum { - IETF_ATTRIBUTE_OCTETS = 0, - IETF_ATTRIBUTE_OID = 1, - IETF_ATTRIBUTE_STRING = 2 -} ietfAttribute_t; - -typedef struct ietfAttr_t ietfAttr_t; - -/** - * Private definition of an ietfAttribute - */ -struct ietfAttr_t { - /** - * IETF attribute kind - */ - ietfAttribute_t kind; - - /** - * IETF attribute valuse - */ - chunk_t value; - - /** - * Compares two ietfAttributes - * - * return -1 if this is earlier in the alphabet than other - * return 0 if this equals other - * return +1 if this is later in the alphabet than other - * - * @param this calling object - * @param other other object - */ - int (*compare) (const ietfAttr_t *this ,const ietfAttr_t *other); - - /** - * Destroys the ietfAttr_t object. - * - * @param this ietfAttr_t to destroy - */ - void (*destroy) (ietfAttr_t *this); -}; - -/** - * Implements ietfAttr_t.compare. - */ -static int ietfAttr_compare(const ietfAttr_t *this ,const ietfAttr_t *other) -{ - int cmp_len, len, cmp_value; - - /* OID attributes are appended after STRING and OCTETS attributes */ - if (this->kind != IETF_ATTRIBUTE_OID && other->kind == IETF_ATTRIBUTE_OID) - { - return -1; - } - if (this->kind == IETF_ATTRIBUTE_OID && other->kind != IETF_ATTRIBUTE_OID) - { - return 1; - } - - cmp_len = this->value.len - other->value.len; - len = (cmp_len < 0)? this->value.len : other->value.len; - cmp_value = memcmp(this->value.ptr, other->value.ptr, len); - - return (cmp_value == 0)? cmp_len : cmp_value; -} - -/** - * Implements ietfAttr_t.destroy. - */ -static void ietfAttr_destroy(ietfAttr_t *this) -{ - free(this->value.ptr); - free(this); -} - -/** - * Creates an ietfAttr_t object. - */ -static ietfAttr_t *ietfAttr_create(ietfAttribute_t kind, chunk_t value) -{ - ietfAttr_t *this = malloc_thing(ietfAttr_t); - - /* initialize */ - this->kind = kind; - this->value = chunk_clone(value); - - /* function */ - this->compare = ietfAttr_compare; - this->destroy = ietfAttr_destroy; - - return this; -} - -/** - * Adds an ietfAttr_t object to a sorted linked list - */ -static void ietfAttr_add(linked_list_t *list, ietfAttr_t *attr) -{ - iterator_t *iterator = list->create_iterator(list, TRUE); - ietfAttr_t *current_attr; - bool found = FALSE; - - while (iterator->iterate(iterator, (void **)¤t_attr)) - { - int cmp = attr->compare(attr, current_attr); - - if (cmp > 0) - { - continue; - } - if (cmp == 0) - { - attr->destroy(attr); - } - else - { - iterator->insert_before(iterator, attr); - } - found = TRUE; - break; - } - iterator->destroy(iterator); - if (!found) - { - list->insert_last(list, attr); - } -} - -/* - * Described in header. - */ -bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b) -{ - bool result = TRUE; - - /* lists must have the same number of attributes */ - if (list_a->get_count(list_a) != list_b->get_count(list_b)) - { - return FALSE; - } - /* empty lists - no attributes */ - if (list_a->get_count(list_a) == 0) - { - return TRUE; - } - - /* compare two alphabetically-sorted lists */ - { - iterator_t *iterator_a = list_a->create_iterator(list_a, TRUE); - iterator_t *iterator_b = list_b->create_iterator(list_b, TRUE); - ietfAttr_t *attr_a, *attr_b; - - while (iterator_a->iterate(iterator_a, (void **)&attr_a) && - iterator_b->iterate(iterator_b, (void **)&attr_b)) - { - if (attr_a->compare(attr_a, attr_b) != 0) - { - /* we have a mismatch */ - result = FALSE; - break; - } - } - iterator_a->destroy(iterator_a); - iterator_b->destroy(iterator_b); - } - return result; -} - -/* - * Described in header. - */ -void ietfAttr_list_list(linked_list_t *list, FILE *out) -{ - iterator_t *iterator = list->create_iterator(list, TRUE); - ietfAttr_t *attr; - bool first = TRUE; - - while (iterator->iterate(iterator, (void **)&attr)) - { - if (first) - { - first = FALSE; - } - else - { - fprintf(out, ", "); - } - - switch (attr->kind) - { - case IETF_ATTRIBUTE_OCTETS: - case IETF_ATTRIBUTE_STRING: - fprintf(out, "%.*s", (int)attr->value.len, attr->value.ptr); - break; - case IETF_ATTRIBUTE_OID: - { - int oid = asn1_known_oid(attr->value); - - if (oid == OID_UNKNOWN) - { - fprintf(out, "0x#B", &attr->value); - } - else - { - fprintf(out, "%s", oid_names[oid]); - } - } - break; - default: - break; - } - } - iterator->destroy(iterator); -} - -/* - * Described in header. - */ -void ietfAttr_list_create_from_string(char *msg, linked_list_t *list) -{ - chunk_t line = { msg, strlen(msg) }; - - while (eat_whitespace(&line)) - { - chunk_t group; - - /* extract the next comma-separated group attribute */ - if (!extract_token(&group, ',', &line)) - { - group = line; - line.len = 0; - } - - /* remove any trailing spaces */ - while (group.len > 0 && *(group.ptr + group.len - 1) == ' ') - { - group.len--; - } - - /* add the group attribute to the list */ - if (group.len > 0) - { - ietfAttr_t *attr = ietfAttr_create(IETF_ATTRIBUTE_STRING, group); - - ietfAttr_add(list, attr); - } - } -} - -/** - * ASN.1 definition of ietfAttrSyntax - */ -static const asn1Object_t ietfAttrSyntaxObjects[] = -{ - { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | - ASN1_BODY }, /* 1 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ - { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */ - { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT | - ASN1_BODY }, /* 4 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ - { 2, "oid", ASN1_OID, ASN1_OPT | - ASN1_BODY }, /* 6 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ - { 2, "string", ASN1_UTF8STRING, ASN1_OPT | - ASN1_BODY }, /* 8 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define IETF_ATTR_OCTETS 4 -#define IETF_ATTR_OID 6 -#define IETF_ATTR_STRING 8 - -/* - * Described in header. - */ -void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - - parser = asn1_parser_create(ietfAttrSyntaxObjects, chunk); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case IETF_ATTR_OCTETS: - case IETF_ATTR_OID: - case IETF_ATTR_STRING: - { - ietfAttribute_t kind = (objectID - IETF_ATTR_OCTETS) / 2; - ietfAttr_t *attr = ietfAttr_create(kind, object); - ietfAttr_add(list, attr); - } - break; - default: - break; - } - } - parser->destroy(parser); -} - -/* - * Described in header. - */ -chunk_t ietfAttr_list_encode(linked_list_t *list) -{ - chunk_t ietfAttributes; - size_t size = 0; - u_char *pos; - iterator_t *iterator = list->create_iterator(list, TRUE); - ietfAttr_t *attr; - - /* precalculate the total size of all values */ - while (iterator->iterate(iterator, (void **)&attr)) - { - size_t len = attr->value.len; - - size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len; - } - iterator->destroy(iterator); - - pos = asn1_build_object(&ietfAttributes, ASN1_SEQUENCE, size); - - iterator = list->create_iterator(list, TRUE); - while (iterator->iterate(iterator, (void **)&attr)) - { - chunk_t ietfAttribute; - asn1_t type = ASN1_NULL; - - switch (attr->kind) - { - case IETF_ATTRIBUTE_OCTETS: - type = ASN1_OCTET_STRING; - break; - case IETF_ATTRIBUTE_STRING: - type = ASN1_UTF8STRING; - break; - case IETF_ATTRIBUTE_OID: - type = ASN1_OID; - break; - } - ietfAttribute = asn1_simple_object(type, attr->value); - - /* copy ietfAttribute into ietfAttributes chunk */ - memcpy(pos, ietfAttribute.ptr, ietfAttribute.len); - pos += ietfAttribute.len; - free(ietfAttribute.ptr); - } - iterator->destroy(iterator); - - return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes); -} - -/* - * Described in header. - */ -void ietfAttr_list_destroy(linked_list_t *list) -{ - list->destroy_offset(list, offsetof(ietfAttr_t, destroy)); -} diff --git a/src/libstrongswan/plugins/x509/ietf_attr_list.h b/src/libstrongswan/plugins/x509/ietf_attr_list.h deleted file mode 100644 index 124468bac..000000000 --- a/src/libstrongswan/plugins/x509/ietf_attr_list.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2007 Andreas Steffen - * - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ietf_attr_list ietf_attr_list - * @{ @ingroup x509_p - */ - -#ifndef IETF_ATTR_LIST_H_ -#define IETF_ATTR_LIST_H_ - -#include <library.h> -#include <utils/linked_list.h> - - -/** - * @brief Compare two linked lists of ietfAttr_t objects for equality - * - * @param list_a first alphabetically-sorted list - * @param list_b second alphabetically-sorted list - * @return TRUE if equal - */ -bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b); - -/** - * @brief Lists a linked list of ietfAttr_t objects - * - * @param list alphabetically-sorted linked list of attributes - * @param out output file - */ -void ietfAttr_list_list(linked_list_t *list, FILE *out); - -/** - * @brief Create a linked list of ietfAttr_t objects from a string - * - * @param msg string with comma-separated group names - * @param list alphabetically-sorted linked list of attributes - */ -void ietfAttr_list_create_from_string(char *msg, linked_list_t *list); - -/** - * @brief Create a linked list of ietfAttr_t objects from an ASN.1-coded chunk - * - * @param chunk chunk containing ASN.1-coded attributes - * @param list alphabetically-sorted linked list of attributes - * @param level0 parsing level - */ -void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0); - -/** - * @brief Encode a linked list of ietfAttr_t objects into an ASN.1-coded chunk - * - * @param list alphabetically-sorted linked list of attributes - * @return chunk containing ASN.1-coded attributes - */ -chunk_t ietfAttr_list_encode(linked_list_t *list); - -/** - * @brief Destroys a linked list of ietfAttr_t objects - * - * @param list list to be destroyed - */ -void ietfAttr_list_destroy(linked_list_t *list); - -#endif /** IETF_ATTR_LIST_H_ @}*/ - diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index 878406a71..5e8ea2e71 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -1,10 +1,10 @@ /* * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler * Copyright (C) 2003 Martin Berner, Lukas Suter - * Copyright (C) 2002-2008 Andreas Steffen + * Copyright (C) 2002-2009 Andreas Steffen * Copyright (C) 2009 Martin Willi * - * Hochschule fuer Technik Rapperswil + * HSR 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 @@ -18,7 +18,6 @@ */ #include "x509_ac.h" -#include "ietf_attr_list.h" #include <time.h> @@ -30,6 +29,7 @@ #include <utils/identification.h> #include <utils/linked_list.h> #include <credentials/certificates/x509.h> +#include <credentials/ietf_attributes/ietf_attributes.h> #include <credentials/keys/private_key.h> extern chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, @@ -100,12 +100,12 @@ struct private_x509_ac_t { /** * List of charging attributes */ - linked_list_t *charging; + ietf_attributes_t *charging; /** * List of groub attributes */ - linked_list_t *groups; + ietf_attributes_t *groups; /** * Authority Key Identifier @@ -413,10 +413,14 @@ static bool parse_certificate(private_x509_ac_t *this) DBG2(" need to parse accessIdentity"); break; case OID_CHARGING_IDENTITY: - ietfAttr_list_create_from_chunk(object, this->charging, level); + DBG2("-- > --"); + this->charging = ietf_attributes_create_from_encoding(object); + DBG2("-- < --"); break; case OID_GROUP: - ietfAttr_list_create_from_chunk(object, this->groups, level); + DBG2("-- > --"); + this->groups = ietf_attributes_create_from_encoding(object); + DBG2("-- < --"); break; case OID_ROLE: parse_roleSyntax(object, level); @@ -543,7 +547,7 @@ static chunk_t build_attribute_type(int type, chunk_t content) static chunk_t build_attributes(private_x509_ac_t *this) { return asn1_wrap(ASN1_SEQUENCE, "m", - build_attribute_type(OID_GROUP, ietfAttr_list_encode(this->groups))); + build_attribute_type(OID_GROUP, this->groups->get_encoding(this->groups))); } /** @@ -664,6 +668,14 @@ static chunk_t get_authKeyIdentifier(private_x509_ac_t *this) } /** + * Implementation of certificate_t.get_groups. + */ +static ietf_attributes_t* get_groups(private_x509_ac_t *this) +{ + return this->groups ? this->groups->get_ref(this->groups) : NULL; +} + +/** * Implementation of certificate_t.get_type */ static certificate_type_t get_type(private_x509_ac_t *this) @@ -881,9 +893,8 @@ static void destroy(private_x509_ac_t *this) DESTROY_IF(this->holderCert); DESTROY_IF(this->signerCert); DESTROY_IF(this->signerKey); - - ietfAttr_list_destroy(this->charging); - ietfAttr_list_destroy(this->groups); + DESTROY_IF(this->charging); + DESTROY_IF(this->groups); free(this->serialNumber.ptr); free(this->authKeyIdentifier.ptr); free(this->encoding.ptr); @@ -902,7 +913,8 @@ static private_x509_ac_t *create_empty(void) this->public.interface.get_serial = (chunk_t (*)(ac_t*))get_serial; this->public.interface.get_holderSerial = (chunk_t (*)(ac_t*))get_holderSerial; this->public.interface.get_holderIssuer = (identification_t* (*)(ac_t*))get_holderIssuer; - this->public.interface.get_authKeyIdentifier = (chunk_t(*)(ac_t*))get_authKeyIdentifier; + this->public.interface.get_authKeyIdentifier = (chunk_t (*)(ac_t*))get_authKeyIdentifier; + this->public.interface.get_groups = (ietf_attributes_t* (*)(ac_t*))get_groups; this->public.interface.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type; this->public.interface.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_subject; this->public.interface.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; @@ -928,8 +940,8 @@ static private_x509_ac_t *create_empty(void) this->holderCert = NULL; this->signerCert = NULL; this->signerKey = NULL; - this->charging = linked_list_create(); - this->groups = linked_list_create(); + this->charging = NULL; + this->groups = NULL; this->ref = 1; return this; @@ -992,7 +1004,7 @@ x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args) ac->serialNumber = chunk_clone(va_arg(args, chunk_t)); continue; case BUILD_IETF_GROUP_ATTR: - ietfAttr_list_create_from_string(va_arg(args, char*), ac->groups); + ac->groups = ietf_attributes_create_from_string(va_arg(args, char*)); continue; case BUILD_CERT: ac->holderCert = va_arg(args, certificate_t*); diff --git a/src/openac/openac.c b/src/openac/openac.c index 407ce3608..89acc06b9 100755 --- a/src/openac/openac.c +++ b/src/openac/openac.c @@ -448,7 +448,6 @@ int main(int argc, char **argv) signerCert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, certfile, - BUILD_X509_FLAG, 0, BUILD_END); if (signerCert == NULL) { @@ -462,7 +461,6 @@ int main(int argc, char **argv) userCert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, usercertfile, - BUILD_X509_FLAG, 0, BUILD_END); if (userCert == NULL) { diff --git a/src/pluto/ac.c b/src/pluto/ac.c index 96cc9b274..e35245845 100644 --- a/src/pluto/ac.c +++ b/src/pluto/ac.c @@ -1,6 +1,7 @@ /* Support of X.509 attribute certificates * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler * Copyright (C) 2003 Martin Berner, Lukas Suter + * Copyright (C) 2009 Andreas Steffen * * 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 @@ -18,16 +19,12 @@ #include <string.h> #include <unistd.h> #include <dirent.h> -#include <time.h> #include <sys/types.h> #include <freeswan.h> #include <utils.h> -#include <asn1/asn1.h> -#include <asn1/asn1_parser.h> -#include <asn1/oid.h> -#include <credentials/certificates/certificate.h> +#include <credentials/certificates/ac.h> #include "ac.h" #include "x509.h" @@ -45,597 +42,13 @@ static x509acert_t *x509acerts = NULL; /** - * Chained list of ietfAttributes - */ -static ietfAttrList_t *ietfAttributes = NULL; - -/** - * ASN.1 definition of ietfAttrSyntax - */ -static const asn1Object_t ietfAttrSyntaxObjects[] = -{ - { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | - ASN1_BODY }, /* 1 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ - { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */ - { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT | - ASN1_BODY }, /* 4 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ - { 2, "oid", ASN1_OID, ASN1_OPT | - ASN1_BODY }, /* 6 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ - { 2, "string", ASN1_UTF8STRING, ASN1_OPT | - ASN1_BODY }, /* 8 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; - -#define IETF_ATTR_OCTETS 4 -#define IETF_ATTR_OID 6 -#define IETF_ATTR_STRING 8 - -/** - * ASN.1 definition of roleSyntax - */ -static const asn1Object_t roleSyntaxObjects[] = -{ - { 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | - ASN1_OBJ }, /* 1 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ - { 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ }, /* 3 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; - -/** - * ASN.1 definition of an X509 attribute certificate - */ -static const asn1Object_t acObjects[] = -{ - { 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ - { 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "version", ASN1_INTEGER, ASN1_DEF | - ASN1_BODY }, /* 2 */ - { 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ - { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */ - { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ - { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */ - { 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | - ASN1_BODY }, /* 7 */ - { 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ - { 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT | - ASN1_OBJ }, /* 10 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ - { 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */ - { 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13 */ - { 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT | - ASN1_BODY }, /* 14 */ - { 4, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ - { 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */ - { 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */ - { 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT | - ASN1_OBJ }, /* 19 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ - { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */ - { 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ - { 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */ - { 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */ - { 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | - ASN1_BODY }, /* 25 */ - { 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */ - { 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */ - { 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */ - { 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */ - { 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT | - ASN1_BODY }, /* 31 */ - { 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */ - { 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */ - { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */ - { 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */ - { 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */ - { 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */ - { 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */ - { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */ - { 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */ - { 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */ - { 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */ - { 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */ - { 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */ - { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */ - { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */ - { 4, "critical", ASN1_BOOLEAN, ASN1_DEF | - ASN1_BODY }, /* 50 */ - { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */ - { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 54 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; - -#define AC_OBJ_CERTIFICATE 0 -#define AC_OBJ_CERTIFICATE_INFO 1 -#define AC_OBJ_VERSION 2 -#define AC_OBJ_HOLDER_ISSUER 5 -#define AC_OBJ_HOLDER_SERIAL 6 -#define AC_OBJ_ENTITY_NAME 10 -#define AC_OBJ_ISSUER_NAME 19 -#define AC_OBJ_ISSUER 23 -#define AC_OBJ_SIG_ALG 35 -#define AC_OBJ_SERIAL_NUMBER 36 -#define AC_OBJ_NOT_BEFORE 38 -#define AC_OBJ_NOT_AFTER 39 -#define AC_OBJ_ATTRIBUTE_TYPE 42 -#define AC_OBJ_ATTRIBUTE_VALUE 44 -#define AC_OBJ_EXTN_ID 49 -#define AC_OBJ_CRITICAL 50 -#define AC_OBJ_EXTN_VALUE 51 -#define AC_OBJ_ALGORITHM 53 -#define AC_OBJ_SIGNATURE 54 - -const x509acert_t empty_ac = { - NULL , /* *next */ - 0 , /* installed */ - { NULL, 0 }, /* certificate */ - { NULL, 0 }, /* certificateInfo */ - 1 , /* version */ - /* holder */ - /* baseCertificateID */ - { NULL, 0 }, /* holderIssuer */ - { NULL, 0 }, /* holderSerial */ - /* entityName */ - { NULL, 0 }, /* generalNames */ - /* v2Form */ - { NULL, 0 }, /* issuerName */ - /* signature */ - OID_UNKNOWN, /* sigAlg */ - { NULL, 0 }, /* serialNumber */ - /* attrCertValidityPeriod */ - 0 , /* notBefore */ - 0 , /* notAfter */ - /* attributes */ - NULL , /* charging */ - NULL , /* groups */ - /* extensions */ - { NULL, 0 }, /* authKeyID */ - { NULL, 0 }, /* authKeySerialNumber */ - FALSE , /* noRevAvail */ - /* signatureAlgorithm */ - OID_UNKNOWN, /* algorithm */ - { NULL, 0 }, /* signature */ -}; - - -/** - * compare two ietfAttributes, returns zero if a equals b - * negative/positive if a is earlier/later in the alphabet than b - */ -static int cmp_ietfAttr(ietfAttr_t *a,ietfAttr_t *b) -{ - int cmp_len, len, cmp_value; - - /* cannot compare OID with STRING or OCTETS attributes */ - if (a->kind == IETF_ATTRIBUTE_OID && b->kind != IETF_ATTRIBUTE_OID) - return 1; - - cmp_len = a->value.len - b->value.len; - len = (cmp_len < 0)? a->value.len : b->value.len; - cmp_value = memcmp(a->value.ptr, b->value.ptr, len); - - return (cmp_value == 0)? cmp_len : cmp_value; -} - -/** - * add an ietfAttribute to the chained list - */ -static ietfAttr_t* add_ietfAttr(ietfAttr_t *attr) -{ - ietfAttrList_t **listp = &ietfAttributes; - ietfAttrList_t *list = *listp; - int cmp = -1; - - while (list != NULL) - { - cmp = cmp_ietfAttr(attr, list->attr); - if (cmp <= 0) - break; - listp = &list->next; - list = *listp; - } - - if (cmp == 0) - { - /* attribute already exists, increase count */ - free(attr); - list->attr->count++; - return list->attr; - } - else - { - ietfAttrList_t *el = malloc_thing(ietfAttrList_t); - - /* new attribute, unshare value */ - attr->value = chunk_clone(attr->value); - attr->count = 1; - time(&attr->installed); - - el->attr = attr; - el->next = list; - *listp = el; - - return attr; - } -} - -/** - * decodes a comma separated list of group attributes - */ -void decode_groups(char *groups, ietfAttrList_t **listp) -{ - if (groups == NULL) - return; - - while (strlen(groups) > 0) - { - char *end; - char *next = strchr(groups, ','); - - if (next == NULL) - end = next = groups + strlen(groups); - else - end = next++; - - /* eat preceeding whitespace */ - while (groups < end && *groups == ' ') - groups++; - - /* eat trailing whitespace */ - while (end > groups && *(end-1) == ' ') - end--; - - if (groups < end) - { - ietfAttr_t *attr = malloc_thing(ietfAttr_t); - ietfAttrList_t *el = malloc_thing(ietfAttrList_t); - - attr->kind = IETF_ATTRIBUTE_STRING; - attr->value.ptr = groups; - attr->value.len = end - groups; - attr->count = 0; - - el->attr = add_ietfAttr(attr); - el->next = *listp; - *listp = el; - } - - groups = next; - } -} - -static bool same_attribute(const ietfAttr_t *a, const ietfAttr_t *b) -{ - return (a->kind == b->kind && a->value.len == b->value.len - && memeq(a->value.ptr, b->value.ptr, b->value.len)); -} - -bool group_membership(const ietfAttrList_t *peer_list - , const char *conn - , const ietfAttrList_t *conn_list) -{ - if (conn_list == NULL) - return TRUE; - - while (peer_list != NULL) - { - const ietfAttr_t *peer_attr = peer_list->attr; - const ietfAttrList_t *list = conn_list; - - while (list != NULL) - { - ietfAttr_t *conn_attr = list->attr; - - if (same_attribute(conn_attr, peer_attr)) - { - DBG(DBG_CONTROL, - DBG_log("%s: peer matches group '%.*s'" - , conn - , (int)peer_attr->value.len, peer_attr->value.ptr) - ) - return TRUE; - } - list = list->next; - } - peer_list = peer_list->next; - } - DBG(DBG_CONTROL, - DBG_log("%s: peer doesn't match any group", conn) - ) - return FALSE; -} - -void unshare_ietfAttrList(ietfAttrList_t **listp) -{ - ietfAttrList_t *list = *listp; - - while (list != NULL) - { - ietfAttrList_t *el = malloc_thing(ietfAttrList_t); - - el->attr = list->attr; - el->attr->count++; - el->next = NULL; - *listp = el; - listp = &el->next; - list = list->next; - } -} - -/** - * Parses ietfAttrSyntax - */ -static ietfAttrList_t* parse_ietfAttrSyntax(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - - ietfAttrList_t *list = NULL; - - parser = asn1_parser_create(ietfAttrSyntaxObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case IETF_ATTR_OCTETS: - case IETF_ATTR_OID: - case IETF_ATTR_STRING: - { - ietfAttr_t *attr = malloc_thing(ietfAttr_t); - ietfAttrList_t *el = malloc_thing(ietfAttrList_t); - - attr->kind = (objectID - IETF_ATTR_OCTETS) / 2; - attr->value = object; - attr->count = 0; - - el->attr = add_ietfAttr(attr); - el->next = list; - list = el; - } - break; - default: - break; - } - } - parser->destroy(parser); - return list; -} - -/** - * Parses roleSyntax - */ -static void parse_roleSyntax(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - - parser = asn1_parser_create(roleSyntaxObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - default: - break; - } - } - parser->destroy(parser); -} - -/** - * Parses an X.509 attribute certificate - */ -bool parse_ac(chunk_t blob, x509acert_t *ac) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - int type = OID_UNKNOWN; - int extn_oid = OID_UNKNOWN; - bool success = FALSE; - bool critical; - - parser = asn1_parser_create(acObjects, blob); - - while (parser->iterate(parser, &objectID, &object)) - { - u_int level = parser->get_level(parser)+1; - - switch (objectID) - { - case AC_OBJ_CERTIFICATE: - ac->certificate = object; - break; - case AC_OBJ_CERTIFICATE_INFO: - ac->certificateInfo = object; - break; - case AC_OBJ_VERSION: - ac->version = (object.len) ? (1 + (u_int)*object.ptr) : 1; - DBG(DBG_PARSING, - DBG_log(" v%d", ac->version); - ) - if (ac->version != 2) - { - plog("v%d attribute certificates are not supported" - , ac->version); - goto end; - } - break; - case AC_OBJ_HOLDER_ISSUER: - ac->holderIssuer = get_directoryName(object, level, FALSE); - break; - case AC_OBJ_HOLDER_SERIAL: - ac->holderSerial = object; - break; - case AC_OBJ_ENTITY_NAME: - ac->entityName = get_directoryName(object, level, TRUE); - break; - case AC_OBJ_ISSUER_NAME: - ac->issuerName = get_directoryName(object, level, FALSE); - break; - case AC_OBJ_SIG_ALG: - ac->sigAlg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case AC_OBJ_SERIAL_NUMBER: - ac->serialNumber = object; - break; - case AC_OBJ_NOT_BEFORE: - ac->notBefore = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case AC_OBJ_NOT_AFTER: - ac->notAfter = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case AC_OBJ_ATTRIBUTE_TYPE: - type = asn1_known_oid(object); - break; - case AC_OBJ_ATTRIBUTE_VALUE: - { - switch (type) { - case OID_AUTHENTICATION_INFO: - DBG(DBG_PARSING, - DBG_log(" need to parse authenticationInfo") - ) - break; - case OID_ACCESS_IDENTITY: - DBG(DBG_PARSING, - DBG_log(" need to parse accessIdentity") - ) - break; - case OID_CHARGING_IDENTITY: - ac->charging = parse_ietfAttrSyntax(object, level); - break; - case OID_GROUP: - ac->groups = parse_ietfAttrSyntax(object, level); - break; - case OID_ROLE: - parse_roleSyntax(object, level); - break; - default: - break; - } - } - break; - case AC_OBJ_EXTN_ID: - extn_oid = asn1_known_oid(object); - break; - case AC_OBJ_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - break; - case AC_OBJ_EXTN_VALUE: - { - switch (extn_oid) { - case OID_CRL_DISTRIBUTION_POINTS: - DBG(DBG_PARSING, - DBG_log(" need to parse crlDistributionPoints") - ) - break; - case OID_AUTHORITY_KEY_ID: - parse_authorityKeyIdentifier(object, level - , &ac->authKeyID, &ac->authKeySerialNumber); - break; - case OID_TARGET_INFORMATION: - DBG(DBG_PARSING, - DBG_log(" need to parse targetInformation") - ) - break; - case OID_NO_REV_AVAIL: - ac->noRevAvail = TRUE; - break; - default: - break; - } - } - break; - case AC_OBJ_ALGORITHM: - ac->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case AC_OBJ_SIGNATURE: - ac->signature = object; - break; - - default: - break; - } - } - success = parser->success(parser); - time(&ac->installed); - -end: - parser->destroy(parser); - return success; -} - -/** - * Release an ietfAttribute, free it if count reaches zero - */ -static void release_ietfAttr(ietfAttr_t* attr) -{ - if (--attr->count == 0) - { - ietfAttrList_t **plist = &ietfAttributes; - ietfAttrList_t *list = *plist; - - while (list->attr != attr) - { - plist = &list->next; - list = *plist; - } - *plist = list->next; - - free(attr->value.ptr); - free(attr); - free(list); - } -} - -/** - * Free an ietfAttrList - */ -void free_ietfAttrList(ietfAttrList_t* list) -{ - while (list != NULL) - { - ietfAttrList_t *el = list; - - release_ietfAttr(el->attr); - list = list->next; - free(el); - } -} - -/** * Free a X.509 attribute certificate */ void free_acert(x509acert_t *ac) { - if (ac != NULL) + if (ac) { - free_ietfAttrList(ac->charging); - free_ietfAttrList(ac->groups); - free(ac->certificate.ptr); + DESTROY_IF(ac->ac); free(ac); } } @@ -656,7 +69,9 @@ static void free_first_acert(void) void free_acerts(void) { while (x509acerts != NULL) + { free_first_acert(); + } } /** @@ -664,25 +79,30 @@ void free_acerts(void) */ x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial) { - x509acert_t *ac = x509acerts; + x509acert_t *x509ac = x509acerts; x509acert_t *prev_ac = NULL; - while (ac != NULL) + while (x509ac != NULL) { - if (same_dn(issuer, ac->holderIssuer) && - chunk_equals(serial, ac->holderSerial)) + ac_t *ac = (ac_t*)x509ac->ac; + identification_t *holderIssuer = ac->get_holderIssuer(ac); + chunk_t holderIssuer_dn = holderIssuer->get_encoding(holderIssuer); + chunk_t holderSerial = ac->get_holderSerial(ac); + + if (same_dn(issuer, holderIssuer_dn) && + chunk_equals(serial, holderSerial)) { - if (ac!= x509acerts) + if (x509ac!= x509acerts) { /* bring the certificate up front */ - prev_ac->next = ac->next; - ac->next = x509acerts; - x509acerts = ac; + prev_ac->next = x509ac->next; + x509ac->next = x509acerts; + x509acerts = x509ac; } - return ac; + return x509ac; } - prev_ac = ac; - ac = ac->next; + prev_ac = x509ac; + x509ac = x509ac->next; } return NULL; } @@ -690,13 +110,19 @@ x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial) /** * Add a X.509 attribute certificate to the chained list */ -static void add_acert(x509acert_t *ac) +static void add_acert(x509acert_t *x509ac) { - x509acert_t *old_ac = get_x509acert(ac->holderIssuer, ac->holderSerial); - + certificate_t *cert_ac = x509ac->ac; + ac_t *ac = (ac_t*)cert_ac; + identification_t *holderIssuer = ac->get_holderIssuer(ac); + chunk_t holderIssuer_dn = holderIssuer->get_encoding(holderIssuer); + chunk_t holderSerial = ac->get_serial(ac); + x509acert_t *old_ac; + + old_ac = get_x509acert(holderIssuer_dn, holderSerial); if (old_ac != NULL) { - if (ac->notBefore >old_ac->notBefore) + if (cert_ac->is_newer(cert_ac, old_ac->ac)) { /* delete the old attribute cert */ free_first_acert(); @@ -709,70 +135,46 @@ static void add_acert(x509acert_t *ac) DBG(DBG_CONTROL, DBG_log("attribute cert is not newer - existing cert kept"); ) - free_acert(ac); + free_acert(x509ac); return; } } plog("attribute cert added"); /* insert new attribute cert at the root of the chain */ - ac->next = x509acerts; - x509acerts = ac; -} - -/** - * Verify the validity of an attribute certificate by - * checking the notBefore and notAfter dates - */ -static err_t check_ac_validity(const x509acert_t *ac) -{ - time_t current_time; - - time(¤t_time); - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" not before : %T", &ac->notBefore, TRUE); - DBG_log(" current time: %T", ¤t_time, TRUE); - DBG_log(" not after : %T", &ac->notAfter, TRUE); - ) - - if (current_time < ac->notBefore) - return "attribute certificate is not valid yet"; - if (current_time > ac->notAfter) - return "attribute certificate has expired"; - else - return NULL; + x509ac->next = x509acerts; + x509acerts = x509ac; } /** * verifies a X.509 attribute certificate */ -bool verify_x509acert(x509acert_t *ac, bool strict) +bool verify_x509acert(x509acert_t *x509ac, bool strict) { - u_char buf[BUF_LEN]; + certificate_t *cert_ac = x509ac->ac; + ac_t *ac = (ac_t*)cert_ac; + identification_t *subject = cert_ac->get_subject(cert_ac); + identification_t *issuer = cert_ac->get_issuer(cert_ac); + chunk_t issuer_dn = issuer->get_encoding(issuer); + chunk_t authKeyID = ac->get_authKeyIdentifier(ac); x509cert_t *aacert; - err_t ugh = NULL; - time_t valid_until = ac->notAfter; + time_t valid_until; DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, ac->entityName); - DBG_log("holder: '%s'",buf); - dntoa(buf, BUF_LEN, ac->issuerName); - DBG_log("issuer: '%s'",buf); + DBG_log("holder: '%Y'", subject); + DBG_log("issuer: '%Y'", issuer); ) - ugh = check_ac_validity(ac); - - if (ugh != NULL) + if (!cert_ac->get_validity(cert_ac, NULL, NULL, &valid_until)) { - plog("%s", ugh); return FALSE; } DBG(DBG_CONTROL, - DBG_log("attribute certificate is valid") + DBG_log("attribute certificate is valid until %T", &valid_until, TRUE) ) lock_authcert_list("verify_x509acert"); - aacert = get_authcert(ac->issuerName, ac->authKeyID, AUTH_AA); + aacert = get_authcert(issuer_dn, authKeyID, X509_AA); unlock_authcert_list("verify_x509acert"); if (aacert == NULL) @@ -784,8 +186,7 @@ bool verify_x509acert(x509acert_t *ac, bool strict) DBG_log("issuer aacert found") ) - if (!x509_check_signature(ac->certificateInfo, ac->signature, ac->algorithm, - aacert->cert)) + if (!cert_ac->issued_by(cert_ac, aacert->cert)) { plog("attribute certificate signature is invalid"); return FALSE; @@ -798,6 +199,31 @@ bool verify_x509acert(x509acert_t *ac, bool strict) } /** + * Check if at least one peer attribute matches a connection attribute + */ +bool match_group_membership(ietf_attributes_t *peer_attributes, char *conn, + ietf_attributes_t *conn_attributes) +{ + bool match; + + if (conn_attributes == NULL) + { + return TRUE; + } + + match = conn_attributes->matches(conn_attributes, peer_attributes); + DBG(DBG_CONTROL, + DBG_log("%s: peer with attributes '%s' is %sa member of the groups '%s'", + conn, + peer_attributes->get_string(peer_attributes), + match ? "" : "not ", + conn_attributes->get_string(conn_attributes)) + ) + return match; + +} + +/** * Loads X.509 attribute certificates */ void load_acerts(void) @@ -840,141 +266,82 @@ void load_acerts(void) } /** - * lists group attributes separated by commas on a single line - */ -void format_groups(const ietfAttrList_t *list, char *buf, int len) -{ - bool first_group = TRUE; - - while (list != NULL && len > 0) - { - ietfAttr_t *attr = list->attr; - - if (attr->kind == IETF_ATTRIBUTE_OCTETS - || attr->kind == IETF_ATTRIBUTE_STRING) - { - int written = snprintf(buf, len, "%s%.*s" - , (first_group)? "" : ", " - , (int)attr->value.len, attr->value.ptr); - - first_group = FALSE; - - /* return value of snprintf() up to glibc 2.0.6 */ - if (written < 0) - break; - - buf += written; - len -= written; - } - list = list->next; - } -} - -/** * list all X.509 attribute certificates in the chained list */ void list_acerts(bool utc) { - x509acert_t *ac = x509acerts; + x509acert_t *x509ac = x509acerts; time_t now; /* determine the current time */ time(&now); - if (ac != NULL) + if (x509ac) { whack_log(RC_COMMENT, " "); whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:"); whack_log(RC_COMMENT, " "); } - while (ac != NULL) + while (x509ac) { - u_char buf[BUF_LEN]; + certificate_t *cert_ac = x509ac->ac; + ac_t *ac = (ac_t*)cert_ac; + identification_t *entityName, *holderIssuer, *issuer; + chunk_t holderSerial, serial, authKeyID; + time_t notBefore, notAfter; + ietf_attributes_t *groups; - whack_log(RC_COMMENT, "%T", &ac->installed, utc); - if (ac->entityName.ptr != NULL) - { - dntoa(buf, BUF_LEN, ac->entityName); - whack_log(RC_COMMENT, " holder: '%s'", buf); - } - if (ac->holderIssuer.ptr != NULL) - { - dntoa(buf, BUF_LEN, ac->holderIssuer); - whack_log(RC_COMMENT, " hissuer: '%s'", buf); - } - if (ac->holderSerial.ptr != NULL) + + whack_log(RC_COMMENT, "%T", &x509ac->installed, utc); + + entityName = cert_ac->get_subject(cert_ac); + if (entityName) { - datatot(ac->holderSerial.ptr, ac->holderSerial.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " hserial: %s", buf); + whack_log(RC_COMMENT, " holder: '%Y'", entityName); } - if (ac->groups != NULL) + + holderIssuer = ac->get_holderIssuer(ac); + if (holderIssuer) { - format_groups(ac->groups, buf, BUF_LEN); - whack_log(RC_COMMENT, " groups: %s", buf); + whack_log(RC_COMMENT, " hissuer: '%Y'", holderIssuer); } - dntoa(buf, BUF_LEN, ac->issuerName); - whack_log(RC_COMMENT, " issuer: '%s'", buf); - datatot(ac->serialNumber.ptr, ac->serialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " serial: %s", buf); - whack_log(RC_COMMENT, " validity: not before %T %s", - &ac->notBefore, utc, - (ac->notBefore < now)?"ok":"fatal (not valid yet)"); - whack_log(RC_COMMENT, " not after %T %s", - &ac->notAfter, utc, - check_expiry(ac->notAfter, ACERT_WARNING_INTERVAL, TRUE)); - if (ac->authKeyID.ptr != NULL) + + holderSerial = ac->get_holderSerial(ac); + if (holderSerial.ptr) { - datatot(ac->authKeyID.ptr, ac->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); + whack_log(RC_COMMENT, " hserial: %#B", &holderSerial); } - if (ac->authKeySerialNumber.ptr != NULL) + + groups = ac->get_groups(ac); + if (groups) { - datatot(ac->authKeySerialNumber.ptr, ac->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + whack_log(RC_COMMENT, " groups: %s", + groups->get_string(groups)); + groups->destroy(groups); } - ac = ac->next; - } -} + issuer = cert_ac->get_issuer(cert_ac); + whack_log(RC_COMMENT, " issuer: '%Y'", issuer); -/** - * list all group attributes in alphabetical order - */ -void list_groups(bool utc) -{ - ietfAttrList_t *list = ietfAttributes; + serial = ac->get_serial(ac); + whack_log(RC_COMMENT, " serial: %#B", &serial); - if (list != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of Group Attributes:"); - whack_log(RC_COMMENT, " "); - } - - while (list != NULL) - { - ietfAttr_t *attr = list->attr; - - whack_log(RC_COMMENT, "%T, count: %d", &attr->installed, utc, attr->count); + cert_ac->get_validity(cert_ac, &now, ¬Before, ¬After); + whack_log(RC_COMMENT, " validity: not before %T %s", + ¬Before, utc, + (notBefore < now)?"ok":"fatal (not valid yet)"); + whack_log(RC_COMMENT, " not after %T %s", + ¬After, utc, + check_expiry(notAfter, ACERT_WARNING_INTERVAL, TRUE)); - switch (attr->kind) + authKeyID = ac->get_authKeyIdentifier(ac); + if (authKeyID.ptr) { - case IETF_ATTRIBUTE_OCTETS: - case IETF_ATTRIBUTE_STRING: - whack_log(RC_COMMENT, " %.*s", (int)attr->value.len, attr->value.ptr); - break; - case IETF_ATTRIBUTE_OID: - whack_log(RC_COMMENT, " OID"); - break; - default: - break; + whack_log(RC_COMMENT, " authkey: %#B", &authKeyID); } - list = list->next; + x509ac = x509ac->next; } } + diff --git a/src/pluto/ac.h b/src/pluto/ac.h index bee016143..d1feb5570 100644 --- a/src/pluto/ac.h +++ b/src/pluto/ac.h @@ -1,6 +1,7 @@ /* Support of X.509 attribute certificates * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler * Copyright (C) 2003 Martin Berner, Lukas Suter + * Copyright (C) 2009 Andreas Steffen * * This program is free software; you can redistribute it and/or modify it @@ -17,85 +18,28 @@ #ifndef _AC_H #define _AC_H -/* definition of ietfAttribute kinds */ - -typedef enum { - IETF_ATTRIBUTE_OCTETS = 0, - IETF_ATTRIBUTE_OID = 1, - IETF_ATTRIBUTE_STRING = 2 -} ietfAttribute_t; - -/* access structure for an ietfAttribute */ - -typedef struct ietfAttr ietfAttr_t; - -struct ietfAttr { - time_t installed; - int count; - ietfAttribute_t kind; - chunk_t value; -}; - -typedef struct ietfAttrList ietfAttrList_t; - -struct ietfAttrList { - ietfAttrList_t *next; - ietfAttr_t *attr; -}; +#include <time.h> +#include <credentials/certificates/certificate.h> +#include <credentials/ietf_attributes/ietf_attributes.h> /* access structure for an X.509 attribute certificate */ typedef struct x509acert x509acert_t; struct x509acert { - x509acert_t *next; - time_t installed; - chunk_t certificate; - chunk_t certificateInfo; - u_int version; - /* holder */ - /* baseCertificateID */ - chunk_t holderIssuer; - chunk_t holderSerial; - chunk_t entityName; - /* v2Form */ - chunk_t issuerName; - /* signature */ - int sigAlg; - chunk_t serialNumber; - /* attrCertValidityPeriod */ - time_t notBefore; - time_t notAfter; - /* attributes */ - ietfAttrList_t *charging; - ietfAttrList_t *groups; - /* extensions */ - chunk_t authKeyID; - chunk_t authKeySerialNumber; - bool noRevAvail; - /* signatureAlgorithm */ - int algorithm; - chunk_t signature; + certificate_t *ac; + x509acert_t *next; + time_t installed; }; -/* used for initialization */ -extern const x509acert_t empty_ac; - -extern void unshare_ietfAttrList(ietfAttrList_t **listp); -extern void free_ietfAttrList(ietfAttrList_t *list); -extern void decode_groups(char *groups, ietfAttrList_t **listp); -extern bool group_membership(const ietfAttrList_t *my_list - , const char *conn, const ietfAttrList_t *conn_list); -extern bool parse_ac(chunk_t blob, x509acert_t *ac); extern bool verify_x509acert(x509acert_t *ac, bool strict); +extern bool match_group_membership(ietf_attributes_t *peer_attributes, char *conn, + ietf_attributes_t *conn_attributes); extern x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial); extern void load_acerts(void); extern void free_acert(x509acert_t *ac); extern void free_acerts(void); extern void list_acerts(bool utc); -extern void list_groups(bool utc); -extern void format_groups(const ietfAttrList_t *list, char *buf, int len); - #endif /* _AH_H */ diff --git a/src/pluto/builder.c b/src/pluto/builder.c index 8a90e05af..b8b9aac35 100644 --- a/src/pluto/builder.c +++ b/src/pluto/builder.c @@ -40,6 +40,7 @@ */ static cert_t *builder_load_cert(certificate_type_t type, va_list args) { + x509_flag_t flags = 0; chunk_t blob = chunk_empty; bool pgp = FALSE; @@ -53,6 +54,9 @@ static cert_t *builder_load_cert(certificate_type_t type, va_list args) case BUILD_BLOB_ASN1_DER: blob = va_arg(args, chunk_t); continue; + case BUILD_X509_FLAG: + flags |= va_arg(args, x509_flag_t); + continue; case BUILD_END: break; default: @@ -85,6 +89,7 @@ static cert_t *builder_load_cert(certificate_type_t type, va_list args) x509cert->cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_BLOB_ASN1_DER, blob, + BUILD_X509_FLAG, flags, BUILD_END); if (x509cert->cert) { @@ -128,9 +133,12 @@ static x509acert_t *builder_load_ac(certificate_type_t type, va_list args) if (blob.ptr) { ac = malloc_thing(x509acert_t); - *ac = empty_ac; - if (parse_ac(chunk_clone(blob), ac) && - verify_x509acert(ac, FALSE)) + ac->next = NULL; + ac->installed = UNDEFINED_TIME; + ac->ac = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509_AC, + BUILD_BLOB_ASN1_DER, blob, BUILD_END); + if (ac->ac && verify_x509acert(ac, FALSE)) { return ac; } diff --git a/src/pluto/ca.c b/src/pluto/ca.c index bc6bfe9ad..816e71087 100644 --- a/src/pluto/ca.c +++ b/src/pluto/ca.c @@ -81,7 +81,7 @@ bool trusted_ca(chunk_t a, chunk_t b, int *pathlen) chunk_t issuer_dn; x509cert_t *cacert; - cacert = get_authcert(a, chunk_empty, AUTH_CA); + cacert = get_authcert(a, chunk_empty, X509_CA); if (cacert == NULL) { break; @@ -180,7 +180,7 @@ void free_authcerts(void) /* * get a X.509 authority certificate with a given subject or keyid */ -x509cert_t* get_authcert(chunk_t subject, chunk_t keyid, u_char auth_flags) +x509cert_t* get_authcert(chunk_t subject, chunk_t keyid, x509_flag_t auth_flags) { x509cert_t *cert, *prev_cert = NULL; @@ -193,11 +193,12 @@ x509cert_t* get_authcert(chunk_t subject, chunk_t keyid, u_char auth_flags) for (cert = x509authcerts; cert != NULL; prev_cert = cert, cert = cert->next) { certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; identification_t *cert_subject; chunk_t cert_subject_dn; /* skip non-matching types of authority certificates */ - if (!(cert->authority_flags & auth_flags)) + if (!(x509->get_flags(x509) & auth_flags)) { continue; } @@ -205,7 +206,6 @@ x509cert_t* get_authcert(chunk_t subject, chunk_t keyid, u_char auth_flags) /* compare the keyid with the certificate's subjectKeyIdentifier */ if (keyid.ptr) { - x509_t *x509 = (x509_t*)certificate; chunk_t subjectKeyId; subjectKeyId = x509->get_subjectKeyIdentifier(x509); @@ -239,7 +239,7 @@ x509cert_t* get_authcert(chunk_t subject, chunk_t keyid, u_char auth_flags) /* * add an authority certificate to the chained list */ -x509cert_t* add_authcert(x509cert_t *cert, u_char auth_flags) +x509cert_t* add_authcert(x509cert_t *cert, x509_flag_t auth_flags) { certificate_t *certificate = cert->cert; x509_t *x509 = (x509_t*)certificate; @@ -247,9 +247,6 @@ x509cert_t* add_authcert(x509cert_t *cert, u_char auth_flags) chunk_t cert_subject_dn = cert_subject->get_encoding(cert_subject); x509cert_t *old_cert; - /* set authority flags */ - cert->authority_flags |= auth_flags; - lock_authcert_list("add_authcert"); old_cert = get_authcert(cert_subject_dn, @@ -259,8 +256,6 @@ x509cert_t* add_authcert(x509cert_t *cert, u_char auth_flags) { if (certificate->equals(certificate, old_cert->cert)) { - /* cert is already present, just add additional authority flags */ - old_cert->authority_flags |= cert->authority_flags; DBG(DBG_CONTROL | DBG_PARSING , DBG_log(" authcert is already present and identical") ) @@ -293,7 +288,7 @@ x509cert_t* add_authcert(x509cert_t *cert, u_char auth_flags) /* * Loads authority certificates */ -void load_authcerts(const char *type, const char *path, u_char auth_flags) +void load_authcerts(const char *type, const char *path, x509_flag_t auth_flags) { struct dirent **filelist; u_char buf[BUF_LEN]; @@ -320,9 +315,10 @@ void load_authcerts(const char *type, const char *path, u_char auth_flags) { cert_t cert; - if (load_cert(filelist[n]->d_name, type, &cert)) + if (load_cert(filelist[n]->d_name, type, auth_flags, &cert)) + { add_authcert(cert.u.x509, auth_flags); - + } free(filelist[n]); } free(filelist); @@ -335,7 +331,7 @@ void load_authcerts(const char *type, const char *path, u_char auth_flags) /* * list all X.509 authcerts with given auth flags in a chained list */ -void list_authcerts(const char *caption, u_char auth_flags, bool utc) +void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc) { lock_authcert_list("list_authcerts"); list_x509cert_chain(caption, x509authcerts, auth_flags, utc); @@ -426,7 +422,7 @@ bool trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chai else { /* search in trusted chain */ - authcert = get_authcert(issuer_dn, authKeyID, AUTH_CA); + authcert = get_authcert(issuer_dn, authKeyID, X509_CA); if (authcert != NULL) { @@ -670,7 +666,7 @@ void add_ca_info(const whack_message_t *msg) unlock_ca_info_list("add_ca_info"); /* add cacert to list of authcerts */ - cacert = add_authcert(cacert, AUTH_CA); + cacert = add_authcert(cacert, X509_CA); if (!cached_cert && sc != NULL) { if (sc->last_cert.type == CERT_X509_SIGNATURE) diff --git a/src/pluto/ca.h b/src/pluto/ca.h index eadb96dba..8c7627d2b 100644 --- a/src/pluto/ca.h +++ b/src/pluto/ca.h @@ -22,13 +22,6 @@ #define MAX_CA_PATH_LEN 7 -/* authority flags */ - -#define AUTH_NONE 0x00 /* no authorities */ -#define AUTH_CA 0x01 /* certification authority */ -#define AUTH_AA 0x02 /* authorization authority */ -#define AUTH_OCSP 0x04 /* ocsp signing authority */ - /* CA info structures */ typedef struct ca_info ca_info_t; @@ -47,17 +40,17 @@ struct ca_info { }; extern bool trusted_ca(chunk_t a, chunk_t b, int *pathlen); -extern bool match_requested_ca(generalName_t *requested_ca - , chunk_t our_ca, int *our_pathlen); +extern bool match_requested_ca(generalName_t *requested_ca, chunk_t our_ca, + int *our_pathlen); extern x509cert_t* get_authcert(chunk_t subject, chunk_t keyid, - u_char auth_flags); -extern void load_authcerts(const char *type, const char *path - , u_char auth_flags); -extern x509cert_t* add_authcert(x509cert_t *cert, u_char auth_flags); + x509_flag_t auth_flags); +extern void load_authcerts(const char *type, const char *path, + x509_flag_t auth_flags); +extern x509cert_t* add_authcert(x509cert_t *cert, x509_flag_t auth_flags); extern void free_authcerts(void); -extern void list_authcerts(const char *caption, u_char auth_flags, bool utc); -extern bool trust_authcert_candidate(const x509cert_t *cert - , const x509cert_t *alt_chain); +extern void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc); +extern bool trust_authcert_candidate(const x509cert_t *cert, + const x509cert_t *alt_chain); extern ca_info_t* get_ca_info(chunk_t name, chunk_t keyid); extern bool find_ca_info_by_name(const char *name, bool delete); extern void add_ca_info(const whack_message_t *msg); diff --git a/src/pluto/certs.c b/src/pluto/certs.c index cdf567e90..456a45fca 100644 --- a/src/pluto/certs.c +++ b/src/pluto/certs.c @@ -162,12 +162,14 @@ private_key_t* load_private_key(char* filename, prompt_pass_t *pass, /** * Loads a X.509 or OpenPGP certificate */ -bool load_cert(char *filename, const char *label, cert_t *out) +bool load_cert(char *filename, const char *label, x509_flag_t flags, cert_t *out) { cert_t *cert; cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT, - BUILD_FROM_FILE, filename, BUILD_END); + BUILD_FROM_FILE, filename, + BUILD_X509_FLAG, flags, + BUILD_END); if (cert) { /* the API passes an empty cert_t, we move over and free the built one */ @@ -186,7 +188,7 @@ bool load_host_cert(char *filename, cert_t *cert) { char *path = concatenate_paths(HOST_CERT_PATH, filename); - return load_cert(path, "host", cert); + return load_cert(path, "host", X509_NONE, cert); } /** @@ -196,7 +198,7 @@ bool load_ca_cert(char *filename, cert_t *cert) { char *path = concatenate_paths(CA_CERT_PATH, filename); - return load_cert(path, "CA", cert); + return load_cert(path, "CA", X509_NONE, cert); } /** diff --git a/src/pluto/certs.h b/src/pluto/certs.h index 1bd03edcd..faf820dae 100644 --- a/src/pluto/certs.h +++ b/src/pluto/certs.h @@ -66,7 +66,8 @@ extern public_key_t* cert_get_public_key(const cert_t cert); extern chunk_t cert_get_encoding(cert_t cert); extern private_key_t* load_private_key(char* filename, prompt_pass_t *pass, key_type_t type); -extern bool load_cert(char *filename, const char *label, cert_t *cert); +extern bool load_cert(char *filename, const char *label, x509_flag_t flags, + cert_t *cert); extern bool load_host_cert(char *filename, cert_t *cert); extern bool load_ca_cert(char *filename, cert_t *cert); extern bool same_cert(const cert_t *a, const cert_t *b); diff --git a/src/pluto/connections.c b/src/pluto/connections.c index d375e49a0..e1a28cade 100644 --- a/src/pluto/connections.c +++ b/src/pluto/connections.c @@ -30,6 +30,7 @@ #include <freeswan.h> #include "kameipsec.h" +#include <credentials/certificates/ac.h> #include <credentials/keys/private_key.h> #include "constants.h" @@ -336,11 +337,11 @@ void delete_connection(connection_t *c, bool relations) free_id_content(&c->spd.this.id); free(c->spd.this.updown); free(c->spd.this.ca.ptr); - free_ietfAttrList(c->spd.this.groups); + DESTROY_IF(c->spd.this.groups); free_id_content(&c->spd.that.id); free(c->spd.that.updown); free(c->spd.that.ca.ptr); - free_ietfAttrList(c->spd.that.groups); + DESTROY_IF(c->spd.that.groups); free_generalNames(c->requested_ca, TRUE); gw_delref(&c->gw_info); @@ -812,7 +813,7 @@ static bool extract_end(struct end *dst, const whack_end_t *src, dst->ca = chunk_empty; /* decode CA distinguished name, if any */ - if (src->ca != NULL) + if (src->ca) { if streq(src->ca, "%same") same_ca = TRUE; @@ -837,7 +838,10 @@ static bool extract_end(struct end *dst, const whack_end_t *src, dst->has_id_wildcards = id_count_wildcards(&dst->id) > 0; /* decode group attributes, if any */ - decode_groups(src->groups, &dst->groups); + if (src->groups) + { + dst->groups = ietf_attributes_create_from_string(src->groups); + } /* the rest is simple copying of corresponding fields */ dst->host_addr = src->host_addr; @@ -1261,8 +1265,14 @@ static connection_t *instantiate(connection_t *c, d->spd.that.has_id_wildcards = FALSE; } unshare_connection_strings(d); - unshare_ietfAttrList(&d->spd.this.groups); - unshare_ietfAttrList(&d->spd.that.groups); + if (d->spd.this.groups) + { + d->spd.this.groups = d->spd.this.groups->get_ref(d->spd.this.groups); + } + if (d->spd.that.groups) + { + d->spd.that.groups = d->spd.that.groups->get_ref(d->spd.that.groups); + } d->kind = CK_INSTANCE; passert(oriented(*d)); @@ -1519,7 +1529,9 @@ connection_t *find_connection_for_clients(struct spd_route **srp, for (c = connections; c != NULL; c = c->ac_next) { if (c->kind == CK_GROUP) + { continue; + } for (sr = &c->spd; best!=c && sr; sr = sr->next) { @@ -1727,7 +1739,9 @@ bool orient(connection_t *c) for (p = interfaces; p != NULL; p = p->next) { if (p->ike_float) + { continue; + } for (;;) { @@ -3036,11 +3050,17 @@ connection_t *route_owner(connection_t *c, struct spd_route **srp, for (src = &c->spd; src; src=src->next) { if (!samesubnet(&src->that.client, &srd->that.client)) + { continue; + } if (src->that.protocol != srd->that.protocol) + { continue; + } if (src->that.port != srd->that.port) + { continue; + } passert(oriented(*d)); if (srd->routing > best_routing) { @@ -3050,11 +3070,17 @@ connection_t *route_owner(connection_t *c, struct spd_route **srp, } if (!samesubnet(&src->this.client, &srd->this.client)) + { continue; + } if (src->this.protocol != srd->this.protocol) + { continue; + } if (src->this.port != srd->this.port) + { continue; + } if (srd->routing > best_erouting) { best_ero = d; @@ -3332,11 +3358,15 @@ connection_t *refine_host_connection(const struct state *st, /* do we have a match? */ if (!match) + { continue; + } /* ignore group connections */ if (d->policy & POLICY_GROUP) + { continue; + } if (c->spd.that.host_port != d->spd.that.host_port && d->kind == CK_INSTANCE) @@ -3354,12 +3384,17 @@ connection_t *refine_host_connection(const struct state *st, const chunk_t *dpsk = get_preshared_secret(d); if (dpsk == NULL) + { continue; /* no secret */ - + } if (psk != dpsk) + { if (psk->len != dpsk->len || memcmp(psk->ptr, dpsk->ptr, psk->len) != 0) + { continue; /* different secret */ + } + } } break; @@ -3374,7 +3409,9 @@ connection_t *refine_host_connection(const struct state *st, .*/ if (d->spd.this.sc == NULL /* no smartcard */ && get_private_key(d) == NULL) /* no private key */ + { continue; + } break; default: @@ -3488,7 +3525,7 @@ static connection_t *fc_try(const connection_t *c, struct host_pair *hp, const u_int8_t peer_protocol, const u_int16_t peer_port, chunk_t peer_ca, - const ietfAttrList_t *peer_list) + ietf_attributes_t *peer_attributes) { connection_t *d; connection_t *best = NULL; @@ -3502,20 +3539,26 @@ static connection_t *fc_try(const connection_t *c, struct host_pair *hp, struct spd_route *sr; if (d->policy & POLICY_GROUP) + { continue; + } if (!(same_id(&c->spd.this.id, &d->spd.this.id) && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards) && trusted_ca(peer_ca, d->spd.that.ca, &pathlen) - && group_membership(peer_list, d->name, d->spd.that.groups))) + && match_group_membership(peer_attributes, d->name, d->spd.that.groups))) + { continue; + } /* compare protocol and ports */ if (d->spd.this.protocol != our_protocol || d->spd.this.port != our_port || d->spd.that.protocol != peer_protocol || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard)) + { continue; + } /* non-Opportunistic case: * our_client must match. @@ -3552,29 +3595,38 @@ static connection_t *fc_try(const connection_t *c, struct host_pair *hp, #endif /* DEBUG */ if (!samesubnet(&sr->this.client, our_net)) + { continue; - + } if (sr->that.has_client) { if (sr->that.has_client_wildcard) { if (!subnetinsubnet(peer_net, &sr->that.client)) + { continue; + } } else { if (!samesubnet(&sr->that.client, peer_net) && !is_virtual_connection(d)) + { continue; + } if (is_virtual_connection(d) && (!is_virtual_net_allowed(d, peer_net, &c->spd.that.host_addr) || is_virtual_net_used(peer_net, peer_id?peer_id:&c->spd.that.id))) - continue; + { + continue; + } } } else { if (!peer_net_is_host) + { continue; + } } /* We've run the gauntlet -- success: @@ -3616,7 +3668,7 @@ static connection_t *fc_try_oppo(const connection_t *c, const u_int8_t peer_protocol, const u_int16_t peer_port, chunk_t peer_ca, - const ietfAttrList_t *peer_list) + ietf_attributes_t *peer_attributes) { connection_t *d; connection_t *best = NULL; @@ -3629,20 +3681,25 @@ static connection_t *fc_try_oppo(const connection_t *c, policy_prio_t prio; if (d->policy & POLICY_GROUP) + { continue; - + } if (!(same_id(&c->spd.this.id, &d->spd.this.id) && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards) && trusted_ca(peer_ca, d->spd.that.ca, &pathlen) - && group_membership(peer_list, d->name, d->spd.that.groups))) + && match_group_membership(peer_attributes, d->name, d->spd.that.groups))) + { continue; + } /* compare protocol and ports */ if (d->spd.this.protocol != our_protocol || d->spd.this.port != our_port || d->spd.that.protocol != peer_protocol || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard)) + { continue; + } /* Opportunistic case: * our_net must be inside d->spd.this.client @@ -3670,7 +3727,9 @@ static connection_t *fc_try_oppo(const connection_t *c, if (!subnetinsubnet(our_net, &sr->this.client) || !subnetinsubnet(peer_net, &sr->that.client)) + { continue; + } /* The connection is feasible, but we continue looking for the best. * The highest priority wins, implementing eroute-like rule. @@ -3710,21 +3769,25 @@ static connection_t *fc_try_oppo(const connection_t *c, /* * get the peer's CA and group attributes */ -chunk_t get_peer_ca_and_groups(connection_t *c, const ietfAttrList_t **peer_list) +chunk_t get_peer_ca_and_groups(connection_t *c, ietf_attributes_t **peer_attributes) { struct state *p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); - *peer_list = NULL; + *peer_attributes = NULL; if (p1st != NULL && p1st->st_peer_pubkey != NULL && p1st->st_peer_pubkey->issuer.ptr != NULL) { - x509acert_t *ac = get_x509acert(p1st->st_peer_pubkey->issuer - , p1st->st_peer_pubkey->serial);; + x509acert_t *x509ac = get_x509acert(p1st->st_peer_pubkey->issuer, + p1st->st_peer_pubkey->serial); - if (ac != NULL && verify_x509acert(ac, strict_crl_policy)) - *peer_list = ac->groups; + if (x509ac && verify_x509acert(x509ac, strict_crl_policy)) + { + ac_t * ac = (ac_t*)x509ac->ac; + + *peer_attributes = ac->get_groups(ac); + } else { DBG(DBG_CONTROL, @@ -3746,9 +3809,8 @@ connection_t *find_client_connection(connection_t *c, { connection_t *d; struct spd_route *sr; - - const ietfAttrList_t *peer_list = NULL; - chunk_t peer_ca = get_peer_ca_and_groups(c, &peer_list); + ietf_attributes_t *peer_attributes = NULL; + chunk_t peer_ca = get_peer_ca_and_groups(c, &peer_attributes); #ifdef DEBUG if (DBGP(DBG_CONTROLMORE)) @@ -3795,12 +3857,14 @@ connection_t *find_client_connection(connection_t *c, && sr->this.port == our_port && sr->that.protocol == peer_protocol && sr->that.port == peer_port - && group_membership(peer_list, c->name, sr->that.groups)) + && match_group_membership(peer_attributes, c->name, sr->that.groups)) { passert(oriented(*c)); if (routed(sr->routing)) + { + DESTROY_IF(peer_attributes); return c; - + } unrouted = c; } } @@ -3808,7 +3872,7 @@ connection_t *find_client_connection(connection_t *c, /* exact match? */ d = fc_try(c, c->host_pair, NULL, our_net, peer_net , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_list); + , peer_ca, peer_attributes); DBG(DBG_CONTROLMORE, DBG_log(" fc_try %s gives %s" @@ -3817,7 +3881,9 @@ connection_t *find_client_connection(connection_t *c, ) if (d == NULL) + { d = unrouted; + } } if (d == NULL) @@ -3852,7 +3918,7 @@ connection_t *find_client_connection(connection_t *c, /* RW match with actual peer_id or abstract peer_id? */ d = fc_try(c, hp, NULL, our_net, peer_net , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_list); + , peer_ca, peer_attributes); if (d == NULL && subnetishost(our_net) @@ -3864,7 +3930,7 @@ connection_t *find_client_connection(connection_t *c, */ d = fc_try_oppo(c, hp, our_net, peer_net , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_list); + , peer_ca, peer_attributes); } } } @@ -3873,6 +3939,7 @@ connection_t *find_client_connection(connection_t *c, DBG_log(" concluding with d = %s" , (d ? d->name : "none")) ) + DESTROY_IF(peer_attributes); return d; } @@ -3978,8 +4045,7 @@ void show_connections_status(bool all, const char *name) dntoa_or_null(this_ca, BUF_LEN, c->spd.this.ca, "%any"); dntoa_or_null(that_ca, BUF_LEN, c->spd.that.ca, "%any"); - whack_log(RC_COMMENT - , "\"%s\"%s: CAs: '%s'...'%s'" + whack_log(RC_COMMENT, "\"%s\"%s: CAs: '%s'...'%s'" , c->name , instance , this_ca @@ -3989,14 +4055,10 @@ void show_connections_status(bool all, const char *name) /* show group attributes if defined */ if (c->spd.that.groups != NULL) { - char buf[BUF_LEN]; - - format_groups(c->spd.that.groups, buf, BUF_LEN); - whack_log(RC_COMMENT - , "\"%s\"%s: groups: %s" + whack_log(RC_COMMENT, "\"%s\"%s: groups: %s" , c->name , instance - , buf); + , c->spd.that.groups->get_string(c->spd.that.groups)); } whack_log(RC_COMMENT diff --git a/src/pluto/connections.h b/src/pluto/connections.h index d6881499b..5bef59b66 100644 --- a/src/pluto/connections.h +++ b/src/pluto/connections.h @@ -146,7 +146,7 @@ struct end { u_int8_t protocol; cert_t cert; /* end certificate */ chunk_t ca; /* CA distinguished name */ - struct ietfAttrList *groups;/* access control groups */ + ietf_attributes_t *groups; /* access control groups */ smartcard_t *sc; /* smartcard reader and key info */ struct virtual_t *virt; bool modecfg; /* this end: request local address from server */ @@ -288,8 +288,8 @@ find_connection_for_clients(struct spd_route **srp , const ip_address *peer_client , int transport_proto); -extern chunk_t get_peer_ca_and_groups(connection_t *c - , const ietfAttrList_t **peer_list); +extern chunk_t get_peer_ca_and_groups(connection_t *c, + ietf_attributes_t **peer_attributes); /* instantiating routines * Note: connection_discard() is in state.h because all its work diff --git a/src/pluto/crl.c b/src/pluto/crl.c index 38e8027d7..01d4839fc 100644 --- a/src/pluto/crl.c +++ b/src/pluto/crl.c @@ -133,7 +133,7 @@ bool insert_crl(x509crl_t *x509crl, char *crl_uri, bool cache_crl) lock_authcert_list("insert_crl"); /* get the issuer cacert */ - issuer_cert = get_authcert(issuer_dn, authKeyID, AUTH_CA); + issuer_cert = get_authcert(issuer_dn, authKeyID, X509_CA); if (issuer_cert == NULL) { plog("crl issuer cacert not found"); @@ -434,7 +434,7 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until, lock_authcert_list("verify_by_crl"); - issuer_cert = get_authcert(issuer_dn, authKeyID, AUTH_CA); + issuer_cert = get_authcert(issuer_dn, authKeyID, X509_CA); valid = cert_crl->issued_by(cert_crl, issuer_cert->cert); unlock_authcert_list("verify_by_crl"); diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c index 9e941192c..eaa4a7a8c 100644 --- a/src/pluto/ipsec_doi.c +++ b/src/pluto/ipsec_doi.c @@ -5182,29 +5182,33 @@ stf_status quick_inR1_outI2(struct msg_digest *md) } /* check the peer's group attributes */ - { - const ietfAttrList_t *peer_list = NULL; + ietf_attributes_t *peer_attributes = NULL; + bool match; - get_peer_ca_and_groups(st->st_connection, &peer_list); + get_peer_ca_and_groups(st->st_connection, &peer_attributes); + match = match_group_membership(peer_attributes, + st->st_connection->name, + st->st_connection->spd.that.groups); + DESTROY_IF(peer_attributes); - if (!group_membership(peer_list, st->st_connection->name - , st->st_connection->spd.that.groups)) + if (!match) { - char buf[BUF_LEN]; + ietf_attributes_t *groups = st->st_connection->spd.that.groups; - format_groups(st->st_connection->spd.that.groups, buf, BUF_LEN); - loglog(RC_LOG_SERIOUS, "peer is not member of one of the groups: %s" - , buf); + loglog(RC_LOG_SERIOUS, + "peer with attributes '%s' is not a member of the groups '%s'", + peer_attributes->get_string(peer_attributes), + groups->get_string(groups)); return STF_FAIL + INVALID_ID_INFORMATION; } } - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->nat_traversal & NAT_T_WITH_NATOA)) - { - nat_traversal_natoa_lookup(md); - } + if ((st->nat_traversal & NAT_T_DETECTED) + && (st->nat_traversal & NAT_T_WITH_NATOA)) + { + nat_traversal_natoa_lookup(md); + } /* ??? We used to copy the accepted proposal into the state, but it was * never used. From sa_pd->pbs.start, length pbs_room(&sa_pd->pbs). diff --git a/src/pluto/ocsp.c b/src/pluto/ocsp.c index 510667e67..d980e7f14 100644 --- a/src/pluto/ocsp.c +++ b/src/pluto/ocsp.c @@ -329,7 +329,7 @@ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *locatio if (authKeyID.ptr == NULL) { - x509cert_t *authcert = get_authcert(issuer_dn, authKeyID, AUTH_CA); + x509cert_t *authcert = get_authcert(issuer_dn, authKeyID, X509_CA); if (authcert != NULL) { @@ -983,7 +983,7 @@ static bool valid_ocsp_response(response_t *res) lock_authcert_list("valid_ocsp_response"); authcert = get_authcert(res->responder_id_name, res->responder_id_key, - AUTH_OCSP | AUTH_CA); + X509_OCSP_SIGNER | X509_CA); if (authcert == NULL) { plog("no matching ocsp signer cert found"); @@ -1040,7 +1040,7 @@ static bool valid_ocsp_response(response_t *res) DBG_log("certificate is valid") ) - authcert = get_authcert(issuer->get_encoding(issuer), authKeyID, AUTH_CA); + authcert = get_authcert(issuer->get_encoding(issuer), authKeyID, X509_CA); if (authcert == NULL) { plog("issuer cacert not found"); @@ -1168,7 +1168,7 @@ static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) if ((x509->get_flags(x509) & X509_OCSP_SIGNER) && trust_authcert_candidate(cert, NULL)) { - add_authcert(cert, AUTH_OCSP); + add_authcert(cert, X509_OCSP_SIGNER); } else { diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c index 78afeacb6..203c24c84 100644 --- a/src/pluto/plutomain.c +++ b/src/pluto/plutomain.c @@ -720,11 +720,11 @@ int main(int argc, char **argv) #endif /* CAPABILITIES */ /* loading X.509 CA certificates */ - load_authcerts("CA", CA_CERT_PATH, AUTH_CA); + load_authcerts("CA", CA_CERT_PATH, X509_CA); /* loading X.509 AA certificates */ - load_authcerts("AA", AA_CERT_PATH, AUTH_AA); + load_authcerts("AA", AA_CERT_PATH, X509_AA); /* loading X.509 OCSP certificates */ - load_authcerts("OCSP", OCSP_CERT_PATH, AUTH_OCSP); + load_authcerts("OCSP", OCSP_CERT_PATH, X509_OCSP_SIGNER); /* loading X.509 CRLs */ load_crls(); /* loading attribute certificates (experimental) */ diff --git a/src/pluto/rcv_whack.c b/src/pluto/rcv_whack.c index ef984f66a..d84a9f5f1 100644 --- a/src/pluto/rcv_whack.c +++ b/src/pluto/rcv_whack.c @@ -451,17 +451,17 @@ whack_handle(int whackctlfd) if (msg.whack_reread & REREAD_CACERTS) { - load_authcerts("CA cert", CA_CERT_PATH, AUTH_CA); + load_authcerts("CA cert", CA_CERT_PATH, X509_CA); } if (msg.whack_reread & REREAD_AACERTS) { - load_authcerts("AA cert", AA_CERT_PATH, AUTH_AA); + load_authcerts("AA cert", AA_CERT_PATH, X509_AA); } if (msg.whack_reread & REREAD_OCSPCERTS) { - load_authcerts("OCSP cert", OCSP_CERT_PATH, AUTH_OCSP); + load_authcerts("OCSP cert", OCSP_CERT_PATH, X509_OCSP_SIGNER); } if (msg.whack_reread & REREAD_ACERTS) @@ -492,17 +492,17 @@ whack_handle(int whackctlfd) if (msg.whack_list & LIST_CACERTS) { - list_authcerts("CA", AUTH_CA, msg.whack_utc); + list_authcerts("CA", X509_CA, msg.whack_utc); } if (msg.whack_list & LIST_AACERTS) { - list_authcerts("AA", AUTH_AA, msg.whack_utc); + list_authcerts("AA", X509_AA, msg.whack_utc); } if (msg.whack_list & LIST_OCSPCERTS) { - list_authcerts("OCSP", AUTH_OCSP, msg.whack_utc); + list_authcerts("OCSP", X509_OCSP_SIGNER, msg.whack_utc); } if (msg.whack_list & LIST_ACERTS) @@ -510,11 +510,6 @@ whack_handle(int whackctlfd) list_acerts(msg.whack_utc); } - if (msg.whack_list & LIST_GROUPS) - { - list_groups(msg.whack_utc); - } - if (msg.whack_list & LIST_CAINFOS) { list_ca_infos(msg.whack_utc); diff --git a/src/pluto/x509.c b/src/pluto/x509.c index d0a57b39a..61d263948 100644 --- a/src/pluto/x509.c +++ b/src/pluto/x509.c @@ -126,8 +126,7 @@ const x509cert_t empty_x509cert = { NULL , /* *next */ UNDEFINED_TIME, /* installed */ 0 , /* count */ - FALSE , /* smartcard */ - AUTH_NONE , /* authority_flags */ + FALSE /* smartcard */ }; /* coding of X.501 distinguished name */ @@ -1038,7 +1037,7 @@ void store_x509certs(x509cert_t **firstcert, bool strict) if (trust_authcert_candidate(cert, cacerts)) { - add_authcert(cert, AUTH_CA); + add_authcert(cert, X509_CA); } else { @@ -1393,7 +1392,7 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) lock_authcert_list("verify_x509cert"); issuer_cert = get_authcert(issuer->get_encoding(issuer), - authKeyID, AUTH_CA); + authKeyID, X509_CA); if (issuer_cert == NULL) { plog("issuer cacert not found"); @@ -1495,7 +1494,7 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) * List all X.509 certs in a chained list */ void list_x509cert_chain(const char *caption, x509cert_t* cert, - u_char auth_flags, bool utc) + x509_flag_t flags, bool utc) { bool first = TRUE; time_t now; @@ -1505,14 +1504,15 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert, while (cert != NULL) { - if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags)) + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + + if (flags == X509_NONE || (flags & x509->get_flags(x509))) { time_t notBefore, notAfter; public_key_t *key; chunk_t serial, keyid, subjkey, authkey; cert_t c; - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; c.type = CERT_X509_SIGNATURE; c.u.x509 = cert; @@ -1579,5 +1579,5 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert, */ void list_x509_end_certs(bool utc) { - list_x509cert_chain("End", x509certs, AUTH_NONE, utc); + list_x509cert_chain("End", x509certs, X509_NONE, utc); } diff --git a/src/pluto/x509.h b/src/pluto/x509.h index 490ffc370..a61d6c06b 100644 --- a/src/pluto/x509.h +++ b/src/pluto/x509.h @@ -58,7 +58,6 @@ struct x509cert { time_t installed; int count; bool smartcard; - u_char authority_flags; }; /* used for initialization */ @@ -91,7 +90,7 @@ extern void release_x509cert(x509cert_t *cert); extern void free_x509cert(x509cert_t *cert); extern void store_x509certs(x509cert_t **firstcert, bool strict); extern void list_x509cert_chain(const char *caption, x509cert_t* cert, - u_char auth_flags, bool utc); + x509_flag_t flags, bool utc); extern void list_x509_end_certs(bool utc); extern void free_generalNames(generalName_t* gn, bool free_name); diff --git a/testing/tests/ikev1/attr-cert/evaltest.dat b/testing/tests/ikev1/attr-cert/evaltest.dat index 59f6eb76a..c6c3c66c3 100644 --- a/testing/tests/ikev1/attr-cert/evaltest.dat +++ b/testing/tests/ikev1/attr-cert/evaltest.dat @@ -1,12 +1,12 @@ carol::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::YES -moon::cat /var/log/auth.log::alice.*peer matches group 'Research'::YES +moon::cat /var/log/auth.log::alice.*peer with attributes .*Research.* is a member of the groups .*Research::YES moon::ipsec status::alice.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::YES carol::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::NO -moon::cat /var/log/auth.log::venus.*peer doesn't match any group::YES +moon::cat /var/log/auth.log::venus.*peer with attributes .*Research.* is not a member of the groups .*Accounting::YES moon::ipsec status::venus.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::NO dave::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::YES -moon::cat /var/log/auth.log::venus.*peer matches group 'Accounting'::YES +moon::cat /var/log/auth.log::venus.*peer with attributes .*Accounting.* is a member of the groups .*Accounting::YES moon::ipsec status::venus.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::YES dave::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::NO -moon::cat /var/log/auth.log::alice.*peer doesn't match any group::YES +moon::cat /var/log/auth.log::alice.*peer with attributes .*Accounting.* is not a member of the groups .*Research::YES moon::ipsec status::alice.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::NO |