From fbebc2a068942d16c20f8439b140027395ba25a0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 12:52:11 +0100 Subject: [PATCH 1/1] Implemented encoding of additional IKEv1 proposal attributes --- .../encoding/payloads/proposal_substructure.c | 163 ++++++++++++++------- .../encoding/payloads/proposal_substructure.h | 41 ++++-- src/libcharon/encoding/payloads/sa_payload.c | 69 ++------- .../encoding/payloads/transform_attribute.c | 19 ++- .../encoding/payloads/transform_attribute.h | 4 +- 5 files changed, 173 insertions(+), 123 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 924f5cb..11d684f 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -573,6 +573,41 @@ static u_int16_t get_ikev1_from_alg(transform_type_t type, u_int16_t value) } /** + * Get IKEv1 authentication attribute from auth_method_t + */ +static u_int16_t get_ikev1_auth(auth_method_t method) +{ + switch (method) + { + case AUTH_RSA: + return IKEV1_AUTH_RSA_SIG; + case AUTH_DSS: + return IKEV1_AUTH_DSS_SIG; + default: + /* TODO-IKEv1: Handle XAUTH methods */ + /* TODO-IKEv1: Handle ECDSA methods */ + case AUTH_PSK: + return IKEV1_AUTH_PSK; + } +} + +/** + * Get IKEv1 encapsulation mode + */ +static u_int16_t get_ikev1_mode(ipsec_mode_t mode, bool udp) +{ + switch (mode) + { + case MODE_TUNNEL: + return udp ? IKEV1_ENCAP_UDP_TUNNEL : IKEV1_ENCAP_TUNNEL; + case MODE_TRANSPORT: + return udp ? IKEV1_ENCAP_UDP_TRANSPORT : IKEV1_ENCAP_TRANSPORT; + default: + return IKEV1_ENCAP_TUNNEL; + } +} + +/** * Add an IKE transform to a proposal for IKEv1 */ static void add_to_proposal_v1_ike(proposal_t *proposal, @@ -771,7 +806,8 @@ proposal_substructure_t *proposal_substructure_create(payload_type_t type) * Add an IKEv1 IKE proposal to the substructure */ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, - proposal_t *proposal, int number) + proposal_t *proposal, u_int32_t lifetime, + auth_method_t method, int number) { transform_substructure_t *transform; u_int16_t alg, key_size; @@ -822,23 +858,15 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, } enumerator->destroy(enumerator); - /* TODO-IKEv1: Add lifetime, non-fixed auth-method and other attributes */ - if(1) /* TODO-IKEv1: Change to 0 if XAUTH is desired. */ - { transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_PSK)); - }else{ - transform->add_transform_attribute(transform, - transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_XAUTH_INIT_PSK)); - } + TATTR_PH1_AUTH_METHOD, get_ikev1_auth(method))); transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH1_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH1_LIFE_DURATION, 10800)); + TATTR_PH1_LIFE_DURATION, lifetime)); add_transform_substructure(this, transform); } @@ -847,7 +875,8 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, * Add an IKEv1 ESP proposal to the substructure */ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, - proposal_t *proposal, int number) + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + ipsec_mode_t mode, bool udp, int number) { transform_substructure_t *transform = NULL; u_int16_t alg, key_size; @@ -884,16 +913,27 @@ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, } enumerator->destroy(enumerator); - /* TODO-IKEv1: Add lifetime and other attributes, ESN */ - transform->add_transform_attribute(transform, - transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH2_ENCAP_MODE, IKEV1_ENCAP_TUNNEL)); transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_ENCAP_MODE, get_ikev1_mode(mode, udp))); + if (lifetime) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); - transform->add_transform_attribute(transform, - transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH2_SA_LIFE_DURATION, 3600)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifetime)); + } + else if (lifebytes) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_KILOBYTES)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifebytes / 1000)); + } add_transform_substructure(this, transform); } @@ -965,36 +1005,14 @@ static void set_from_proposal_v2(private_proposal_substructure_t *this, enumerator->destroy(enumerator); } -/* - * Described in header. +/** + * Set SPI and other data from proposal, compute length */ -proposal_substructure_t *proposal_substructure_create_from_proposal( - payload_type_t type, proposal_t *proposal) +static void set_data(private_proposal_substructure_t *this, proposal_t *proposal) { - private_proposal_substructure_t *this; u_int64_t spi64; u_int32_t spi32; - this = (private_proposal_substructure_t*)proposal_substructure_create(type); - - if (type == PROPOSAL_SUBSTRUCTURE) - { - set_from_proposal_v2(this, proposal); - } - else - { - switch (proposal->get_protocol(proposal)) - { - case PROTO_IKE: - set_from_proposal_v1_ike(this, proposal, 0); - break; - case PROTO_ESP: - set_from_proposal_v1_esp(this, proposal, 0); - break; - default: - break; - } - } /* add SPI, if necessary */ switch (proposal->get_protocol(proposal)) { @@ -1018,6 +1036,48 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( this->proposal_number = proposal->get_number(proposal); this->protocol_id = proposal->get_protocol(proposal); compute_length(this); +} + +/* + * Described in header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposal_v2( + proposal_t *proposal) +{ + private_proposal_substructure_t *this; + + this = (private_proposal_substructure_t*) + proposal_substructure_create(SECURITY_ASSOCIATION); + set_from_proposal_v2(this, proposal); + set_data(this, proposal); + + return &this->public; +} + +/** + * See header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposal_v1( + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp) +{ + private_proposal_substructure_t *this; + + this = (private_proposal_substructure_t*) + proposal_substructure_create(PROPOSAL_SUBSTRUCTURE_V1); + switch (proposal->get_protocol(proposal)) + { + case PROTO_IKE: + set_from_proposal_v1_ike(this, proposal, lifetime, auth, 0); + break; + case PROTO_ESP: + set_from_proposal_v1_esp(this, proposal, lifetime, + lifebytes, mode, udp, 0); + break; + default: + break; + } + set_data(this, proposal); return &this->public; } @@ -1025,8 +1085,9 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( /** * See header. */ -proposal_substructure_t *proposal_substructure_create_from_proposals( - linked_list_t *proposals) +proposal_substructure_t *proposal_substructure_create_from_proposals_v1( + linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp) { private_proposal_substructure_t *this = NULL; enumerator_t *enumerator; @@ -1039,18 +1100,20 @@ proposal_substructure_t *proposal_substructure_create_from_proposals( if (!this) { this = (private_proposal_substructure_t*) - proposal_substructure_create_from_proposal( - PROPOSAL_SUBSTRUCTURE_V1, proposal); + proposal_substructure_create_from_proposal_v1( + proposal, lifetime, lifebytes, auth, mode, udp); } else { switch (proposal->get_protocol(proposal)) { case PROTO_IKE: - set_from_proposal_v1_ike(this, proposal, ++number); + set_from_proposal_v1_ike(this, proposal, lifetime, + auth, ++number); break; case PROTO_ESP: - set_from_proposal_v1_esp(this, proposal, ++number); + set_from_proposal_v1_esp(this, proposal, lifetime, + lifebytes, mode, udp, ++number); break; default: break; diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h index 496a352..de06f91 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.h +++ b/src/libcharon/encoding/payloads/proposal_substructure.h @@ -29,6 +29,8 @@ typedef struct proposal_substructure_t proposal_substructure_t; #include #include #include +#include +#include /** * Class representing an IKEv1/IKEv2 proposal substructure. @@ -124,22 +126,43 @@ struct proposal_substructure_t { proposal_substructure_t *proposal_substructure_create(payload_type_t type); /** - * Creates a proposal_substructure_t from a proposal_t. + * Creates an IKEv2 proposal_substructure_t from a proposal_t. * - * @param type PROPOSAL_SUBSTRUCTURE or PROPOSAL_SUBSTRUCTURE_V1 * @param proposal proposal to build a substruct out of it - * @return proposal_substructure_t object + * @return proposal_substructure_t PROPOSAL_SUBSTRUCTURE */ -proposal_substructure_t *proposal_substructure_create_from_proposal( - payload_type_t type, proposal_t *proposal); - +proposal_substructure_t *proposal_substructure_create_from_proposal_v2( + proposal_t *proposal); /** - * Creates a proposal_substructure_t from a list of proposal_t (IKEv1 only). + * Creates an IKEv1 proposal_substructure_t from a proposal_t. * * @param proposal proposal to build a substruct out of it + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * + * + * @return proposal_substructure_t object PROPOSAL_SUBSTRUCTURE_V1 + */ +proposal_substructure_t *proposal_substructure_create_from_proposal_v1( + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp); + +/** + * Creates an IKEv1 proposal_substructure_t from a list of proposal_t. + * + * @param proposals list of proposal_t to encode in a substructure + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation * @return IKEv1 proposal_substructure_t PROPOSAL_SUBSTRUCTURE_V1 */ -proposal_substructure_t *proposal_substructure_create_from_proposals( - linked_list_t *proposals); +proposal_substructure_t *proposal_substructure_create_from_proposals_v1( + linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp); #endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 385517b..5f739c9 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -259,17 +259,12 @@ METHOD(payload_t, get_length, size_t, /** * Create a transform substructure from a proposal, add to payload */ -static void add_proposal(private_sa_payload_t *this, proposal_t *proposal) +static void add_proposal_v2(private_sa_payload_t *this, proposal_t *proposal) { proposal_substructure_t *substruct, *last; - payload_type_t subtype = PROPOSAL_SUBSTRUCTURE; u_int count; - if (this->type == SECURITY_ASSOCIATION_V1) - { - subtype = PROPOSAL_SUBSTRUCTURE_V1; - } - substruct = proposal_substructure_create_from_proposal(subtype, proposal); + substruct = proposal_substructure_create_from_proposal_v2(proposal); count = this->proposals->get_count(this->proposals); if (count > 0) { @@ -417,53 +412,6 @@ sa_payload_t *sa_payload_create(payload_type_t type) /* * Described in header. */ -sa_payload_t *sa_payload_create_from_proposal_list(payload_type_t type, - linked_list_t *proposals) -{ - private_sa_payload_t *this; - enumerator_t *enumerator; - proposal_t *proposal; - - this = (private_sa_payload_t*)sa_payload_create(type); - if (type == SECURITY_ASSOCIATION) - { - enumerator = proposals->create_enumerator(proposals); - while (enumerator->enumerate(enumerator, &proposal)) - { - add_proposal(this, proposal); - } - enumerator->destroy(enumerator); - } - else - { /* IKEv1 encodes multiple proposals in a single substructure - * TODO-IKEv1: Encode ESP+AH proposals in two different substructs */ - proposal_substructure_t *substruct; - - substruct = proposal_substructure_create_from_proposals(proposals); - substruct->set_is_last_proposal(substruct, TRUE); - this->proposals->insert_last(this->proposals, substruct); - compute_length(this); - } - return &this->public; -} - -/* - * Described in header. - */ -sa_payload_t *sa_payload_create_from_proposal(payload_type_t type, - proposal_t *proposal) -{ - private_sa_payload_t *this; - - this = (private_sa_payload_t*)sa_payload_create(type); - add_proposal(this, proposal); - - return &this->public; -} - -/* - * Described in header. - */ sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals) { private_sa_payload_t *this; @@ -474,7 +422,7 @@ sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals) enumerator = proposals->create_enumerator(proposals); while (enumerator->enumerate(enumerator, &proposal)) { - add_proposal(this, proposal); + add_proposal_v2(this, proposal); } enumerator->destroy(enumerator); @@ -489,7 +437,7 @@ sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal) private_sa_payload_t *this; this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); - add_proposal(this, proposal); + add_proposal_v2(this, proposal); return &this->public; @@ -505,11 +453,12 @@ sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals, proposal_substructure_t *substruct; private_sa_payload_t *this; - this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION_V1); /* IKEv1 encodes multiple proposals in a single substructure * TODO-IKEv1: Encode ESP+AH proposals in two different substructs */ - substruct = proposal_substructure_create_from_proposals(proposals); + substruct = proposal_substructure_create_from_proposals_v1(proposals, + lifetime, lifebytes, auth, mode, udp); substruct->set_is_last_proposal(substruct, TRUE); this->proposals->insert_last(this->proposals, substruct); compute_length(this); @@ -529,8 +478,8 @@ sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal, this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION_V1); - substruct = proposal_substructure_create_from_proposal( - PROPOSAL_SUBSTRUCTURE_V1, proposal); + substruct = proposal_substructure_create_from_proposal_v1(proposal, + lifetime, lifebytes, auth, mode, udp); substruct->set_is_last_proposal(substruct, TRUE); this->proposals->insert_last(this->proposals, substruct); compute_length(this); diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index 474362f..7e8a9c7 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -290,13 +290,28 @@ transform_attribute_t *transform_attribute_create(payload_type_t type) * Described in header. */ transform_attribute_t *transform_attribute_create_value(payload_type_t type, - transform_attribute_type_t kind, u_int16_t value) + transform_attribute_type_t kind, u_int64_t value) { transform_attribute_t *attribute; attribute = transform_attribute_create(type); attribute->set_attribute_type(attribute, kind); - attribute->set_value(attribute, value); + if (value <= UINT16_MAX) + { + attribute->set_value(attribute, value); + } + else if (value <= UINT32_MAX) + { + u_int32_t val32; + + val32 = htonl(value); + attribute->set_value_chunk(attribute, chunk_from_thing(val32)); + } + else + { + value = htobe64(value); + attribute->set_value_chunk(attribute, chunk_from_thing(value)); + } return attribute; } diff --git a/src/libcharon/encoding/payloads/transform_attribute.h b/src/libcharon/encoding/payloads/transform_attribute.h index eedb3be..52e5d84 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.h +++ b/src/libcharon/encoding/payloads/transform_attribute.h @@ -163,7 +163,7 @@ struct transform_attribute_t { transform_attribute_t *transform_attribute_create(payload_type_t type); /** - * Creates a two byte value attribute for a given attribute kind. + * Creates a two byte value or a larger attribute for a given attribute kind. * * @param type TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 * @param kind attribute kind @@ -171,6 +171,6 @@ transform_attribute_t *transform_attribute_create(payload_type_t type); * @return transform_attribute_t object */ transform_attribute_t *transform_attribute_create_value(payload_type_t type, - transform_attribute_type_t kind, u_int16_t value); + transform_attribute_type_t kind, u_int64_t value); #endif /** TRANSFORM_ATTRIBUTE_H_ @}*/ -- 2.7.4