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