diff options
Diffstat (limited to 'src/libcharon/config')
-rw-r--r-- | src/libcharon/config/backend.h | 2 | ||||
-rw-r--r-- | src/libcharon/config/backend_manager.c | 122 | ||||
-rw-r--r-- | src/libcharon/config/backend_manager.h | 9 | ||||
-rw-r--r-- | src/libcharon/config/child_cfg.c | 96 | ||||
-rw-r--r-- | src/libcharon/config/child_cfg.h | 14 | ||||
-rw-r--r-- | src/libcharon/config/ike_cfg.c | 79 | ||||
-rw-r--r-- | src/libcharon/config/ike_cfg.h | 120 | ||||
-rw-r--r-- | src/libcharon/config/peer_cfg.c | 172 | ||||
-rw-r--r-- | src/libcharon/config/peer_cfg.h | 101 | ||||
-rw-r--r-- | src/libcharon/config/proposal.c | 643 | ||||
-rw-r--r-- | src/libcharon/config/proposal.h | 11 |
11 files changed, 775 insertions, 594 deletions
diff --git a/src/libcharon/config/backend.h b/src/libcharon/config/backend.h index 458abc37f..aca3352ba 100644 --- a/src/libcharon/config/backend.h +++ b/src/libcharon/config/backend.h @@ -26,7 +26,7 @@ typedef struct backend_t backend_t; #include <library.h> #include <config/ike_cfg.h> #include <config/peer_cfg.h> -#include <utils/linked_list.h> +#include <collections/linked_list.h> /** * The interface for a configuration backend. diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c index a93457ea4..f47d5715a 100644 --- a/src/libcharon/config/backend_manager.c +++ b/src/libcharon/config/backend_manager.c @@ -18,7 +18,7 @@ #include <sys/types.h> #include <daemon.h> -#include <utils/linked_list.h> +#include <collections/linked_list.h> #include <threading/rwlock.h> @@ -49,10 +49,16 @@ struct private_backend_manager_t { * match of an ike_cfg */ typedef enum ike_cfg_match_t { - MATCH_NONE = 0x00, - MATCH_ANY = 0x01, - MATCH_ME = 0x04, - MATCH_OTHER = 0x08, + /* doesn't match at all */ + MATCH_NONE = 0x00, + /* match for a %any host. For both hosts, hence skip 0x02 */ + MATCH_ANY = 0x01, + /* IKE version matches exactly (config is not for any version) */ + MATCH_VERSION = 0x04, + /* local identity matches */ + MATCH_ME = 0x08, + /* remote identity matches */ + MATCH_OTHER = 0x10, } ike_cfg_match_t; /** @@ -75,15 +81,24 @@ static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data) /** * get a match of a candidate ike_cfg for two hosts */ -static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other) +static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other, + ike_version_t version) { host_t *me_cand, *other_cand; + char *my_addr, *other_addr; + bool my_allow_any, other_allow_any; ike_cfg_match_t match = MATCH_NONE; + if (cand->get_version(cand) != IKE_ANY && + version != cand->get_version(cand)) + { + return MATCH_NONE; + } + if (me) { - me_cand = host_create_from_dns(cand->get_my_addr(cand), - me->get_family(me), 0); + my_addr = cand->get_my_addr(cand, &my_allow_any); + me_cand = host_create_from_dns(my_addr, me->get_family(me), 0); if (!me_cand) { return MATCH_NONE; @@ -92,7 +107,7 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other) { match += MATCH_ME; } - else if (me_cand->is_anyaddr(me_cand)) + else if (my_allow_any || me_cand->is_anyaddr(me_cand)) { match += MATCH_ANY; } @@ -110,8 +125,8 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other) if (other) { - other_cand = host_create_from_dns(cand->get_other_addr(cand), - other->get_family(other), 0); + other_addr = cand->get_other_addr(cand, &other_allow_any); + other_cand = host_create_from_dns(other_addr, other->get_family(other), 0); if (!other_cand) { return MATCH_NONE; @@ -120,7 +135,7 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other) { match += MATCH_OTHER; } - else if (other_cand->is_anyaddr(other_cand)) + else if (other_allow_any || other_cand->is_anyaddr(other_cand)) { match += MATCH_ANY; } @@ -135,21 +150,31 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other) { match += MATCH_ANY; } + + if (match != MATCH_NONE && + cand->get_version(cand) != IKE_ANY) + { /* if we have a match, improve it if candidate version specified */ + match += MATCH_VERSION; + } return match; } METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, - private_backend_manager_t *this, host_t *me, host_t *other) + private_backend_manager_t *this, host_t *me, host_t *other, + ike_version_t version) { ike_cfg_t *current, *found = NULL; + char *my_addr, *other_addr; + bool my_allow_any, other_allow_any; enumerator_t *enumerator; ike_cfg_match_t match, best = MATCH_ANY; ike_data_t *data; - data = malloc_thing(ike_data_t); - data->this = this; - data->me = me; - data->other = other; + INIT(data, + .this = this, + .me = me, + .other = other, + ); DBG2(DBG_CFG, "looking for an ike config for %H...%H", me, other); @@ -159,13 +184,16 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, (void*)ike_enum_create, data, (void*)free); while (enumerator->enumerate(enumerator, (void**)¤t)) { - match = get_ike_match(current, me, other); - + match = get_ike_match(current, me, other, version); + DBG3(DBG_CFG, "ike config match: %d (%H %H %N)", + match, me, other, ike_version_names, version); if (match) { - DBG2(DBG_CFG, " candidate: %s...%s, prio %d", - current->get_my_addr(current), - current->get_other_addr(current), match); + my_addr = current->get_my_addr(current, &my_allow_any); + other_addr = current->get_other_addr(current, &other_allow_any); + DBG2(DBG_CFG, " candidate: %s%s...%s%s, prio %d", + my_allow_any ? "%":"", my_addr, + other_allow_any ? "%":"", other_addr, match); if (match > best) { DESTROY_IF(found); @@ -179,8 +207,11 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, this->lock->unlock(this->lock); if (found) { - DBG2(DBG_CFG, "found matching ike config: %s...%s with prio %d", - found->get_my_addr(found), found->get_other_addr(found), best); + my_addr = found->get_my_addr(found, &my_allow_any); + other_addr = found->get_other_addr(found, &other_allow_any); + DBG2(DBG_CFG, "found matching ike config: %s%s...%s%s with prio %d", + my_allow_any ? "%":"", my_addr, + other_allow_any ? "%":"", other_addr, best); } return found; } @@ -195,9 +226,13 @@ static id_match_t get_peer_match(identification_t *id, auth_cfg_t *auth; identification_t *candidate; id_match_t match = ID_MATCH_NONE; + char *where = local ? "local" : "remote"; + chunk_t data; if (!id) { + DBG3(DBG_CFG, "peer config match %s: %d (%N)", + where, ID_MATCH_ANY, id_type_names, ID_ANY); return ID_MATCH_ANY; } @@ -221,6 +256,10 @@ static id_match_t get_peer_match(identification_t *id, } } enumerator->destroy(enumerator); + + data = id->get_encoding(id); + DBG3(DBG_CFG, "peer config match %s: %d (%N -> %#B)", + where, match, id_type_names, id->get_type(id), &data); return match; } @@ -317,17 +356,18 @@ static void insert_sorted(match_entry_t *entry, linked_list_t *list, METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, private_backend_manager_t *this, host_t *me, host_t *other, - identification_t *my_id, identification_t *other_id) + identification_t *my_id, identification_t *other_id, ike_version_t version) { enumerator_t *enumerator; peer_data_t *data; peer_cfg_t *cfg; linked_list_t *configs, *helper; - data = malloc_thing(peer_data_t); - data->lock = this->lock; - data->me = my_id; - data->other = other_id; + INIT(data, + .lock = this->lock, + .me = my_id, + .other = other_id, + ); /* create a sorted list with all matches */ this->lock->read_lock(this->lock); @@ -340,9 +380,6 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, return enumerator; } - DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]", - me, my_id, other, other_id); - configs = linked_list_create(); /* only once allocated helper list for sorting */ helper = linked_list_create(); @@ -351,28 +388,23 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, id_match_t match_peer_me, match_peer_other; ike_cfg_match_t match_ike; match_entry_t *entry; - chunk_t data; match_peer_me = get_peer_match(my_id, cfg, TRUE); - data = my_id->get_encoding(my_id); - DBG3(DBG_CFG, "match_peer_me: %d (%N -> %#B)", match_peer_me, - id_type_names, my_id->get_type(my_id), &data); match_peer_other = get_peer_match(other_id, cfg, FALSE); - data = other_id->get_encoding(other_id); - DBG3(DBG_CFG, "match_peer_other: %d (%N -> %#B)", match_peer_other, - id_type_names, other_id->get_type(other_id), &data); - match_ike = get_ike_match(cfg->get_ike_cfg(cfg), me, other); - DBG3(DBG_CFG, "match_ike: %d (%H %H)", match_ike, me, other); + match_ike = get_ike_match(cfg->get_ike_cfg(cfg), me, other, version); + DBG3(DBG_CFG, "ike config match: %d (%H %H %N)", + match_ike, me, other, ike_version_names, version); if (match_peer_me && match_peer_other && match_ike) { DBG2(DBG_CFG, " candidate \"%s\", match: %d/%d/%d (me/other/ike)", cfg->get_name(cfg), match_peer_me, match_peer_other, match_ike); - entry = malloc_thing(match_entry_t); - entry->match_peer = match_peer_me + match_peer_other; - entry->match_ike = match_ike; - entry->cfg = cfg->get_ref(cfg); + INIT(entry, + .match_peer = match_peer_me + match_peer_other, + .match_ike = match_ike, + .cfg = cfg->get_ref(cfg), + ); insert_sorted(entry, configs, helper); } } diff --git a/src/libcharon/config/backend_manager.h b/src/libcharon/config/backend_manager.h index 5b394f791..cc8ef8785 100644 --- a/src/libcharon/config/backend_manager.h +++ b/src/libcharon/config/backend_manager.h @@ -24,7 +24,7 @@ typedef struct backend_manager_t backend_manager_t; #include <library.h> -#include <utils/host.h> +#include <networking/host.h> #include <utils/identification.h> #include <config/ike_cfg.h> #include <config/peer_cfg.h> @@ -56,10 +56,12 @@ struct backend_manager_t { * * @param my_host address of own host * @param other_host address of remote host + * @param version IKE version to get a config for * @return matching ike_config, or NULL if none found */ ike_cfg_t* (*get_ike_cfg)(backend_manager_t *this, - host_t *my_host, host_t *other_host); + host_t *my_host, host_t *other_host, + ike_version_t version); /** * Get a peer_config identified by it's name. @@ -79,11 +81,12 @@ struct backend_manager_t { * @param other remote address * @param my_id IDr in first authentication round * @param other_id IDi in first authentication round + * @param version IKE version to get a config for * @return enumerator over peer_cfg_t */ enumerator_t* (*create_peer_cfg_enumerator)(backend_manager_t *this, host_t *me, host_t *other, identification_t *my_id, - identification_t *other_id); + identification_t *other_id, ike_version_t version); /** * Register a backend on the manager. * diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index 74949be3c..6fe7d44b8 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -165,12 +165,14 @@ METHOD(child_cfg_t, get_proposals, linked_list_t*, current = current->clone(current); if (strip_dh) { - current->strip_dh(current); + current->strip_dh(current, MODP_NONE); } proposals->insert_last(proposals, current); } enumerator->destroy(enumerator); + DBG2(DBG_CFG, "configured proposals: %#P", proposals); + return proposals; } @@ -192,7 +194,7 @@ METHOD(child_cfg_t, select_proposal, proposal_t*, { if (strip_dh) { - stored->strip_dh(stored); + stored->strip_dh(stored, MODP_NONE); } selected = stored->select(stored, supplied, private); if (selected) @@ -235,12 +237,16 @@ METHOD(child_cfg_t, add_traffic_selector, void, } METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*, - private_child_cfg_t *this, bool local, linked_list_t *supplied, host_t *host) + private_child_cfg_t *this, bool local, linked_list_t *supplied, + linked_list_t *hosts) { enumerator_t *e1, *e2; traffic_selector_t *ts1, *ts2, *selected; - linked_list_t *result = linked_list_create(); + linked_list_t *result, *derived; + host_t *host; + result = linked_list_create(); + derived = linked_list_create(); if (local) { e1 = this->my_ts->create_enumerator(this->my_ts); @@ -249,41 +255,47 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*, { e1 = this->other_ts->create_enumerator(this->other_ts); } - - /* no list supplied, just fetch the stored traffic selectors */ - if (supplied == NULL) + /* In a first step, replace "dynamic" TS with the host list */ + while (e1->enumerate(e1, &ts1)) { - DBG2(DBG_CFG, "proposing traffic selectors for %s:", - local ? "us" : "other"); - while (e1->enumerate(e1, &ts1)) + if (hosts && hosts->get_count(hosts) && + ts1->is_dynamic(ts1)) { - /* we make a copy of the TS, this allows us to update dynamic TS' */ - selected = ts1->clone(ts1); - if (host) + e2 = hosts->create_enumerator(hosts); + while (e2->enumerate(e2, &host)) { - selected->set_address(selected, host); + ts2 = ts1->clone(ts1); + ts2->set_address(ts2, host); + derived->insert_last(derived, ts2); } - DBG2(DBG_CFG, " %R (derived from %R)", selected, ts1); - result->insert_last(result, selected); + e2->destroy(e2); } - e1->destroy(e1); + else + { + derived->insert_last(derived, ts1->clone(ts1)); + } + } + e1->destroy(e1); + + DBG2(DBG_CFG, "%s traffic selectors for %s:", + supplied ? "selecting" : "proposing", local ? "us" : "other"); + if (supplied == NULL) + { + while (derived->remove_first(derived, (void**)&ts1) == SUCCESS) + { + DBG2(DBG_CFG, " %R", ts1); + result->insert_last(result, ts1); + } + derived->destroy(derived); } else { - DBG2(DBG_CFG, "selecting traffic selectors for %s:", - local ? "us" : "other"); + e1 = derived->create_enumerator(derived); e2 = supplied->create_enumerator(supplied); - /* iterate over all stored selectors */ + /* enumerate all configured/derived selectors */ while (e1->enumerate(e1, &ts1)) { - /* we make a copy of the TS, as we have to update dynamic TS' */ - ts1 = ts1->clone(ts1); - if (host) - { - ts1->set_address(ts1, host); - } - - /* iterate over all supplied traffic selectors */ + /* enumerate all supplied traffic selectors */ while (e2->enumerate(e2, &ts2)) { selected = ts1->get_subset(ts1, ts2); @@ -299,12 +311,27 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*, ts1, ts2); } } - e2->destroy(e2); - e2 = supplied->create_enumerator(supplied); - ts1->destroy(ts1); + supplied->reset_enumerator(supplied, e2); } e1->destroy(e1); e2->destroy(e2); + + /* check if we/peer did any narrowing, raise alert */ + e1 = derived->create_enumerator(derived); + e2 = result->create_enumerator(result); + while (e1->enumerate(e1, &ts1)) + { + if (!e2->enumerate(e2, &ts2) || !ts1->equals(ts1, ts2)) + { + charon->bus->alert(charon->bus, ALERT_TS_NARROWED, + local, result, this); + break; + } + } + e1->destroy(e1); + e2->destroy(e2); + + derived->destroy_offset(derived, offsetof(traffic_selector_t, destroy)); } /* remove any redundant traffic selectors in the list */ @@ -320,16 +347,14 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*, { result->remove_at(result, e2); ts2->destroy(ts2); - e1->destroy(e1); - e1 = result->create_enumerator(result); + result->reset_enumerator(result, e1); break; } if (ts1->is_contained_in(ts1, ts2)) { result->remove_at(result, e1); ts1->destroy(ts1); - e2->destroy(e2); - e2 = result->create_enumerator(result); + result->reset_enumerator(result, e2); break; } } @@ -566,4 +591,3 @@ child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime, return &this->public; } - diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index 370ff9d58..20d1fa811 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -129,12 +129,12 @@ struct child_cfg_t { * * @param local TRUE for TS on local side, FALSE for remote * @param supplied list with TS to select from, or NULL - * @param host address to use for narrowing "dynamic" TS', or NULL + * @param hosts addresses to use for narrowing "dynamic" TS', host_t * @return list containing the traffic selectors */ linked_list_t *(*get_traffic_selectors)(child_cfg_t *this, bool local, linked_list_t *supplied, - host_t *host); + linked_list_t *hosts); /** * Get the updown script to run for the CHILD_SA. * @@ -213,14 +213,14 @@ struct child_cfg_t { u_int32_t (*get_inactivity)(child_cfg_t *this); /** - * Specific reqid to use for CHILD_SA + * Specific reqid to use for CHILD_SA. * * @return reqid */ u_int32_t (*get_reqid)(child_cfg_t *this); /** - * Optional mark for CHILD_SA + * Optional mark for CHILD_SA. * * @param inbound TRUE for inbound, FALSE for outbound * @return mark @@ -235,7 +235,7 @@ struct child_cfg_t { u_int32_t (*get_tfc)(child_cfg_t *this); /** - * Sets two options needed for Mobile IPv6 interoperability + * Sets two options needed for Mobile IPv6 interoperability. * * @param proxy_mode use IPsec transport proxy mode (default FALSE) * @param install_policy install IPsec kernel policies (default TRUE) @@ -244,7 +244,7 @@ struct child_cfg_t { bool install_policy); /** - * Check whether IPsec transport SA should be set up in proxy mode + * Check whether IPsec transport SA should be set up in proxy mode. * * @return TRUE, if proxy mode should be used * FALSE, otherwise @@ -252,7 +252,7 @@ struct child_cfg_t { bool (*use_proxy_mode)(child_cfg_t *this); /** - * Check whether IPsec policies should be installed in the kernel + * Check whether IPsec policies should be installed in the kernel. * * @return TRUE, if IPsec kernel policies should be installed * FALSE, otherwise diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c index 342b9ddbe..54a054e40 100644 --- a/src/libcharon/config/ike_cfg.c +++ b/src/libcharon/config/ike_cfg.c @@ -21,6 +21,12 @@ #include <daemon.h> +ENUM(ike_version_names, IKE_ANY, IKEV2, + "IKEv1/2", + "IKEv1", + "IKEv2", +); + typedef struct private_ike_cfg_t private_ike_cfg_t; /** @@ -39,6 +45,11 @@ struct private_ike_cfg_t { refcount_t refcount; /** + * IKE version to use + */ + ike_version_t version; + + /** * Address of local host */ char *me; @@ -49,6 +60,16 @@ struct private_ike_cfg_t { char *other; /** + * Allow override of local address + */ + bool my_allow_any; + + /** + * Allow override of remote address + */ + bool other_allow_any; + + /** * our source port */ u_int16_t my_port; @@ -69,11 +90,27 @@ struct private_ike_cfg_t { bool force_encap; /** + * use IKEv1 fragmentation + */ + fragmentation_t fragmentation; + + /** + * DSCP value to use on sent IKE packets + */ + u_int8_t dscp; + + /** * List of proposals to use */ linked_list_t *proposals; }; +METHOD(ike_cfg_t, get_version, ike_version_t, + private_ike_cfg_t *this) +{ + return this->version; +} + METHOD(ike_cfg_t, send_certreq, bool, private_ike_cfg_t *this) { @@ -86,15 +123,29 @@ METHOD(ike_cfg_t, force_encap_, bool, return this->force_encap; } -METHOD(ike_cfg_t, get_my_addr, char*, +METHOD(ike_cfg_t, fragmentation, fragmentation_t, private_ike_cfg_t *this) { + return this->fragmentation; +} + +METHOD(ike_cfg_t, get_my_addr, char*, + private_ike_cfg_t *this, bool *allow_any) +{ + if (allow_any) + { + *allow_any = this->my_allow_any; + } return this->me; } METHOD(ike_cfg_t, get_other_addr, char*, - private_ike_cfg_t *this) + private_ike_cfg_t *this, bool *allow_any) { + if (allow_any) + { + *allow_any = this->other_allow_any; + } return this->other; } @@ -110,6 +161,12 @@ METHOD(ike_cfg_t, get_other_port, u_int16_t, return this->other_port; } +METHOD(ike_cfg_t, get_dscp, u_int8_t, + private_ike_cfg_t *this) +{ + return this->dscp; +} + METHOD(ike_cfg_t, add_proposal, void, private_ike_cfg_t *this, proposal_t *proposal) { @@ -132,6 +189,8 @@ METHOD(ike_cfg_t, get_proposals, linked_list_t*, } enumerator->destroy(enumerator); + DBG2(DBG_CFG, "configured proposals: %#P", proposals); + return proposals; } @@ -228,8 +287,10 @@ METHOD(ike_cfg_t, equals, bool, e2->destroy(e2); return (eq && + this->version == other->version && this->certreq == other->certreq && this->force_encap == other->force_encap && + this->fragmentation == other->fragmentation && streq(this->me, other->me) && streq(this->other, other->other) && this->my_port == other->my_port && @@ -259,19 +320,24 @@ METHOD(ike_cfg_t, destroy, void, /** * Described in header. */ -ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap, - char *me, u_int16_t my_port, char *other, u_int16_t other_port) +ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, + char *me, bool my_allow_any, u_int16_t my_port, + char *other, bool other_allow_any, u_int16_t other_port, + fragmentation_t fragmentation, u_int8_t dscp) { private_ike_cfg_t *this; INIT(this, .public = { + .get_version = _get_version, .send_certreq = _send_certreq, .force_encap = _force_encap_, + .fragmentation = _fragmentation, .get_my_addr = _get_my_addr, .get_other_addr = _get_other_addr, .get_my_port = _get_my_port, .get_other_port = _get_other_port, + .get_dscp = _get_dscp, .add_proposal = _add_proposal, .get_proposals = _get_proposals, .select_proposal = _select_proposal, @@ -281,12 +347,17 @@ ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap, .destroy = _destroy, }, .refcount = 1, + .version = version, .certreq = certreq, .force_encap = force_encap, + .fragmentation = fragmentation, .me = strdup(me), .other = strdup(other), + .my_allow_any = my_allow_any, + .other_allow_any = other_allow_any, .my_port = my_port, .other_port = other_port, + .dscp = dscp, .proposals = linked_list_create(), ); diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h index f1edde255..719ceb9dd 100644 --- a/src/libcharon/config/ike_cfg.h +++ b/src/libcharon/config/ike_cfg.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -22,16 +23,47 @@ #ifndef IKE_CFG_H_ #define IKE_CFG_H_ +typedef enum ike_version_t ike_version_t; +typedef enum fragmentation_t fragmentation_t; typedef struct ike_cfg_t ike_cfg_t; #include <library.h> -#include <utils/host.h> -#include <utils/linked_list.h> +#include <networking/host.h> +#include <collections/linked_list.h> #include <utils/identification.h> #include <config/proposal.h> #include <crypto/diffie_hellman.h> /** + * IKE version. + */ +enum ike_version_t { + /** any version */ + IKE_ANY = 0, + /** IKE version 1 */ + IKEV1 = 1, + /** IKE version 2 */ + IKEV2 = 2, +}; + +/** + * Proprietary IKEv1 fragmentation + */ +enum fragmentation_t { + /** disable fragmentation */ + FRAGMENTATION_NO, + /** enable fragmentation if supported by peer */ + FRAGMENTATION_YES, + /** force use of fragmentation (even for the first message) */ + FRAGMENTATION_FORCE, +}; + +/** + * enum strings fro ike_version_t + */ +extern enum_name_t *ike_version_names; + +/** * An ike_cfg_t defines the rules to set up an IKE_SA. * * @see peer_cfg_t to get an overview over the configurations. @@ -39,40 +71,56 @@ typedef struct ike_cfg_t ike_cfg_t; struct ike_cfg_t { /** + * Get the IKE version to use with this configuration. + * + * @return IKE major version + */ + ike_version_t (*get_version)(ike_cfg_t *this); + + /** * Get own address. * - * @return string of address/DNS name + * @param allow_any allow any address to match + * @return string of address/DNS name */ - char* (*get_my_addr) (ike_cfg_t *this); + char* (*get_my_addr) (ike_cfg_t *this, bool *allow_any); /** - * Get peers address. + * Get peer's address. * - * @return string of address/DNS name + * @param allow_any allow any address to match + * @return string of address/DNS name */ - char* (*get_other_addr) (ike_cfg_t *this); + char* (*get_other_addr) (ike_cfg_t *this, bool *allow_any); /** * Get the port to use as our source port. * - * @return source address port, host order + * @return source address port, host order */ u_int16_t (*get_my_port)(ike_cfg_t *this); /** * Get the port to use as destination port. * - * @return destination address, host order + * @return destination address, host order */ u_int16_t (*get_other_port)(ike_cfg_t *this); /** + * Get the DSCP value to use for IKE packets send from connections. + * + * @return DSCP value + */ + u_int8_t (*get_dscp)(ike_cfg_t *this); + + /** * Adds a proposal to the list. * * The first added proposal has the highest priority, the last * added the lowest. * - * @param proposal proposal to add + * @param proposal proposal to add */ void (*add_proposal) (ike_cfg_t *this, proposal_t *proposal); @@ -81,7 +129,7 @@ struct ike_cfg_t { * * Returned list and its proposals must be destroyed after use. * - * @return list containing all the proposals + * @return list containing all the proposals */ linked_list_t* (*get_proposals) (ike_cfg_t *this); @@ -90,9 +138,9 @@ struct ike_cfg_t { * * Returned proposal must be destroyed after use. * - * @param proposals list of proposals to select from - * @param private accept algorithms from a private range - * @return selected proposal, or NULL if none matches. + * @param proposals list of proposals to select from + * @param private accept algorithms from a private range + * @return selected proposal, or NULL if none matches. */ proposal_t *(*select_proposal) (ike_cfg_t *this, linked_list_t *proposals, bool private); @@ -100,36 +148,43 @@ struct ike_cfg_t { /** * Should we send a certificate request in IKE_SA_INIT? * - * @return certificate request sending policy + * @return certificate request sending policy */ bool (*send_certreq) (ike_cfg_t *this); /** * Enforce UDP encapsulation by faking NATD notifies? * - * @return TRUE to enfoce UDP encapsulation + * @return TRUE to enforce UDP encapsulation */ bool (*force_encap) (ike_cfg_t *this); /** + * Use proprietary IKEv1 fragmentation + * + * @return TRUE to use fragmentation + */ + fragmentation_t (*fragmentation) (ike_cfg_t *this); + + /** * Get the DH group to use for IKE_SA setup. * - * @return dh group to use for initialization + * @return dh group to use for initialization */ diffie_hellman_group_t (*get_dh_group)(ike_cfg_t *this); /** * Check if two IKE configs are equal. * - * @param other other to check for equality - * @return TRUE if other equal to this + * @param other other to check for equality + * @return TRUE if other equal to this */ bool (*equals)(ike_cfg_t *this, ike_cfg_t *other); /** * Increase reference count. * - * @return reference to this + * @return reference to this */ ike_cfg_t* (*get_ref) (ike_cfg_t *this); @@ -147,15 +202,22 @@ struct ike_cfg_t { * * Supplied hosts become owned by ike_cfg, the name gets cloned. * - * @param certreq TRUE to send a certificate request - * @param force_encap enforce UDP encapsulation by faking NATD notify - * @param me address/DNS name of local peer - * @param my_port IKE port to use as source, 500 uses IKEv2 port floating - * @param other address/DNS name of remote peer - * @param other_port IKE port to use as dest, 500 uses IKEv2 port floating - * @return ike_cfg_t object. + * @param version IKE major version to use for this config + * @param certreq TRUE to send a certificate request + * @param force_encap enforce UDP encapsulation by faking NATD notify + * @param me address/DNS name of local peer + * @param my_allow_any allow override of local address by any address + * @param my_port IKE port to use as source, 500 uses IKEv2 port floating + * @param other address/DNS name of remote peer + * @param other_allow_any allow override of remote address by any address + * @param other_port IKE port to use as dest, 500 uses IKEv2 port floating + * @param fragmentation use IKEv1 fragmentation + * @param dscp DSCP value to send IKE packets with + * @return ike_cfg_t object. */ -ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap, - char *me, u_int16_t my_port, char *other, u_int16_t other_port); +ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, + char *me, bool my_allow_any, u_int16_t my_port, + char *other, bool other_allow_any, u_int16_t other_port, + fragmentation_t fragmentation, u_int8_t dscp); #endif /** IKE_CFG_H_ @}*/ diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index c623cbc9b..eb983199b 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -22,7 +22,7 @@ #include <daemon.h> #include <threading/mutex.h> -#include <utils/linked_list.h> +#include <collections/linked_list.h> #include <utils/identification.h> ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND, @@ -60,11 +60,6 @@ struct private_peer_cfg_t { char *name; /** - * IKE version to use for initiation - */ - u_int ike_version; - - /** * IKE config associated to this peer config */ ike_cfg_t *ike_cfg; @@ -100,6 +95,11 @@ struct private_peer_cfg_t { bool use_mobike; /** + * Use aggressive mode? + */ + bool aggressive; + + /** * Time before starting rekeying */ u_int32_t rekey_time; @@ -125,14 +125,19 @@ struct private_peer_cfg_t { u_int32_t dpd; /** - * virtual IP to use locally + * DPD timeout intervall (used for IKEv1 only) */ - host_t *virtual_ip; + u_int32_t dpd_timeout; /** - * pool to acquire configuration attributes from + * List of virtual IPs (host_t*) to request */ - char *pool; + linked_list_t *vips; + + /** + * List of pool names to use for virtual IP lookup + */ + linked_list_t *pools; /** * local authentication configs (rulesets) @@ -169,10 +174,10 @@ METHOD(peer_cfg_t, get_name, char*, return this->name; } -METHOD(peer_cfg_t, get_ike_version, u_int, +METHOD(peer_cfg_t, get_ike_version, ike_version_t, private_peer_cfg_t *this) { - return this->ike_version; + return this->ike_cfg->get_version(this->ike_cfg); } METHOD(peer_cfg_t, get_ike_cfg, ike_cfg_t*, @@ -240,15 +245,15 @@ METHOD(peer_cfg_t, create_child_cfg_enumerator, enumerator_t*, * Check how good a list of TS matches a given child config */ static int get_ts_match(child_cfg_t *cfg, bool local, - linked_list_t *sup_list, host_t *host) + linked_list_t *sup_list, linked_list_t *hosts) { linked_list_t *cfg_list; enumerator_t *sup_enum, *cfg_enum; - traffic_selector_t *sup_ts, *cfg_ts; + traffic_selector_t *sup_ts, *cfg_ts, *subset; int match = 0, round; /* fetch configured TS list, narrowing dynamic TS */ - cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, host); + cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, hosts); /* use a round counter to rate leading TS with higher priority */ round = sup_list->get_count(sup_list); @@ -263,10 +268,14 @@ static int get_ts_match(child_cfg_t *cfg, bool local, { /* equality is honored better than matches */ match += round * 5; } - else if (cfg_ts->is_contained_in(cfg_ts, sup_ts) || - sup_ts->is_contained_in(sup_ts, cfg_ts)) + else { - match += round * 1; + subset = cfg_ts->get_subset(cfg_ts, sup_ts); + if (subset) + { + subset->destroy(subset); + match += round * 1; + } } } cfg_enum->destroy(cfg_enum); @@ -281,7 +290,7 @@ static int get_ts_match(child_cfg_t *cfg, bool local, METHOD(peer_cfg_t, select_child_cfg, child_cfg_t*, private_peer_cfg_t *this, linked_list_t *my_ts, linked_list_t *other_ts, - host_t *my_host, host_t *other_host) + linked_list_t *my_hosts, linked_list_t *other_hosts) { child_cfg_t *current, *found = NULL; enumerator_t *enumerator; @@ -293,8 +302,8 @@ METHOD(peer_cfg_t, select_child_cfg, child_cfg_t*, { int my_prio, other_prio; - my_prio = get_ts_match(current, TRUE, my_ts, my_host); - other_prio = get_ts_match(current, FALSE, other_ts, other_host); + my_prio = get_ts_match(current, TRUE, my_ts, my_hosts); + other_prio = get_ts_match(current, FALSE, other_ts, other_hosts); if (my_prio && other_prio) { @@ -336,13 +345,13 @@ METHOD(peer_cfg_t, get_keyingtries, u_int32_t, } METHOD(peer_cfg_t, get_rekey_time, u_int32_t, - private_peer_cfg_t *this) + private_peer_cfg_t *this, bool jitter) { if (this->rekey_time == 0) { return 0; } - if (this->jitter_time == 0) + if (this->jitter_time == 0 || !jitter) { return this->rekey_time; } @@ -350,13 +359,13 @@ METHOD(peer_cfg_t, get_rekey_time, u_int32_t, } METHOD(peer_cfg_t, get_reauth_time, u_int32_t, - private_peer_cfg_t *this) + private_peer_cfg_t *this, bool jitter) { if (this->reauth_time == 0) { return 0; } - if (this->jitter_time == 0) + if (this->jitter_time == 0 || !jitter) { return this->reauth_time; } @@ -375,22 +384,46 @@ METHOD(peer_cfg_t, use_mobike, bool, return this->use_mobike; } +METHOD(peer_cfg_t, use_aggressive, bool, + private_peer_cfg_t *this) +{ + return this->aggressive; +} + METHOD(peer_cfg_t, get_dpd, u_int32_t, private_peer_cfg_t *this) { return this->dpd; } -METHOD(peer_cfg_t, get_virtual_ip, host_t*, +METHOD(peer_cfg_t, get_dpd_timeout, u_int32_t, private_peer_cfg_t *this) { - return this->virtual_ip; + return this->dpd_timeout; +} + +METHOD(peer_cfg_t, add_virtual_ip, void, + private_peer_cfg_t *this, host_t *vip) +{ + this->vips->insert_last(this->vips, vip); } -METHOD(peer_cfg_t, get_pool, char*, +METHOD(peer_cfg_t, create_virtual_ip_enumerator, enumerator_t*, private_peer_cfg_t *this) { - return this->pool; + return this->vips->create_enumerator(this->vips); +} + +METHOD(peer_cfg_t, add_pool, void, + private_peer_cfg_t *this, char *name) +{ + this->pools->insert_last(this->pools, strdup(name)); +} + +METHOD(peer_cfg_t, create_pool_enumerator, enumerator_t*, + private_peer_cfg_t *this) +{ + return this->pools->create_enumerator(this->pools); } METHOD(peer_cfg_t, add_auth_cfg, void, @@ -493,6 +526,10 @@ static bool auth_cfg_equal(private_peer_cfg_t *this, private_peer_cfg_t *other) METHOD(peer_cfg_t, equals, bool, private_peer_cfg_t *this, private_peer_cfg_t *other) { + enumerator_t *e1, *e2; + host_t *vip1, *vip2; + char *pool1, *pool2; + if (this == other) { return TRUE; @@ -502,8 +539,45 @@ METHOD(peer_cfg_t, equals, bool, return FALSE; } + if (this->vips->get_count(this->vips) != other->vips->get_count(other->vips)) + { + return FALSE; + } + e1 = create_virtual_ip_enumerator(this); + e2 = create_virtual_ip_enumerator(other); + if (e1->enumerate(e1, &vip1) && e2->enumerate(e2, &vip2)) + { + if (!vip1->ip_equals(vip1, vip2)) + { + e1->destroy(e1); + e2->destroy(e2); + return FALSE; + } + } + e1->destroy(e1); + e2->destroy(e2); + + if (this->pools->get_count(this->pools) != + other->pools->get_count(other->pools)) + { + return FALSE; + } + e1 = create_pool_enumerator(this); + e2 = create_pool_enumerator(other); + if (e1->enumerate(e1, &pool1) && e2->enumerate(e2, &pool2)) + { + if (!streq(pool1, pool2)) + { + e1->destroy(e1); + e2->destroy(e2); + return FALSE; + } + } + e1->destroy(e1); + e2->destroy(e2); + return ( - this->ike_version == other->ike_version && + get_ike_version(this) == get_ike_version(other) && this->cert_policy == other->cert_policy && this->unique == other->unique && this->keyingtries == other->keyingtries && @@ -513,11 +587,7 @@ METHOD(peer_cfg_t, equals, bool, this->jitter_time == other->jitter_time && this->over_time == other->over_time && this->dpd == other->dpd && - (this->virtual_ip == other->virtual_ip || - (this->virtual_ip && other->virtual_ip && - this->virtual_ip->equals(this->virtual_ip, other->virtual_ip))) && - (this->pool == other->pool || - (this->pool && other->pool && streq(this->pool, other->pool))) && + this->aggressive == other->aggressive && auth_cfg_equal(this, other) #ifdef ME && this->mediation == other->mediation && @@ -544,18 +614,18 @@ METHOD(peer_cfg_t, destroy, void, this->ike_cfg->destroy(this->ike_cfg); this->child_cfgs->destroy_offset(this->child_cfgs, offsetof(child_cfg_t, destroy)); - DESTROY_IF(this->virtual_ip); this->local_auth->destroy_offset(this->local_auth, offsetof(auth_cfg_t, destroy)); this->remote_auth->destroy_offset(this->remote_auth, offsetof(auth_cfg_t, destroy)); + this->vips->destroy_offset(this->vips, offsetof(host_t, destroy)); + this->pools->destroy_function(this->pools, free); #ifdef ME DESTROY_IF(this->mediated_by); DESTROY_IF(this->peer_id); #endif /* ME */ this->mutex->destroy(this->mutex); free(this->name); - free(this->pool); free(this); } } @@ -563,12 +633,13 @@ METHOD(peer_cfg_t, destroy, void, /* * Described in header-file */ -peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, - cert_policy_t cert_policy, unique_policy_t unique, - u_int32_t keyingtries, u_int32_t rekey_time, - u_int32_t reauth_time, u_int32_t jitter_time, - u_int32_t over_time, bool mobike, u_int32_t dpd, - host_t *virtual_ip, char *pool, +peer_cfg_t *peer_cfg_create(char *name, + ike_cfg_t *ike_cfg, cert_policy_t cert_policy, + unique_policy_t unique, u_int32_t keyingtries, + u_int32_t rekey_time, u_int32_t reauth_time, + u_int32_t jitter_time, u_int32_t over_time, + bool mobike, bool aggressive, u_int32_t dpd, + u_int32_t dpd_timeout, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id) { @@ -599,9 +670,13 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, .get_reauth_time = _get_reauth_time, .get_over_time = _get_over_time, .use_mobike = _use_mobike, + .use_aggressive = _use_aggressive, .get_dpd = _get_dpd, - .get_virtual_ip = _get_virtual_ip, - .get_pool = _get_pool, + .get_dpd_timeout = _get_dpd_timeout, + .add_virtual_ip = _add_virtual_ip, + .create_virtual_ip_enumerator = _create_virtual_ip_enumerator, + .add_pool = _add_pool, + .create_pool_enumerator = _create_pool_enumerator, .add_auth_cfg = _add_auth_cfg, .create_auth_cfg_enumerator = _create_auth_cfg_enumerator, .equals = (void*)_equals, @@ -614,7 +689,6 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, #endif /* ME */ }, .name = strdup(name), - .ike_version = ike_version, .ike_cfg = ike_cfg, .child_cfgs = linked_list_create(), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), @@ -626,9 +700,11 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, .jitter_time = jitter_time, .over_time = over_time, .use_mobike = mobike, + .aggressive = aggressive, .dpd = dpd, - .virtual_ip = virtual_ip, - .pool = strdupnull(pool), + .dpd_timeout = dpd_timeout, + .vips = linked_list_create(), + .pools = linked_list_create(), .local_auth = linked_list_create(), .remote_auth = linked_list_create(), .refcount = 1, diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index f644fb547..e62e03ec5 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -29,13 +29,11 @@ typedef struct peer_cfg_t peer_cfg_t; #include <library.h> #include <utils/identification.h> -#include <utils/enumerator.h> +#include <collections/enumerator.h> #include <selectors/traffic_selector.h> #include <config/proposal.h> #include <config/ike_cfg.h> #include <config/child_cfg.h> -#include <sa/authenticators/authenticator.h> -#include <sa/authenticators/eap/eap_method.h> #include <credentials/auth_cfg.h> /** @@ -65,11 +63,13 @@ extern enum_name_t *cert_policy_names; * Uniqueness of an IKE_SA, used to drop multiple connections with one peer. */ enum unique_policy_t { - /** do not check for client uniqueness */ + /** never check for client uniqueness */ + UNIQUE_NEVER, + /** only check for client uniqueness when receiving an INITIAL_CONTACT */ UNIQUE_NO, - /** replace unique IKE_SAs if new ones get established */ + /** replace existing IKE_SAs when new ones get established by a client */ UNIQUE_REPLACE, - /** keep existing IKE_SAs, close the new ones on connection attept */ + /** keep existing IKE_SAs, close the new ones on connection attempt */ UNIQUE_KEEP, }; @@ -130,7 +130,7 @@ struct peer_cfg_t { * * @return IKE major version */ - u_int (*get_ike_version)(peer_cfg_t *this); + ike_version_t (*get_ike_version)(peer_cfg_t *this); /** * Get the IKE config to use for initiaton. @@ -165,18 +165,18 @@ struct peer_cfg_t { * * @param my_ts TS for local side * @param other_ts TS for remote side - * @param my_host host to narrow down dynamic TS for local side - * @param other_host host to narrow down dynamic TS for remote side + * @param my_hosts hosts to narrow down dynamic TS for local side + * @param other_hosts hosts to narrow down dynamic TS for remote side * @return selected CHILD config, or NULL if no match found */ - child_cfg_t* (*select_child_cfg) (peer_cfg_t *this, linked_list_t *my_ts, - linked_list_t *other_ts, host_t *my_host, - host_t *other_host); + child_cfg_t* (*select_child_cfg) (peer_cfg_t *this, + linked_list_t *my_ts, linked_list_t *other_ts, + linked_list_t *my_hosts, linked_list_t *other_hosts); /** * Add an authentication config to the peer configuration. * - * @param config config to add + * @param cfg config to add * @param local TRUE for local rules, FALSE for remote constraints */ void (*add_auth_cfg)(peer_cfg_t *this, auth_cfg_t *cfg, bool local); @@ -190,7 +190,7 @@ struct peer_cfg_t { enumerator_t* (*create_auth_cfg_enumerator)(peer_cfg_t *this, bool local); /** - * Should be sent a certificate for this connection? + * Should a certificate be sent for this connection? * * @return certificate sending policy */ @@ -211,18 +211,20 @@ struct peer_cfg_t { u_int32_t (*get_keyingtries) (peer_cfg_t *this); /** - * Get a time to start rekeying (is randomized with jitter). + * Get a time to start rekeying. * + * @param jitter remove a jitter value to randomize time * @return time in s when to start rekeying, 0 disables rekeying */ - u_int32_t (*get_rekey_time)(peer_cfg_t *this); + u_int32_t (*get_rekey_time)(peer_cfg_t *this, bool jitter); /** - * Get a time to start reauthentication (is randomized with jitter). + * Get a time to start reauthentication. * + * @param jitter remove a jitter value to randomize time * @return time in s when to start reauthentication, 0 disables it */ - u_int32_t (*get_reauth_time)(peer_cfg_t *this); + u_int32_t (*get_reauth_time)(peer_cfg_t *this, bool jitter); /** * Get the timeout of a rekeying/reauthenticating SA. @@ -239,6 +241,13 @@ struct peer_cfg_t { bool (*use_mobike) (peer_cfg_t *this); /** + * Use/Accept aggressive mode with IKEv1?. + * + * @return TRUE to use aggressive mode + */ + bool (*use_aggressive)(peer_cfg_t *this); + + /** * Get the DPD check interval. * * @return dpd_delay in seconds @@ -246,23 +255,41 @@ struct peer_cfg_t { u_int32_t (*get_dpd) (peer_cfg_t *this); /** - * Get a virtual IP for the local peer. + * Get the DPD timeout interval (IKEv1 only) + * + * @return dpd_timeout in seconds + */ + u_int32_t (*get_dpd_timeout) (peer_cfg_t *this); + + /** + * Add a virtual IP to request as initiator. * - * If no virtual IP should be used, NULL is returned. %any means to request - * a virtual IP using configuration payloads. A specific address is also - * used for a request and may be changed by the server. + * @param vip virtual IP to request, may be %any or %any6 + */ + void (*add_virtual_ip)(peer_cfg_t *this, host_t *vip); + + /** + * Create an enumerator over virtual IPs to request. + * + * The returned enumerator enumerates over IPs added with add_virtual_ip(). + * + * @return enumerator over host_t* + */ + enumerator_t* (*create_virtual_ip_enumerator)(peer_cfg_t *this); + + /** + * Add a pool name this configuration uses to select virtual IPs. * - * @param suggestion NULL, %any or specific - * @return virtual IP, %any or NULL + * @param name pool name to use for virtual IP lookup */ - host_t* (*get_virtual_ip) (peer_cfg_t *this); + void (*add_pool)(peer_cfg_t *this, char *name); /** - * Get the name of the pool to acquire configuration attributes from. + * Create an enumerator over pool names of this config. * - * @return pool name, NULL if none defined + * @return enumerator over char* */ - char* (*get_pool)(peer_cfg_t *this); + enumerator_t* (*create_pool_enumerator)(peer_cfg_t *this); #ifdef ME /** @@ -329,7 +356,6 @@ struct peer_cfg_t { * (rekeylifetime - random(0, jitter)). * * @param name name of the peer_cfg - * @param ike_version which IKE version we should use for this peer * @param ike_cfg IKE config to use when acting as initiator * @param cert_policy should we send a certificate payload? * @param unique uniqueness of an IKE_SA @@ -339,20 +365,21 @@ struct peer_cfg_t { * @param jitter_time timerange to randomly subtract from rekey/reauth time * @param over_time maximum overtime before closing a rekeying/reauth SA * @param mobike use MOBIKE (RFC4555) if peer supports it + * @param aggressive use/accept aggressive mode with IKEv1 * @param dpd DPD check interval, 0 to disable - * @param virtual_ip virtual IP for local host, or NULL - * @param pool pool name to get configuration attributes from, or NULL + * @param dpd_timeout DPD timeout interval (IKEv1 only), if 0 default applies * @param mediation TRUE if this is a mediation connection * @param mediated_by peer_cfg_t of the mediation connection to mediate through * @param peer_id ID that identifies our peer at the mediation server * @return peer_cfg_t object */ -peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, - cert_policy_t cert_policy, unique_policy_t unique, - u_int32_t keyingtries, u_int32_t rekey_time, - u_int32_t reauth_time, u_int32_t jitter_time, - u_int32_t over_time, bool mobike, u_int32_t dpd, - host_t *virtual_ip, char *pool, +peer_cfg_t *peer_cfg_create(char *name, + ike_cfg_t *ike_cfg, cert_policy_t cert_policy, + unique_policy_t unique, u_int32_t keyingtries, + u_int32_t rekey_time, u_int32_t reauth_time, + u_int32_t jitter_time, u_int32_t over_time, + bool mobike, bool aggressive, u_int32_t dpd, + u_int32_t dpd_timeout, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id); diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c index d3c60a469..0b702e014 100644 --- a/src/libcharon/config/proposal.c +++ b/src/libcharon/config/proposal.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2009 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2006-2010 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -19,24 +19,23 @@ #include "proposal.h" #include <daemon.h> -#include <utils/linked_list.h> +#include <collections/array.h> #include <utils/identification.h> -#include <utils/lexparser.h> + #include <crypto/transform.h> #include <crypto/prfs/prf.h> #include <crypto/crypters/crypter.h> #include <crypto/signers/signer.h> -#include <crypto/proposal/proposal_keywords.h> -ENUM(protocol_id_names, PROTO_NONE, PROTO_ESP, +ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP, "PROTO_NONE", "IKE", "AH", "ESP", + "IPCOMP", ); typedef struct private_proposal_t private_proposal_t; -typedef struct algorithm_t algorithm_t; /** * Private data of an proposal_t object @@ -54,29 +53,9 @@ struct private_proposal_t { protocol_id_t protocol; /** - * priority ordered list of encryption algorithms - */ - linked_list_t *encryption_algos; - - /** - * priority ordered list of integrity algorithms + * Priority ordered list of transforms, as entry_t */ - linked_list_t *integrity_algos; - - /** - * priority ordered list of pseudo random functions - */ - linked_list_t *prf_algos; - - /** - * priority ordered list of dh groups - */ - linked_list_t *dh_groups; - - /** - * priority ordered list of extended sequence number flags - */ - linked_list_t *esns; + array_t *transforms; /** * senders SPI @@ -92,68 +71,47 @@ struct private_proposal_t { /** * Struct used to store different kinds of algorithms. */ -struct algorithm_t { - /** - * Value from an encryption_algorithm_t/integrity_algorithm_t/... - */ - u_int16_t algorithm; - - /** - * the associated key size in bits, or zero if not needed - */ +typedef struct { + /** Type of the transform */ + transform_type_t type; + /** algorithm identifier */ + u_int16_t alg; + /** key size in bits, or zero if not needed */ u_int16_t key_size; -}; - -/** - * Add algorithm/keysize to a algorithm list - */ -static void add_algo(linked_list_t *list, u_int16_t algo, u_int16_t key_size) -{ - algorithm_t *algo_key; - - algo_key = malloc_thing(algorithm_t); - algo_key->algorithm = algo; - algo_key->key_size = key_size; - list->insert_last(list, (void*)algo_key); -} +} entry_t; METHOD(proposal_t, add_algorithm, void, private_proposal_t *this, transform_type_t type, - u_int16_t algo, u_int16_t key_size) + u_int16_t alg, u_int16_t key_size) { - switch (type) - { - case ENCRYPTION_ALGORITHM: - add_algo(this->encryption_algos, algo, key_size); - break; - case INTEGRITY_ALGORITHM: - add_algo(this->integrity_algos, algo, key_size); - break; - case PSEUDO_RANDOM_FUNCTION: - add_algo(this->prf_algos, algo, key_size); - break; - case DIFFIE_HELLMAN_GROUP: - add_algo(this->dh_groups, algo, 0); - break; - case EXTENDED_SEQUENCE_NUMBERS: - add_algo(this->esns, algo, 0); - break; - default: - break; - } + entry_t entry = { + .type = type, + .alg = alg, + .key_size = key_size, + }; + + array_insert(this->transforms, ARRAY_TAIL, &entry); } /** * filter function for peer configs */ -static bool alg_filter(void *null, algorithm_t **in, u_int16_t *alg, +static bool alg_filter(uintptr_t type, entry_t **in, u_int16_t *alg, void **unused, u_int16_t *key_size) { - algorithm_t *algo = *in; - *alg = algo->algorithm; + entry_t *entry = *in; + + if (entry->type != type) + { + return FALSE; + } + if (alg) + { + *alg = entry->alg; + } if (key_size) { - *key_size = algo->key_size; + *key_size = entry->key_size; } return TRUE; } @@ -161,30 +119,9 @@ static bool alg_filter(void *null, algorithm_t **in, u_int16_t *alg, METHOD(proposal_t, create_enumerator, enumerator_t*, private_proposal_t *this, transform_type_t type) { - linked_list_t *list; - - switch (type) - { - case ENCRYPTION_ALGORITHM: - list = this->encryption_algos; - break; - case INTEGRITY_ALGORITHM: - list = this->integrity_algos; - break; - case PSEUDO_RANDOM_FUNCTION: - list = this->prf_algos; - break; - case DIFFIE_HELLMAN_GROUP: - list = this->dh_groups; - break; - case EXTENDED_SEQUENCE_NUMBERS: - list = this->esns; - break; - default: - return NULL; - } - return enumerator_create_filter(list->create_enumerator(list), - (void*)alg_filter, NULL, NULL); + return enumerator_create_filter( + array_create_enumerator(this->transforms), + (void*)alg_filter, (void*)(uintptr_t)type, NULL); } METHOD(proposal_t, get_algorithm, bool, @@ -200,77 +137,91 @@ METHOD(proposal_t, get_algorithm, bool, found = TRUE; } enumerator->destroy(enumerator); + return found; } METHOD(proposal_t, has_dh_group, bool, private_proposal_t *this, diffie_hellman_group_t group) { - bool result = FALSE; + bool found = FALSE, any = FALSE; + enumerator_t *enumerator; + u_int16_t current; - if (this->dh_groups->get_count(this->dh_groups)) + enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP); + while (enumerator->enumerate(enumerator, ¤t, NULL)) { - algorithm_t *current; - enumerator_t *enumerator; - - enumerator = this->dh_groups->create_enumerator(this->dh_groups); - while (enumerator->enumerate(enumerator, (void**)¤t)) + any = TRUE; + if (current == group) { - if (current->algorithm == group) - { - result = TRUE; - break; - } + found = TRUE; + break; } - enumerator->destroy(enumerator); } - else if (group == MODP_NONE) + enumerator->destroy(enumerator); + + if (!any && group == MODP_NONE) { - result = TRUE; + found = TRUE; } - return result; + return found; } METHOD(proposal_t, strip_dh, void, - private_proposal_t *this) + private_proposal_t *this, diffie_hellman_group_t keep) { - algorithm_t *alg; + enumerator_t *enumerator; + entry_t *entry; - while (this->dh_groups->remove_last(this->dh_groups, (void**)&alg) == SUCCESS) + enumerator = array_create_enumerator(this->transforms); + while (enumerator->enumerate(enumerator, &entry)) { - free(alg); + if (entry->type == DIFFIE_HELLMAN_GROUP && + entry->alg != keep) + { + array_remove_at(this->transforms, enumerator); + } } + enumerator->destroy(enumerator); } /** - * Find a matching alg/keysize in two linked lists + * Select a matching proposal from this and other, insert into selected. */ -static bool select_algo(linked_list_t *first, linked_list_t *second, bool priv, - bool *add, u_int16_t *alg, size_t *key_size) +static bool select_algo(private_proposal_t *this, proposal_t *other, + proposal_t *selected, transform_type_t type, bool priv) { enumerator_t *e1, *e2; - algorithm_t *alg1, *alg2; + u_int16_t alg1, alg2, ks1, ks2; + bool found = FALSE; - /* if in both are zero algorithms specified, we HAVE a match */ - if (first->get_count(first) == 0 && second->get_count(second) == 0) + if (type == INTEGRITY_ALGORITHM && + selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) && + encryption_algorithm_is_aead(alg1)) { - *add = FALSE; + /* no integrity algorithm required, we have an AEAD */ return TRUE; } - e1 = first->create_enumerator(first); - e2 = second->create_enumerator(second); + e1 = create_enumerator(this, type); + e2 = other->create_enumerator(other, type); + if (!e1->enumerate(e1, NULL, NULL) && !e2->enumerate(e2, NULL, NULL)) + { + found = TRUE; + } + + e1->destroy(e1); + e1 = create_enumerator(this, type); /* compare algs, order of algs in "first" is preferred */ - while (e1->enumerate(e1, &alg1)) + while (!found && e1->enumerate(e1, &alg1, &ks1)) { e2->destroy(e2); - e2 = second->create_enumerator(second); - while (e2->enumerate(e2, &alg2)) + e2 = other->create_enumerator(other, type); + while (e2->enumerate(e2, &alg2, &ks2)) { - if (alg1->algorithm == alg2->algorithm && - alg1->key_size == alg2->key_size) + if (alg1 == alg2 && ks1 == ks2) { - if (!priv && alg1->algorithm >= 1024) + if (!priv && alg1 >= 1024) { /* accept private use algorithms only if requested */ DBG1(DBG_CFG, "an algorithm from private space would match, " @@ -278,132 +229,52 @@ static bool select_algo(linked_list_t *first, linked_list_t *second, bool priv, continue; } /* ok, we have an algorithm */ - *alg = alg1->algorithm; - *key_size = alg1->key_size; - *add = TRUE; - e1->destroy(e1); - e2->destroy(e2); - return TRUE; + selected->add_algorithm(selected, type, alg1, ks1); + found = TRUE; + break; } } } /* no match in all comparisons */ e1->destroy(e1); e2->destroy(e2); - return FALSE; + + if (!found) + { + DBG2(DBG_CFG, " no acceptable %N found", transform_type_names, type); + } + return found; } METHOD(proposal_t, select_proposal, proposal_t*, - private_proposal_t *this, proposal_t *other_pub, bool private) + private_proposal_t *this, proposal_t *other, bool private) { - private_proposal_t *other = (private_proposal_t*)other_pub; proposal_t *selected; - u_int16_t algo; - size_t key_size; - bool add; DBG2(DBG_CFG, "selecting proposal:"); - /* check protocol */ - if (this->protocol != other->protocol) + if (this->protocol != other->get_protocol(other)) { DBG2(DBG_CFG, " protocol mismatch, skipping"); return NULL; } - selected = proposal_create(this->protocol, other->number); + selected = proposal_create(this->protocol, other->get_number(other)); - /* select encryption algorithm */ - if (select_algo(this->encryption_algos, other->encryption_algos, private, - &add, &algo, &key_size)) - { - if (add) - { - selected->add_algorithm(selected, ENCRYPTION_ALGORITHM, - algo, key_size); - } - } - else - { - selected->destroy(selected); - DBG2(DBG_CFG, " no acceptable %N found", - transform_type_names, ENCRYPTION_ALGORITHM); - return NULL; - } - /* select integrity algorithm */ - if (!encryption_algorithm_is_aead(algo)) - { - if (select_algo(this->integrity_algos, other->integrity_algos, private, - &add, &algo, &key_size)) - { - if (add) - { - selected->add_algorithm(selected, INTEGRITY_ALGORITHM, - algo, key_size); - } - } - else - { - selected->destroy(selected); - DBG2(DBG_CFG, " no acceptable %N found", - transform_type_names, INTEGRITY_ALGORITHM); - return NULL; - } - } - /* select prf algorithm */ - if (select_algo(this->prf_algos, other->prf_algos, private, - &add, &algo, &key_size)) - { - if (add) - { - selected->add_algorithm(selected, PSEUDO_RANDOM_FUNCTION, - algo, key_size); - } - } - else - { - selected->destroy(selected); - DBG2(DBG_CFG, " no acceptable %N found", - transform_type_names, PSEUDO_RANDOM_FUNCTION); - return NULL; - } - /* select a DH-group */ - if (select_algo(this->dh_groups, other->dh_groups, private, - &add, &algo, &key_size)) - { - if (add) - { - selected->add_algorithm(selected, DIFFIE_HELLMAN_GROUP, algo, 0); - } - } - else - { - selected->destroy(selected); - DBG2(DBG_CFG, " no acceptable %N found", - transform_type_names, DIFFIE_HELLMAN_GROUP); - return NULL; - } - /* select if we use ESNs (has no private use space) */ - if (select_algo(this->esns, other->esns, TRUE, &add, &algo, &key_size)) - { - if (add) - { - selected->add_algorithm(selected, EXTENDED_SEQUENCE_NUMBERS, algo, 0); - } - } - else + if (!select_algo(this, other, selected, ENCRYPTION_ALGORITHM, private) || + !select_algo(this, other, selected, PSEUDO_RANDOM_FUNCTION, private) || + !select_algo(this, other, selected, INTEGRITY_ALGORITHM, private) || + !select_algo(this, other, selected, DIFFIE_HELLMAN_GROUP, private) || + !select_algo(this, other, selected, EXTENDED_SEQUENCE_NUMBERS, private)) { selected->destroy(selected); - DBG2(DBG_CFG, " no acceptable %N found", - transform_type_names, EXTENDED_SEQUENCE_NUMBERS); return NULL; } + DBG2(DBG_CFG, " proposal matches"); - /* apply SPI from "other" */ - selected->set_spi(selected, other->spi); + selected->set_spi(selected, other->get_spi(other)); - /* everything matched, return new proposal */ return selected; } @@ -426,50 +297,39 @@ METHOD(proposal_t, get_spi, u_int64_t, } /** - * Clone a algorithm list + * Check if two proposals have the same algorithms for a given transform type */ -static void clone_algo_list(linked_list_t *list, linked_list_t *clone_list) -{ - algorithm_t *algo, *clone_algo; - enumerator_t *enumerator; - - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &algo)) - { - clone_algo = malloc_thing(algorithm_t); - memcpy(clone_algo, algo, sizeof(algorithm_t)); - clone_list->insert_last(clone_list, (void*)clone_algo); - } - enumerator->destroy(enumerator); -} - -/** - * check if an algorithm list equals - */ -static bool algo_list_equals(linked_list_t *l1, linked_list_t *l2) +static bool algo_list_equals(private_proposal_t *this, proposal_t *other, + transform_type_t type) { enumerator_t *e1, *e2; - algorithm_t *alg1, *alg2; + u_int16_t alg1, alg2, ks1, ks2; bool equals = TRUE; - if (l1->get_count(l1) != l2->get_count(l2)) + e1 = create_enumerator(this, type); + e2 = other->create_enumerator(other, type); + while (e1->enumerate(e1, &alg1, &ks1)) { - return FALSE; - } - - e1 = l1->create_enumerator(l1); - e2 = l2->create_enumerator(l2); - while (e1->enumerate(e1, &alg1) && e2->enumerate(e2, &alg2)) - { - if (alg1->algorithm != alg2->algorithm || - alg1->key_size != alg2->key_size) + if (!e2->enumerate(e2, &alg2, &ks2)) { + /* this has more algs */ equals = FALSE; break; } + if (alg1 != alg2 || ks1 != ks2) + { + equals = FALSE; + break; + } + } + if (e2->enumerate(e2, &alg2, ks2)) + { + /* other has more algs */ + equals = FALSE; } e1->destroy(e1); e2->destroy(e2); + return equals; } @@ -480,33 +340,35 @@ METHOD(proposal_t, get_number, u_int, } METHOD(proposal_t, equals, bool, - private_proposal_t *this, proposal_t *other_pub) + private_proposal_t *this, proposal_t *other) { - private_proposal_t *other = (private_proposal_t*)other_pub; - - if (this == other) + if (&this->public == other) { return TRUE; } return ( - algo_list_equals(this->encryption_algos, other->encryption_algos) && - algo_list_equals(this->integrity_algos, other->integrity_algos) && - algo_list_equals(this->prf_algos, other->prf_algos) && - algo_list_equals(this->dh_groups, other->dh_groups) && - algo_list_equals(this->esns, other->esns)); + algo_list_equals(this, other, ENCRYPTION_ALGORITHM) && + algo_list_equals(this, other, INTEGRITY_ALGORITHM) && + algo_list_equals(this, other, PSEUDO_RANDOM_FUNCTION) && + algo_list_equals(this, other, DIFFIE_HELLMAN_GROUP) && + algo_list_equals(this, other, EXTENDED_SEQUENCE_NUMBERS)); } METHOD(proposal_t, clone_, proposal_t*, private_proposal_t *this) { private_proposal_t *clone; + enumerator_t *enumerator; + entry_t *entry; clone = (private_proposal_t*)proposal_create(this->protocol, 0); - clone_algo_list(this->encryption_algos, clone->encryption_algos); - clone_algo_list(this->integrity_algos, clone->integrity_algos); - clone_algo_list(this->prf_algos, clone->prf_algos); - clone_algo_list(this->dh_groups, clone->dh_groups); - clone_algo_list(this->esns, clone->esns); + + enumerator = array_create_enumerator(this->transforms); + while (enumerator->enumerate(enumerator, &entry)) + { + array_insert(clone->transforms, ARRAY_TAIL, entry); + } + enumerator->destroy(enumerator); clone->spi = this->spi; clone->number = this->number; @@ -515,18 +377,62 @@ METHOD(proposal_t, clone_, proposal_t*, } /** + * Map integrity algorithms to the PRF functions using the same algorithm. + */ +static const struct { + integrity_algorithm_t integ; + pseudo_random_function_t prf; +} integ_prf_map[] = { + {AUTH_HMAC_SHA1_96, PRF_HMAC_SHA1 }, + {AUTH_HMAC_SHA2_256_128, PRF_HMAC_SHA2_256 }, + {AUTH_HMAC_SHA2_384_192, PRF_HMAC_SHA2_384 }, + {AUTH_HMAC_SHA2_512_256, PRF_HMAC_SHA2_512 }, + {AUTH_HMAC_MD5_96, PRF_HMAC_MD5 }, + {AUTH_AES_XCBC_96, PRF_AES128_XCBC }, + {AUTH_CAMELLIA_XCBC_96, PRF_CAMELLIA128_XCBC }, + {AUTH_AES_CMAC_96, PRF_AES128_CMAC }, +}; + +/** * Checks the proposal read from a string. */ static void check_proposal(private_proposal_t *this) { enumerator_t *e; - algorithm_t *alg; + entry_t *entry; + u_int16_t alg, ks; bool all_aead = TRUE; + int i; + + if (this->protocol == PROTO_IKE) + { + e = create_enumerator(this, PSEUDO_RANDOM_FUNCTION); + if (!e->enumerate(e, &alg, &ks)) + { + /* No explicit PRF found. We assume the same algorithm as used + * for integrity checking */ + e->destroy(e); + e = create_enumerator(this, INTEGRITY_ALGORITHM); + while (e->enumerate(e, &alg, &ks)) + { + for (i = 0; i < countof(integ_prf_map); i++) + { + if (alg == integ_prf_map[i].integ) + { + add_algorithm(this, PSEUDO_RANDOM_FUNCTION, + integ_prf_map[i].prf, 0); + break; + } + } + } + } + e->destroy(e); + } - e = this->encryption_algos->create_enumerator(this->encryption_algos); - while (e->enumerate(e, &alg)) + e = create_enumerator(this, ENCRYPTION_ALGORITHM); + while (e->enumerate(e, &alg, &ks)) { - if (!encryption_algorithm_is_aead(alg->algorithm)) + if (!encryption_algorithm_is_aead(alg)) { all_aead = FALSE; break; @@ -536,86 +442,55 @@ static void check_proposal(private_proposal_t *this) if (all_aead) { - /* if all encryption algorithms in the proposal are authenticated encryption - * algorithms we MUST NOT propose any integrity algorithms */ - while (this->integrity_algos->remove_last(this->integrity_algos, - (void**)&alg) == SUCCESS) + /* if all encryption algorithms in the proposal are AEADs, + * we MUST NOT propose any integrity algorithms */ + e = array_create_enumerator(this->transforms); + while (e->enumerate(e, &entry)) { - free(alg); + if (entry->type == INTEGRITY_ALGORITHM) + { + array_remove_at(this->transforms, e); + } } + e->destroy(e); } if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP) { - e = this->esns->create_enumerator(this->esns); - if (!e->enumerate(e, &alg)) + e = create_enumerator(this, EXTENDED_SEQUENCE_NUMBERS); + if (!e->enumerate(e, NULL, NULL)) { /* ESN not specified, assume not supported */ add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); } e->destroy(e); } + + array_compress(this->transforms); } /** * add a algorithm identified by a string to the proposal. */ -static status_t add_string_algo(private_proposal_t *this, chunk_t alg) +static bool add_string_algo(private_proposal_t *this, const char *alg) { - const proposal_token_t *token = proposal_get_token(alg.ptr, alg.len); + const proposal_token_t *token; + token = lib->proposal->get_token(lib->proposal, alg); if (token == NULL) { - DBG1(DBG_CFG, "algorithm '%.*s' not recognized", alg.len, alg.ptr); - return FAILED; + DBG1(DBG_CFG, "algorithm '%s' not recognized", alg); + return FALSE; } add_algorithm(this, token->type, token->algorithm, token->keysize); - if (this->protocol == PROTO_IKE && token->type == INTEGRITY_ALGORITHM) - { - pseudo_random_function_t prf; - - switch (token->algorithm) - { - case AUTH_HMAC_SHA1_96: - prf = PRF_HMAC_SHA1; - break; - case AUTH_HMAC_SHA2_256_128: - prf = PRF_HMAC_SHA2_256; - break; - case AUTH_HMAC_SHA2_384_192: - prf = PRF_HMAC_SHA2_384; - break; - case AUTH_HMAC_SHA2_512_256: - prf = PRF_HMAC_SHA2_512; - break; - case AUTH_HMAC_MD5_96: - prf = PRF_HMAC_MD5; - break; - case AUTH_AES_XCBC_96: - prf = PRF_AES128_XCBC; - break; - case AUTH_CAMELLIA_XCBC_96: - prf = PRF_CAMELLIA128_XCBC; - break; - case AUTH_AES_CMAC_96: - prf = PRF_AES128_CMAC; - break; - default: - prf = PRF_UNDEFINED; - } - if (prf != PRF_UNDEFINED) - { - add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0); - } - } - return SUCCESS; + return TRUE; } /** * print all algorithms of a kind to buffer */ -static int print_alg(private_proposal_t *this, char **dst, size_t *len, +static int print_alg(private_proposal_t *this, printf_hook_data_t *data, u_int kind, void *names, bool *first) { enumerator_t *enumerator; @@ -627,16 +502,16 @@ static int print_alg(private_proposal_t *this, char **dst, size_t *len, { if (*first) { - written += print_in_hook(*dst, *len, "%N", names, alg); + written += print_in_hook(data, "%N", names, alg); *first = FALSE; } else { - written += print_in_hook(*dst, *len, "/%N", names, alg); + written += print_in_hook(data, "/%N", names, alg); } if (size) { - written += print_in_hook(*dst, *len, "_%u", size); + written += print_in_hook(data, "_%u", size); } } enumerator->destroy(enumerator); @@ -646,7 +521,7 @@ static int print_alg(private_proposal_t *this, char **dst, size_t *len, /** * Described in header. */ -int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args) { private_proposal_t *this = *((private_proposal_t**)(args[0])); @@ -657,7 +532,7 @@ int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, if (this == NULL) { - return print_in_hook(dst, len, "(null)"); + return print_in_hook(data, "(null)"); } if (spec->hash) @@ -667,28 +542,28 @@ int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, { /* call recursivly */ if (first) { - written += print_in_hook(dst, len, "%P", this); + written += print_in_hook(data, "%P", this); first = FALSE; } else { - written += print_in_hook(dst, len, ", %P", this); + written += print_in_hook(data, ", %P", this); } } enumerator->destroy(enumerator); return written; } - written = print_in_hook(dst, len, "%N:", protocol_id_names, this->protocol); - written += print_alg(this, &dst, &len, ENCRYPTION_ALGORITHM, + written = print_in_hook(data, "%N:", protocol_id_names, this->protocol); + written += print_alg(this, data, ENCRYPTION_ALGORITHM, encryption_algorithm_names, &first); - written += print_alg(this, &dst, &len, INTEGRITY_ALGORITHM, + written += print_alg(this, data, INTEGRITY_ALGORITHM, integrity_algorithm_names, &first); - written += print_alg(this, &dst, &len, PSEUDO_RANDOM_FUNCTION, + written += print_alg(this, data, PSEUDO_RANDOM_FUNCTION, pseudo_random_function_names, &first); - written += print_alg(this, &dst, &len, DIFFIE_HELLMAN_GROUP, + written += print_alg(this, data, DIFFIE_HELLMAN_GROUP, diffie_hellman_group_names, &first); - written += print_alg(this, &dst, &len, EXTENDED_SEQUENCE_NUMBERS, + written += print_alg(this, data, EXTENDED_SEQUENCE_NUMBERS, extended_sequence_numbers_names, &first); return written; } @@ -696,11 +571,7 @@ int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, METHOD(proposal_t, destroy, void, private_proposal_t *this) { - this->encryption_algos->destroy_function(this->encryption_algos, free); - this->integrity_algos->destroy_function(this->integrity_algos, free); - this->prf_algos->destroy_function(this->prf_algos, free); - this->dh_groups->destroy_function(this->dh_groups, free); - this->esns->destroy_function(this->esns, free); + array_destroy(this->transforms); free(this); } @@ -729,11 +600,7 @@ proposal_t *proposal_create(protocol_id_t protocol, u_int number) }, .protocol = protocol, .number = number, - .encryption_algos = linked_list_create(), - .integrity_algos = linked_list_create(), - .prf_algos = linked_list_create(), - .dh_groups = linked_list_create(), - .esns = linked_list_create(), + .transforms = array_create(sizeof(entry_t), 0), ); return &this->public; @@ -760,6 +627,28 @@ static void proposal_add_supported_ike(private_proposal_t *this) case ENCR_AES_CTR: case ENCR_CAMELLIA_CBC: case ENCR_CAMELLIA_CTR: + /* we assume that we support all AES/Camellia sizes */ + add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128); + add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192); + add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256); + break; + case ENCR_3DES: + add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0); + break; + case ENCR_DES: + /* no, thanks */ + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + enumerator = lib->crypto->create_aead_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &encryption, &plugin_name)) + { + switch (encryption) + { case ENCR_AES_CCM_ICV8: case ENCR_AES_CCM_ICV12: case ENCR_AES_CCM_ICV16: @@ -774,12 +663,6 @@ static void proposal_add_supported_ike(private_proposal_t *this) add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192); add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256); break; - case ENCR_3DES: - add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0); - break; - case ENCR_DES: - /* no, thanks */ - break; default: break; } @@ -840,6 +723,7 @@ static void proposal_add_supported_ike(private_proposal_t *this) case MODP_1024_BIT: case MODP_1536_BIT: case MODP_2048_BIT: + case MODP_3072_BIT: case MODP_4096_BIT: case MODP_8192_BIT: case ECP_256_BIT: @@ -899,28 +783,27 @@ proposal_t *proposal_create_default(protocol_id_t protocol) */ proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs) { - private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0); - chunk_t string = {(void*)algs, strlen(algs)}; - chunk_t alg; - status_t status = SUCCESS; + private_proposal_t *this; + enumerator_t *enumerator; + bool failed = TRUE; + char *alg; - eat_whitespace(&string); - if (string.len < 1) - { - destroy(this); - return NULL; - } + this = (private_proposal_t*)proposal_create(protocol, 0); /* get all tokens, separated by '-' */ - while (extract_token(&alg, '-', &string)) + enumerator = enumerator_create_token(algs, "-", " "); + while (enumerator->enumerate(enumerator, &alg)) { - status |= add_string_algo(this, alg); - } - if (string.len) - { - status |= add_string_algo(this, string); + if (!add_string_algo(this, alg)) + { + failed = TRUE; + break; + } + failed = FALSE; } - if (status != SUCCESS) + enumerator->destroy(enumerator); + + if (failed) { destroy(this); return NULL; diff --git a/src/libcharon/config/proposal.h b/src/libcharon/config/proposal.h index 8f54d7e6e..7733143a8 100644 --- a/src/libcharon/config/proposal.h +++ b/src/libcharon/config/proposal.h @@ -27,8 +27,8 @@ typedef struct proposal_t proposal_t; #include <library.h> #include <utils/identification.h> -#include <utils/linked_list.h> -#include <utils/host.h> +#include <collections/linked_list.h> +#include <networking/host.h> #include <crypto/transform.h> #include <crypto/crypters/crypter.h> #include <crypto/signers/signer.h> @@ -43,6 +43,7 @@ enum protocol_id_t { PROTO_IKE = 1, PROTO_AH = 2, PROTO_ESP = 3, + PROTO_IPCOMP = 4, /* IKEv1 only */ }; /** @@ -110,8 +111,10 @@ struct proposal_t { /** * Strip DH groups from proposal to use it without PFS. + * + * @param keep group to keep (MODP_NONE to remove all) */ - void (*strip_dh)(proposal_t *this); + void (*strip_dh)(proposal_t *this, diffie_hellman_group_t keep); /** * Compare two proposal, and select a matching subset. @@ -215,7 +218,7 @@ proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs * With the #-specifier, arguments are: * linked_list_t *list containing proposal_t* */ -int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args); #endif /** PROPOSAL_H_ @}*/ |