Annotation of embedaddon/strongswan/src/libtls/tls_cache.c, revision 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>