aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2013-10-11 10:15:43 +0200
committerMartin Willi <martin@revosec.ch>2013-10-11 10:15:43 +0200
commitb59bcba2b38dda5f0f6301b7ae90acc58b4a069b (patch)
tree65c3cee3a20b6f323f5887b95bd88bc1981fa59c /src/libcharon
parent4524e128f845f8842cdf9ffecf4c1978218212cb (diff)
parent5fdbb3c6ad49f992c5df7075f920a2a133a81860 (diff)
downloadstrongswan-b59bcba2b38dda5f0f6301b7ae90acc58b4a069b.tar.bz2
strongswan-b59bcba2b38dda5f0f6301b7ae90acc58b4a069b.tar.xz
Merge branch 'ah'
Brings support for Security Associations integrity protected by the Authentication Header protocol, both to IKEv1 and IKEv2. Currently only plain AH is supported, but no (now deprecated) RFC2401 style AH+ESP bundles.
Diffstat (limited to 'src/libcharon')
-rw-r--r--src/libcharon/config/proposal.c35
-rw-r--r--src/libcharon/encoding/message.c4
-rw-r--r--src/libcharon/encoding/payloads/proposal_substructure.c130
-rw-r--r--src/libcharon/encoding/payloads/sa_payload.c20
-rw-r--r--src/libcharon/kernel/kernel_handler.c80
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.c25
-rw-r--r--src/libcharon/plugins/stroke/stroke_list.c8
-rw-r--r--src/libcharon/plugins/stroke/stroke_socket.c2
-rw-r--r--src/libcharon/plugins/updown/updown_listener.c2
-rw-r--r--src/libcharon/sa/child_sa.c9
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_delete.c2
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.c21
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c18
-rw-r--r--src/libcharon/sa/keymat.c1
-rw-r--r--src/libcharon/sa/trap_manager.c16
15 files changed, 245 insertions, 128 deletions
diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c
index 0b702e014..0acc425d6 100644
--- a/src/libcharon/config/proposal.c
+++ b/src/libcharon/config/proposal.c
@@ -429,30 +429,33 @@ static void check_proposal(private_proposal_t *this)
e->destroy(e);
}
- e = create_enumerator(this, ENCRYPTION_ALGORITHM);
- while (e->enumerate(e, &alg, &ks))
+ if (this->protocol == PROTO_ESP)
{
- if (!encryption_algorithm_is_aead(alg))
+ e = create_enumerator(this, ENCRYPTION_ALGORITHM);
+ while (e->enumerate(e, &alg, &ks))
{
- all_aead = FALSE;
- break;
+ if (!encryption_algorithm_is_aead(alg))
+ {
+ all_aead = FALSE;
+ break;
+ }
}
- }
- e->destroy(e);
+ e->destroy(e);
- 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))
+ if (all_aead)
{
- if (entry->type == INTEGRITY_ALGORITHM)
+ /* 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))
{
- array_remove_at(this->transforms, e);
+ if (entry->type == INTEGRITY_ALGORITHM)
+ {
+ array_remove_at(this->transforms, e);
+ }
}
+ e->destroy(e);
}
- e->destroy(e);
}
if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c
index 3896d7199..9fc108b40 100644
--- a/src/libcharon/encoding/message.c
+++ b/src/libcharon/encoding/message.c
@@ -439,7 +439,7 @@ static payload_rule_t id_prot_i_rules[] = {
{NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE},
{NAT_D_DRAFT_00_03_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE},
{ID_V1, 0, 1, TRUE, FALSE},
- {CERTIFICATE_V1, 0, 2, TRUE, FALSE},
+ {CERTIFICATE_V1, 0, MAX_CERT_PAYLOADS, TRUE, FALSE},
{SIGNATURE_V1, 0, 1, TRUE, FALSE},
{HASH_V1, 0, 1, TRUE, FALSE},
{FRAGMENT_V1, 0, 1, FALSE, TRUE},
@@ -479,7 +479,7 @@ static payload_rule_t id_prot_r_rules[] = {
{NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE},
{NAT_D_DRAFT_00_03_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE},
{ID_V1, 0, 1, TRUE, FALSE},
- {CERTIFICATE_V1, 0, 2, TRUE, FALSE},
+ {CERTIFICATE_V1, 0, MAX_CERT_PAYLOADS, TRUE, FALSE},
{SIGNATURE_V1, 0, 1, TRUE, FALSE},
{HASH_V1, 0, 1, TRUE, FALSE},
{FRAGMENT_V1, 0, 1, FALSE, TRUE},
diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c
index 3cf22aefd..cb9b359b3 100644
--- a/src/libcharon/encoding/payloads/proposal_substructure.c
+++ b/src/libcharon/encoding/payloads/proposal_substructure.c
@@ -246,6 +246,24 @@ typedef enum {
} ikev1_esp_auth_transid_it;
/**
+ * IKEv1 Transform ID AH authentication algorithm.
+ */
+typedef enum {
+ IKEV1_AH_HMAC_MD5 = 2,
+ IKEV1_AH_HMAC_SHA = 3,
+ IKEV1_AH_DES_MAC = 4,
+ IKEV1_AH_HMAC_SHA2_256 = 5,
+ IKEV1_AH_HMAC_SHA2_384 = 6,
+ IKEV1_AH_HMAC_SHA2_512 = 7,
+ IKEV1_AH_RIPEMD = 8,
+ IKEV1_AH_AES_XCBC_MAC = 9,
+ IKEV1_AH_RSA = 10,
+ IKEV1_AH_AES_128_GMAC = 11,
+ IKEV1_AH_AES_192_GMAC = 12,
+ IKEV1_AH_AES_256_GMAC = 13,
+} ikev1_ah_transid_t;
+
+/**
* IKEv1 ESP Encapsulation mode.
*/
typedef enum {
@@ -637,6 +655,22 @@ static algo_map_t map_esp_auth[] = {
};
/**
+ * AH authentication algorithm mapping
+ */
+static algo_map_t map_ah[] = {
+ { IKEV1_AH_HMAC_MD5, AUTH_HMAC_MD5_96 },
+ { IKEV1_AH_HMAC_SHA, AUTH_HMAC_SHA1_96 },
+ { IKEV1_AH_DES_MAC, AUTH_DES_MAC },
+ { IKEV1_AH_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_128 },
+ { IKEV1_AH_HMAC_SHA2_384, AUTH_HMAC_SHA2_384_192 },
+ { IKEV1_AH_HMAC_SHA2_512, AUTH_HMAC_SHA2_512_256 },
+ { IKEV1_AH_AES_XCBC_MAC, AUTH_AES_XCBC_96 },
+ { IKEV1_AH_AES_128_GMAC, AUTH_AES_128_GMAC },
+ { IKEV1_AH_AES_192_GMAC, AUTH_AES_192_GMAC },
+ { IKEV1_AH_AES_256_GMAC, AUTH_AES_256_GMAC },
+};
+
+/**
* Get IKEv2 algorithm from IKEv1 identifier
*/
static u_int16_t get_alg_from_ikev1(transform_type_t type, u_int16_t value)
@@ -713,7 +747,8 @@ static u_int16_t get_ikev1_from_alg(transform_type_t type, u_int16_t value)
/**
* Get IKEv2 algorithm from IKEv1 ESP transaction ID
*/
-static u_int16_t get_alg_from_ikev1_transid(transform_type_t type, u_int16_t value)
+static u_int16_t get_alg_from_ikev1_transid(protocol_id_t proto,
+ transform_type_t type, u_int16_t value)
{
algo_map_t *map;
u_int16_t def;
@@ -727,8 +762,16 @@ static u_int16_t get_alg_from_ikev1_transid(transform_type_t type, u_int16_t val
def = ENCR_UNDEFINED;
break;
case INTEGRITY_ALGORITHM:
- map = map_esp_auth;
- count = countof(map_esp_auth);
+ if (proto == PROTO_ESP)
+ {
+ map = map_esp_auth;
+ count = countof(map_esp_auth);
+ }
+ else
+ {
+ map = map_ah;
+ count = countof(map_ah);
+ }
def = AUTH_UNDEFINED;
break;
default:
@@ -745,9 +788,10 @@ static u_int16_t get_alg_from_ikev1_transid(transform_type_t type, u_int16_t val
}
/**
- * Get IKEv1 ESP transaction ID from IKEv2 identifier
+ * Get IKEv1 ESP/AH transaction ID from IKEv2 identifier
*/
-static u_int16_t get_ikev1_transid_from_alg(transform_type_t type, u_int16_t value)
+static u_int16_t get_ikev1_transid_from_alg(protocol_id_t proto,
+ transform_type_t type, u_int16_t value)
{
algo_map_t *map;
int i, count;
@@ -759,8 +803,16 @@ static u_int16_t get_ikev1_transid_from_alg(transform_type_t type, u_int16_t val
count = countof(map_esp_encr);
break;
case INTEGRITY_ALGORITHM:
- map = map_esp_auth;
- count = countof(map_esp_auth);
+ if (proto == PROTO_ESP)
+ {
+ map = map_esp_auth;
+ count = countof(map_esp_auth);
+ }
+ else
+ {
+ map = map_ah;
+ count = countof(map_ah);
+ }
break;
default:
return 0;
@@ -889,10 +941,10 @@ static void add_to_proposal_v1_ike(proposal_t *proposal,
}
/**
- * Add an ESP transform to a proposal for IKEv1
+ * Add an ESP/AH transform to a proposal for IKEv1
*/
-static void add_to_proposal_v1_esp(proposal_t *proposal,
- transform_substructure_t *transform)
+static void add_to_proposal_v1(proposal_t *proposal,
+ transform_substructure_t *transform, protocol_id_t proto)
{
transform_attribute_type_t type;
transform_attribute_t *tattr;
@@ -911,7 +963,7 @@ static void add_to_proposal_v1_esp(proposal_t *proposal,
break;
case TATTR_PH2_AUTH_ALGORITHM:
proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM,
- get_alg_from_ikev1_transid(INTEGRITY_ALGORITHM,
+ get_alg_from_ikev1_transid(proto, INTEGRITY_ALGORITHM,
value), 0);
break;
case TATTR_PH2_GROUP:
@@ -927,12 +979,15 @@ static void add_to_proposal_v1_esp(proposal_t *proposal,
/* TODO-IKEv1: handle ESN attribute */
proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS,
NO_EXT_SEQ_NUMBERS, 0);
- encr = get_alg_from_ikev1_transid(ENCRYPTION_ALGORITHM,
- transform->get_transform_id(transform));
- if (encr)
+ if (proto == PROTO_ESP)
{
- proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr,
- key_length);
+ encr = get_alg_from_ikev1_transid(proto, ENCRYPTION_ALGORITHM,
+ transform->get_transform_id(transform));
+ if (encr)
+ {
+ proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr,
+ key_length);
+ }
}
}
@@ -977,7 +1032,8 @@ METHOD(proposal_substructure_t, get_proposals, void,
add_to_proposal_v1_ike(proposal, transform);
break;
case PROTO_ESP:
- add_to_proposal_v1_esp(proposal, transform);
+ case PROTO_AH:
+ add_to_proposal_v1(proposal, transform, this->protocol_id);
break;
default:
break;
@@ -1072,6 +1128,7 @@ METHOD(proposal_substructure_t, get_lifetime, u_int32_t,
return get_life_duration(this, TATTR_PH1_LIFE_TYPE,
IKEV1_LIFE_TYPE_SECONDS, TATTR_PH1_LIFE_DURATION);
case PROTO_ESP:
+ case PROTO_AH:
duration = get_life_duration(this, TATTR_PH2_SA_LIFE_TYPE,
IKEV1_LIFE_TYPE_SECONDS, TATTR_PH2_SA_LIFE_DURATION);
if (!duration)
@@ -1090,6 +1147,7 @@ METHOD(proposal_substructure_t, get_lifebytes, u_int64_t,
switch (this->protocol_id)
{
case PROTO_ESP:
+ case PROTO_AH:
return 1000 * get_life_duration(this, TATTR_PH2_SA_LIFE_TYPE,
IKEV1_LIFE_TYPE_KILOBYTES, TATTR_PH2_SA_LIFE_DURATION);
case PROTO_IKE:
@@ -1281,24 +1339,26 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this,
}
/**
- * Add an IKEv1 ESP proposal to the substructure
+ * Add an IKEv1 ESP/AH proposal to the substructure
*/
-static void set_from_proposal_v1_esp(private_proposal_substructure_t *this,
+static void set_from_proposal_v1(private_proposal_substructure_t *this,
proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes,
ipsec_mode_t mode, encap_t udp, int number)
{
transform_substructure_t *transform = NULL;
u_int16_t alg, key_size;
enumerator_t *enumerator;
+ protocol_id_t proto;
+ proto = proposal->get_protocol(proposal);
enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM);
if (enumerator->enumerate(enumerator, &alg, &key_size))
{
- alg = get_ikev1_transid_from_alg(ENCRYPTION_ALGORITHM, alg);
+ alg = get_ikev1_transid_from_alg(proto, ENCRYPTION_ALGORITHM, alg);
if (alg)
{
- transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1,
- number, alg);
+ transform = transform_substructure_create_type(
+ TRANSFORM_SUBSTRUCTURE_V1, number, alg);
if (key_size)
{
transform->add_transform_attribute(transform,
@@ -1308,17 +1368,18 @@ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this,
}
}
enumerator->destroy(enumerator);
- if (!transform)
- {
- return;
- }
enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM);
if (enumerator->enumerate(enumerator, &alg, &key_size))
{
- alg = get_ikev1_transid_from_alg(INTEGRITY_ALGORITHM, alg);
+ alg = get_ikev1_transid_from_alg(proto, INTEGRITY_ALGORITHM, alg);
if (alg)
{
+ if (!transform)
+ {
+ transform = transform_substructure_create_type(
+ TRANSFORM_SUBSTRUCTURE_V1, number, alg);
+ }
transform->add_transform_attribute(transform,
transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
TATTR_PH2_AUTH_ALGORITHM, alg));
@@ -1326,6 +1387,11 @@ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this,
}
enumerator->destroy(enumerator);
+ if (!transform)
+ {
+ return;
+ }
+
enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP);
if (enumerator->enumerate(enumerator, &alg, &key_size))
{
@@ -1493,8 +1559,9 @@ proposal_substructure_t *proposal_substructure_create_from_proposal_v1(
set_from_proposal_v1_ike(this, proposal, lifetime, auth, 1);
break;
case PROTO_ESP:
- set_from_proposal_v1_esp(this, proposal, lifetime,
- lifebytes, mode, udp, 1);
+ case PROTO_AH:
+ set_from_proposal_v1(this, proposal, lifetime,
+ lifebytes, mode, udp, 1);
break;
default:
break;
@@ -1535,8 +1602,9 @@ proposal_substructure_t *proposal_substructure_create_from_proposals_v1(
auth, ++number);
break;
case PROTO_ESP:
- set_from_proposal_v1_esp(this, proposal, lifetime,
- lifebytes, mode, udp, ++number);
+ case PROTO_AH:
+ set_from_proposal_v1(this, proposal, lifetime,
+ lifebytes, mode, udp, ++number);
break;
default:
break;
diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c
index 613412014..3a5bb43a6 100644
--- a/src/libcharon/encoding/payloads/sa_payload.c
+++ b/src/libcharon/encoding/payloads/sa_payload.c
@@ -341,10 +341,10 @@ METHOD(sa_payload_t, get_ipcomp_proposals, linked_list_t*,
{
int current_proposal = -1, unsupported_proposal = -1;
enumerator_t *enumerator;
- proposal_substructure_t *substruct, *esp = NULL, *ipcomp = NULL;
+ proposal_substructure_t *substruct, *espah = NULL, *ipcomp = NULL;
linked_list_t *list;
- /* we currently only support the combination ESP+IPComp, find the first */
+ /* we currently only support the combination ESP|AH+IPComp, find the first */
enumerator = this->proposals->create_enumerator(this->proposals);
while (enumerator->enumerate(enumerator, &substruct))
{
@@ -355,25 +355,27 @@ METHOD(sa_payload_t, get_ipcomp_proposals, linked_list_t*,
{
continue;
}
- if (protocol_id != PROTO_ESP && protocol_id != PROTO_IPCOMP)
+ if (protocol_id != PROTO_ESP && protocol_id != PROTO_AH &&
+ protocol_id != PROTO_IPCOMP)
{ /* unsupported combination */
- esp = ipcomp = NULL;
+ espah = ipcomp = NULL;
unsupported_proposal = current_proposal;
continue;
}
if (proposal_number != current_proposal)
{ /* start of a new proposal */
- if (esp && ipcomp)
+ if (espah && ipcomp)
{ /* previous proposal is valid */
break;
}
- esp = ipcomp = NULL;
+ espah = ipcomp = NULL;
current_proposal = proposal_number;
}
switch (protocol_id)
{
case PROTO_ESP:
- esp = substruct;
+ case PROTO_AH:
+ espah = substruct;
break;
case PROTO_IPCOMP:
ipcomp = substruct;
@@ -383,9 +385,9 @@ METHOD(sa_payload_t, get_ipcomp_proposals, linked_list_t*,
enumerator->destroy(enumerator);
list = linked_list_create();
- if (esp && ipcomp && ipcomp->get_cpi(ipcomp, cpi))
+ if (espah && ipcomp && ipcomp->get_cpi(ipcomp, cpi))
{
- esp->get_proposals(esp, list);
+ espah->get_proposals(espah, list);
}
return list;
}
diff --git a/src/libcharon/kernel/kernel_handler.c b/src/libcharon/kernel/kernel_handler.c
index aa5c4e059..059124e35 100644
--- a/src/libcharon/kernel/kernel_handler.c
+++ b/src/libcharon/kernel/kernel_handler.c
@@ -35,7 +35,6 @@ struct private_kernel_handler_t {
* Public part of kernel_handler_t object.
*/
kernel_handler_t public;
-
};
/**
@@ -55,85 +54,83 @@ static inline protocol_id_t proto_ip2ike(u_int8_t protocol)
}
METHOD(kernel_listener_t, acquire, bool,
- private_kernel_handler_t *this, u_int32_t reqid,
- traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
+ private_kernel_handler_t *this, u_int32_t reqid,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
{
- job_t *job;
if (src_ts && dst_ts)
{
- DBG1(DBG_KNL, "creating acquire job for policy %R === %R "
- "with reqid {%u}", src_ts, dst_ts, reqid);
+ DBG1(DBG_KNL, "creating acquire job for policy %R === %R with "
+ "reqid {%u}", src_ts, dst_ts, reqid);
}
else
{
DBG1(DBG_KNL, "creating acquire job for policy with reqid {%u}", reqid);
}
- job = (job_t*)acquire_job_create(reqid, src_ts, dst_ts);
- lib->processor->queue_job(lib->processor, job);
+ lib->processor->queue_job(lib->processor,
+ (job_t*)acquire_job_create(reqid, src_ts, dst_ts));
return TRUE;
}
METHOD(kernel_listener_t, expire, bool,
- private_kernel_handler_t *this, u_int32_t reqid, u_int8_t protocol,
- u_int32_t spi, bool hard)
+ private_kernel_handler_t *this, u_int32_t reqid, u_int8_t protocol,
+ u_int32_t spi, bool hard)
{
- job_t *job;
protocol_id_t proto = proto_ip2ike(protocol);
- DBG1(DBG_KNL, "creating %s job for %N CHILD_SA with SPI %.8x "
- "and reqid {%u}", hard ? "delete" : "rekey",
- protocol_id_names, proto, ntohl(spi), reqid);
+
+ DBG1(DBG_KNL, "creating %s job for %N CHILD_SA with SPI %.8x and reqid {%u}",
+ hard ? "delete" : "rekey", protocol_id_names, proto, ntohl(spi), reqid);
+
if (hard)
{
- job = (job_t*)delete_child_sa_job_create(reqid, proto, spi, hard);
+ lib->processor->queue_job(lib->processor,
+ (job_t*)delete_child_sa_job_create(reqid, proto, spi, hard));
}
else
{
- job = (job_t*)rekey_child_sa_job_create(reqid, proto, spi);
+ lib->processor->queue_job(lib->processor,
+ (job_t*)rekey_child_sa_job_create(reqid, proto, spi));
}
- lib->processor->queue_job(lib->processor, job);
return TRUE;
}
METHOD(kernel_listener_t, mapping, bool,
- private_kernel_handler_t *this, u_int32_t reqid, u_int32_t spi,
- host_t *remote)
+ private_kernel_handler_t *this, u_int32_t reqid, u_int32_t spi,
+ host_t *remote)
{
- job_t *job;
- DBG1(DBG_KNL, "NAT mappings of ESP CHILD_SA with SPI %.8x and "
- "reqid {%u} changed, queuing update job", ntohl(spi), reqid);
- job = (job_t*)update_sa_job_create(reqid, remote);
- lib->processor->queue_job(lib->processor, job);
+ DBG1(DBG_KNL, "NAT mappings of ESP CHILD_SA with SPI %.8x and reqid {%u} "
+ "changed, queuing update job", ntohl(spi), reqid);
+
+ lib->processor->queue_job(lib->processor,
+ (job_t*)update_sa_job_create(reqid, remote));
return TRUE;
}
METHOD(kernel_listener_t, migrate, bool,
- private_kernel_handler_t *this, u_int32_t reqid,
- traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
- policy_dir_t direction, host_t *local, host_t *remote)
+ private_kernel_handler_t *this, u_int32_t reqid,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
+ policy_dir_t direction, host_t *local, host_t *remote)
{
- job_t *job;
- DBG1(DBG_KNL, "creating migrate job for policy %R === %R %N with "
- "reqid {%u}", src_ts, dst_ts, policy_dir_names, direction,
- reqid, local);
- job = (job_t*)migrate_job_create(reqid, src_ts, dst_ts, direction, local,
- remote);
- lib->processor->queue_job(lib->processor, job);
+ DBG1(DBG_KNL, "creating migrate job for policy %R === %R %N with reqid {%u}",
+ src_ts, dst_ts, policy_dir_names, direction, reqid, local);
+
+ lib->processor->queue_job(lib->processor,
+ (job_t*)migrate_job_create(reqid, src_ts, dst_ts,
+ direction, local, remote));
return TRUE;
}
METHOD(kernel_listener_t, roam, bool,
- private_kernel_handler_t *this, bool address)
+ private_kernel_handler_t *this, bool address)
{
- job_t *job;
- DBG2(DBG_KNL, "creating roam job %s", address ? "due to address/link change"
- : "due to route change");
- job = (job_t*)roam_job_create(address);
- lib->processor->queue_job(lib->processor, job);
+ DBG2(DBG_KNL, "creating roam job %s",
+ address ? "due to address/link change" : "due to route change");
+
+ lib->processor->queue_job(lib->processor, (job_t*)roam_job_create(address));
return TRUE;
}
METHOD(kernel_handler_t, destroy, void,
- private_kernel_handler_t *this)
+ private_kernel_handler_t *this)
{
hydra->kernel_interface->remove_listener(hydra->kernel_interface,
&this->public.listener);
@@ -162,4 +159,3 @@ kernel_handler_t *kernel_handler_create()
return &this->public;
}
-
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index edfa8a9c3..2e10f324b 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -131,19 +131,14 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
* parse a proposal string, either into ike_cfg or child_cfg
*/
static void add_proposals(private_stroke_config_t *this, char *string,
- ike_cfg_t *ike_cfg, child_cfg_t *child_cfg)
+ ike_cfg_t *ike_cfg, child_cfg_t *child_cfg, protocol_id_t proto)
{
if (string)
{
char *single;
char *strict;
proposal_t *proposal;
- protocol_id_t proto = PROTO_ESP;
- if (ike_cfg)
- {
- proto = PROTO_IKE;
- }
strict = string + strlen(string) - 1;
if (*strict == '!')
{
@@ -178,11 +173,11 @@ static void add_proposals(private_stroke_config_t *this, char *string,
}
if (ike_cfg)
{
- ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
+ ike_cfg->add_proposal(ike_cfg, proposal_create_default(proto));
}
else
{
- child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
+ child_cfg->add_proposal(child_cfg, proposal_create_default(proto));
}
}
@@ -270,7 +265,7 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg
msg->add_conn.fragmentation,
msg->add_conn.ikedscp);
- add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL);
+ add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL, PROTO_IKE);
return ike_cfg;
}
@@ -1159,8 +1154,16 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
- add_proposals(this, msg->add_conn.algorithms.esp, NULL, child_cfg);
-
+ if (msg->add_conn.algorithms.ah)
+ {
+ add_proposals(this, msg->add_conn.algorithms.ah,
+ NULL, child_cfg, PROTO_AH);
+ }
+ else
+ {
+ add_proposals(this, msg->add_conn.algorithms.esp,
+ NULL, child_cfg, PROTO_ESP);
+ }
return child_cfg;
}
diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c
index a5825519b..ea168058f 100644
--- a/src/libcharon/plugins/stroke/stroke_list.c
+++ b/src/libcharon/plugins/stroke/stroke_list.c
@@ -245,6 +245,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
u_int16_t encr_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED;
u_int16_t encr_size = 0, int_size = 0;
u_int16_t esn = NO_EXT_SEQ_NUMBERS;
+ bool first = TRUE;
proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
&encr_alg, &encr_size);
@@ -256,6 +257,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
if (encr_alg != ENCR_UNDEFINED)
{
fprintf(out, "%N", encryption_algorithm_names, encr_alg);
+ first = FALSE;
if (encr_size)
{
fprintf(out, "_%u", encr_size);
@@ -263,7 +265,11 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
}
if (int_alg != AUTH_UNDEFINED)
{
- fprintf(out, "/%N", integrity_algorithm_names, int_alg);
+ if (!first)
+ {
+ fprintf(out, "/");
+ }
+ fprintf(out, "%N", integrity_algorithm_names, int_alg);
if (int_size)
{
fprintf(out, "_%u", int_size);
diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c
index 88f73f3b0..3adebb523 100644
--- a/src/libcharon/plugins/stroke/stroke_socket.c
+++ b/src/libcharon/plugins/stroke/stroke_socket.c
@@ -186,6 +186,7 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
pop_string(msg, &msg->add_conn.xauth_identity);
pop_string(msg, &msg->add_conn.algorithms.ike);
pop_string(msg, &msg->add_conn.algorithms.esp);
+ pop_string(msg, &msg->add_conn.algorithms.ah);
pop_string(msg, &msg->add_conn.ikeme.mediated_by);
pop_string(msg, &msg->add_conn.ikeme.peerid);
DBG2(DBG_CFG, " eap_identity=%s", msg->add_conn.eap_identity);
@@ -193,6 +194,7 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
DBG2(DBG_CFG, " xauth_identity=%s", msg->add_conn.xauth_identity);
DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike);
DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp);
+ DBG2(DBG_CFG, " ah=%s", msg->add_conn.algorithms.ah);
DBG2(DBG_CFG, " dpddelay=%d", msg->add_conn.dpd.delay);
DBG2(DBG_CFG, " dpdtimeout=%d", msg->add_conn.dpd.timeout);
DBG2(DBG_CFG, " dpdaction=%d", msg->add_conn.dpd.action);
diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c
index 0268c88f3..3c3994b81 100644
--- a/src/libcharon/plugins/updown/updown_listener.c
+++ b/src/libcharon/plugins/updown/updown_listener.c
@@ -311,6 +311,7 @@ METHOD(listener_t, child_updown, bool,
"PLUTO_CONNECTION='%s' "
"PLUTO_INTERFACE='%s' "
"PLUTO_REQID='%u' "
+ "PLUTO_PROTO='%s' "
"PLUTO_UNIQUEID='%u' "
"PLUTO_ME='%H' "
"PLUTO_MY_ID='%Y' "
@@ -336,6 +337,7 @@ METHOD(listener_t, child_updown, bool,
config->get_name(config),
iface ? iface : "unknown",
child_sa->get_reqid(child_sa),
+ child_sa->get_protocol(child_sa) == PROTO_ESP ? "esp" : "ah",
ike_sa->get_unique_id(ike_sa),
me, ike_sa->get_my_id(ike_sa),
my_client, my_client_mask,
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 46e4b6f7b..9bd0c05ad 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -594,6 +594,9 @@ METHOD(child_sa_t, alloc_spi, u_int32_t,
proto_ike2ip(protocol), this->reqid,
&this->my_spi) == SUCCESS)
{
+ /* if we allocate a SPI, but then are unable to establish the SA, we
+ * need to know the protocol family to delete the partial SA */
+ this->protocol = protocol;
return this->my_spi;
}
return 0;
@@ -1039,12 +1042,6 @@ METHOD(child_sa_t, destroy, void,
/* delete SAs in the kernel, if they are set up */
if (this->my_spi)
{
- /* if CHILD was not established, use PROTO_ESP used during alloc_spi().
- * TODO: For AH support, we have to store protocol specific SPI.s */
- if (this->protocol == PROTO_NONE)
- {
- this->protocol = PROTO_ESP;
- }
hydra->kernel_interface->del_sa(hydra->kernel_interface,
this->other_addr, this->my_addr, this->my_spi,
proto_ike2ip(this->protocol), this->my_cpi,
diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c
index 1a2cdb777..605c10cea 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_delete.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c
@@ -177,7 +177,7 @@ METHOD(task_t, build_i, status_t,
DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
protocol_id_names, this->protocol, ntohl(this->spi));
- delete_payload = delete_payload_create(DELETE_V1, PROTO_ESP);
+ delete_payload = delete_payload_create(DELETE_V1, this->protocol);
delete_payload->add_spi(delete_payload, this->spi);
message->add_payload(message, &delete_payload->payload_interface);
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 925b1c617..12ee594b9 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -165,6 +165,11 @@ struct private_quick_mode_t {
*/
ipsec_mode_t mode;
+ /*
+ * SA protocol (ESP|AH) negotiated
+ */
+ protocol_id_t proto;
+
/**
* Use UDP encapsulation
*/
@@ -722,7 +727,7 @@ static status_t send_notify(private_quick_mode_t *this, notify_type_t type)
notify_payload_t *notify;
notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1,
- PROTO_ESP, type);
+ this->proto, type);
notify->set_spi(notify, this->spi_i);
this->ike_sa->queue_task(this->ike_sa,
@@ -774,6 +779,7 @@ METHOD(task_t, build_i, status_t,
{
sa_payload_t *sa_payload;
linked_list_t *list, *tsi, *tsr;
+ proposal_t *proposal;
diffie_hellman_group_t group;
encap_t encap;
@@ -800,12 +806,19 @@ METHOD(task_t, build_i, status_t,
}
}
- this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
+ list = this->config->get_proposals(this->config, MODP_NONE);
+ if (list->get_first(list, (void**)&proposal) == SUCCESS)
+ {
+ this->proto = proposal->get_protocol(proposal);
+ }
+ list->destroy_offset(list, offsetof(proposal_t, destroy));
+ this->spi_i = this->child_sa->alloc_spi(this->child_sa, this->proto);
if (!this->spi_i)
{
DBG1(DBG_IKE, "allocating SPI from kernel failed");
return FAILED;
}
+
group = this->config->get_dh_group(this->config);
if (group != MODP_NONE)
{
@@ -1139,7 +1152,8 @@ METHOD(task_t, build_r, status_t,
sa_payload_t *sa_payload;
encap_t encap;
- this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
+ this->proto = this->proposal->get_protocol(this->proposal);
+ this->spi_r = this->child_sa->alloc_spi(this->child_sa, this->proto);
if (!this->spi_r)
{
DBG1(DBG_IKE, "allocating SPI from kernel failed");
@@ -1347,6 +1361,7 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
.state = QM_INIT,
.tsi = tsi ? tsi->clone(tsi) : NULL,
.tsr = tsr ? tsr->clone(tsr) : NULL,
+ .proto = PROTO_ESP,
);
if (config)
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index 8ae36af84..7cfa537a9 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -244,9 +244,23 @@ static bool allocate_spi(private_child_create_t *this)
{
enumerator_t *enumerator;
proposal_t *proposal;
+ protocol_id_t proto = PROTO_ESP;
- /* TODO: allocate additional SPI for AH if we have such proposals */
- this->my_spi = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
+ if (this->initiator)
+ {
+ /* we just get a SPI for the first protocol. TODO: If we ever support
+ * proposal lists with mixed protocols, we'd need multiple SPIs */
+ if (this->proposals->get_first(this->proposals,
+ (void**)&proposal) == SUCCESS)
+ {
+ proto = proposal->get_protocol(proposal);
+ }
+ }
+ else
+ {
+ proto = this->proposal->get_protocol(this->proposal);
+ }
+ this->my_spi = this->child_sa->alloc_spi(this->child_sa, proto);
if (this->my_spi)
{
if (this->initiator)
diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c
index 26c305f77..d1f6a1bdc 100644
--- a/src/libcharon/sa/keymat.c
+++ b/src/libcharon/sa/keymat.c
@@ -93,6 +93,7 @@ int keymat_get_keylen_integ(integrity_algorithm_t alg)
{AUTH_HMAC_SHA2_384_192, 384},
{AUTH_HMAC_SHA2_512_256, 512},
{AUTH_AES_XCBC_96, 128},
+ {AUTH_AES_CMAC_96, 128},
};
int i;
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c
index 0d5c10d59..5a4c06c2d 100644
--- a/src/libcharon/sa/trap_manager.c
+++ b/src/libcharon/sa/trap_manager.c
@@ -102,6 +102,9 @@ METHOD(trap_manager_t, install, u_int32_t,
linked_list_t *my_ts, *other_ts, *list;
enumerator_t *enumerator;
status_t status;
+ linked_list_t *proposals;
+ proposal_t *proposal;
+ protocol_id_t proto = PROTO_ESP;
/* try to resolve addresses */
ike_cfg = peer->get_ike_cfg(peer);
@@ -160,10 +163,15 @@ METHOD(trap_manager_t, install, u_int32_t,
other_ts = child->get_traffic_selectors(child, FALSE, NULL, list);
list->destroy_offset(list, offsetof(host_t, destroy));
- /* while we don't know the finally negotiated protocol (ESP|AH), we
- * could iterate all proposals for a best guess (TODO). But as we
- * support ESP only for now, we set it here. */
- child_sa->set_protocol(child_sa, PROTO_ESP);
+ /* We don't know the finally negotiated protocol (ESP|AH), we install
+ * the SA with the protocol of the first proposal */
+ proposals = child->get_proposals(child, TRUE);
+ if (proposals->get_first(proposals, (void**)&proposal) == SUCCESS)
+ {
+ proto = proposal->get_protocol(proposal);
+ }
+ proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
+ child_sa->set_protocol(child_sa, proto);
child_sa->set_mode(child_sa, child->get_mode(child));
status = child_sa->add_policies(child_sa, my_ts, other_ts);
my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));