Cleaned up quick mode notify processing
[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/ke_payload.h>
25 #include <encoding/payloads/id_payload.h>
26 #include <encoding/payloads/payload.h>
27
28 typedef struct private_quick_mode_t private_quick_mode_t;
29
30 /**
31 * Private members of a quick_mode_t task.
32 */
33 struct private_quick_mode_t {
34
35 /**
36 * Public methods and task_t interface.
37 */
38 quick_mode_t public;
39
40 /**
41 * Assigned IKE_SA.
42 */
43 ike_sa_t *ike_sa;
44
45 /**
46 * TRUE if we are initiating quick mode
47 */
48 bool initiator;
49
50 /**
51 * Traffic selector of initiator
52 */
53 traffic_selector_t *tsi;
54
55 /**
56 * Traffic selector of responder
57 */
58 traffic_selector_t *tsr;
59
60 /**
61 * Initiators nonce
62 */
63 chunk_t nonce_i;
64
65 /**
66 * Responder nonce
67 */
68 chunk_t nonce_r;
69
70 /**
71 * Initiators ESP SPI
72 */
73 u_int32_t spi_i;
74
75 /**
76 * Responder ESP SPI
77 */
78 u_int32_t spi_r;
79
80 /**
81 * selected CHILD_SA proposal
82 */
83 proposal_t *proposal;
84
85 /**
86 * Config of CHILD_SA to establish
87 */
88 child_cfg_t *config;
89
90 /**
91 * CHILD_SA we are about to establish
92 */
93 child_sa_t *child_sa;
94
95 /**
96 * IKEv1 keymat
97 */
98 keymat_v1_t *keymat;
99
100 /**
101 * DH exchange, when PFS is in use
102 */
103 diffie_hellman_t *dh;
104
105 /**
106 * Negotiated lifetime of new SA
107 */
108 u_int32_t lifetime;
109
110 /**
111 * Negotaited lifebytes of new SA
112 */
113 u_int64_t lifebytes;
114
115 /** states of quick mode */
116 enum {
117 QM_INIT,
118 QM_NEGOTIATED,
119 } state;
120 };
121
122 /**
123 * Install negotiated CHILD_SA
124 */
125 static bool install(private_quick_mode_t *this)
126 {
127 status_t status, status_i, status_o;
128 chunk_t encr_i, encr_r, integ_i, integ_r;
129 linked_list_t *tsi, *tsr;
130
131 this->child_sa->set_proposal(this->child_sa, this->proposal);
132 this->child_sa->set_state(this->child_sa, CHILD_INSTALLING);
133 this->child_sa->set_mode(this->child_sa, MODE_TUNNEL);
134 this->child_sa->set_protocol(this->child_sa,
135 this->proposal->get_protocol(this->proposal));
136
137 status_i = status_o = FAILED;
138 encr_i = encr_r = integ_i = integ_r = chunk_empty;
139 tsi = linked_list_create();
140 tsr = linked_list_create();
141 tsi->insert_last(tsi, this->tsi);
142 tsr->insert_last(tsr, this->tsr);
143 if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh,
144 this->spi_i, this->spi_r, this->nonce_i, this->nonce_r,
145 &encr_i, &integ_i, &encr_r, &integ_r))
146 {
147 if (this->initiator)
148 {
149 status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
150 this->spi_i, 0, TRUE, FALSE, tsi, tsr);
151 status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
152 this->spi_r, 0, FALSE, FALSE, tsi, tsr);
153 }
154 else
155 {
156 status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
157 this->spi_r, 0, TRUE, FALSE, tsr, tsi);
158 status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
159 this->spi_i, 0, FALSE, FALSE, tsr, tsi);
160 }
161 }
162 chunk_clear(&integ_i);
163 chunk_clear(&integ_r);
164 chunk_clear(&encr_i);
165 chunk_clear(&encr_r);
166
167 if (status_i != SUCCESS || status_o != SUCCESS)
168 {
169 DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel",
170 (status_i != SUCCESS) ? "inbound " : "",
171 (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
172 (status_o != SUCCESS) ? "outbound " : "");
173 tsi->destroy(tsi);
174 tsr->destroy(tsr);
175 return FALSE;
176 }
177
178 if (this->initiator)
179 {
180 status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
181 }
182 else
183 {
184 status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
185 }
186 tsi->destroy(tsi);
187 tsr->destroy(tsr);
188 if (status != SUCCESS)
189 {
190 DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
191 return FALSE;
192 }
193
194 charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
195 this->dh, this->nonce_i, this->nonce_r);
196
197 /* add to IKE_SA, and remove from task */
198 this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
199 this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
200
201 DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
202 "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
203 this->child_sa->get_name(this->child_sa),
204 this->child_sa->get_reqid(this->child_sa),
205 ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
206 ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
207 this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
208 this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
209
210 charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
211
212 this->child_sa = NULL;
213
214 return TRUE;
215 }
216
217 /**
218 * Generate and add NONCE
219 */
220 static bool add_nonce(private_quick_mode_t *this, chunk_t *nonce,
221 message_t *message)
222 {
223 nonce_payload_t *nonce_payload;
224 rng_t *rng;
225
226 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
227 if (!rng)
228 {
229 DBG1(DBG_IKE, "no RNG found to create nonce");
230 return FALSE;
231 }
232 rng->allocate_bytes(rng, NONCE_SIZE, nonce);
233 rng->destroy(rng);
234
235 nonce_payload = nonce_payload_create(NONCE_V1);
236 nonce_payload->set_nonce(nonce_payload, *nonce);
237 message->add_payload(message, &nonce_payload->payload_interface);
238
239 return TRUE;
240 }
241
242 /**
243 * Extract nonce from NONCE payload
244 */
245 static bool get_nonce(private_quick_mode_t *this, chunk_t *nonce,
246 message_t *message)
247 {
248 nonce_payload_t *nonce_payload;
249
250 nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1);
251 if (!nonce_payload)
252 {
253 DBG1(DBG_IKE, "NONCE payload missing in message");
254 return FALSE;
255 }
256 *nonce = nonce_payload->get_nonce(nonce_payload);
257
258 return TRUE;
259 }
260
261 /**
262 * Add KE payload to message
263 */
264 static void add_ke(private_quick_mode_t *this, message_t *message)
265 {
266 ke_payload_t *ke_payload;
267
268 ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, this->dh);
269 message->add_payload(message, &ke_payload->payload_interface);
270 }
271
272 /**
273 * Get DH value from a KE payload
274 */
275 static bool get_ke(private_quick_mode_t *this, message_t *message)
276 {
277 ke_payload_t *ke_payload;
278
279 ke_payload = (ke_payload_t*)message->get_payload(message, KEY_EXCHANGE_V1);
280 if (!ke_payload)
281 {
282 DBG1(DBG_IKE, "KE payload missing");
283 return FALSE;
284 }
285 this->dh->set_other_public_value(this->dh,
286 ke_payload->get_key_exchange_data(ke_payload));
287 return TRUE;
288 }
289
290 /**
291 * Select a traffic selector from configuration
292 */
293 static traffic_selector_t* select_ts(private_quick_mode_t *this, bool initiator)
294 {
295 traffic_selector_t *ts;
296 linked_list_t *list;
297 host_t *host;
298
299 if (initiator)
300 {
301 host = this->ike_sa->get_my_host(this->ike_sa);
302 }
303 else
304 {
305 host = this->ike_sa->get_other_host(this->ike_sa);
306 }
307 list = this->config->get_traffic_selectors(this->config, initiator,
308 NULL, host);
309 if (list->get_first(list, (void**)&ts) == SUCCESS)
310 {
311 if (list->get_count(list) > 1)
312 {
313 DBG1(DBG_IKE, "configuration has more than one %s traffic selector,"
314 " using first only", initiator ? "initiator" : "responder");
315 }
316 ts = ts->clone(ts);
317 }
318 else
319 {
320 DBG1(DBG_IKE, "%s traffic selector missing in configuration",
321 initiator ? "initiator" : "responder");
322 ts = NULL;
323 }
324 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
325 return ts;
326 }
327
328 /**
329 * Add selected traffic selectors to message
330 */
331 static void add_ts(private_quick_mode_t *this, message_t *message)
332 {
333 id_payload_t *id_payload;
334 host_t *hsi, *hsr;
335
336 if (this->initiator)
337 {
338 hsi = this->ike_sa->get_my_host(this->ike_sa);
339 hsr = this->ike_sa->get_other_host(this->ike_sa);
340 }
341 else
342 {
343 hsr = this->ike_sa->get_my_host(this->ike_sa);
344 hsi = this->ike_sa->get_other_host(this->ike_sa);
345 }
346 /* add ID payload only if negotiating non host2host tunnels */
347 if (!this->tsi->is_host(this->tsi, hsi) ||
348 !this->tsr->is_host(this->tsr, hsr) ||
349 this->tsi->get_protocol(this->tsi) ||
350 this->tsr->get_protocol(this->tsr) ||
351 this->tsi->get_from_port(this->tsi) ||
352 this->tsr->get_from_port(this->tsr) ||
353 this->tsi->get_to_port(this->tsi) != 65535 ||
354 this->tsr->get_to_port(this->tsr) != 65535)
355 {
356 id_payload = id_payload_create_from_ts(this->tsi);
357 message->add_payload(message, &id_payload->payload_interface);
358 id_payload = id_payload_create_from_ts(this->tsr);
359 message->add_payload(message, &id_payload->payload_interface);
360 }
361 }
362
363 /**
364 * Get traffic selectors from received message
365 */
366 static bool get_ts(private_quick_mode_t *this, message_t *message)
367 {
368 traffic_selector_t *tsi = NULL, *tsr = NULL;
369 enumerator_t *enumerator;
370 id_payload_t *id_payload;
371 payload_t *payload;
372 host_t *hsi, *hsr;
373 bool first = TRUE;
374
375 enumerator = message->create_payload_enumerator(message);
376 while (enumerator->enumerate(enumerator, &payload))
377 {
378 if (payload->get_type(payload) == ID_V1)
379 {
380 id_payload = (id_payload_t*)payload;
381
382 if (first)
383 {
384 tsi = id_payload->get_ts(id_payload);
385 first = FALSE;
386 }
387 else
388 {
389 tsr = id_payload->get_ts(id_payload);
390 break;
391 }
392 }
393 }
394 enumerator->destroy(enumerator);
395
396 /* create host2host selectors if ID payloads missing */
397 if (this->initiator)
398 {
399 hsi = this->ike_sa->get_my_host(this->ike_sa);
400 hsr = this->ike_sa->get_other_host(this->ike_sa);
401 }
402 else
403 {
404 hsr = this->ike_sa->get_my_host(this->ike_sa);
405 hsi = this->ike_sa->get_other_host(this->ike_sa);
406 }
407 if (!tsi)
408 {
409 tsi = traffic_selector_create_from_subnet(hsi->clone(hsi),
410 hsi->get_family(hsi) == AF_INET ? 32 : 128, 0, 0);
411 }
412 if (!tsr)
413 {
414 tsr = traffic_selector_create_from_subnet(hsr->clone(hsr),
415 hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0);
416 }
417 if (this->initiator)
418 {
419 /* check if peer selection valid */
420 if (!tsr->is_contained_in(tsr, this->tsr) ||
421 !tsi->is_contained_in(tsi, this->tsi))
422 {
423 DBG1(DBG_IKE, "peer selected invalid traffic selectors: ",
424 "%R for %R, %R for %R", tsi, this->tsi, tsr, this->tsr);
425 tsi->destroy(tsi);
426 tsr->destroy(tsr);
427 return FALSE;
428 }
429 this->tsi->destroy(this->tsi);
430 this->tsr->destroy(this->tsr);
431 this->tsi = tsi;
432 this->tsr = tsr;
433 }
434 else
435 {
436 this->tsi = tsi;
437 this->tsr = tsr;
438 }
439 return TRUE;
440 }
441
442 /**
443 * Add NAT-OA payloads
444 */
445 static void add_nat_oa_payloads(private_quick_mode_t *this, message_t *message)
446 {
447 identification_t *id;
448 id_payload_t *nat_oa;
449 host_t *src, *dst;
450
451 src = message->get_source(message);
452 dst = message->get_destination(message);
453
454 src = this->initiator ? src : dst;
455 dst = this->initiator ? dst : src;
456
457 /* first NAT-OA is the initiator's address */
458 id = identification_create_from_sockaddr(src->get_sockaddr(src));
459 nat_oa = id_payload_create_from_identification(NAT_OA_V1, id);
460 message->add_payload(message, (payload_t*)nat_oa);
461 id->destroy(id);
462
463 /* second NAT-OA is that of the responder */
464 id = identification_create_from_sockaddr(dst->get_sockaddr(dst));
465 nat_oa = id_payload_create_from_identification(NAT_OA_V1, id);
466 message->add_payload(message, (payload_t*)nat_oa);
467 id->destroy(id);
468 }
469
470 /**
471 * Look up lifetimes
472 */
473 static void get_lifetimes(private_quick_mode_t *this)
474 {
475 lifetime_cfg_t *lft;
476
477 lft = this->config->get_lifetime(this->config);
478 if (lft->time.life)
479 {
480 this->lifetime = lft->time.life;
481 }
482 else if (lft->bytes.life)
483 {
484 this->lifebytes = lft->bytes.life;
485 }
486 free(lft);
487 }
488
489 /**
490 * Check and apply lifetimes
491 */
492 static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload)
493 {
494 u_int32_t lifetime;
495 u_int64_t lifebytes;
496
497 lifetime = sa_payload->get_lifetime(sa_payload);
498 lifebytes = sa_payload->get_lifebytes(sa_payload);
499 if (this->lifetime != lifetime)
500 {
501 DBG1(DBG_IKE, "received %us lifetime, configured %us, using lower",
502 lifetime, this->lifetime);
503 this->lifetime = min(this->lifetime, lifetime);
504 }
505 if (this->lifebytes != lifebytes)
506 {
507 DBG1(DBG_IKE, "received %llu lifebytes, configured %llu, using lower",
508 lifebytes, this->lifebytes);
509 this->lifebytes = min(this->lifebytes, lifebytes);
510 }
511 }
512
513 METHOD(task_t, build_i, status_t,
514 private_quick_mode_t *this, message_t *message)
515 {
516 switch (this->state)
517 {
518 case QM_INIT:
519 {
520 enumerator_t *enumerator;
521 sa_payload_t *sa_payload;
522 linked_list_t *list;
523 proposal_t *proposal;
524 ipsec_mode_t mode;
525 diffie_hellman_group_t group;
526 bool udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
527
528 this->child_sa = child_sa_create(
529 this->ike_sa->get_my_host(this->ike_sa),
530 this->ike_sa->get_other_host(this->ike_sa),
531 this->config, 0, udp);
532
533 list = this->config->get_proposals(this->config, FALSE);
534
535 this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
536 if (!this->spi_i)
537 {
538 DBG1(DBG_IKE, "allocating SPI from kernel failed");
539 return FAILED;
540 }
541 enumerator = list->create_enumerator(list);
542 while (enumerator->enumerate(enumerator, &proposal))
543 {
544 proposal->set_spi(proposal, this->spi_i);
545 }
546 enumerator->destroy(enumerator);
547
548 mode = this->config->get_mode(this->config);
549 if (udp && mode == MODE_TRANSPORT)
550 {
551 /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
552 add_nat_oa_payloads(this, message);
553 }
554
555 get_lifetimes(this);
556 sa_payload = sa_payload_create_from_proposals_v1(list,
557 this->lifetime, this->lifebytes, AUTH_NONE,
558 mode, udp);
559 list->destroy_offset(list, offsetof(proposal_t, destroy));
560 message->add_payload(message, &sa_payload->payload_interface);
561
562 if (!add_nonce(this, &this->nonce_i, message))
563 {
564 return FAILED;
565 }
566
567 group = this->config->get_dh_group(this->config);
568 if (group != MODP_NONE)
569 {
570 this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
571 group);
572 if (!this->dh)
573 {
574 DBG1(DBG_IKE, "configured DH group %N not supported",
575 diffie_hellman_group_names, group);
576 return FAILED;
577 }
578 add_ke(this, message);
579 }
580 this->tsi = select_ts(this, TRUE);
581 this->tsr = select_ts(this, FALSE);
582 if (!this->tsi || !this->tsr)
583 {
584 return FAILED;
585 }
586 add_ts(this, message);
587 return NEED_MORE;
588 }
589 case QM_NEGOTIATED:
590 {
591 return SUCCESS;
592 }
593 default:
594 return FAILED;
595 }
596 }
597
598 /**
599 * Check for notify errors, return TRUE if error found
600 */
601 static bool has_notify_errors(private_quick_mode_t *this, message_t *message)
602 {
603 enumerator_t *enumerator;
604 payload_t *payload;
605 bool err = FALSE;
606
607 enumerator = message->create_payload_enumerator(message);
608 while (enumerator->enumerate(enumerator, &payload))
609 {
610 if (payload->get_type(payload) == NOTIFY_V1)
611 {
612 notify_payload_t *notify;
613 notify_type_t type;
614
615 notify = (notify_payload_t*)payload;
616 type = notify->get_notify_type(notify);
617 if (type < 16384)
618 {
619 DBG1(DBG_IKE, "received %N error notify",
620 notify_type_names, type);
621 err = TRUE;
622 }
623 else
624 {
625 DBG1(DBG_IKE, "received %N notify", notify_type_names, type);
626 }
627 }
628 }
629 enumerator->destroy(enumerator);
630
631 return err;
632 }
633
634 METHOD(task_t, process_r, 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 *tsi, *tsr, *list;
643 peer_cfg_t *peer_cfg;
644 host_t *me, *other;
645 u_int16_t group;
646 bool udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
647
648 if (!get_ts(this, message))
649 {
650 return FAILED;
651 }
652 me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
653 if (!me)
654 {
655 me = this->ike_sa->get_my_host(this->ike_sa);
656 }
657 other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
658 if (!other)
659 {
660 other = this->ike_sa->get_other_host(this->ike_sa);
661 }
662 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
663 tsi = linked_list_create();
664 tsr = linked_list_create();
665 tsi->insert_last(tsi, this->tsi);
666 tsr->insert_last(tsr, this->tsr);
667 this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
668 me, other);
669 tsi->destroy(tsi);
670 tsr->destroy(tsr);
671 if (!this->config)
672 {
673 DBG1(DBG_IKE, "no child config found");
674 return FAILED;
675 }
676
677 sa_payload = (sa_payload_t*)message->get_payload(message,
678 SECURITY_ASSOCIATION_V1);
679 if (!sa_payload)
680 {
681 DBG1(DBG_IKE, "sa payload missing");
682 return FAILED;
683 }
684 list = sa_payload->get_proposals(sa_payload);
685 this->proposal = this->config->select_proposal(this->config,
686 list, FALSE, FALSE);
687 list->destroy_offset(list, offsetof(proposal_t, destroy));
688
689 get_lifetimes(this);
690 apply_lifetimes(this, sa_payload);
691
692 if (!this->proposal)
693 {
694 DBG1(DBG_IKE, "no matching proposal found");
695 return FAILED;
696 }
697 this->spi_i = this->proposal->get_spi(this->proposal);
698
699 if (!get_nonce(this, &this->nonce_i, message))
700 {
701 return FAILED;
702 }
703
704 if (this->proposal->get_algorithm(this->proposal,
705 DIFFIE_HELLMAN_GROUP, &group, NULL))
706 {
707 this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
708 group);
709 if (!this->dh)
710 {
711 DBG1(DBG_IKE, "negotiated DH group %N not supported",
712 diffie_hellman_group_names, group);
713 return FAILED;
714 }
715 if (!get_ke(this, message))
716 {
717 return FAILED;
718 }
719 }
720
721 this->child_sa = child_sa_create(
722 this->ike_sa->get_my_host(this->ike_sa),
723 this->ike_sa->get_other_host(this->ike_sa),
724 this->config, 0, udp);
725 return NEED_MORE;
726 }
727 case QM_NEGOTIATED:
728 {
729 if (has_notify_errors(this, message))
730 {
731 return FAILED;
732 }
733 if (!install(this))
734 {
735 return FAILED;
736 }
737 return SUCCESS;
738 }
739 default:
740 return FAILED;
741 }
742 }
743
744 METHOD(task_t, build_r, status_t,
745 private_quick_mode_t *this, message_t *message)
746 {
747 switch (this->state)
748 {
749 case QM_INIT:
750 {
751 sa_payload_t *sa_payload;
752 ipsec_mode_t mode;
753 bool udp = this->child_sa->has_encap(this->child_sa);
754
755 this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
756 if (!this->spi_r)
757 {
758 DBG1(DBG_IKE, "allocating SPI from kernel failed");
759 return FAILED;
760 }
761 this->proposal->set_spi(this->proposal, this->spi_r);
762
763 mode = this->config->get_mode(this->config);
764 if (udp && mode == MODE_TRANSPORT)
765 {
766 /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
767 add_nat_oa_payloads(this, message);
768 }
769
770 sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
771 this->lifetime, this->lifebytes, AUTH_NONE,
772 mode, udp);
773 message->add_payload(message, &sa_payload->payload_interface);
774
775 if (!add_nonce(this, &this->nonce_r, message))
776 {
777 return FAILED;
778 }
779 if (this->dh)
780 {
781 add_ke(this, message);
782 }
783
784 add_ts(this, message);
785
786 this->state = QM_NEGOTIATED;
787 return NEED_MORE;
788 }
789 default:
790 return FAILED;
791 }
792 }
793
794 METHOD(task_t, process_i, status_t,
795 private_quick_mode_t *this, message_t *message)
796 {
797 switch (this->state)
798 {
799 case QM_INIT:
800 {
801 sa_payload_t *sa_payload;
802 linked_list_t *list;
803
804 sa_payload = (sa_payload_t*)message->get_payload(message,
805 SECURITY_ASSOCIATION_V1);
806 if (!sa_payload)
807 {
808 DBG1(DBG_IKE, "sa payload missing");
809 return FAILED;
810 }
811 list = sa_payload->get_proposals(sa_payload);
812 this->proposal = this->config->select_proposal(this->config,
813 list, FALSE, FALSE);
814 list->destroy_offset(list, offsetof(proposal_t, destroy));
815 if (!this->proposal)
816 {
817 DBG1(DBG_IKE, "no matching proposal found");
818 return FAILED;
819 }
820 this->spi_r = this->proposal->get_spi(this->proposal);
821
822 apply_lifetimes(this, sa_payload);
823
824 if (!get_nonce(this, &this->nonce_r, message))
825 {
826 return FAILED;
827 }
828 if (this->dh && !get_ke(this, message))
829 {
830 return FAILED;
831 }
832 if (!get_ts(this, message))
833 {
834 return FAILED;
835 }
836 if (!install(this))
837 {
838 return FAILED;
839 }
840 this->state = QM_NEGOTIATED;
841 return NEED_MORE;
842 }
843 default:
844 return FAILED;
845 }
846 }
847
848 METHOD(task_t, get_type, task_type_t,
849 private_quick_mode_t *this)
850 {
851 return TASK_QUICK_MODE;
852 }
853
854 METHOD(task_t, migrate, void,
855 private_quick_mode_t *this, ike_sa_t *ike_sa)
856 {
857 this->ike_sa = ike_sa;
858 }
859
860 METHOD(task_t, destroy, void,
861 private_quick_mode_t *this)
862 {
863 chunk_free(&this->nonce_i);
864 chunk_free(&this->nonce_r);
865 DESTROY_IF(this->tsi);
866 DESTROY_IF(this->tsr);
867 DESTROY_IF(this->proposal);
868 DESTROY_IF(this->child_sa);
869 DESTROY_IF(this->config);
870 DESTROY_IF(this->dh);
871 free(this);
872 }
873
874 /*
875 * Described in header.
876 */
877 quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
878 traffic_selector_t *tsi, traffic_selector_t *tsr)
879 {
880 private_quick_mode_t *this;
881
882 INIT(this,
883 .public = {
884 .task = {
885 .get_type = _get_type,
886 .migrate = _migrate,
887 .destroy = _destroy,
888 },
889 },
890 .ike_sa = ike_sa,
891 .initiator = config != NULL,
892 .config = config,
893 .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
894 .state = QM_INIT,
895 );
896
897 if (config)
898 {
899 this->public.task.build = _build_i;
900 this->public.task.process = _process_i;
901 }
902 else
903 {
904 this->public.task.build = _build_r;
905 this->public.task.process = _process_r;
906 }
907
908 return &this->public;
909 }