summaryrefslogtreecommitdiff
path: root/src/libcharon/config
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/config')
-rw-r--r--src/libcharon/config/child_cfg.c14
-rw-r--r--src/libcharon/config/child_cfg.h10
-rw-r--r--src/libcharon/config/ike_cfg.h2
-rw-r--r--src/libcharon/config/proposal.c127
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;
}