summaryrefslogtreecommitdiff
path: root/src/libcharon/encoding/payloads/sa_payload.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/encoding/payloads/sa_payload.c')
-rw-r--r--src/libcharon/encoding/payloads/sa_payload.c373
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 **)&current))
{
- 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;
}