4 * @brief Implementation of child_sa_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 <utils/allocator.h>
30 typedef struct policy_t policy_t
;
33 * Struct used to store information for a policy. This
34 * is needed since we must provide all this information
35 * for deleting a policy...
40 * Network on local side
45 * Network on remote side
50 * Number of bits for local network (subnet size)
55 * Number of bits for remote network (subnet size)
57 u_int8_t other_net_mask
;
60 * Protocol for this policy, such as TCP/UDP/ICMP...
65 typedef struct private_child_sa_t private_child_sa_t
;
68 * Private data of a child_sa_t object.
70 struct private_child_sa_t
{
72 * Public interface of child_sa_t.
87 * Local security parameter index for AH protocol, 0 if not used
92 * Local security parameter index for ESP protocol, 0 if not used
97 * Remote security parameter index for AH protocol, 0 if not used
99 u_int32_t other_ah_spi
;
102 * Remote security parameter index for ESP protocol, 0 if not used
104 u_int32_t other_esp_spi
;
107 * List containing policy_id_t objects
109 linked_list_t
*policies
;
112 * reqid used for this child_sa
117 * CHILD_SAs own logger
123 * Implements child_sa_t.alloc
125 static status_t
alloc(private_child_sa_t
*this, linked_list_t
*proposals
)
127 protocol_id_t protocols
[2];
128 iterator_t
*iterator
;
129 proposal_t
*proposal
;
133 /* iterator through proposals */
134 iterator
= proposals
->create_iterator(proposals
, TRUE
);
135 while(iterator
->has_next(iterator
))
137 iterator
->current(iterator
, (void**)&proposal
);
138 proposal
->get_protocols(proposal
, protocols
);
140 /* check all protocols */
141 for (i
= 0; i
<2; i
++)
143 switch (protocols
[i
])
146 /* do we already have an spi for AH?*/
147 if (this->my_ah_spi
== 0)
150 status
= charon
->kernel_interface
->get_spi(
151 charon
->kernel_interface
,
152 this->me
, this->other
,
156 /* update proposal */
157 proposal
->set_spi(proposal
, AH
, (u_int64_t
)this->my_ah_spi
);
160 /* do we already have an spi for ESP?*/
161 if (this->my_esp_spi
== 0)
164 status
= charon
->kernel_interface
->get_spi(
165 charon
->kernel_interface
,
166 this->me
, this->other
,
168 &(this->my_esp_spi
));
170 /* update proposal */
171 proposal
->set_spi(proposal
, ESP
, (u_int64_t
)this->my_esp_spi
);
176 if (status
!= SUCCESS
)
178 iterator
->destroy(iterator
);
183 iterator
->destroy(iterator
);
187 static status_t
install(private_child_sa_t
*this, proposal_t
*proposal
, prf_plus_t
*prf_plus
, bool mine
)
189 protocol_id_t protocols
[2];
191 encryption_algorithm_t enc_algo
;
192 integrity_algorithm_t int_algo
;
193 chunk_t enc_key
, int_key
;
203 /* we must assign the roles to correctly set up the SAs */
215 proposal
->get_protocols(proposal
, protocols
);
216 /* derive keys in order as protocols appear */
217 for (i
= 0; i
<2; i
++)
219 if (protocols
[i
] != UNDEFINED_PROTOCOL_ID
)
222 /* now we have to decide which spi to use. Use self allocated, if "mine",
223 * or the one in the proposal, if not "mine" (others). */
226 if (protocols
[i
] == AH
)
228 spi
= this->my_ah_spi
;
232 spi
= this->my_esp_spi
;
235 else /* use proposals spi */
237 spi
= proposal
->get_spi(proposal
, protocols
[i
]);
238 if (protocols
[i
] == AH
)
240 this->other_ah_spi
= spi
;
244 this->other_esp_spi
= spi
;
248 /* derive encryption key first */
249 if (proposal
->get_algorithm(proposal
, protocols
[i
], ENCRYPTION_ALGORITHM
, &algo
))
251 enc_algo
= algo
->algorithm
;
252 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "%s for %s: using %s %s, ",
253 mapping_find(protocol_id_m
, protocols
[i
]),
254 mine
? "me" : "other",
255 mapping_find(transform_type_m
, ENCRYPTION_ALGORITHM
),
256 mapping_find(encryption_algorithm_m
, enc_algo
));
258 /* we must create a (unused) crypter, since its the only way to get the size
259 * of the key. This is not so nice, since charon must support all algorithms
260 * the kernel supports...
261 * TODO: build something of a encryption algorithm lookup function
263 crypter
= crypter_create(enc_algo
, algo
->key_size
);
264 key_size
= crypter
->get_key_size(crypter
);
265 crypter
->destroy(crypter
);
266 prf_plus
->allocate_bytes(prf_plus
, key_size
, &enc_key
);
267 this->logger
->log_chunk(this->logger
, PRIVATE
, "key:", &enc_key
);
271 enc_algo
= ENCR_UNDEFINED
;
274 /* derive integrity key */
275 if (proposal
->get_algorithm(proposal
, protocols
[i
], INTEGRITY_ALGORITHM
, &algo
))
277 int_algo
= algo
->algorithm
;
278 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "%s for %s: using %s %s,",
279 mapping_find(protocol_id_m
, protocols
[i
]),
280 mine
? "me" : "other",
281 mapping_find(transform_type_m
, INTEGRITY_ALGORITHM
),
282 mapping_find(integrity_algorithm_m
, algo
->algorithm
));
284 signer
= signer_create(int_algo
);
285 key_size
= signer
->get_key_size(signer
);
286 signer
->destroy(signer
);
287 prf_plus
->allocate_bytes(prf_plus
, key_size
, &int_key
);
288 this->logger
->log_chunk(this->logger
, PRIVATE
, "key:", &int_key
);
292 int_algo
= AUTH_UNDEFINED
;
294 /* send keys down to kernel */
295 this->logger
->log(this->logger
, CONTROL
|LEVEL1
,
296 "installing 0x%.8x for %s, src %s dst %s",
297 ntohl(spi
), mapping_find(protocol_id_m
, protocols
[i
]),
298 src
->get_address(src
), dst
->get_address(dst
));
299 status
= charon
->kernel_interface
->add_sa(charon
->kernel_interface
,
304 int_algo
, int_key
, mine
);
305 /* clean up for next round */
306 if (enc_algo
!= ENCR_UNDEFINED
)
308 allocator_free_chunk(&enc_key
);
310 if (int_algo
!= AUTH_UNDEFINED
)
312 allocator_free_chunk(&int_key
);
315 if (status
!= SUCCESS
)
326 static status_t
add(private_child_sa_t
*this, proposal_t
*proposal
, prf_plus_t
*prf_plus
)
330 /* install others (initiators) SAs*/
331 if (install(this, proposal
, prf_plus
, FALSE
) != SUCCESS
)
336 /* get SPIs for our SAs */
337 list
= linked_list_create();
338 list
->insert_last(list
, proposal
);
339 if (alloc(this, list
) != SUCCESS
)
346 /* install our (responders) SAs */
347 if (install(this, proposal
, prf_plus
, TRUE
) != SUCCESS
)
355 static status_t
update(private_child_sa_t
*this, proposal_t
*proposal
, prf_plus_t
*prf_plus
)
357 /* install our (initator) SAs */
358 if (install(this, proposal
, prf_plus
, TRUE
) != SUCCESS
)
362 /* install his (responder) SAs */
363 if (install(this, proposal
, prf_plus
, FALSE
) != SUCCESS
)
371 static u_int8_t
get_mask(chunk_t start
, chunk_t end
)
373 int byte
, bit
, mask
= 0;
375 if (start
.len
!= end
.len
)
379 for (byte
= 0; byte
< start
.len
; byte
++)
381 for (bit
= 7; bit
>= 0; bit
--)
383 if ((*(start
.ptr
+ byte
) | (1<<bit
)) ==
384 (*(end
.ptr
+ byte
) | (1<<bit
)))
394 return start
.len
* 8;
397 static status_t
add_policies(private_child_sa_t
*this, linked_list_t
*my_ts_list
, linked_list_t
*other_ts_list
)
399 iterator_t
*my_iter
, *other_iter
;
400 traffic_selector_t
*my_ts
, *other_ts
;
402 /* iterate over both lists */
403 my_iter
= my_ts_list
->create_iterator(my_ts_list
, TRUE
);
404 other_iter
= other_ts_list
->create_iterator(other_ts_list
, TRUE
);
405 while (my_iter
->has_next(my_iter
))
407 my_iter
->current(my_iter
, (void**)&my_ts
);
408 other_iter
->reset(other_iter
);
409 while (other_iter
->has_next(other_iter
))
411 /* set up policies for every entry in my_ts_list to every entry in other_ts_list */
413 chunk_t from_addr
, to_addr
;
414 u_int16_t from_port
, to_port
;
418 other_iter
->current(other_iter
, (void**)&other_ts
);
420 /* only set up policies if protocol matches */
421 if (my_ts
->get_protocol(my_ts
) != other_ts
->get_protocol(other_ts
))
425 policy
= allocator_alloc_thing(policy_t
);
426 policy
->upper_proto
= my_ts
->get_protocol(my_ts
);
428 /* calculate net and ports for local side */
429 family
= my_ts
->get_type(my_ts
) == TS_IPV4_ADDR_RANGE
? AF_INET
: AF_INET6
;
430 from_addr
= my_ts
->get_from_address(my_ts
);
431 to_addr
= my_ts
->get_to_address(my_ts
);
432 from_port
= my_ts
->get_from_port(my_ts
);
433 to_port
= my_ts
->get_to_port(my_ts
);
434 from_port
= (from_port
!= to_port
) ? 0 : from_port
;
435 policy
->my_net
= host_create_from_chunk(family
, from_addr
, from_port
);
436 policy
->my_net_mask
= get_mask(from_addr
, to_addr
);
437 allocator_free_chunk(&from_addr
);
438 allocator_free_chunk(&to_addr
);
440 /* calculate net and ports for remote side */
441 family
= other_ts
->get_type(other_ts
) == TS_IPV4_ADDR_RANGE
? AF_INET
: AF_INET6
;
442 from_addr
= other_ts
->get_from_address(other_ts
);
443 to_addr
= other_ts
->get_to_address(other_ts
);
444 from_port
= other_ts
->get_from_port(other_ts
);
445 to_port
= other_ts
->get_to_port(other_ts
);
446 from_port
= (from_port
!= to_port
) ? 0 : from_port
;
447 policy
->other_net
= host_create_from_chunk(family
, from_addr
, from_port
);
448 policy
->other_net_mask
= get_mask(from_addr
, to_addr
);
449 allocator_free_chunk(&from_addr
);
450 allocator_free_chunk(&to_addr
);
452 /* install 3 policies: out, in and forward */
453 status
= charon
->kernel_interface
->add_policy(charon
->kernel_interface
,
454 this->me
, this->other
,
455 policy
->my_net
, policy
->other_net
,
456 policy
->my_net_mask
, policy
->other_net_mask
,
457 XFRM_POLICY_OUT
, policy
->upper_proto
,
458 this->my_ah_spi
, this->my_esp_spi
,
461 status
|= charon
->kernel_interface
->add_policy(charon
->kernel_interface
,
462 this->other
, this->me
,
463 policy
->other_net
, policy
->my_net
,
464 policy
->other_net_mask
, policy
->my_net_mask
,
465 XFRM_POLICY_IN
, policy
->upper_proto
,
466 this->my_ah_spi
, this->my_esp_spi
,
469 status
|= charon
->kernel_interface
->add_policy(charon
->kernel_interface
,
470 this->other
, this->me
,
471 policy
->other_net
, policy
->my_net
,
472 policy
->other_net_mask
, policy
->my_net_mask
,
473 XFRM_POLICY_FWD
, policy
->upper_proto
,
474 this->my_ah_spi
, this->my_esp_spi
,
477 if (status
!= SUCCESS
)
479 my_iter
->destroy(my_iter
);
480 other_iter
->destroy(other_iter
);
481 allocator_free(policy
);
485 /* add it to the policy list, since we want to know which policies we own */
486 this->policies
->insert_last(this->policies
, policy
);
490 my_iter
->destroy(my_iter
);
491 other_iter
->destroy(other_iter
);
496 * Implementation of child_sa_t.destroy.
498 static void destroy(private_child_sa_t
*this)
500 /* delete all policys in the kernel */
502 while (this->policies
->remove_last(this->policies
, (void**)&policy
) == SUCCESS
)
504 charon
->kernel_interface
->del_policy(charon
->kernel_interface
,
505 this->me
, this->other
,
506 policy
->my_net
, policy
->other_net
,
507 policy
->my_net_mask
, policy
->other_net_mask
,
508 XFRM_POLICY_OUT
, policy
->upper_proto
);
510 charon
->kernel_interface
->del_policy(charon
->kernel_interface
,
511 this->other
, this->me
,
512 policy
->other_net
, policy
->my_net
,
513 policy
->other_net_mask
, policy
->my_net_mask
,
514 XFRM_POLICY_IN
, policy
->upper_proto
);
516 charon
->kernel_interface
->del_policy(charon
->kernel_interface
,
517 this->other
, this->me
,
518 policy
->other_net
, policy
->my_net
,
519 policy
->other_net_mask
, policy
->my_net_mask
,
520 XFRM_POLICY_FWD
, policy
->upper_proto
);
522 policy
->my_net
->destroy(policy
->my_net
);
523 policy
->other_net
->destroy(policy
->other_net
);
524 allocator_free(policy
);
526 this->policies
->destroy(this->policies
);
528 /* delete SAs in the kernel, if they are set up */
531 charon
->kernel_interface
->del_sa(charon
->kernel_interface
,
532 this->other
, this->my_ah_spi
, AH
);
533 charon
->kernel_interface
->del_sa(charon
->kernel_interface
,
534 this->me
, this->other_ah_spi
, AH
);
536 if (this->my_esp_spi
)
538 charon
->kernel_interface
->del_sa(charon
->kernel_interface
,
539 this->other
, this->my_esp_spi
, ESP
);
540 charon
->kernel_interface
->del_sa(charon
->kernel_interface
,
541 this->me
, this->other_esp_spi
, ESP
);
544 charon
->logger_manager
->destroy_logger(charon
->logger_manager
, this->logger
);
545 allocator_free(this);
549 * Described in header.
551 child_sa_t
* child_sa_create(host_t
*me
, host_t
* other
)
553 static u_int32_t reqid
= 1;
554 private_child_sa_t
*this = allocator_alloc_thing(private_child_sa_t
);
556 /* public functions */
557 this->public.alloc
= (status_t(*)(child_sa_t
*,linked_list_t
*))alloc
;
558 this->public.add
= (status_t(*)(child_sa_t
*,proposal_t
*,prf_plus_t
*))add
;
559 this->public.update
= (status_t(*)(child_sa_t
*,proposal_t
*,prf_plus_t
*))update
;
560 this->public.add_policies
= (status_t (*)(child_sa_t
*, linked_list_t
*,linked_list_t
*))add_policies
;
561 this->public.destroy
= (void(*)(child_sa_t
*))destroy
;
564 this->logger
= charon
->logger_manager
->create_logger(charon
->logger_manager
, CHILD_SA
, NULL
);
568 this->my_esp_spi
= 0;
569 this->other_ah_spi
= 0;
570 this->other_esp_spi
= 0;
571 this->reqid
= reqid
++;
572 this->policies
= linked_list_create();
574 return (&this->public);