Annotation of embedaddon/strongswan/src/libtls/tls_cache.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2011 Martin Willi
                      3:  * Copyright (C) 2011 revosec AG
                      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 "tls_cache.h"
                     17: 
                     18: #include <utils/debug.h>
                     19: #include <collections/linked_list.h>
                     20: #include <collections/hashtable.h>
                     21: #include <threading/rwlock.h>
                     22: 
                     23: typedef struct private_tls_cache_t private_tls_cache_t;
                     24: 
                     25: /**
                     26:  * Private data of an tls_cache_t object.
                     27:  */
                     28: struct private_tls_cache_t {
                     29: 
                     30:        /**
                     31:         * Public tls_cache_t interface.
                     32:         */
                     33:        tls_cache_t public;
                     34: 
                     35:        /**
                     36:         * Mapping session => entry_t, fast lookup by session
                     37:         */
                     38:        hashtable_t *table;
                     39: 
                     40:        /**
                     41:         * List containing all entries
                     42:         */
                     43:        linked_list_t *list;
                     44: 
                     45:        /**
                     46:         * Lock to list and table
                     47:         */
                     48:        rwlock_t *lock;
                     49: 
                     50:        /**
                     51:         * Session limit
                     52:         */
                     53:        u_int max_sessions;
                     54: 
                     55:        /**
                     56:         * maximum age of a session, in seconds
                     57:         */
                     58:        u_int max_age;
                     59: };
                     60: 
                     61: /**
                     62:  * Hashtable entry
                     63:  */
                     64: typedef struct {
                     65:        /** session identifier */
                     66:        chunk_t session;
                     67:        /** master secret */
                     68:        chunk_t master;
                     69:        /** TLS cipher suite */
                     70:        tls_cipher_suite_t suite;
                     71:        /** optional identity this entry is bound to */
                     72:        identification_t *id;
                     73:        /** time of add */
                     74:        time_t t;
                     75: } entry_t;
                     76: 
                     77: /**
                     78:  * Destroy an entry
                     79:  */
                     80: static void entry_destroy(entry_t *entry)
                     81: {
                     82:        chunk_clear(&entry->session);
                     83:        chunk_clear(&entry->master);
                     84:        DESTROY_IF(entry->id);
                     85:        free(entry);
                     86: }
                     87: 
                     88: /**
                     89:  * Hashtable hash function
                     90:  */
                     91: static u_int hash(chunk_t *key)
                     92: {
                     93:        return chunk_hash(*key);
                     94: }
                     95: 
                     96: /**
                     97:  * Hashtable equals function
                     98:  */
                     99: static bool equals(chunk_t *a, chunk_t *b)
                    100: {
                    101:        return chunk_equals(*a, *b);
                    102: }
                    103: 
                    104: METHOD(tls_cache_t, create_, void,
                    105:        private_tls_cache_t *this, chunk_t session, identification_t *id,
                    106:        chunk_t master, tls_cipher_suite_t suite)
                    107: {
                    108:        entry_t *entry;
                    109: 
                    110:        INIT(entry,
                    111:                .session = chunk_clone(session),
                    112:                .master = chunk_clone(master),
                    113:                .suite = suite,
                    114:                .id = id ? id->clone(id) : NULL,
                    115:                .t = time_monotonic(NULL),
                    116:        );
                    117: 
                    118:        this->lock->write_lock(this->lock);
                    119:        this->list->insert_first(this->list, entry);
                    120:        this->table->put(this->table, &entry->session, entry);
                    121:        if (this->list->get_count(this->list) > this->max_sessions &&
                    122:                this->list->remove_last(this->list, (void**)&entry) == SUCCESS)
                    123:        {
                    124:                DBG2(DBG_TLS, "session limit of %u reached, deleting %#B",
                    125:                         this->max_sessions, &entry->session);
                    126:                this->table->remove(this->table, &entry->session);
                    127:                entry_destroy(entry);
                    128:        }
                    129:        this->lock->unlock(this->lock);
                    130: 
                    131:        DBG2(DBG_TLS, "created TLS session %#B, %d sessions",
                    132:                 &session, this->list->get_count(this->list));
                    133: }
                    134: 
                    135: METHOD(tls_cache_t, lookup, tls_cipher_suite_t,
                    136:        private_tls_cache_t *this, chunk_t session, identification_t *id,
                    137:        chunk_t* master)
                    138: {
                    139:        tls_cipher_suite_t suite = 0;
                    140:        entry_t *entry;
                    141:        time_t now;
                    142:        u_int age;
                    143: 
                    144:        now = time_monotonic(NULL);
                    145: 
                    146:        this->lock->write_lock(this->lock);
                    147:        entry = this->table->get(this->table, &session);
                    148:        if (entry)
                    149:        {
                    150:                age = now - entry->t;
                    151:                if (age <= this->max_age)
                    152:                {
                    153:                        if (!id || !entry->id || id->equals(id, entry->id))
                    154:                        {
                    155:                                *master = chunk_clone(entry->master);
                    156:                                suite = entry->suite;
                    157:                        }
                    158:                }
                    159:                else
                    160:                {
                    161:                        DBG2(DBG_TLS, "TLS session %#B expired: %u seconds", &session, age);
                    162:                }
                    163:        }
                    164:        this->lock->unlock(this->lock);
                    165: 
                    166:        if (suite)
                    167:        {
                    168:                DBG2(DBG_TLS, "resuming TLS session %#B, age %u seconds", &session, age);
                    169:        }
                    170:        return suite;
                    171: }
                    172: 
                    173: METHOD(tls_cache_t, check, chunk_t,
                    174:        private_tls_cache_t *this, identification_t *id)
                    175: {
                    176:        chunk_t session = chunk_empty;
                    177:        enumerator_t *enumerator;
                    178:        entry_t *entry;
                    179:        time_t now;
                    180: 
                    181:        now = time_monotonic(NULL);
                    182:        this->lock->read_lock(this->lock);
                    183:        enumerator = this->list->create_enumerator(this->list);
                    184:        while (enumerator->enumerate(enumerator, &entry))
                    185:        {
                    186:                if (entry->t + this->max_age >= now &&
                    187:                        entry->id && id->equals(id, entry->id))
                    188:                {
                    189:                        session = chunk_clone(entry->session);
                    190:                        break;
                    191:                }
                    192:        }
                    193:        enumerator->destroy(enumerator);
                    194:        this->lock->unlock(this->lock);
                    195: 
                    196:        return session;
                    197: }
                    198: 
                    199: METHOD(tls_cache_t, destroy, void,
                    200:        private_tls_cache_t *this)
                    201: {
                    202:        entry_t *entry;
                    203: 
                    204:        while (this->list->remove_last(this->list, (void**)&entry) == SUCCESS)
                    205:        {
                    206:                entry_destroy(entry);
                    207:        }
                    208:        this->list->destroy(this->list);
                    209:        this->table->destroy(this->table);
                    210:        this->lock->destroy(this->lock);
                    211:        free(this);
                    212: }
                    213: 
                    214: /**
                    215:  * See header
                    216:  */
                    217: tls_cache_t *tls_cache_create(u_int max_sessions, u_int max_age)
                    218: {
                    219:        private_tls_cache_t *this;
                    220: 
                    221:        INIT(this,
                    222:                .public = {
                    223:                        .create = _create_,
                    224:                        .lookup = _lookup,
                    225:                        .check = _check,
                    226:                        .destroy = _destroy,
                    227:                },
                    228:                .table = hashtable_create((hashtable_hash_t)hash,
                    229:                                                                  (hashtable_equals_t)equals, 8),
                    230:                .list = linked_list_create(),
                    231:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
                    232:                .max_sessions = max_sessions,
                    233:                .max_age = max_age,
                    234:        );
                    235: 
                    236:        return &this->public;
                    237: }

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