diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2013-10-17 21:23:38 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2013-10-17 21:23:38 +0200 |
commit | 9d37ad77ef660b92ea51b69d74e14f931d2a04e2 (patch) | |
tree | d6bbb4a5fed1959f8675df9ee7c03713b543fcc9 /src/libcharon/encoding/payloads/sa_payload.c | |
parent | 104f57d4b0fb6d7547d6898352eaa5fb4b222010 (diff) | |
parent | e5ee4e7fcdd58b7d86bf1b458da2c63e8e19627b (diff) | |
download | vyos-strongswan-9d37ad77ef660b92ea51b69d74e14f931d2a04e2.tar.gz vyos-strongswan-9d37ad77ef660b92ea51b69d74e14f931d2a04e2.zip |
Merge tag 'v5.1.0-1' into sid
tag strongSwan 5.1.0-1
Diffstat (limited to 'src/libcharon/encoding/payloads/sa_payload.c')
-rw-r--r-- | src/libcharon/encoding/payloads/sa_payload.c | 373 |
1 files changed, 328 insertions, 45 deletions
diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 010f63cfd..613412014 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -19,9 +20,11 @@ #include "sa_payload.h" #include <encoding/payloads/encodings.h> -#include <utils/linked_list.h> +#include <collections/linked_list.h> #include <daemon.h> +/* IKEv1 situation */ +#define SIT_IDENTITY_ONLY 1 typedef struct private_sa_payload_t private_sa_payload_t; @@ -48,7 +51,7 @@ struct private_sa_payload_t { /** * Reserved bits */ - bool reserved[7]; + bool reserved[8]; /** * Length of this payload. @@ -58,21 +61,75 @@ struct private_sa_payload_t { /** * Proposals in this payload are stored in a linked_list_t. */ - linked_list_t * proposals; + linked_list_t *proposals; + + /** + * Type of this payload, V1 or V2 + */ + payload_type_t type; + + /** + * IKEv1 DOI + */ + u_int32_t doi; + + /** + * IKEv1 situation + */ + u_int32_t situation; }; /** - * Encoding rules to parse or generate a IKEv2-SA Payload - * - * The defined offsets are the positions in a object of type - * private_sa_payload_t. + * Encoding rules for IKEv1 SA payload + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_sa_payload_t, next_payload) }, + /* 8 reserved bits */ + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[7]) }, + /* Length of the whole SA payload*/ + { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) }, + /* DOI*/ + { U_INT_32, offsetof(private_sa_payload_t, doi) }, + /* Situation*/ + { U_INT_32, offsetof(private_sa_payload_t, situation) }, + /* Proposals are stored in a proposal substructure list */ + { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1, + offsetof(private_sa_payload_t, proposals) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! DOI ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Situation ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ <Proposals> ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Encoding rules for IKEv2 SA payload */ -encoding_rule_t sa_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_sa_payload_t, next_payload) }, /* the critical bit */ { FLAG, offsetof(private_sa_payload_t, critical) }, - /* 7 Bit reserved bits, nowhere stored */ + /* 7 Bit reserved bits */ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) }, { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) }, { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) }, @@ -82,9 +139,9 @@ encoding_rule_t sa_payload_encodings[] = { { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) }, /* Length of the whole SA payload*/ { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) }, - /* Proposals are stored in a proposal substructure, - offset points to a linked_list_t pointer */ - { PROPOSALS, offsetof(private_sa_payload_t, proposals) }, + /* Proposals are stored in a proposal substructure list */ + { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE, + offsetof(private_sa_payload_t, proposals) }, }; /* @@ -102,11 +159,16 @@ encoding_rule_t sa_payload_encodings[] = { METHOD(payload_t, verify, status_t, private_sa_payload_t *this) { - int expected_number = 1, current_number; + int expected_number = 0, current_number; status_t status = SUCCESS; enumerator_t *enumerator; proposal_substructure_t *substruct; + if (this->type == SECURITY_ASSOCIATION) + { + expected_number = 1; + } + /* check proposal numbering */ enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, (void**)&substruct)) @@ -131,17 +193,32 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_sa_payload_t *this, encoding_rule_t **rules) { - *rules = sa_payload_encodings; - *rule_count = countof(sa_payload_encodings); + if (this->type == SECURITY_ASSOCIATION_V1) + { + *rules = encodings_v1; + return countof(encodings_v1); + } + *rules = encodings_v2; + return countof(encodings_v2); +} + +METHOD(payload_t, get_header_length, int, + private_sa_payload_t *this) +{ + if (this->type == SECURITY_ASSOCIATION_V1) + { + return 12; + } + return 4; } METHOD(payload_t, get_type, payload_type_t, private_sa_payload_t *this) { - return SECURITY_ASSOCIATION; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -163,16 +240,15 @@ static void compute_length(private_sa_payload_t *this) { enumerator_t *enumerator; payload_t *current; - size_t length = SA_PAYLOAD_HEADER_LENGTH; + + this->payload_length = get_header_length(this); enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, (void **)¤t)) { - length += current->get_length(current); + this->payload_length += current->get_length(current); } enumerator->destroy(enumerator); - - this->payload_length = length; } METHOD(payload_t, get_length, size_t, @@ -181,14 +257,16 @@ METHOD(payload_t, get_length, size_t, return this->payload_length; } -METHOD(sa_payload_t, add_proposal, void, - private_sa_payload_t *this, proposal_t *proposal) +/** + * Create a transform substructure from a proposal, add to payload + */ +static void add_proposal_v2(private_sa_payload_t *this, proposal_t *proposal) { proposal_substructure_t *substruct, *last; u_int count; + substruct = proposal_substructure_create_from_proposal_v2(proposal); count = this->proposals->get_count(this->proposals); - substruct = proposal_substructure_create_from_proposal(proposal); if (count > 0) { this->proposals->get_last(this->proposals, (void**)&last); @@ -215,15 +293,19 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*, int ignore_struct_number = 0; enumerator_t *enumerator; proposal_substructure_t *substruct; - linked_list_t *list; - proposal_t *proposal; + linked_list_t *substructs, *list; + + if (this->type == SECURITY_ASSOCIATION_V1) + { /* IKEv1 proposals start with 0 */ + struct_number = ignore_struct_number = -1; + } - list = linked_list_create(); /* we do not support proposals split up to two proposal substructures, as * AH+ESP bundles are not supported in RFC4301 anymore. * To handle such structures safely, we just skip proposals with multiple * protocols. */ + substructs = linked_list_create(); enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, &substruct)) { @@ -231,22 +313,80 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*, if (substruct->get_proposal_number(substruct) == struct_number) { if (ignore_struct_number < struct_number) - { - /* remove an already added, if first of series */ - list->remove_last(list, (void**)&proposal); - proposal->destroy(proposal); + { /* remove an already added, if first of series */ + substructs->remove_last(substructs, (void**)&substruct); ignore_struct_number = struct_number; } continue; } struct_number++; - proposal = substruct->get_proposal(substruct); - if (proposal) + substructs->insert_last(substructs, substruct); + } + enumerator->destroy(enumerator); + + /* generate proposals from substructs */ + list = linked_list_create(); + enumerator = substructs->create_enumerator(substructs); + while (enumerator->enumerate(enumerator, &substruct)) + { + substruct->get_proposals(substruct, list); + } + enumerator->destroy(enumerator); + substructs->destroy(substructs); + return list; +} + +METHOD(sa_payload_t, get_ipcomp_proposals, linked_list_t*, + private_sa_payload_t *this, u_int16_t *cpi) +{ + int current_proposal = -1, unsupported_proposal = -1; + enumerator_t *enumerator; + proposal_substructure_t *substruct, *esp = NULL, *ipcomp = NULL; + linked_list_t *list; + + /* we currently only support the combination ESP+IPComp, find the first */ + enumerator = this->proposals->create_enumerator(this->proposals); + while (enumerator->enumerate(enumerator, &substruct)) + { + u_int8_t proposal_number = substruct->get_proposal_number(substruct); + u_int8_t protocol_id = substruct->get_protocol_id(substruct); + + if (proposal_number == unsupported_proposal) + { + continue; + } + if (protocol_id != PROTO_ESP && protocol_id != PROTO_IPCOMP) + { /* unsupported combination */ + esp = ipcomp = NULL; + unsupported_proposal = current_proposal; + continue; + } + if (proposal_number != current_proposal) + { /* start of a new proposal */ + if (esp && ipcomp) + { /* previous proposal is valid */ + break; + } + esp = ipcomp = NULL; + current_proposal = proposal_number; + } + switch (protocol_id) { - list->insert_last(list, proposal); + case PROTO_ESP: + esp = substruct; + break; + case PROTO_IPCOMP: + ipcomp = substruct; + break; } } enumerator->destroy(enumerator); + + list = linked_list_create(); + if (esp && ipcomp && ipcomp->get_cpi(ipcomp, cpi)) + { + esp->get_proposals(esp, list); + } return list; } @@ -256,18 +396,86 @@ METHOD(sa_payload_t, create_substructure_enumerator, enumerator_t*, return this->proposals->create_enumerator(this->proposals); } +METHOD(sa_payload_t, get_lifetime, u_int32_t, + private_sa_payload_t *this) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + u_int32_t lifetime = 0; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + lifetime = substruct->get_lifetime(substruct); + } + enumerator->destroy(enumerator); + + return lifetime; +} + +METHOD(sa_payload_t, get_lifebytes, u_int64_t, + private_sa_payload_t *this) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + u_int64_t lifebytes = 0; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + lifebytes = substruct->get_lifebytes(substruct); + } + enumerator->destroy(enumerator); + + return lifebytes; +} + +METHOD(sa_payload_t, get_auth_method, auth_method_t, + private_sa_payload_t *this) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + auth_method_t method = AUTH_NONE; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + method = substruct->get_auth_method(substruct); + } + enumerator->destroy(enumerator); + + return method; +} + +METHOD(sa_payload_t, get_encap_mode, ipsec_mode_t, + private_sa_payload_t *this, bool *udp) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + ipsec_mode_t mode = MODE_NONE; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + mode = substruct->get_encap_mode(substruct, udp); + } + enumerator->destroy(enumerator); + + return mode; +} + METHOD2(payload_t, sa_payload_t, destroy, void, private_sa_payload_t *this) { this->proposals->destroy_offset(this->proposals, - offsetof(proposal_substructure_t, destroy)); + offsetof(payload_t, destroy)); free(this); } /* * Described in header. */ -sa_payload_t *sa_payload_create() +sa_payload_t *sa_payload_create(payload_type_t type) { private_sa_payload_t *this; @@ -276,38 +484,49 @@ sa_payload_t *sa_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, .get_type = _get_type, .destroy = _destroy, }, - .add_proposal = _add_proposal, .get_proposals = _get_proposals, + .get_ipcomp_proposals = _get_ipcomp_proposals, .create_substructure_enumerator = _create_substructure_enumerator, + .get_lifetime = _get_lifetime, + .get_lifebytes = _get_lifebytes, + .get_auth_method = _get_auth_method, + .get_encap_mode = _get_encap_mode, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = SA_PAYLOAD_HEADER_LENGTH, .proposals = linked_list_create(), + .type = type, + /* for IKEv1 only */ + .doi = IKEV1_DOI_IPSEC, + .situation = SIT_IDENTITY_ONLY, ); + + compute_length(this); + return &this->public; } /* * Described in header. */ -sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals) +sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals) { private_sa_payload_t *this; enumerator_t *enumerator; proposal_t *proposal; - this = (private_sa_payload_t*)sa_payload_create(); + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); enumerator = proposals->create_enumerator(proposals); while (enumerator->enumerate(enumerator, &proposal)) { - add_proposal(this, proposal); + add_proposal_v2(this, proposal); } enumerator->destroy(enumerator); @@ -317,12 +536,76 @@ sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals) /* * Described in header. */ -sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal) +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(); - add_proposal(this, proposal); + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); + add_proposal_v2(this, proposal); + + return &this->public; + +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, + encap_t udp, u_int16_t cpi) +{ + proposal_substructure_t *substruct; + private_sa_payload_t *this; + + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION_V1); + + if (!proposals || !proposals->get_count(proposals)) + { + return &this->public; + } + + /* IKEv1 encodes multiple proposals in a single substructure + * TODO-IKEv1: Encode ESP+AH proposals in two substructs with same num */ + substruct = proposal_substructure_create_from_proposals_v1(proposals, + lifetime, lifebytes, auth, mode, udp); + this->proposals->insert_last(this->proposals, substruct); + substruct->set_is_last_proposal(substruct, FALSE); + if (cpi) + { + u_int8_t proposal_number = substruct->get_proposal_number(substruct); + + substruct = proposal_substructure_create_for_ipcomp_v1(lifetime, + lifebytes, cpi, mode, udp, proposal_number); + this->proposals->insert_last(this->proposals, substruct); + substruct->set_is_last_proposal(substruct, FALSE); + /* add the proposals again without IPComp */ + substruct = proposal_substructure_create_from_proposals_v1(proposals, + lifetime, lifebytes, auth, mode, udp); + substruct->set_proposal_number(substruct, proposal_number + 1); + this->proposals->insert_last(this->proposals, substruct); + } + substruct->set_is_last_proposal(substruct, TRUE); + compute_length(this); + + return &this->public; +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, + encap_t udp, u_int16_t cpi) +{ + private_sa_payload_t *this; + linked_list_t *proposals; + proposals = linked_list_create(); + proposals->insert_last(proposals, proposal); + this = (private_sa_payload_t*)sa_payload_create_from_proposals_v1(proposals, + lifetime, lifebytes, auth, mode, udp, cpi); + proposals->destroy(proposals); return &this->public; } |