4 * @brief Implementation of the ike_rekey task.
9 * Copyright (C) 2005-2007 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 #include "ike_rekey.h"
27 #include <encoding/payloads/notify_payload.h>
28 #include <sa/tasks/ike_init.h>
29 #include <queues/jobs/delete_ike_sa_job.h>
32 typedef struct private_ike_rekey_t private_ike_rekey_t
;
35 * Private members of a ike_rekey_t task.
37 struct private_ike_rekey_t
{
40 * Public methods and task_t interface.
50 * New IKE_SA which replaces the current one
55 * Are we the initiator?
60 * the IKE_INIT task which is reused to simplify rekeying
65 * colliding task detected by the task manager
71 * Implementation of task_t.build for initiator
73 static status_t
build_i(private_ike_rekey_t
*this, message_t
*message
)
75 connection_t
*connection
;
79 id
= ike_sa_id_create(0, 0, TRUE
);
80 this->new_sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, id
);
83 connection
= this->ike_sa
->get_connection(this->ike_sa
);
84 policy
= this->ike_sa
->get_policy(this->ike_sa
);
85 this->new_sa
->set_connection(this->new_sa
, connection
);
86 this->new_sa
->set_policy(this->new_sa
, policy
);
88 this->ike_init
= ike_init_create(this->new_sa
, TRUE
, this->ike_sa
);
89 this->ike_init
->task
.build(&this->ike_init
->task
, message
);
91 this->ike_sa
->set_state(this->ike_sa
, IKE_REKEYING
);
97 * Implementation of task_t.process for initiator
99 static status_t
process_r(private_ike_rekey_t
*this, message_t
*message
)
101 connection_t
*connection
;
104 iterator_t
*iterator
;
105 child_sa_t
*child_sa
;
107 if (this->ike_sa
->get_state(this->ike_sa
) == IKE_DELETING
)
109 DBG1(DBG_IKE
, "peer initiated rekeying, but we are deleting");
113 iterator
= this->ike_sa
->create_child_sa_iterator(this->ike_sa
);
114 while (iterator
->iterate(iterator
, (void**)&child_sa
))
116 switch (child_sa
->get_state(child_sa
))
121 /* we do not allow rekeying while we have children in-progress */
122 DBG1(DBG_IKE
, "peer initiated rekeying, but a child is half-open");
123 iterator
->destroy(iterator
);
129 iterator
->destroy(iterator
);
131 id
= ike_sa_id_create(0, 0, FALSE
);
132 this->new_sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, id
);
135 connection
= this->ike_sa
->get_connection(this->ike_sa
);
136 policy
= this->ike_sa
->get_policy(this->ike_sa
);
137 this->new_sa
->set_connection(this->new_sa
, connection
);
138 this->new_sa
->set_policy(this->new_sa
, policy
);
140 this->ike_init
= ike_init_create(this->new_sa
, FALSE
, this->ike_sa
);
141 this->ike_init
->task
.process(&this->ike_init
->task
, message
);
147 * Implementation of task_t.build for responder
149 static status_t
build_r(private_ike_rekey_t
*this, message_t
*message
)
151 if (this->new_sa
== NULL
)
153 /* IKE_SA/a CHILD_SA is in an inacceptable state, deny rekeying */
154 message
->add_notify(message
, TRUE
, NO_PROPOSAL_CHOSEN
, chunk_empty
);
158 if (this->ike_init
->task
.build(&this->ike_init
->task
, message
) == FAILED
)
163 this->ike_sa
->set_state(this->ike_sa
, IKE_REKEYING
);
164 this->new_sa
->set_state(this->new_sa
, IKE_ESTABLISHED
);
170 * Implementation of task_t.process for initiator
172 static status_t
process_i(private_ike_rekey_t
*this, message_t
*message
)
175 ike_sa_id_t
*to_delete
;
177 if (this->ike_init
->task
.process(&this->ike_init
->task
, message
) == FAILED
)
179 /* rekeying failed, fallback to old SA */
180 if (!(this->collision
&&
181 this->collision
->get_type(this->collision
) == IKE_DELETE
))
183 this->ike_sa
->set_state(this->ike_sa
, IKE_ESTABLISHED
);
184 /* TODO: reschedule rekeying */
189 this->new_sa
->set_state(this->new_sa
, IKE_ESTABLISHED
);
190 to_delete
= this->ike_sa
->get_id(this->ike_sa
);
192 /* check for collisions */
193 if (this->collision
&&
194 this->collision
->get_type(this->collision
) == IKE_REKEY
)
196 chunk_t this_nonce
, other_nonce
;
198 private_ike_rekey_t
*other
= (private_ike_rekey_t
*)this->collision
;
200 this_nonce
= this->ike_init
->get_lower_nonce(this->ike_init
);
201 other_nonce
= other
->ike_init
->get_lower_nonce(other
->ike_init
);
203 /* if we have the lower nonce, delete rekeyed SA. If not, delete
205 if (memcmp(this_nonce
.ptr
, other_nonce
.ptr
,
206 min(this_nonce
.len
, other_nonce
.len
)) < 0)
208 DBG1(DBG_IKE
, "IKE_SA rekey collision won, deleting rekeyed IKE_SA");
209 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, other
->new_sa
);
213 DBG1(DBG_IKE
, "IKE_SA rekey collision lost, deleting redundant IKE_SA");
214 /* apply host for a proper delete */
215 host
= this->ike_sa
->get_my_host(this->ike_sa
);
216 this->new_sa
->set_my_host(this->new_sa
, host
->clone(host
));
217 host
= this->ike_sa
->get_other_host(this->ike_sa
);
218 this->new_sa
->set_other_host(this->new_sa
, host
->clone(host
));
219 this->ike_sa
->set_state(this->ike_sa
, IKE_ESTABLISHED
);
220 to_delete
= this->new_sa
->get_id(this->new_sa
);
221 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, this->new_sa
);
222 /* inherit to other->new_sa in destroy() */
223 this->new_sa
= other
->new_sa
;
224 other
->new_sa
= NULL
;
228 job
= (job_t
*)delete_ike_sa_job_create(to_delete
, TRUE
);
229 charon
->job_queue
->add(charon
->job_queue
, job
);
235 * Implementation of task_t.get_type
237 static task_type_t
get_type(private_ike_rekey_t
*this)
242 static void collide(private_ike_rekey_t
* this, task_t
*other
)
244 DESTROY_IF(this->collision
);
245 this->collision
= other
;
249 * Implementation of task_t.migrate
251 static void migrate(private_ike_rekey_t
*this, ike_sa_t
*ike_sa
)
255 this->ike_init
->task
.destroy(&this->ike_init
->task
);
259 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
,
262 DESTROY_IF(this->collision
);
264 this->collision
= NULL
;
265 this->ike_sa
= ike_sa
;
267 this->ike_init
= NULL
;
271 * Implementation of task_t.destroy
273 static void destroy(private_ike_rekey_t
*this)
277 if (this->new_sa
->get_state(this->new_sa
) == IKE_ESTABLISHED
)
279 this->new_sa
->inherit(this->new_sa
, this->ike_sa
);
280 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, this->new_sa
);
284 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
,
290 this->ike_init
->task
.destroy(&this->ike_init
->task
);
292 DESTROY_IF(this->collision
);
297 * Described in header.
299 ike_rekey_t
*ike_rekey_create(ike_sa_t
*ike_sa
, bool initiator
)
301 private_ike_rekey_t
*this = malloc_thing(private_ike_rekey_t
);
303 this->public.collide
= (void(*)(ike_rekey_t
*,task_t
*))collide
;
304 this->public.task
.get_type
= (task_type_t(*)(task_t
*))get_type
;
305 this->public.task
.migrate
= (void(*)(task_t
*,ike_sa_t
*))migrate
;
306 this->public.task
.destroy
= (void(*)(task_t
*))destroy
;
309 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_i
;
310 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_i
;
314 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_r
;
315 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_r
;
318 this->ike_sa
= ike_sa
;
320 this->ike_init
= NULL
;
321 this->initiator
= initiator
;
322 this->collision
= NULL
;
324 return &this->public;