Install negotiated IKEv1 CHILD_SA negotiated in quick mode
[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 /** states of quick mode */
99 enum {
100 QM_INIT,
101 QM_NEGOTIATED,
102 } state;
103 };
104
105 /**
106 * Install negotiated CHILD_SA
107 */
108 static bool install(private_quick_mode_t *this)
109 {
110 status_t status, status_i, status_o;
111 chunk_t encr_i, encr_r, integ_i, integ_r;
112 linked_list_t *tsi, *tsr;
113
114 this->child_sa->set_proposal(this->child_sa, this->proposal);
115 this->child_sa->set_state(this->child_sa, CHILD_INSTALLING);
116 this->child_sa->set_mode(this->child_sa, MODE_TUNNEL);
117 this->child_sa->set_protocol(this->child_sa,
118 this->proposal->get_protocol(this->proposal));
119
120 status_i = status_o = FAILED;
121 encr_i = encr_r = integ_i = integ_r = chunk_empty;
122 tsi = linked_list_create();
123 tsr = linked_list_create();
124 tsi->insert_last(tsi, this->tsi);
125 tsr->insert_last(tsr, this->tsr);
126 if (this->keymat->derive_child_keys(this->keymat, this->proposal, NULL,
127 this->nonce_i, this->nonce_r, &encr_i, &integ_i, &encr_r, &integ_r))
128 {
129 if (this->initiator)
130 {
131 status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
132 this->spi_i, 0, TRUE, FALSE, tsi, tsr);
133 status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
134 this->spi_r, 0, FALSE, FALSE, tsi, tsr);
135 }
136 else
137 {
138 status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
139 this->spi_r, 0, TRUE, FALSE, tsr, tsi);
140 status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
141 this->spi_i, 0, FALSE, FALSE, tsr, tsi);
142 }
143 }
144 chunk_clear(&integ_i);
145 chunk_clear(&integ_r);
146 chunk_clear(&encr_i);
147 chunk_clear(&encr_r);
148
149 if (status_i != SUCCESS || status_o != SUCCESS)
150 {
151 DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel",
152 (status_i != SUCCESS) ? "inbound " : "",
153 (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
154 (status_o != SUCCESS) ? "outbound " : "");
155 tsi->destroy(tsi);
156 tsr->destroy(tsr);
157 return FALSE;
158 }
159
160 if (this->initiator)
161 {
162 status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
163 }
164 else
165 {
166 status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
167 }
168 tsi->destroy(tsi);
169 tsr->destroy(tsr);
170 if (status != SUCCESS)
171 {
172 DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
173 return FALSE;
174 }
175
176 charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
177 NULL, this->nonce_i, this->nonce_r);
178
179 /* add to IKE_SA, and remove from task */
180 this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
181 this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
182
183 DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
184 "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
185 this->child_sa->get_name(this->child_sa),
186 this->child_sa->get_reqid(this->child_sa),
187 ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
188 ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
189 this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
190 this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
191
192 charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
193
194 this->child_sa = NULL;
195
196 return TRUE;
197 }
198
199 METHOD(task_t, build_i, status_t,
200 private_quick_mode_t *this, message_t *message)
201 {
202 switch (this->state)
203 {
204 case QM_INIT:
205 {
206 enumerator_t *enumerator;
207 sa_payload_t *sa_payload;
208 nonce_payload_t *nonce_payload;
209 id_payload_t *id_payload;
210 traffic_selector_t *ts;
211 linked_list_t *list;
212 proposal_t *proposal;
213 rng_t *rng;
214
215 this->child_sa = child_sa_create(
216 this->ike_sa->get_my_host(this->ike_sa),
217 this->ike_sa->get_other_host(this->ike_sa),
218 this->config, 0, FALSE);
219
220 list = this->config->get_proposals(this->config, TRUE);
221
222 this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
223 if (!this->spi_i)
224 {
225 DBG1(DBG_IKE, "allocating SPI from kernel failed");
226 return FAILED;
227 }
228 enumerator = list->create_enumerator(list);
229 while (enumerator->enumerate(enumerator, &proposal))
230 {
231 proposal->set_spi(proposal, this->spi_i);
232 }
233 enumerator->destroy(enumerator);
234
235 sa_payload = sa_payload_create_from_proposal_list(
236 SECURITY_ASSOCIATION_V1, list);
237 list->destroy_offset(list, offsetof(proposal_t, destroy));
238 message->add_payload(message, &sa_payload->payload_interface);
239
240 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
241 if (!rng)
242 {
243 DBG1(DBG_IKE, "no RNG found to create nonce");
244 return FAILED;
245 }
246 rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_i);
247 rng->destroy(rng);
248 nonce_payload = nonce_payload_create(NONCE_V1);
249 nonce_payload->set_nonce(nonce_payload, this->nonce_i);
250 message->add_payload(message, &nonce_payload->payload_interface);
251
252 list = this->config->get_traffic_selectors(this->config, TRUE, NULL,
253 this->ike_sa->get_my_host(this->ike_sa));
254 if (list->get_first(list, (void**)&ts) != SUCCESS)
255 {
256 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
257 DBG1(DBG_IKE, "traffic selector missing");
258 return FAILED;
259 }
260 id_payload = id_payload_create_from_ts(ts);
261 this->tsi = ts->clone(ts);
262 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
263 message->add_payload(message, &id_payload->payload_interface);
264
265 list = this->config->get_traffic_selectors(this->config, FALSE, NULL,
266 this->ike_sa->get_other_host(this->ike_sa));
267 if (list->get_first(list, (void**)&ts) != SUCCESS)
268 {
269 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
270 DBG1(DBG_IKE, "traffic selector missing");
271 return FAILED;
272 }
273 id_payload = id_payload_create_from_ts(ts);
274 this->tsr = ts->clone(ts);
275 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
276 message->add_payload(message, &id_payload->payload_interface);
277
278 /* TODO-IKEv1: Add HASH(1) */
279
280 return NEED_MORE;
281 }
282 case QM_NEGOTIATED:
283 {
284 /* TODO-IKEv1: Send HASH(3) */
285 return SUCCESS;
286 }
287 default:
288 return FAILED;
289 }
290 }
291
292 METHOD(task_t, process_r, status_t,
293 private_quick_mode_t *this, message_t *message)
294 {
295 switch (this->state)
296 {
297 case QM_INIT:
298 {
299 sa_payload_t *sa_payload;
300 nonce_payload_t *nonce_payload;
301 id_payload_t *id_payload;
302 payload_t *payload;
303 linked_list_t *tsi, *tsr, *list;
304 peer_cfg_t *peer_cfg;
305 host_t *me, *other;
306 enumerator_t *enumerator;
307 bool first = TRUE;
308
309 enumerator = message->create_payload_enumerator(message);
310 while (enumerator->enumerate(enumerator, &payload))
311 {
312 if (payload->get_type(payload) == ID_V1)
313 {
314 id_payload = (id_payload_t*)payload;
315
316 if (first)
317 {
318 this->tsi = id_payload->get_ts(id_payload);
319 first = FALSE;
320 }
321 else
322 {
323 this->tsr = id_payload->get_ts(id_payload);
324 break;
325 }
326 }
327 }
328 enumerator->destroy(enumerator);
329
330 /* TODO-IKEv1: create host2host TS if ID payloads missing */
331
332 me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
333 if (!me)
334 {
335 me = this->ike_sa->get_my_host(this->ike_sa);
336 }
337 other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
338 if (!other)
339 {
340 other = this->ike_sa->get_other_host(this->ike_sa);
341 }
342 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
343 tsi = linked_list_create();
344 tsr = linked_list_create();
345 tsi->insert_last(tsi, this->tsi);
346 tsr->insert_last(tsr, this->tsr);
347 this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
348 me, other);
349 tsi->destroy(tsi);
350 tsr->destroy(tsr);
351 if (!this->config)
352 {
353 DBG1(DBG_IKE, "no child config found");
354 return FAILED;
355 }
356
357 sa_payload = (sa_payload_t*)message->get_payload(message,
358 SECURITY_ASSOCIATION_V1);
359 if (!sa_payload)
360 {
361 DBG1(DBG_IKE, "sa payload missing");
362 return FAILED;
363 }
364 list = sa_payload->get_proposals(sa_payload);
365 this->proposal = this->config->select_proposal(this->config,
366 list, TRUE, FALSE);
367 list->destroy_offset(list, offsetof(proposal_t, destroy));
368 if (!this->proposal)
369 {
370 DBG1(DBG_IKE, "no matching proposal found");
371 return FAILED;
372 }
373 this->spi_i = this->proposal->get_spi(this->proposal);
374
375 nonce_payload = (nonce_payload_t*)message->get_payload(message,
376 NONCE_V1);
377 if (!nonce_payload)
378 {
379 DBG1(DBG_IKE, "Nonce payload missing");
380 return FAILED;
381 }
382 this->nonce_i = nonce_payload->get_nonce(nonce_payload);
383
384 /* TODO-IKEv1: verify HASH(1) */
385
386 this->child_sa = child_sa_create(
387 this->ike_sa->get_my_host(this->ike_sa),
388 this->ike_sa->get_other_host(this->ike_sa),
389 this->config, 0, FALSE);
390 return NEED_MORE;
391 }
392 case QM_NEGOTIATED:
393 {
394 /* TODO-IKEv1: verify HASH(3) */
395
396 if (!install(this))
397 {
398 return FAILED;
399 }
400
401 return SUCCESS;
402 }
403 default:
404 return FAILED;
405 }
406 }
407
408 METHOD(task_t, build_r, status_t,
409 private_quick_mode_t *this, message_t *message)
410 {
411 switch (this->state)
412 {
413 case QM_INIT:
414 {
415 sa_payload_t *sa_payload;
416 nonce_payload_t *nonce_payload;
417 id_payload_t *id_payload;
418 rng_t *rng;
419
420 this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
421 if (!this->spi_r)
422 {
423 DBG1(DBG_IKE, "allocating SPI from kernel failed");
424 return FAILED;
425 }
426 this->proposal->set_spi(this->proposal, this->spi_r);
427
428 sa_payload = sa_payload_create_from_proposal(
429 SECURITY_ASSOCIATION_V1, this->proposal);
430 message->add_payload(message, &sa_payload->payload_interface);
431
432 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
433 if (!rng)
434 {
435 DBG1(DBG_IKE, "no RNG found to create nonce");
436 return FAILED;
437 }
438 rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_r);
439 rng->destroy(rng);
440 nonce_payload = nonce_payload_create(NONCE_V1);
441 nonce_payload->set_nonce(nonce_payload, this->nonce_r);
442 message->add_payload(message, &nonce_payload->payload_interface);
443
444 id_payload = id_payload_create_from_ts(this->tsi);
445 message->add_payload(message, &id_payload->payload_interface);
446 id_payload = id_payload_create_from_ts(this->tsr);
447 message->add_payload(message, &id_payload->payload_interface);
448
449 /* TODO-IKEv1: add HASH(2) */
450
451 this->state = QM_NEGOTIATED;
452 return NEED_MORE;
453 }
454 default:
455 return FAILED;
456 }
457 }
458
459 METHOD(task_t, process_i, status_t,
460 private_quick_mode_t *this, message_t *message)
461 {
462 switch (this->state)
463 {
464 case QM_INIT:
465 {
466 sa_payload_t *sa_payload;
467 nonce_payload_t *nonce_payload;
468 id_payload_t *id_payload;
469 payload_t *payload;
470 traffic_selector_t *tsi = NULL, *tsr = NULL;
471 linked_list_t *list;
472 enumerator_t *enumerator;
473 bool first = TRUE;
474
475 enumerator = message->create_payload_enumerator(message);
476 while (enumerator->enumerate(enumerator, &payload))
477 {
478 if (payload->get_type(payload) == ID_V1)
479 {
480 id_payload = (id_payload_t*)payload;
481
482 if (first)
483 {
484 tsi = id_payload->get_ts(id_payload);
485 first = FALSE;
486 }
487 else
488 {
489 tsr = id_payload->get_ts(id_payload);
490 break;
491 }
492 }
493 }
494 enumerator->destroy(enumerator);
495
496 /* TODO-IKEv1: create host2host TS if ID payloads missing */
497
498 if (!tsr->is_contained_in(tsr, this->tsr) ||
499 !tsi->is_contained_in(tsi, this->tsi))
500 {
501 tsi->destroy(tsi);
502 tsr->destroy(tsr);
503 DBG1(DBG_IKE, "TS mismatch");
504 return FAILED;
505 }
506 this->tsi->destroy(this->tsi);
507 this->tsr->destroy(this->tsr);
508 this->tsi = tsi;
509 this->tsr = tsr;
510
511 sa_payload = (sa_payload_t*)message->get_payload(message,
512 SECURITY_ASSOCIATION_V1);
513 if (!sa_payload)
514 {
515 DBG1(DBG_IKE, "sa payload missing");
516 return FAILED;
517 }
518 list = sa_payload->get_proposals(sa_payload);
519 this->proposal = this->config->select_proposal(this->config,
520 list, TRUE, FALSE);
521 list->destroy_offset(list, offsetof(proposal_t, destroy));
522 if (!this->proposal)
523 {
524 DBG1(DBG_IKE, "no matching proposal found");
525 return FAILED;
526 }
527 this->spi_r = this->proposal->get_spi(this->proposal);
528
529 nonce_payload = (nonce_payload_t*)message->get_payload(message,
530 NONCE_V1);
531 if (!nonce_payload)
532 {
533 DBG1(DBG_IKE, "Nonce payload missing");
534 return FAILED;
535 }
536 this->nonce_r = nonce_payload->get_nonce(nonce_payload);
537
538 /* TODO-IKEv1: verify HASH(2) */
539
540 if (!install(this))
541 {
542 return FAILED;
543 }
544
545 this->state = QM_NEGOTIATED;
546 return NEED_MORE;
547 }
548 default:
549 return FAILED;
550 }
551 }
552
553 METHOD(task_t, get_type, task_type_t,
554 private_quick_mode_t *this)
555 {
556 return TASK_QUICK_MODE;
557 }
558
559 METHOD(task_t, migrate, void,
560 private_quick_mode_t *this, ike_sa_t *ike_sa)
561 {
562 this->ike_sa = ike_sa;
563 }
564
565 METHOD(task_t, destroy, void,
566 private_quick_mode_t *this)
567 {
568 chunk_free(&this->nonce_i);
569 chunk_free(&this->nonce_r);
570 DESTROY_IF(this->tsi);
571 DESTROY_IF(this->tsr);
572 DESTROY_IF(this->proposal);
573 DESTROY_IF(this->child_sa);
574 DESTROY_IF(this->config);
575 free(this);
576 }
577
578 /*
579 * Described in header.
580 */
581 quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
582 traffic_selector_t *tsi, traffic_selector_t *tsr)
583 {
584 private_quick_mode_t *this;
585
586 INIT(this,
587 .public = {
588 .task = {
589 .get_type = _get_type,
590 .migrate = _migrate,
591 .destroy = _destroy,
592 },
593 },
594 .ike_sa = ike_sa,
595 .initiator = config != NULL,
596 .config = config,
597 .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
598 .state = QM_INIT,
599 );
600
601 if (config)
602 {
603 this->public.task.build = _build_i;
604 this->public.task.process = _process_i;
605 }
606 else
607 {
608 this->public.task.build = _build_r;
609 this->public.task.process = _process_r;
610 }
611
612 return &this->public;
613 }