Annotation of embedaddon/strongswan/src/libipsec/esp_context.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2012-2013 Tobias Brunner
        !             3:  * Copyright (C) 2012 Giuliano Grassi
        !             4:  * Copyright (C) 2012 Ralf Sager
        !             5:  * HSR Hochschule fuer Technik Rapperswil
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or modify it
        !             8:  * under the terms of the GNU General Public License as published by the
        !             9:  * Free Software Foundation; either version 2 of the License, or (at your
        !            10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful, but
        !            13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            15:  * for more details.
        !            16:  */
        !            17: 
        !            18: #include <limits.h>
        !            19: #include <stdint.h>
        !            20: 
        !            21: #include "esp_context.h"
        !            22: 
        !            23: #include <library.h>
        !            24: #include <utils/debug.h>
        !            25: 
        !            26: /**
        !            27:  * Should be a multiple of 8
        !            28:  */
        !            29: #define ESP_DEFAULT_WINDOW_SIZE 128
        !            30: 
        !            31: typedef struct private_esp_context_t private_esp_context_t;
        !            32: 
        !            33: /**
        !            34:  * Private additions to esp_context_t.
        !            35:  */
        !            36: struct private_esp_context_t {
        !            37: 
        !            38:        /**
        !            39:         * Public members
        !            40:         */
        !            41:        esp_context_t public;
        !            42: 
        !            43:        /**
        !            44:         * AEAD wrapper or method to encrypt/decrypt/authenticate ESP packets
        !            45:         */
        !            46:        aead_t *aead;
        !            47: 
        !            48:        /**
        !            49:         * The highest sequence number that was successfully verified
        !            50:         * and authenticated, or assigned in an outbound context
        !            51:         */
        !            52:        uint32_t last_seqno;
        !            53: 
        !            54:        /**
        !            55:         * The bit in the window of the highest authenticated sequence number
        !            56:         */
        !            57:        u_int seqno_index;
        !            58: 
        !            59:        /**
        !            60:         * The size of the anti-replay window (in bits)
        !            61:         */
        !            62:        u_int window_size;
        !            63: 
        !            64:        /**
        !            65:         * The anti-replay window buffer
        !            66:         */
        !            67:        chunk_t window;
        !            68: 
        !            69:        /**
        !            70:         * TRUE in case of an inbound ESP context
        !            71:         */
        !            72:        bool inbound;
        !            73: };
        !            74: 
        !            75: /**
        !            76:  * Set or unset a bit in the window.
        !            77:  */
        !            78: static inline void set_window_bit(private_esp_context_t *this,
        !            79:                                                                  u_int index, bool set)
        !            80: {
        !            81:        u_int i = index / CHAR_BIT;
        !            82: 
        !            83:        if (set)
        !            84:        {
        !            85:                this->window.ptr[i] |= 1 << (index % CHAR_BIT);
        !            86:        }
        !            87:        else
        !            88:        {
        !            89:                this->window.ptr[i] &= ~(1 << (index % CHAR_BIT));
        !            90:        }
        !            91: }
        !            92: 
        !            93: /**
        !            94:  * Get a bit from the window.
        !            95:  */
        !            96: static inline bool get_window_bit(private_esp_context_t *this, u_int index)
        !            97: {
        !            98:        u_int i = index / CHAR_BIT;
        !            99: 
        !           100:        return this->window.ptr[i] & (1 << index % CHAR_BIT);
        !           101: }
        !           102: 
        !           103: /**
        !           104:  * Returns TRUE if the supplied seqno is not already marked in the window
        !           105:  */
        !           106: static bool check_window(private_esp_context_t *this, uint32_t seqno)
        !           107: {
        !           108:        u_int offset;
        !           109: 
        !           110:        offset = this->last_seqno - seqno;
        !           111:        offset = (this->seqno_index - offset) % this->window_size;
        !           112:        return !get_window_bit(this, offset);
        !           113: }
        !           114: 
        !           115: METHOD(esp_context_t, verify_seqno, bool,
        !           116:        private_esp_context_t *this, uint32_t seqno)
        !           117: {
        !           118:        if (!this->inbound)
        !           119:        {
        !           120:                return FALSE;
        !           121:        }
        !           122: 
        !           123:        if (seqno > this->last_seqno)
        !           124:        {       /*       |----------------------------------------|
        !           125:                 *  <---------^   ^   or    <---------^     ^
        !           126:                 *     WIN    H   S            WIN    H     S
        !           127:                 */
        !           128:                return TRUE;
        !           129:        }
        !           130:        else if (seqno > 0 && this->window_size > this->last_seqno - seqno)
        !           131:        {       /*       |----------------------------------------|
        !           132:                 *  <---------^      or     <---------^
        !           133:                 *     WIN ^  H                WIN ^  H
        !           134:                 *         S                       S
        !           135:                 */
        !           136:                return check_window(this, seqno);
        !           137:        }
        !           138:        else
        !           139:        {       /*       |----------------------------------------|
        !           140:                 *                       ^  <---------^
        !           141:                 *                       S     WIN    H
        !           142:                 */
        !           143:                return FALSE;
        !           144:        }
        !           145: }
        !           146: 
        !           147: METHOD(esp_context_t, set_authenticated_seqno, void,
        !           148:        private_esp_context_t *this, uint32_t seqno)
        !           149: {
        !           150:        u_int i, shift;
        !           151: 
        !           152:        if (!this->inbound)
        !           153:        {
        !           154:                return;
        !           155:        }
        !           156: 
        !           157:        if (seqno > this->last_seqno)
        !           158:        {       /* shift the window to the new highest authenticated seqno */
        !           159:                shift = seqno - this->last_seqno;
        !           160:                shift = shift < this->window_size ? shift : this->window_size;
        !           161:                for (i = 0; i < shift; ++i)
        !           162:                {
        !           163:                        this->seqno_index = (this->seqno_index + 1) % this->window_size;
        !           164:                        set_window_bit(this, this->seqno_index, FALSE);
        !           165:                }
        !           166:                set_window_bit(this, this->seqno_index, TRUE);
        !           167:                this->last_seqno = seqno;
        !           168:        }
        !           169:        else
        !           170:        {       /* seqno is inside the window, set the corresponding window bit */
        !           171:                i = this->last_seqno - seqno;
        !           172:                set_window_bit(this, (this->seqno_index - i) % this->window_size, TRUE);
        !           173:        }
        !           174: }
        !           175: 
        !           176: METHOD(esp_context_t, get_seqno, uint32_t,
        !           177:        private_esp_context_t *this)
        !           178: {
        !           179:        return this->last_seqno;
        !           180: }
        !           181: 
        !           182: METHOD(esp_context_t, next_seqno, bool,
        !           183:        private_esp_context_t *this, uint32_t *seqno)
        !           184: {
        !           185:        if (this->inbound || this->last_seqno == UINT32_MAX)
        !           186:        {       /* inbound or segno would cycle */
        !           187:                return FALSE;
        !           188:        }
        !           189:        *seqno = ++this->last_seqno;
        !           190:        return TRUE;
        !           191: }
        !           192: 
        !           193: METHOD(esp_context_t, get_aead, aead_t*,
        !           194:        private_esp_context_t *this)
        !           195: {
        !           196:        return this->aead;
        !           197: }
        !           198: 
        !           199: METHOD(esp_context_t, destroy, void,
        !           200:        private_esp_context_t *this)
        !           201: {
        !           202:        chunk_free(&this->window);
        !           203:        DESTROY_IF(this->aead);
        !           204:        free(this);
        !           205: }
        !           206: 
        !           207: /**
        !           208:  * Create an AEAD algorithm
        !           209:  */
        !           210: static bool create_aead(private_esp_context_t *this, int alg,
        !           211:                                                chunk_t key)
        !           212: {
        !           213:        size_t salt = 0;
        !           214: 
        !           215:        switch (alg)
        !           216:        {
        !           217:                case ENCR_AES_GCM_ICV8:
        !           218:                case ENCR_AES_GCM_ICV12:
        !           219:                case ENCR_AES_GCM_ICV16:
        !           220:                case ENCR_CHACHA20_POLY1305:
        !           221:                        salt = 4;
        !           222:                        break;
        !           223:                case ENCR_AES_CCM_ICV8:
        !           224:                case ENCR_AES_CCM_ICV12:
        !           225:                case ENCR_AES_CCM_ICV16:
        !           226:                case ENCR_CAMELLIA_CCM_ICV8:
        !           227:                case ENCR_CAMELLIA_CCM_ICV12:
        !           228:                case ENCR_CAMELLIA_CCM_ICV16:
        !           229:                        salt = 3;
        !           230:                        break;
        !           231:                default:
        !           232:                        break;
        !           233:        }
        !           234:        if (salt)
        !           235:        {
        !           236:                this->aead = lib->crypto->create_aead(lib->crypto, alg,
        !           237:                                                                                          key.len - salt, salt);
        !           238:        }
        !           239:        if (!this->aead)
        !           240:        {
        !           241:                DBG1(DBG_ESP, "failed to create ESP context: unsupported AEAD "
        !           242:                         "algorithm %N", encryption_algorithm_names, alg);
        !           243:                return FALSE;
        !           244:        }
        !           245:        if (!this->aead->set_key(this->aead, key))
        !           246:        {
        !           247:                DBG1(DBG_ESP, "failed to create ESP context: setting AEAD key failed");
        !           248:                return FALSE;
        !           249:        }
        !           250:        return TRUE;
        !           251: }
        !           252: 
        !           253: /**
        !           254:  * Create AEAD wrapper around traditional encryption/integrity algorithms
        !           255:  */
        !           256: static bool create_traditional(private_esp_context_t *this, int enc_alg,
        !           257:                                                           chunk_t enc_key, int int_alg, chunk_t int_key)
        !           258: {
        !           259:        crypter_t *crypter = NULL;
        !           260:        signer_t *signer = NULL;
        !           261:        iv_gen_t *ivg;
        !           262: 
        !           263:        switch (enc_alg)
        !           264:        {
        !           265:                case ENCR_AES_CTR:
        !           266:                case ENCR_CAMELLIA_CTR:
        !           267:                        /* the key includes a 4 byte salt */
        !           268:                        crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
        !           269:                                                                                                  enc_key.len - 4);
        !           270:                        break;
        !           271:                default:
        !           272:                        crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
        !           273:                                                                                                  enc_key.len);
        !           274:                        break;
        !           275:        }
        !           276:        if (!crypter)
        !           277:        {
        !           278:                DBG1(DBG_ESP, "failed to create ESP context: unsupported encryption "
        !           279:                         "algorithm %N", encryption_algorithm_names, enc_alg);
        !           280:                goto failed;
        !           281:        }
        !           282:        if (!crypter->set_key(crypter, enc_key))
        !           283:        {
        !           284:                DBG1(DBG_ESP, "failed to create ESP context: setting encryption key "
        !           285:                         "failed");
        !           286:                goto failed;
        !           287:        }
        !           288: 
        !           289:        signer = lib->crypto->create_signer(lib->crypto, int_alg);
        !           290:        if (!signer)
        !           291:        {
        !           292:                DBG1(DBG_ESP, "failed to create ESP context: unsupported integrity "
        !           293:                         "algorithm %N", integrity_algorithm_names, int_alg);
        !           294:                goto failed;
        !           295:        }
        !           296:        if (!signer->set_key(signer, int_key))
        !           297:        {
        !           298:                DBG1(DBG_ESP, "failed to create ESP context: setting signature key "
        !           299:                         "failed");
        !           300:                goto failed;
        !           301:        }
        !           302:        ivg = iv_gen_create_for_alg(enc_alg);
        !           303:        if (!ivg)
        !           304:        {
        !           305:                DBG1(DBG_ESP, "failed to create ESP context: creating iv gen failed");
        !           306:                goto failed;
        !           307:        }
        !           308:        this->aead = aead_create(crypter, signer, ivg);
        !           309:        return TRUE;
        !           310: 
        !           311: failed:
        !           312:        DESTROY_IF(crypter);
        !           313:        DESTROY_IF(signer);
        !           314:        return FALSE;
        !           315: }
        !           316: 
        !           317: /**
        !           318:  * Described in header.
        !           319:  */
        !           320: esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
        !           321:                                                                  int int_alg, chunk_t int_key, bool inbound)
        !           322: {
        !           323:        private_esp_context_t *this;
        !           324: 
        !           325:        INIT(this,
        !           326:                .public = {
        !           327:                        .get_aead = _get_aead,
        !           328:                        .get_seqno = _get_seqno,
        !           329:                        .next_seqno = _next_seqno,
        !           330:                        .verify_seqno = _verify_seqno,
        !           331:                        .set_authenticated_seqno = _set_authenticated_seqno,
        !           332:                        .destroy = _destroy,
        !           333:                },
        !           334:                .inbound = inbound,
        !           335:                .window_size = ESP_DEFAULT_WINDOW_SIZE,
        !           336:        );
        !           337: 
        !           338:        if (encryption_algorithm_is_aead(enc_alg))
        !           339:        {
        !           340:                if (!create_aead(this, enc_alg, enc_key))
        !           341:                {
        !           342:                        destroy(this);
        !           343:                        return NULL;
        !           344:                }
        !           345:        }
        !           346:        else
        !           347:        {
        !           348:                if (!create_traditional(this, enc_alg, enc_key, int_alg, int_key))
        !           349:                {
        !           350:                        destroy(this);
        !           351:                        return NULL;
        !           352:                }
        !           353:        }
        !           354: 
        !           355:        if (inbound)
        !           356:        {
        !           357:                this->window = chunk_alloc(this->window_size / CHAR_BIT + 1);
        !           358:                memset(this->window.ptr, 0, this->window.len);
        !           359:        }
        !           360:        return &this->public;
        !           361: }

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