diff options
Diffstat (limited to 'src')
23 files changed, 265 insertions, 137 deletions
diff --git a/src/_updown/_updown.in b/src/_updown/_updown.in index f582e1a78..ca0398ab7 100644 --- a/src/_updown/_updown.in +++ b/src/_updown/_updown.in @@ -45,7 +45,10 @@ # is the name of the ipsec interface to be used. # # PLUTO_REQID -# is the requid of the ESP policy +# is the requid of the AH|ESP policy +# +# PLUTO_PROTO +# is the negotiated IPsec protocol, ah|esp # # PLUTO_UNIQUEID # is the unique identifier of the associated IKE_SA @@ -280,7 +283,7 @@ then IPSEC_POLICY_OUT="" else KLIPS= - IPSEC_POLICY="-m policy --pol ipsec --proto esp --reqid $PLUTO_REQID" + IPSEC_POLICY="-m policy --pol ipsec --proto $PLUTO_PROTO --reqid $PLUTO_REQID" IPSEC_POLICY_IN="$IPSEC_POLICY --dir in" IPSEC_POLICY_OUT="$IPSEC_POLICY --dir out" fi 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)); diff --git a/src/starter/args.c b/src/starter/args.c index 5fbf51856..f5a617eaa 100644 --- a/src/starter/args.c +++ b/src/starter/args.c @@ -140,7 +140,6 @@ static const token_info_t token_info[] = { ARG_MISC, 0, NULL /* KW_COMPRESS */ }, { ARG_ENUM, offsetof(starter_conn_t, install_policy), LST_bool }, { ARG_ENUM, offsetof(starter_conn_t, aggressive), LST_bool }, - { ARG_MISC, 0, NULL /* KW_AUTH */ }, { ARG_STR, offsetof(starter_conn_t, authby), LST_authby }, { ARG_STR, offsetof(starter_conn_t, eap_identity), NULL }, { ARG_STR, offsetof(starter_conn_t, aaa_identity), NULL }, @@ -161,6 +160,7 @@ static const token_info_t token_info[] = { ARG_MISC, 0, NULL /* KW_REAUTH */ }, { ARG_STR, offsetof(starter_conn_t, ike), NULL }, { ARG_STR, offsetof(starter_conn_t, esp), NULL }, + { ARG_STR, offsetof(starter_conn_t, ah), NULL }, { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL }, { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL }, { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action }, @@ -295,6 +295,15 @@ bool assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base, return FALSE; } + if (token == KW_ESP || token == KW_AH) + { + if (*seen & (SEEN_KW(KW_ESP, first) | SEEN_KW(KW_AH, first))) + { + DBG1(DBG_APP, "# can't have both 'ah' and 'esp' options"); + return FALSE; + } + } + /* set flag that this argument has been seen */ *seen |= SEEN_KW(token, first); diff --git a/src/starter/confread.c b/src/starter/confread.c index 2fb022692..cec9399e3 100644 --- a/src/starter/confread.c +++ b/src/starter/confread.c @@ -521,9 +521,6 @@ static void load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg case KW_COMPRESS: KW_SA_OPTION_FLAG("yes", "no", SA_OPTION_COMPRESS) break; - case KW_AUTH: - KW_SA_OPTION_FLAG("ah", "esp", SA_OPTION_AUTHENTICATE) - break; case KW_MARK: if (!handle_mark(kw->value, &conn->mark_in)) { diff --git a/src/starter/confread.h b/src/starter/confread.h index 0690bed4e..d55a17e63 100644 --- a/src/starter/confread.h +++ b/src/starter/confread.h @@ -78,7 +78,6 @@ typedef enum { typedef enum { /* IPsec options */ - SA_OPTION_AUTHENTICATE = 1 << 0, /* use AH instead of ESP? */ SA_OPTION_COMPRESS = 1 << 1, /* use IPComp */ /* IKE and other other options */ @@ -171,6 +170,7 @@ struct starter_conn { unsigned long id; char *esp; + char *ah; char *ike; time_t dpd_delay; diff --git a/src/starter/keywords.h b/src/starter/keywords.h index 83ce4a7dd..705a7c16e 100644 --- a/src/starter/keywords.h +++ b/src/starter/keywords.h @@ -36,7 +36,6 @@ typedef enum { KW_COMPRESS, KW_INSTALLPOLICY, KW_AGGRESSIVE, - KW_AUTH, KW_AUTHBY, KW_EAP_IDENTITY, KW_AAA_IDENTITY, @@ -57,6 +56,7 @@ typedef enum { KW_REAUTH, KW_IKE, KW_ESP, + KW_AH, KW_DPDDELAY, KW_DPDTIMEOUT, KW_DPDACTION, diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt index 20d35ded0..ad915bf2a 100644 --- a/src/starter/keywords.txt +++ b/src/starter/keywords.txt @@ -34,7 +34,6 @@ type, KW_TYPE compress, KW_COMPRESS installpolicy, KW_INSTALLPOLICY aggressive, KW_AGGRESSIVE -auth, KW_AUTH authby, KW_AUTHBY eap_identity, KW_EAP_IDENTITY aaa_identity, KW_AAA_IDENTITY @@ -57,6 +56,7 @@ rekey, KW_REKEY reauth, KW_REAUTH ike, KW_IKE esp, KW_ESP +ah, KW_AH dpddelay, KW_DPDDELAY dpdtimeout, KW_DPDTIMEOUT dpdaction, KW_DPDACTION diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index bf7e0284f..fca4b1e7d 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -192,6 +192,7 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn) msg.add_conn.unique = cfg->setup.uniqueids; msg.add_conn.algorithms.ike = push_string(&msg, conn->ike); msg.add_conn.algorithms.esp = push_string(&msg, conn->esp); + msg.add_conn.algorithms.ah = push_string(&msg, conn->ah); msg.add_conn.dpd.delay = conn->dpd_delay; msg.add_conn.dpd.timeout = conn->dpd_timeout; msg.add_conn.dpd.action = conn->dpd_action; diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h index 6c8dcf5f9..5ece7248b 100644 --- a/src/stroke/stroke_msg.h +++ b/src/stroke/stroke_msg.h @@ -275,6 +275,7 @@ struct stroke_msg_t { struct { char *ike; char *esp; + char *ah; } algorithms; struct { int reauth; |