diff options
Diffstat (limited to 'src/libcharon/config')
-rw-r--r-- | src/libcharon/config/child_cfg.c | 14 | ||||
-rw-r--r-- | src/libcharon/config/child_cfg.h | 10 | ||||
-rw-r--r-- | src/libcharon/config/ike_cfg.h | 2 | ||||
-rw-r--r-- | src/libcharon/config/proposal.c | 127 |
4 files changed, 126 insertions, 27 deletions
diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index 76d7f2c58..6a9c342f4 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -154,6 +154,11 @@ struct private_child_cfg_t { bool install_policy; /** + * Install outbound FWD policies + */ + bool fwd_out_policy; + + /** * anti-replay window size */ uint32_t replay_window; @@ -564,6 +569,12 @@ METHOD(child_cfg_t, install_policy, bool, return this->install_policy; } +METHOD(child_cfg_t, install_fwd_out_policy, bool, + private_child_cfg_t *this) +{ + return this->fwd_out_policy; +} + #define LT_PART_EQUALS(a, b) ({ a.life == b.life && a.rekey == b.rekey && a.jitter == b.jitter; }) #define LIFETIME_EQUALS(a, b) ({ LT_PART_EQUALS(a.time, b.time) && LT_PART_EQUALS(a.bytes, b.bytes) && LT_PART_EQUALS(a.packets, b.packets); }) @@ -613,6 +624,7 @@ METHOD(child_cfg_t, equals, bool, this->replay_window == other->replay_window && this->proxy_mode == other->proxy_mode && this->install_policy == other->install_policy && + this->fwd_out_policy == other->fwd_out_policy && streq(this->updown, other->updown) && streq(this->interface, other->interface); } @@ -673,6 +685,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .set_replay_window = _set_replay_window, .use_proxy_mode = _use_proxy_mode, .install_policy = _install_policy, + .install_fwd_out_policy = _install_fwd_out_policy, .equals = _equals, .get_ref = _get_ref, .destroy = _destroy, @@ -695,6 +708,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .manual_prio = data->priority, .interface = strdupnull(data->interface), .install_policy = !data->suppress_policies, + .fwd_out_policy = data->fwd_out_policies, .refcount = 1, .proposals = linked_list_create(), .my_ts = linked_list_create(), diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index e736b2737..b85bfd9bc 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -284,6 +284,14 @@ struct child_cfg_t { bool (*install_policy)(child_cfg_t *this); /** + * Check whether outbound FWD IPsec policies should be installed. + * + * @return TRUE, if outbound FWD policies should be installed + * FALSE, otherwise + */ + bool (*install_fwd_out_policy)(child_cfg_t *this); + + /** * Check if two child_cfg objects are equal. * * @param other candidate to check for equality against this @@ -346,6 +354,8 @@ struct child_cfg_create_t { bool hostaccess; /** Don't install IPsec policies */ bool suppress_policies; + /** Install outbound FWD IPsec policies to bypass drop policies */ + bool fwd_out_policies; }; /** diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h index 5655a3497..afcb772fe 100644 --- a/src/libcharon/config/ike_cfg.h +++ b/src/libcharon/config/ike_cfg.h @@ -256,7 +256,7 @@ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, fragmentation_t fragmentation, uint8_t dscp); /** - * Determine the address family of the local or remtoe address(es). If multiple + * Determine the address family of the local or remote address(es). If multiple * families are configured AF_UNSPEC is returned. %any is ignored (%any4|6 are * not though). * diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c index a83acec23..011c0b8b0 100644 --- a/src/libcharon/config/proposal.c +++ b/src/libcharon/config/proposal.c @@ -420,24 +420,40 @@ static const struct { }; /** + * Remove all entries of the given transform type + */ +static void remove_transform(private_proposal_t *this, transform_type_t type) +{ + enumerator_t *e; + entry_t *entry; + + e = array_create_enumerator(this->transforms); + while (e->enumerate(e, &entry)) + { + if (entry->type == type) + { + array_remove_at(this->transforms, e); + } + } + e->destroy(e); +} + +/** * Checks the proposal read from a string. */ -static void check_proposal(private_proposal_t *this) +static bool check_proposal(private_proposal_t *this) { enumerator_t *e; entry_t *entry; uint16_t alg, ks; - bool all_aead = TRUE; + bool all_aead = TRUE, any_aead = FALSE, any_enc = FALSE; 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); + if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL)) + { /* No explicit PRF found. We assume the same algorithm as used + * for integrity checking. */ e = create_enumerator(this, INTEGRITY_ALGORITHM); while (e->enumerate(e, &alg, &ks)) { @@ -451,8 +467,13 @@ static void check_proposal(private_proposal_t *this) } } } + e->destroy(e); + } + if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL)) + { + DBG1(DBG_CFG, "a PRF algorithm is mandatory in IKE proposals"); + return FALSE; } - e->destroy(e); /* remove MODP_NONE from IKE proposal */ e = array_create_enumerator(this->transforms); while (e->enumerate(e, &entry)) @@ -463,48 +484,103 @@ static void check_proposal(private_proposal_t *this) } } e->destroy(e); + if (!get_algorithm(this, DIFFIE_HELLMAN_GROUP, NULL, NULL)) + { + DBG1(DBG_CFG, "a DH group is mandatory in IKE proposals"); + return FALSE; + } + } + else + { /* remove PRFs from ESP/AH proposals */ + remove_transform(this, PSEUDO_RANDOM_FUNCTION); } - if (this->protocol == PROTO_ESP) + if (this->protocol == PROTO_IKE || this->protocol == PROTO_ESP) { e = create_enumerator(this, ENCRYPTION_ALGORITHM); while (e->enumerate(e, &alg, &ks)) { - if (!encryption_algorithm_is_aead(alg)) + any_enc = TRUE; + if (encryption_algorithm_is_aead(alg)) { - all_aead = FALSE; - break; + any_aead = TRUE; + continue; } + all_aead = FALSE; } e->destroy(e); - if (all_aead) + if (!any_enc) + { + DBG1(DBG_CFG, "an encryption algorithm is mandatory in %N proposals", + protocol_id_names, this->protocol); + return FALSE; + } + else if (any_aead && !all_aead) { - /* if all encryption algorithms in the proposal are AEADs, + DBG1(DBG_CFG, "classic and combined-mode (AEAD) encryption " + "algorithms can't be contained in the same %N proposal", + protocol_id_names, this->protocol); + return FALSE; + } + else if (all_aead) + { /* 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)) + remove_transform(this, INTEGRITY_ALGORITHM); + } + } + else + { /* AES-GMAC is parsed as encryption algorithm, so we map that to the + * proper integrity algorithm */ + e = array_create_enumerator(this->transforms); + while (e->enumerate(e, &entry)) + { + if (entry->type == ENCRYPTION_ALGORITHM) { - if (entry->type == INTEGRITY_ALGORITHM) + if (entry->alg == ENCR_NULL_AUTH_AES_GMAC) { - array_remove_at(this->transforms, e); + entry->type = INTEGRITY_ALGORITHM; + ks = entry->key_size; + entry->key_size = 0; + switch (ks) + { + case 128: + entry->alg = AUTH_AES_128_GMAC; + continue; + case 192: + entry->alg = AUTH_AES_192_GMAC; + continue; + case 256: + entry->alg = AUTH_AES_256_GMAC; + continue; + default: + break; + } } + /* remove all other encryption algorithms */ + array_remove_at(this->transforms, e); } - e->destroy(e); + } + e->destroy(e); + + if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL)) + { + DBG1(DBG_CFG, "an integrity algorithm is mandatory in AH " + "proposals"); + return FALSE; } } if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP) { - e = create_enumerator(this, EXTENDED_SEQUENCE_NUMBERS); - if (!e->enumerate(e, NULL, NULL)) + if (!get_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, 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); + return TRUE; } /** @@ -842,6 +918,7 @@ static bool proposal_add_supported_ike(private_proposal_t *this, bool aead) case NTRU_128_BIT: case NTRU_192_BIT: case NTRU_256_BIT: + case NH_128_BIT: add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0); break; default: @@ -999,13 +1076,11 @@ proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs } enumerator->destroy(enumerator); - if (failed) + if (failed || !check_proposal(this)) { destroy(this); return NULL; } - check_proposal(this); - return &this->public; } |