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 list */
103 { PAYLOAD_LIST
+ PROPOSAL_SUBSTRUCTURE_V1
,
104 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 list */
142 { PAYLOAD_LIST
+ PROPOSAL_SUBSTRUCTURE
,
143 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 DBG1(DBG_ENC
, "proposal number smaller than previous");
183 status
= substruct
->payload_interface
.verify(&substruct
->payload_interface
);
184 if (status
!= SUCCESS
)
186 DBG1(DBG_ENC
, "PROPOSAL_SUBSTRUCTURE verification failed");
189 expected_number
= current_number
;
191 enumerator
->destroy(enumerator
);
195 METHOD(payload_t
, get_encoding_rules
, int,
196 private_sa_payload_t
*this, encoding_rule_t
**rules
)
198 if (this->type
== SECURITY_ASSOCIATION_V1
)
200 *rules
= encodings_v1
;
201 return countof(encodings_v1
);
203 *rules
= encodings_v2
;
204 return countof(encodings_v2
);
207 METHOD(payload_t
, get_header_length
, int,
208 private_sa_payload_t
*this)
210 if (this->type
== SECURITY_ASSOCIATION_V1
)
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
;
243 this->payload_length
= get_header_length(this);
245 enumerator
= this->proposals
->create_enumerator(this->proposals
);
246 while (enumerator
->enumerate(enumerator
, (void **)¤t
))
248 this->payload_length
+= current
->get_length(current
);
250 enumerator
->destroy(enumerator
);
253 METHOD(payload_t
, get_length
, size_t,
254 private_sa_payload_t
*this)
256 return this->payload_length
;
260 * Create a transform substructure from a proposal, add to payload
262 static void add_proposal_v2(private_sa_payload_t
*this, proposal_t
*proposal
)
264 proposal_substructure_t
*substruct
, *last
;
267 substruct
= proposal_substructure_create_from_proposal_v2(proposal
);
268 count
= this->proposals
->get_count(this->proposals
);
271 this->proposals
->get_last(this->proposals
, (void**)&last
);
272 /* last transform is now not anymore last one */
273 last
->set_is_last_proposal(last
, FALSE
);
275 substruct
->set_is_last_proposal(substruct
, TRUE
);
276 if (proposal
->get_number(proposal
))
277 { /* use the selected proposals number, if any */
278 substruct
->set_proposal_number(substruct
, proposal
->get_number(proposal
));
282 substruct
->set_proposal_number(substruct
, count
+ 1);
284 this->proposals
->insert_last(this->proposals
, substruct
);
285 compute_length(this);
288 METHOD(sa_payload_t
, get_proposals
, linked_list_t
*,
289 private_sa_payload_t
*this)
291 int struct_number
= 0;
292 int ignore_struct_number
= 0;
293 enumerator_t
*enumerator
;
294 proposal_substructure_t
*substruct
;
295 proposal_t
*proposal
;
298 if (this->type
== SECURITY_ASSOCIATION_V1
)
299 { /* IKEv1 proposals start with 0 */
300 struct_number
= ignore_struct_number
= -1;
303 list
= linked_list_create();
304 /* we do not support proposals split up to two proposal substructures, as
305 * AH+ESP bundles are not supported in RFC4301 anymore.
306 * To handle such structures safely, we just skip proposals with multiple
309 enumerator
= this->proposals
->create_enumerator(this->proposals
);
310 while (enumerator
->enumerate(enumerator
, &substruct
))
312 /* check if a proposal has a single protocol */
313 if (substruct
->get_proposal_number(substruct
) == struct_number
)
315 if (ignore_struct_number
< struct_number
)
317 /* remove an already added, if first of series */
318 if (list
->remove_last(list
, (void**)&proposal
) == SUCCESS
)
320 proposal
->destroy(proposal
);
322 ignore_struct_number
= struct_number
;
327 substruct
->get_proposals(substruct
, list
);
329 enumerator
->destroy(enumerator
);
333 METHOD(sa_payload_t
, create_substructure_enumerator
, enumerator_t
*,
334 private_sa_payload_t
*this)
336 return this->proposals
->create_enumerator(this->proposals
);
339 METHOD(sa_payload_t
, get_lifetime
, u_int32_t
,
340 private_sa_payload_t
*this)
342 proposal_substructure_t
*substruct
;
343 enumerator_t
*enumerator
;
344 u_int32_t lifetime
= 0;
346 enumerator
= this->proposals
->create_enumerator(this->proposals
);
347 if (enumerator
->enumerate(enumerator
, &substruct
))
349 lifetime
= substruct
->get_lifetime(substruct
);
351 enumerator
->destroy(enumerator
);
356 METHOD(sa_payload_t
, get_lifebytes
, u_int64_t
,
357 private_sa_payload_t
*this)
359 proposal_substructure_t
*substruct
;
360 enumerator_t
*enumerator
;
361 u_int64_t lifebytes
= 0;
363 enumerator
= this->proposals
->create_enumerator(this->proposals
);
364 if (enumerator
->enumerate(enumerator
, &substruct
))
366 lifebytes
= substruct
->get_lifebytes(substruct
);
368 enumerator
->destroy(enumerator
);
373 METHOD(sa_payload_t
, get_auth_method
, auth_method_t
,
374 private_sa_payload_t
*this)
376 proposal_substructure_t
*substruct
;
377 enumerator_t
*enumerator
;
378 auth_method_t method
= AUTH_NONE
;
380 enumerator
= this->proposals
->create_enumerator(this->proposals
);
381 if (enumerator
->enumerate(enumerator
, &substruct
))
383 method
= substruct
->get_auth_method(substruct
);
385 enumerator
->destroy(enumerator
);
390 METHOD(sa_payload_t
, get_encap_mode
, ipsec_mode_t
,
391 private_sa_payload_t
*this, bool *udp
)
393 proposal_substructure_t
*substruct
;
394 enumerator_t
*enumerator
;
395 ipsec_mode_t mode
= MODE_NONE
;
397 enumerator
= this->proposals
->create_enumerator(this->proposals
);
398 if (enumerator
->enumerate(enumerator
, &substruct
))
400 mode
= substruct
->get_encap_mode(substruct
, udp
);
402 enumerator
->destroy(enumerator
);
407 METHOD2(payload_t
, sa_payload_t
, destroy
, void,
408 private_sa_payload_t
*this)
410 this->proposals
->destroy_offset(this->proposals
,
411 offsetof(payload_t
, destroy
));
416 * Described in header.
418 sa_payload_t
*sa_payload_create(payload_type_t type
)
420 private_sa_payload_t
*this;
424 .payload_interface
= {
426 .get_encoding_rules
= _get_encoding_rules
,
427 .get_header_length
= _get_header_length
,
428 .get_length
= _get_length
,
429 .get_next_type
= _get_next_type
,
430 .set_next_type
= _set_next_type
,
431 .get_type
= _get_type
,
434 .get_proposals
= _get_proposals
,
435 .create_substructure_enumerator
= _create_substructure_enumerator
,
436 .get_lifetime
= _get_lifetime
,
437 .get_lifebytes
= _get_lifebytes
,
438 .get_auth_method
= _get_auth_method
,
439 .get_encap_mode
= _get_encap_mode
,
442 .next_payload
= NO_PAYLOAD
,
443 .proposals
= linked_list_create(),
446 .doi
= IKEV1_DOI_IPSEC
,
447 .situation
= SIT_IDENTITY_ONLY
,
450 compute_length(this);
452 return &this->public;
456 * Described in header.
458 sa_payload_t
*sa_payload_create_from_proposals_v2(linked_list_t
*proposals
)
460 private_sa_payload_t
*this;
461 enumerator_t
*enumerator
;
462 proposal_t
*proposal
;
464 this = (private_sa_payload_t
*)sa_payload_create(SECURITY_ASSOCIATION
);
465 enumerator
= proposals
->create_enumerator(proposals
);
466 while (enumerator
->enumerate(enumerator
, &proposal
))
468 add_proposal_v2(this, proposal
);
470 enumerator
->destroy(enumerator
);
472 return &this->public;
476 * Described in header.
478 sa_payload_t
*sa_payload_create_from_proposal_v2(proposal_t
*proposal
)
480 private_sa_payload_t
*this;
482 this = (private_sa_payload_t
*)sa_payload_create(SECURITY_ASSOCIATION
);
483 add_proposal_v2(this, proposal
);
485 return &this->public;
490 * Described in header.
492 sa_payload_t
*sa_payload_create_from_proposals_v1(linked_list_t
*proposals
,
493 u_int32_t lifetime
, u_int64_t lifebytes
,
494 auth_method_t auth
, ipsec_mode_t mode
, bool udp
)
496 proposal_substructure_t
*substruct
;
497 private_sa_payload_t
*this;
499 this = (private_sa_payload_t
*)sa_payload_create(SECURITY_ASSOCIATION_V1
);
501 /* IKEv1 encodes multiple proposals in a single substructure
502 * TODO-IKEv1: Encode ESP+AH proposals in two different substructs */
503 substruct
= proposal_substructure_create_from_proposals_v1(proposals
,
504 lifetime
, lifebytes
, auth
, mode
, udp
);
505 substruct
->set_is_last_proposal(substruct
, TRUE
);
506 this->proposals
->insert_last(this->proposals
, substruct
);
507 compute_length(this);
509 return &this->public;
513 * Described in header.
515 sa_payload_t
*sa_payload_create_from_proposal_v1(proposal_t
*proposal
,
516 u_int32_t lifetime
, u_int64_t lifebytes
,
517 auth_method_t auth
, ipsec_mode_t mode
, bool udp
)
519 proposal_substructure_t
*substruct
;
520 private_sa_payload_t
*this;
522 this = (private_sa_payload_t
*)sa_payload_create(SECURITY_ASSOCIATION_V1
);
524 substruct
= proposal_substructure_create_from_proposal_v1(proposal
,
525 lifetime
, lifebytes
, auth
, mode
, udp
);
526 substruct
->set_is_last_proposal(substruct
, TRUE
);
527 this->proposals
->insert_last(this->proposals
, substruct
);
528 compute_length(this);
530 return &this->public;