mediation connections should now properly rekey
[strongswan.git] / src / charon / credentials / auth_info.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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 * $Id$
16 */
17
18
19 #include "auth_info.h"
20
21 #include <daemon.h>
22 #include <utils/linked_list.h>
23 #include <utils/identification.h>
24 #include <credentials/certificates/certificate.h>
25
26 ENUM(auth_item_names, AUTHN_CA_CERT, AUTHZ_AC_GROUP,
27 "AUTHN_CA_CERT",
28 "AUTHN_CA_CERT_KEYID",
29 "AUTHN_CA_CERT_NAME",
30 "AUTHN_IM_CERT",
31 "AUTHN_SUBJECT_CERT",
32 "AUTHZ_PUBKEY",
33 "AUTHZ_PSK",
34 "AUTHZ_EAP",
35 "AUTHZ_CA_CERT",
36 "AUTHZ_CA_CERT_NAME",
37 "AUTHZ_IM_CERT",
38 "AUTHZ_SUBJECT_CERT",
39 "AUTHZ_CRL_VALIDATION",
40 "AUTHZ_OCSP_VALIDATION",
41 "AUTHZ_AC_GROUP",
42 );
43
44 typedef struct private_auth_info_t private_auth_info_t;
45
46 /**
47 * private data of item_set
48 */
49 struct private_auth_info_t {
50
51 /**
52 * public functions
53 */
54 auth_info_t public;
55
56 /**
57 * list of item_t's
58 */
59 linked_list_t *items;
60 };
61
62 typedef struct item_t item_t;
63
64 struct item_t {
65 /** type of this item */
66 auth_item_t type;
67 /** associated privlege value, if any */
68 void *value;
69 };
70
71 /**
72 * implements item_enumerator_t.enumerate
73 */
74 static bool item_filter(void *data, item_t **item, auth_item_t *type,
75 void *unused, void **value)
76 {
77 *type = (*item)->type;
78 *value = (*item)->value;
79 return TRUE;
80 }
81
82 /**
83 * Implementation of auth_info_t.create_item_enumerator.
84 */
85 static enumerator_t* create_item_enumerator(private_auth_info_t *this)
86 {
87 return enumerator_create_filter(this->items->create_enumerator(this->items),
88 (void*)item_filter, NULL, NULL);
89 }
90
91 /**
92 * Implementation of auth_info_t.get_item.
93 */
94 static bool get_item(private_auth_info_t *this, auth_item_t type, void** value)
95 {
96 enumerator_t *enumerator;
97 void *current_value;
98 auth_item_t current_type;
99 bool found = FALSE;
100
101 enumerator = create_item_enumerator(this);
102 while (enumerator->enumerate(enumerator, &current_type, &current_value))
103 {
104 if (type == current_type)
105 {
106 *value = current_value;
107 found = TRUE;
108 break;
109 }
110 }
111 enumerator->destroy(enumerator);
112 return found;
113 }
114
115 /**
116 * Implementation of auth_info_t.add_item.
117 */
118 static void add_item(private_auth_info_t *this, auth_item_t type, void *value)
119 {
120 item_t *item = malloc_thing(item_t);
121
122 item->type = type;
123 switch (type)
124 {
125 case AUTHZ_PUBKEY:
126 {
127 public_key_t *key = (public_key_t*)value;
128
129 item->value = key->get_ref(key);
130 break;
131 }
132 case AUTHZ_PSK:
133 {
134 shared_key_t *key = (shared_key_t*)value;
135
136 item->value = key->get_ref(key);
137 break;
138 }
139 case AUTHN_CA_CERT:
140 case AUTHN_IM_CERT:
141 case AUTHN_SUBJECT_CERT:
142 case AUTHZ_CA_CERT:
143 case AUTHZ_IM_CERT:
144 case AUTHZ_SUBJECT_CERT:
145 {
146 certificate_t *cert = (certificate_t*)value;
147
148 item->value = cert->get_ref(cert);
149 break;
150 }
151 case AUTHZ_CRL_VALIDATION:
152 case AUTHZ_OCSP_VALIDATION:
153 {
154 cert_validation_t *validation = malloc_thing(cert_validation_t);
155
156 *validation = *(cert_validation_t*)value;
157 item->value = validation;
158 break;
159 }
160 case AUTHZ_EAP:
161 {
162 eap_method_t *method = malloc_thing(eap_method_t);
163
164 *method = *(eap_method_t*)value;
165 item->value = method;
166 break;
167 }
168 case AUTHN_CA_CERT_KEYID:
169 case AUTHN_CA_CERT_NAME:
170 case AUTHZ_CA_CERT_NAME:
171 case AUTHZ_AC_GROUP:
172 {
173 identification_t *id = (identification_t*)value;
174
175 item->value = id->clone(id);
176 break;
177 }
178 }
179 this->items->insert_last(this->items, item);
180 }
181
182
183 /**
184 * Implementation of auth_info_t.complies.
185 */
186 static bool complies(private_auth_info_t *this, auth_info_t *constraints)
187 {
188 enumerator_t *enumerator;
189 bool success = TRUE;
190 auth_item_t t1, t2;
191 void *value;
192
193 enumerator = constraints->create_item_enumerator(constraints);
194 while (enumerator->enumerate(enumerator, &t1, &value))
195 {
196 switch (t1)
197 {
198 case AUTHN_CA_CERT_KEYID:
199 case AUTHN_CA_CERT:
200 case AUTHN_CA_CERT_NAME:
201 case AUTHN_IM_CERT:
202 case AUTHN_SUBJECT_CERT:
203 { /* skip non-authorization tokens */
204 continue;
205 }
206 case AUTHZ_CRL_VALIDATION:
207 case AUTHZ_OCSP_VALIDATION:
208 {
209 cert_validation_t *valid;
210
211 /* OCSP validation is also sufficient for CRL constraint, but
212 * not vice-versa */
213 if (!get_item(this, t1, (void**)&valid) &&
214 t1 == AUTHZ_CRL_VALIDATION &&
215 !get_item(this, AUTHZ_OCSP_VALIDATION, (void**)&valid))
216 {
217 DBG1(DBG_CFG, "constraint check failed: %N requires at "
218 "least %N, but no check done", auth_item_names, t1,
219 cert_validation_names, *(cert_validation_t*)value);
220 success = FALSE;
221 break;
222 }
223 switch (*(cert_validation_t*)value)
224 {
225 case VALIDATION_SKIPPED:
226 if (*valid == VALIDATION_SKIPPED)
227 {
228 break;
229 } /* FALL */
230 case VALIDATION_GOOD:
231 if (*valid == VALIDATION_GOOD)
232 {
233 break;
234 } /* FALL */
235 default:
236 DBG1(DBG_CFG, "constraint check failed: %N is %N, but "
237 "requires at least %N", auth_item_names, t1,
238 cert_validation_names, *valid,
239 cert_validation_names, *(cert_validation_t*)value);
240 success = FALSE;
241 break;
242 }
243 break;
244 }
245 case AUTHZ_CA_CERT:
246 {
247 enumerator_t *enumerator;
248 certificate_t *c1, *c2;
249
250 c1 = (certificate_t*)value;
251
252 success = FALSE;
253 enumerator = create_item_enumerator(this);
254 while (enumerator->enumerate(enumerator, &t2, &c2))
255 {
256 if ((t2 == AUTHZ_CA_CERT || t2 == AUTHZ_IM_CERT) &&
257 c1->equals(c1, c2))
258 {
259 success = TRUE;
260 }
261 }
262 enumerator->destroy(enumerator);
263 if (!success)
264 {
265 DBG1(DBG_CFG, "constraint check failed: peer not "
266 "authenticated by CA '%D'.", c1->get_subject(c1));
267 }
268 break;
269 }
270 case AUTHZ_CA_CERT_NAME:
271 {
272 enumerator_t *enumerator;
273 certificate_t *cert;
274 identification_t *id;
275
276 id = (identification_t*)value;
277 success = FALSE;
278 enumerator = create_item_enumerator(this);
279 while (enumerator->enumerate(enumerator, &t2, &cert))
280 {
281 if ((t2 == AUTHZ_CA_CERT || t2 == AUTHZ_IM_CERT) &&
282 cert->has_subject(cert, id))
283 {
284 success = TRUE;
285 }
286 }
287 enumerator->destroy(enumerator);
288 if (!success)
289 {
290 DBG1(DBG_CFG, "constraint check failed: peer not "
291 "authenticated by CA '%D'.", id);
292 }
293 break;
294 }
295 case AUTHZ_PUBKEY:
296 case AUTHZ_PSK:
297 case AUTHZ_IM_CERT:
298 case AUTHZ_SUBJECT_CERT:
299 case AUTHZ_EAP:
300 case AUTHZ_AC_GROUP:
301 {
302 DBG1(DBG_CFG, "constraint check %N not implemented!",
303 auth_item_names, t1);
304 success = FALSE;
305 break;
306 }
307 }
308 if (!success)
309 {
310 break;
311 }
312 }
313 enumerator->destroy(enumerator);
314 return success;
315 }
316
317 /**
318 * Implementation of auth_info_t.merge.
319 */
320 static void merge(private_auth_info_t *this, private_auth_info_t *other)
321 {
322 item_t *item;
323
324 while (other->items->remove_first(other->items, (void**)&item) == SUCCESS)
325 {
326 this->items->insert_last(this->items, item);
327 }
328 }
329
330 /**
331 * Implementation of auth_info_t.equals.
332 */
333 static bool equals(private_auth_info_t *this, private_auth_info_t *other)
334 {
335 enumerator_t *e1, *e2;
336 item_t *i1, *i2;
337 bool equal = TRUE, found;
338
339 e1 = this->items->create_enumerator(this->items);
340 while (e1->enumerate(e1, &i1))
341 {
342 found = FALSE;
343 e2 = other->items->create_enumerator(other->items);
344 while (e2->enumerate(e2, &i2))
345 {
346 if (i1->type == i2->type)
347 {
348 switch (i1->type)
349 {
350 case AUTHZ_CRL_VALIDATION:
351 case AUTHZ_OCSP_VALIDATION:
352 {
353 cert_validation_t c1, c2;
354
355 c1 = *(cert_validation_t*)i1->value;
356 c2 = *(cert_validation_t*)i2->value;
357
358 if (c1 == c2)
359 {
360 found = TRUE;
361 break;
362 }
363 continue;
364 }
365 case AUTHN_CA_CERT:
366 case AUTHN_IM_CERT:
367 case AUTHN_SUBJECT_CERT:
368 case AUTHZ_CA_CERT:
369 case AUTHZ_IM_CERT:
370 case AUTHZ_SUBJECT_CERT:
371 {
372 certificate_t *c1, *c2;
373
374 c1 = (certificate_t*)i1->value;
375 c2 = (certificate_t*)i2->value;
376
377 if (c1->equals(c1, c2))
378 {
379 found = TRUE;
380 break;
381 }
382 continue;
383 }
384 case AUTHN_CA_CERT_KEYID:
385 case AUTHN_CA_CERT_NAME:
386 case AUTHZ_CA_CERT_NAME:
387 {
388 identification_t *c1, *c2;
389
390 c1 = (identification_t*)i1->value;
391 c2 = (identification_t*)i2->value;
392
393 if (c1->equals(c1, c2))
394 {
395 found = TRUE;
396 break;
397 }
398 continue;
399 }
400 case AUTHZ_PUBKEY:
401 case AUTHZ_PSK:
402 case AUTHZ_EAP:
403 case AUTHZ_AC_GROUP:
404 /* TODO: implement value comparison */
405 break;
406 }
407 break;
408 }
409 }
410 e2->destroy(e2);
411 if (!found)
412 {
413 equal = FALSE;
414 break;
415 }
416 }
417 e1->destroy(e1);
418 return equal;
419 }
420
421 /**
422 * Implementation of auth_info_t.destroy
423 */
424 static void destroy(private_auth_info_t *this)
425 {
426 item_t *item;
427
428 while (this->items->remove_last(this->items, (void**)&item) == SUCCESS)
429 {
430 switch (item->type)
431 {
432 case AUTHZ_PUBKEY:
433 {
434 public_key_t *key = (public_key_t*)item->value;
435 key->destroy(key);
436 break;
437 }
438 case AUTHZ_PSK:
439 {
440 shared_key_t *key = (shared_key_t*)item->value;
441 key->destroy(key);
442 break;
443 }
444 case AUTHN_CA_CERT:
445 case AUTHN_IM_CERT:
446 case AUTHN_SUBJECT_CERT:
447 case AUTHZ_CA_CERT:
448 case AUTHZ_IM_CERT:
449 case AUTHZ_SUBJECT_CERT:
450 {
451 certificate_t *cert = (certificate_t*)item->value;
452 cert->destroy(cert);
453 break;
454 }
455 case AUTHZ_CRL_VALIDATION:
456 case AUTHZ_OCSP_VALIDATION:
457 case AUTHZ_EAP:
458 {
459 free(item->value);
460 break;
461 }
462 case AUTHN_CA_CERT_KEYID:
463 case AUTHN_CA_CERT_NAME:
464 case AUTHZ_CA_CERT_NAME:
465 case AUTHZ_AC_GROUP:
466 {
467 identification_t *id = (identification_t*)item->value;
468 id->destroy(id);
469 break;
470 }
471 }
472 free(item);
473 }
474 this->items->destroy(this->items);
475 free(this);
476 }
477
478 /*
479 * see header file
480 */
481 auth_info_t *auth_info_create()
482 {
483 private_auth_info_t *this = malloc_thing(private_auth_info_t);
484
485 this->public.add_item = (void(*)(auth_info_t*, auth_item_t type, void *value))add_item;
486 this->public.get_item = (bool(*)(auth_info_t*, auth_item_t type, void **value))get_item;
487 this->public.create_item_enumerator = (enumerator_t*(*)(auth_info_t*))create_item_enumerator;
488 this->public.complies = (bool(*)(auth_info_t*, auth_info_t *))complies;
489 this->public.merge = (void(*)(auth_info_t*, auth_info_t *other))merge;
490 this->public.equals = (bool(*)(auth_info_t*, auth_info_t *other))equals;
491 this->public.destroy = (void(*)(auth_info_t*))destroy;
492
493 this->items = linked_list_create();
494
495 return &this->public;
496 }
497