ike-rekey: Handle TEMPORARY_FAILURE notify
[strongswan.git] / src / libcharon / sa / ikev2 / tasks / ike_rekey.c
1 /*
2 * Copyright (C) 2015-2016 Tobias Brunner
3 * Copyright (C) 2005-2008 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * HSR Hochschule fuer Technik Rapperswil
6 *
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>.
11 *
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
15 * for more details.
16 */
17
18 #include "ike_rekey.h"
19
20 #include <daemon.h>
21 #include <encoding/payloads/notify_payload.h>
22 #include <sa/ikev2/tasks/ike_init.h>
23 #include <sa/ikev2/tasks/ike_delete.h>
24 #include <processing/jobs/delete_ike_sa_job.h>
25 #include <processing/jobs/rekey_ike_sa_job.h>
26 #include <processing/jobs/initiate_tasks_job.h>
27
28
29 typedef struct private_ike_rekey_t private_ike_rekey_t;
30
31 /**
32 * Private members of a ike_rekey_t task.
33 */
34 struct private_ike_rekey_t {
35
36 /**
37 * Public methods and task_t interface.
38 */
39 ike_rekey_t public;
40
41 /**
42 * Assigned IKE_SA.
43 */
44 ike_sa_t *ike_sa;
45
46 /**
47 * New IKE_SA which replaces the current one
48 */
49 ike_sa_t *new_sa;
50
51 /**
52 * Are we the initiator?
53 */
54 bool initiator;
55
56 /**
57 * the TASK_IKE_INIT task which is reused to simplify rekeying
58 */
59 ike_init_t *ike_init;
60
61 /**
62 * IKE_DELETE task to delete the old IKE_SA after rekeying was successful
63 */
64 ike_delete_t *ike_delete;
65
66 /**
67 * colliding task detected by the task manager
68 */
69 task_t *collision;
70 };
71
72 /**
73 * Schedule a retry if rekeying temporary failed
74 */
75 static void schedule_delayed_rekey(private_ike_rekey_t *this)
76 {
77 uint32_t retry;
78 job_t *job;
79
80 retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
81 job = (job_t*)rekey_ike_sa_job_create(
82 this->ike_sa->get_id(this->ike_sa), FALSE);
83 DBG1(DBG_IKE, "IKE_SA rekeying failed, trying again in %d seconds", retry);
84 this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
85 lib->scheduler->schedule_job(lib->scheduler, job, retry);
86 }
87
88 /**
89 * Check if an IKE_SA has any queued tasks, return initiation job
90 */
91 static job_t* check_queued_tasks(ike_sa_t *ike_sa)
92 {
93 enumerator_t *enumerator;
94 task_t *task;
95 job_t *job = NULL;
96
97 enumerator = ike_sa->create_task_enumerator(ike_sa, TASK_QUEUE_QUEUED);
98 if (enumerator->enumerate(enumerator, &task))
99 {
100 job = (job_t*)initiate_tasks_job_create(ike_sa->get_id(ike_sa));
101 }
102 enumerator->destroy(enumerator);
103 return job;
104 }
105
106 /**
107 * Establish the new replacement IKE_SA
108 */
109 static void establish_new(private_ike_rekey_t *this)
110 {
111 if (this->new_sa)
112 {
113 job_t *job;
114
115 this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
116 DBG0(DBG_IKE, "IKE_SA %s[%d] rekeyed between %H[%Y]...%H[%Y]",
117 this->new_sa->get_name(this->new_sa),
118 this->new_sa->get_unique_id(this->new_sa),
119 this->ike_sa->get_my_host(this->ike_sa),
120 this->ike_sa->get_my_id(this->ike_sa),
121 this->ike_sa->get_other_host(this->ike_sa),
122 this->ike_sa->get_other_id(this->ike_sa));
123
124 this->new_sa->inherit_post(this->new_sa, this->ike_sa);
125 charon->bus->ike_rekey(charon->bus, this->ike_sa, this->new_sa);
126 job = check_queued_tasks(this->new_sa);
127 /* don't queue job before checkin(), as the IKE_SA is not yet
128 * registered at the manager */
129 charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
130 if (job)
131 {
132 lib->processor->queue_job(lib->processor, job);
133 }
134 this->new_sa = NULL;
135 charon->bus->set_sa(charon->bus, this->ike_sa);
136
137 this->ike_sa->set_state(this->ike_sa, IKE_REKEYED);
138 }
139 }
140
141 METHOD(task_t, build_i_delete, status_t,
142 private_ike_rekey_t *this, message_t *message)
143 {
144 /* update exchange type to INFORMATIONAL for the delete */
145 message->set_exchange_type(message, INFORMATIONAL);
146
147 return this->ike_delete->task.build(&this->ike_delete->task, message);
148 }
149
150 METHOD(task_t, process_i_delete, status_t,
151 private_ike_rekey_t *this, message_t *message)
152 {
153 return this->ike_delete->task.process(&this->ike_delete->task, message);
154 }
155
156 METHOD(task_t, build_i, status_t,
157 private_ike_rekey_t *this, message_t *message)
158 {
159 ike_version_t version;
160
161 /* create new SA only on first try */
162 if (this->new_sa == NULL)
163 {
164 version = this->ike_sa->get_version(this->ike_sa);
165 this->new_sa = charon->ike_sa_manager->checkout_new(
166 charon->ike_sa_manager, version, TRUE);
167 if (!this->new_sa)
168 { /* shouldn't happen */
169 return FAILED;
170 }
171 this->new_sa->inherit_pre(this->new_sa, this->ike_sa);
172 this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa);
173 this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
174 }
175 this->ike_init->task.build(&this->ike_init->task, message);
176
177 return NEED_MORE;
178 }
179
180 METHOD(task_t, process_r, status_t,
181 private_ike_rekey_t *this, message_t *message)
182 {
183 enumerator_t *enumerator;
184 child_sa_t *child_sa;
185
186 if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
187 {
188 DBG1(DBG_IKE, "peer initiated rekeying, but we are deleting");
189 return NEED_MORE;
190 }
191
192 enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
193 while (enumerator->enumerate(enumerator, (void**)&child_sa))
194 {
195 switch (child_sa->get_state(child_sa))
196 {
197 case CHILD_CREATED:
198 case CHILD_REKEYING:
199 case CHILD_RETRYING:
200 case CHILD_DELETING:
201 /* we do not allow rekeying while we have children in-progress */
202 DBG1(DBG_IKE, "peer initiated rekeying, but a child is half-open");
203 enumerator->destroy(enumerator);
204 return NEED_MORE;
205 default:
206 break;
207 }
208 }
209 enumerator->destroy(enumerator);
210
211 this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
212 this->ike_sa->get_version(this->ike_sa), FALSE);
213 if (!this->new_sa)
214 { /* shouldn't happen */
215 return FAILED;
216 }
217 this->new_sa->inherit_pre(this->new_sa, this->ike_sa);
218 this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa);
219 this->ike_init->task.process(&this->ike_init->task, message);
220
221 return NEED_MORE;
222 }
223
224 METHOD(task_t, build_r, status_t,
225 private_ike_rekey_t *this, message_t *message)
226 {
227 if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
228 {
229 message->add_notify(message, TRUE, TEMPORARY_FAILURE, chunk_empty);
230 return SUCCESS;
231 }
232 if (this->new_sa == NULL)
233 {
234 /* IKE_SA/a CHILD_SA is in an inacceptable state, deny rekeying */
235 message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
236 return SUCCESS;
237 }
238
239 if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED)
240 {
241 charon->bus->set_sa(charon->bus, this->ike_sa);
242 return SUCCESS;
243 }
244 charon->bus->set_sa(charon->bus, this->ike_sa);
245
246 if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING)
247 { /* in case of a collision we let the initiating task handle this */
248 establish_new(this);
249 /* make sure the IKE_SA is gone in case the peer fails to delete it */
250 lib->scheduler->schedule_job(lib->scheduler, (job_t*)
251 delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE),
252 90);
253 }
254 return SUCCESS;
255 }
256
257 METHOD(task_t, process_i, status_t,
258 private_ike_rekey_t *this, message_t *message)
259 {
260 if (message->get_notify(message, NO_ADDITIONAL_SAS))
261 {
262 DBG1(DBG_IKE, "peer seems to not support IKE rekeying, "
263 "starting reauthentication");
264 this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
265 lib->processor->queue_job(lib->processor,
266 (job_t*)rekey_ike_sa_job_create(
267 this->ike_sa->get_id(this->ike_sa), TRUE));
268 return SUCCESS;
269 }
270 if (message->get_notify(message, TEMPORARY_FAILURE))
271 {
272 schedule_delayed_rekey(this);
273 return SUCCESS;
274 }
275
276 switch (this->ike_init->task.process(&this->ike_init->task, message))
277 {
278 case FAILED:
279 /* rekeying failed, fallback to old SA */
280 if (!(this->collision && (
281 this->collision->get_type(this->collision) == TASK_IKE_DELETE ||
282 this->collision->get_type(this->collision) == TASK_IKE_REAUTH)))
283 {
284 schedule_delayed_rekey(this);
285 }
286 return SUCCESS;
287 case NEED_MORE:
288 /* bad dh group, try again */
289 this->ike_init->task.migrate(&this->ike_init->task, this->new_sa);
290 return NEED_MORE;
291 default:
292 break;
293 }
294
295 /* check for collisions */
296 if (this->collision &&
297 this->collision->get_type(this->collision) == TASK_IKE_REKEY)
298 {
299 private_ike_rekey_t *other = (private_ike_rekey_t*)this->collision;
300
301 /* ike_init can be NULL, if child_sa is half-open */
302 if (other->ike_init)
303 {
304 host_t *host;
305 chunk_t this_nonce, other_nonce;
306
307 this_nonce = this->ike_init->get_lower_nonce(this->ike_init);
308 other_nonce = other->ike_init->get_lower_nonce(other->ike_init);
309
310 /* if we have the lower nonce, delete rekeyed SA. If not, delete
311 * the redundant. */
312 if (memcmp(this_nonce.ptr, other_nonce.ptr,
313 min(this_nonce.len, other_nonce.len)) > 0)
314 {
315 /* peer should delete this SA. Add a timeout just in case. */
316 job_t *job = (job_t*)delete_ike_sa_job_create(
317 other->new_sa->get_id(other->new_sa), TRUE);
318 lib->scheduler->schedule_job(lib->scheduler, job,
319 HALF_OPEN_IKE_SA_TIMEOUT);
320 DBG1(DBG_IKE, "IKE_SA rekey collision won, waiting for delete "
321 "for redundant IKE_SA %s[%d]",
322 other->new_sa->get_name(other->new_sa),
323 other->new_sa->get_unique_id(other->new_sa));
324 other->new_sa->set_state(other->new_sa, IKE_REKEYED);
325 charon->ike_sa_manager->checkin(charon->ike_sa_manager,
326 other->new_sa);
327 other->new_sa = NULL;
328 }
329 else
330 {
331 DBG1(DBG_IKE, "IKE_SA rekey collision lost, deleting redundant "
332 "IKE_SA %s[%d]", this->new_sa->get_name(this->new_sa),
333 this->new_sa->get_unique_id(this->new_sa));
334 /* apply host for a proper delete */
335 host = this->ike_sa->get_my_host(this->ike_sa);
336 this->new_sa->set_my_host(this->new_sa, host->clone(host));
337 host = this->ike_sa->get_other_host(this->ike_sa);
338 this->new_sa->set_other_host(this->new_sa, host->clone(host));
339 /* IKE_SAs in state IKE_REKEYED are silently deleted, so we use
340 * IKE_REKEYING */
341 this->new_sa->set_state(this->new_sa, IKE_REKEYING);
342 if (this->new_sa->delete(this->new_sa) == DESTROY_ME)
343 {
344 this->new_sa->destroy(this->new_sa);
345 }
346 else
347 {
348 charon->ike_sa_manager->checkin(charon->ike_sa_manager,
349 this->new_sa);
350 }
351 charon->bus->set_sa(charon->bus, this->ike_sa);
352 this->new_sa = NULL;
353 establish_new(other);
354 return SUCCESS;
355 }
356 }
357 charon->bus->set_sa(charon->bus, this->ike_sa);
358 }
359
360 establish_new(this);
361
362 /* rekeying successful, delete the IKE_SA using a subtask */
363 this->ike_delete = ike_delete_create(this->ike_sa, TRUE);
364 this->public.task.build = _build_i_delete;
365 this->public.task.process = _process_i_delete;
366
367 return NEED_MORE;
368 }
369
370 METHOD(task_t, get_type, task_type_t,
371 private_ike_rekey_t *this)
372 {
373 return TASK_IKE_REKEY;
374 }
375
376 METHOD(ike_rekey_t, collide, void,
377 private_ike_rekey_t* this, task_t *other)
378 {
379 DBG1(DBG_IKE, "detected %N collision with %N", task_type_names,
380 TASK_IKE_REKEY, task_type_names, other->get_type(other));
381 DESTROY_IF(this->collision);
382 this->collision = other;
383 }
384
385 /**
386 * Cleanup the task
387 */
388 static void cleanup(private_ike_rekey_t *this)
389 {
390 ike_sa_t *cur_sa;
391
392 if (this->ike_init)
393 {
394 this->ike_init->task.destroy(&this->ike_init->task);
395 }
396 if (this->ike_delete)
397 {
398 this->ike_delete->task.destroy(&this->ike_delete->task);
399 }
400 cur_sa = charon->bus->get_sa(charon->bus);
401 DESTROY_IF(this->new_sa);
402 charon->bus->set_sa(charon->bus, cur_sa);
403 DESTROY_IF(this->collision);
404 }
405
406 METHOD(task_t, migrate, void,
407 private_ike_rekey_t *this, ike_sa_t *ike_sa)
408 {
409 cleanup(this);
410 this->collision = NULL;
411 this->ike_sa = ike_sa;
412 this->new_sa = NULL;
413 this->ike_init = NULL;
414 this->ike_delete = NULL;
415 }
416
417 METHOD(task_t, destroy, void,
418 private_ike_rekey_t *this)
419 {
420 cleanup(this);
421 free(this);
422 }
423
424 /*
425 * Described in header.
426 */
427 ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator)
428 {
429 private_ike_rekey_t *this;
430
431 INIT(this,
432 .public = {
433 .task = {
434 .get_type = _get_type,
435 .build = _build_r,
436 .process = _process_r,
437 .migrate = _migrate,
438 .destroy = _destroy,
439 },
440 .collide = _collide,
441 },
442 .ike_sa = ike_sa,
443 .initiator = initiator,
444 );
445 if (initiator)
446 {
447 this->public.task.build = _build_i;
448 this->public.task.process = _process_i;
449 }
450
451 return &this->public;
452 }