2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2005-2010 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 #include "sa_payload.h"
22 #include <encoding/payloads/encodings.h>
23 #include <collections/linked_list.h>
27 #define SIT_IDENTITY_ONLY 1
29 typedef struct private_sa_payload_t private_sa_payload_t
;
32 * Private data of an sa_payload_t object.
34 struct private_sa_payload_t
{
37 * Public sa_payload_t interface.
44 u_int8_t next_payload
;
57 * Length of this payload.
59 u_int16_t payload_length
;
62 * Proposals in this payload are stored in a linked_list_t.
64 linked_list_t
*proposals
;
67 * Type of this payload, V1 or V2
83 * Encoding rules for IKEv1 SA payload
85 static encoding_rule_t encodings_v1
[] = {
86 /* 1 Byte next payload type, stored in the field next_payload */
87 { U_INT_8
, offsetof(private_sa_payload_t
, next_payload
) },
89 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[0]) },
90 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[1]) },
91 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[2]) },
92 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[3]) },
93 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[4]) },
94 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[5]) },
95 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[6]) },
96 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[7]) },
97 /* Length of the whole SA payload*/
98 { PAYLOAD_LENGTH
, offsetof(private_sa_payload_t
, payload_length
) },
100 { U_INT_32
, offsetof(private_sa_payload_t
, doi
) },
102 { U_INT_32
, offsetof(private_sa_payload_t
, situation
) },
103 /* Proposals are stored in a proposal substructure list */
104 { PAYLOAD_LIST
+ PROPOSAL_SUBSTRUCTURE_V1
,
105 offsetof(private_sa_payload_t
, proposals
) },
110 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
111 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
112 ! Next Payload ! RESERVED ! Payload Length !
113 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
117 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
121 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
125 * Encoding rules for IKEv2 SA payload
127 static encoding_rule_t encodings_v2
[] = {
128 /* 1 Byte next payload type, stored in the field next_payload */
129 { U_INT_8
, offsetof(private_sa_payload_t
, next_payload
) },
130 /* the critical bit */
131 { FLAG
, offsetof(private_sa_payload_t
, critical
) },
132 /* 7 Bit reserved bits */
133 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[0]) },
134 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[1]) },
135 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[2]) },
136 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[3]) },
137 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[4]) },
138 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[5]) },
139 { RESERVED_BIT
, offsetof(private_sa_payload_t
, reserved
[6]) },
140 /* Length of the whole SA payload*/
141 { PAYLOAD_LENGTH
, offsetof(private_sa_payload_t
, payload_length
) },
142 /* Proposals are stored in a proposal substructure list */
143 { PAYLOAD_LIST
+ PROPOSAL_SUBSTRUCTURE
,
144 offsetof(private_sa_payload_t
, proposals
) },
149 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
150 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
151 ! Next Payload !C! RESERVED ! Payload Length !
152 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
156 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
159 METHOD(payload_t
, verify
, status_t
,
160 private_sa_payload_t
*this)
162 int expected_number
= 0, current_number
;
163 status_t status
= SUCCESS
;
164 enumerator_t
*enumerator
;
165 proposal_substructure_t
*substruct
;
167 if (this->type
== SECURITY_ASSOCIATION
)
172 /* check proposal numbering */
173 enumerator
= this->proposals
->create_enumerator(this->proposals
);
174 while (enumerator
->enumerate(enumerator
, (void**)&substruct
))
176 current_number
= substruct
->get_proposal_number(substruct
);
177 if (current_number
< expected_number
)
179 DBG1(DBG_ENC
, "proposal number smaller than previous");
184 status
= substruct
->payload_interface
.verify(&substruct
->payload_interface
);
185 if (status
!= SUCCESS
)
187 DBG1(DBG_ENC
, "PROPOSAL_SUBSTRUCTURE verification failed");
190 expected_number
= current_number
;
192 enumerator
->destroy(enumerator
);
196 METHOD(payload_t
, get_encoding_rules
, int,
197 private_sa_payload_t
*this, encoding_rule_t
**rules
)
199 if (this->type
== SECURITY_ASSOCIATION_V1
)
201 *rules
= encodings_v1
;
202 return countof(encodings_v1
);
204 *rules
= encodings_v2
;
205 return countof(encodings_v2
);
208 METHOD(payload_t
, get_header_length
, int,
209 private_sa_payload_t
*this)
211 if (this->type
== SECURITY_ASSOCIATION_V1
)
218 METHOD(payload_t
, get_type
, payload_type_t
,
219 private_sa_payload_t
*this)
224 METHOD(payload_t
, get_next_type
, payload_type_t
,
225 private_sa_payload_t
*this)
227 return this->next_payload
;
230 METHOD(payload_t
, set_next_type
, void,
231 private_sa_payload_t
*this,payload_type_t type
)
233 this->next_payload
= type
;
237 * recompute length of the payload.
239 static void compute_length(private_sa_payload_t
*this)
241 enumerator_t
*enumerator
;
244 this->payload_length
= get_header_length(this);
246 enumerator
= this->proposals
->create_enumerator(this->proposals
);
247 while (enumerator
->enumerate(enumerator
, (void **)¤t
))
249 this->payload_length
+= current
->get_length(current
);
251 enumerator
->destroy(enumerator
);
254 METHOD(payload_t
, get_length
, size_t,
255 private_sa_payload_t
*this)
257 return this->payload_length
;
261 * Create a transform substructure from a proposal, add to payload
263 static void add_proposal_v2(private_sa_payload_t
*this, proposal_t
*proposal
)
265 proposal_substructure_t
*substruct
, *last
;
268 substruct
= proposal_substructure_create_from_proposal_v2(proposal
);
269 count
= this->proposals
->get_count(this->proposals
);
272 this->proposals
->get_last(this->proposals
, (void**)&last
);
273 /* last transform is now not anymore last one */
274 last
->set_is_last_proposal(last
, FALSE
);
276 substruct
->set_is_last_proposal(substruct
, TRUE
);
277 if (proposal
->get_number(proposal
))
278 { /* use the selected proposals number, if any */
279 substruct
->set_proposal_number(substruct
, proposal
->get_number(proposal
));
283 substruct
->set_proposal_number(substruct
, count
+ 1);
285 this->proposals
->insert_last(this->proposals
, substruct
);
286 compute_length(this);
289 METHOD(sa_payload_t
, get_proposals
, linked_list_t
*,
290 private_sa_payload_t
*this)
292 int struct_number
= 0;
293 int ignore_struct_number
= 0;
294 enumerator_t
*enumerator
;
295 proposal_substructure_t
*substruct
;
296 linked_list_t
*substructs
, *list
;
298 if (this->type
== SECURITY_ASSOCIATION_V1
)
299 { /* IKEv1 proposals start with 0 */
300 struct_number
= ignore_struct_number
= -1;
303 /* we do not support proposals split up to two proposal substructures, as
304 * AH+ESP bundles are not supported in RFC4301 anymore.
305 * To handle such structures safely, we just skip proposals with multiple
308 substructs
= linked_list_create();
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
)
316 { /* remove an already added, if first of series */
317 substructs
->remove_last(substructs
, (void**)&substruct
);
318 ignore_struct_number
= struct_number
;
323 substructs
->insert_last(substructs
, substruct
);
325 enumerator
->destroy(enumerator
);
327 /* generate proposals from substructs */
328 list
= linked_list_create();
329 enumerator
= substructs
->create_enumerator(substructs
);
330 while (enumerator
->enumerate(enumerator
, &substruct
))
332 substruct
->get_proposals(substruct
, list
);
334 enumerator
->destroy(enumerator
);
335 substructs
->destroy(substructs
);
339 METHOD(sa_payload_t
, get_ipcomp_proposals
, linked_list_t
*,
340 private_sa_payload_t
*this, u_int16_t
*cpi
)
342 int current_proposal
= -1, unsupported_proposal
= -1;
343 enumerator_t
*enumerator
;
344 proposal_substructure_t
*substruct
, *esp
= NULL
, *ipcomp
= NULL
;
347 /* we currently only support the combination ESP+IPComp, find the first */
348 enumerator
= this->proposals
->create_enumerator(this->proposals
);
349 while (enumerator
->enumerate(enumerator
, &substruct
))
351 u_int8_t proposal_number
= substruct
->get_proposal_number(substruct
);
352 u_int8_t protocol_id
= substruct
->get_protocol_id(substruct
);
354 if (proposal_number
== unsupported_proposal
)
358 if (protocol_id
!= PROTO_ESP
&& protocol_id
!= PROTO_IPCOMP
)
359 { /* unsupported combination */
361 unsupported_proposal
= current_proposal
;
364 if (proposal_number
!= current_proposal
)
365 { /* start of a new proposal */
367 { /* previous proposal is valid */
371 current_proposal
= proposal_number
;
383 enumerator
->destroy(enumerator
);
385 list
= linked_list_create();
386 if (esp
&& ipcomp
&& ipcomp
->get_cpi(ipcomp
, cpi
))
388 esp
->get_proposals(esp
, list
);
393 METHOD(sa_payload_t
, create_substructure_enumerator
, enumerator_t
*,
394 private_sa_payload_t
*this)
396 return this->proposals
->create_enumerator(this->proposals
);
399 METHOD(sa_payload_t
, get_lifetime
, u_int32_t
,
400 private_sa_payload_t
*this)
402 proposal_substructure_t
*substruct
;
403 enumerator_t
*enumerator
;
404 u_int32_t lifetime
= 0;
406 enumerator
= this->proposals
->create_enumerator(this->proposals
);
407 if (enumerator
->enumerate(enumerator
, &substruct
))
409 lifetime
= substruct
->get_lifetime(substruct
);
411 enumerator
->destroy(enumerator
);
416 METHOD(sa_payload_t
, get_lifebytes
, u_int64_t
,
417 private_sa_payload_t
*this)
419 proposal_substructure_t
*substruct
;
420 enumerator_t
*enumerator
;
421 u_int64_t lifebytes
= 0;
423 enumerator
= this->proposals
->create_enumerator(this->proposals
);
424 if (enumerator
->enumerate(enumerator
, &substruct
))
426 lifebytes
= substruct
->get_lifebytes(substruct
);
428 enumerator
->destroy(enumerator
);
433 METHOD(sa_payload_t
, get_auth_method
, auth_method_t
,
434 private_sa_payload_t
*this)
436 proposal_substructure_t
*substruct
;
437 enumerator_t
*enumerator
;
438 auth_method_t method
= AUTH_NONE
;
440 enumerator
= this->proposals
->create_enumerator(this->proposals
);
441 if (enumerator
->enumerate(enumerator
, &substruct
))
443 method
= substruct
->get_auth_method(substruct
);
445 enumerator
->destroy(enumerator
);
450 METHOD(sa_payload_t
, get_encap_mode
, ipsec_mode_t
,
451 private_sa_payload_t
*this, bool *udp
)
453 proposal_substructure_t
*substruct
;
454 enumerator_t
*enumerator
;
455 ipsec_mode_t mode
= MODE_NONE
;
457 enumerator
= this->proposals
->create_enumerator(this->proposals
);
458 if (enumerator
->enumerate(enumerator
, &substruct
))
460 mode
= substruct
->get_encap_mode(substruct
, udp
);
462 enumerator
->destroy(enumerator
);
467 METHOD2(payload_t
, sa_payload_t
, destroy
, void,
468 private_sa_payload_t
*this)
470 this->proposals
->destroy_offset(this->proposals
,
471 offsetof(payload_t
, destroy
));
476 * Described in header.
478 sa_payload_t
*sa_payload_create(payload_type_t type
)
480 private_sa_payload_t
*this;
484 .payload_interface
= {
486 .get_encoding_rules
= _get_encoding_rules
,
487 .get_header_length
= _get_header_length
,
488 .get_length
= _get_length
,
489 .get_next_type
= _get_next_type
,
490 .set_next_type
= _set_next_type
,
491 .get_type
= _get_type
,
494 .get_proposals
= _get_proposals
,
495 .get_ipcomp_proposals
= _get_ipcomp_proposals
,
496 .create_substructure_enumerator
= _create_substructure_enumerator
,
497 .get_lifetime
= _get_lifetime
,
498 .get_lifebytes
= _get_lifebytes
,
499 .get_auth_method
= _get_auth_method
,
500 .get_encap_mode
= _get_encap_mode
,
503 .next_payload
= NO_PAYLOAD
,
504 .proposals
= linked_list_create(),
507 .doi
= IKEV1_DOI_IPSEC
,
508 .situation
= SIT_IDENTITY_ONLY
,
511 compute_length(this);
513 return &this->public;
517 * Described in header.
519 sa_payload_t
*sa_payload_create_from_proposals_v2(linked_list_t
*proposals
)
521 private_sa_payload_t
*this;
522 enumerator_t
*enumerator
;
523 proposal_t
*proposal
;
525 this = (private_sa_payload_t
*)sa_payload_create(SECURITY_ASSOCIATION
);
526 enumerator
= proposals
->create_enumerator(proposals
);
527 while (enumerator
->enumerate(enumerator
, &proposal
))
529 add_proposal_v2(this, proposal
);
531 enumerator
->destroy(enumerator
);
533 return &this->public;
537 * Described in header.
539 sa_payload_t
*sa_payload_create_from_proposal_v2(proposal_t
*proposal
)
541 private_sa_payload_t
*this;
543 this = (private_sa_payload_t
*)sa_payload_create(SECURITY_ASSOCIATION
);
544 add_proposal_v2(this, proposal
);
546 return &this->public;
551 * Described in header.
553 sa_payload_t
*sa_payload_create_from_proposals_v1(linked_list_t
*proposals
,
554 u_int32_t lifetime
, u_int64_t lifebytes
,
555 auth_method_t auth
, ipsec_mode_t mode
,
556 encap_t udp
, u_int16_t cpi
)
558 proposal_substructure_t
*substruct
;
559 private_sa_payload_t
*this;
561 this = (private_sa_payload_t
*)sa_payload_create(SECURITY_ASSOCIATION_V1
);
563 if (!proposals
|| !proposals
->get_count(proposals
))
565 return &this->public;
568 /* IKEv1 encodes multiple proposals in a single substructure
569 * TODO-IKEv1: Encode ESP+AH proposals in two substructs with same num */
570 substruct
= proposal_substructure_create_from_proposals_v1(proposals
,
571 lifetime
, lifebytes
, auth
, mode
, udp
);
572 this->proposals
->insert_last(this->proposals
, substruct
);
573 substruct
->set_is_last_proposal(substruct
, FALSE
);
576 u_int8_t proposal_number
= substruct
->get_proposal_number(substruct
);
578 substruct
= proposal_substructure_create_for_ipcomp_v1(lifetime
,
579 lifebytes
, cpi
, mode
, udp
, proposal_number
);
580 this->proposals
->insert_last(this->proposals
, substruct
);
581 substruct
->set_is_last_proposal(substruct
, FALSE
);
582 /* add the proposals again without IPComp */
583 substruct
= proposal_substructure_create_from_proposals_v1(proposals
,
584 lifetime
, lifebytes
, auth
, mode
, udp
);
585 substruct
->set_proposal_number(substruct
, proposal_number
+ 1);
586 this->proposals
->insert_last(this->proposals
, substruct
);
588 substruct
->set_is_last_proposal(substruct
, TRUE
);
589 compute_length(this);
591 return &this->public;
595 * Described in header.
597 sa_payload_t
*sa_payload_create_from_proposal_v1(proposal_t
*proposal
,
598 u_int32_t lifetime
, u_int64_t lifebytes
,
599 auth_method_t auth
, ipsec_mode_t mode
,
600 encap_t udp
, u_int16_t cpi
)
602 private_sa_payload_t
*this;
603 linked_list_t
*proposals
;
605 proposals
= linked_list_create();
606 proposals
->insert_last(proposals
, proposal
);
607 this = (private_sa_payload_t
*)sa_payload_create_from_proposals_v1(proposals
,
608 lifetime
, lifebytes
, auth
, mode
, udp
, cpi
);
609 proposals
->destroy(proposals
);
610 return &this->public;