cabbdaec7ed29d8fe7fa1800ec38ac5c86d20c11
[strongswan.git] / src / libstrongswan / credentials / sets / mem_cred.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 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 "mem_cred.h"
17
18 #include <threading/rwlock.h>
19 #include <utils/linked_list.h>
20
21 typedef struct private_mem_cred_t private_mem_cred_t;
22
23 /**
24 * Private data of an mem_cred_t object.
25 */
26 struct private_mem_cred_t {
27
28 /**
29 * Public mem_cred_t interface.
30 */
31 mem_cred_t public;
32
33 /**
34 * Lock for this set
35 */
36 rwlock_t *lock;
37
38 /**
39 * List of trusted certificates, certificate_t
40 */
41 linked_list_t *trusted;
42
43 /**
44 * List of trusted and untrusted certificates, certificate_t
45 */
46 linked_list_t *untrusted;
47
48 /**
49 * List of private keys, private_key_t
50 */
51 linked_list_t *keys;
52
53 /**
54 * List of shared keys, as shared_entry_t
55 */
56 linked_list_t *shared;
57 };
58
59 /**
60 * Data for the certificate enumerator
61 */
62 typedef struct {
63 rwlock_t *lock;
64 certificate_type_t cert;
65 key_type_t key;
66 identification_t *id;
67 } cert_data_t;
68
69 /**
70 * destroy cert_data
71 */
72 static void cert_data_destroy(cert_data_t *data)
73 {
74 data->lock->unlock(data->lock);
75 free(data);
76 }
77
78 /**
79 * filter function for certs enumerator
80 */
81 static bool certs_filter(cert_data_t *data, certificate_t **in, certificate_t **out)
82 {
83 public_key_t *public;
84 certificate_t *cert = *in;
85
86 if (data->cert == CERT_ANY || data->cert == cert->get_type(cert))
87 {
88 public = cert->get_public_key(cert);
89 if (public)
90 {
91 if (data->key == KEY_ANY || data->key == public->get_type(public))
92 {
93 if (data->id && public->has_fingerprint(public,
94 data->id->get_encoding(data->id)))
95 {
96 public->destroy(public);
97 *out = *in;
98 return TRUE;
99 }
100 }
101 public->destroy(public);
102 }
103 else if (data->key != KEY_ANY)
104 {
105 return FALSE;
106 }
107 if (data->id == NULL || cert->has_subject(cert, data->id))
108 {
109 *out = *in;
110 return TRUE;
111 }
112 }
113 return FALSE;
114 }
115
116 METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
117 private_mem_cred_t *this, certificate_type_t cert, key_type_t key,
118 identification_t *id, bool trusted)
119 {
120 cert_data_t *data;
121 enumerator_t *enumerator;
122
123 INIT(data,
124 .lock = this->lock,
125 .cert = cert,
126 .key = key,
127 .id = id,
128 );
129 this->lock->read_lock(this->lock);
130 if (trusted)
131 {
132 enumerator = this->trusted->create_enumerator(this->trusted);
133 }
134 else
135 {
136 enumerator = this->untrusted->create_enumerator(this->untrusted);
137 }
138 return enumerator_create_filter(enumerator, (void*)certs_filter, data,
139 (void*)cert_data_destroy);
140 }
141
142 METHOD(mem_cred_t, add_cert, void,
143 private_mem_cred_t *this, bool trusted, certificate_t *cert)
144 {
145 this->lock->write_lock(this->lock);
146 if (trusted)
147 {
148 this->trusted->insert_last(this->trusted, cert->get_ref(cert));
149 }
150 this->untrusted->insert_last(this->untrusted, cert);
151 this->lock->unlock(this->lock);
152 }
153
154 /**
155 * Data for key enumerator
156 */
157 typedef struct {
158 rwlock_t *lock;
159 key_type_t type;
160 identification_t *id;
161 } key_data_t;
162
163 /**
164 * Destroy key enumerator data
165 */
166 static void key_data_destroy(key_data_t *data)
167 {
168 data->lock->unlock(data->lock);
169 free(data);
170 }
171
172 /**
173 * filter function for private key enumerator
174 */
175 static bool key_filter(key_data_t *data, private_key_t **in, private_key_t **out)
176 {
177 private_key_t *key;
178
179 key = *in;
180 if (data->type == KEY_ANY || data->type == key->get_type(key))
181 {
182 if (data->id == NULL ||
183 key->has_fingerprint(key, data->id->get_encoding(data->id)))
184 {
185 *out = key;
186 return TRUE;
187 }
188 }
189 return FALSE;
190 }
191
192 METHOD(credential_set_t, create_private_enumerator, enumerator_t*,
193 private_mem_cred_t *this, key_type_t type, identification_t *id)
194 {
195 key_data_t *data;
196
197 INIT(data,
198 .lock = this->lock,
199 .type = type,
200 .id = id,
201 );
202 this->lock->read_lock(this->lock);
203 return enumerator_create_filter(this->keys->create_enumerator(this->keys),
204 (void*)key_filter, data, (void*)key_data_destroy);
205 }
206
207 METHOD(mem_cred_t, add_key, void,
208 private_mem_cred_t *this, private_key_t *key)
209 {
210 this->lock->write_lock(this->lock);
211 this->keys->insert_last(this->keys, key);
212 this->lock->unlock(this->lock);
213 }
214
215 /**
216 * Shared key entry
217 */
218 typedef struct {
219 /* shared key */
220 shared_key_t *shared;
221 /* list of owners, identification_t */
222 linked_list_t *owners;
223 } shared_entry_t;
224
225 /**
226 * Clean up a shared entry
227 */
228 static void shared_entry_destroy(shared_entry_t *entry)
229 {
230 entry->owners->destroy_offset(entry->owners,
231 offsetof(identification_t, destroy));
232 entry->shared->destroy(entry->shared);
233 free(entry);
234 }
235
236 /**
237 * Data for the shared_key enumerator
238 */
239 typedef struct {
240 rwlock_t *lock;
241 identification_t *me;
242 identification_t *other;
243 shared_key_type_t type;
244 } shared_data_t;
245
246 /**
247 * free shared key enumerator data and unlock list
248 */
249 static void shared_data_destroy(shared_data_t *data)
250 {
251 data->lock->unlock(data->lock);
252 free(data);
253 }
254
255 /**
256 * Get the best match of an owner in an entry.
257 */
258 static id_match_t has_owner(shared_entry_t *entry, identification_t *owner)
259 {
260 enumerator_t *enumerator;
261 id_match_t match, best = ID_MATCH_NONE;
262 identification_t *current;
263
264 enumerator = entry->owners->create_enumerator(entry->owners);
265 while (enumerator->enumerate(enumerator, &current))
266 {
267 match = owner->matches(owner, current);
268 if (match > best)
269 {
270 best = match;
271 }
272 }
273 enumerator->destroy(enumerator);
274 return best;
275 }
276
277 /**
278 * enumerator filter function for shared entries
279 */
280 static bool shared_filter(shared_data_t *data,
281 shared_entry_t **in, shared_key_t **out,
282 void **unused1, id_match_t *me,
283 void **unused2, id_match_t *other)
284 {
285 id_match_t my_match = ID_MATCH_NONE, other_match = ID_MATCH_NONE;
286 shared_entry_t *entry = *in;
287
288 if (data->type != SHARED_ANY &&
289 entry->shared->get_type(entry->shared) != data->type)
290 {
291 return FALSE;
292 }
293 if (data->me)
294 {
295 my_match = has_owner(entry, data->me);
296 }
297 if (data->other)
298 {
299 other_match = has_owner(entry, data->other);
300 }
301 if ((data->me || data->other) && (!my_match && !other_match))
302 {
303 return FALSE;
304 }
305 *out = entry->shared;
306 if (me)
307 {
308 *me = my_match;
309 }
310 if (other)
311 {
312 *other = other_match;
313 }
314 return TRUE;
315 }
316
317 METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
318 private_mem_cred_t *this, shared_key_type_t type,
319 identification_t *me, identification_t *other)
320 {
321 shared_data_t *data;
322
323 INIT(data,
324 .lock = this->lock,
325 .me = me,
326 .other = other,
327 .type = type,
328 );
329 data->lock->read_lock(data->lock);
330 return enumerator_create_filter(
331 this->shared->create_enumerator(this->shared),
332 (void*)shared_filter, data, (void*)shared_data_destroy);
333 }
334
335 METHOD(mem_cred_t, add_shared, void,
336 private_mem_cred_t *this, shared_key_t *shared, ...)
337 {
338 shared_entry_t *entry;
339 identification_t *id;
340 va_list args;
341
342 INIT(entry,
343 .shared = shared,
344 .owners = linked_list_create(),
345 );
346
347 va_start(args, shared);
348 do
349 {
350 id = va_arg(args, identification_t*);
351 if (id)
352 {
353 entry->owners->insert_last(entry->owners, id);
354 }
355 }
356 while (id);
357 va_end(args);
358
359 this->lock->write_lock(this->lock);
360 this->shared->insert_last(this->shared, entry);
361 this->lock->unlock(this->lock);
362 }
363
364 METHOD(mem_cred_t, clear, void,
365 private_mem_cred_t *this)
366 {
367 this->lock->write_lock(this->lock);
368 this->trusted->destroy_offset(this->trusted,
369 offsetof(certificate_t, destroy));
370 this->untrusted->destroy_offset(this->untrusted,
371 offsetof(certificate_t, destroy));
372 this->keys->destroy_offset(this->keys, offsetof(private_key_t, destroy));
373 this->shared->destroy_function(this->shared, (void*)shared_entry_destroy);
374 this->trusted = linked_list_create();
375 this->untrusted = linked_list_create();
376 this->keys = linked_list_create();
377 this->shared = linked_list_create();
378 this->lock->unlock(this->lock);
379 }
380
381 METHOD(mem_cred_t, destroy, void,
382 private_mem_cred_t *this)
383 {
384 _clear(this);
385 this->trusted->destroy(this->trusted);
386 this->untrusted->destroy(this->untrusted);
387 this->keys->destroy(this->keys);
388 this->shared->destroy(this->shared);
389 this->lock->destroy(this->lock);
390 free(this);
391 }
392
393 /**
394 * See header
395 */
396 mem_cred_t *mem_cred_create()
397 {
398 private_mem_cred_t *this;
399
400 INIT(this,
401 .public = {
402 .set = {
403 .create_shared_enumerator = _create_shared_enumerator,
404 .create_private_enumerator = _create_private_enumerator,
405 .create_cert_enumerator = _create_cert_enumerator,
406 .create_cdp_enumerator = (void*)return_null,
407 .cache_cert = (void*)nop,
408 },
409 .add_cert = _add_cert,
410 .add_key = _add_key,
411 .add_shared = _add_shared,
412 .clear = _clear,
413 .destroy = _destroy,
414 },
415 .trusted = linked_list_create(),
416 .untrusted = linked_list_create(),
417 .keys = linked_list_create(),
418 .shared = linked_list_create(),
419 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
420 );
421
422 return &this->public;
423 }