Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012-2013 Tobias Brunner
! 3: * Copyright (C) 2009 Martin Willi
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16:
! 17: /*
! 18: * Copyright (C) 2012-2014 Volker RĂ¼melin
! 19: *
! 20: * Permission is hereby granted, free of charge, to any person obtaining a copy
! 21: * of this software and associated documentation files (the "Software"), to deal
! 22: * in the Software without restriction, including without limitation the rights
! 23: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 24: * copies of the Software, and to permit persons to whom the Software is
! 25: * furnished to do so, subject to the following conditions:
! 26: *
! 27: * The above copyright notice and this permission notice shall be included in
! 28: * all copies or substantial portions of the Software.
! 29: *
! 30: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 31: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 32: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 33: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 34: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! 35: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! 36: * THE SOFTWARE.
! 37: */
! 38:
! 39: #include "isakmp_vendor.h"
! 40:
! 41: #include <daemon.h>
! 42: #include <encoding/payloads/vendor_id_payload.h>
! 43:
! 44: typedef struct private_isakmp_vendor_t private_isakmp_vendor_t;
! 45:
! 46: /**
! 47: * Private data of an isakmp_vendor_t object.
! 48: */
! 49: struct private_isakmp_vendor_t {
! 50:
! 51: /**
! 52: * Public isakmp_vendor_t interface.
! 53: */
! 54: isakmp_vendor_t public;
! 55:
! 56: /**
! 57: * Associated IKE_SA
! 58: */
! 59: ike_sa_t *ike_sa;
! 60:
! 61: /**
! 62: * Are we the initiator of this task
! 63: */
! 64: bool initiator;
! 65:
! 66: /**
! 67: * Index of best nat traversal VID found
! 68: */
! 69: int best_natt_ext;
! 70:
! 71: /**
! 72: * Number of times we have been invoked
! 73: */
! 74: int count;
! 75: };
! 76:
! 77: /**
! 78: * IKEv1 Vendor ID database
! 79: */
! 80: static struct {
! 81: /* Description */
! 82: char *desc;
! 83: /* extension flag negotiated with vendor ID, if any */
! 84: ike_extension_t extension;
! 85: /* send yourself? */
! 86: bool send;
! 87: /* length of vendor ID string */
! 88: int len;
! 89: /* vendor ID string */
! 90: char *id;
! 91: } vendor_ids[] = {
! 92:
! 93: /* strongSwan MD5("strongSwan") */
! 94: { "strongSwan", EXT_STRONGSWAN, FALSE, 16,
! 95: "\x88\x2f\xe5\x6d\x6f\xd2\x0d\xbc\x22\x51\x61\x3b\x2e\xbe\x5b\xeb"},
! 96:
! 97: /* XAuth, MD5("draft-ietf-ipsra-isakmp-xauth-06.txt") */
! 98: { "XAuth", EXT_XAUTH, TRUE, 8,
! 99: "\x09\x00\x26\x89\xdf\xd6\xb7\x12"},
! 100:
! 101: /* Dead peer detection, RFC 3706 */
! 102: { "DPD", EXT_DPD, TRUE, 16,
! 103: "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00"},
! 104:
! 105: /* CISCO-UNITY, similar to DPD the last two bytes indicate the version */
! 106: { "Cisco Unity", EXT_CISCO_UNITY, FALSE, 16,
! 107: "\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00"},
! 108:
! 109: /* Proprietary IKE fragmentation extension. Capabilities are handled
! 110: * specially on receipt of this VID. Windows peers send this VID
! 111: * without capabilities, but accept it with and without capabilities. */
! 112: { "FRAGMENTATION", EXT_IKE_FRAGMENTATION, FALSE, 20,
! 113: "\x40\x48\xb7\xd5\x6e\xbc\xe8\x85\x25\xe7\xde\x7f\x00\xd6\xc2\xd3\x80\x00\x00\x00"},
! 114:
! 115: /* Windows peers send this VID and a version number */
! 116: { "MS NT5 ISAKMPOAKLEY", EXT_MS_WINDOWS, FALSE, 20,
! 117: "\x1e\x2b\x51\x69\x05\x99\x1c\x7d\x7c\x96\xfc\xbf\xb5\x87\xe4\x61\x00\x00\x00\x00"},
! 118:
! 119: }, vendor_natt_ids[] = {
! 120:
! 121: /* NAT-Traversal VIDs ordered by preference */
! 122:
! 123: /* NAT-Traversal, MD5("RFC 3947") */
! 124: { "NAT-T (RFC 3947)", EXT_NATT, TRUE, 16,
! 125: "\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57\x28\xf2\x0e\x95\x45\x2f"},
! 126:
! 127: { "draft-ietf-ipsec-nat-t-ike-03", EXT_NATT | EXT_NATT_DRAFT_02_03,
! 128: FALSE, 16,
! 129: "\x7d\x94\x19\xa6\x53\x10\xca\x6f\x2c\x17\x9d\x92\x15\x52\x9d\x56"},
! 130:
! 131: { "draft-ietf-ipsec-nat-t-ike-02", EXT_NATT | EXT_NATT_DRAFT_02_03,
! 132: FALSE, 16,
! 133: "\xcd\x60\x46\x43\x35\xdf\x21\xf8\x7c\xfd\xb2\xfc\x68\xb6\xa4\x48"},
! 134:
! 135: { "draft-ietf-ipsec-nat-t-ike-02\\n", EXT_NATT | EXT_NATT_DRAFT_02_03,
! 136: TRUE, 16,
! 137: "\x90\xcb\x80\x91\x3e\xbb\x69\x6e\x08\x63\x81\xb5\xec\x42\x7b\x1f"},
! 138:
! 139: { "draft-ietf-ipsec-nat-t-ike-08", 0, FALSE, 16,
! 140: "\x8f\x8d\x83\x82\x6d\x24\x6b\x6f\xc7\xa8\xa6\xa4\x28\xc1\x1d\xe8"},
! 141:
! 142: { "draft-ietf-ipsec-nat-t-ike-07", 0, FALSE, 16,
! 143: "\x43\x9b\x59\xf8\xba\x67\x6c\x4c\x77\x37\xae\x22\xea\xb8\xf5\x82"},
! 144:
! 145: { "draft-ietf-ipsec-nat-t-ike-06", 0, FALSE, 16,
! 146: "\x4d\x1e\x0e\x13\x6d\xea\xfa\x34\xc4\xf3\xea\x9f\x02\xec\x72\x85"},
! 147:
! 148: { "draft-ietf-ipsec-nat-t-ike-05", 0, FALSE, 16,
! 149: "\x80\xd0\xbb\x3d\xef\x54\x56\x5e\xe8\x46\x45\xd4\xc8\x5c\xe3\xee"},
! 150:
! 151: { "draft-ietf-ipsec-nat-t-ike-04", 0, FALSE, 16,
! 152: "\x99\x09\xb6\x4e\xed\x93\x7c\x65\x73\xde\x52\xac\xe9\x52\xfa\x6b"},
! 153:
! 154: { "draft-ietf-ipsec-nat-t-ike-00", 0, FALSE, 16,
! 155: "\x44\x85\x15\x2d\x18\xb6\xbb\xcd\x0b\xe8\xa8\x46\x95\x79\xdd\xcc"},
! 156:
! 157: { "draft-ietf-ipsec-nat-t-ike", 0, FALSE, 16,
! 158: "\x4d\xf3\x79\x28\xe9\xfc\x4f\xd1\xb3\x26\x21\x70\xd5\x15\xc6\x62"},
! 159:
! 160: { "draft-stenberg-ipsec-nat-traversal-02", 0, FALSE, 16,
! 161: "\x61\x05\xc4\x22\xe7\x68\x47\xe4\x3f\x96\x84\x80\x12\x92\xae\xcd"},
! 162:
! 163: { "draft-stenberg-ipsec-nat-traversal-01", 0, FALSE, 16,
! 164: "\x27\xba\xb5\xdc\x01\xea\x07\x60\xea\x4e\x31\x90\xac\x27\xc0\xd0"},
! 165:
! 166: };
! 167:
! 168: /**
! 169: * According to racoon 0x80000000 seems to indicate support for fragmentation
! 170: * of Aggressive and Main mode messages. 0x40000000 seems to indicate support
! 171: * for fragmentation of base ISAKMP messages (Cisco adds that and thus sends
! 172: * 0xc0000000)
! 173: */
! 174: static const uint32_t fragmentation_ike = 0x80000000;
! 175:
! 176: static bool is_known_vid(chunk_t data, int i)
! 177: {
! 178: switch (vendor_ids[i].extension)
! 179: {
! 180: case EXT_IKE_FRAGMENTATION:
! 181: if (data.len >= 16 && memeq(data.ptr, vendor_ids[i].id, 16))
! 182: {
! 183: switch (data.len)
! 184: {
! 185: case 16:
! 186: return TRUE;
! 187: case 20:
! 188: return untoh32(&data.ptr[16]) & fragmentation_ike;
! 189: }
! 190: }
! 191: break;
! 192: case EXT_MS_WINDOWS:
! 193: return data.len == 20 && memeq(data.ptr, vendor_ids[i].id, 16);
! 194: case EXT_CISCO_UNITY:
! 195: return data.len == 16 && memeq(data.ptr, vendor_ids[i].id, 14);
! 196: default:
! 197: return chunk_equals(data, chunk_create(vendor_ids[i].id,
! 198: vendor_ids[i].len));
! 199: }
! 200: return FALSE;
! 201: }
! 202:
! 203: /**
! 204: * Add supported vendor ID payloads
! 205: */
! 206: static void build(private_isakmp_vendor_t *this, message_t *message)
! 207: {
! 208: vendor_id_payload_t *vid_payload;
! 209: bool strongswan, cisco_unity, fragmentation;
! 210: ike_cfg_t *ike_cfg;
! 211: int i;
! 212:
! 213: strongswan = lib->settings->get_bool(lib->settings,
! 214: "%s.send_vendor_id", FALSE, lib->ns);
! 215: cisco_unity = lib->settings->get_bool(lib->settings,
! 216: "%s.cisco_unity", FALSE, lib->ns);
! 217: ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
! 218: fragmentation = ike_cfg->fragmentation(ike_cfg) != FRAGMENTATION_NO;
! 219: if (!this->initiator && fragmentation)
! 220: {
! 221: fragmentation = this->ike_sa->supports_extension(this->ike_sa,
! 222: EXT_IKE_FRAGMENTATION);
! 223: }
! 224: for (i = 0; i < countof(vendor_ids); i++)
! 225: {
! 226: if (vendor_ids[i].send ||
! 227: (vendor_ids[i].extension == EXT_STRONGSWAN && strongswan) ||
! 228: (vendor_ids[i].extension == EXT_CISCO_UNITY && cisco_unity) ||
! 229: (vendor_ids[i].extension == EXT_IKE_FRAGMENTATION && fragmentation))
! 230: {
! 231: DBG2(DBG_IKE, "sending %s vendor ID", vendor_ids[i].desc);
! 232: vid_payload = vendor_id_payload_create_data(PLV1_VENDOR_ID,
! 233: chunk_clone(chunk_create(vendor_ids[i].id, vendor_ids[i].len)));
! 234: message->add_payload(message, &vid_payload->payload_interface);
! 235: }
! 236: }
! 237: for (i = 0; i < countof(vendor_natt_ids); i++)
! 238: {
! 239: if ((this->initiator && vendor_natt_ids[i].send) ||
! 240: this->best_natt_ext == i)
! 241: {
! 242: DBG2(DBG_IKE, "sending %s vendor ID", vendor_natt_ids[i].desc);
! 243: vid_payload = vendor_id_payload_create_data(PLV1_VENDOR_ID,
! 244: chunk_clone(chunk_create(vendor_natt_ids[i].id,
! 245: vendor_natt_ids[i].len)));
! 246: message->add_payload(message, &vid_payload->payload_interface);
! 247: }
! 248: }
! 249: }
! 250:
! 251: /**
! 252: * Process vendor ID payloads
! 253: */
! 254: static void process(private_isakmp_vendor_t *this, message_t *message)
! 255: {
! 256: enumerator_t *enumerator;
! 257: payload_t *payload;
! 258: int i;
! 259:
! 260: enumerator = message->create_payload_enumerator(message);
! 261: while (enumerator->enumerate(enumerator, &payload))
! 262: {
! 263: if (payload->get_type(payload) == PLV1_VENDOR_ID)
! 264: {
! 265: vendor_id_payload_t *vid;
! 266: bool found = FALSE;
! 267: chunk_t data;
! 268:
! 269: vid = (vendor_id_payload_t*)payload;
! 270: data = vid->get_data(vid);
! 271:
! 272: for (i = 0; i < countof(vendor_ids); i++)
! 273: {
! 274: if (is_known_vid(data, i))
! 275: {
! 276: DBG1(DBG_IKE, "received %s vendor ID", vendor_ids[i].desc);
! 277: if (vendor_ids[i].extension)
! 278: {
! 279: this->ike_sa->enable_extension(this->ike_sa,
! 280: vendor_ids[i].extension);
! 281: }
! 282: found = TRUE;
! 283: break;
! 284: }
! 285: }
! 286: if (!found)
! 287: {
! 288: for (i = 0; i < countof(vendor_natt_ids); i++)
! 289: {
! 290: if (chunk_equals(data, chunk_create(vendor_natt_ids[i].id,
! 291: vendor_natt_ids[i].len)))
! 292: {
! 293: DBG1(DBG_IKE, "received %s vendor ID",
! 294: vendor_natt_ids[i].desc);
! 295: if (vendor_natt_ids[i].extension &&
! 296: (i < this->best_natt_ext || this->best_natt_ext < 0))
! 297: {
! 298: this->best_natt_ext = i;
! 299: }
! 300: found = TRUE;
! 301: break;
! 302: }
! 303: }
! 304: }
! 305: if (!found)
! 306: {
! 307: DBG1(DBG_ENC, "received unknown vendor ID: %#B", &data);
! 308: }
! 309: }
! 310: }
! 311: enumerator->destroy(enumerator);
! 312:
! 313: if (this->best_natt_ext >= 0)
! 314: {
! 315: this->ike_sa->enable_extension(this->ike_sa,
! 316: vendor_natt_ids[this->best_natt_ext].extension);
! 317: }
! 318: }
! 319:
! 320: METHOD(task_t, build_i, status_t,
! 321: private_isakmp_vendor_t *this, message_t *message)
! 322: {
! 323: if (this->count++ == 0)
! 324: {
! 325: build(this, message);
! 326: }
! 327: if (message->get_exchange_type(message) == AGGRESSIVE && this->count > 1)
! 328: {
! 329: return SUCCESS;
! 330: }
! 331: return NEED_MORE;
! 332: }
! 333:
! 334: METHOD(task_t, process_r, status_t,
! 335: private_isakmp_vendor_t *this, message_t *message)
! 336: {
! 337: this->count++;
! 338: process(this, message);
! 339: if (message->get_exchange_type(message) == AGGRESSIVE && this->count > 1)
! 340: {
! 341: return SUCCESS;
! 342: }
! 343: return NEED_MORE;
! 344: }
! 345:
! 346: METHOD(task_t, build_r, status_t,
! 347: private_isakmp_vendor_t *this, message_t *message)
! 348: {
! 349: if (this->count == 1)
! 350: {
! 351: build(this, message);
! 352: }
! 353: if (message->get_exchange_type(message) == ID_PROT && this->count > 2)
! 354: {
! 355: return SUCCESS;
! 356: }
! 357: return NEED_MORE;
! 358: }
! 359:
! 360: METHOD(task_t, process_i, status_t,
! 361: private_isakmp_vendor_t *this, message_t *message)
! 362: {
! 363: process(this, message);
! 364: if (message->get_exchange_type(message) == ID_PROT && this->count > 2)
! 365: {
! 366: return SUCCESS;
! 367: }
! 368: return NEED_MORE;
! 369: }
! 370:
! 371: METHOD(task_t, migrate, void,
! 372: private_isakmp_vendor_t *this, ike_sa_t *ike_sa)
! 373: {
! 374: this->ike_sa = ike_sa;
! 375: this->count = 0;
! 376: }
! 377:
! 378: METHOD(task_t, get_type, task_type_t,
! 379: private_isakmp_vendor_t *this)
! 380: {
! 381: return TASK_ISAKMP_VENDOR;
! 382: }
! 383:
! 384: METHOD(task_t, destroy, void,
! 385: private_isakmp_vendor_t *this)
! 386: {
! 387: free(this);
! 388: }
! 389:
! 390: /**
! 391: * See header
! 392: */
! 393: isakmp_vendor_t *isakmp_vendor_create(ike_sa_t *ike_sa, bool initiator)
! 394: {
! 395: private_isakmp_vendor_t *this;
! 396:
! 397: INIT(this,
! 398: .public = {
! 399: .task = {
! 400: .migrate = _migrate,
! 401: .get_type = _get_type,
! 402: .destroy = _destroy,
! 403: },
! 404: },
! 405: .initiator = initiator,
! 406: .ike_sa = ike_sa,
! 407: .best_natt_ext = -1,
! 408: );
! 409:
! 410: if (initiator)
! 411: {
! 412: this->public.task.build = _build_i;
! 413: this->public.task.process = _process_i;
! 414: }
! 415: else
! 416: {
! 417: this->public.task.build = _build_r;
! 418: this->public.task.process = _process_r;
! 419: }
! 420:
! 421: return &this->public;
! 422: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>