Annotation of embedaddon/strongswan/src/libcharon/plugins/ha/ha_ike.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2008 Martin Willi
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #include "ha_ike.h"
                     17: 
                     18: #include <sa/ikev2/keymat_v2.h>
                     19: #include <sa/ikev1/keymat_v1.h>
                     20: 
                     21: typedef struct private_ha_ike_t private_ha_ike_t;
                     22: 
                     23: /**
                     24:  * Private data of an ha_ike_t object.
                     25:  */
                     26: struct private_ha_ike_t {
                     27: 
                     28:        /**
                     29:         * Public ha_ike_t interface.
                     30:         */
                     31:        ha_ike_t public;
                     32: 
                     33:        /**
                     34:         * socket we use for syncing
                     35:         */
                     36:        ha_socket_t *socket;
                     37: 
                     38:        /**
                     39:         * tunnel securing sync messages
                     40:         */
                     41:        ha_tunnel_t *tunnel;
                     42: 
                     43:        /**
                     44:         * message cache
                     45:         */
                     46:        ha_cache_t *cache;
                     47: };
                     48: 
                     49: /**
                     50:  * Return condition if it is set on ike_sa
                     51:  */
                     52: static ike_condition_t copy_condition(ike_sa_t *ike_sa, ike_condition_t cond)
                     53: {
                     54:        if (ike_sa->has_condition(ike_sa, cond))
                     55:        {
                     56:                return cond;
                     57:        }
                     58:        return 0;
                     59: }
                     60: 
                     61: /**
                     62:  * Return extension if it is supported by peers IKE_SA
                     63:  */
                     64: static ike_extension_t copy_extension(ike_sa_t *ike_sa, ike_extension_t ext)
                     65: {
                     66:        if (ike_sa->supports_extension(ike_sa, ext))
                     67:        {
                     68:                return ext;
                     69:        }
                     70:        return 0;
                     71: }
                     72: 
                     73: METHOD(listener_t, ike_keys, bool,
                     74:        private_ha_ike_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
                     75:        chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey,
                     76:        shared_key_t *shared, auth_method_t method)
                     77: {
                     78:        ha_message_t *m;
                     79:        chunk_t secret;
                     80:        proposal_t *proposal;
                     81:        uint16_t alg, len;
                     82: 
                     83:        if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
                     84:        {       /* do not sync SA between nodes */
                     85:                return TRUE;
                     86:        }
                     87:        if (!dh->get_shared_secret(dh, &secret))
                     88:        {
                     89:                return TRUE;
                     90:        }
                     91: 
                     92:        m = ha_message_create(HA_IKE_ADD);
                     93:        m->add_attribute(m, HA_IKE_VERSION, ike_sa->get_version(ike_sa));
                     94:        m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
                     95: 
                     96:        if (rekey && rekey->get_version(rekey) == IKEV2)
                     97:        {
                     98:                chunk_t skd;
                     99:                keymat_v2_t *keymat;
                    100: 
                    101:                keymat = (keymat_v2_t*)rekey->get_keymat(rekey);
                    102:                m->add_attribute(m, HA_IKE_REKEY_ID, rekey->get_id(rekey));
                    103:                m->add_attribute(m, HA_ALG_OLD_PRF, keymat->get_skd(keymat, &skd));
                    104:                m->add_attribute(m, HA_OLD_SKD, skd);
                    105:        }
                    106: 
                    107:        proposal = ike_sa->get_proposal(ike_sa);
                    108:        if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &len))
                    109:        {
                    110:                m->add_attribute(m, HA_ALG_ENCR, alg);
                    111:                if (len)
                    112:                {
                    113:                        m->add_attribute(m, HA_ALG_ENCR_LEN, len);
                    114:                }
                    115:        }
                    116:        if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
                    117:        {
                    118:                m->add_attribute(m, HA_ALG_INTEG, alg);
                    119:        }
                    120:        if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
                    121:        {
                    122:                m->add_attribute(m, HA_ALG_PRF, alg);
                    123:        }
                    124:        if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &alg, NULL))
                    125:        {
                    126:                m->add_attribute(m, HA_ALG_DH, alg);
                    127:        }
                    128:        m->add_attribute(m, HA_NONCE_I, nonce_i);
                    129:        m->add_attribute(m, HA_NONCE_R, nonce_r);
                    130:        m->add_attribute(m, HA_SECRET, secret);
                    131:        chunk_clear(&secret);
                    132:        if (ike_sa->get_version(ike_sa) == IKEV1)
                    133:        {
                    134:                if (dh->get_my_public_value(dh, &secret))
                    135:                {
                    136:                        m->add_attribute(m, HA_LOCAL_DH, secret);
                    137:                        chunk_free(&secret);
                    138:                }
                    139:                m->add_attribute(m, HA_REMOTE_DH, dh_other);
                    140:                if (shared)
                    141:                {
                    142:                        m->add_attribute(m, HA_PSK, shared->get_key(shared));
                    143:                }
                    144:                else
                    145:                {
                    146:                        m->add_attribute(m, HA_AUTH_METHOD, method);
                    147:                }
                    148:        }
                    149:        m->add_attribute(m, HA_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
                    150: 
                    151:        this->socket->push(this->socket, m);
                    152:        this->cache->cache(this->cache, ike_sa, m);
                    153: 
                    154:        return TRUE;
                    155: }
                    156: 
                    157: METHOD(listener_t, ike_updown, bool,
                    158:        private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
                    159: {
                    160:        ha_message_t *m;
                    161: 
                    162:        if (ike_sa->get_state(ike_sa) == IKE_PASSIVE)
                    163:        {       /* only sync active IKE_SAs */
                    164:                return TRUE;
                    165:        }
                    166:        if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
                    167:        {       /* do not sync SA between nodes */
                    168:                return TRUE;
                    169:        }
                    170: 
                    171:        if (up)
                    172:        {
                    173:                enumerator_t *enumerator;
                    174:                peer_cfg_t *peer_cfg;
                    175:                uint32_t extension, condition;
                    176:                host_t *addr;
                    177:                ike_sa_id_t *id;
                    178:                identification_t *eap_id;
                    179: 
                    180:                peer_cfg = ike_sa->get_peer_cfg(ike_sa);
                    181: 
                    182:                condition = copy_condition(ike_sa, COND_NAT_ANY)
                    183:                                  | copy_condition(ike_sa, COND_NAT_HERE)
                    184:                                  | copy_condition(ike_sa, COND_NAT_THERE)
                    185:                                  | copy_condition(ike_sa, COND_NAT_FAKE)
                    186:                                  | copy_condition(ike_sa, COND_EAP_AUTHENTICATED)
                    187:                                  | copy_condition(ike_sa, COND_CERTREQ_SEEN)
                    188:                                  | copy_condition(ike_sa, COND_ORIGINAL_INITIATOR)
                    189:                                  | copy_condition(ike_sa, COND_STALE)
                    190:                                  | copy_condition(ike_sa, COND_INIT_CONTACT_SEEN)
                    191:                                  | copy_condition(ike_sa, COND_XAUTH_AUTHENTICATED);
                    192: 
                    193:                extension = copy_extension(ike_sa, EXT_NATT)
                    194:                                  | copy_extension(ike_sa, EXT_MOBIKE)
                    195:                                  | copy_extension(ike_sa, EXT_HASH_AND_URL)
                    196:                                  | copy_extension(ike_sa, EXT_MULTIPLE_AUTH)
                    197:                                  | copy_extension(ike_sa, EXT_STRONGSWAN)
                    198:                                  | copy_extension(ike_sa, EXT_EAP_ONLY_AUTHENTICATION)
                    199:                                  | copy_extension(ike_sa, EXT_MS_WINDOWS)
                    200:                                  | copy_extension(ike_sa, EXT_XAUTH)
                    201:                                  | copy_extension(ike_sa, EXT_DPD);
                    202: 
                    203:                id = ike_sa->get_id(ike_sa);
                    204: 
                    205:                m = ha_message_create(HA_IKE_UPDATE);
                    206:                m->add_attribute(m, HA_IKE_ID, id);
                    207:                m->add_attribute(m, HA_LOCAL_ID, ike_sa->get_my_id(ike_sa));
                    208:                m->add_attribute(m, HA_REMOTE_ID, ike_sa->get_other_id(ike_sa));
                    209:                eap_id = ike_sa->get_other_eap_id(ike_sa);
                    210:                if (!eap_id->equals(eap_id, ike_sa->get_other_id(ike_sa)))
                    211:                {
                    212:                        m->add_attribute(m, HA_REMOTE_EAP_ID, eap_id);
                    213:                }
                    214:                m->add_attribute(m, HA_LOCAL_ADDR, ike_sa->get_my_host(ike_sa));
                    215:                m->add_attribute(m, HA_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
                    216:                m->add_attribute(m, HA_CONDITIONS, condition);
                    217:                m->add_attribute(m, HA_EXTENSIONS, extension);
                    218:                m->add_attribute(m, HA_CONFIG_NAME, peer_cfg->get_name(peer_cfg));
                    219:                enumerator = ike_sa->create_peer_address_enumerator(ike_sa);
                    220:                while (enumerator->enumerate(enumerator, (void**)&addr))
                    221:                {
                    222:                        m->add_attribute(m, HA_PEER_ADDR, addr);
                    223:                }
                    224:                enumerator->destroy(enumerator);
                    225:        }
                    226:        else
                    227:        {
                    228:                m = ha_message_create(HA_IKE_DELETE);
                    229:                m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
                    230:        }
                    231:        this->socket->push(this->socket, m);
                    232:        this->cache->cache(this->cache, ike_sa, m);
                    233:        return TRUE;
                    234: }
                    235: 
                    236: METHOD(listener_t, ike_rekey, bool,
                    237:        private_ha_ike_t *this, ike_sa_t *old, ike_sa_t *new)
                    238: {
                    239:        ike_updown(this, old, FALSE);
                    240:        ike_updown(this, new, TRUE);
                    241:        return TRUE;
                    242: }
                    243: 
                    244: METHOD(listener_t, alert, bool,
                    245:        private_ha_ike_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args)
                    246: {
                    247:        switch (alert)
                    248:        {
                    249:                case ALERT_HALF_OPEN_TIMEOUT:
                    250:                        ike_updown(this, ike_sa, FALSE);
                    251:                        break;
                    252:                default:
                    253:                        break;
                    254:        }
                    255:        return TRUE;
                    256: }
                    257: 
                    258: METHOD(listener_t, ike_state_change, bool,
                    259:        private_ha_ike_t *this, ike_sa_t *ike_sa, ike_sa_state_t new)
                    260: {
                    261:        /* delete any remaining cache entry if IKE_SA gets destroyed */
                    262:        if (new == IKE_DESTROYING)
                    263:        {
                    264:                this->cache->delete(this->cache, ike_sa);
                    265:        }
                    266:        return TRUE;
                    267: }
                    268: 
                    269: /**
                    270:  * Send a virtual IP sync message for remote VIPs
                    271:  */
                    272: static void sync_vips(private_ha_ike_t *this, ike_sa_t *ike_sa)
                    273: {
                    274:        ha_message_t *m = NULL;
                    275:        enumerator_t *enumerator;
                    276:        host_t *vip;
                    277: 
                    278:        enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
                    279:        while (enumerator->enumerate(enumerator, &vip))
                    280:        {
                    281:                if (!m)
                    282:                {
                    283:                        m = ha_message_create(HA_IKE_UPDATE);
                    284:                        m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
                    285:                }
                    286:                m->add_attribute(m, HA_REMOTE_VIP, vip);
                    287:        }
                    288:        enumerator->destroy(enumerator);
                    289: 
                    290:        if (m)
                    291:        {
                    292:                this->socket->push(this->socket, m);
                    293:                this->cache->cache(this->cache, ike_sa, m);
                    294:        }
                    295: }
                    296: 
                    297: METHOD(listener_t, message_hook, bool,
                    298:        private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message,
                    299:        bool incoming, bool plain)
                    300: {
                    301:        if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
                    302:        {       /* do not sync SA between nodes */
                    303:                return TRUE;
                    304:        }
                    305: 
                    306:        if (plain && ike_sa->get_version(ike_sa) == IKEV2)
                    307:        {
                    308:                if (message->get_exchange_type(message) != IKE_SA_INIT &&
                    309:                        message->get_request(message))
                    310:                {       /* we sync on requests, but skip it on IKE_SA_INIT */
                    311:                        ha_message_t *m;
                    312: 
                    313:                        if (incoming)
                    314:                        {
                    315:                                m = ha_message_create(HA_IKE_MID_RESPONDER);
                    316:                        }
                    317:                        else
                    318:                        {
                    319:                                m = ha_message_create(HA_IKE_MID_INITIATOR);
                    320:                        }
                    321:                        m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
                    322:                        m->add_attribute(m, HA_MID, message->get_message_id(message) + 1);
                    323:                        this->socket->push(this->socket, m);
                    324:                        this->cache->cache(this->cache, ike_sa, m);
                    325:                }
                    326:                if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
                    327:                        message->get_exchange_type(message) == IKE_AUTH &&
                    328:                        !message->get_request(message))
                    329:                {       /* After IKE_SA has been established, sync peers virtual IP.
                    330:                         * We cannot sync it in the state_change hook, it is installed later.
                    331:                         * TODO: where to sync local VIP? */
                    332:                        sync_vips(this, ike_sa);
                    333:                }
                    334:        }
                    335:        if (ike_sa->get_version(ike_sa) == IKEV1)
                    336:        {
                    337:                ha_message_t *m;
                    338:                keymat_v1_t *keymat;
                    339:                chunk_t iv;
                    340: 
                    341:                /* we need the last block (or expected next IV) of Phase 1, which gets
                    342:                 * updated after successful en-/decryption depending on direction */
                    343:                if (incoming == plain)
                    344:                {
                    345:                        if (message->get_message_id(message) == 0)
                    346:                        {
                    347:                                keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
                    348:                                if (keymat->get_iv(keymat, 0, &iv))
                    349:                                {
                    350:                                        m = ha_message_create(HA_IKE_IV);
                    351:                                        m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
                    352:                                        m->add_attribute(m, HA_IV, iv);
                    353:                                        this->socket->push(this->socket, m);
                    354:                                        this->cache->cache(this->cache, ike_sa, m);
                    355:                                }
                    356:                        }
                    357:                }
                    358:                if (!plain && !incoming &&
                    359:                        message->get_exchange_type(message) == TRANSACTION)
                    360:                {
                    361:                        sync_vips(this, ike_sa);
                    362:                }
                    363:        }
                    364:        if (plain && ike_sa->get_version(ike_sa) == IKEV1 &&
                    365:                message->get_exchange_type(message) == INFORMATIONAL_V1)
                    366:        {
                    367:                ha_message_t *m;
                    368:                notify_payload_t *notify;
                    369:                chunk_t data;
                    370:                uint32_t seq;
                    371: 
                    372:                notify = message->get_notify(message, DPD_R_U_THERE);
                    373:                if (notify)
                    374:                {
                    375:                        data = notify->get_notification_data(notify);
                    376:                        if (data.len == 4)
                    377:                        {
                    378:                                seq = untoh32(data.ptr);
                    379:                                if (incoming)
                    380:                                {
                    381:                                        m = ha_message_create(HA_IKE_MID_RESPONDER);
                    382:                                }
                    383:                                else
                    384:                                {
                    385:                                        m = ha_message_create(HA_IKE_MID_INITIATOR);
                    386:                                }
                    387:                                m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
                    388:                                m->add_attribute(m, HA_MID, seq + 1);
                    389:                                this->socket->push(this->socket, m);
                    390:                                this->cache->cache(this->cache, ike_sa, m);
                    391:                        }
                    392:                }
                    393:        }
                    394:        return TRUE;
                    395: }
                    396: 
                    397: METHOD(ha_ike_t, destroy, void,
                    398:        private_ha_ike_t *this)
                    399: {
                    400:        free(this);
                    401: }
                    402: 
                    403: /**
                    404:  * See header
                    405:  */
                    406: ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
                    407:                                                ha_cache_t *cache)
                    408: {
                    409:        private_ha_ike_t *this;
                    410: 
                    411:        INIT(this,
                    412:                .public = {
                    413:                        .listener = {
                    414:                                .alert = _alert,
                    415:                                .ike_keys = _ike_keys,
                    416:                                .ike_updown = _ike_updown,
                    417:                                .ike_rekey = _ike_rekey,
                    418:                                .ike_state_change = _ike_state_change,
                    419:                                .message = _message_hook,
                    420:                        },
                    421:                        .destroy = _destroy,
                    422:                },
                    423:                .socket = socket,
                    424:                .tunnel = tunnel,
                    425:                .cache = cache,
                    426:        );
                    427: 
                    428:        return &this->public;
                    429: }
                    430: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>