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>