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>