Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/tasks/child_rekey.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2009-2018 Tobias Brunner
3: * Copyright (C) 2005-2007 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 "child_rekey.h"
19:
20: #include <daemon.h>
21: #include <encoding/payloads/notify_payload.h>
22: #include <sa/ikev2/tasks/child_create.h>
23: #include <sa/ikev2/tasks/child_delete.h>
24: #include <processing/jobs/rekey_child_sa_job.h>
25: #include <processing/jobs/rekey_ike_sa_job.h>
26:
27:
28: typedef struct private_child_rekey_t private_child_rekey_t;
29:
30: /**
31: * Private members of a child_rekey_t task.
32: */
33: struct private_child_rekey_t {
34:
35: /**
36: * Public methods and task_t interface.
37: */
38: child_rekey_t public;
39:
40: /**
41: * Assigned IKE_SA.
42: */
43: ike_sa_t *ike_sa;
44:
45: /**
46: * Are we the initiator?
47: */
48: bool initiator;
49:
50: /**
51: * Protocol of CHILD_SA to rekey
52: */
53: protocol_id_t protocol;
54:
55: /**
56: * Inbound SPI of CHILD_SA to rekey
57: */
58: uint32_t spi;
59:
60: /**
61: * the CHILD_CREATE task which is reused to simplify rekeying
62: */
63: child_create_t *child_create;
64:
65: /**
66: * the CHILD_DELETE task to delete rekeyed CHILD_SA
67: */
68: child_delete_t *child_delete;
69:
70: /**
71: * CHILD_SA which gets rekeyed
72: */
73: child_sa_t *child_sa;
74:
75: /**
76: * colliding task, may be delete or rekey
77: */
78: task_t *collision;
79:
80: /**
81: * Indicate that peer destroyed the redundant child from collision.
82: * This happens if a peer's delete notification for the redundant
83: * child gets processed before the rekey job. If so, we must not
84: * touch the child created in the collision since it points to
85: * memory already freed.
86: */
87: bool other_child_destroyed;
88: };
89:
90: /**
91: * Schedule a retry if rekeying temporary failed
92: */
93: static void schedule_delayed_rekey(private_child_rekey_t *this)
94: {
95: uint32_t retry;
96: job_t *job;
97:
98: retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
99: job = (job_t*)rekey_child_sa_job_create(
100: this->child_sa->get_protocol(this->child_sa),
101: this->child_sa->get_spi(this->child_sa, TRUE),
102: this->ike_sa->get_my_host(this->ike_sa));
103: DBG1(DBG_IKE, "CHILD_SA rekeying failed, trying again in %d seconds", retry);
104: this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
105: lib->scheduler->schedule_job(lib->scheduler, job, retry);
106: }
107:
108: /**
109: * Implementation of task_t.build for initiator, after rekeying
110: */
111: static status_t build_i_delete(private_child_rekey_t *this, message_t *message)
112: {
113: /* update exchange type to INFORMATIONAL for the delete */
114: message->set_exchange_type(message, INFORMATIONAL);
115:
116: return this->child_delete->task.build(&this->child_delete->task, message);
117: }
118:
119: /**
120: * Implementation of task_t.process for initiator, after rekeying
121: */
122: static status_t process_i_delete(private_child_rekey_t *this, message_t *message)
123: {
124: return this->child_delete->task.process(&this->child_delete->task, message);
125: }
126:
127: /**
128: * find a child using the REKEY_SA notify
129: */
130: static void find_child(private_child_rekey_t *this, message_t *message)
131: {
132: notify_payload_t *notify;
133: protocol_id_t protocol;
134: uint32_t spi;
135: child_sa_t *child_sa;
136:
137: notify = message->get_notify(message, REKEY_SA);
138: if (notify)
139: {
140: protocol = notify->get_protocol_id(notify);
141: spi = notify->get_spi(notify);
142:
143: if (protocol == PROTO_ESP || protocol == PROTO_AH)
144: {
145: child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
146: spi, FALSE);
147: if (child_sa &&
148: child_sa->get_state(child_sa) == CHILD_DELETED)
149: { /* ignore rekeyed CHILD_SAs we keep around */
150: return;
151: }
152: this->child_sa = child_sa;
153: }
154: }
155: }
156:
157: METHOD(task_t, build_i, status_t,
158: private_child_rekey_t *this, message_t *message)
159: {
160: notify_payload_t *notify;
161: uint32_t reqid;
162: child_cfg_t *config;
163:
164: this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
165: this->spi, TRUE);
166: if (!this->child_sa)
167: { /* check if it is an outbound CHILD_SA */
168: this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
169: this->spi, FALSE);
170: if (this->child_sa)
171: {
172: /* we work only with the inbound SPI */
173: this->spi = this->child_sa->get_spi(this->child_sa, TRUE);
174: }
175: }
176: if (!this->child_sa ||
177: (!this->child_create &&
178: this->child_sa->get_state(this->child_sa) != CHILD_INSTALLED) ||
179: (this->child_create &&
180: this->child_sa->get_state(this->child_sa) != CHILD_REKEYING))
181: {
182: /* CHILD_SA is gone or in the wrong state, unable to rekey */
183: message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
184: return SUCCESS;
185: }
186: config = this->child_sa->get_config(this->child_sa);
187:
188:
189: /* our CHILD_CREATE task does the hard work for us */
190: if (!this->child_create)
191: {
192: proposal_t *proposal;
193: uint16_t dh_group;
194:
195: this->child_create = child_create_create(this->ike_sa,
196: config->get_ref(config), TRUE, NULL, NULL);
197:
198: proposal = this->child_sa->get_proposal(this->child_sa);
199: if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP,
200: &dh_group, NULL))
201: { /* reuse the DH group negotiated previously */
202: this->child_create->use_dh_group(this->child_create, dh_group);
203: }
204: }
205: reqid = this->child_sa->get_reqid(this->child_sa);
206: this->child_create->use_reqid(this->child_create, reqid);
207: this->child_create->use_marks(this->child_create,
208: this->child_sa->get_mark(this->child_sa, TRUE).value,
209: this->child_sa->get_mark(this->child_sa, FALSE).value);
210: this->child_create->use_if_ids(this->child_create,
211: this->child_sa->get_if_id(this->child_sa, TRUE),
212: this->child_sa->get_if_id(this->child_sa, FALSE));
213:
214: if (this->child_create->task.build(&this->child_create->task,
215: message) != NEED_MORE)
216: {
217: schedule_delayed_rekey(this);
218: message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
219: return SUCCESS;
220: }
221: if (message->get_exchange_type(message) == CREATE_CHILD_SA)
222: {
223: /* don't add the notify if the CHILD_CREATE task changed the exchange */
224: notify = notify_payload_create_from_protocol_and_type(PLV2_NOTIFY,
225: this->protocol, REKEY_SA);
226: notify->set_spi(notify, this->spi);
227: message->add_payload(message, (payload_t*)notify);
228: }
229: this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
230:
231: return NEED_MORE;
232: }
233:
234: METHOD(task_t, process_r, status_t,
235: private_child_rekey_t *this, message_t *message)
236: {
237: /* let the CHILD_CREATE task process the message */
238: this->child_create->task.process(&this->child_create->task, message);
239:
240: find_child(this, message);
241:
242: return NEED_MORE;
243: }
244:
245: METHOD(task_t, build_r, status_t,
246: private_child_rekey_t *this, message_t *message)
247: {
248: child_cfg_t *config;
249: uint32_t reqid;
250: child_sa_state_t state;
251: child_sa_t *child_sa;
252:
253: if (!this->child_sa)
254: {
255: DBG1(DBG_IKE, "unable to rekey, CHILD_SA not found");
256: message->add_notify(message, TRUE, CHILD_SA_NOT_FOUND, chunk_empty);
257: return SUCCESS;
258: }
259: if (this->child_sa->get_state(this->child_sa) == CHILD_DELETING)
260: {
261: DBG1(DBG_IKE, "unable to rekey, we are deleting the CHILD_SA");
262: message->add_notify(message, TRUE, TEMPORARY_FAILURE, chunk_empty);
263: return SUCCESS;
264: }
265:
266: /* let the CHILD_CREATE task build the response */
267: reqid = this->child_sa->get_reqid(this->child_sa);
268: this->child_create->use_reqid(this->child_create, reqid);
269: this->child_create->use_marks(this->child_create,
270: this->child_sa->get_mark(this->child_sa, TRUE).value,
271: this->child_sa->get_mark(this->child_sa, FALSE).value);
272: this->child_create->use_if_ids(this->child_create,
273: this->child_sa->get_if_id(this->child_sa, TRUE),
274: this->child_sa->get_if_id(this->child_sa, FALSE));
275: config = this->child_sa->get_config(this->child_sa);
276: this->child_create->set_config(this->child_create, config->get_ref(config));
277: this->child_create->task.build(&this->child_create->task, message);
278:
279: state = this->child_sa->get_state(this->child_sa);
280: this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
281:
282: if (message->get_payload(message, PLV2_SECURITY_ASSOCIATION) == NULL)
283: { /* rekeying failed, reuse old child */
284: this->child_sa->set_state(this->child_sa, state);
285: return SUCCESS;
286: }
287:
288: child_sa = this->child_create->get_child(this->child_create);
289: this->child_sa->set_state(this->child_sa, CHILD_REKEYED);
290: this->child_sa->set_rekey_spi(this->child_sa,
291: child_sa->get_spi(child_sa, FALSE));
292:
293: /* invoke rekey hook */
294: charon->bus->child_rekey(charon->bus, this->child_sa,
295: this->child_create->get_child(this->child_create));
296: return SUCCESS;
297: }
298:
299: /**
300: * Handle a rekey collision
301: */
302: static child_sa_t *handle_collision(private_child_rekey_t *this,
303: child_sa_t **to_install)
304: {
305: child_sa_t *to_delete;
306:
307: if (this->collision->get_type(this->collision) == TASK_CHILD_REKEY)
308: {
309: chunk_t this_nonce, other_nonce;
310: private_child_rekey_t *other = (private_child_rekey_t*)this->collision;
311:
312: this_nonce = this->child_create->get_lower_nonce(this->child_create);
313: other_nonce = other->child_create->get_lower_nonce(other->child_create);
314:
315: /* if we have the lower nonce, delete rekeyed SA. If not, delete
316: * the redundant. */
317: if (memcmp(this_nonce.ptr, other_nonce.ptr,
318: min(this_nonce.len, other_nonce.len)) > 0)
319: {
320: child_sa_t *child_sa;
321:
322: *to_install = this->child_create->get_child(this->child_create);
323: to_delete = this->child_sa;
324: DBG1(DBG_IKE, "CHILD_SA rekey collision won, deleting old child "
325: "%s{%d}", to_delete->get_name(to_delete),
326: to_delete->get_unique_id(to_delete));
327: /* don't touch child other created, it has already been deleted */
328: if (!this->other_child_destroyed)
329: {
330: /* disable close action and updown event for redundant child */
331: child_sa = other->child_create->get_child(other->child_create);
332: if (child_sa)
333: {
334: child_sa->set_close_action(child_sa, ACTION_NONE);
335: if (child_sa->get_state(child_sa) != CHILD_REKEYED)
336: {
337: child_sa->set_state(child_sa, CHILD_REKEYED);
338: }
339: }
340: }
341: }
342: else
343: {
344: to_delete = this->child_create->get_child(this->child_create);
345: DBG1(DBG_IKE, "CHILD_SA rekey collision lost, deleting redundant "
346: "child %s{%d}", to_delete->get_name(to_delete),
347: to_delete->get_unique_id(to_delete));
348: }
349: }
350: else
351: { /* CHILD_DELETE */
352: child_delete_t *del = (child_delete_t*)this->collision;
353:
354: /* we didn't had a chance to compare the nonces, so we delete
355: * the CHILD_SA the other is not deleting. */
356: if (del->get_child(del) != this->child_sa)
357: {
358: to_delete = this->child_sa;
359: DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, deleting old child "
360: "%s{%d}", to_delete->get_name(to_delete),
361: to_delete->get_unique_id(to_delete));
362: }
363: else
364: {
365: to_delete = this->child_create->get_child(this->child_create);
366: DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, deleting redundant "
367: "child %s{%d}", to_delete->get_name(to_delete),
368: to_delete->get_unique_id(to_delete));
369: }
370: }
371: return to_delete;
372: }
373:
374: METHOD(task_t, process_i, status_t,
375: private_child_rekey_t *this, message_t *message)
376: {
377: protocol_id_t protocol;
378: uint32_t spi;
379: child_sa_t *to_delete, *to_install = NULL;
380:
381: if (message->get_notify(message, NO_ADDITIONAL_SAS))
382: {
383: DBG1(DBG_IKE, "peer seems to not support CHILD_SA rekeying, "
384: "starting reauthentication");
385: this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
386: lib->processor->queue_job(lib->processor,
387: (job_t*)rekey_ike_sa_job_create(
388: this->ike_sa->get_id(this->ike_sa), TRUE));
389: return SUCCESS;
390: }
391: if (message->get_notify(message, CHILD_SA_NOT_FOUND))
392: {
393: child_cfg_t *child_cfg;
394: uint32_t reqid;
395:
396: if (this->collision &&
397: this->collision->get_type(this->collision) == TASK_CHILD_DELETE)
398: { /* ignore this error if we already deleted the CHILD_SA on the
399: * peer's behalf (could happen if the other peer does not detect
400: * the collision and did not respond with TEMPORARY_FAILURE) */
401: return SUCCESS;
402: }
403: DBG1(DBG_IKE, "peer didn't find the CHILD_SA we tried to rekey");
404: /* FIXME: according to RFC 7296 we should only create a new CHILD_SA if
405: * it does not exist yet, we currently have no good way of checking for
406: * that (we could go by name, but that might be tricky e.g. due to
407: * narrowing) */
408: spi = this->child_sa->get_spi(this->child_sa, TRUE);
409: reqid = this->child_sa->get_reqid(this->child_sa);
410: protocol = this->child_sa->get_protocol(this->child_sa);
411: child_cfg = this->child_sa->get_config(this->child_sa);
412: child_cfg->get_ref(child_cfg);
413: charon->bus->child_updown(charon->bus, this->child_sa, FALSE);
414: this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
415: return this->ike_sa->initiate(this->ike_sa,
416: child_cfg->get_ref(child_cfg), reqid,
417: NULL, NULL);
418: }
419:
420: if (this->child_create->task.process(&this->child_create->task,
421: message) == NEED_MORE)
422: {
423: /* bad DH group while rekeying, retry, or failure requiring deletion */
424: return NEED_MORE;
425: }
426: if (message->get_payload(message, PLV2_SECURITY_ASSOCIATION) == NULL)
427: {
428: /* establishing new child failed, reuse old and try again. but not when
429: * we received a delete in the meantime */
430: if (!this->collision ||
431: this->collision->get_type(this->collision) != TASK_CHILD_DELETE)
432: {
433: schedule_delayed_rekey(this);
434: }
435: return SUCCESS;
436: }
437:
438: /* check for rekey collisions */
439: if (this->collision)
440: {
441: to_delete = handle_collision(this, &to_install);
442: }
443: else
444: {
445: to_install = this->child_create->get_child(this->child_create);
446: to_delete = this->child_sa;
447: }
448: if (to_install)
449: {
450: if (to_install->install_outbound(to_install) != SUCCESS)
451: {
452: DBG1(DBG_IKE, "unable to install outbound IPsec SA (SAD) in kernel");
453: charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
454: to_install);
455: /* FIXME: delete the child_sa? fail the task? */
456: }
457: else
458: {
459: linked_list_t *my_ts, *other_ts;
460:
461: my_ts = linked_list_create_from_enumerator(
462: to_install->create_ts_enumerator(to_install, TRUE));
463: other_ts = linked_list_create_from_enumerator(
464: to_install->create_ts_enumerator(to_install, FALSE));
465:
466: DBG0(DBG_IKE, "outbound CHILD_SA %s{%d} established "
467: "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
468: to_install->get_name(to_install),
469: to_install->get_unique_id(to_install),
470: ntohl(to_install->get_spi(to_install, TRUE)),
471: ntohl(to_install->get_spi(to_install, FALSE)),
472: my_ts, other_ts);
473:
474: my_ts->destroy(my_ts);
475: other_ts->destroy(other_ts);
476: }
477: }
478: if (to_delete != this->child_create->get_child(this->child_create))
479: { /* invoke rekey hook if rekeying successful */
480: charon->bus->child_rekey(charon->bus, this->child_sa,
481: this->child_create->get_child(this->child_create));
482: }
483: if (to_delete == NULL)
484: {
485: return SUCCESS;
486: }
487: /* disable updown event for redundant CHILD_SA */
488: if (to_delete->get_state(to_delete) != CHILD_REKEYED)
489: {
490: to_delete->set_state(to_delete, CHILD_REKEYED);
491: }
492: spi = to_delete->get_spi(to_delete, TRUE);
493: protocol = to_delete->get_protocol(to_delete);
494:
495: /* rekeying done, delete the obsolete CHILD_SA using a subtask */
496: this->child_delete = child_delete_create(this->ike_sa, protocol, spi, FALSE);
497: this->public.task.build = (status_t(*)(task_t*,message_t*))build_i_delete;
498: this->public.task.process = (status_t(*)(task_t*,message_t*))process_i_delete;
499:
500: return NEED_MORE;
501: }
502:
503: METHOD(task_t, get_type, task_type_t,
504: private_child_rekey_t *this)
505: {
506: return TASK_CHILD_REKEY;
507: }
508:
509: METHOD(child_rekey_t, is_redundant, bool,
510: private_child_rekey_t *this, child_sa_t *child)
511: {
512: if (this->collision &&
513: this->collision->get_type(this->collision) == TASK_CHILD_REKEY)
514: {
515: private_child_rekey_t *rekey = (private_child_rekey_t*)this->collision;
516: return child == rekey->child_create->get_child(rekey->child_create);
517: }
518: return FALSE;
519: }
520:
521: METHOD(child_rekey_t, collide, void,
522: private_child_rekey_t *this, task_t *other)
523: {
524: /* the task manager only detects exchange collision, but not if
525: * the collision is for the same child. we check it here. */
526: if (other->get_type(other) == TASK_CHILD_REKEY)
527: {
528: private_child_rekey_t *rekey = (private_child_rekey_t*)other;
529: child_sa_t *other_child;
530:
531: if (rekey->child_sa != this->child_sa)
532: { /* not the same child => no collision */
533: other->destroy(other);
534: return;
535: }
536: /* ignore passive tasks that did not successfully create a CHILD_SA */
537: other_child = rekey->child_create->get_child(rekey->child_create);
538: if (!other_child ||
539: other_child->get_state(other_child) != CHILD_INSTALLED)
540: {
541: other->destroy(other);
542: return;
543: }
544: }
545: else if (other->get_type(other) == TASK_CHILD_DELETE)
546: {
547: child_delete_t *del = (child_delete_t*)other;
548: if (is_redundant(this, del->get_child(del)))
549: {
550: this->other_child_destroyed = TRUE;
551: other->destroy(other);
552: return;
553: }
554: if (del->get_child(del) != this->child_sa)
555: {
556: /* not the same child => no collision */
557: other->destroy(other);
558: return;
559: }
560: }
561: else
562: {
563: /* any other task is not critical for collisions, ignore */
564: other->destroy(other);
565: return;
566: }
567: DBG1(DBG_IKE, "detected %N collision with %N", task_type_names,
568: TASK_CHILD_REKEY, task_type_names, other->get_type(other));
569: DESTROY_IF(this->collision);
570: this->collision = other;
571: }
572:
573: METHOD(task_t, migrate, void,
574: private_child_rekey_t *this, ike_sa_t *ike_sa)
575: {
576: if (this->child_create)
577: {
578: this->child_create->task.migrate(&this->child_create->task, ike_sa);
579: }
580: if (this->child_delete)
581: {
582: this->child_delete->task.migrate(&this->child_delete->task, ike_sa);
583: }
584: DESTROY_IF(this->collision);
585:
586: this->ike_sa = ike_sa;
587: this->collision = NULL;
588: }
589:
590: METHOD(task_t, destroy, void,
591: private_child_rekey_t *this)
592: {
593: if (this->child_create)
594: {
595: this->child_create->task.destroy(&this->child_create->task);
596: }
597: if (this->child_delete)
598: {
599: this->child_delete->task.destroy(&this->child_delete->task);
600: }
601: DESTROY_IF(this->collision);
602: free(this);
603: }
604:
605: /*
606: * Described in header.
607: */
608: child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol,
609: uint32_t spi)
610: {
611: private_child_rekey_t *this;
612:
613: INIT(this,
614: .public = {
615: .task = {
616: .get_type = _get_type,
617: .migrate = _migrate,
618: .destroy = _destroy,
619: },
620: .is_redundant = _is_redundant,
621: .collide = _collide,
622: },
623: .ike_sa = ike_sa,
624: .protocol = protocol,
625: .spi = spi,
626: );
627:
628: if (protocol != PROTO_NONE)
629: {
630: this->public.task.build = _build_i;
631: this->public.task.process = _process_i;
632: this->initiator = TRUE;
633: this->child_create = NULL;
634: }
635: else
636: {
637: this->public.task.build = _build_r;
638: this->public.task.process = _process_r;
639: this->initiator = FALSE;
640: this->child_create = child_create_create(ike_sa, NULL, TRUE, NULL, NULL);
641: }
642:
643: return &this->public;
644: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>