1a1f086c06fdc667c5476c99e9965e719dc68d5e
[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 /**
150 * Add a certificate the the cache. Returns a reference to "cert" or a
151 * previously cached certificate that equals "cert".
152 */
153 static certificate_t *add_cert_internal(private_mem_cred_t *this, bool trusted,
154 certificate_t *cert)
155 {
156 certificate_t *cached;
157 this->lock->write_lock(this->lock);
158 if (this->untrusted->find_last(this->untrusted,
159 (linked_list_match_t)certificate_equals,
160 (void**)&cached, cert) == SUCCESS)
161 {
162 cert->destroy(cert);
163 cert = cached->get_ref(cached);
164 }
165 else
166 {
167 if (trusted)
168 {
169 this->trusted->insert_last(this->trusted, cert->get_ref(cert));
170 }
171 this->untrusted->insert_last(this->untrusted, cert->get_ref(cert));
172 }
173 this->lock->unlock(this->lock);
174 return cert;
175 }
176
177 METHOD(mem_cred_t, add_cert, void,
178 private_mem_cred_t *this, bool trusted, certificate_t *cert)
179 {
180 certificate_t *cached = add_cert_internal(this, trusted, cert);
181 cached->destroy(cached);
182 }
183
184 METHOD(mem_cred_t, add_cert_ref, certificate_t*,
185 private_mem_cred_t *this, bool trusted, certificate_t *cert)
186 {
187 return add_cert_internal(this, trusted, cert);
188 }
189
190 METHOD(mem_cred_t, add_crl, bool,
191 private_mem_cred_t *this, crl_t *crl)
192 {
193 certificate_t *current, *cert = &crl->certificate;
194 enumerator_t *enumerator;
195 bool new = TRUE;
196
197 this->lock->write_lock(this->lock);
198 enumerator = this->untrusted->create_enumerator(this->untrusted);
199 while (enumerator->enumerate(enumerator, (void**)&current))
200 {
201 if (current->get_type(current) != CERT_X509_CRL)
202 {
203 bool found = FALSE;
204 crl_t *crl_c = (crl_t*)current;
205 chunk_t authkey = crl->get_authKeyIdentifier(crl);
206 chunk_t authkey_c = crl_c->get_authKeyIdentifier(crl_c);
207
208 /* compare authorityKeyIdentifiers if available */
209 if (chunk_equals(authkey, authkey_c))
210 {
211 found = TRUE;
212 }
213 else
214 {
215 identification_t *issuer = cert->get_issuer(cert);
216 identification_t *issuer_c = current->get_issuer(current);
217
218 /* otherwise compare issuer distinguished names */
219 if (issuer->equals(issuer, issuer_c))
220 {
221 found = TRUE;
222 }
223 }
224 if (found)
225 {
226 new = crl_is_newer(crl, crl_c);
227 if (new)
228 {
229 this->untrusted->remove_at(this->untrusted, enumerator);
230 }
231 else
232 {
233 cert->destroy(cert);
234 }
235 break;
236 }
237 }
238 }
239 enumerator->destroy(enumerator);
240
241 if (new)
242 {
243 this->untrusted->insert_last(this->untrusted, cert);
244 }
245 this->lock->unlock(this->lock);
246 return new;
247 }
248
249 /**
250 * Data for key enumerator
251 */
252 typedef struct {
253 rwlock_t *lock;
254 key_type_t type;
255 identification_t *id;
256 } key_data_t;
257
258 /**
259 * Destroy key enumerator data
260 */
261 static void key_data_destroy(key_data_t *data)
262 {
263 data->lock->unlock(data->lock);
264 free(data);
265 }
266
267 /**
268 * filter function for private key enumerator
269 */
270 static bool key_filter(key_data_t *data, private_key_t **in, private_key_t **out)
271 {
272 private_key_t *key;
273
274 key = *in;
275 if (data->type == KEY_ANY || data->type == key->get_type(key))
276 {
277 if (data->id == NULL ||
278 key->has_fingerprint(key, data->id->get_encoding(data->id)))
279 {
280 *out = key;
281 return TRUE;
282 }
283 }
284 return FALSE;
285 }
286
287 METHOD(credential_set_t, create_private_enumerator, enumerator_t*,
288 private_mem_cred_t *this, key_type_t type, identification_t *id)
289 {
290 key_data_t *data;
291
292 INIT(data,
293 .lock = this->lock,
294 .type = type,
295 .id = id,
296 );
297 this->lock->read_lock(this->lock);
298 return enumerator_create_filter(this->keys->create_enumerator(this->keys),
299 (void*)key_filter, data, (void*)key_data_destroy);
300 }
301
302 METHOD(mem_cred_t, add_key, void,
303 private_mem_cred_t *this, private_key_t *key)
304 {
305 this->lock->write_lock(this->lock);
306 this->keys->insert_last(this->keys, key);
307 this->lock->unlock(this->lock);
308 }
309
310 /**
311 * Shared key entry
312 */
313 typedef struct {
314 /* shared key */
315 shared_key_t *shared;
316 /* list of owners, identification_t */
317 linked_list_t *owners;
318 } shared_entry_t;
319
320 /**
321 * Clean up a shared entry
322 */
323 static void shared_entry_destroy(shared_entry_t *entry)
324 {
325 entry->owners->destroy_offset(entry->owners,
326 offsetof(identification_t, destroy));
327 entry->shared->destroy(entry->shared);
328 free(entry);
329 }
330
331 /**
332 * Data for the shared_key enumerator
333 */
334 typedef struct {
335 rwlock_t *lock;
336 identification_t *me;
337 identification_t *other;
338 shared_key_type_t type;
339 } shared_data_t;
340
341 /**
342 * free shared key enumerator data and unlock list
343 */
344 static void shared_data_destroy(shared_data_t *data)
345 {
346 data->lock->unlock(data->lock);
347 free(data);
348 }
349
350 /**
351 * Get the best match of an owner in an entry.
352 */
353 static id_match_t has_owner(shared_entry_t *entry, identification_t *owner)
354 {
355 enumerator_t *enumerator;
356 id_match_t match, best = ID_MATCH_NONE;
357 identification_t *current;
358
359 enumerator = entry->owners->create_enumerator(entry->owners);
360 while (enumerator->enumerate(enumerator, &current))
361 {
362 match = owner->matches(owner, current);
363 if (match > best)
364 {
365 best = match;
366 }
367 }
368 enumerator->destroy(enumerator);
369 return best;
370 }
371
372 /**
373 * enumerator filter function for shared entries
374 */
375 static bool shared_filter(shared_data_t *data,
376 shared_entry_t **in, shared_key_t **out,
377 void **unused1, id_match_t *me,
378 void **unused2, id_match_t *other)
379 {
380 id_match_t my_match = ID_MATCH_NONE, other_match = ID_MATCH_NONE;
381 shared_entry_t *entry = *in;
382
383 if (data->type != SHARED_ANY &&
384 entry->shared->get_type(entry->shared) != data->type)
385 {
386 return FALSE;
387 }
388 if (data->me)
389 {
390 my_match = has_owner(entry, data->me);
391 }
392 if (data->other)
393 {
394 other_match = has_owner(entry, data->other);
395 }
396 if ((data->me || data->other) && (!my_match && !other_match))
397 {
398 return FALSE;
399 }
400 *out = entry->shared;
401 if (me)
402 {
403 *me = my_match;
404 }
405 if (other)
406 {
407 *other = other_match;
408 }
409 return TRUE;
410 }
411
412 METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
413 private_mem_cred_t *this, shared_key_type_t type,
414 identification_t *me, identification_t *other)
415 {
416 shared_data_t *data;
417
418 INIT(data,
419 .lock = this->lock,
420 .me = me,
421 .other = other,
422 .type = type,
423 );
424 data->lock->read_lock(data->lock);
425 return enumerator_create_filter(
426 this->shared->create_enumerator(this->shared),
427 (void*)shared_filter, data, (void*)shared_data_destroy);
428 }
429
430 METHOD(mem_cred_t, add_shared_list, void,
431 private_mem_cred_t *this, shared_key_t *shared, linked_list_t* owners)
432 {
433 shared_entry_t *entry;
434
435 INIT(entry,
436 .shared = shared,
437 .owners = owners,
438 );
439
440 this->lock->write_lock(this->lock);
441 this->shared->insert_last(this->shared, entry);
442 this->lock->unlock(this->lock);
443 }
444
445 METHOD(mem_cred_t, add_shared, void,
446 private_mem_cred_t *this, shared_key_t *shared, ...)
447 {
448 identification_t *id;
449 linked_list_t *owners = linked_list_create();
450 va_list args;
451
452 va_start(args, shared);
453 do
454 {
455 id = va_arg(args, identification_t*);
456 if (id)
457 {
458 owners->insert_last(owners, id);
459 }
460 }
461 while (id);
462 va_end(args);
463
464 add_shared_list(this, shared, owners);
465 }
466
467 METHOD(mem_cred_t, clear_secrets, void,
468 private_mem_cred_t *this)
469 {
470 this->lock->write_lock(this->lock);
471 this->keys->destroy_offset(this->keys, offsetof(private_key_t, destroy));
472 this->shared->destroy_function(this->shared, (void*)shared_entry_destroy);
473 this->keys = linked_list_create();
474 this->shared = linked_list_create();
475 this->lock->unlock(this->lock);
476 }
477
478 METHOD(mem_cred_t, clear_, void,
479 private_mem_cred_t *this)
480 {
481 this->lock->write_lock(this->lock);
482 this->trusted->destroy_offset(this->trusted,
483 offsetof(certificate_t, destroy));
484 this->untrusted->destroy_offset(this->untrusted,
485 offsetof(certificate_t, destroy));
486 this->trusted = linked_list_create();
487 this->untrusted = linked_list_create();
488 this->lock->unlock(this->lock);
489
490 clear_secrets(this);
491 }
492
493 METHOD(mem_cred_t, destroy, void,
494 private_mem_cred_t *this)
495 {
496 clear_(this);
497 this->trusted->destroy(this->trusted);
498 this->untrusted->destroy(this->untrusted);
499 this->keys->destroy(this->keys);
500 this->shared->destroy(this->shared);
501 this->lock->destroy(this->lock);
502 free(this);
503 }
504
505 /**
506 * See header
507 */
508 mem_cred_t *mem_cred_create()
509 {
510 private_mem_cred_t *this;
511
512 INIT(this,
513 .public = {
514 .set = {
515 .create_shared_enumerator = _create_shared_enumerator,
516 .create_private_enumerator = _create_private_enumerator,
517 .create_cert_enumerator = _create_cert_enumerator,
518 .create_cdp_enumerator = (void*)return_null,
519 .cache_cert = (void*)nop,
520 },
521 .add_cert = _add_cert,
522 .add_cert_ref = _add_cert_ref,
523 .add_crl = _add_crl,
524 .add_key = _add_key,
525 .add_shared = _add_shared,
526 .add_shared_list = _add_shared_list,
527 .clear = _clear_,
528 .clear_secrets = _clear_secrets,
529 .destroy = _destroy,
530 },
531 .trusted = linked_list_create(),
532 .untrusted = linked_list_create(),
533 .keys = linked_list_create(),
534 .shared = linked_list_create(),
535 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
536 );
537
538 return &this->public;
539 }