Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/phase1.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012-2017 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * Copyright (C) 2012 Martin Willi
! 6: * Copyright (C) 2012 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: #include "phase1.h"
! 20:
! 21: #include <daemon.h>
! 22: #include <sa/ikev1/keymat_v1.h>
! 23: #include <encoding/payloads/ke_payload.h>
! 24: #include <encoding/payloads/nonce_payload.h>
! 25: #include <collections/linked_list.h>
! 26:
! 27: typedef struct private_phase1_t private_phase1_t;
! 28:
! 29: /**
! 30: * Private data of an phase1_t object.
! 31: */
! 32: struct private_phase1_t {
! 33:
! 34: /**
! 35: * Public phase1_t interface.
! 36: */
! 37: phase1_t public;
! 38:
! 39: /**
! 40: * IKE_SA we negotiate
! 41: */
! 42: ike_sa_t *ike_sa;
! 43:
! 44: /**
! 45: * Currently selected peer config
! 46: */
! 47: peer_cfg_t *peer_cfg;
! 48:
! 49: /**
! 50: * Other possible peer config candidates
! 51: */
! 52: linked_list_t *candidates;
! 53:
! 54: /**
! 55: * Acting as initiator
! 56: */
! 57: bool initiator;
! 58:
! 59: /**
! 60: * Extracted SA payload bytes
! 61: */
! 62: chunk_t sa_payload;
! 63:
! 64: /**
! 65: * DH exchange
! 66: */
! 67: diffie_hellman_t *dh;
! 68:
! 69: /**
! 70: * Keymat derivation (from SA)
! 71: */
! 72: keymat_v1_t *keymat;
! 73:
! 74: /**
! 75: * Received public DH value from peer
! 76: */
! 77: chunk_t dh_value;
! 78:
! 79: /**
! 80: * Initiators nonce
! 81: */
! 82: chunk_t nonce_i;
! 83:
! 84: /**
! 85: * Responder nonce
! 86: */
! 87: chunk_t nonce_r;
! 88: };
! 89:
! 90: /**
! 91: * Get the first authentication config from peer config
! 92: */
! 93: static auth_cfg_t *get_auth_cfg(peer_cfg_t *peer_cfg, bool local)
! 94: {
! 95: enumerator_t *enumerator;
! 96: auth_cfg_t *cfg = NULL;
! 97:
! 98: enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
! 99: enumerator->enumerate(enumerator, &cfg);
! 100: enumerator->destroy(enumerator);
! 101: return cfg;
! 102: }
! 103:
! 104: /**
! 105: * Find a shared key for the given identities
! 106: */
! 107: static shared_key_t *find_shared_key(identification_t *my_id, host_t *me,
! 108: identification_t *other_id, host_t *other)
! 109: {
! 110: identification_t *any_id = NULL;
! 111: shared_key_t *shared_key;
! 112:
! 113: if (!other_id)
! 114: {
! 115: any_id = identification_create_from_encoding(ID_ANY, chunk_empty);
! 116: other_id = any_id;
! 117: }
! 118: shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE,
! 119: my_id, other_id);
! 120: if (!shared_key)
! 121: {
! 122: DBG1(DBG_IKE, "no shared key found for '%Y'[%H] - '%Y'[%H]",
! 123: my_id, me, other_id, other);
! 124: }
! 125: DESTROY_IF(any_id);
! 126: return shared_key;
! 127: }
! 128:
! 129: /**
! 130: * Lookup a shared secret for this IKE_SA
! 131: */
! 132: static shared_key_t *lookup_shared_key(private_phase1_t *this,
! 133: peer_cfg_t *peer_cfg)
! 134: {
! 135: host_t *me, *other;
! 136: identification_t *my_id, *other_id;
! 137: shared_key_t *shared_key = NULL;
! 138: auth_cfg_t *my_auth, *other_auth;
! 139: enumerator_t *enumerator;
! 140:
! 141: me = this->ike_sa->get_my_host(this->ike_sa);
! 142: other = this->ike_sa->get_other_host(this->ike_sa);
! 143:
! 144: if (peer_cfg)
! 145: { /* as initiator or aggressive responder, use identities */
! 146: my_auth = get_auth_cfg(peer_cfg, TRUE);
! 147: other_auth = get_auth_cfg(peer_cfg, FALSE);
! 148: if (my_auth && other_auth)
! 149: {
! 150: my_id = my_auth->get(my_auth, AUTH_RULE_IDENTITY);
! 151: if (peer_cfg->use_aggressive(peer_cfg))
! 152: {
! 153: other_id = this->ike_sa->get_other_id(this->ike_sa);
! 154: }
! 155: else
! 156: {
! 157: other_id = other_auth->get(other_auth, AUTH_RULE_IDENTITY);
! 158: }
! 159: if (my_id)
! 160: {
! 161: shared_key = find_shared_key(my_id, me, other_id, other);
! 162: }
! 163: }
! 164: }
! 165: else
! 166: { /* as responder, we try to find a config by IP addresses and use the
! 167: * configured identities to find the PSK */
! 168: enumerator = charon->backends->create_peer_cfg_enumerator(
! 169: charon->backends, me, other, NULL, NULL, IKEV1);
! 170: while (enumerator->enumerate(enumerator, &peer_cfg))
! 171: {
! 172: my_auth = get_auth_cfg(peer_cfg, TRUE);
! 173: other_auth = get_auth_cfg(peer_cfg, FALSE);
! 174: if (my_auth && other_auth)
! 175: {
! 176: my_id = my_auth->get(my_auth, AUTH_RULE_IDENTITY);
! 177: other_id = other_auth->get(other_auth, AUTH_RULE_IDENTITY);
! 178: if (my_id)
! 179: {
! 180: shared_key = find_shared_key(my_id, me, other_id, other);
! 181: if (shared_key)
! 182: {
! 183: break;
! 184: }
! 185: }
! 186: }
! 187: }
! 188: enumerator->destroy(enumerator);
! 189: }
! 190: if (!shared_key)
! 191: { /* try to get a PSK for IP addresses */
! 192: my_id = identification_create_from_sockaddr(me->get_sockaddr(me));
! 193: other_id = identification_create_from_sockaddr(
! 194: other->get_sockaddr(other));
! 195: if (my_id && other_id)
! 196: {
! 197: shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE,
! 198: my_id, other_id);
! 199: }
! 200: DESTROY_IF(my_id);
! 201: DESTROY_IF(other_id);
! 202: if (!shared_key)
! 203: {
! 204: DBG1(DBG_IKE, "no shared key found for %H - %H", me, other);
! 205: }
! 206: }
! 207: return shared_key;
! 208: }
! 209:
! 210: METHOD(phase1_t, create_hasher, bool,
! 211: private_phase1_t *this)
! 212: {
! 213: return this->keymat->create_hasher(this->keymat,
! 214: this->ike_sa->get_proposal(this->ike_sa));
! 215: }
! 216:
! 217: METHOD(phase1_t, create_dh, bool,
! 218: private_phase1_t *this, diffie_hellman_group_t group)
! 219: {
! 220: this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, group);
! 221: return this->dh != NULL;
! 222: }
! 223:
! 224: METHOD(phase1_t, derive_keys, bool,
! 225: private_phase1_t *this, peer_cfg_t *peer_cfg, auth_method_t method)
! 226: {
! 227: shared_key_t *shared_key = NULL;
! 228:
! 229: switch (method)
! 230: {
! 231: case AUTH_PSK:
! 232: case AUTH_XAUTH_INIT_PSK:
! 233: case AUTH_XAUTH_RESP_PSK:
! 234: shared_key = lookup_shared_key(this, peer_cfg);
! 235: if (!shared_key)
! 236: {
! 237: return FALSE;
! 238: }
! 239: break;
! 240: default:
! 241: break;
! 242: }
! 243:
! 244: if (!this->keymat->derive_ike_keys(this->keymat,
! 245: this->ike_sa->get_proposal(this->ike_sa),
! 246: this->dh, this->dh_value, this->nonce_i, this->nonce_r,
! 247: this->ike_sa->get_id(this->ike_sa), method, shared_key))
! 248: {
! 249: DESTROY_IF(shared_key);
! 250: DBG1(DBG_IKE, "key derivation for %N failed", auth_method_names, method);
! 251: return FALSE;
! 252: }
! 253: charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, this->dh_value,
! 254: this->nonce_i, this->nonce_r, NULL, shared_key,
! 255: method);
! 256: DESTROY_IF(shared_key);
! 257: return TRUE;
! 258: }
! 259:
! 260: /**
! 261: * Check if a peer skipped authentication by using Hybrid authentication
! 262: */
! 263: static bool skipped_auth(private_phase1_t *this,
! 264: auth_method_t method, bool local)
! 265: {
! 266: bool initiator;
! 267:
! 268: initiator = local == this->initiator;
! 269: if (initiator && method == AUTH_HYBRID_INIT_RSA)
! 270: {
! 271: return TRUE;
! 272: }
! 273: if (!initiator && method == AUTH_HYBRID_RESP_RSA)
! 274: {
! 275: return TRUE;
! 276: }
! 277: return FALSE;
! 278: }
! 279:
! 280: /**
! 281: * Check if remote authentication constraints fulfilled
! 282: */
! 283: static bool check_constraints(private_phase1_t *this, auth_method_t method)
! 284: {
! 285: identification_t *id;
! 286: auth_cfg_t *auth, *cfg;
! 287: peer_cfg_t *peer_cfg;
! 288:
! 289: auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
! 290: /* auth identity to comply */
! 291: id = this->ike_sa->get_other_id(this->ike_sa);
! 292: auth->add(auth, AUTH_RULE_IDENTITY, id->clone(id));
! 293: if (skipped_auth(this, method, FALSE))
! 294: {
! 295: return TRUE;
! 296: }
! 297: peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
! 298: cfg = get_auth_cfg(peer_cfg, FALSE);
! 299: return cfg && auth->complies(auth, cfg, TRUE);
! 300: }
! 301:
! 302: /**
! 303: * Save authentication information after authentication succeeded
! 304: */
! 305: static void save_auth_cfg(private_phase1_t *this,
! 306: auth_method_t method, bool local)
! 307: {
! 308: auth_cfg_t *auth;
! 309:
! 310: if (skipped_auth(this, method, local))
! 311: {
! 312: return;
! 313: }
! 314: auth = auth_cfg_create();
! 315: /* for local config, we _copy_ entries from the config, as it contains
! 316: * certificates we must send later. */
! 317: auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), local);
! 318: this->ike_sa->add_auth_cfg(this->ike_sa, local, auth);
! 319: }
! 320:
! 321: /**
! 322: * Create an authenticator instance
! 323: */
! 324: static authenticator_t* create_authenticator(private_phase1_t *this,
! 325: auth_method_t method, chunk_t id)
! 326: {
! 327: authenticator_t *authenticator;
! 328:
! 329: authenticator = authenticator_create_v1(this->ike_sa, this->initiator,
! 330: method, this->dh, this->dh_value, this->sa_payload, id);
! 331: if (!authenticator)
! 332: {
! 333: DBG1(DBG_IKE, "negotiated authentication method %N not supported",
! 334: auth_method_names, method);
! 335: }
! 336: return authenticator;
! 337: }
! 338:
! 339: METHOD(phase1_t, verify_auth, bool,
! 340: private_phase1_t *this, auth_method_t method, message_t *message,
! 341: chunk_t id_data)
! 342: {
! 343: authenticator_t *authenticator;
! 344: status_t status;
! 345:
! 346: authenticator = create_authenticator(this, method, id_data);
! 347: if (authenticator)
! 348: {
! 349: status = authenticator->process(authenticator, message);
! 350: authenticator->destroy(authenticator);
! 351: if (status == SUCCESS && check_constraints(this, method))
! 352: {
! 353: save_auth_cfg(this, method, FALSE);
! 354: return TRUE;
! 355: }
! 356: }
! 357: return FALSE;
! 358: }
! 359:
! 360: METHOD(phase1_t, build_auth, bool,
! 361: private_phase1_t *this, auth_method_t method, message_t *message,
! 362: chunk_t id_data)
! 363: {
! 364: authenticator_t *authenticator;
! 365: status_t status;
! 366:
! 367: authenticator = create_authenticator(this, method, id_data);
! 368: if (authenticator)
! 369: {
! 370: status = authenticator->build(authenticator, message);
! 371: authenticator->destroy(authenticator);
! 372: if (status == SUCCESS)
! 373: {
! 374: save_auth_cfg(this, method, TRUE);
! 375: return TRUE;
! 376: }
! 377: }
! 378: return FALSE;
! 379: }
! 380:
! 381: /**
! 382: * Get the two auth classes from local or remote config
! 383: */
! 384: static void get_auth_class(peer_cfg_t *peer_cfg, bool local,
! 385: auth_class_t *c1, auth_class_t *c2)
! 386: {
! 387: enumerator_t *enumerator;
! 388: auth_cfg_t *auth;
! 389:
! 390: *c1 = *c2 = AUTH_CLASS_ANY;
! 391:
! 392: enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
! 393: while (enumerator->enumerate(enumerator, &auth))
! 394: {
! 395: if (*c1 == AUTH_CLASS_ANY)
! 396: {
! 397: *c1 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
! 398: }
! 399: else
! 400: {
! 401: *c2 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
! 402: break;
! 403: }
! 404: }
! 405: enumerator->destroy(enumerator);
! 406: }
! 407:
! 408: /**
! 409: * Select an auth method to use by checking what key we have
! 410: */
! 411: static auth_method_t get_pubkey_method(private_phase1_t *this, auth_cfg_t *auth)
! 412: {
! 413: auth_method_t method = AUTH_NONE;
! 414: identification_t *id;
! 415: private_key_t *private;
! 416:
! 417: if (auth)
! 418: {
! 419: id = (identification_t*)auth->get(auth, AUTH_RULE_IDENTITY);
! 420: if (id)
! 421: {
! 422: private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, NULL);
! 423: if (private)
! 424: {
! 425: switch (private->get_type(private))
! 426: {
! 427: case KEY_RSA:
! 428: method = AUTH_RSA;
! 429: break;
! 430: case KEY_ECDSA:
! 431: switch (private->get_keysize(private))
! 432: {
! 433: case 256:
! 434: method = AUTH_ECDSA_256;
! 435: break;
! 436: case 384:
! 437: method = AUTH_ECDSA_384;
! 438: break;
! 439: case 521:
! 440: method = AUTH_ECDSA_521;
! 441: break;
! 442: default:
! 443: DBG1(DBG_IKE, "%d bit ECDSA private key size not "
! 444: "supported", private->get_keysize(private));
! 445: break;
! 446: }
! 447: break;
! 448: default:
! 449: DBG1(DBG_IKE, "private key of type %N not supported",
! 450: key_type_names, private->get_type(private));
! 451: break;
! 452: }
! 453: private->destroy(private);
! 454: }
! 455: else
! 456: {
! 457: DBG1(DBG_IKE, "no private key found for '%Y'", id);
! 458: }
! 459: }
! 460: }
! 461: return method;
! 462: }
! 463:
! 464: /**
! 465: * Calculate authentication method from a peer config
! 466: */
! 467: static auth_method_t calc_auth_method(private_phase1_t *this,
! 468: peer_cfg_t *peer_cfg)
! 469: {
! 470: auth_class_t i1, i2, r1, r2;
! 471:
! 472: get_auth_class(peer_cfg, this->initiator, &i1, &i2);
! 473: get_auth_class(peer_cfg, !this->initiator, &r1, &r2);
! 474:
! 475: if (i1 == AUTH_CLASS_PUBKEY && r1 == AUTH_CLASS_PUBKEY)
! 476: {
! 477: if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY)
! 478: {
! 479: /* for any pubkey method, return RSA */
! 480: return AUTH_RSA;
! 481: }
! 482: if (i2 == AUTH_CLASS_XAUTH)
! 483: {
! 484: return AUTH_XAUTH_INIT_RSA;
! 485: }
! 486: if (r2 == AUTH_CLASS_XAUTH)
! 487: {
! 488: return AUTH_XAUTH_RESP_RSA;
! 489: }
! 490: }
! 491: if (i1 == AUTH_CLASS_PSK && r1 == AUTH_CLASS_PSK)
! 492: {
! 493: if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY)
! 494: {
! 495: return AUTH_PSK;
! 496: }
! 497: if (i2 == AUTH_CLASS_XAUTH)
! 498: {
! 499: return AUTH_XAUTH_INIT_PSK;
! 500: }
! 501: if (r2 == AUTH_CLASS_XAUTH)
! 502: {
! 503: return AUTH_XAUTH_RESP_PSK;
! 504: }
! 505: }
! 506: if (i1 == AUTH_CLASS_XAUTH && r1 == AUTH_CLASS_PUBKEY &&
! 507: i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY)
! 508: {
! 509: return AUTH_HYBRID_INIT_RSA;
! 510: }
! 511: return AUTH_NONE;
! 512: }
! 513:
! 514: METHOD(phase1_t, get_auth_method, auth_method_t,
! 515: private_phase1_t *this, peer_cfg_t *peer_cfg)
! 516: {
! 517: auth_method_t method;
! 518:
! 519: method = calc_auth_method(this, peer_cfg);
! 520: if (method == AUTH_RSA)
! 521: {
! 522: return get_pubkey_method(this, get_auth_cfg(peer_cfg, TRUE));
! 523: }
! 524: return method;
! 525: }
! 526:
! 527: /**
! 528: * Check if a peer config can be used with a given auth method
! 529: */
! 530: static bool check_auth_method(private_phase1_t *this, peer_cfg_t *peer_cfg,
! 531: auth_method_t given)
! 532: {
! 533: auth_method_t method;
! 534:
! 535: method = calc_auth_method(this, peer_cfg);
! 536: switch (given)
! 537: {
! 538: case AUTH_ECDSA_256:
! 539: case AUTH_ECDSA_384:
! 540: case AUTH_ECDSA_521:
! 541: return method == AUTH_RSA;
! 542: default:
! 543: return method == given;
! 544: }
! 545: }
! 546:
! 547: METHOD(phase1_t, select_config, peer_cfg_t*,
! 548: private_phase1_t *this, auth_method_t method, bool aggressive,
! 549: identification_t *id)
! 550: {
! 551: enumerator_t *enumerator;
! 552: peer_cfg_t *current;
! 553: host_t *me, *other;
! 554: int unusable = 0;
! 555:
! 556: if (this->peer_cfg)
! 557: { /* try to find an alternative config */
! 558: if (this->candidates->remove_first(this->candidates,
! 559: (void**)¤t) != SUCCESS)
! 560: {
! 561: DBG1(DBG_CFG, "no alternative config found");
! 562: return NULL;
! 563: }
! 564: DBG1(DBG_CFG, "switching to peer config '%s'",
! 565: current->get_name(current));
! 566: return current;
! 567: }
! 568:
! 569: me = this->ike_sa->get_my_host(this->ike_sa);
! 570: other = this->ike_sa->get_other_host(this->ike_sa);
! 571: DBG1(DBG_CFG, "looking for %N peer configs matching %H...%H[%Y]",
! 572: auth_method_names, method, me, other, id);
! 573: enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
! 574: me, other, NULL, id, IKEV1);
! 575: while (enumerator->enumerate(enumerator, ¤t))
! 576: {
! 577: if (check_auth_method(this, current, method) &&
! 578: current->use_aggressive(current) == aggressive)
! 579: {
! 580: current->get_ref(current);
! 581: if (!this->peer_cfg)
! 582: {
! 583: this->peer_cfg = current;
! 584: }
! 585: else
! 586: {
! 587: this->candidates->insert_last(this->candidates, current);
! 588: }
! 589: }
! 590: else
! 591: {
! 592: unusable++;
! 593: }
! 594: }
! 595: enumerator->destroy(enumerator);
! 596:
! 597: if (this->peer_cfg)
! 598: {
! 599: DBG1(DBG_CFG, "selected peer config \"%s\"",
! 600: this->peer_cfg->get_name(this->peer_cfg));
! 601: return this->peer_cfg->get_ref(this->peer_cfg);
! 602: }
! 603: if (unusable)
! 604: {
! 605: DBG1(DBG_IKE, "found %d matching config%s, but none allows %N "
! 606: "authentication using %s Mode", unusable, unusable > 1 ? "s" : "",
! 607: auth_method_names, method, aggressive ? "Aggressive" : "Main");
! 608: return NULL;
! 609: }
! 610: DBG1(DBG_IKE, "no peer config found");
! 611: return NULL;
! 612: }
! 613:
! 614: METHOD(phase1_t, get_id, identification_t*,
! 615: private_phase1_t *this, peer_cfg_t *peer_cfg, bool local)
! 616: {
! 617: identification_t *id = NULL;
! 618: auth_cfg_t *auth;
! 619:
! 620: auth = get_auth_cfg(peer_cfg, local);
! 621: if (auth)
! 622: {
! 623: id = auth->get(auth, AUTH_RULE_IDENTITY);
! 624: if (local && (!id || id->get_type(id) == ID_ANY))
! 625: { /* no ID configured, use local IP address */
! 626: host_t *me;
! 627:
! 628: me = this->ike_sa->get_my_host(this->ike_sa);
! 629: if (!me->is_anyaddr(me))
! 630: {
! 631: id = identification_create_from_sockaddr(me->get_sockaddr(me));
! 632: auth->add(auth, AUTH_RULE_IDENTITY, id);
! 633: }
! 634: }
! 635: }
! 636: return id;
! 637: }
! 638:
! 639: METHOD(phase1_t, has_virtual_ip, bool,
! 640: private_phase1_t *this, peer_cfg_t *peer_cfg)
! 641: {
! 642: enumerator_t *enumerator;
! 643: bool found = FALSE;
! 644: host_t *host;
! 645:
! 646: enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg);
! 647: found = enumerator->enumerate(enumerator, &host);
! 648: enumerator->destroy(enumerator);
! 649:
! 650: return found;
! 651: }
! 652:
! 653: METHOD(phase1_t, has_pool, bool,
! 654: private_phase1_t *this, peer_cfg_t *peer_cfg)
! 655: {
! 656: enumerator_t *enumerator;
! 657: bool found = FALSE;
! 658: char *pool;
! 659:
! 660: enumerator = peer_cfg->create_pool_enumerator(peer_cfg);
! 661: found = enumerator->enumerate(enumerator, &pool);
! 662: enumerator->destroy(enumerator);
! 663:
! 664: return found;
! 665: }
! 666:
! 667: METHOD(phase1_t, save_sa_payload, bool,
! 668: private_phase1_t *this, message_t *message)
! 669: {
! 670: enumerator_t *enumerator;
! 671: payload_t *payload, *sa = NULL;
! 672: chunk_t data;
! 673: size_t offset = IKE_HEADER_LENGTH;
! 674:
! 675: enumerator = message->create_payload_enumerator(message);
! 676: while (enumerator->enumerate(enumerator, &payload))
! 677: {
! 678: if (payload->get_type(payload) == PLV1_SECURITY_ASSOCIATION)
! 679: {
! 680: sa = payload;
! 681: break;
! 682: }
! 683: else
! 684: {
! 685: offset += payload->get_length(payload);
! 686: }
! 687: }
! 688: enumerator->destroy(enumerator);
! 689:
! 690: data = message->get_packet_data(message);
! 691: if (sa && data.len >= offset + sa->get_length(sa))
! 692: {
! 693: /* Get SA payload without 4 byte fixed header */
! 694: data = chunk_skip(data, offset);
! 695: data.len = sa->get_length(sa);
! 696: data = chunk_skip(data, 4);
! 697: this->sa_payload = chunk_clone(data);
! 698: return TRUE;
! 699: }
! 700: DBG1(DBG_IKE, "unable to extract SA payload encoding");
! 701: return FALSE;
! 702: }
! 703:
! 704: METHOD(phase1_t, add_nonce_ke, bool,
! 705: private_phase1_t *this, message_t *message)
! 706: {
! 707: nonce_payload_t *nonce_payload;
! 708: ke_payload_t *ke_payload;
! 709: nonce_gen_t *nonceg;
! 710: chunk_t nonce;
! 711:
! 712: ke_payload = ke_payload_create_from_diffie_hellman(PLV1_KEY_EXCHANGE,
! 713: this->dh);
! 714: if (!ke_payload)
! 715: {
! 716: DBG1(DBG_IKE, "creating KE payload failed");
! 717: return FALSE;
! 718: }
! 719: message->add_payload(message, &ke_payload->payload_interface);
! 720:
! 721: nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat);
! 722: if (!nonceg)
! 723: {
! 724: DBG1(DBG_IKE, "no nonce generator found to create nonce");
! 725: return FALSE;
! 726: }
! 727: if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, &nonce))
! 728: {
! 729: DBG1(DBG_IKE, "nonce allocation failed");
! 730: nonceg->destroy(nonceg);
! 731: return FALSE;
! 732: }
! 733: nonceg->destroy(nonceg);
! 734:
! 735: nonce_payload = nonce_payload_create(PLV1_NONCE);
! 736: nonce_payload->set_nonce(nonce_payload, nonce);
! 737: message->add_payload(message, &nonce_payload->payload_interface);
! 738:
! 739: if (this->initiator)
! 740: {
! 741: this->nonce_i = nonce;
! 742: }
! 743: else
! 744: {
! 745: this->nonce_r = nonce;
! 746: }
! 747: return TRUE;
! 748: }
! 749:
! 750: METHOD(phase1_t, get_nonce_ke, bool,
! 751: private_phase1_t *this, message_t *message)
! 752: {
! 753: nonce_payload_t *nonce_payload;
! 754: ke_payload_t *ke_payload;
! 755:
! 756: ke_payload = (ke_payload_t*)message->get_payload(message, PLV1_KEY_EXCHANGE);
! 757: if (!ke_payload)
! 758: {
! 759: DBG1(DBG_IKE, "KE payload missing in message");
! 760: return FALSE;
! 761: }
! 762: this->dh_value = chunk_clone(ke_payload->get_key_exchange_data(ke_payload));
! 763: if (!this->dh->set_other_public_value(this->dh, this->dh_value))
! 764: {
! 765: DBG1(DBG_IKE, "unable to apply received KE value");
! 766: return FALSE;
! 767: }
! 768:
! 769: nonce_payload = (nonce_payload_t*)message->get_payload(message, PLV1_NONCE);
! 770: if (!nonce_payload)
! 771: {
! 772: DBG1(DBG_IKE, "NONCE payload missing in message");
! 773: return FALSE;
! 774: }
! 775:
! 776: if (this->initiator)
! 777: {
! 778: this->nonce_r = nonce_payload->get_nonce(nonce_payload);
! 779: }
! 780: else
! 781: {
! 782: this->nonce_i = nonce_payload->get_nonce(nonce_payload);
! 783: }
! 784: return TRUE;
! 785: }
! 786:
! 787: METHOD(phase1_t, destroy, void,
! 788: private_phase1_t *this)
! 789: {
! 790: DESTROY_IF(this->peer_cfg);
! 791: this->candidates->destroy_offset(this->candidates,
! 792: offsetof(peer_cfg_t, destroy));
! 793: chunk_free(&this->sa_payload);
! 794: DESTROY_IF(this->dh);
! 795: free(this->dh_value.ptr);
! 796: free(this->nonce_i.ptr);
! 797: free(this->nonce_r.ptr);
! 798: free(this);
! 799: }
! 800:
! 801: /**
! 802: * See header
! 803: */
! 804: phase1_t *phase1_create(ike_sa_t *ike_sa, bool initiator)
! 805: {
! 806: private_phase1_t *this;
! 807:
! 808: INIT(this,
! 809: .public = {
! 810: .create_hasher = _create_hasher,
! 811: .create_dh = _create_dh,
! 812: .derive_keys = _derive_keys,
! 813: .get_auth_method = _get_auth_method,
! 814: .get_id = _get_id,
! 815: .select_config = _select_config,
! 816: .has_virtual_ip = _has_virtual_ip,
! 817: .has_pool = _has_pool,
! 818: .verify_auth = _verify_auth,
! 819: .build_auth = _build_auth,
! 820: .save_sa_payload = _save_sa_payload,
! 821: .add_nonce_ke = _add_nonce_ke,
! 822: .get_nonce_ke = _get_nonce_ke,
! 823: .destroy = _destroy,
! 824: },
! 825: .candidates = linked_list_create(),
! 826: .ike_sa = ike_sa,
! 827: .initiator = initiator,
! 828: .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
! 829: );
! 830:
! 831: return &this->public;
! 832: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>