353a1dba2288979c123d4173a7b10b3b272a1bc2
[strongswan.git] / src / libcharon / sa / tasks / quick_mode.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "quick_mode.h"
17
18 #include <string.h>
19
20 #include <daemon.h>
21 #include <sa/keymat_v1.h>
22 #include <encoding/payloads/sa_payload.h>
23 #include <encoding/payloads/nonce_payload.h>
24 #include <encoding/payloads/id_payload.h>
25
26 typedef struct private_quick_mode_t private_quick_mode_t;
27
28 /**
29 * Private members of a quick_mode_t task.
30 */
31 struct private_quick_mode_t {
32
33 /**
34 * Public methods and task_t interface.
35 */
36 quick_mode_t public;
37
38 /**
39 * Assigned IKE_SA.
40 */
41 ike_sa_t *ike_sa;
42
43 /**
44 * TRUE if we are initiating quick mode
45 */
46 bool initiator;
47
48 /**
49 * Traffic selector of initiator
50 */
51 traffic_selector_t *tsi;
52
53 /**
54 * Traffic selector of responder
55 */
56 traffic_selector_t *tsr;
57
58 /**
59 * Initiators nonce
60 */
61 chunk_t nonce_i;
62
63 /**
64 * Responder nonce
65 */
66 chunk_t nonce_r;
67
68 /**
69 * Initiators ESP SPI
70 */
71 u_int32_t spi_i;
72
73 /**
74 * Responder ESP SPI
75 */
76 u_int32_t spi_r;
77
78 /**
79 * selected CHILD_SA proposal
80 */
81 proposal_t *proposal;
82
83 /**
84 * Config of CHILD_SA to establish
85 */
86 child_cfg_t *config;
87
88 /**
89 * CHILD_SA we are about to establish
90 */
91 child_sa_t *child_sa;
92
93 /**
94 * IKEv1 keymat
95 */
96 keymat_v1_t *keymat;
97
98 /**
99 * Negotiated lifetime of new SA
100 */
101 u_int32_t lifetime;
102
103 /**
104 * Negotaited lifebytes of new SA
105 */
106 u_int64_t lifebytes;
107
108 /** states of quick mode */
109 enum {
110 QM_INIT,
111 QM_NEGOTIATED,
112 } state;
113 };
114
115 /**
116 * Install negotiated CHILD_SA
117 */
118 static bool install(private_quick_mode_t *this)
119 {
120 status_t status, status_i, status_o;
121 chunk_t encr_i, encr_r, integ_i, integ_r;
122 linked_list_t *tsi, *tsr;
123
124 this->child_sa->set_proposal(this->child_sa, this->proposal);
125 this->child_sa->set_state(this->child_sa, CHILD_INSTALLING);
126 this->child_sa->set_mode(this->child_sa, MODE_TUNNEL);
127 this->child_sa->set_protocol(this->child_sa,
128 this->proposal->get_protocol(this->proposal));
129
130 status_i = status_o = FAILED;
131 encr_i = encr_r = integ_i = integ_r = chunk_empty;
132 tsi = linked_list_create();
133 tsr = linked_list_create();
134 tsi->insert_last(tsi, this->tsi);
135 tsr->insert_last(tsr, this->tsr);
136 if (this->keymat->derive_child_keys(this->keymat, this->proposal, NULL,
137 this->spi_i, this->spi_r, this->nonce_i, this->nonce_r,
138 &encr_i, &integ_i, &encr_r, &integ_r))
139 {
140 if (this->initiator)
141 {
142 status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
143 this->spi_i, 0, TRUE, FALSE, tsi, tsr);
144 status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
145 this->spi_r, 0, FALSE, FALSE, tsi, tsr);
146 }
147 else
148 {
149 status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
150 this->spi_r, 0, TRUE, FALSE, tsr, tsi);
151 status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
152 this->spi_i, 0, FALSE, FALSE, tsr, tsi);
153 }
154 }
155 chunk_clear(&integ_i);
156 chunk_clear(&integ_r);
157 chunk_clear(&encr_i);
158 chunk_clear(&encr_r);
159
160 if (status_i != SUCCESS || status_o != SUCCESS)
161 {
162 DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel",
163 (status_i != SUCCESS) ? "inbound " : "",
164 (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
165 (status_o != SUCCESS) ? "outbound " : "");
166 tsi->destroy(tsi);
167 tsr->destroy(tsr);
168 return FALSE;
169 }
170
171 if (this->initiator)
172 {
173 status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
174 }
175 else
176 {
177 status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
178 }
179 tsi->destroy(tsi);
180 tsr->destroy(tsr);
181 if (status != SUCCESS)
182 {
183 DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
184 return FALSE;
185 }
186
187 charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
188 NULL, this->nonce_i, this->nonce_r);
189
190 /* add to IKE_SA, and remove from task */
191 this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
192 this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
193
194 DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
195 "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
196 this->child_sa->get_name(this->child_sa),
197 this->child_sa->get_reqid(this->child_sa),
198 ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
199 ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
200 this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
201 this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
202
203 charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
204
205 this->child_sa = NULL;
206
207 return TRUE;
208 }
209
210 /**
211 * Generate and add NONCE
212 */
213 static bool add_nonce(private_quick_mode_t *this, chunk_t *nonce,
214 message_t *message)
215 {
216 nonce_payload_t *nonce_payload;
217 rng_t *rng;
218
219 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
220 if (!rng)
221 {
222 DBG1(DBG_IKE, "no RNG found to create nonce");
223 return FALSE;
224 }
225 rng->allocate_bytes(rng, NONCE_SIZE, nonce);
226 rng->destroy(rng);
227
228 nonce_payload = nonce_payload_create(NONCE_V1);
229 nonce_payload->set_nonce(nonce_payload, *nonce);
230 message->add_payload(message, &nonce_payload->payload_interface);
231
232 return TRUE;
233 }
234
235 /**
236 * Extract nonce from NONCE payload
237 */
238 static bool get_nonce(private_quick_mode_t *this, chunk_t *nonce,
239 message_t *message)
240 {
241 nonce_payload_t *nonce_payload;
242
243 nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1);
244 if (!nonce_payload)
245 {
246 DBG1(DBG_IKE, "NONCE payload missing in message");
247 return FALSE;
248 }
249 *nonce = nonce_payload->get_nonce(nonce_payload);
250
251 return TRUE;
252 }
253
254 /**
255 * Select a traffic selector from configuration
256 */
257 static traffic_selector_t* select_ts(private_quick_mode_t *this, bool initiator)
258 {
259 traffic_selector_t *ts;
260 linked_list_t *list;
261 host_t *host;
262
263 if (initiator)
264 {
265 host = this->ike_sa->get_my_host(this->ike_sa);
266 }
267 else
268 {
269 host = this->ike_sa->get_other_host(this->ike_sa);
270 }
271 list = this->config->get_traffic_selectors(this->config, initiator,
272 NULL, host);
273 if (list->get_first(list, (void**)&ts) == SUCCESS)
274 {
275 if (list->get_count(list) > 1)
276 {
277 DBG1(DBG_IKE, "configuration has more than one %s traffic selector,"
278 " using first only", initiator ? "initiator" : "responder");
279 }
280 ts = ts->clone(ts);
281 }
282 else
283 {
284 DBG1(DBG_IKE, "%s traffic selector missing in configuration",
285 initiator ? "initiator" : "responder");
286 ts = NULL;
287 }
288 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
289 return ts;
290 }
291
292 /**
293 * Add selected traffic selectors to message
294 */
295 static void add_ts(private_quick_mode_t *this, message_t *message)
296 {
297 id_payload_t *id_payload;
298 host_t *hsi, *hsr;
299
300 if (this->initiator)
301 {
302 hsi = this->ike_sa->get_my_host(this->ike_sa);
303 hsr = this->ike_sa->get_other_host(this->ike_sa);
304 }
305 else
306 {
307 hsr = this->ike_sa->get_my_host(this->ike_sa);
308 hsi = this->ike_sa->get_other_host(this->ike_sa);
309 }
310 /* add ID payload only if negotiating non host2host tunnels */
311 if (!this->tsi->is_host(this->tsi, hsi) ||
312 !this->tsr->is_host(this->tsr, hsr) ||
313 this->tsi->get_protocol(this->tsi) ||
314 this->tsr->get_protocol(this->tsr) ||
315 this->tsi->get_from_port(this->tsi) ||
316 this->tsr->get_from_port(this->tsr) ||
317 this->tsi->get_to_port(this->tsi) != 65535 ||
318 this->tsr->get_to_port(this->tsr) != 65535)
319 {
320 id_payload = id_payload_create_from_ts(this->tsi);
321 message->add_payload(message, &id_payload->payload_interface);
322 id_payload = id_payload_create_from_ts(this->tsr);
323 message->add_payload(message, &id_payload->payload_interface);
324 }
325 }
326
327 /**
328 * Get traffic selectors from received message
329 */
330 static bool get_ts(private_quick_mode_t *this, message_t *message)
331 {
332 traffic_selector_t *tsi = NULL, *tsr = NULL;
333 enumerator_t *enumerator;
334 id_payload_t *id_payload;
335 payload_t *payload;
336 host_t *hsi, *hsr;
337 bool first = TRUE;
338
339 enumerator = message->create_payload_enumerator(message);
340 while (enumerator->enumerate(enumerator, &payload))
341 {
342 if (payload->get_type(payload) == ID_V1)
343 {
344 id_payload = (id_payload_t*)payload;
345
346 if (first)
347 {
348 tsi = id_payload->get_ts(id_payload);
349 first = FALSE;
350 }
351 else
352 {
353 tsr = id_payload->get_ts(id_payload);
354 break;
355 }
356 }
357 }
358 enumerator->destroy(enumerator);
359
360 /* create host2host selectors if ID payloads missing */
361 if (this->initiator)
362 {
363 hsi = this->ike_sa->get_my_host(this->ike_sa);
364 hsr = this->ike_sa->get_other_host(this->ike_sa);
365 }
366 else
367 {
368 hsr = this->ike_sa->get_my_host(this->ike_sa);
369 hsi = this->ike_sa->get_other_host(this->ike_sa);
370 }
371 if (!tsi)
372 {
373 tsi = traffic_selector_create_from_subnet(hsi->clone(hsi),
374 hsi->get_family(hsi) == AF_INET ? 32 : 128, 0, 0);
375 }
376 if (!tsr)
377 {
378 tsr = traffic_selector_create_from_subnet(hsr->clone(hsr),
379 hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0);
380 }
381 if (this->initiator)
382 {
383 /* check if peer selection valid */
384 if (!tsr->is_contained_in(tsr, this->tsr) ||
385 !tsi->is_contained_in(tsi, this->tsi))
386 {
387 DBG1(DBG_IKE, "peer selected invalid traffic selectors: ",
388 "%R for %R, %R for %R", tsi, this->tsi, tsr, this->tsr);
389 tsi->destroy(tsi);
390 tsr->destroy(tsr);
391 return FALSE;
392 }
393 this->tsi->destroy(this->tsi);
394 this->tsr->destroy(this->tsr);
395 this->tsi = tsi;
396 this->tsr = tsr;
397 }
398 else
399 {
400 this->tsi = tsi;
401 this->tsr = tsr;
402 }
403 return TRUE;
404 }
405
406 /**
407 * Look up lifetimes
408 */
409 static void get_lifetimes(private_quick_mode_t *this)
410 {
411 lifetime_cfg_t *lft;
412
413 lft = this->config->get_lifetime(this->config);
414 if (lft->time.life)
415 {
416 this->lifetime = lft->time.life;
417 }
418 else if (lft->bytes.life)
419 {
420 this->lifebytes = lft->bytes.life;
421 }
422 free(lft);
423 }
424
425 /**
426 * Check and apply lifetimes
427 */
428 static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload)
429 {
430 u_int32_t lifetime;
431 u_int64_t lifebytes;
432
433 lifetime = sa_payload->get_lifetime(sa_payload);
434 lifebytes = sa_payload->get_lifebytes(sa_payload);
435 if (this->lifetime != lifetime)
436 {
437 DBG1(DBG_IKE, "received %us lifetime, configured %us, using lower",
438 lifetime, this->lifetime);
439 this->lifetime = min(this->lifetime, lifetime);
440 }
441 if (this->lifebytes != lifebytes)
442 {
443 DBG1(DBG_IKE, "received %llu lifebytes, configured %llu, using lower",
444 lifebytes, this->lifebytes);
445 this->lifebytes = min(this->lifebytes, lifebytes);
446 }
447 }
448
449 METHOD(task_t, build_i, status_t,
450 private_quick_mode_t *this, message_t *message)
451 {
452 switch (this->state)
453 {
454 case QM_INIT:
455 {
456 enumerator_t *enumerator;
457 sa_payload_t *sa_payload;
458 linked_list_t *list;
459 proposal_t *proposal;
460
461 this->child_sa = child_sa_create(
462 this->ike_sa->get_my_host(this->ike_sa),
463 this->ike_sa->get_other_host(this->ike_sa),
464 this->config, 0, FALSE);
465
466 list = this->config->get_proposals(this->config, TRUE);
467
468 this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
469 if (!this->spi_i)
470 {
471 DBG1(DBG_IKE, "allocating SPI from kernel failed");
472 return FAILED;
473 }
474 enumerator = list->create_enumerator(list);
475 while (enumerator->enumerate(enumerator, &proposal))
476 {
477 proposal->set_spi(proposal, this->spi_i);
478 }
479 enumerator->destroy(enumerator);
480
481 get_lifetimes(this);
482 sa_payload = sa_payload_create_from_proposals_v1(list,
483 this->lifetime, this->lifebytes, AUTH_NONE,
484 this->config->get_mode(this->config), FALSE);
485 list->destroy_offset(list, offsetof(proposal_t, destroy));
486 message->add_payload(message, &sa_payload->payload_interface);
487
488 if (!add_nonce(this, &this->nonce_i, message))
489 {
490 return FAILED;
491 }
492 this->tsi = select_ts(this, TRUE);
493 this->tsr = select_ts(this, FALSE);
494 if (!this->tsi || !this->tsr)
495 {
496 return FAILED;
497 }
498 add_ts(this, message);
499 return NEED_MORE;
500 }
501 case QM_NEGOTIATED:
502 {
503 return SUCCESS;
504 }
505 default:
506 return FAILED;
507 }
508 }
509
510 METHOD(task_t, process_r, status_t,
511 private_quick_mode_t *this, message_t *message)
512 {
513 switch (this->state)
514 {
515 case QM_INIT:
516 {
517 sa_payload_t *sa_payload;
518 linked_list_t *tsi, *tsr, *list;
519 peer_cfg_t *peer_cfg;
520 host_t *me, *other;
521
522 if (!get_ts(this, message))
523 {
524 return FAILED;
525 }
526 me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
527 if (!me)
528 {
529 me = this->ike_sa->get_my_host(this->ike_sa);
530 }
531 other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
532 if (!other)
533 {
534 other = this->ike_sa->get_other_host(this->ike_sa);
535 }
536 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
537 tsi = linked_list_create();
538 tsr = linked_list_create();
539 tsi->insert_last(tsi, this->tsi);
540 tsr->insert_last(tsr, this->tsr);
541 this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
542 me, other);
543 tsi->destroy(tsi);
544 tsr->destroy(tsr);
545 if (!this->config)
546 {
547 DBG1(DBG_IKE, "no child config found");
548 return FAILED;
549 }
550
551 sa_payload = (sa_payload_t*)message->get_payload(message,
552 SECURITY_ASSOCIATION_V1);
553 if (!sa_payload)
554 {
555 DBG1(DBG_IKE, "sa payload missing");
556 return FAILED;
557 }
558 list = sa_payload->get_proposals(sa_payload);
559 this->proposal = this->config->select_proposal(this->config,
560 list, TRUE, FALSE);
561 list->destroy_offset(list, offsetof(proposal_t, destroy));
562
563 get_lifetimes(this);
564 apply_lifetimes(this, sa_payload);
565
566 if (!this->proposal)
567 {
568 DBG1(DBG_IKE, "no matching proposal found");
569 return FAILED;
570 }
571 this->spi_i = this->proposal->get_spi(this->proposal);
572
573 if (!get_nonce(this, &this->nonce_i, message))
574 {
575 return FAILED;
576 }
577
578
579 this->child_sa = child_sa_create(
580 this->ike_sa->get_my_host(this->ike_sa),
581 this->ike_sa->get_other_host(this->ike_sa),
582 this->config, 0, FALSE);
583 return NEED_MORE;
584 }
585 case QM_NEGOTIATED:
586 {
587 if (!install(this))
588 {
589 return FAILED;
590 }
591 return SUCCESS;
592 }
593 default:
594 return FAILED;
595 }
596 }
597
598 METHOD(task_t, build_r, status_t,
599 private_quick_mode_t *this, message_t *message)
600 {
601 switch (this->state)
602 {
603 case QM_INIT:
604 {
605 sa_payload_t *sa_payload;
606
607 this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
608 if (!this->spi_r)
609 {
610 DBG1(DBG_IKE, "allocating SPI from kernel failed");
611 return FAILED;
612 }
613 this->proposal->set_spi(this->proposal, this->spi_r);
614
615 sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
616 this->lifetime, this->lifebytes, AUTH_NONE,
617 this->config->get_mode(this->config), FALSE);
618 message->add_payload(message, &sa_payload->payload_interface);
619
620 if (!add_nonce(this, &this->nonce_r, message))
621 {
622 return FAILED;
623 }
624 add_ts(this, message);
625
626 this->state = QM_NEGOTIATED;
627 return NEED_MORE;
628 }
629 default:
630 return FAILED;
631 }
632 }
633
634 METHOD(task_t, process_i, status_t,
635 private_quick_mode_t *this, message_t *message)
636 {
637 switch (this->state)
638 {
639 case QM_INIT:
640 {
641 sa_payload_t *sa_payload;
642 linked_list_t *list;
643
644 sa_payload = (sa_payload_t*)message->get_payload(message,
645 SECURITY_ASSOCIATION_V1);
646 if (!sa_payload)
647 {
648 DBG1(DBG_IKE, "sa payload missing");
649 return FAILED;
650 }
651 list = sa_payload->get_proposals(sa_payload);
652 this->proposal = this->config->select_proposal(this->config,
653 list, TRUE, FALSE);
654 list->destroy_offset(list, offsetof(proposal_t, destroy));
655 if (!this->proposal)
656 {
657 DBG1(DBG_IKE, "no matching proposal found");
658 return FAILED;
659 }
660 this->spi_r = this->proposal->get_spi(this->proposal);
661
662 apply_lifetimes(this, sa_payload);
663
664 if (!get_nonce(this, &this->nonce_r, message))
665 {
666 return FAILED;
667 }
668 if (!get_ts(this, message))
669 {
670 return FAILED;
671 }
672 if (!install(this))
673 {
674 return FAILED;
675 }
676 this->state = QM_NEGOTIATED;
677 return NEED_MORE;
678 }
679 default:
680 return FAILED;
681 }
682 }
683
684 METHOD(task_t, get_type, task_type_t,
685 private_quick_mode_t *this)
686 {
687 return TASK_QUICK_MODE;
688 }
689
690 METHOD(task_t, migrate, void,
691 private_quick_mode_t *this, ike_sa_t *ike_sa)
692 {
693 this->ike_sa = ike_sa;
694 }
695
696 METHOD(task_t, destroy, void,
697 private_quick_mode_t *this)
698 {
699 chunk_free(&this->nonce_i);
700 chunk_free(&this->nonce_r);
701 DESTROY_IF(this->tsi);
702 DESTROY_IF(this->tsr);
703 DESTROY_IF(this->proposal);
704 DESTROY_IF(this->child_sa);
705 DESTROY_IF(this->config);
706 free(this);
707 }
708
709 /*
710 * Described in header.
711 */
712 quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
713 traffic_selector_t *tsi, traffic_selector_t *tsr)
714 {
715 private_quick_mode_t *this;
716
717 INIT(this,
718 .public = {
719 .task = {
720 .get_type = _get_type,
721 .migrate = _migrate,
722 .destroy = _destroy,
723 },
724 },
725 .ike_sa = ike_sa,
726 .initiator = config != NULL,
727 .config = config,
728 .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
729 .state = QM_INIT,
730 );
731
732 if (config)
733 {
734 this->public.task.build = _build_i;
735 this->public.task.process = _process_i;
736 }
737 else
738 {
739 this->public.task.build = _build_r;
740 this->public.task.process = _process_r;
741 }
742
743 return &this->public;
744 }