Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/iv_manager.c, revision 1.1.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>