2 * Copyright (C) 2005-2010 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 #include "sa_payload.h"
21 #include <encoding/payloads/encodings.h>
22 #include <utils/linked_list.h>
26 #define SIT_IDENTITY_ONLY 1
28 typedef struct private_sa_payload_t private_sa_payload_t
;
31 * Private data of an sa_payload_t object.
33 struct private_sa_payload_t
{
36 * Public sa_payload_t interface.
43 u_int8_t next_payload
;
56 * Length of this payload.
58 u_int16_t payload_length
;
61 * Proposals in this payload are stored in a linked_list_t.
63 linked_list_t
*proposals
;
66 * Type of this payload, V1 or V2
82 * Encoding rules for IKEv1 SA payload
84 static encoding_rule_t encodings_v1
[] = {
85 /* 1 Byte next payload type, stored in the field next_payload */
86 { U_INT_8
, offsetof(private_sa_payload_t
, next_payload
) },
88 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[0]) },
89 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[1]) },
90 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[2]) },
91 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[3]) },
92 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[4]) },
93 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[5]) },
94 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[6]) },
95 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[7]) },
96 /* Length of the whole SA payload*/
97 { PAYLOAD_LENGTH
, offsetof(private_sa_payload_t
, payload_length
) },
99 { U_INT_32
, offsetof(private_sa_payload_t
, doi
) },
101 { U_INT_32
, offsetof(private_sa_payload_t
, situation
) },
102 /* Proposals are stored in a proposal substructure,
103 offset points to a linked_list_t pointer */
104 { PROPOSALS_V1
, offsetof(private_sa_payload_t
, proposals
) },
109 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
110 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
111 ! Next Payload ! RESERVED ! Payload Length !
112 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
114 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
116 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
120 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124 * Encoding rules for IKEv2 SA payload
126 static encoding_rule_t encodings_v2
[] = {
127 /* 1 Byte next payload type, stored in the field next_payload */
128 { U_INT_8
, offsetof(private_sa_payload_t
, next_payload
) },
129 /* the critical bit */
130 { FLAG
, offsetof(private_sa_payload_t
, critical
) },
131 /* 7 Bit reserved bits */
132 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[0]) },
133 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[1]) },
134 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[2]) },
135 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[3]) },
136 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[4]) },
137 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[5]) },
138 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[6]) },
139 /* Length of the whole SA payload*/
140 { PAYLOAD_LENGTH
, offsetof(private_sa_payload_t
, payload_length
) },
141 /* Proposals are stored in a proposal substructure,
142 offset points to a linked_list_t pointer */
143 { PROPOSALS
, offsetof(private_sa_payload_t
, proposals
) },
148 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
149 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
150 ! Next Payload !C! RESERVED ! Payload Length !
151 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
155 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
158 METHOD(payload_t
, verify
, status_t
,
159 private_sa_payload_t
*this)
161 int expected_number
= 0, current_number
;
162 status_t status
= SUCCESS
;
163 enumerator_t
*enumerator
;
164 proposal_substructure_t
*substruct
;
166 if (this->type
== SECURITY_ASSOCIATION
)
171 /* check proposal numbering */
172 enumerator
= this->proposals
->create_enumerator(this->proposals
);
173 while (enumerator
->enumerate(enumerator
, (void**)&substruct
))
175 current_number
= substruct
->get_proposal_number(substruct
);
176 if (current_number
< expected_number
)
178 if (current_number
!= expected_number
+ 1)
180 DBG1(DBG_ENC
, "proposal number is %d, expected %d or %d",
181 current_number
, expected_number
, expected_number
+ 1);
186 else if (current_number
< expected_number
)
188 DBG1(DBG_ENC
, "proposal number smaller than previous");
193 status
= substruct
->payload_interface
.verify(&substruct
->payload_interface
);
194 if (status
!= SUCCESS
)
196 DBG1(DBG_ENC
, "PROPOSAL_SUBSTRUCTURE verification failed");
199 expected_number
= current_number
;
201 enumerator
->destroy(enumerator
);
205 METHOD(payload_t
, get_encoding_rules
, int,
206 private_sa_payload_t
*this, encoding_rule_t
**rules
)
208 if (this->type
== SECURITY_ASSOCIATION_V1
)
210 *rules
= encodings_v1
;
211 return countof(encodings_v1
);
213 *rules
= encodings_v2
;
214 return countof(encodings_v2
);
217 METHOD(payload_t
, get_type
, payload_type_t
,
218 private_sa_payload_t
*this)
223 METHOD(payload_t
, get_next_type
, payload_type_t
,
224 private_sa_payload_t
*this)
226 return this->next_payload
;
229 METHOD(payload_t
, set_next_type
, void,
230 private_sa_payload_t
*this,payload_type_t type
)
232 this->next_payload
= type
;
236 * recompute length of the payload.
238 static void compute_length(private_sa_payload_t
*this)
240 enumerator_t
*enumerator
;
242 size_t length
= SA_PAYLOAD_HEADER_LENGTH
;
244 if (this->type
== SECURITY_ASSOCIATION_V1
)
246 length
= SA_PAYLOAD_V1_HEADER_LENGTH
;
249 enumerator
= this->proposals
->create_enumerator(this->proposals
);
250 while (enumerator
->enumerate(enumerator
, (void **)¤t
))
252 length
+= current
->get_length(current
);
254 enumerator
->destroy(enumerator
);
256 this->payload_length
= length
;
259 METHOD(payload_t
, get_length
, size_t,
260 private_sa_payload_t
*this)
262 return this->payload_length
;
265 METHOD(sa_payload_t
, add_proposal
, void,
266 private_sa_payload_t
*this, proposal_t
*proposal
)
268 proposal_substructure_t
*substruct
, *last
;
269 payload_type_t subtype
= PROPOSAL_SUBSTRUCTURE
;
272 if (this->type
== SECURITY_ASSOCIATION_V1
)
274 subtype
= PROPOSAL_SUBSTRUCTURE_V1
;
276 substruct
= proposal_substructure_create_from_proposal(subtype
, proposal
);
277 count
= this->proposals
->get_count(this->proposals
);
280 this->proposals
->get_last(this->proposals
, (void**)&last
);
281 /* last transform is now not anymore last one */
282 last
->set_is_last_proposal(last
, FALSE
);
284 substruct
->set_is_last_proposal(substruct
, TRUE
);
285 if (proposal
->get_number(proposal
))
286 { /* use the selected proposals number, if any */
287 substruct
->set_proposal_number(substruct
, proposal
->get_number(proposal
));
291 substruct
->set_proposal_number(substruct
, count
+ 1);
293 this->proposals
->insert_last(this->proposals
, substruct
);
294 compute_length(this);
297 METHOD(sa_payload_t
, get_proposals
, linked_list_t
*,
298 private_sa_payload_t
*this)
300 int struct_number
= 0;
301 int ignore_struct_number
= 0;
302 enumerator_t
*enumerator
;
303 proposal_substructure_t
*substruct
;
305 proposal_t
*proposal
;
307 if (this->type
== SECURITY_ASSOCIATION_V1
)
308 { /* IKEv1 proposals start with 0 */
309 struct_number
= ignore_struct_number
= -1;
312 list
= linked_list_create();
313 /* we do not support proposals split up to two proposal substructures, as
314 * AH+ESP bundles are not supported in RFC4301 anymore.
315 * To handle such structures safely, we just skip proposals with multiple
318 enumerator
= this->proposals
->create_enumerator(this->proposals
);
319 while (enumerator
->enumerate(enumerator
, &substruct
))
321 /* check if a proposal has a single protocol */
322 if (substruct
->get_proposal_number(substruct
) == struct_number
)
324 if (ignore_struct_number
< struct_number
)
326 /* remove an already added, if first of series */
327 list
->remove_last(list
, (void**)&proposal
);
328 proposal
->destroy(proposal
);
329 ignore_struct_number
= struct_number
;
334 proposal
= substruct
->get_proposal(substruct
);
337 list
->insert_last(list
, proposal
);
340 enumerator
->destroy(enumerator
);
344 METHOD(sa_payload_t
, create_substructure_enumerator
, enumerator_t
*,
345 private_sa_payload_t
*this)
347 return this->proposals
->create_enumerator(this->proposals
);
350 METHOD2(payload_t
, sa_payload_t
, destroy
, void,
351 private_sa_payload_t
*this)
353 this->proposals
->destroy_offset(this->proposals
,
354 offsetof(payload_t
, destroy
));
359 * Described in header.
361 sa_payload_t
*sa_payload_create(payload_type_t type
)
363 private_sa_payload_t
*this;
367 .payload_interface
= {
369 .get_encoding_rules
= _get_encoding_rules
,
370 .get_length
= _get_length
,
371 .get_next_type
= _get_next_type
,
372 .set_next_type
= _set_next_type
,
373 .get_type
= _get_type
,
376 .add_proposal
= _add_proposal
,
377 .get_proposals
= _get_proposals
,
378 .create_substructure_enumerator
= _create_substructure_enumerator
,
381 .next_payload
= NO_PAYLOAD
,
382 .proposals
= linked_list_create(),
385 .doi
= IKEV1_DOI_IPSEC
,
386 .situation
= SIT_IDENTITY_ONLY
,
389 compute_length(this);
391 return &this->public;
395 * Described in header.
397 sa_payload_t
*sa_payload_create_from_proposal_list(payload_type_t type
,
398 linked_list_t
*proposals
)
401 enumerator_t
*enumerator
;
402 proposal_t
*proposal
;
404 this = sa_payload_create(type
);
405 enumerator
= proposals
->create_enumerator(proposals
);
406 while (enumerator
->enumerate(enumerator
, &proposal
))
408 this->add_proposal(this, proposal
);
410 enumerator
->destroy(enumerator
);
416 * Described in header.
418 sa_payload_t
*sa_payload_create_from_proposal(payload_type_t type
,
419 proposal_t
*proposal
)
423 this = sa_payload_create(type
);
424 this->add_proposal(this, proposal
);