4 * @brief Implementation of sa_payload_t.
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 #include "sa_payload.h"
28 #include <encoding/payloads/encodings.h>
29 #include <utils/allocator.h>
30 #include <utils/linked_list.h>
33 typedef struct private_sa_payload_t private_sa_payload_t
;
36 * Private data of an sa_payload_t object.
39 struct private_sa_payload_t
{
41 * Public sa_payload_t interface.
48 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 * @brief Computes the length of this payload.
68 * @param this calling private_sa_payload_t object
70 void (*compute_length
) (private_sa_payload_t
*this);
74 * Encoding rules to parse or generate a IKEv2-SA Payload
76 * The defined offsets are the positions in a object of type
77 * private_sa_payload_t.
80 encoding_rule_t sa_payload_encodings
[] = {
81 /* 1 Byte next payload type, stored in the field next_payload */
82 { U_INT_8
, offsetof(private_sa_payload_t
, next_payload
) },
83 /* the critical bit */
84 { FLAG
, offsetof(private_sa_payload_t
, critical
) },
85 /* 7 Bit reserved bits, nowhere stored */
93 /* Length of the whole SA payload*/
94 { PAYLOAD_LENGTH
, offsetof(private_sa_payload_t
, payload_length
) },
95 /* Proposals are stored in a proposal substructure,
96 offset points to a linked_list_t pointer */
97 { PROPOSALS
, offsetof(private_sa_payload_t
, proposals
) }
102 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
103 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104 ! Next Payload !C! RESERVED ! Payload Length !
105 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
109 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
113 * Implementation of payload_t.verify.
115 static status_t
verify(private_sa_payload_t
*this)
117 int proposal_number
= 1;
118 status_t status
= SUCCESS
;
119 iterator_t
*iterator
;
124 /* critical bit set! */
128 /* check proposal numbering */
129 iterator
= this->proposals
->create_iterator(this->proposals
,TRUE
);
131 while(iterator
->has_next(iterator
))
133 proposal_substructure_t
*current_proposal
;
134 iterator
->current(iterator
,(void **)¤t_proposal
);
135 if (current_proposal
->get_proposal_number(current_proposal
) > proposal_number
)
139 /* first number must be 1 */
144 if (current_proposal
->get_proposal_number(current_proposal
) != (proposal_number
+ 1))
146 /* must be only one more then previous proposal */
151 else if (current_proposal
->get_proposal_number(current_proposal
) < proposal_number
)
153 iterator
->destroy(iterator
);
154 /* must not be smaller then proceeding one */
159 status
= current_proposal
->payload_interface
.verify(&(current_proposal
->payload_interface
));
160 if (status
!= SUCCESS
)
167 iterator
->destroy(iterator
);
173 * Implementation of payload_t.destroy and sa_payload_t.destroy.
175 static status_t
destroy(private_sa_payload_t
*this)
177 /* all proposals are getting destroyed */
178 while (this->proposals
->get_count(this->proposals
) > 0)
180 proposal_substructure_t
*current_proposal
;
181 this->proposals
->remove_last(this->proposals
,(void **)¤t_proposal
);
182 current_proposal
->destroy(current_proposal
);
184 this->proposals
->destroy(this->proposals
);
186 allocator_free(this);
192 * Implementation of payload_t.get_encoding_rules.
194 static void get_encoding_rules(private_sa_payload_t
*this, encoding_rule_t
**rules
, size_t *rule_count
)
196 *rules
= sa_payload_encodings
;
197 *rule_count
= sizeof(sa_payload_encodings
) / sizeof(encoding_rule_t
);
201 * Implementation of payload_t.get_type.
203 static payload_type_t
get_type(private_sa_payload_t
*this)
205 return SECURITY_ASSOCIATION
;
209 * Implementation of payload_t.get_next_type.
211 static payload_type_t
get_next_type(private_sa_payload_t
*this)
213 return (this->next_payload
);
217 * Implementation of payload_t.set_next_type.
219 static void set_next_type(private_sa_payload_t
*this,payload_type_t type
)
221 this->next_payload
= type
;
225 * Implementation of payload_t.get_length.
227 static size_t get_length(private_sa_payload_t
*this)
229 this->compute_length(this);
230 return this->payload_length
;
234 * Implementation of sa_payload_t.create_proposal_substructure_iterator.
236 static iterator_t
*create_proposal_substructure_iterator (private_sa_payload_t
*this,bool forward
)
238 return this->proposals
->create_iterator(this->proposals
,forward
);
242 * Implementation of sa_payload_t.add_proposal_substructure.
244 static void add_proposal_substructure (private_sa_payload_t
*this,proposal_substructure_t
*proposal
)
247 if (this->proposals
->get_count(this->proposals
) > 0)
249 proposal_substructure_t
*last_proposal
;
250 status
= this->proposals
->get_last(this->proposals
,(void **) &last_proposal
);
251 /* last transform is now not anymore last one */
252 last_proposal
->set_is_last_proposal(last_proposal
,FALSE
);
254 proposal
->set_is_last_proposal(proposal
,TRUE
);
256 this->proposals
->insert_last(this->proposals
,(void *) proposal
);
257 this->compute_length(this);
261 * Implementation of sa_payload_t.get_ike_proposals.
263 static status_t
get_ike_proposals (private_sa_payload_t
*this,ike_proposal_t
** proposals
, size_t *proposal_count
)
265 int found_ike_proposals
= 0;
266 int current_proposal_number
= 0;
267 iterator_t
*iterator
;
268 ike_proposal_t
*tmp_proposals
;
271 iterator
= this->proposals
->create_iterator(this->proposals
,TRUE
);
273 /* first find out the number of ike proposals and check their number of transforms and
274 * if the SPI is empty!*/
275 while (iterator
->has_next(iterator
))
277 proposal_substructure_t
*current_proposal
;
278 iterator
->current(iterator
,(void **)&(current_proposal
));
279 if (current_proposal
->get_protocol_id(current_proposal
) == IKE
)
281 /* a ike proposal consists of 4 transforms and an empty spi*/
282 if ((current_proposal
->get_transform_count(current_proposal
) != 4) ||
283 (current_proposal
->get_spi_size(current_proposal
) != 0))
285 iterator
->destroy(iterator
);
289 found_ike_proposals
++;
292 iterator
->reset(iterator
);
294 if (found_ike_proposals
== 0)
296 iterator
->destroy(iterator
);
300 /* allocate memory to hold each proposal as ike_proposal_t */
302 tmp_proposals
= allocator_alloc(found_ike_proposals
* sizeof(ike_proposal_t
));
304 /* create from each proposal_substructure a ike_proposal_t data area*/
305 while (iterator
->has_next(iterator
))
307 proposal_substructure_t
*current_proposal
;
308 iterator
->current(iterator
,(void **)&(current_proposal
));
309 if (current_proposal
->get_protocol_id(current_proposal
) == IKE
)
311 bool encryption_algorithm_found
= FALSE
;
312 bool integrity_algorithm_found
= FALSE
;
313 bool pseudo_random_function_found
= FALSE
;
314 bool diffie_hellman_group_found
= FALSE
;
316 iterator_t
*transforms
;
318 transforms
= current_proposal
->create_transform_substructure_iterator(current_proposal
,TRUE
);
319 while (transforms
->has_next(transforms
))
321 transform_substructure_t
*current_transform
;
322 transforms
->current(transforms
,(void **)&(current_transform
));
324 switch (current_transform
->get_transform_type(current_transform
))
326 case ENCRYPTION_ALGORITHM
:
328 tmp_proposals
[current_proposal_number
].encryption_algorithm
= current_transform
->get_transform_id(current_transform
);
329 status
= current_transform
->get_key_length(current_transform
,&(tmp_proposals
[current_proposal_number
].encryption_algorithm_key_length
));
330 if (status
== SUCCESS
)
332 encryption_algorithm_found
= TRUE
;
336 case INTEGRITY_ALGORITHM
:
338 tmp_proposals
[current_proposal_number
].integrity_algorithm
= current_transform
->get_transform_id(current_transform
);
339 status
= current_transform
->get_key_length(current_transform
,&(tmp_proposals
[current_proposal_number
].integrity_algorithm_key_length
));
340 if (status
== SUCCESS
)
342 integrity_algorithm_found
= TRUE
;
346 case PSEUDO_RANDOM_FUNCTION
:
348 tmp_proposals
[current_proposal_number
].pseudo_random_function
= current_transform
->get_transform_id(current_transform
);
349 status
= current_transform
->get_key_length(current_transform
,&(tmp_proposals
[current_proposal_number
].pseudo_random_function_key_length
));
350 if (status
== SUCCESS
)
352 pseudo_random_function_found
= TRUE
;
356 case DIFFIE_HELLMAN_GROUP
:
358 tmp_proposals
[current_proposal_number
].diffie_hellman_group
= current_transform
->get_transform_id(current_transform
);
359 diffie_hellman_group_found
= TRUE
;
364 /* not a transform of an ike proposal. Break here */
371 transforms
->destroy(transforms
);
373 if ((!encryption_algorithm_found
) ||
374 (!integrity_algorithm_found
) ||
375 (!pseudo_random_function_found
) ||
376 (!diffie_hellman_group_found
))
378 /* one of needed transforms could not be found */
379 iterator
->reset(iterator
);
380 allocator_free(tmp_proposals
);
384 current_proposal_number
++;
388 iterator
->destroy(iterator
);
390 *proposals
= tmp_proposals
;
391 *proposal_count
= found_ike_proposals
;
397 * Implementation of private_sa_payload_t.compute_length.
399 static void compute_length (private_sa_payload_t
*this)
401 iterator_t
*iterator
;
402 size_t length
= SA_PAYLOAD_HEADER_LENGTH
;
403 iterator
= this->proposals
->create_iterator(this->proposals
,TRUE
);
404 while (iterator
->has_next(iterator
))
406 payload_t
*current_proposal
;
407 iterator
->current(iterator
,(void **) ¤t_proposal
);
408 length
+= current_proposal
->get_length(current_proposal
);
410 iterator
->destroy(iterator
);
412 this->payload_length
= length
;
416 * Described in header.
418 sa_payload_t
*sa_payload_create()
420 private_sa_payload_t
*this = allocator_alloc_thing(private_sa_payload_t
);
422 /* public interface */
423 this->public.payload_interface
.verify
= (status_t (*) (payload_t
*))verify
;
424 this->public.payload_interface
.get_encoding_rules
= (void (*) (payload_t
*, encoding_rule_t
**, size_t *) ) get_encoding_rules
;
425 this->public.payload_interface
.get_length
= (size_t (*) (payload_t
*)) get_length
;
426 this->public.payload_interface
.get_next_type
= (payload_type_t (*) (payload_t
*)) get_next_type
;
427 this->public.payload_interface
.set_next_type
= (void (*) (payload_t
*,payload_type_t
)) set_next_type
;
428 this->public.payload_interface
.get_type
= (payload_type_t (*) (payload_t
*)) get_type
;
429 this->public.payload_interface
.destroy
= (void (*) (payload_t
*))destroy
;
431 /* public functions */
432 this->public.create_proposal_substructure_iterator
= (iterator_t
* (*) (sa_payload_t
*,bool)) create_proposal_substructure_iterator
;
433 this->public.add_proposal_substructure
= (void (*) (sa_payload_t
*,proposal_substructure_t
*)) add_proposal_substructure
;
434 this->public.get_ike_proposals
= (status_t (*) (sa_payload_t
*, ike_proposal_t
**, size_t *)) get_ike_proposals
;
435 this->public.destroy
= (void (*) (sa_payload_t
*)) destroy
;
437 /* private functions */
438 this->compute_length
= compute_length
;
440 /* set default values of the fields */
441 this->critical
= SA_PAYLOAD_CRITICAL_FLAG
;
442 this->next_payload
= NO_PAYLOAD
;
443 this->payload_length
= SA_PAYLOAD_HEADER_LENGTH
;
445 this->proposals
= linked_list_create();
446 return (&(this->public));
450 * Described in header.
452 sa_payload_t
*sa_payload_create_from_ike_proposals(ike_proposal_t
*proposals
, size_t proposal_count
)
455 sa_payload_t
*sa_payload
= sa_payload_create();
457 for (i
= 0; i
< proposal_count
; i
++)
459 proposal_substructure_t
*proposal_substructure
;
460 transform_substructure_t
*encryption_algorithm
;
461 transform_substructure_t
*integrity_algorithm
;
462 transform_substructure_t
*pseudo_random_function
;
463 transform_substructure_t
*diffie_hellman_group
;
465 /* create proposal substructure */
466 proposal_substructure
= proposal_substructure_create();
467 proposal_substructure
->set_protocol_id(proposal_substructure
,IKE
);
468 proposal_substructure
->set_proposal_number(proposal_substructure
,(i
+ 1));
470 /* create transform substructures to hold each specific transform for an ike proposal */
471 encryption_algorithm
= transform_substructure_create_type(ENCRYPTION_ALGORITHM
,proposals
[i
].encryption_algorithm
,proposals
[i
].encryption_algorithm_key_length
);
472 proposal_substructure
->add_transform_substructure(proposal_substructure
,encryption_algorithm
);
474 pseudo_random_function
= transform_substructure_create_type(PSEUDO_RANDOM_FUNCTION
,proposals
[i
].pseudo_random_function
,proposals
[i
].pseudo_random_function_key_length
);
475 proposal_substructure
->add_transform_substructure(proposal_substructure
,pseudo_random_function
);
477 integrity_algorithm
= transform_substructure_create_type(INTEGRITY_ALGORITHM
,proposals
[i
].integrity_algorithm
,proposals
[i
].integrity_algorithm_key_length
);
478 proposal_substructure
->add_transform_substructure(proposal_substructure
,integrity_algorithm
);
480 diffie_hellman_group
= transform_substructure_create_type(DIFFIE_HELLMAN_GROUP
,proposals
[i
].diffie_hellman_group
,0);
481 proposal_substructure
->add_transform_substructure(proposal_substructure
,diffie_hellman_group
);
483 /* add proposal to sa payload */
484 sa_payload
->add_proposal_substructure(sa_payload
,proposal_substructure
);