/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2005-2010 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
#include "sa_payload.h"
#include <encoding/payloads/encodings.h>
-#include <utils/linked_list.h>
+#include <collections/linked_list.h>
#include <daemon.h>
/* IKEv1 situation */
/* Situation*/
{ U_INT_32, offsetof(private_sa_payload_t, situation) },
/* Proposals are stored in a proposal substructure list */
- { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1,
+ { PAYLOAD_LIST + PLV1_PROPOSAL_SUBSTRUCTURE,
offsetof(private_sa_payload_t, proposals) },
};
/* Length of the whole SA payload*/
{ PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) },
/* Proposals are stored in a proposal substructure list */
- { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE,
+ { PAYLOAD_LIST + PLV2_PROPOSAL_SUBSTRUCTURE,
offsetof(private_sa_payload_t, proposals) },
};
enumerator_t *enumerator;
proposal_substructure_t *substruct;
- if (this->type == SECURITY_ASSOCIATION)
+ if (this->type == PLV2_SECURITY_ASSOCIATION)
{
expected_number = 1;
}
METHOD(payload_t, get_encoding_rules, int,
private_sa_payload_t *this, encoding_rule_t **rules)
{
- if (this->type == SECURITY_ASSOCIATION_V1)
+ if (this->type == PLV1_SECURITY_ASSOCIATION)
{
*rules = encodings_v1;
return countof(encodings_v1);
METHOD(payload_t, get_header_length, int,
private_sa_payload_t *this)
{
- if (this->type == SECURITY_ASSOCIATION_V1)
+ if (this->type == PLV1_SECURITY_ASSOCIATION)
{
return 12;
}
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;
- 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)
{
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)
+ if (this->type == PLV1_SECURITY_ASSOCIATION)
{ /* 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))
{
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, *espah = NULL, *ipcomp = NULL;
+ linked_list_t *list;
+
+ /* we currently only support the combination ESP|AH+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_AH &&
+ protocol_id != PROTO_IPCOMP)
+ { /* unsupported combination */
+ espah = ipcomp = NULL;
+ unsupported_proposal = current_proposal;
+ continue;
+ }
+ if (proposal_number != current_proposal)
+ { /* start of a new proposal */
+ if (espah && ipcomp)
+ { /* previous proposal is valid */
+ break;
+ }
+ espah = ipcomp = NULL;
+ current_proposal = proposal_number;
+ }
+ switch (protocol_id)
{
- list->insert_last(list, proposal);
+ case PROTO_ESP:
+ case PROTO_AH:
+ espah = substruct;
+ break;
+ case PROTO_IPCOMP:
+ ipcomp = substruct;
+ break;
}
}
enumerator->destroy(enumerator);
+
+ list = linked_list_create();
+ if (espah && ipcomp && ipcomp->get_cpi(ipcomp, cpi))
+ {
+ espah->get_proposals(espah, list);
+ }
return list;
}
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)
{
.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,
+ .next_payload = PL_NONE,
.proposals = linked_list_create(),
.type = type,
/* for IKEv1 only */
/*
* Described in header.
*/
-sa_payload_t *sa_payload_create_from_proposal_list(payload_type_t type,
- linked_list_t *proposals)
+sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals)
{
- sa_payload_t *this;
+ private_sa_payload_t *this;
enumerator_t *enumerator;
proposal_t *proposal;
- this = sa_payload_create(type);
+ this = (private_sa_payload_t*)sa_payload_create(PLV2_SECURITY_ASSOCIATION);
enumerator = proposals->create_enumerator(proposals);
while (enumerator->enumerate(enumerator, &proposal))
{
- this->add_proposal(this, proposal);
+ add_proposal_v2(this, proposal);
}
enumerator->destroy(enumerator);
- return this;
+ return &this->public;
}
/*
* Described in header.
*/
-sa_payload_t *sa_payload_create_from_proposal(payload_type_t type,
- proposal_t *proposal)
+sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal)
{
- sa_payload_t *this;
+ private_sa_payload_t *this;
- this = sa_payload_create(type);
- this->add_proposal(this, proposal);
+ this = (private_sa_payload_t*)sa_payload_create(PLV2_SECURITY_ASSOCIATION);
+ add_proposal_v2(this, proposal);
- return this;
+ 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(PLV1_SECURITY_ASSOCIATION);
+
+ 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;
}