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>