Added certificate support to in-memory credential set
[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 shared keys, as shared_entry_t
50 */
51 linked_list_t *shared;
52 };
53
54 /**
55 * Data for the certificate enumerator
56 */
57 typedef struct {
58 rwlock_t *lock;
59 certificate_type_t cert;
60 key_type_t key;
61 identification_t *id;
62 } cert_data_t;
63
64 /**
65 * destroy cert_data
66 */
67 static void cert_data_destroy(cert_data_t *data)
68 {
69 data->lock->unlock(data->lock);
70 free(data);
71 }
72
73 /**
74 * filter function for certs enumerator
75 */
76 static bool certs_filter(cert_data_t *data, certificate_t **in, certificate_t **out)
77 {
78 public_key_t *public;
79 certificate_t *cert = *in;
80
81 if (data->cert == CERT_ANY || data->cert == cert->get_type(cert))
82 {
83 public = cert->get_public_key(cert);
84 if (public)
85 {
86 if (data->key == KEY_ANY || data->key == public->get_type(public))
87 {
88 if (public->has_fingerprint(public,
89 data->id->get_encoding(data->id)))
90 {
91 public->destroy(public);
92 *out = *in;
93 return TRUE;
94 }
95 }
96 public->destroy(public);
97 }
98 else if (data->key != KEY_ANY)
99 {
100 return FALSE;
101 }
102 if (data->id == NULL || cert->has_subject(cert, data->id))
103 {
104 *out = *in;
105 return TRUE;
106 }
107 }
108 return FALSE;
109 }
110
111 METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
112 private_mem_cred_t *this, certificate_type_t cert, key_type_t key,
113 identification_t *id, bool trusted)
114 {
115 cert_data_t *data;
116 enumerator_t *enumerator;
117
118 INIT(data,
119 .lock = this->lock,
120 .cert = cert,
121 .key = key,
122 .id = id,
123 );
124 this->lock->read_lock(this->lock);
125 if (trusted)
126 {
127 enumerator = this->trusted->create_enumerator(this->trusted);
128 }
129 else
130 {
131 enumerator = this->untrusted->create_enumerator(this->untrusted);
132 }
133 return enumerator_create_filter(enumerator, (void*)certs_filter, data,
134 (void*)cert_data_destroy);
135 }
136
137 METHOD(mem_cred_t, add_cert, void,
138 private_mem_cred_t *this, bool trusted, certificate_t *cert)
139 {
140 this->lock->write_lock(this->lock);
141 if (trusted)
142 {
143 this->trusted->insert_last(this->trusted, cert->get_ref(cert));
144 }
145 this->untrusted->insert_last(this->untrusted, cert);
146 this->lock->unlock(this->lock);
147 }
148
149 /**
150 * Shared key entry
151 */
152 typedef struct {
153 /* shared key */
154 shared_key_t *shared;
155 /* list of owners, identification_t */
156 linked_list_t *owners;
157 } shared_entry_t;
158
159 /**
160 * Clean up a shared entry
161 */
162 static void shared_entry_destroy(shared_entry_t *entry)
163 {
164 entry->owners->destroy_offset(entry->owners,
165 offsetof(identification_t, destroy));
166 entry->shared->destroy(entry->shared);
167 free(entry);
168 }
169
170 /**
171 * Data for the shared_key enumerator
172 */
173 typedef struct {
174 rwlock_t *lock;
175 identification_t *me;
176 identification_t *other;
177 shared_key_type_t type;
178 } shared_data_t;
179
180 /**
181 * free shared key enumerator data and unlock list
182 */
183 static void shared_data_destroy(shared_data_t *data)
184 {
185 data->lock->unlock(data->lock);
186 free(data);
187 }
188
189 /**
190 * Get the best match of an owner in an entry.
191 */
192 static id_match_t has_owner(shared_entry_t *entry, identification_t *owner)
193 {
194 enumerator_t *enumerator;
195 id_match_t match, best = ID_MATCH_NONE;
196 identification_t *current;
197
198 enumerator = entry->owners->create_enumerator(entry->owners);
199 while (enumerator->enumerate(enumerator, &current))
200 {
201 match = owner->matches(owner, current);
202 if (match > best)
203 {
204 best = match;
205 }
206 }
207 enumerator->destroy(enumerator);
208 return best;
209 }
210
211 /**
212 * enumerator filter function for shared entries
213 */
214 static bool shared_filter(shared_data_t *data,
215 shared_entry_t **in, shared_key_t **out,
216 void **unused1, id_match_t *me,
217 void **unused2, id_match_t *other)
218 {
219 id_match_t my_match = ID_MATCH_NONE, other_match = ID_MATCH_NONE;
220 shared_entry_t *entry = *in;
221
222 if (data->type != SHARED_ANY &&
223 entry->shared->get_type(entry->shared) != data->type)
224 {
225 return FALSE;
226 }
227 if (data->me)
228 {
229 my_match = has_owner(entry, data->me);
230 }
231 if (data->other)
232 {
233 other_match = has_owner(entry, data->other);
234 }
235 if ((data->me || data->other) && (!my_match && !other_match))
236 {
237 return FALSE;
238 }
239 *out = entry->shared;
240 if (me)
241 {
242 *me = my_match;
243 }
244 if (other)
245 {
246 *other = other_match;
247 }
248 return TRUE;
249 }
250
251 METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
252 private_mem_cred_t *this, shared_key_type_t type,
253 identification_t *me, identification_t *other)
254 {
255 shared_data_t *data;
256
257 INIT(data,
258 .lock = this->lock,
259 .me = me,
260 .other = other,
261 .type = type,
262 );
263 data->lock->read_lock(data->lock);
264 return enumerator_create_filter(
265 this->shared->create_enumerator(this->shared),
266 (void*)shared_filter, data, (void*)shared_data_destroy);
267 }
268
269 METHOD(mem_cred_t, add_shared, void,
270 private_mem_cred_t *this, shared_key_t *shared, ...)
271 {
272 shared_entry_t *entry;
273 identification_t *id;
274 va_list args;
275
276 INIT(entry,
277 .shared = shared,
278 .owners = linked_list_create(),
279 );
280
281 va_start(args, shared);
282 do
283 {
284 id = va_arg(args, identification_t*);
285 if (id)
286 {
287 entry->owners->insert_last(entry->owners, id);
288 }
289 }
290 while (id);
291 va_end(args);
292
293 this->lock->write_lock(this->lock);
294 this->shared->insert_last(this->shared, entry);
295 this->lock->unlock(this->lock);
296 }
297
298 METHOD(mem_cred_t, destroy, void,
299 private_mem_cred_t *this)
300 {
301 this->trusted->destroy_offset(this->trusted,
302 offsetof(certificate_t, destroy));
303 this->untrusted->destroy_offset(this->untrusted,
304 offsetof(certificate_t, destroy));
305 this->shared->destroy_function(this->shared, (void*)shared_entry_destroy);
306 this->lock->destroy(this->lock);
307 free(this);
308 }
309
310 /**
311 * See header
312 */
313 mem_cred_t *mem_cred_create()
314 {
315 private_mem_cred_t *this;
316
317 INIT(this,
318 .public = {
319 .set = {
320 .create_shared_enumerator = _create_shared_enumerator,
321 .create_private_enumerator = (void*)return_null,
322 .create_cert_enumerator = _create_cert_enumerator,
323 .create_cdp_enumerator = (void*)return_null,
324 .cache_cert = (void*)nop,
325 },
326 .add_cert = _add_cert,
327 .add_shared = _add_shared,
328 .destroy = _destroy,
329 },
330 .trusted = linked_list_create(),
331 .untrusted = linked_list_create(),
332 .shared = linked_list_create(),
333 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
334 );
335
336 return &this->public;
337 }