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
, void,
206 private_sa_payload_t
*this, encoding_rule_t
**rules
, size_t *rule_count
)
208 if (this->type
== SECURITY_ASSOCIATION_V1
)
210 *rules
= encodings_v1
;
211 *rule_count
= countof(encodings_v1
);
215 *rules
= encodings_v2
;
216 *rule_count
= countof(encodings_v2
);
220 METHOD(payload_t
, get_type
, payload_type_t
,
221 private_sa_payload_t
*this)
226 METHOD(payload_t
, get_next_type
, payload_type_t
,
227 private_sa_payload_t
*this)
229 return this->next_payload
;
232 METHOD(payload_t
, set_next_type
, void,
233 private_sa_payload_t
*this,payload_type_t type
)
235 this->next_payload
= type
;
239 * recompute length of the payload.
241 static void compute_length(private_sa_payload_t
*this)
243 enumerator_t
*enumerator
;
245 size_t length
= SA_PAYLOAD_HEADER_LENGTH
;
247 if (this->type
== SECURITY_ASSOCIATION_V1
)
249 length
= SA_PAYLOAD_V1_HEADER_LENGTH
;
252 enumerator
= this->proposals
->create_enumerator(this->proposals
);
253 while (enumerator
->enumerate(enumerator
, (void **)¤t
))
255 length
+= current
->get_length(current
);
257 enumerator
->destroy(enumerator
);
259 this->payload_length
= length
;
262 METHOD(payload_t
, get_length
, size_t,
263 private_sa_payload_t
*this)
265 return this->payload_length
;
268 METHOD(sa_payload_t
, add_proposal
, void,
269 private_sa_payload_t
*this, proposal_t
*proposal
)
271 proposal_substructure_t
*substruct
, *last
;
272 payload_type_t subtype
= PROPOSAL_SUBSTRUCTURE
;
275 count
= this->proposals
->get_count(this->proposals
);
276 if (this->type
== SECURITY_ASSOCIATION_V1
)
278 subtype
= PROPOSAL_SUBSTRUCTURE_V1
;
280 substruct
= proposal_substructure_create_from_proposal(subtype
, proposal
);
283 this->proposals
->get_last(this->proposals
, (void**)&last
);
284 /* last transform is now not anymore last one */
285 last
->set_is_last_proposal(last
, FALSE
);
287 substruct
->set_is_last_proposal(substruct
, TRUE
);
288 if (proposal
->get_number(proposal
))
289 { /* use the selected proposals number, if any */
290 substruct
->set_proposal_number(substruct
, proposal
->get_number(proposal
));
294 substruct
->set_proposal_number(substruct
, count
+ 1);
296 this->proposals
->insert_last(this->proposals
, substruct
);
297 compute_length(this);
300 METHOD(sa_payload_t
, get_proposals
, linked_list_t
*,
301 private_sa_payload_t
*this)
303 int struct_number
= 0;
304 int ignore_struct_number
= 0;
305 enumerator_t
*enumerator
;
306 proposal_substructure_t
*substruct
;
308 proposal_t
*proposal
;
310 if (this->type
== SECURITY_ASSOCIATION_V1
)
311 { /* IKEv1 proposals start with 0 */
312 struct_number
= ignore_struct_number
= -1;
315 list
= linked_list_create();
316 /* we do not support proposals split up to two proposal substructures, as
317 * AH+ESP bundles are not supported in RFC4301 anymore.
318 * To handle such structures safely, we just skip proposals with multiple
321 enumerator
= this->proposals
->create_enumerator(this->proposals
);
322 while (enumerator
->enumerate(enumerator
, &substruct
))
324 /* check if a proposal has a single protocol */
325 if (substruct
->get_proposal_number(substruct
) == struct_number
)
327 if (ignore_struct_number
< struct_number
)
329 /* remove an already added, if first of series */
330 list
->remove_last(list
, (void**)&proposal
);
331 proposal
->destroy(proposal
);
332 ignore_struct_number
= struct_number
;
337 proposal
= substruct
->get_proposal(substruct
);
340 list
->insert_last(list
, proposal
);
343 enumerator
->destroy(enumerator
);
347 METHOD(sa_payload_t
, create_substructure_enumerator
, enumerator_t
*,
348 private_sa_payload_t
*this)
350 return this->proposals
->create_enumerator(this->proposals
);
353 METHOD2(payload_t
, sa_payload_t
, destroy
, void,
354 private_sa_payload_t
*this)
356 this->proposals
->destroy_offset(this->proposals
,
357 offsetof(payload_t
, destroy
));
362 * Described in header.
364 sa_payload_t
*sa_payload_create(payload_type_t type
)
366 private_sa_payload_t
*this;
370 .payload_interface
= {
372 .get_encoding_rules
= _get_encoding_rules
,
373 .get_length
= _get_length
,
374 .get_next_type
= _get_next_type
,
375 .set_next_type
= _set_next_type
,
376 .get_type
= _get_type
,
379 .add_proposal
= _add_proposal
,
380 .get_proposals
= _get_proposals
,
381 .create_substructure_enumerator
= _create_substructure_enumerator
,
384 .next_payload
= NO_PAYLOAD
,
385 .proposals
= linked_list_create(),
388 .doi
= IKEV1_DOI_IPSEC
,
389 .situation
= SIT_IDENTITY_ONLY
,
392 compute_length(this);
394 return &this->public;
398 * Described in header.
400 sa_payload_t
*sa_payload_create_from_proposal_list(payload_type_t type
,
401 linked_list_t
*proposals
)
404 enumerator_t
*enumerator
;
405 proposal_t
*proposal
;
407 this = sa_payload_create(type
);
408 enumerator
= proposals
->create_enumerator(proposals
);
409 while (enumerator
->enumerate(enumerator
, &proposal
))
411 this->add_proposal(this, proposal
);
413 enumerator
->destroy(enumerator
);
419 * Described in header.
421 sa_payload_t
*sa_payload_create_from_proposal(payload_type_t type
,
422 proposal_t
*proposal
)
426 this = sa_payload_create(type
);
427 this->add_proposal(this, proposal
);