diff options
author | Martin Willi <martin@revosec.ch> | 2014-02-04 16:11:37 +0100 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2014-03-31 11:14:58 +0200 |
commit | a17598bc69926f69a87eaf60c29a81b8e0d1e203 (patch) | |
tree | 4480ffdc78a27d7030657c720bfb45bb3d51acb5 /src/libstrongswan | |
parent | 61b2d815b9af23261c479b552fb86faf212387fe (diff) | |
download | strongswan-a17598bc69926f69a87eaf60c29a81b8e0d1e203.tar.bz2 strongswan-a17598bc69926f69a87eaf60c29a81b8e0d1e203.tar.xz |
x509: Integrate IETF attribute handling, and obsolete ietf_attributes_t
The ietf_attributes_t class is used for attribute certificates only these days,
and integrating them to x509_ac_t simplifies things significantly.
Diffstat (limited to 'src/libstrongswan')
-rw-r--r-- | src/libstrongswan/Android.mk | 2 | ||||
-rw-r--r-- | src/libstrongswan/Makefile.am | 3 | ||||
-rw-r--r-- | src/libstrongswan/credentials/certificates/ac.h | 1 | ||||
-rw-r--r-- | src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c | 528 | ||||
-rw-r--r-- | src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h | 98 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_ac.c | 193 |
6 files changed, 186 insertions, 639 deletions
diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk index 440913071..2b58db554 100644 --- a/src/libstrongswan/Android.mk +++ b/src/libstrongswan/Android.mk @@ -20,7 +20,7 @@ credentials/keys/public_key.c credentials/keys/shared_key.c \ credentials/certificates/certificate.c credentials/certificates/crl.c \ credentials/certificates/ocsp_response.c \ credentials/containers/container.c credentials/containers/pkcs12.c \ -credentials/ietf_attributes/ietf_attributes.c credentials/credential_manager.c \ +credentials/credential_manager.c \ credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \ credentials/sets/cert_cache.c credentials/sets/mem_cred.c \ credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \ diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index b3a4eda99..50cac493d 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -18,7 +18,7 @@ credentials/keys/public_key.c credentials/keys/shared_key.c \ credentials/certificates/certificate.c credentials/certificates/crl.c \ credentials/certificates/ocsp_response.c \ credentials/containers/container.c credentials/containers/pkcs12.c \ -credentials/ietf_attributes/ietf_attributes.c credentials/credential_manager.c \ +credentials/credential_manager.c \ credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \ credentials/sets/cert_cache.c credentials/sets/mem_cred.c \ credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \ @@ -61,7 +61,6 @@ credentials/certificates/ocsp_response.h \ credentials/certificates/pgp_certificate.h \ credentials/containers/container.h credentials/containers/pkcs7.h \ credentials/containers/pkcs12.h \ -credentials/ietf_attributes/ietf_attributes.h \ credentials/credential_manager.h credentials/sets/auth_cfg_wrapper.h \ credentials/sets/ocsp_response_wrapper.h credentials/sets/cert_cache.h \ credentials/sets/mem_cred.h credentials/sets/callback_cred.h \ diff --git a/src/libstrongswan/credentials/certificates/ac.h b/src/libstrongswan/credentials/certificates/ac.h index 1094cdcfd..9a3d8f0b9 100644 --- a/src/libstrongswan/credentials/certificates/ac.h +++ b/src/libstrongswan/credentials/certificates/ac.h @@ -24,7 +24,6 @@ #include <library.h> #include <credentials/certificates/certificate.h> -#include <credentials/ietf_attributes/ietf_attributes.h> typedef struct ac_t ac_t; typedef enum ac_group_type_t ac_group_type_t; diff --git a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c b/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c deleted file mode 100644 index 6efbfb70e..000000000 --- a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * 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 <collections/linked_list.h> -#include <utils/lexparser.h> -#include <credentials/certificates/ac.h> - -#include "ietf_attributes.h" - -typedef struct ietf_attr_t ietf_attr_t; - -/** - * Private definition of an IETF attribute - */ -struct ietf_attr_t { - - /** - * IETF attribute type - */ - ac_group_type_t type; - - /** - * IETF attribute value - */ - chunk_t value; -}; - -/** - * 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 != AC_GROUP_TYPE_OID && other->type == AC_GROUP_TYPE_OID) - { - return -1; - } - if (this->type == AC_GROUP_TYPE_OID && other->type != AC_GROUP_TYPE_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(ac_group_type_t type, chunk_t value) -{ - ietf_attr_t *this; - - INIT(this, - .type = type, - .value = chunk_clone(value), - ); - - 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; -}; - -METHOD(ietf_attributes_t, get_string, char*, - 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; - - if (first) - { - first = FALSE; - } - else - { - written = snprintf(pos, len, ", "); - if (written < 0 || written >= len) - { - break; - } - pos += written; - len -= written; - } - - switch (attr->type) - { - case AC_GROUP_TYPE_OCTETS: - case AC_GROUP_TYPE_STRING: - written = snprintf(pos, len, "%.*s", (int)attr->value.len, - attr->value.ptr); - break; - case AC_GROUP_TYPE_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].name); - } - break; - } - default: - written = 0; - break; - } - if (written < 0 || written >= len) - { - break; - } - pos += written; - len -= written; - } - enumerator->destroy(enumerator); - if (len < BUF_LEN) - { - this->string = strdup(buf); - } - } - return this->string; -} - -/** - * Filter function for attribute enumeration - */ -static bool attr_filter(void *null, ietf_attr_t **in, ac_group_type_t *type, - void *in2, chunk_t *out) -{ - *type = (*in)->type; - *out = (*in)->value; - return TRUE; -} - -METHOD(ietf_attributes_t, create_enumerator, enumerator_t*, - private_ietf_attributes_t *this) -{ - return enumerator_create_filter(this->list->create_enumerator(this->list), - (void*)attr_filter, NULL, NULL); -} - -METHOD(ietf_attributes_t, get_encoding, chunk_t, - 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 AC_GROUP_TYPE_OCTETS: - type = ASN1_OCTET_STRING; - break; - case AC_GROUP_TYPE_STRING: - type = ASN1_UTF8STRING; - break; - case AC_GROUP_TYPE_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); -} - -/** - * Implementation of ietf_attributes_t.equals. - */ -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 (ietf_attr_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; -} - -/** - * Implementation of ietf_attributes_t.matches. - */ -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) - { - int cmp; - - cmp = ietf_attr_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; -} - -METHOD(ietf_attributes_t, get_ref, ietf_attributes_t*, - private_ietf_attributes_t *this) -{ - ref_get(&this->ref); - return &this->public; -} - -METHOD(ietf_attributes_t, destroy, void, - private_ietf_attributes_t *this) -{ - if (ref_put(&this->ref)) - { - this->list->destroy_function(this->list, (void*)ietf_attr_destroy); - free(this->string); - free(this); - } -} - -static private_ietf_attributes_t* create_empty(void) -{ - private_ietf_attributes_t *this; - - INIT(this, - .public = { - .get_string = _get_string, - .create_enumerator = _create_enumerator, - .get_encoding = _get_encoding, - .equals = (bool (*)(ietf_attributes_t*,ietf_attributes_t*))equals, - .matches = (bool (*)(ietf_attributes_t*,ietf_attributes_t*))matches, - .get_ref = _get_ref, - .destroy = _destroy, - }, - .list = linked_list_create(), - .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; - enumerator_t *enumerator; - int cmp = -1; - - enumerator = this->list->create_enumerator(this->list); - while (enumerator->enumerate(enumerator, (void **)¤t_attr) && - (cmp = ietf_attr_compare(attr, current_attr)) > 0) - { - continue; - } - if (cmp == 0) - { - ietf_attr_destroy(attr); - } - else - { /* the enumerator either points to the end or to the attribute > attr */ - this->list->insert_before(this->list, enumerator, attr); - } - enumerator->destroy(enumerator); -} - -/* - * 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(AC_GROUP_TYPE_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: - { - ac_group_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 deleted file mode 100644 index a34b23a3d..000000000 --- a/src/libstrongswan/credentials/ietf_attributes/ietf_attributes.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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); - - /** - * Create an enumerator over attributes. - * - * @return enumerator over (ac_group_type_t, chunk_t) - */ - enumerator_t* (*create_enumerator)(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/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index 9845b21a8..410b2e5ce 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -29,7 +29,6 @@ #include <utils/identification.h> #include <collections/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, @@ -98,9 +97,9 @@ struct private_x509_ac_t { time_t notAfter; /** - * List of groub attributes + * List of group attributes, as group_t */ - ietf_attributes_t *groups; + linked_list_t *groups; /** * Authority Key Identifier @@ -148,6 +147,25 @@ struct private_x509_ac_t { refcount_t ref; }; +/** + * Group definition, an IETF attribute + */ +typedef struct { + /** Attribute type */ + ac_group_type_t type; + /* attribute value */ + chunk_t value; +} group_t; + +/** + * Clean up a group entry + */ +static void group_destroy(group_t *group) +{ + free(group->value.ptr); + free(group); +} + static chunk_t ASN1_noRevAvail_ext = chunk_from_chars( 0x30, 0x09, 0x06, 0x03, @@ -238,6 +256,74 @@ static void parse_roleSyntax(chunk_t blob, int level0) } /** + * 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 + +/** + * Parse group memberships, IETF attributes + */ +static bool parse_groups(private_x509_ac_t *this, chunk_t encoded, int level0) +{ + ac_group_type_t type; + group_t *group; + asn1_parser_t *parser; + chunk_t object; + int objectID; + bool success; + + parser = asn1_parser_create(ietfAttrSyntaxObjects, encoded); + parser->set_top_level(parser, level0); + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case IETF_ATTR_OCTETS: + type = AC_GROUP_TYPE_OCTETS; + break; + case IETF_ATTR_OID: + type = AC_GROUP_TYPE_OID; + break; + case IETF_ATTR_STRING: + type = AC_GROUP_TYPE_STRING; + break; + default: + continue; + } + INIT(group, + .type = type, + .value = chunk_clone(object), + ); + this->groups->insert_last(this->groups, group); + } + success = parser->success(parser); + parser->destroy(parser); + + return success; +} + +/** * ASN.1 definition of an X509 attribute certificate */ static const asn1Object_t acObjects[] = @@ -415,7 +501,10 @@ static bool parse_certificate(private_x509_ac_t *this) break; case OID_GROUP: DBG2(DBG_ASN, "-- > --"); - this->groups = ietf_attributes_create_from_encoding(object); + if (!parse_groups(this, object, level)) + { + goto end; + } DBG2(DBG_ASN, "-- < --"); break; case OID_ROLE: @@ -545,9 +634,55 @@ static chunk_t build_attribute_type(int type, chunk_t content) */ static chunk_t build_attributes(private_x509_ac_t *this) { + enumerator_t *enumerator; + group_t *group; + chunk_t values; + size_t size = 0, len; + u_char *pos; + + /* precalculate the total size of all values */ + enumerator = this->groups->create_enumerator(this->groups); + while (enumerator->enumerate(enumerator, &group)) + { + len = group->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->groups->create_enumerator(this->groups); + while (enumerator->enumerate(enumerator, &group)) + { + chunk_t attr; + asn1_t type; + + switch (group->type) + { + case AC_GROUP_TYPE_OCTETS: + type = ASN1_OCTET_STRING; + break; + case AC_GROUP_TYPE_STRING: + type = ASN1_UTF8STRING; + break; + case AC_GROUP_TYPE_OID: + type = ASN1_OID; + break; + default: + continue; + } + attr = asn1_simple_object(type, group->value); + + memcpy(pos, attr.ptr, attr.len); + pos += attr.len; + free(attr.ptr); + } + enumerator->destroy(enumerator); + return asn1_wrap(ASN1_SEQUENCE, "m", - build_attribute_type(OID_GROUP, - this->groups->get_encoding(this->groups))); + build_attribute_type(OID_GROUP, + asn1_wrap(ASN1_SEQUENCE, "m", values))); } /** @@ -655,10 +790,28 @@ METHOD(ac_t, get_authKeyIdentifier, chunk_t, return this->authKeyIdentifier; } +/** + * Filter function for attribute enumeration + */ +static bool attr_filter(void *null, group_t **in, ac_group_type_t *type, + void *in2, chunk_t *out) +{ + if ((*in)->type == AC_GROUP_TYPE_STRING && + !chunk_printable((*in)->value, NULL, 0)) + { /* skip non-printable strings */ + return FALSE; + } + *type = (*in)->type; + *out = (*in)->value; + return TRUE; +} + METHOD(ac_t, create_group_enumerator, enumerator_t*, private_x509_ac_t *this) { - return this->groups->create_enumerator(this->groups); + return enumerator_create_filter( + this->groups->create_enumerator(this->groups), + (void*)attr_filter, NULL, NULL); } METHOD(certificate_t, get_type, certificate_type_t, @@ -830,7 +983,7 @@ METHOD(certificate_t, destroy, void, DESTROY_IF(this->holderCert); DESTROY_IF(this->signerCert); DESTROY_IF(this->signerKey); - DESTROY_IF(this->groups); + this->groups->destroy_function(this->groups, (void*)group_destroy); free(this->serialNumber.ptr); free(this->authKeyIdentifier.ptr); free(this->encoding.ptr); @@ -869,6 +1022,7 @@ static private_x509_ac_t *create_empty(void) .create_group_enumerator = _create_group_enumerator, }, }, + .groups = linked_list_create(), .ref = 1, ); @@ -911,6 +1065,27 @@ x509_ac_t *x509_ac_load(certificate_type_t type, va_list args) } /** + * Parse a comma separated group list into AC group memberships + */ +static void add_groups_from_string(private_x509_ac_t *this, char *str) +{ + enumerator_t *enumerator; + group_t *group; + char *name; + + enumerator = enumerator_create_token(str, ",", " "); + while (enumerator->enumerate(enumerator, &name)) + { + INIT(group, + .type = AC_GROUP_TYPE_STRING, + .value = chunk_clone(chunk_from_str(name)), + ); + this->groups->insert_last(this->groups, group); + } + enumerator->destroy(enumerator); +} + +/** * See header. */ x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args) @@ -932,7 +1107,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: - ac->groups = ietf_attributes_create_from_string(va_arg(args, char*)); + add_groups_from_string(ac, va_arg(args, char*)); continue; case BUILD_CERT: ac->holderCert = va_arg(args, certificate_t*); |