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