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(private_sa_payload_t
*this, proposal_t
*proposal
)
264 proposal_substructure_t
*substruct
, *last
;
265 payload_type_t subtype
= PROPOSAL_SUBSTRUCTURE
;
268 if (this->type
== SECURITY_ASSOCIATION_V1
)
270 subtype
= PROPOSAL_SUBSTRUCTURE_V1
;
272 substruct
= proposal_substructure_create_from_proposal(subtype
, proposal
);
273 count
= this->proposals
->get_count(this->proposals
);
276 this->proposals
->get_last(this->proposals
, (void**)&last
);
277 /* last transform is now not anymore last one */
278 last
->set_is_last_proposal(last
, FALSE
);
280 substruct
->set_is_last_proposal(substruct
, TRUE
);
281 if (proposal
->get_number(proposal
))
282 { /* use the selected proposals number, if any */
283 substruct
->set_proposal_number(substruct
, proposal
->get_number(proposal
));
287 substruct
->set_proposal_number(substruct
, count
+ 1);
289 this->proposals
->insert_last(this->proposals
, substruct
);
290 compute_length(this);
293 METHOD(sa_payload_t
, get_proposals
, linked_list_t
*,
294 private_sa_payload_t
*this)
296 int struct_number
= 0;
297 int ignore_struct_number
= 0;
298 enumerator_t
*enumerator
;
299 proposal_substructure_t
*substruct
;
300 proposal_t
*proposal
;
303 if (this->type
== SECURITY_ASSOCIATION_V1
)
304 { /* IKEv1 proposals start with 0 */
305 struct_number
= ignore_struct_number
= -1;
308 list
= linked_list_create();
309 /* we do not support proposals split up to two proposal substructures, as
310 * AH+ESP bundles are not supported in RFC4301 anymore.
311 * To handle such structures safely, we just skip proposals with multiple
314 enumerator
= this->proposals
->create_enumerator(this->proposals
);
315 while (enumerator
->enumerate(enumerator
, &substruct
))
317 /* check if a proposal has a single protocol */
318 if (substruct
->get_proposal_number(substruct
) == struct_number
)
320 if (ignore_struct_number
< struct_number
)
322 /* remove an already added, if first of series */
323 if (list
->remove_last(list
, (void**)&proposal
) == SUCCESS
)
325 proposal
->destroy(proposal
);
327 ignore_struct_number
= struct_number
;
332 substruct
->get_proposals(substruct
, list
);
334 enumerator
->destroy(enumerator
);
338 METHOD(sa_payload_t
, create_substructure_enumerator
, enumerator_t
*,
339 private_sa_payload_t
*this)
341 return this->proposals
->create_enumerator(this->proposals
);
344 METHOD(sa_payload_t
, get_lifetime
, u_int32_t
,
345 private_sa_payload_t
*this)
350 METHOD(sa_payload_t
, get_lifebytes
, u_int64_t
,
351 private_sa_payload_t
*this)
356 METHOD(sa_payload_t
, get_auth_method
, auth_method_t
,
357 private_sa_payload_t
*this)
362 METHOD(sa_payload_t
, get_encap_mode
, ipsec_mode_t
,
363 private_sa_payload_t
*this, bool *udp
)
369 METHOD2(payload_t
, sa_payload_t
, destroy
, void,
370 private_sa_payload_t
*this)
372 this->proposals
->destroy_offset(this->proposals
,
373 offsetof(payload_t
, destroy
));
378 * Described in header.
380 sa_payload_t
*sa_payload_create(payload_type_t type
)
382 private_sa_payload_t
*this;
386 .payload_interface
= {
388 .get_encoding_rules
= _get_encoding_rules
,
389 .get_header_length
= _get_header_length
,
390 .get_length
= _get_length
,
391 .get_next_type
= _get_next_type
,
392 .set_next_type
= _set_next_type
,
393 .get_type
= _get_type
,
396 .get_proposals
= _get_proposals
,
397 .create_substructure_enumerator
= _create_substructure_enumerator
,
398 .get_lifetime
= _get_lifetime
,
399 .get_lifebytes
= _get_lifebytes
,
400 .get_auth_method
= _get_auth_method
,
401 .get_encap_mode
= _get_encap_mode
,
404 .next_payload
= NO_PAYLOAD
,
405 .proposals
= linked_list_create(),
408 .doi
= IKEV1_DOI_IPSEC
,
409 .situation
= SIT_IDENTITY_ONLY
,
412 compute_length(this);
414 return &this->public;
418 * Described in header.
420 sa_payload_t
*sa_payload_create_from_proposal_list(payload_type_t type
,
421 linked_list_t
*proposals
)
423 private_sa_payload_t
*this;
424 enumerator_t
*enumerator
;
425 proposal_t
*proposal
;
427 this = (private_sa_payload_t
*)sa_payload_create(type
);
428 if (type
== SECURITY_ASSOCIATION
)
430 enumerator
= proposals
->create_enumerator(proposals
);
431 while (enumerator
->enumerate(enumerator
, &proposal
))
433 add_proposal(this, proposal
);
435 enumerator
->destroy(enumerator
);
438 { /* IKEv1 encodes multiple proposals in a single substructure
439 * TODO-IKEv1: Encode ESP+AH proposals in two different substructs */
440 proposal_substructure_t
*substruct
;
442 substruct
= proposal_substructure_create_from_proposals(proposals
);
443 substruct
->set_is_last_proposal(substruct
, TRUE
);
444 this->proposals
->insert_last(this->proposals
, substruct
);
445 compute_length(this);
447 return &this->public;
451 * Described in header.
453 sa_payload_t
*sa_payload_create_from_proposal(payload_type_t type
,
454 proposal_t
*proposal
)
456 private_sa_payload_t
*this;
458 this = (private_sa_payload_t
*)sa_payload_create(type
);
459 add_proposal(this, proposal
);
461 return &this->public;
465 * Described in header.
467 sa_payload_t
*sa_payload_create_from_proposals_v2(linked_list_t
*proposals
)
469 private_sa_payload_t
*this;
470 enumerator_t
*enumerator
;
471 proposal_t
*proposal
;
473 this = (private_sa_payload_t
*)sa_payload_create(SECURITY_ASSOCIATION
);
474 enumerator
= proposals
->create_enumerator(proposals
);
475 while (enumerator
->enumerate(enumerator
, &proposal
))
477 add_proposal(this, proposal
);
479 enumerator
->destroy(enumerator
);
481 return &this->public;
485 * Described in header.
487 sa_payload_t
*sa_payload_create_from_proposal_v2(proposal_t
*proposal
)
489 private_sa_payload_t
*this;
491 this = (private_sa_payload_t
*)sa_payload_create(SECURITY_ASSOCIATION
);
492 add_proposal(this, proposal
);
494 return &this->public;
499 * Described in header.
501 sa_payload_t
*sa_payload_create_from_proposals_v1(linked_list_t
*proposals
,
502 u_int32_t lifetime
, u_int64_t lifebytes
,
503 auth_method_t auth
, ipsec_mode_t mode
, bool udp
)
505 proposal_substructure_t
*substruct
;
506 private_sa_payload_t
*this;
508 this = (private_sa_payload_t
*)sa_payload_create(SECURITY_ASSOCIATION
);
510 /* IKEv1 encodes multiple proposals in a single substructure
511 * TODO-IKEv1: Encode ESP+AH proposals in two different substructs */
512 substruct
= proposal_substructure_create_from_proposals(proposals
);
513 substruct
->set_is_last_proposal(substruct
, TRUE
);
514 this->proposals
->insert_last(this->proposals
, substruct
);
515 compute_length(this);
517 return &this->public;
521 * Described in header.
523 sa_payload_t
*sa_payload_create_from_proposal_v1(proposal_t
*proposal
,
524 u_int32_t lifetime
, u_int64_t lifebytes
,
525 auth_method_t auth
, ipsec_mode_t mode
, bool udp
)
527 proposal_substructure_t
*substruct
;
528 private_sa_payload_t
*this;
530 this = (private_sa_payload_t
*)sa_payload_create(SECURITY_ASSOCIATION_V1
);
532 substruct
= proposal_substructure_create_from_proposal(
533 PROPOSAL_SUBSTRUCTURE_V1
, proposal
);
534 substruct
->set_is_last_proposal(substruct
, TRUE
);
535 this->proposals
->insert_last(this->proposals
, substruct
);
536 compute_length(this);
538 return &this->public;