Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/iv_manager.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2011-2016 Tobias Brunner
        !             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 "iv_manager.h"
        !            17: 
        !            18: #include <library.h>
        !            19: #include <collections/linked_list.h>
        !            20: 
        !            21: /**
        !            22:  * Max. number of IVs/QMs to track.
        !            23:  */
        !            24: #define MAX_EXCHANGES_DEFAULT 3
        !            25: 
        !            26: typedef struct private_iv_manager_t private_iv_manager_t;
        !            27: typedef struct iv_data_t iv_data_t;
        !            28: typedef struct qm_data_t qm_data_t;
        !            29: 
        !            30: /**
        !            31:  * Data stored for IVs.
        !            32:  */
        !            33: struct iv_data_t {
        !            34:        /**
        !            35:         * message ID
        !            36:         */
        !            37:        uint32_t mid;
        !            38: 
        !            39:        /**
        !            40:         * current IV
        !            41:         */
        !            42:        chunk_t iv;
        !            43: 
        !            44:        /**
        !            45:         * last block of encrypted message
        !            46:         */
        !            47:        chunk_t last_block;
        !            48: };
        !            49: 
        !            50: /**
        !            51:  * Private data of a iv_manager_t object.
        !            52:  */
        !            53: struct private_iv_manager_t {
        !            54:        /**
        !            55:         * Implement public interface.
        !            56:         */
        !            57:        iv_manager_t public;
        !            58: 
        !            59:        /**
        !            60:         * Phase 1 IV.
        !            61:         */
        !            62:        iv_data_t phase1_iv;
        !            63: 
        !            64:        /**
        !            65:         * Keep track of IVs for exchanges after phase 1. We store only a limited
        !            66:         * number of IVs in an MRU sort of way. Stores iv_data_t objects.
        !            67:         */
        !            68:        linked_list_t *ivs;
        !            69: 
        !            70:        /**
        !            71:         * Keep track of Nonces during Quick Mode exchanges. Only a limited number
        !            72:         * of QMs are tracked at the same time. Stores qm_data_t objects.
        !            73:         */
        !            74:        linked_list_t *qms;
        !            75: 
        !            76:        /**
        !            77:         * Max. number of IVs/Quick Modes to track.
        !            78:         */
        !            79:        int max_exchanges;
        !            80: 
        !            81:        /**
        !            82:         * Hasher used for IV generation.
        !            83:         */
        !            84:        hasher_t *hasher;
        !            85: 
        !            86:        /*
        !            87:         * Encryption algorithm the block size.
        !            88:         */
        !            89:        size_t block_size;
        !            90: };
        !            91: 
        !            92: /**
        !            93:  * Data stored for Quick Mode exchanges.
        !            94:  */
        !            95: struct qm_data_t {
        !            96:        /**
        !            97:         * Message ID.
        !            98:         */
        !            99:        uint32_t mid;
        !           100: 
        !           101:        /**
        !           102:         * Ni_b (Nonce from first message).
        !           103:         */
        !           104:        chunk_t n_i;
        !           105: 
        !           106:        /**
        !           107:         * Nr_b (Nonce from second message).
        !           108:         */
        !           109:        chunk_t n_r;
        !           110: };
        !           111: 
        !           112: /**
        !           113:  * Destroy an iv_data_t object.
        !           114:  */
        !           115: static void iv_data_destroy(iv_data_t *this)
        !           116: {
        !           117:        chunk_free(&this->last_block);
        !           118:        chunk_free(&this->iv);
        !           119:        free(this);
        !           120: }
        !           121: 
        !           122: /**
        !           123:  * Destroy a qm_data_t object.
        !           124:  */
        !           125: static void qm_data_destroy(qm_data_t *this)
        !           126: {
        !           127:        chunk_free(&this->n_i);
        !           128:        chunk_free(&this->n_r);
        !           129:        free(this);
        !           130: }
        !           131: 
        !           132: /**
        !           133:  * Generate an IV.
        !           134:  */
        !           135: static bool generate_iv(private_iv_manager_t *this, iv_data_t *iv)
        !           136: {
        !           137:        if (iv->mid == 0 || iv->iv.ptr)
        !           138:        {       /* use last block of previous encrypted message */
        !           139:                chunk_free(&iv->iv);
        !           140:                iv->iv = iv->last_block;
        !           141:                iv->last_block = chunk_empty;
        !           142:        }
        !           143:        else
        !           144:        {
        !           145:                /* initial phase 2 IV = hash(last_phase1_block | mid) */
        !           146:                uint32_t net;;
        !           147:                chunk_t data;
        !           148: 
        !           149:                net = htonl(iv->mid);
        !           150:                data = chunk_cata("cc", this->phase1_iv.iv, chunk_from_thing(net));
        !           151:                if (!this->hasher->allocate_hash(this->hasher, data, &iv->iv))
        !           152:                {
        !           153:                        return FALSE;
        !           154:                }
        !           155:                if (iv->iv.len > this->block_size)
        !           156:                {
        !           157:                        iv->iv.len = this->block_size;
        !           158:                }
        !           159:        }
        !           160:        DBG4(DBG_IKE, "next IV for MID %u %B", iv->mid, &iv->iv);
        !           161:        return TRUE;
        !           162: }
        !           163: 
        !           164: /**
        !           165:  * Try to find an IV for the given message ID, if not found, generate it.
        !           166:  */
        !           167: static iv_data_t *lookup_iv(private_iv_manager_t *this, uint32_t mid)
        !           168: {
        !           169:        enumerator_t *enumerator;
        !           170:        iv_data_t *iv, *found = NULL;
        !           171: 
        !           172:        if (mid == 0)
        !           173:        {
        !           174:                return &this->phase1_iv;
        !           175:        }
        !           176: 
        !           177:        enumerator = this->ivs->create_enumerator(this->ivs);
        !           178:        while (enumerator->enumerate(enumerator, &iv))
        !           179:        {
        !           180:                if (iv->mid == mid)
        !           181:                {       /* IV gets moved to the front of the list */
        !           182:                        this->ivs->remove_at(this->ivs, enumerator);
        !           183:                        found = iv;
        !           184:                        break;
        !           185:                }
        !           186:        }
        !           187:        enumerator->destroy(enumerator);
        !           188:        if (!found)
        !           189:        {
        !           190:                INIT(found,
        !           191:                        .mid = mid,
        !           192:                );
        !           193:                if (!generate_iv(this, found))
        !           194:                {
        !           195:                        iv_data_destroy(found);
        !           196:                        return NULL;
        !           197:                }
        !           198:        }
        !           199:        this->ivs->insert_first(this->ivs, found);
        !           200:        /* remove least recently used IV if maximum reached */
        !           201:        if (this->ivs->get_count(this->ivs) > this->max_exchanges &&
        !           202:                this->ivs->remove_last(this->ivs, (void**)&iv) == SUCCESS)
        !           203:        {
        !           204:                iv_data_destroy(iv);
        !           205:        }
        !           206:        return found;
        !           207: }
        !           208: 
        !           209: METHOD(iv_manager_t, init_iv_chain, bool,
        !           210:        private_iv_manager_t *this, chunk_t data, hasher_t *hasher,
        !           211:        size_t block_size)
        !           212: {
        !           213:        this->hasher = hasher;
        !           214:        this->block_size = block_size;
        !           215: 
        !           216:        if (!this->hasher->allocate_hash(this->hasher, data, &this->phase1_iv.iv))
        !           217:        {
        !           218:                return FALSE;
        !           219:        }
        !           220:        if (this->phase1_iv.iv.len > this->block_size)
        !           221:        {
        !           222:                this->phase1_iv.iv.len = this->block_size;
        !           223:        }
        !           224:        DBG4(DBG_IKE, "initial IV %B", &this->phase1_iv.iv);
        !           225:        return TRUE;
        !           226: }
        !           227: 
        !           228: METHOD(iv_manager_t, get_iv, bool,
        !           229:        private_iv_manager_t *this, uint32_t mid, chunk_t *out)
        !           230: {
        !           231:        iv_data_t *iv;
        !           232: 
        !           233:        iv = lookup_iv(this, mid);
        !           234:        if (iv)
        !           235:        {
        !           236:                *out = iv->iv;
        !           237:                return TRUE;
        !           238:        }
        !           239:        return FALSE;
        !           240: }
        !           241: 
        !           242: METHOD(iv_manager_t, update_iv, bool,
        !           243:        private_iv_manager_t *this, uint32_t mid, chunk_t last_block)
        !           244: {
        !           245:        iv_data_t *iv = lookup_iv(this, mid);
        !           246:        if (iv)
        !           247:        {       /* update last block */
        !           248:                chunk_free(&iv->last_block);
        !           249:                iv->last_block = chunk_clone(last_block);
        !           250:                return TRUE;
        !           251:        }
        !           252:        return FALSE;
        !           253: }
        !           254: 
        !           255: METHOD(iv_manager_t, confirm_iv, bool,
        !           256:        private_iv_manager_t *this, uint32_t mid)
        !           257: {
        !           258:        iv_data_t *iv = lookup_iv(this, mid);
        !           259:        if (iv)
        !           260:        {
        !           261:                return generate_iv(this, iv);
        !           262:        }
        !           263:        return FALSE;
        !           264: }
        !           265: 
        !           266: METHOD(iv_manager_t, lookup_quick_mode, void,
        !           267:        private_iv_manager_t *this, uint32_t mid, chunk_t **n_i, chunk_t **n_r)
        !           268: {
        !           269:        enumerator_t *enumerator;
        !           270:        qm_data_t *qm, *found = NULL;
        !           271: 
        !           272:        enumerator = this->qms->create_enumerator(this->qms);
        !           273:        while (enumerator->enumerate(enumerator, &qm))
        !           274:        {
        !           275:                if (qm->mid == mid)
        !           276:                {       /* state gets moved to the front of the list */
        !           277:                        this->qms->remove_at(this->qms, enumerator);
        !           278:                        found = qm;
        !           279:                        break;
        !           280:                }
        !           281:        }
        !           282:        enumerator->destroy(enumerator);
        !           283:        if (!found)
        !           284:        {
        !           285:                INIT(found,
        !           286:                        .mid = mid,
        !           287:                );
        !           288:        }
        !           289: 
        !           290:        *n_i = &found->n_i;
        !           291:        *n_r = &found->n_r;
        !           292: 
        !           293:        this->qms->insert_first(this->qms, found);
        !           294:        /* remove least recently used state if maximum reached */
        !           295:        if (this->qms->get_count(this->qms) > this->max_exchanges &&
        !           296:                this->qms->remove_last(this->qms, (void**)&qm) == SUCCESS)
        !           297:        {
        !           298:                qm_data_destroy(qm);
        !           299:        }
        !           300: }
        !           301: 
        !           302: METHOD(iv_manager_t, remove_quick_mode, void,
        !           303:        private_iv_manager_t *this, uint32_t mid)
        !           304: {
        !           305:        enumerator_t *enumerator;
        !           306:        qm_data_t *qm;
        !           307: 
        !           308:        enumerator = this->qms->create_enumerator(this->qms);
        !           309:        while (enumerator->enumerate(enumerator, &qm))
        !           310:        {
        !           311:                if (qm->mid == mid)
        !           312:                {
        !           313:                        this->qms->remove_at(this->qms, enumerator);
        !           314:                        qm_data_destroy(qm);
        !           315:                        break;
        !           316:                }
        !           317:        }
        !           318:        enumerator->destroy(enumerator);
        !           319: }
        !           320: 
        !           321: METHOD(iv_manager_t, destroy, void,
        !           322:        private_iv_manager_t *this)
        !           323: {
        !           324:        chunk_free(&this->phase1_iv.iv);
        !           325:        chunk_free(&this->phase1_iv.last_block);
        !           326:        this->ivs->destroy_function(this->ivs, (void*)iv_data_destroy);
        !           327:        this->qms->destroy_function(this->qms, (void*)qm_data_destroy);
        !           328:        free(this);
        !           329: }
        !           330: 
        !           331: iv_manager_t *iv_manager_create(int max_exchanges)
        !           332: {
        !           333:        private_iv_manager_t *this;
        !           334: 
        !           335:        INIT(this,
        !           336:                .public = {
        !           337:                        .init_iv_chain = _init_iv_chain,
        !           338:                        .get_iv = _get_iv,
        !           339:                        .update_iv = _update_iv,
        !           340:                        .confirm_iv = _confirm_iv,
        !           341:                        .lookup_quick_mode = _lookup_quick_mode,
        !           342:                        .remove_quick_mode = _remove_quick_mode,
        !           343:                        .destroy = _destroy,
        !           344:                },
        !           345:                .ivs = linked_list_create(),
        !           346:                .qms = linked_list_create(),
        !           347:                .max_exchanges = max_exchanges,
        !           348:        );
        !           349: 
        !           350:        if (!this->max_exchanges)
        !           351:        {
        !           352:                this->max_exchanges = lib->settings->get_int(lib->settings,
        !           353:                                        "%s.max_ikev1_exchanges", MAX_EXCHANGES_DEFAULT, lib->ns);
        !           354:        }
        !           355:        return &this->public;
        !           356: }

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