diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/charon/config/backends/local_backend.c | 7 | ||||
-rw-r--r-- | src/charon/config/peer_cfg.c | 32 | ||||
-rw-r--r-- | src/charon/config/peer_cfg.h | 21 | ||||
-rwxr-xr-x | src/charon/control/interfaces/stroke_interface.c | 22 | ||||
-rw-r--r-- | src/libstrongswan/Makefile.am | 1 | ||||
-rw-r--r-- | src/libstrongswan/crypto/ac.c | 264 | ||||
-rw-r--r-- | src/libstrongswan/crypto/ac.h | 9 | ||||
-rw-r--r-- | src/libstrongswan/crypto/ietf_attr_list.c | 353 | ||||
-rw-r--r-- | src/libstrongswan/crypto/ietf_attr_list.h | 81 |
9 files changed, 517 insertions, 273 deletions
diff --git a/src/charon/config/backends/local_backend.c b/src/charon/config/backends/local_backend.c index 2e80cc870..b5795098a 100644 --- a/src/charon/config/backends/local_backend.c +++ b/src/charon/config/backends/local_backend.c @@ -146,6 +146,13 @@ static peer_cfg_t *get_peer_cfg(private_local_backend_t *this, int prio = (wc1 + wc2) * (MAX_CA_PATH_LEN + 1); int pathlen = 0; identification_t *other_candidate_ca = current->get_other_ca(current); + linked_list_t *groups = current->get_groups(current); + + /* is a group membership required? */ + if (groups->get_count(groups) > 0) + { + DBG1(DBG_CFG, " group membership required"); + } /* are there any ca constraints? */ if (other_candidate_ca->get_type(other_candidate_ca) != ID_ANY) diff --git a/src/charon/config/peer_cfg.c b/src/charon/config/peer_cfg.c index 4a802d551..6733df08c 100644 --- a/src/charon/config/peer_cfg.c +++ b/src/charon/config/peer_cfg.c @@ -28,6 +28,7 @@ #include <utils/linked_list.h> #include <utils/identification.h> +#include <crypto/ietf_attr_list.h> ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND, "CERT_ALWAYS_SEND", @@ -105,6 +106,11 @@ struct private_peer_cfg_t { identification_t *other_ca; /** + * we require the other end to belong to at least one group + */ + linked_list_t *groups; + + /** * should we send a certificate */ cert_policy_t cert_policy; @@ -279,10 +285,21 @@ static identification_t *get_my_ca(private_peer_cfg_t *this) return this->my_ca; } +/** + * Implementation of peer_cfg_t.get_other_ca + */ static identification_t *get_other_ca(private_peer_cfg_t *this) { return this->other_ca; -} +} + +/** + * Implementation of peer_cfg_t.get_groups + */ +static linked_list_t *get_groups(private_peer_cfg_t *this) +{ + return this->groups; +} /** * Implementation of peer_cfg_t.get_cert_policy. @@ -417,9 +434,9 @@ static void destroy(private_peer_cfg_t *this) this->other_id->destroy(this->other_id); DESTROY_IF(this->my_ca); DESTROY_IF(this->other_ca); - DESTROY_IF(this->my_virtual_ip); DESTROY_IF(this->other_virtual_ip); + ietfAttr_list_destroy(this->groups); free(this->name); free(this); } @@ -431,10 +448,11 @@ static void destroy(private_peer_cfg_t *this) peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, identification_t *my_id, identification_t *other_id, identification_t *my_ca, identification_t *other_ca, - cert_policy_t cert_policy, auth_method_t auth_method, - eap_type_t eap_type, u_int32_t keyingtries, - u_int32_t lifetime, u_int32_t rekeytime, - u_int32_t jitter, bool reauth, bool mobike, + linked_list_t *groups, cert_policy_t cert_policy, + auth_method_t auth_method, eap_type_t eap_type, + u_int32_t keyingtries, u_int32_t lifetime, + u_int32_t rekeytime, u_int32_t jitter, + bool reauth, bool mobike, u_int32_t dpd_delay, dpd_action_t dpd_action, host_t *my_virtual_ip, host_t *other_virtual_ip) { @@ -451,6 +469,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->public.get_other_id = (identification_t* (*)(peer_cfg_t *))get_other_id; this->public.get_my_ca = (identification_t* (*)(peer_cfg_t *))get_my_ca; this->public.get_other_ca = (identification_t* (*)(peer_cfg_t *))get_other_ca; + this->public.get_groups = (linked_list_t* (*)(peer_cfg_t *))get_groups; this->public.get_cert_policy = (cert_policy_t (*) (peer_cfg_t *))get_cert_policy; this->public.get_auth_method = (auth_method_t (*) (peer_cfg_t *))get_auth_method; this->public.get_eap_type = (eap_type_t (*) (peer_cfg_t *))get_eap_type; @@ -475,6 +494,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->other_id = other_id; this->my_ca = my_ca; this->other_ca = other_ca; + this->groups = groups; this->cert_policy = cert_policy; this->auth_method = auth_method; this->eap_type = eap_type; diff --git a/src/charon/config/peer_cfg.h b/src/charon/config/peer_cfg.h index edbcd956c..1c6051f16 100644 --- a/src/charon/config/peer_cfg.h +++ b/src/charon/config/peer_cfg.h @@ -30,6 +30,7 @@ typedef struct peer_cfg_t peer_cfg_t; #include <library.h> #include <utils/identification.h> +#include <utils/linked_list.h> #include <config/traffic_selector.h> #include <config/proposal.h> #include <config/ike_cfg.h> @@ -194,7 +195,7 @@ struct peer_cfg_t { identification_t* (*get_my_ca)(peer_cfg_t *this); /** - * @brief Get peers CA. + * @brief Get peer CA. * * @param this calling object * @return other ca @@ -202,6 +203,14 @@ struct peer_cfg_t { identification_t* (*get_other_ca)(peer_cfg_t *this); /** + * @brief Get list of group attributes. + * + * @param this calling object + * @return linked list of group attributes + */ + linked_list_t* (*get_groups)(peer_cfg_t *this); + + /** * @brief Should be sent a certificate for this connection? * * @param this calling object @@ -347,6 +356,7 @@ struct peer_cfg_t { * @param other_id identification_t for the remote guy * @param my_ca CA to use for us * @param other_ca CA to use for other + * @param groups list of group memberships * @param cert_policy should we send a certificate payload? * @param auth_method auth method to use to authenticate us * @param eap_type EAP type to use for peer authentication @@ -367,10 +377,11 @@ struct peer_cfg_t { peer_cfg_t *peer_cfg_create(char *name, u_int ikev_version, ike_cfg_t *ike_cfg, identification_t *my_id, identification_t *other_id, identification_t *my_ca, identification_t *other_ca, - cert_policy_t cert_policy, auth_method_t auth_method, - eap_type_t eap_type, u_int32_t keyingtries, - u_int32_t lifetime, u_int32_t rekeytime, - u_int32_t jitter, bool use_reauth, bool use_mobike, + linked_list_t *groups, cert_policy_t cert_policy, + auth_method_t auth_method, eap_type_t eap_type, + u_int32_t keyingtries, u_int32_t lifetime, + u_int32_t rekeytime, u_int32_t jitter, + bool reauth, bool mobike, u_int32_t dpd_delay, dpd_action_t dpd_action, host_t *my_virtual_ip, host_t *other_virtual_ip); diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c index 7350c11d2..0da646532 100755 --- a/src/charon/control/interfaces/stroke_interface.c +++ b/src/charon/control/interfaces/stroke_interface.c @@ -38,6 +38,7 @@ #include <stroke.h> #include <daemon.h> #include <crypto/x509.h> +#include <crypto/ietf_attr_list.h> #include <crypto/ac.h> #include <crypto/ca.h> #include <crypto/crl.h> @@ -238,6 +239,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) bool other_ca_same =FALSE; host_t *my_host, *other_host, *my_subnet, *other_subnet; host_t *my_vip = NULL, *other_vip = NULL; + linked_list_t *my_groups = linked_list_create(); + linked_list_t *other_groups = linked_list_create(); proposal_t *proposal; traffic_selector_t *my_ts, *other_ts; char *interface; @@ -475,6 +478,11 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) DBG2(DBG_CFG, " my ca: '%D'", my_ca); DBG2(DBG_CFG, " other ca:'%D'", other_ca); + if (msg->add_conn.other.groups) + { + ietfAttr_list_create_from_string(msg->add_conn.other.groups, other_groups); + } + /* have a look for an (almost) identical peer config to reuse */ iterator = charon->backends->create_iterator(charon->backends); while (iterator->iterate(iterator, (void**)&peer_cfg)) @@ -485,6 +493,7 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) && my_host->equals(my_host, ike_cfg->get_my_host(ike_cfg)) && other_host->equals(other_host, ike_cfg->get_other_host(ike_cfg)) && other_ca->equals(other_ca, peer_cfg->get_other_ca(peer_cfg)) + && ietfAttr_list_equals(other_groups, peer_cfg->get_groups(peer_cfg)) && peer_cfg->get_ike_version(peer_cfg) == (msg->add_conn.ikev2 ? 2 : 1) && peer_cfg->get_auth_method(peer_cfg) == msg->add_conn.auth_method && peer_cfg->get_eap_type(peer_cfg) == msg->add_conn.eap_type) @@ -507,6 +516,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) other_host->destroy(other_host); other_id->destroy(other_id); other_ca->destroy(other_ca); + ietfAttr_list_destroy(my_groups); + ietfAttr_list_destroy(other_groups); } else { @@ -554,7 +565,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) peer_cfg = peer_cfg_create(msg->add_conn.name, msg->add_conn.ikev2 ? 2 : 1, - ike_cfg, my_id, other_id, my_ca, other_ca, msg->add_conn.me.sendcert, + ike_cfg, my_id, other_id, my_ca, other_ca, other_groups, + msg->add_conn.me.sendcert, msg->add_conn.auth_method, msg->add_conn.eap_type, msg->add_conn.rekey.tries, msg->add_conn.rekey.ike_lifetime, msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin, @@ -1251,6 +1263,7 @@ static void stroke_status(stroke_msg_t *msg, FILE *out, bool all) { identification_t *my_ca = peer_cfg->get_my_ca(peer_cfg); identification_t *other_ca = peer_cfg->get_other_ca(peer_cfg); + linked_list_t *groups = peer_cfg->get_groups(peer_cfg); if (my_ca->get_type(my_ca) != ID_ANY || other_ca->get_type(other_ca) != ID_ANY) @@ -1258,6 +1271,13 @@ static void stroke_status(stroke_msg_t *msg, FILE *out, bool all) fprintf(out, "%12s: CAs: '%D'...'%D'\n", peer_cfg->get_name(peer_cfg), my_ca, other_ca); } + if (groups->get_count(groups) > 0) + { + fprintf(out, "%12s: groups: ", peer_cfg->get_name(peer_cfg)); + ietfAttr_list_list(groups, out); + fprintf(out, "\n"); + } + } children = peer_cfg->create_child_cfg_iterator(peer_cfg); while (children->iterate(children, (void**)&child_cfg)) diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index c7de8b37f..d84e9da6c 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -32,6 +32,7 @@ crypto/hashers/sha1_hasher.c crypto/hashers/sha1_hasher.h \ crypto/hashers/sha2_hasher.c crypto/hashers/sha2_hasher.h \ crypto/hashers/md5_hasher.c crypto/hashers/md5_hasher.h \ crypto/hmac.c crypto/hmac.h \ +crypto/ietf_attr_list.c crypto/ietf_attr_list.h \ crypto/ocsp.c crypto/ocsp.h \ crypto/prfs/fips_prf.c crypto/prfs/fips_prf.h \ crypto/prfs/hmac_prf.c crypto/prfs/hmac_prf.h \ diff --git a/src/libstrongswan/crypto/ac.c b/src/libstrongswan/crypto/ac.c index 7ecf23514..277b7cc5b 100644 --- a/src/libstrongswan/crypto/ac.c +++ b/src/libstrongswan/crypto/ac.c @@ -30,8 +30,10 @@ #include <asn1/asn1.h> #include <asn1/pem.h> #include <crypto/x509.h> +#include <crypto/ietf_attr_list.h> #include <utils/identification.h> #include <utils/linked_list.h> +#include <utils/lexparser.h> #include "ac.h" @@ -145,219 +147,6 @@ struct private_x509ac_t { }; /** - * 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_t ietfAttr_t; - -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; -} - -/** - * 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); - } -} - -/** - * Create a linked list of ietfAttr_t objects from a string - */ -static void ietfAttr_create_from_string(linked_list_t *list, const char *msg) -{ - -} - -/** - * Lists a linked list of ietfAttr_t objects - */ -static void ietfAttr_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 = 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); -} - -/** - * Destroys an ietfAttr_t object - */ -static void ietfAttr_destroy(ietfAttr_t *this) -{ - free(this->value.ptr); - free(this); -} - -/** - * Creates an ietfAttr_t object. - */ -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; -} - -/** - * 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 */ -}; - -#define IETF_ATTR_OCTETS 4 -#define IETF_ATTR_OID 6 -#define IETF_ATTR_STRING 8 -#define IETF_ATTR_ROOF 11 - -/** * ASN.1 definition of roleSyntax */ static const asn1Object_t roleSyntaxObjects[] = @@ -549,43 +338,6 @@ static bool parse_directoryName(chunk_t blob, int level, bool implicit, identifi } /** - * parses ietfAttrSyntax - */ -static void parse_ietfAttrSyntax(chunk_t blob, int level0, linked_list_t *list) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - - while (objectID < IETF_ATTR_ROOF) - { - if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx)) - { - return; - } - - 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; - } - objectID++; - } -} - -/** * parses roleSyntax */ static void parse_roleSyntax(chunk_t blob, int level0) @@ -700,10 +452,10 @@ static bool parse_certificate(chunk_t blob, private_x509ac_t *this) DBG2(" need to parse accessIdentity"); break; case OID_CHARGING_IDENTITY: - parse_ietfAttrSyntax(object, level, this->charging); + ietfAttr_list_create_from_chunk(object, this->charging, level); break; case OID_GROUP: - parse_ietfAttrSyntax(object, level, this->groups); + ietfAttr_list_create_from_chunk(object, this->groups, level); break; case OID_ROLE: parse_roleSyntax(object, level); @@ -781,7 +533,7 @@ static void list(const private_x509ac_t *this, FILE *out, bool utc) /* list all group attributes on a single line */ fprintf(out, " groups: "); - ietfAttr_list(this->groups, out); + ietfAttr_list_list(this->groups, out); fprintf(out, "\n"); fprintf(out, " issuer: '%D'\n", this->issuerName); @@ -830,10 +582,8 @@ static void destroy(private_x509ac_t *this) DESTROY_IF(this->holderIssuer); DESTROY_IF(this->entityName); DESTROY_IF(this->issuerName); - this->charging->destroy_offset(this->charging, - offsetof(ietfAttr_t, destroy)); - this->groups->destroy_offset(this->groups, - offsetof(ietfAttr_t, destroy)); + ietfAttr_list_destroy(this->charging); + ietfAttr_list_destroy(this->groups); free(this->certificate.ptr); free(this); } diff --git a/src/libstrongswan/crypto/ac.h b/src/libstrongswan/crypto/ac.h index dc344292d..9ef145e3c 100644 --- a/src/libstrongswan/crypto/ac.h +++ b/src/libstrongswan/crypto/ac.h @@ -26,6 +26,8 @@ #ifndef AC_H_ #define AC_H_ +#include <library.h> + typedef struct x509ac_t x509ac_t; /** @@ -94,14 +96,13 @@ x509ac_t *x509ac_create_from_chunk(chunk_t chunk); /** * @brief Read a x509 attribute certificate from a DER encoded file. - * + * * @param filename file containing DER encoded data - * @return created x509ac_t certificate, or NULL if invalid. - * + * @return created x509ac_t certificate, or NULL if invalid. + * * @ingroup crypto */ x509ac_t *x509ac_create_from_file(const char *filename); - #endif /* AC_H_ */ diff --git a/src/libstrongswan/crypto/ietf_attr_list.c b/src/libstrongswan/crypto/ietf_attr_list.c new file mode 100644 index 000000000..55d8bbea3 --- /dev/null +++ b/src/libstrongswan/crypto/ietf_attr_list.c @@ -0,0 +1,353 @@ +/** + * @file ietf_attr.c + * + * @brief Implementation of ietfAttr_t. + * + */ + +/* + * 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 <asn1/asn1.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 = 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 */ +}; + +#define IETF_ATTR_OCTETS 4 +#define IETF_ATTR_OID 6 +#define IETF_ATTR_STRING 8 +#define IETF_ATTR_ROOF 11 + +/* + * Described in header. + */ +void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, chunk, level0, FALSE, FALSE); + + while (objectID < IETF_ATTR_ROOF) + { + if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx)) + { + return; + } + + 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; + } + objectID++; + } +} + +/* + * Described in header. + */ +void ietfAttr_list_destroy(linked_list_t *list) +{ + list->destroy_offset(list, offsetof(ietfAttr_t, destroy)); +} diff --git a/src/libstrongswan/crypto/ietf_attr_list.h b/src/libstrongswan/crypto/ietf_attr_list.h new file mode 100644 index 000000000..8352cad5b --- /dev/null +++ b/src/libstrongswan/crypto/ietf_attr_list.h @@ -0,0 +1,81 @@ +/** + * @file ietf_attr_list.h + * + * @brief Handling of ietfAttr_t linked lists + * + */ + +/* + * 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. + */ + +#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 + * + * @ingroup crypto + */ +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 + * + * @ingroup crypto + */ +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 + * + * @ingroup crypto + */ +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 Destroys a linked list of ietfAttr_t objects + * + * @param list list to be destroyed + * + * @ingroup crypto + */ +void ietfAttr_list_destroy(linked_list_t *list); + +#endif /* IETF_ATTR_LIST_H_ */ + |