2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
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>.
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
16 #include "quick_mode.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>
26 typedef struct private_quick_mode_t private_quick_mode_t
;
29 * Private members of a quick_mode_t task.
31 struct private_quick_mode_t
{
34 * Public methods and task_t interface.
44 * TRUE if we are initiating quick mode
49 * Traffic selector of initiator
51 traffic_selector_t
*tsi
;
54 * Traffic selector of responder
56 traffic_selector_t
*tsr
;
79 * selected CHILD_SA proposal
84 * Config of CHILD_SA to establish
89 * CHILD_SA we are about to establish
98 /** states of quick mode */
106 * Install negotiated CHILD_SA
108 static bool install(private_quick_mode_t
*this)
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
;
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
));
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
))
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
);
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
);
145 chunk_clear(&integ_i
);
146 chunk_clear(&integ_r
);
147 chunk_clear(&encr_i
);
148 chunk_clear(&encr_r
);
150 if (status_i
!= SUCCESS
|| status_o
!= SUCCESS
)
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 " : "");
163 status
= this->child_sa
->add_policies(this->child_sa
, tsi
, tsr
);
167 status
= this->child_sa
->add_policies(this->child_sa
, tsr
, tsi
);
171 if (status
!= SUCCESS
)
173 DBG1(DBG_IKE
, "unable to install IPsec policies (SPD) in kernel");
177 charon
->bus
->child_keys(charon
->bus
, this->child_sa
, this->initiator
,
178 NULL
, this->nonce_i
, this->nonce_r
);
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
);
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
));
193 charon
->bus
->child_updown(charon
->bus
, this->child_sa
, TRUE
);
195 this->child_sa
= NULL
;
201 * Generate and add NONCE
203 static bool add_nonce(private_quick_mode_t
*this, chunk_t
*nonce
,
206 nonce_payload_t
*nonce_payload
;
209 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
212 DBG1(DBG_IKE
, "no RNG found to create nonce");
215 rng
->allocate_bytes(rng
, NONCE_SIZE
, nonce
);
218 nonce_payload
= nonce_payload_create(NONCE_V1
);
219 nonce_payload
->set_nonce(nonce_payload
, *nonce
);
220 message
->add_payload(message
, &nonce_payload
->payload_interface
);
226 * Extract nonce from NONCE payload
228 static bool get_nonce(private_quick_mode_t
*this, chunk_t
*nonce
,
231 nonce_payload_t
*nonce_payload
;
233 nonce_payload
= (nonce_payload_t
*)message
->get_payload(message
, NONCE_V1
);
236 DBG1(DBG_IKE
, "NONCE payload missing in message");
239 *nonce
= nonce_payload
->get_nonce(nonce_payload
);
245 * Select a traffic selector from configuration
247 static traffic_selector_t
* select_ts(private_quick_mode_t
*this, bool initiator
)
249 traffic_selector_t
*ts
;
255 host
= this->ike_sa
->get_my_host(this->ike_sa
);
259 host
= this->ike_sa
->get_other_host(this->ike_sa
);
261 list
= this->config
->get_traffic_selectors(this->config
, initiator
,
263 if (list
->get_first(list
, (void**)&ts
) == SUCCESS
)
265 if (list
->get_count(list
) > 1)
267 DBG1(DBG_IKE
, "configuration has more than one %s traffic selector,"
268 " using first only", initiator ?
"initiator" : "responder");
274 DBG1(DBG_IKE
, "%s traffic selector missing in configuration",
275 initiator ?
"initiator" : "responder");
278 list
->destroy_offset(list
, offsetof(traffic_selector_t
, destroy
));
283 * Add selected traffic selectors to message
285 static void add_ts(private_quick_mode_t
*this, message_t
*message
)
287 id_payload_t
*id_payload
;
292 hsi
= this->ike_sa
->get_my_host(this->ike_sa
);
293 hsr
= this->ike_sa
->get_other_host(this->ike_sa
);
297 hsr
= this->ike_sa
->get_my_host(this->ike_sa
);
298 hsi
= this->ike_sa
->get_other_host(this->ike_sa
);
300 /* add ID payload only if negotiating non host2host tunnels */
301 if (!this->tsi
->is_host(this->tsi
, hsi
) ||
302 !this->tsr
->is_host(this->tsr
, hsr
) ||
303 this->tsi
->get_protocol(this->tsi
) ||
304 this->tsr
->get_protocol(this->tsr
) ||
305 this->tsi
->get_from_port(this->tsi
) ||
306 this->tsr
->get_from_port(this->tsr
) ||
307 this->tsi
->get_to_port(this->tsi
) != 65535 ||
308 this->tsr
->get_to_port(this->tsr
) != 65535)
310 id_payload
= id_payload_create_from_ts(this->tsi
);
311 message
->add_payload(message
, &id_payload
->payload_interface
);
312 id_payload
= id_payload_create_from_ts(this->tsr
);
313 message
->add_payload(message
, &id_payload
->payload_interface
);
318 * Get traffic selectors from received message
320 static bool get_ts(private_quick_mode_t
*this, message_t
*message
)
322 traffic_selector_t
*tsi
= NULL
, *tsr
= NULL
;
323 enumerator_t
*enumerator
;
324 id_payload_t
*id_payload
;
329 enumerator
= message
->create_payload_enumerator(message
);
330 while (enumerator
->enumerate(enumerator
, &payload
))
332 if (payload
->get_type(payload
) == ID_V1
)
334 id_payload
= (id_payload_t
*)payload
;
338 tsi
= id_payload
->get_ts(id_payload
);
343 tsr
= id_payload
->get_ts(id_payload
);
348 enumerator
->destroy(enumerator
);
350 /* create host2host selectors if ID payloads missing */
353 hsi
= this->ike_sa
->get_my_host(this->ike_sa
);
354 hsr
= this->ike_sa
->get_other_host(this->ike_sa
);
358 hsr
= this->ike_sa
->get_my_host(this->ike_sa
);
359 hsi
= this->ike_sa
->get_other_host(this->ike_sa
);
363 tsi
= traffic_selector_create_from_subnet(hsi
->clone(hsi
),
364 hsi
->get_family(hsi
) == AF_INET ?
32 : 128, 0, 0);
368 tsr
= traffic_selector_create_from_subnet(hsr
->clone(hsr
),
369 hsr
->get_family(hsr
) == AF_INET ?
32 : 128, 0, 0);
373 /* check if peer selection valid */
374 if (!tsr
->is_contained_in(tsr
, this->tsr
) ||
375 !tsi
->is_contained_in(tsi
, this->tsi
))
377 DBG1(DBG_IKE
, "peer selected invalid traffic selectors: ",
378 "%R for %R, %R for %R", tsi
, this->tsi
, tsr
, this->tsr
);
383 this->tsi
->destroy(this->tsi
);
384 this->tsr
->destroy(this->tsr
);
396 METHOD(task_t
, build_i
, status_t
,
397 private_quick_mode_t
*this, message_t
*message
)
403 enumerator_t
*enumerator
;
404 sa_payload_t
*sa_payload
;
406 proposal_t
*proposal
;
408 this->child_sa
= child_sa_create(
409 this->ike_sa
->get_my_host(this->ike_sa
),
410 this->ike_sa
->get_other_host(this->ike_sa
),
411 this->config
, 0, FALSE
);
413 list
= this->config
->get_proposals(this->config
, TRUE
);
415 this->spi_i
= this->child_sa
->alloc_spi(this->child_sa
, PROTO_ESP
);
418 DBG1(DBG_IKE
, "allocating SPI from kernel failed");
421 enumerator
= list
->create_enumerator(list
);
422 while (enumerator
->enumerate(enumerator
, &proposal
))
424 proposal
->set_spi(proposal
, this->spi_i
);
426 enumerator
->destroy(enumerator
);
428 sa_payload
= sa_payload_create_from_proposal_list(
429 SECURITY_ASSOCIATION_V1
, list
);
430 list
->destroy_offset(list
, offsetof(proposal_t
, destroy
));
431 message
->add_payload(message
, &sa_payload
->payload_interface
);
433 if (!add_nonce(this, &this->nonce_i
, message
))
437 this->tsi
= select_ts(this, TRUE
);
438 this->tsr
= select_ts(this, FALSE
);
439 if (!this->tsi
|| !this->tsr
)
443 add_ts(this, message
);
455 METHOD(task_t
, process_r
, status_t
,
456 private_quick_mode_t
*this, message_t
*message
)
462 sa_payload_t
*sa_payload
;
463 linked_list_t
*tsi
, *tsr
, *list
;
464 peer_cfg_t
*peer_cfg
;
467 if (!get_ts(this, message
))
471 me
= this->ike_sa
->get_virtual_ip(this->ike_sa
, TRUE
);
474 me
= this->ike_sa
->get_my_host(this->ike_sa
);
476 other
= this->ike_sa
->get_virtual_ip(this->ike_sa
, FALSE
);
479 other
= this->ike_sa
->get_other_host(this->ike_sa
);
481 peer_cfg
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
482 tsi
= linked_list_create();
483 tsr
= linked_list_create();
484 tsi
->insert_last(tsi
, this->tsi
);
485 tsr
->insert_last(tsr
, this->tsr
);
486 this->config
= peer_cfg
->select_child_cfg(peer_cfg
, tsr
, tsi
,
492 DBG1(DBG_IKE
, "no child config found");
496 sa_payload
= (sa_payload_t
*)message
->get_payload(message
,
497 SECURITY_ASSOCIATION_V1
);
500 DBG1(DBG_IKE
, "sa payload missing");
503 list
= sa_payload
->get_proposals(sa_payload
);
504 this->proposal
= this->config
->select_proposal(this->config
,
506 list
->destroy_offset(list
, offsetof(proposal_t
, destroy
));
509 DBG1(DBG_IKE
, "no matching proposal found");
512 this->spi_i
= this->proposal
->get_spi(this->proposal
);
514 if (!get_nonce(this, &this->nonce_i
, message
))
518 this->child_sa
= child_sa_create(
519 this->ike_sa
->get_my_host(this->ike_sa
),
520 this->ike_sa
->get_other_host(this->ike_sa
),
521 this->config
, 0, FALSE
);
537 METHOD(task_t
, build_r
, status_t
,
538 private_quick_mode_t
*this, message_t
*message
)
544 sa_payload_t
*sa_payload
;
546 this->spi_r
= this->child_sa
->alloc_spi(this->child_sa
, PROTO_ESP
);
549 DBG1(DBG_IKE
, "allocating SPI from kernel failed");
552 this->proposal
->set_spi(this->proposal
, this->spi_r
);
554 sa_payload
= sa_payload_create_from_proposal(
555 SECURITY_ASSOCIATION_V1
, this->proposal
);
556 message
->add_payload(message
, &sa_payload
->payload_interface
);
558 if (!add_nonce(this, &this->nonce_r
, message
))
562 add_ts(this, message
);
564 this->state
= QM_NEGOTIATED
;
572 METHOD(task_t
, process_i
, status_t
,
573 private_quick_mode_t
*this, message_t
*message
)
579 sa_payload_t
*sa_payload
;
582 sa_payload
= (sa_payload_t
*)message
->get_payload(message
,
583 SECURITY_ASSOCIATION_V1
);
586 DBG1(DBG_IKE
, "sa payload missing");
589 list
= sa_payload
->get_proposals(sa_payload
);
590 this->proposal
= this->config
->select_proposal(this->config
,
592 list
->destroy_offset(list
, offsetof(proposal_t
, destroy
));
595 DBG1(DBG_IKE
, "no matching proposal found");
598 this->spi_r
= this->proposal
->get_spi(this->proposal
);
600 if (!get_nonce(this, &this->nonce_r
, message
))
604 if (!get_ts(this, message
))
612 this->state
= QM_NEGOTIATED
;
620 METHOD(task_t
, get_type
, task_type_t
,
621 private_quick_mode_t
*this)
623 return TASK_QUICK_MODE
;
626 METHOD(task_t
, migrate
, void,
627 private_quick_mode_t
*this, ike_sa_t
*ike_sa
)
629 this->ike_sa
= ike_sa
;
632 METHOD(task_t
, destroy
, void,
633 private_quick_mode_t
*this)
635 chunk_free(&this->nonce_i
);
636 chunk_free(&this->nonce_r
);
637 DESTROY_IF(this->tsi
);
638 DESTROY_IF(this->tsr
);
639 DESTROY_IF(this->proposal
);
640 DESTROY_IF(this->child_sa
);
641 DESTROY_IF(this->config
);
646 * Described in header.
648 quick_mode_t
*quick_mode_create(ike_sa_t
*ike_sa
, child_cfg_t
*config
,
649 traffic_selector_t
*tsi
, traffic_selector_t
*tsr
)
651 private_quick_mode_t
*this;
656 .get_type
= _get_type
,
662 .initiator
= config
!= NULL
,
664 .keymat
= (keymat_v1_t
*)ike_sa
->get_keymat(ike_sa
),
670 this->public.task
.build
= _build_i
;
671 this->public.task
.process
= _process_i
;
675 this->public.task
.build
= _build_r
;
676 this->public.task
.process
= _process_r
;
679 return &this->public;