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