fixed auth_info_t.equals()
[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 type;
191 void *value;
192
193 enumerator = constraints->create_item_enumerator(constraints);
194 while (enumerator->enumerate(enumerator, &type, &value))
195 {
196 switch (type)
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, type, (void**)&valid) &&
214 type == 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, type,
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, type,
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_NAME:
246 case AUTHZ_PUBKEY:
247 case AUTHZ_PSK:
248 case AUTHZ_IM_CERT:
249 case AUTHZ_SUBJECT_CERT:
250 case AUTHZ_EAP:
251 case AUTHZ_AC_GROUP:
252 DBG1(DBG_CFG, "constraint check %N not implemented!",
253 auth_item_names, type);
254 success = FALSE;
255 break;
256 case AUTHZ_CA_CERT:
257 {
258 certificate_t *cert;
259
260 if (!get_item(this, AUTHZ_CA_CERT, (void**)&cert) ||
261 !cert->equals(cert, (certificate_t*)value))
262 {
263 cert = (certificate_t*)value;
264 DBG1(DBG_CFG, "constraint check failed: peer not "
265 "authenticated by CA '%D'.", cert->get_issuer(cert));
266 success = FALSE;
267 }
268 break;
269 }
270 }
271 if (!success)
272 {
273 break;
274 }
275 }
276 enumerator->destroy(enumerator);
277 return success;
278 }
279
280 /**
281 * Implementation of auth_info_t.merge.
282 */
283 static void merge(private_auth_info_t *this, private_auth_info_t *other)
284 {
285 item_t *item;
286
287 while (other->items->remove_first(other->items, (void**)&item) == SUCCESS)
288 {
289 this->items->insert_last(this->items, item);
290 }
291 }
292
293 /**
294 * Implementation of auth_info_t.equals.
295 */
296 static bool equals(private_auth_info_t *this, private_auth_info_t *other)
297 {
298 enumerator_t *e1, *e2;
299 item_t *i1, *i2;
300 bool equal = TRUE, found;
301
302 e1 = this->items->create_enumerator(this->items);
303 while (e1->enumerate(e1, &i1))
304 {
305 found = FALSE;
306 e2 = other->items->create_enumerator(other->items);
307 while (e2->enumerate(e2, &i2))
308 {
309 if (i1->type == i2->type)
310 {
311 switch (i1->type)
312 {
313 case AUTHZ_CRL_VALIDATION:
314 case AUTHZ_OCSP_VALIDATION:
315 {
316 cert_validation_t c1, c2;
317
318 c1 = *(cert_validation_t*)i1->value;
319 c2 = *(cert_validation_t*)i2->value;
320
321 if (c1 == c2)
322 {
323 found = TRUE;
324 break;
325 }
326 continue;
327 }
328 case AUTHN_CA_CERT:
329 case AUTHN_IM_CERT:
330 case AUTHN_SUBJECT_CERT:
331 case AUTHZ_CA_CERT:
332 case AUTHZ_IM_CERT:
333 case AUTHZ_SUBJECT_CERT:
334 {
335 certificate_t *c1, *c2;
336
337 c1 = (certificate_t*)i1->value;
338 c2 = (certificate_t*)i2->value;
339
340 if (c1->equals(c1, c2))
341 {
342 found = TRUE;
343 break;
344 }
345 continue;
346 }
347 case AUTHN_CA_CERT_KEYID:
348 case AUTHN_CA_CERT_NAME:
349 case AUTHZ_CA_CERT_NAME:
350 {
351 identification_t *c1, *c2;
352
353 c1 = (identification_t*)i1->value;
354 c2 = (identification_t*)i2->value;
355
356 if (c1->equals(c1, c2))
357 {
358 found = TRUE;
359 break;
360 }
361 continue;
362 }
363 case AUTHZ_PUBKEY:
364 case AUTHZ_PSK:
365 case AUTHZ_EAP:
366 case AUTHZ_AC_GROUP:
367 /* TODO: implement value comparison */
368 break;
369 }
370 break;
371 }
372 }
373 e2->destroy(e2);
374 if (!found)
375 {
376 equal = FALSE;
377 break;
378 }
379 }
380 e1->destroy(e1);
381 return equal;
382 }
383
384 /**
385 * Implementation of auth_info_t.destroy
386 */
387 static void destroy(private_auth_info_t *this)
388 {
389 item_t *item;
390
391 while (this->items->remove_last(this->items, (void**)&item) == SUCCESS)
392 {
393 switch (item->type)
394 {
395 case AUTHZ_PUBKEY:
396 {
397 public_key_t *key = (public_key_t*)item->value;
398 key->destroy(key);
399 break;
400 }
401 case AUTHZ_PSK:
402 {
403 shared_key_t *key = (shared_key_t*)item->value;
404 key->destroy(key);
405 break;
406 }
407 case AUTHN_CA_CERT:
408 case AUTHN_IM_CERT:
409 case AUTHN_SUBJECT_CERT:
410 case AUTHZ_CA_CERT:
411 case AUTHZ_IM_CERT:
412 case AUTHZ_SUBJECT_CERT:
413 {
414 certificate_t *cert = (certificate_t*)item->value;
415 cert->destroy(cert);
416 break;
417 }
418 case AUTHZ_CRL_VALIDATION:
419 case AUTHZ_OCSP_VALIDATION:
420 case AUTHZ_EAP:
421 {
422 free(item->value);
423 break;
424 }
425 case AUTHN_CA_CERT_KEYID:
426 case AUTHN_CA_CERT_NAME:
427 case AUTHZ_CA_CERT_NAME:
428 case AUTHZ_AC_GROUP:
429 {
430 identification_t *id = (identification_t*)item->value;
431 id->destroy(id);
432 break;
433 }
434 }
435 free(item);
436 }
437 this->items->destroy(this->items);
438 free(this);
439 }
440
441 /*
442 * see header file
443 */
444 auth_info_t *auth_info_create()
445 {
446 private_auth_info_t *this = malloc_thing(private_auth_info_t);
447
448 this->public.add_item = (void(*)(auth_info_t*, auth_item_t type, void *value))add_item;
449 this->public.get_item = (bool(*)(auth_info_t*, auth_item_t type, void **value))get_item;
450 this->public.create_item_enumerator = (enumerator_t*(*)(auth_info_t*))create_item_enumerator;
451 this->public.complies = (bool(*)(auth_info_t*, auth_info_t *))complies;
452 this->public.merge = (void(*)(auth_info_t*, auth_info_t *other))merge;
453 this->public.equals = (bool(*)(auth_info_t*, auth_info_t *other))equals;
454 this->public.destroy = (void(*)(auth_info_t*))destroy;
455
456 this->items = linked_list_create();
457
458 return &this->public;
459 }
460