Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/tasks/quick_mode.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012-2019 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * Copyright (C) 2011 Martin Willi
! 6: * Copyright (C) 2011 revosec AG
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify it
! 9: * under the terms of the GNU General Public License as published by the
! 10: * Free Software Foundation; either version 2 of the License, or (at your
! 11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 12: *
! 13: * This program is distributed in the hope that it will be useful, but
! 14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 16: * for more details.
! 17: */
! 18:
! 19: /*
! 20: * Copyright (C) 2012 Volker RĂ¼melin
! 21: *
! 22: * Permission is hereby granted, free of charge, to any person obtaining a copy
! 23: * of this software and associated documentation files (the "Software"), to deal
! 24: * in the Software without restriction, including without limitation the rights
! 25: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 26: * copies of the Software, and to permit persons to whom the Software is
! 27: * furnished to do so, subject to the following conditions:
! 28: *
! 29: * The above copyright notice and this permission notice shall be included in
! 30: * all copies or substantial portions of the Software.
! 31: *
! 32: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 33: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 34: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 35: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 36: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! 37: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! 38: * THE SOFTWARE.
! 39: */
! 40:
! 41: #include "quick_mode.h"
! 42:
! 43: #include <string.h>
! 44:
! 45: #include <daemon.h>
! 46: #include <sa/ikev1/keymat_v1.h>
! 47: #include <encoding/payloads/sa_payload.h>
! 48: #include <encoding/payloads/nonce_payload.h>
! 49: #include <encoding/payloads/ke_payload.h>
! 50: #include <encoding/payloads/id_payload.h>
! 51: #include <encoding/payloads/payload.h>
! 52: #include <sa/ikev1/tasks/informational.h>
! 53: #include <sa/ikev1/tasks/quick_delete.h>
! 54: #include <processing/jobs/inactivity_job.h>
! 55:
! 56: typedef struct private_quick_mode_t private_quick_mode_t;
! 57:
! 58: /**
! 59: * Private members of a quick_mode_t task.
! 60: */
! 61: struct private_quick_mode_t {
! 62:
! 63: /**
! 64: * Public methods and task_t interface.
! 65: */
! 66: quick_mode_t public;
! 67:
! 68: /**
! 69: * Assigned IKE_SA.
! 70: */
! 71: ike_sa_t *ike_sa;
! 72:
! 73: /**
! 74: * TRUE if we are initiating quick mode
! 75: */
! 76: bool initiator;
! 77:
! 78: /**
! 79: * Traffic selector of initiator
! 80: */
! 81: traffic_selector_t *tsi;
! 82:
! 83: /**
! 84: * Traffic selector of responder
! 85: */
! 86: traffic_selector_t *tsr;
! 87:
! 88: /**
! 89: * Initiators nonce
! 90: */
! 91: chunk_t nonce_i;
! 92:
! 93: /**
! 94: * Responder nonce
! 95: */
! 96: chunk_t nonce_r;
! 97:
! 98: /**
! 99: * Initiators ESP SPI
! 100: */
! 101: uint32_t spi_i;
! 102:
! 103: /**
! 104: * Responder ESP SPI
! 105: */
! 106: uint32_t spi_r;
! 107:
! 108: /**
! 109: * Initiators IPComp CPI
! 110: */
! 111: uint16_t cpi_i;
! 112:
! 113: /**
! 114: * Responders IPComp CPI
! 115: */
! 116: uint16_t cpi_r;
! 117:
! 118: /**
! 119: * selected CHILD_SA proposal
! 120: */
! 121: proposal_t *proposal;
! 122:
! 123: /**
! 124: * Config of CHILD_SA to establish
! 125: */
! 126: child_cfg_t *config;
! 127:
! 128: /**
! 129: * CHILD_SA we are about to establish
! 130: */
! 131: child_sa_t *child_sa;
! 132:
! 133: /**
! 134: * IKEv1 keymat
! 135: */
! 136: keymat_v1_t *keymat;
! 137:
! 138: /**
! 139: * DH exchange, when PFS is in use
! 140: */
! 141: diffie_hellman_t *dh;
! 142:
! 143: /**
! 144: * Negotiated lifetime of new SA
! 145: */
! 146: uint32_t lifetime;
! 147:
! 148: /**
! 149: * Negotiated lifebytes of new SA
! 150: */
! 151: uint64_t lifebytes;
! 152:
! 153: /**
! 154: * Data collected to create the CHILD_SA
! 155: */
! 156: child_sa_create_t child;
! 157:
! 158: /**
! 159: * SPI of SA we rekey
! 160: */
! 161: uint32_t rekey;
! 162:
! 163: /**
! 164: * Delete old child after successful rekey
! 165: */
! 166: bool delete;
! 167:
! 168: /**
! 169: * Negotiated mode, tunnel or transport
! 170: */
! 171: ipsec_mode_t mode;
! 172:
! 173: /*
! 174: * SA protocol (ESP|AH) negotiated
! 175: */
! 176: protocol_id_t proto;
! 177:
! 178: /**
! 179: * Message ID of handled quick mode exchange
! 180: */
! 181: uint32_t mid;
! 182:
! 183: /** states of quick mode */
! 184: enum {
! 185: QM_INIT,
! 186: QM_NEGOTIATED,
! 187: } state;
! 188: };
! 189:
! 190: /**
! 191: * Schedule inactivity timeout for CHILD_SA with reqid, if enabled
! 192: */
! 193: static void schedule_inactivity_timeout(private_quick_mode_t *this)
! 194: {
! 195: uint32_t timeout;
! 196: bool close_ike;
! 197:
! 198: timeout = this->config->get_inactivity(this->config);
! 199: if (timeout)
! 200: {
! 201: close_ike = lib->settings->get_bool(lib->settings,
! 202: "%s.inactivity_close_ike", FALSE, lib->ns);
! 203: lib->scheduler->schedule_job(lib->scheduler, (job_t*)
! 204: inactivity_job_create(this->child_sa->get_unique_id(this->child_sa),
! 205: timeout, close_ike), timeout);
! 206: }
! 207: }
! 208:
! 209: /**
! 210: * Check if we have a an address pool configured
! 211: */
! 212: static bool have_pool(ike_sa_t *ike_sa)
! 213: {
! 214: enumerator_t *enumerator;
! 215: peer_cfg_t *peer_cfg;
! 216: char *pool;
! 217: bool found = FALSE;
! 218:
! 219: peer_cfg = ike_sa->get_peer_cfg(ike_sa);
! 220: if (peer_cfg)
! 221: {
! 222: enumerator = peer_cfg->create_pool_enumerator(peer_cfg);
! 223: if (enumerator->enumerate(enumerator, &pool))
! 224: {
! 225: found = TRUE;
! 226: }
! 227: enumerator->destroy(enumerator);
! 228: }
! 229: return found;
! 230: }
! 231:
! 232: /**
! 233: * Get hosts to use for dynamic traffic selectors
! 234: */
! 235: static linked_list_t *get_dynamic_hosts(ike_sa_t *ike_sa, bool local)
! 236: {
! 237: enumerator_t *enumerator;
! 238: linked_list_t *list;
! 239: host_t *host;
! 240:
! 241: list = linked_list_create();
! 242: enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
! 243: while (enumerator->enumerate(enumerator, &host))
! 244: {
! 245: list->insert_last(list, host);
! 246: }
! 247: enumerator->destroy(enumerator);
! 248:
! 249: if (list->get_count(list) == 0)
! 250: { /* no virtual IPs assigned */
! 251: if (local)
! 252: {
! 253: host = ike_sa->get_my_host(ike_sa);
! 254: list->insert_last(list, host);
! 255: }
! 256: else if (!have_pool(ike_sa))
! 257: { /* use host only if we don't have a pool configured */
! 258: host = ike_sa->get_other_host(ike_sa);
! 259: list->insert_last(list, host);
! 260: }
! 261: }
! 262: return list;
! 263: }
! 264:
! 265: /**
! 266: * Install negotiated CHILD_SA
! 267: */
! 268: static bool install(private_quick_mode_t *this)
! 269: {
! 270: status_t status, status_i, status_o;
! 271: chunk_t encr_i, encr_r, integ_i, integ_r;
! 272: linked_list_t *tsi, *tsr, *my_ts, *other_ts;
! 273: child_sa_t *old = NULL;
! 274:
! 275: this->child_sa->set_proposal(this->child_sa, this->proposal);
! 276: this->child_sa->set_state(this->child_sa, CHILD_INSTALLING);
! 277: this->child_sa->set_mode(this->child_sa, this->mode);
! 278:
! 279: if (this->cpi_i && this->cpi_r)
! 280: { /* DEFLATE is the only transform we currently support */
! 281: this->child_sa->set_ipcomp(this->child_sa, IPCOMP_DEFLATE);
! 282: }
! 283: else
! 284: {
! 285: this->cpi_i = this->cpi_r = 0;
! 286: }
! 287:
! 288: this->child_sa->set_protocol(this->child_sa,
! 289: this->proposal->get_protocol(this->proposal));
! 290:
! 291: status_i = status_o = FAILED;
! 292: encr_i = encr_r = integ_i = integ_r = chunk_empty;
! 293: tsi = linked_list_create_with_items(this->tsi->clone(this->tsi), NULL);
! 294: tsr = linked_list_create_with_items(this->tsr->clone(this->tsr), NULL);
! 295: if (this->initiator)
! 296: {
! 297: charon->bus->narrow(charon->bus, this->child_sa,
! 298: NARROW_INITIATOR_POST_AUTH, tsi, tsr);
! 299: }
! 300: else
! 301: {
! 302: charon->bus->narrow(charon->bus, this->child_sa,
! 303: NARROW_RESPONDER_POST, tsr, tsi);
! 304: }
! 305: if (tsi->get_count(tsi) == 0 || tsr->get_count(tsr) == 0)
! 306: {
! 307: tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
! 308: tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
! 309: DBG1(DBG_IKE, "no acceptable traffic selectors found");
! 310: return FALSE;
! 311: }
! 312:
! 313: if (this->initiator)
! 314: {
! 315: this->child_sa->set_policies(this->child_sa, tsi, tsr);
! 316: }
! 317: else
! 318: {
! 319: this->child_sa->set_policies(this->child_sa, tsr, tsi);
! 320: }
! 321: tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
! 322: tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
! 323:
! 324: if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh,
! 325: this->spi_i, this->spi_r, this->nonce_i, this->nonce_r,
! 326: &encr_i, &integ_i, &encr_r, &integ_r))
! 327: {
! 328: if (this->initiator)
! 329: {
! 330: status_i = this->child_sa->install(this->child_sa,
! 331: encr_r, integ_r, this->spi_i, this->cpi_i,
! 332: this->initiator, TRUE, FALSE);
! 333: status_o = this->child_sa->install(this->child_sa,
! 334: encr_i, integ_i, this->spi_r, this->cpi_r,
! 335: this->initiator, FALSE, FALSE);
! 336: }
! 337: else
! 338: {
! 339: status_i = this->child_sa->install(this->child_sa,
! 340: encr_i, integ_i, this->spi_r, this->cpi_r,
! 341: this->initiator, TRUE, FALSE);
! 342: status_o = this->child_sa->install(this->child_sa,
! 343: encr_r, integ_r, this->spi_i, this->cpi_i,
! 344: this->initiator, FALSE, FALSE);
! 345: }
! 346: }
! 347:
! 348: if (status_i != SUCCESS || status_o != SUCCESS)
! 349: {
! 350: DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel",
! 351: (status_i != SUCCESS) ? "inbound " : "",
! 352: (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
! 353: (status_o != SUCCESS) ? "outbound " : "");
! 354: status = FAILED;
! 355: }
! 356: else
! 357: {
! 358: status = this->child_sa->install_policies(this->child_sa);
! 359:
! 360: if (status != SUCCESS)
! 361: {
! 362: DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
! 363: }
! 364: else
! 365: {
! 366: charon->bus->child_derived_keys(charon->bus, this->child_sa,
! 367: this->initiator, encr_i, encr_r,
! 368: integ_i, integ_r);
! 369: }
! 370: }
! 371: chunk_clear(&integ_i);
! 372: chunk_clear(&integ_r);
! 373: chunk_clear(&encr_i);
! 374: chunk_clear(&encr_r);
! 375:
! 376: if (status != SUCCESS)
! 377: {
! 378: return FALSE;
! 379: }
! 380:
! 381: charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
! 382: this->dh, this->nonce_i, this->nonce_r);
! 383:
! 384: my_ts = linked_list_create_from_enumerator(
! 385: this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
! 386: other_ts = linked_list_create_from_enumerator(
! 387: this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
! 388:
! 389: DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
! 390: "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
! 391: this->child_sa->get_name(this->child_sa),
! 392: this->child_sa->get_unique_id(this->child_sa),
! 393: ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
! 394: ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts);
! 395:
! 396: my_ts->destroy(my_ts);
! 397: other_ts->destroy(other_ts);
! 398:
! 399: this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
! 400: this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
! 401:
! 402: if (this->rekey)
! 403: {
! 404: old = this->ike_sa->get_child_sa(this->ike_sa,
! 405: this->proposal->get_protocol(this->proposal),
! 406: this->rekey, TRUE);
! 407: }
! 408: if (old)
! 409: {
! 410: charon->bus->child_rekey(charon->bus, old, this->child_sa);
! 411: /* rekeyed CHILD_SAs stay installed until they expire or are deleted
! 412: * by the other peer */
! 413: old->set_state(old, CHILD_REKEYED);
! 414: /* as initiator we delete the CHILD_SA if configured to do so */
! 415: if (this->initiator && this->delete)
! 416: {
! 417: this->ike_sa->queue_task(this->ike_sa,
! 418: (task_t*)quick_delete_create(this->ike_sa,
! 419: this->proposal->get_protocol(this->proposal),
! 420: this->rekey, TRUE, FALSE));
! 421: }
! 422: }
! 423: else
! 424: {
! 425: charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
! 426: }
! 427: schedule_inactivity_timeout(this);
! 428: this->child_sa = NULL;
! 429: return TRUE;
! 430: }
! 431:
! 432: /**
! 433: * Generate and add NONCE
! 434: */
! 435: static bool add_nonce(private_quick_mode_t *this, chunk_t *nonce,
! 436: message_t *message)
! 437: {
! 438: nonce_payload_t *nonce_payload;
! 439: nonce_gen_t *nonceg;
! 440:
! 441: nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat);
! 442: if (!nonceg)
! 443: {
! 444: DBG1(DBG_IKE, "no nonce generator found to create nonce");
! 445: return FALSE;
! 446: }
! 447: if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, nonce))
! 448: {
! 449: DBG1(DBG_IKE, "nonce allocation failed");
! 450: nonceg->destroy(nonceg);
! 451: return FALSE;
! 452: }
! 453: nonceg->destroy(nonceg);
! 454:
! 455: nonce_payload = nonce_payload_create(PLV1_NONCE);
! 456: nonce_payload->set_nonce(nonce_payload, *nonce);
! 457: message->add_payload(message, &nonce_payload->payload_interface);
! 458:
! 459: return TRUE;
! 460: }
! 461:
! 462: /**
! 463: * Extract nonce from NONCE payload
! 464: */
! 465: static bool get_nonce(private_quick_mode_t *this, chunk_t *nonce,
! 466: message_t *message)
! 467: {
! 468: nonce_payload_t *nonce_payload;
! 469:
! 470: nonce_payload = (nonce_payload_t*)message->get_payload(message, PLV1_NONCE);
! 471: if (!nonce_payload)
! 472: {
! 473: DBG1(DBG_IKE, "NONCE payload missing in message");
! 474: return FALSE;
! 475: }
! 476: *nonce = nonce_payload->get_nonce(nonce_payload);
! 477:
! 478: return TRUE;
! 479: }
! 480:
! 481: /**
! 482: * Add KE payload to message
! 483: */
! 484: static bool add_ke(private_quick_mode_t *this, message_t *message)
! 485: {
! 486: ke_payload_t *ke_payload;
! 487:
! 488: ke_payload = ke_payload_create_from_diffie_hellman(PLV1_KEY_EXCHANGE,
! 489: this->dh);
! 490: if (!ke_payload)
! 491: {
! 492: DBG1(DBG_IKE, "creating KE payload failed");
! 493: return FALSE;
! 494: }
! 495: message->add_payload(message, &ke_payload->payload_interface);
! 496: return TRUE;
! 497: }
! 498:
! 499: /**
! 500: * Get DH value from a KE payload
! 501: */
! 502: static bool get_ke(private_quick_mode_t *this, message_t *message)
! 503: {
! 504: ke_payload_t *ke_payload;
! 505:
! 506: ke_payload = (ke_payload_t*)message->get_payload(message, PLV1_KEY_EXCHANGE);
! 507: if (!ke_payload)
! 508: {
! 509: DBG1(DBG_IKE, "KE payload missing");
! 510: return FALSE;
! 511: }
! 512: if (!this->dh->set_other_public_value(this->dh,
! 513: ke_payload->get_key_exchange_data(ke_payload)))
! 514: {
! 515: DBG1(DBG_IKE, "unable to apply received KE value");
! 516: return FALSE;
! 517: }
! 518: return TRUE;
! 519: }
! 520:
! 521: /**
! 522: * Select a traffic selector from configuration
! 523: */
! 524: static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
! 525: linked_list_t *supplied)
! 526: {
! 527: traffic_selector_t *ts;
! 528: linked_list_t *list, *hosts;
! 529:
! 530: hosts = get_dynamic_hosts(this->ike_sa, local);
! 531: list = this->config->get_traffic_selectors(this->config,
! 532: local, supplied, hosts, TRUE);
! 533: hosts->destroy(hosts);
! 534: if (list->get_first(list, (void**)&ts) == SUCCESS)
! 535: {
! 536: ts = ts->clone(ts);
! 537: }
! 538: else
! 539: {
! 540: DBG1(DBG_IKE, "%s traffic selector missing in configuration",
! 541: local ? "local" : "remote");
! 542: ts = NULL;
! 543: }
! 544: list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
! 545: return ts;
! 546: }
! 547:
! 548: /**
! 549: * Add selected traffic selectors to message
! 550: */
! 551: static void add_ts(private_quick_mode_t *this, message_t *message)
! 552: {
! 553: id_payload_t *id_payload;
! 554:
! 555: id_payload = id_payload_create_from_ts(this->tsi);
! 556: message->add_payload(message, &id_payload->payload_interface);
! 557: id_payload = id_payload_create_from_ts(this->tsr);
! 558: message->add_payload(message, &id_payload->payload_interface);
! 559: }
! 560:
! 561: /**
! 562: * Get traffic selectors from received message
! 563: */
! 564: static bool get_ts(private_quick_mode_t *this, message_t *message)
! 565: {
! 566: traffic_selector_t *tsi = NULL, *tsr = NULL;
! 567: enumerator_t *enumerator;
! 568: id_payload_t *id_payload;
! 569: payload_t *payload;
! 570: host_t *hsi, *hsr;
! 571: bool first = TRUE;
! 572:
! 573: enumerator = message->create_payload_enumerator(message);
! 574: while (enumerator->enumerate(enumerator, &payload))
! 575: {
! 576: if (payload->get_type(payload) == PLV1_ID)
! 577: {
! 578: id_payload = (id_payload_t*)payload;
! 579:
! 580: if (first)
! 581: {
! 582: tsi = id_payload->get_ts(id_payload);
! 583: first = FALSE;
! 584: }
! 585: else
! 586: {
! 587: tsr = id_payload->get_ts(id_payload);
! 588: break;
! 589: }
! 590: }
! 591: }
! 592: enumerator->destroy(enumerator);
! 593:
! 594: /* create host2host selectors if ID payloads missing */
! 595: if (this->initiator)
! 596: {
! 597: hsi = this->ike_sa->get_my_host(this->ike_sa);
! 598: hsr = this->ike_sa->get_other_host(this->ike_sa);
! 599: }
! 600: else
! 601: {
! 602: hsr = this->ike_sa->get_my_host(this->ike_sa);
! 603: hsi = this->ike_sa->get_other_host(this->ike_sa);
! 604: }
! 605: if (!tsi)
! 606: {
! 607: tsi = traffic_selector_create_from_subnet(hsi->clone(hsi),
! 608: hsi->get_family(hsi) == AF_INET ? 32 : 128, 0, 0, 65535);
! 609: }
! 610: if (!tsr)
! 611: {
! 612: tsr = traffic_selector_create_from_subnet(hsr->clone(hsr),
! 613: hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0, 65535);
! 614: }
! 615: if (this->mode == MODE_TRANSPORT && this->child.encap &&
! 616: (!tsi->is_host(tsi, hsi) || !tsr->is_host(tsr, hsr)))
! 617: { /* change TS in case of a NAT in transport mode */
! 618: DBG2(DBG_IKE, "changing received traffic selectors %R=== %R due to NAT",
! 619: tsi, tsr);
! 620: tsi->set_address(tsi, hsi);
! 621: tsr->set_address(tsr, hsr);
! 622: }
! 623:
! 624: if (this->initiator)
! 625: {
! 626: traffic_selector_t *tsisub, *tsrsub;
! 627:
! 628: /* check if peer selection is valid */
! 629: tsisub = this->tsi->get_subset(this->tsi, tsi);
! 630: tsrsub = this->tsr->get_subset(this->tsr, tsr);
! 631: if (!tsisub || !tsrsub)
! 632: {
! 633: DBG1(DBG_IKE, "peer selected invalid traffic selectors: "
! 634: "%R for %R, %R for %R", tsi, this->tsi, tsr, this->tsr);
! 635: DESTROY_IF(tsisub);
! 636: DESTROY_IF(tsrsub);
! 637: tsi->destroy(tsi);
! 638: tsr->destroy(tsr);
! 639: return FALSE;
! 640: }
! 641: tsi->destroy(tsi);
! 642: tsr->destroy(tsr);
! 643: this->tsi->destroy(this->tsi);
! 644: this->tsr->destroy(this->tsr);
! 645: this->tsi = tsisub;
! 646: this->tsr = tsrsub;
! 647: }
! 648: else
! 649: {
! 650: this->tsi = tsi;
! 651: this->tsr = tsr;
! 652: }
! 653: return TRUE;
! 654: }
! 655:
! 656: /**
! 657: * Get encap
! 658: */
! 659: static encap_t get_encap(ike_sa_t* ike_sa, bool udp)
! 660: {
! 661: if (!udp)
! 662: {
! 663: return ENCAP_NONE;
! 664: }
! 665: if (ike_sa->supports_extension(ike_sa, EXT_NATT_DRAFT_02_03))
! 666: {
! 667: return ENCAP_UDP_DRAFT_00_03;
! 668: }
! 669: return ENCAP_UDP;
! 670: }
! 671:
! 672: /**
! 673: * Get NAT-OA payload type (RFC 3947 or RFC 3947 drafts).
! 674: */
! 675: static payload_type_t get_nat_oa_payload_type(ike_sa_t *ike_sa)
! 676: {
! 677: if (ike_sa->supports_extension(ike_sa, EXT_NATT_DRAFT_02_03))
! 678: {
! 679: return PLV1_NAT_OA_DRAFT_00_03;
! 680: }
! 681: return PLV1_NAT_OA;
! 682: }
! 683:
! 684: /**
! 685: * Add NAT-OA payloads
! 686: */
! 687: static void add_nat_oa_payloads(private_quick_mode_t *this, message_t *message)
! 688: {
! 689: identification_t *id;
! 690: id_payload_t *nat_oa;
! 691: host_t *init, *resp;
! 692: payload_type_t nat_oa_payload_type;
! 693:
! 694: if (this->initiator)
! 695: {
! 696: init = message->get_source(message);
! 697: resp = message->get_destination(message);
! 698: }
! 699: else
! 700: {
! 701: init = message->get_destination(message);
! 702: resp = message->get_source(message);
! 703: }
! 704:
! 705: nat_oa_payload_type = get_nat_oa_payload_type(this->ike_sa);
! 706:
! 707: /* first NAT-OA is the initiator's address */
! 708: id = identification_create_from_sockaddr(init->get_sockaddr(init));
! 709: nat_oa = id_payload_create_from_identification(nat_oa_payload_type, id);
! 710: message->add_payload(message, (payload_t*)nat_oa);
! 711: id->destroy(id);
! 712:
! 713: /* second NAT-OA is that of the responder */
! 714: id = identification_create_from_sockaddr(resp->get_sockaddr(resp));
! 715: nat_oa = id_payload_create_from_identification(nat_oa_payload_type, id);
! 716: message->add_payload(message, (payload_t*)nat_oa);
! 717: id->destroy(id);
! 718: }
! 719:
! 720: /**
! 721: * Look up lifetimes
! 722: */
! 723: static void get_lifetimes(private_quick_mode_t *this)
! 724: {
! 725: lifetime_cfg_t *lft;
! 726:
! 727: lft = this->config->get_lifetime(this->config, TRUE);
! 728: if (lft->time.life)
! 729: {
! 730: this->lifetime = lft->time.life;
! 731: }
! 732: if (lft->bytes.life)
! 733: {
! 734: this->lifebytes = lft->bytes.life;
! 735: }
! 736: free(lft);
! 737: }
! 738:
! 739: /**
! 740: * Check and apply lifetimes
! 741: */
! 742: static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload)
! 743: {
! 744: uint32_t lifetime;
! 745: uint64_t lifebytes;
! 746:
! 747: lifetime = sa_payload->get_lifetime(sa_payload, this->proposal);
! 748: lifebytes = sa_payload->get_lifebytes(sa_payload, this->proposal);
! 749: if (this->lifetime != lifetime)
! 750: {
! 751: DBG1(DBG_IKE, "received %us lifetime, configured %us",
! 752: lifetime, this->lifetime);
! 753: this->lifetime = lifetime;
! 754: }
! 755: if (this->lifebytes != lifebytes)
! 756: {
! 757: DBG1(DBG_IKE, "received %llu lifebytes, configured %llu",
! 758: lifebytes, this->lifebytes);
! 759: this->lifebytes = lifebytes;
! 760: }
! 761: }
! 762:
! 763: /**
! 764: * Set the task ready to build notify error message
! 765: */
! 766: static status_t send_notify(private_quick_mode_t *this, notify_type_t type)
! 767: {
! 768: notify_payload_t *notify;
! 769:
! 770: notify = notify_payload_create_from_protocol_and_type(PLV1_NOTIFY,
! 771: this->proto, type);
! 772: notify->set_spi(notify, this->spi_i);
! 773:
! 774: this->ike_sa->queue_task(this->ike_sa,
! 775: (task_t*)informational_create(this->ike_sa, notify));
! 776: /* cancel all active/passive tasks in favour of informational */
! 777: this->ike_sa->flush_queue(this->ike_sa,
! 778: this->initiator ? TASK_QUEUE_ACTIVE : TASK_QUEUE_PASSIVE);
! 779: return ALREADY_DONE;
! 780: }
! 781:
! 782: /**
! 783: * Prepare a list of proposals from child_config containing only the specified
! 784: * DH group, unless it is set to MODP_NONE.
! 785: */
! 786: static linked_list_t *get_proposals(private_quick_mode_t *this,
! 787: diffie_hellman_group_t group)
! 788: {
! 789: linked_list_t *list;
! 790: proposal_t *proposal;
! 791: enumerator_t *enumerator;
! 792:
! 793: list = this->config->get_proposals(this->config, FALSE);
! 794: enumerator = list->create_enumerator(list);
! 795: while (enumerator->enumerate(enumerator, &proposal))
! 796: {
! 797: if (group != MODP_NONE)
! 798: {
! 799: if (!proposal->has_dh_group(proposal, group))
! 800: {
! 801: list->remove_at(list, enumerator);
! 802: proposal->destroy(proposal);
! 803: continue;
! 804: }
! 805: proposal->promote_dh_group(proposal, group);
! 806: }
! 807: proposal->set_spi(proposal, this->spi_i);
! 808: }
! 809: enumerator->destroy(enumerator);
! 810:
! 811: return list;
! 812: }
! 813:
! 814: METHOD(task_t, build_i, status_t,
! 815: private_quick_mode_t *this, message_t *message)
! 816: {
! 817: switch (this->state)
! 818: {
! 819: case QM_INIT:
! 820: {
! 821: sa_payload_t *sa_payload;
! 822: linked_list_t *list, *tsi, *tsr;
! 823: proposal_t *proposal;
! 824: diffie_hellman_group_t group;
! 825: encap_t encap;
! 826:
! 827: this->mode = this->config->get_mode(this->config);
! 828: this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa,
! 829: TRUE);
! 830: this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa,
! 831: FALSE);
! 832: this->child.encap = this->ike_sa->has_condition(this->ike_sa,
! 833: COND_NAT_ANY);
! 834: this->child_sa = child_sa_create(
! 835: this->ike_sa->get_my_host(this->ike_sa),
! 836: this->ike_sa->get_other_host(this->ike_sa),
! 837: this->config, &this->child);
! 838:
! 839: if (this->child.encap && this->mode == MODE_TRANSPORT)
! 840: {
! 841: /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
! 842: add_nat_oa_payloads(this, message);
! 843: }
! 844:
! 845: if (this->config->has_option(this->config, OPT_IPCOMP))
! 846: {
! 847: this->cpi_i = this->child_sa->alloc_cpi(this->child_sa);
! 848: if (!this->cpi_i)
! 849: {
! 850: DBG1(DBG_IKE, "unable to allocate a CPI from kernel, "
! 851: "IPComp disabled");
! 852: }
! 853: }
! 854:
! 855: list = this->config->get_proposals(this->config, FALSE);
! 856: if (list->get_first(list, (void**)&proposal) == SUCCESS)
! 857: {
! 858: this->proto = proposal->get_protocol(proposal);
! 859: }
! 860: list->destroy_offset(list, offsetof(proposal_t, destroy));
! 861: this->spi_i = this->child_sa->alloc_spi(this->child_sa, this->proto);
! 862: if (!this->spi_i)
! 863: {
! 864: DBG1(DBG_IKE, "allocating SPI from kernel failed");
! 865: return FAILED;
! 866: }
! 867:
! 868: group = this->config->get_dh_group(this->config);
! 869: if (group != MODP_NONE)
! 870: {
! 871: proposal_t *proposal;
! 872: uint16_t preferred_group;
! 873:
! 874: proposal = this->ike_sa->get_proposal(this->ike_sa);
! 875: proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP,
! 876: &preferred_group, NULL);
! 877: /* try the negotiated DH group from IKE_SA */
! 878: list = get_proposals(this, preferred_group);
! 879: if (list->get_count(list))
! 880: {
! 881: group = preferred_group;
! 882: }
! 883: else
! 884: {
! 885: /* fall back to the first configured DH group */
! 886: list->destroy(list);
! 887: list = get_proposals(this, group);
! 888: }
! 889:
! 890: this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
! 891: group);
! 892: if (!this->dh)
! 893: {
! 894: DBG1(DBG_IKE, "configured DH group %N not supported",
! 895: diffie_hellman_group_names, group);
! 896: list->destroy_offset(list, offsetof(proposal_t, destroy));
! 897: return FAILED;
! 898: }
! 899: }
! 900: else
! 901: {
! 902: list = get_proposals(this, MODP_NONE);
! 903: }
! 904:
! 905: get_lifetimes(this);
! 906: encap = get_encap(this->ike_sa, this->child.encap);
! 907: sa_payload = sa_payload_create_from_proposals_v1(list,
! 908: this->lifetime, this->lifebytes, AUTH_NONE,
! 909: this->mode, encap, this->cpi_i);
! 910: list->destroy_offset(list, offsetof(proposal_t, destroy));
! 911: message->add_payload(message, &sa_payload->payload_interface);
! 912:
! 913: if (!add_nonce(this, &this->nonce_i, message))
! 914: {
! 915: return FAILED;
! 916: }
! 917: if (group != MODP_NONE)
! 918: {
! 919: if (!add_ke(this, message))
! 920: {
! 921: return FAILED;
! 922: }
! 923: }
! 924: if (!this->tsi)
! 925: {
! 926: this->tsi = select_ts(this, TRUE, NULL);
! 927: }
! 928: if (!this->tsr)
! 929: {
! 930: this->tsr = select_ts(this, FALSE, NULL);
! 931: }
! 932: tsi = linked_list_create_with_items(this->tsi, NULL);
! 933: tsr = linked_list_create_with_items(this->tsr, NULL);
! 934: this->tsi = this->tsr = NULL;
! 935: charon->bus->narrow(charon->bus, this->child_sa,
! 936: NARROW_INITIATOR_PRE_AUTH, tsi, tsr);
! 937: tsi->remove_first(tsi, (void**)&this->tsi);
! 938: tsr->remove_first(tsr, (void**)&this->tsr);
! 939: tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
! 940: tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
! 941: if (!this->tsi || !this->tsr)
! 942: {
! 943: return FAILED;
! 944: }
! 945: add_ts(this, message);
! 946: return NEED_MORE;
! 947: }
! 948: case QM_NEGOTIATED:
! 949: {
! 950: return SUCCESS;
! 951: }
! 952: default:
! 953: return FAILED;
! 954: }
! 955: }
! 956:
! 957: /**
! 958: * Check for notify errors, return TRUE if error found
! 959: */
! 960: static bool has_notify_errors(private_quick_mode_t *this, message_t *message)
! 961: {
! 962: enumerator_t *enumerator;
! 963: payload_t *payload;
! 964: bool err = FALSE;
! 965:
! 966: enumerator = message->create_payload_enumerator(message);
! 967: while (enumerator->enumerate(enumerator, &payload))
! 968: {
! 969: if (payload->get_type(payload) == PLV1_NOTIFY)
! 970: {
! 971: notify_payload_t *notify;
! 972: notify_type_t type;
! 973:
! 974: notify = (notify_payload_t*)payload;
! 975: type = notify->get_notify_type(notify);
! 976: if (type < 16384)
! 977: {
! 978:
! 979: DBG1(DBG_IKE, "received %N error notify",
! 980: notify_type_names, type);
! 981: err = TRUE;
! 982: }
! 983: else
! 984: {
! 985: DBG1(DBG_IKE, "received %N notify", notify_type_names, type);
! 986: }
! 987: }
! 988: }
! 989: enumerator->destroy(enumerator);
! 990:
! 991: return err;
! 992: }
! 993:
! 994: /**
! 995: * Check if this is a rekey for an existing CHILD_SA, reuse reqid if so
! 996: */
! 997: static void check_for_rekeyed_child(private_quick_mode_t *this, bool responder)
! 998: {
! 999: enumerator_t *enumerator, *policies;
! 1000: traffic_selector_t *local, *remote, *my_ts, *other_ts;
! 1001: child_sa_t *child_sa;
! 1002: proposal_t *proposal;
! 1003: char *name;
! 1004:
! 1005: if (responder)
! 1006: {
! 1007: my_ts = this->tsr;
! 1008: other_ts = this->tsi;
! 1009: }
! 1010: else
! 1011: {
! 1012: my_ts = this->tsi;
! 1013: other_ts = this->tsr;
! 1014: }
! 1015:
! 1016: name = this->config->get_name(this->config);
! 1017: enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
! 1018: while (!this->child.reqid && enumerator->enumerate(enumerator, &child_sa))
! 1019: {
! 1020: if (streq(child_sa->get_name(child_sa), name))
! 1021: {
! 1022: proposal = child_sa->get_proposal(child_sa);
! 1023: switch (child_sa->get_state(child_sa))
! 1024: {
! 1025: case CHILD_INSTALLED:
! 1026: case CHILD_REKEYING:
! 1027: policies = child_sa->create_policy_enumerator(child_sa);
! 1028: if (policies->enumerate(policies, &local, &remote) &&
! 1029: local->equals(local, my_ts) &&
! 1030: remote->equals(remote, other_ts) &&
! 1031: this->proposal->equals(this->proposal, proposal))
! 1032: {
! 1033: this->rekey = child_sa->get_spi(child_sa, TRUE);
! 1034: this->child.reqid = child_sa->get_reqid(child_sa);
! 1035: this->child.mark_in = child_sa->get_mark(child_sa,
! 1036: TRUE).value;
! 1037: this->child.mark_out = child_sa->get_mark(child_sa,
! 1038: FALSE).value;
! 1039: this->child.if_id_in = child_sa->get_if_id(child_sa,
! 1040: TRUE);
! 1041: this->child.if_id_out = child_sa->get_if_id(child_sa,
! 1042: FALSE);
! 1043: child_sa->set_state(child_sa, CHILD_REKEYING);
! 1044: DBG1(DBG_IKE, "detected rekeying of CHILD_SA %s{%u}",
! 1045: child_sa->get_name(child_sa),
! 1046: child_sa->get_unique_id(child_sa));
! 1047: }
! 1048: policies->destroy(policies);
! 1049: break;
! 1050: case CHILD_REKEYED:
! 1051: default:
! 1052: break;
! 1053: }
! 1054: }
! 1055: }
! 1056: enumerator->destroy(enumerator);
! 1057: }
! 1058:
! 1059: METHOD(task_t, process_r, status_t,
! 1060: private_quick_mode_t *this, message_t *message)
! 1061: {
! 1062: if (this->mid && this->mid != message->get_message_id(message))
! 1063: { /* not responsible for this quick mode exchange */
! 1064: return INVALID_ARG;
! 1065: }
! 1066:
! 1067: switch (this->state)
! 1068: {
! 1069: case QM_INIT:
! 1070: {
! 1071: sa_payload_t *sa_payload;
! 1072: linked_list_t *tsi, *tsr, *hostsi, *hostsr, *list = NULL;
! 1073: peer_cfg_t *peer_cfg;
! 1074: uint16_t group;
! 1075: proposal_selection_flag_t flags = 0;
! 1076:
! 1077: sa_payload = (sa_payload_t*)message->get_payload(message,
! 1078: PLV1_SECURITY_ASSOCIATION);
! 1079: if (!sa_payload)
! 1080: {
! 1081: DBG1(DBG_IKE, "sa payload missing");
! 1082: return send_notify(this, INVALID_PAYLOAD_TYPE);
! 1083: }
! 1084:
! 1085: this->mode = sa_payload->get_encap_mode(sa_payload,
! 1086: &this->child.encap);
! 1087:
! 1088: if (!get_ts(this, message))
! 1089: {
! 1090: return FAILED;
! 1091: }
! 1092: peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
! 1093: tsi = linked_list_create_with_items(this->tsi, NULL);
! 1094: tsr = linked_list_create_with_items(this->tsr, NULL);
! 1095: this->tsi = this->tsr = NULL;
! 1096: hostsi = get_dynamic_hosts(this->ike_sa, FALSE);
! 1097: hostsr = get_dynamic_hosts(this->ike_sa, TRUE);
! 1098: this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
! 1099: hostsr, hostsi);
! 1100: hostsi->destroy(hostsi);
! 1101: hostsr->destroy(hostsr);
! 1102: if (this->config)
! 1103: {
! 1104: this->tsi = select_ts(this, FALSE, tsi);
! 1105: this->tsr = select_ts(this, TRUE, tsr);
! 1106: }
! 1107: if (!this->config || !this->tsi || !this->tsr ||
! 1108: this->mode != this->config->get_mode(this->config))
! 1109: {
! 1110: DBG1(DBG_IKE, "no matching CHILD_SA config found for "
! 1111: "%#R === %#R", tsi, tsr);
! 1112: tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
! 1113: tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
! 1114: return send_notify(this, INVALID_ID_INFORMATION);
! 1115: }
! 1116: tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
! 1117: tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
! 1118:
! 1119: if (this->config->has_option(this->config, OPT_IPCOMP))
! 1120: {
! 1121: list = sa_payload->get_ipcomp_proposals(sa_payload,
! 1122: &this->cpi_i);
! 1123: if (!list->get_count(list))
! 1124: {
! 1125: DBG1(DBG_IKE, "expected IPComp proposal but peer did "
! 1126: "not send one, IPComp disabled");
! 1127: this->cpi_i = 0;
! 1128: }
! 1129: }
! 1130: if (!list || !list->get_count(list))
! 1131: {
! 1132: DESTROY_IF(list);
! 1133: list = sa_payload->get_proposals(sa_payload);
! 1134: }
! 1135: if (!this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN)
! 1136: && !lib->settings->get_bool(lib->settings,
! 1137: "%s.accept_private_algs", FALSE, lib->ns))
! 1138: {
! 1139: flags |= PROPOSAL_SKIP_PRIVATE;
! 1140: }
! 1141: if (!lib->settings->get_bool(lib->settings,
! 1142: "%s.prefer_configured_proposals", TRUE, lib->ns))
! 1143: {
! 1144: flags |= PROPOSAL_PREFER_SUPPLIED;
! 1145: }
! 1146: this->proposal = this->config->select_proposal(this->config, list,
! 1147: flags);
! 1148: list->destroy_offset(list, offsetof(proposal_t, destroy));
! 1149:
! 1150: if (!this->proposal)
! 1151: {
! 1152: DBG1(DBG_IKE, "no matching proposal found, sending %N",
! 1153: notify_type_names, NO_PROPOSAL_CHOSEN);
! 1154: return send_notify(this, NO_PROPOSAL_CHOSEN);
! 1155: }
! 1156: this->spi_i = this->proposal->get_spi(this->proposal);
! 1157:
! 1158: get_lifetimes(this);
! 1159: apply_lifetimes(this, sa_payload);
! 1160:
! 1161: if (!get_nonce(this, &this->nonce_i, message))
! 1162: {
! 1163: return send_notify(this, INVALID_PAYLOAD_TYPE);
! 1164: }
! 1165:
! 1166: if (this->proposal->get_algorithm(this->proposal,
! 1167: DIFFIE_HELLMAN_GROUP, &group, NULL))
! 1168: {
! 1169: this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
! 1170: group);
! 1171: if (!this->dh)
! 1172: {
! 1173: DBG1(DBG_IKE, "negotiated DH group %N not supported",
! 1174: diffie_hellman_group_names, group);
! 1175: return send_notify(this, INVALID_KEY_INFORMATION);
! 1176: }
! 1177: if (!get_ke(this, message))
! 1178: {
! 1179: return send_notify(this, INVALID_PAYLOAD_TYPE);
! 1180: }
! 1181: }
! 1182:
! 1183: check_for_rekeyed_child(this, TRUE);
! 1184: this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa,
! 1185: TRUE);
! 1186: this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa,
! 1187: FALSE);
! 1188: this->child_sa = child_sa_create(
! 1189: this->ike_sa->get_my_host(this->ike_sa),
! 1190: this->ike_sa->get_other_host(this->ike_sa),
! 1191: this->config, &this->child);
! 1192:
! 1193: tsi = linked_list_create_with_items(this->tsi, NULL);
! 1194: tsr = linked_list_create_with_items(this->tsr, NULL);
! 1195: this->tsi = this->tsr = NULL;
! 1196: charon->bus->narrow(charon->bus, this->child_sa,
! 1197: NARROW_RESPONDER, tsr, tsi);
! 1198: if (tsi->remove_first(tsi, (void**)&this->tsi) != SUCCESS ||
! 1199: tsr->remove_first(tsr, (void**)&this->tsr) != SUCCESS)
! 1200: {
! 1201: tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
! 1202: tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
! 1203: return send_notify(this, INVALID_ID_INFORMATION);
! 1204: }
! 1205: tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
! 1206: tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
! 1207:
! 1208: return NEED_MORE;
! 1209: }
! 1210: case QM_NEGOTIATED:
! 1211: {
! 1212: if (has_notify_errors(this, message))
! 1213: {
! 1214: return SUCCESS;
! 1215: }
! 1216: if (message->get_exchange_type(message) == INFORMATIONAL_V1)
! 1217: {
! 1218: if (message->get_payload(message, PLV1_DELETE))
! 1219: {
! 1220: /* If the DELETE for a Quick Mode follows immediately
! 1221: * after rekeying, we might receive it before the
! 1222: * third completing Quick Mode message. Ignore it, as
! 1223: * it gets handled by a separately queued delete task. */
! 1224: return NEED_MORE;
! 1225: }
! 1226: return SUCCESS;
! 1227: }
! 1228: if (!this->rekey)
! 1229: {
! 1230: /* do another check in case SAs were created since we handled
! 1231: * the QM request, this is consistent with the rekey check
! 1232: * before installation on the initiator */
! 1233: check_for_rekeyed_child(this, TRUE);
! 1234: if (this->rekey)
! 1235: {
! 1236: this->child_sa->destroy(this->child_sa);
! 1237: this->child_sa = child_sa_create(
! 1238: this->ike_sa->get_my_host(this->ike_sa),
! 1239: this->ike_sa->get_other_host(this->ike_sa),
! 1240: this->config, &this->child);
! 1241: }
! 1242: }
! 1243: if (!install(this))
! 1244: {
! 1245: ike_sa_t *ike_sa = this->ike_sa;
! 1246: task_t *task;
! 1247:
! 1248: task = (task_t*)quick_delete_create(this->ike_sa,
! 1249: this->proposal->get_protocol(this->proposal),
! 1250: this->spi_i, TRUE, TRUE);
! 1251: /* flush_queue() destroys the current task */
! 1252: ike_sa->flush_queue(ike_sa, TASK_QUEUE_PASSIVE);
! 1253: ike_sa->queue_task(ike_sa, task);
! 1254: return ALREADY_DONE;
! 1255: }
! 1256: return SUCCESS;
! 1257: }
! 1258: default:
! 1259: return FAILED;
! 1260: }
! 1261: }
! 1262:
! 1263: METHOD(task_t, build_r, status_t,
! 1264: private_quick_mode_t *this, message_t *message)
! 1265: {
! 1266: if (this->mid && this->mid != message->get_message_id(message))
! 1267: { /* not responsible for this quick mode exchange */
! 1268: return INVALID_ARG;
! 1269: }
! 1270:
! 1271: switch (this->state)
! 1272: {
! 1273: case QM_INIT:
! 1274: {
! 1275: sa_payload_t *sa_payload;
! 1276: encap_t encap;
! 1277:
! 1278: this->proto = this->proposal->get_protocol(this->proposal);
! 1279: this->spi_r = this->child_sa->alloc_spi(this->child_sa, this->proto);
! 1280: if (!this->spi_r)
! 1281: {
! 1282: DBG1(DBG_IKE, "allocating SPI from kernel failed");
! 1283: return send_notify(this, NO_PROPOSAL_CHOSEN);
! 1284: }
! 1285: this->proposal->set_spi(this->proposal, this->spi_r);
! 1286:
! 1287: if (this->cpi_i)
! 1288: {
! 1289: this->cpi_r = this->child_sa->alloc_cpi(this->child_sa);
! 1290: if (!this->cpi_r)
! 1291: {
! 1292: DBG1(DBG_IKE, "unable to allocate a CPI from "
! 1293: "kernel, IPComp disabled");
! 1294: return send_notify(this, NO_PROPOSAL_CHOSEN);
! 1295: }
! 1296: }
! 1297:
! 1298: if (this->child.encap && this->mode == MODE_TRANSPORT)
! 1299: {
! 1300: /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
! 1301: add_nat_oa_payloads(this, message);
! 1302: }
! 1303:
! 1304: encap = get_encap(this->ike_sa, this->child.encap);
! 1305: sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
! 1306: this->lifetime, this->lifebytes, AUTH_NONE,
! 1307: this->mode, encap, this->cpi_r);
! 1308: message->add_payload(message, &sa_payload->payload_interface);
! 1309:
! 1310: if (!add_nonce(this, &this->nonce_r, message))
! 1311: {
! 1312: return FAILED;
! 1313: }
! 1314: if (this->dh)
! 1315: {
! 1316: if (!add_ke(this, message))
! 1317: {
! 1318: return FAILED;
! 1319: }
! 1320: }
! 1321:
! 1322: add_ts(this, message);
! 1323:
! 1324: this->state = QM_NEGOTIATED;
! 1325: this->mid = message->get_message_id(message);
! 1326: return NEED_MORE;
! 1327: }
! 1328: case QM_NEGOTIATED:
! 1329: if (message->get_exchange_type(message) == INFORMATIONAL_V1)
! 1330: {
! 1331: /* skip INFORMATIONAL response if we received a INFORMATIONAL
! 1332: * delete, see process_r() */
! 1333: return ALREADY_DONE;
! 1334: }
! 1335: /* fall */
! 1336: default:
! 1337: return FAILED;
! 1338: }
! 1339: }
! 1340:
! 1341: METHOD(task_t, process_i, status_t,
! 1342: private_quick_mode_t *this, message_t *message)
! 1343: {
! 1344: switch (this->state)
! 1345: {
! 1346: case QM_INIT:
! 1347: {
! 1348: sa_payload_t *sa_payload;
! 1349: linked_list_t *list = NULL;
! 1350: proposal_selection_flag_t flags = 0;
! 1351:
! 1352: sa_payload = (sa_payload_t*)message->get_payload(message,
! 1353: PLV1_SECURITY_ASSOCIATION);
! 1354: if (!sa_payload)
! 1355: {
! 1356: DBG1(DBG_IKE, "sa payload missing");
! 1357: return send_notify(this, NO_PROPOSAL_CHOSEN);
! 1358: }
! 1359: if (this->cpi_i)
! 1360: {
! 1361: list = sa_payload->get_ipcomp_proposals(sa_payload,
! 1362: &this->cpi_r);
! 1363: if (!list->get_count(list))
! 1364: {
! 1365: DBG1(DBG_IKE, "peer did not accept our IPComp proposal, "
! 1366: "IPComp disabled");
! 1367: this->cpi_i = 0;
! 1368: }
! 1369: }
! 1370: if (!list || !list->get_count(list))
! 1371: {
! 1372: DESTROY_IF(list);
! 1373: list = sa_payload->get_proposals(sa_payload);
! 1374: }
! 1375: if (!this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN)
! 1376: && !lib->settings->get_bool(lib->settings,
! 1377: "%s.accept_private_algs", FALSE, lib->ns))
! 1378: {
! 1379: flags |= PROPOSAL_SKIP_PRIVATE;
! 1380: }
! 1381: this->proposal = this->config->select_proposal(this->config, list,
! 1382: flags);
! 1383: list->destroy_offset(list, offsetof(proposal_t, destroy));
! 1384: if (!this->proposal)
! 1385: {
! 1386: DBG1(DBG_IKE, "no matching proposal found");
! 1387: return send_notify(this, NO_PROPOSAL_CHOSEN);
! 1388: }
! 1389: this->spi_r = this->proposal->get_spi(this->proposal);
! 1390:
! 1391: apply_lifetimes(this, sa_payload);
! 1392:
! 1393: if (!get_nonce(this, &this->nonce_r, message))
! 1394: {
! 1395: return send_notify(this, INVALID_PAYLOAD_TYPE);
! 1396: }
! 1397: if (this->dh && !get_ke(this, message))
! 1398: {
! 1399: return send_notify(this, INVALID_KEY_INFORMATION);
! 1400: }
! 1401: if (!get_ts(this, message))
! 1402: {
! 1403: return send_notify(this, INVALID_PAYLOAD_TYPE);
! 1404: }
! 1405: check_for_rekeyed_child(this, FALSE);
! 1406: if (!install(this))
! 1407: {
! 1408: return send_notify(this, NO_PROPOSAL_CHOSEN);
! 1409: }
! 1410: this->state = QM_NEGOTIATED;
! 1411: return NEED_MORE;
! 1412: }
! 1413: default:
! 1414: return FAILED;
! 1415: }
! 1416: }
! 1417:
! 1418: METHOD(task_t, get_type, task_type_t,
! 1419: private_quick_mode_t *this)
! 1420: {
! 1421: return TASK_QUICK_MODE;
! 1422: }
! 1423:
! 1424: METHOD(quick_mode_t, get_mid, uint32_t,
! 1425: private_quick_mode_t *this)
! 1426: {
! 1427: return this->mid;
! 1428: }
! 1429:
! 1430: METHOD(quick_mode_t, use_reqid, void,
! 1431: private_quick_mode_t *this, uint32_t reqid)
! 1432: {
! 1433: this->child.reqid = reqid;
! 1434: }
! 1435:
! 1436: METHOD(quick_mode_t, use_marks, void,
! 1437: private_quick_mode_t *this, uint32_t in, uint32_t out)
! 1438: {
! 1439: this->child.mark_in = in;
! 1440: this->child.mark_out = out;
! 1441: }
! 1442:
! 1443: METHOD(quick_mode_t, use_if_ids, void,
! 1444: private_quick_mode_t *this, uint32_t in, uint32_t out)
! 1445: {
! 1446: this->child.if_id_in = in;
! 1447: this->child.if_id_out = out;
! 1448: }
! 1449:
! 1450: METHOD(quick_mode_t, rekey, void,
! 1451: private_quick_mode_t *this, uint32_t spi)
! 1452: {
! 1453: this->rekey = spi;
! 1454: }
! 1455:
! 1456: METHOD(task_t, migrate, void,
! 1457: private_quick_mode_t *this, ike_sa_t *ike_sa)
! 1458: {
! 1459: chunk_free(&this->nonce_i);
! 1460: chunk_free(&this->nonce_r);
! 1461: DESTROY_IF(this->tsi);
! 1462: DESTROY_IF(this->tsr);
! 1463: DESTROY_IF(this->proposal);
! 1464: DESTROY_IF(this->child_sa);
! 1465: DESTROY_IF(this->dh);
! 1466:
! 1467: this->ike_sa = ike_sa;
! 1468: this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
! 1469: this->state = QM_INIT;
! 1470: this->mid = 0;
! 1471: this->tsi = NULL;
! 1472: this->tsr = NULL;
! 1473: this->proposal = NULL;
! 1474: this->child_sa = NULL;
! 1475: this->dh = NULL;
! 1476: this->spi_i = 0;
! 1477: this->spi_r = 0;
! 1478: this->child = (child_sa_create_t){};
! 1479:
! 1480: if (!this->initiator)
! 1481: {
! 1482: DESTROY_IF(this->config);
! 1483: this->config = NULL;
! 1484: }
! 1485: }
! 1486:
! 1487: METHOD(task_t, destroy, void,
! 1488: private_quick_mode_t *this)
! 1489: {
! 1490: chunk_free(&this->nonce_i);
! 1491: chunk_free(&this->nonce_r);
! 1492: DESTROY_IF(this->tsi);
! 1493: DESTROY_IF(this->tsr);
! 1494: DESTROY_IF(this->proposal);
! 1495: DESTROY_IF(this->child_sa);
! 1496: DESTROY_IF(this->config);
! 1497: DESTROY_IF(this->dh);
! 1498: free(this);
! 1499: }
! 1500:
! 1501: /*
! 1502: * Described in header.
! 1503: */
! 1504: quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
! 1505: traffic_selector_t *tsi, traffic_selector_t *tsr)
! 1506: {
! 1507: private_quick_mode_t *this;
! 1508:
! 1509: INIT(this,
! 1510: .public = {
! 1511: .task = {
! 1512: .get_type = _get_type,
! 1513: .migrate = _migrate,
! 1514: .destroy = _destroy,
! 1515: },
! 1516: .get_mid = _get_mid,
! 1517: .use_reqid = _use_reqid,
! 1518: .use_marks = _use_marks,
! 1519: .use_if_ids = _use_if_ids,
! 1520: .rekey = _rekey,
! 1521: },
! 1522: .ike_sa = ike_sa,
! 1523: .initiator = config != NULL,
! 1524: .config = config,
! 1525: .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
! 1526: .state = QM_INIT,
! 1527: .tsi = tsi ? tsi->clone(tsi) : NULL,
! 1528: .tsr = tsr ? tsr->clone(tsr) : NULL,
! 1529: .proto = PROTO_ESP,
! 1530: .delete = lib->settings->get_bool(lib->settings,
! 1531: "%s.delete_rekeyed", FALSE, lib->ns),
! 1532: );
! 1533:
! 1534: if (config)
! 1535: {
! 1536: this->public.task.build = _build_i;
! 1537: this->public.task.process = _process_i;
! 1538: }
! 1539: else
! 1540: {
! 1541: this->public.task.build = _build_r;
! 1542: this->public.task.process = _process_r;
! 1543: }
! 1544:
! 1545: return &this->public;
! 1546: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>