Annotation of embedaddon/strongswan/src/libipsec/esp_context.c, revision 1.1.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>