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
30 typedef struct sa_policy_t sa_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
, PROTO_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
, PROTO_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
] != PROTO_NONE
)
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
] == PROTO_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
] == PROTO_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 chunk_free(&enc_key
);
310 if (int_algo
!= AUTH_UNDEFINED
)
312 chunk_free(&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 status_t
add_policies(private_child_sa_t
*this, linked_list_t
*my_ts_list
, linked_list_t
*other_ts_list
)
373 iterator_t
*my_iter
, *other_iter
;
374 traffic_selector_t
*my_ts
, *other_ts
;
376 /* iterate over both lists */
377 my_iter
= my_ts_list
->create_iterator(my_ts_list
, TRUE
);
378 other_iter
= other_ts_list
->create_iterator(other_ts_list
, TRUE
);
379 while (my_iter
->has_next(my_iter
))
381 my_iter
->current(my_iter
, (void**)&my_ts
);
382 other_iter
->reset(other_iter
);
383 while (other_iter
->has_next(other_iter
))
385 /* set up policies for every entry in my_ts_list to every entry in other_ts_list */
388 u_int16_t from_port
, to_port
;
392 other_iter
->current(other_iter
, (void**)&other_ts
);
394 /* only set up policies if protocol matches */
395 if (my_ts
->get_protocol(my_ts
) != other_ts
->get_protocol(other_ts
))
399 policy
= malloc_thing(sa_policy_t
);
400 policy
->upper_proto
= my_ts
->get_protocol(my_ts
);
402 /* calculate net and ports for local side */
403 family
= my_ts
->get_type(my_ts
) == TS_IPV4_ADDR_RANGE
? AF_INET
: AF_INET6
;
404 from_addr
= my_ts
->get_from_address(my_ts
);
405 from_port
= my_ts
->get_from_port(my_ts
);
406 to_port
= my_ts
->get_to_port(my_ts
);
407 from_port
= (from_port
!= to_port
) ? 0 : from_port
;
408 policy
->my_net
= host_create_from_chunk(family
, from_addr
, from_port
);
409 policy
->my_net_mask
= my_ts
->get_netmask(my_ts
);
410 chunk_free(&from_addr
);
412 /* calculate net and ports for remote side */
413 family
= other_ts
->get_type(other_ts
) == TS_IPV4_ADDR_RANGE
? AF_INET
: AF_INET6
;
414 from_addr
= other_ts
->get_from_address(other_ts
);
415 from_port
= other_ts
->get_from_port(other_ts
);
416 to_port
= other_ts
->get_to_port(other_ts
);
417 from_port
= (from_port
!= to_port
) ? 0 : from_port
;
418 policy
->other_net
= host_create_from_chunk(family
, from_addr
, from_port
);
419 policy
->other_net_mask
= other_ts
->get_netmask(other_ts
);
420 chunk_free(&from_addr
);
422 /* install 3 policies: out, in and forward */
423 status
= charon
->kernel_interface
->add_policy(charon
->kernel_interface
,
424 this->me
, this->other
,
425 policy
->my_net
, policy
->other_net
,
426 policy
->my_net_mask
, policy
->other_net_mask
,
427 XFRM_POLICY_OUT
, policy
->upper_proto
,
428 this->my_ah_spi
, this->my_esp_spi
,
431 status
|= charon
->kernel_interface
->add_policy(charon
->kernel_interface
,
432 this->other
, this->me
,
433 policy
->other_net
, policy
->my_net
,
434 policy
->other_net_mask
, policy
->my_net_mask
,
435 XFRM_POLICY_IN
, policy
->upper_proto
,
436 this->my_ah_spi
, this->my_esp_spi
,
439 status
|= charon
->kernel_interface
->add_policy(charon
->kernel_interface
,
440 this->other
, this->me
,
441 policy
->other_net
, policy
->my_net
,
442 policy
->other_net_mask
, policy
->my_net_mask
,
443 XFRM_POLICY_FWD
, policy
->upper_proto
,
444 this->my_ah_spi
, this->my_esp_spi
,
447 if (status
!= SUCCESS
)
449 my_iter
->destroy(my_iter
);
450 other_iter
->destroy(other_iter
);
451 policy
->my_net
->destroy(policy
->my_net
);
452 policy
->other_net
->destroy(policy
->other_net
);
457 /* add it to the policy list, since we want to know which policies we own */
458 this->policies
->insert_last(this->policies
, policy
);
462 my_iter
->destroy(my_iter
);
463 other_iter
->destroy(other_iter
);
468 * Implementation of child_sa_t.log_status.
470 static void log_status(private_child_sa_t
*this, logger_t
*logger
, char* name
)
472 iterator_t
*iterator
;
474 struct protoent
*proto
;
475 char proto_buf
[8] = "";
476 char *proto_name
= proto_buf
;
480 logger
= this->logger
;
482 logger
->log(logger
, CONTROL
|LEVEL1
, "\"%s\": protected with ESP (0x%x/0x%x), AH (0x%x,0x%x):",
484 htonl(this->my_esp_spi
), htonl(this->other_esp_spi
),
485 htonl(this->my_ah_spi
), htonl(this->other_ah_spi
));
486 iterator
= this->policies
->create_iterator(this->policies
, TRUE
);
487 while (iterator
->has_next(iterator
))
489 iterator
->current(iterator
, (void**)&policy
);
490 if (policy
->upper_proto
)
492 proto
= getprotobynumber(policy
->upper_proto
);
495 proto_name
= proto
->p_name
;
499 snprintf(proto_buf
, sizeof(proto_buf
), "<%d>", policy
->upper_proto
);
502 logger
->log(logger
, CONTROL
, "\"%s\": %s/%d==%s==%s/%d",
504 policy
->my_net
->get_address(policy
->my_net
), policy
->my_net_mask
,
506 policy
->other_net
->get_address(policy
->other_net
), policy
->other_net_mask
);
508 iterator
->destroy(iterator
);
512 * Implementation of child_sa_t.destroy.
514 static void destroy(private_child_sa_t
*this)
516 /* delete all policys in the kernel */
518 while (this->policies
->remove_last(this->policies
, (void**)&policy
) == SUCCESS
)
520 charon
->kernel_interface
->del_policy(charon
->kernel_interface
,
521 this->me
, this->other
,
522 policy
->my_net
, policy
->other_net
,
523 policy
->my_net_mask
, policy
->other_net_mask
,
524 XFRM_POLICY_OUT
, policy
->upper_proto
);
526 charon
->kernel_interface
->del_policy(charon
->kernel_interface
,
527 this->other
, this->me
,
528 policy
->other_net
, policy
->my_net
,
529 policy
->other_net_mask
, policy
->my_net_mask
,
530 XFRM_POLICY_IN
, policy
->upper_proto
);
532 charon
->kernel_interface
->del_policy(charon
->kernel_interface
,
533 this->other
, this->me
,
534 policy
->other_net
, policy
->my_net
,
535 policy
->other_net_mask
, policy
->my_net_mask
,
536 XFRM_POLICY_FWD
, policy
->upper_proto
);
538 policy
->my_net
->destroy(policy
->my_net
);
539 policy
->other_net
->destroy(policy
->other_net
);
542 this->policies
->destroy(this->policies
);
544 /* delete SAs in the kernel, if they are set up */
547 charon
->kernel_interface
->del_sa(charon
->kernel_interface
,
548 this->other
, this->my_ah_spi
, PROTO_AH
);
549 charon
->kernel_interface
->del_sa(charon
->kernel_interface
,
550 this->me
, this->other_ah_spi
, PROTO_AH
);
552 if (this->my_esp_spi
)
554 charon
->kernel_interface
->del_sa(charon
->kernel_interface
,
555 this->other
, this->my_esp_spi
, PROTO_ESP
);
556 charon
->kernel_interface
->del_sa(charon
->kernel_interface
,
557 this->me
, this->other_esp_spi
, PROTO_ESP
);
563 * Described in header.
565 child_sa_t
* child_sa_create(host_t
*me
, host_t
* other
)
567 static u_int32_t reqid
= 0xc0000000;
568 private_child_sa_t
*this = malloc_thing(private_child_sa_t
);
570 /* public functions */
571 this->public.alloc
= (status_t(*)(child_sa_t
*,linked_list_t
*))alloc
;
572 this->public.add
= (status_t(*)(child_sa_t
*,proposal_t
*,prf_plus_t
*))add
;
573 this->public.update
= (status_t(*)(child_sa_t
*,proposal_t
*,prf_plus_t
*))update
;
574 this->public.add_policies
= (status_t (*)(child_sa_t
*, linked_list_t
*,linked_list_t
*))add_policies
;
575 this->public.log_status
= (void (*)(child_sa_t
*, logger_t
*, char*))log_status
;
576 this->public.destroy
= (void(*)(child_sa_t
*))destroy
;
579 this->logger
= logger_manager
->get_logger(logger_manager
, CHILD_SA
);
583 this->my_esp_spi
= 0;
584 this->other_ah_spi
= 0;
585 this->other_esp_spi
= 0;
586 this->reqid
= reqid
++;
587 this->policies
= linked_list_create();
589 return (&this->public);