Moving charon to libcharon.
[strongswan.git] / src / libcharon / config / auth_cfg.c
1 /*
2 * Copyright (C) 2007-2009 Martin Willi
3 * Copyright (C) 2008 Tobias Brunner
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "auth_cfg.h"
18
19 #include <daemon.h>
20 #include <utils/linked_list.h>
21 #include <utils/identification.h>
22 #include <credentials/certificates/certificate.h>
23
24 ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_SUBJECT_HASH_URL,
25 "RULE_IDENTITY",
26 "RULE_AUTH_CLASS",
27 "RULE_EAP_IDENTITY",
28 "RULE_EAP_TYPE",
29 "RULE_EAP_VENDOR",
30 "RULE_CA_CERT",
31 "RULE_IM_CERT",
32 "RULE_SUBJECT_CERT",
33 "RULE_CRL_VALIDATION",
34 "RULE_OCSP_VALIDATION",
35 "RULE_AC_GROUP",
36 "HELPER_IM_CERT",
37 "HELPER_SUBJECT_CERT",
38 "HELPER_IM_HASH_URL",
39 "HELPER_SUBJECT_HASH_URL",
40 );
41
42 typedef struct private_auth_cfg_t private_auth_cfg_t;
43
44 /**
45 * private data of item_set
46 */
47 struct private_auth_cfg_t {
48
49 /**
50 * public functions
51 */
52 auth_cfg_t public;
53
54 /**
55 * list of entry_t
56 */
57 linked_list_t *entries;
58 };
59
60 typedef struct entry_t entry_t;
61
62 struct entry_t {
63 /** rule type */
64 auth_rule_t type;
65 /** associated value */
66 void *value;
67 };
68
69 /**
70 * enumerator for auth_cfg_t.create_enumerator()
71 */
72 typedef struct {
73 /** implements enumerator_t */
74 enumerator_t public;
75 /** inner enumerator from linked_list_t */
76 enumerator_t *inner;
77 /** current entry */
78 entry_t *current;
79 } entry_enumerator_t;
80
81 /**
82 * enumerate function for item_enumerator_t
83 */
84 static bool enumerate(entry_enumerator_t *this, auth_rule_t *type, void **value)
85 {
86 entry_t *entry;
87
88 if (this->inner->enumerate(this->inner, &entry))
89 {
90 this->current = entry;
91 *type = entry->type;
92 *value = entry->value;
93 return TRUE;
94 }
95 return FALSE;
96 }
97
98 /**
99 * destroy function for item_enumerator_t
100 */
101 static void entry_enumerator_destroy(entry_enumerator_t *this)
102 {
103 this->inner->destroy(this->inner);
104 free(this);
105 }
106
107 /**
108 * Implementation of auth_cfg_t.create_enumerator.
109 */
110 static enumerator_t* create_enumerator(private_auth_cfg_t *this)
111 {
112 entry_enumerator_t *enumerator;
113
114 enumerator = malloc_thing(entry_enumerator_t);
115 enumerator->inner = this->entries->create_enumerator(this->entries);
116 enumerator->public.enumerate = (void*)enumerate;
117 enumerator->public.destroy = (void*)entry_enumerator_destroy;
118 enumerator->current = NULL;
119 return &enumerator->public;
120 }
121
122 /**
123 * Destroy the value associated with an entry
124 */
125 static void destroy_entry_value(entry_t *entry)
126 {
127 switch (entry->type)
128 {
129 case AUTH_RULE_IDENTITY:
130 case AUTH_RULE_EAP_IDENTITY:
131 case AUTH_RULE_AC_GROUP:
132 {
133 identification_t *id = (identification_t*)entry->value;
134 id->destroy(id);
135 break;
136 }
137 case AUTH_RULE_CA_CERT:
138 case AUTH_RULE_IM_CERT:
139 case AUTH_RULE_SUBJECT_CERT:
140 case AUTH_HELPER_IM_CERT:
141 case AUTH_HELPER_SUBJECT_CERT:
142 {
143 certificate_t *cert = (certificate_t*)entry->value;
144 cert->destroy(cert);
145 break;
146 }
147 case AUTH_HELPER_IM_HASH_URL:
148 case AUTH_HELPER_SUBJECT_HASH_URL:
149 {
150 free(entry->value);
151 break;
152 }
153 case AUTH_RULE_AUTH_CLASS:
154 case AUTH_RULE_EAP_TYPE:
155 case AUTH_RULE_EAP_VENDOR:
156 case AUTH_RULE_CRL_VALIDATION:
157 case AUTH_RULE_OCSP_VALIDATION:
158 break;
159 }
160 }
161
162 /**
163 * Implementation of auth_cfg_t.replace.
164 */
165 static void replace(auth_cfg_t *this, entry_enumerator_t *enumerator,
166 auth_rule_t type, ...)
167 {
168 if (enumerator->current)
169 {
170 va_list args;
171
172 va_start(args, type);
173
174 destroy_entry_value(enumerator->current);
175 enumerator->current->type = type;
176 switch (type)
177 {
178 case AUTH_RULE_AUTH_CLASS:
179 case AUTH_RULE_EAP_TYPE:
180 case AUTH_RULE_EAP_VENDOR:
181 case AUTH_RULE_CRL_VALIDATION:
182 case AUTH_RULE_OCSP_VALIDATION:
183 /* integer type */
184 enumerator->current->value = (void*)(uintptr_t)va_arg(args, u_int);
185 break;
186 case AUTH_RULE_IDENTITY:
187 case AUTH_RULE_EAP_IDENTITY:
188 case AUTH_RULE_AC_GROUP:
189 case AUTH_RULE_CA_CERT:
190 case AUTH_RULE_IM_CERT:
191 case AUTH_RULE_SUBJECT_CERT:
192 case AUTH_HELPER_IM_CERT:
193 case AUTH_HELPER_SUBJECT_CERT:
194 case AUTH_HELPER_IM_HASH_URL:
195 case AUTH_HELPER_SUBJECT_HASH_URL:
196 /* pointer type */
197 enumerator->current->value = va_arg(args, void*);
198 break;
199 }
200 va_end(args);
201 }
202 }
203
204 /**
205 * Implementation of auth_cfg_t.get.
206 */
207 static void* get(private_auth_cfg_t *this, auth_rule_t type)
208 {
209 enumerator_t *enumerator;
210 void *current_value, *best_value = NULL;
211 auth_rule_t current_type;
212 bool found = FALSE;
213
214 enumerator = create_enumerator(this);
215 while (enumerator->enumerate(enumerator, &current_type, &current_value))
216 {
217 if (type == current_type)
218 {
219 if (type == AUTH_RULE_CRL_VALIDATION ||
220 type == AUTH_RULE_OCSP_VALIDATION)
221 { /* for CRL/OCSP validation, always get() the highest value */
222 if (!found || current_value > best_value)
223 {
224 best_value = current_value;
225 }
226 found = TRUE;
227 continue;
228 }
229 best_value = current_value;
230 found = TRUE;
231 break;
232 }
233 }
234 enumerator->destroy(enumerator);
235 if (found)
236 {
237 return best_value;
238 }
239 switch (type)
240 {
241 /* use some sane defaults if we don't find an entry */
242 case AUTH_RULE_AUTH_CLASS:
243 return (void*)AUTH_CLASS_ANY;
244 case AUTH_RULE_EAP_TYPE:
245 return (void*)EAP_NAK;
246 case AUTH_RULE_EAP_VENDOR:
247 return (void*)0;
248 case AUTH_RULE_CRL_VALIDATION:
249 case AUTH_RULE_OCSP_VALIDATION:
250 return (void*)VALIDATION_FAILED;
251 case AUTH_RULE_IDENTITY:
252 case AUTH_RULE_EAP_IDENTITY:
253 case AUTH_RULE_AC_GROUP:
254 case AUTH_RULE_CA_CERT:
255 case AUTH_RULE_IM_CERT:
256 case AUTH_RULE_SUBJECT_CERT:
257 case AUTH_HELPER_IM_CERT:
258 case AUTH_HELPER_SUBJECT_CERT:
259 case AUTH_HELPER_IM_HASH_URL:
260 case AUTH_HELPER_SUBJECT_HASH_URL:
261 default:
262 return NULL;
263 }
264 }
265
266 /**
267 * Implementation of auth_cfg_t.add.
268 */
269 static void add(private_auth_cfg_t *this, auth_rule_t type, ...)
270 {
271 entry_t *entry = malloc_thing(entry_t);
272 va_list args;
273
274 va_start(args, type);
275 entry->type = type;
276 switch (type)
277 {
278 case AUTH_RULE_AUTH_CLASS:
279 case AUTH_RULE_EAP_TYPE:
280 case AUTH_RULE_EAP_VENDOR:
281 case AUTH_RULE_CRL_VALIDATION:
282 case AUTH_RULE_OCSP_VALIDATION:
283 /* integer type */
284 entry->value = (void*)(uintptr_t)va_arg(args, u_int);
285 break;
286 case AUTH_RULE_IDENTITY:
287 case AUTH_RULE_EAP_IDENTITY:
288 case AUTH_RULE_AC_GROUP:
289 case AUTH_RULE_CA_CERT:
290 case AUTH_RULE_IM_CERT:
291 case AUTH_RULE_SUBJECT_CERT:
292 case AUTH_HELPER_IM_CERT:
293 case AUTH_HELPER_SUBJECT_CERT:
294 case AUTH_HELPER_IM_HASH_URL:
295 case AUTH_HELPER_SUBJECT_HASH_URL:
296 /* pointer type */
297 entry->value = va_arg(args, void*);
298 break;
299 }
300 va_end(args);
301 this->entries->insert_last(this->entries, entry);
302 }
303
304 /**
305 * Implementation of auth_cfg_t.complies.
306 */
307 static bool complies(private_auth_cfg_t *this, auth_cfg_t *constraints,
308 bool log_error)
309 {
310 enumerator_t *e1, *e2;
311 bool success = TRUE;
312 auth_rule_t t1, t2;
313 void *value;
314
315 e1 = constraints->create_enumerator(constraints);
316 while (e1->enumerate(e1, &t1, &value))
317 {
318 switch (t1)
319 {
320 case AUTH_RULE_CA_CERT:
321 case AUTH_RULE_IM_CERT:
322 {
323 certificate_t *c1, *c2;
324
325 c1 = (certificate_t*)value;
326
327 success = FALSE;
328 e2 = create_enumerator(this);
329 while (e2->enumerate(e2, &t2, &c2))
330 {
331 if ((t2 == AUTH_RULE_CA_CERT || t2 == AUTH_RULE_IM_CERT) &&
332 c1->equals(c1, c2))
333 {
334 success = TRUE;
335 }
336 }
337 e2->destroy(e2);
338 if (!success && log_error)
339 {
340 DBG1(DBG_CFG, "constraint check failed: peer not "
341 "authenticated by CA '%Y'.", c1->get_subject(c1));
342 }
343 break;
344 }
345 case AUTH_RULE_SUBJECT_CERT:
346 {
347 certificate_t *c1, *c2;
348
349 c1 = (certificate_t*)value;
350 c2 = get(this, AUTH_RULE_SUBJECT_CERT);
351 if (!c2 || !c1->equals(c1, c2))
352 {
353 success = FALSE;
354 if (log_error)
355 {
356 DBG1(DBG_CFG, "constraint check failed: peer not "
357 "authenticated with peer cert '%Y'.",
358 c1->get_subject(c1));
359 }
360 }
361 break;
362 }
363 case AUTH_RULE_CRL_VALIDATION:
364 case AUTH_RULE_OCSP_VALIDATION:
365 {
366 cert_validation_t validated, required;
367
368 required = (uintptr_t)value;
369 validated = (uintptr_t)get(this, t1);
370 switch (required)
371 {
372 case VALIDATION_FAILED:
373 /* no constraint */
374 break;
375 case VALIDATION_SKIPPED:
376 if (validated == VALIDATION_SKIPPED)
377 {
378 break;
379 }
380 /* FALL */
381 case VALIDATION_GOOD:
382 if (validated == VALIDATION_GOOD)
383 {
384 break;
385 }
386 /* FALL */
387 default:
388 success = FALSE;
389 if (log_error)
390 {
391 DBG1(DBG_CFG, "constraint check failed: %N is %N, "
392 "but requires at least %N", auth_rule_names,
393 t1, cert_validation_names, validated,
394 cert_validation_names, required);
395 }
396 break;
397 }
398 break;
399 }
400 case AUTH_RULE_IDENTITY:
401 case AUTH_RULE_EAP_IDENTITY:
402 {
403 identification_t *id1, *id2;
404
405 id1 = (identification_t*)value;
406 id2 = get(this, t1);
407 if (!id2 || !id2->matches(id2, id1))
408 {
409 success = FALSE;
410 if (log_error)
411 {
412 DBG1(DBG_CFG, "constraint check failed: %sidentity '%Y'"
413 " required ", t1 == AUTH_RULE_IDENTITY ? "" :
414 "EAP ", id1);
415 }
416 }
417 break;
418 }
419 case AUTH_RULE_AUTH_CLASS:
420 {
421 if ((uintptr_t)value != AUTH_CLASS_ANY &&
422 (uintptr_t)value != (uintptr_t)get(this, t1))
423 {
424 success = FALSE;
425 if (log_error)
426 {
427 DBG1(DBG_CFG, "constraint requires %N authentication, "
428 "but %N was used", auth_class_names, (uintptr_t)value,
429 auth_class_names, (uintptr_t)get(this, t1));
430 }
431 }
432 break;
433 }
434 case AUTH_RULE_EAP_TYPE:
435 {
436 if ((uintptr_t)value != (uintptr_t)get(this, t1))
437 {
438 success = FALSE;
439 if (log_error)
440 {
441 DBG1(DBG_CFG, "constraint requires %N, "
442 "but %N was used", eap_type_names, (uintptr_t)value,
443 eap_type_names, (uintptr_t)get(this, t1));
444 }
445 }
446 break;
447 }
448 case AUTH_RULE_EAP_VENDOR:
449 {
450 if ((uintptr_t)value != (uintptr_t)get(this, t1))
451 {
452 success = FALSE;
453 if (log_error)
454 {
455 DBG1(DBG_CFG, "constraint requires EAP vendor %d, "
456 "but %d was used", (uintptr_t)value,
457 (uintptr_t)get(this, t1));
458 }
459 }
460 break;
461 }
462 case AUTH_RULE_AC_GROUP:
463 {
464 success = FALSE;
465 if (log_error)
466 {
467 DBG1(DBG_CFG, "constraint check %N not implemented!",
468 auth_rule_names, t1);
469 }
470 break;
471 }
472 case AUTH_HELPER_IM_CERT:
473 case AUTH_HELPER_SUBJECT_CERT:
474 case AUTH_HELPER_IM_HASH_URL:
475 case AUTH_HELPER_SUBJECT_HASH_URL:
476 /* skip helpers */
477 continue;
478 }
479 if (!success)
480 {
481 break;
482 }
483 }
484 e1->destroy(e1);
485 return success;
486 }
487
488 /**
489 * Implementation of auth_cfg_t.merge.
490 */
491 static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy)
492 {
493 if (!other)
494 { /* nothing to merge */
495 return;
496 }
497 if (copy)
498 {
499 enumerator_t *enumerator;
500 auth_rule_t type;
501 void *value;
502
503 enumerator = create_enumerator(other);
504 while (enumerator->enumerate(enumerator, &type, &value))
505 {
506 switch (type)
507 {
508 case AUTH_RULE_CA_CERT:
509 case AUTH_RULE_IM_CERT:
510 case AUTH_RULE_SUBJECT_CERT:
511 case AUTH_HELPER_IM_CERT:
512 case AUTH_HELPER_SUBJECT_CERT:
513 {
514 certificate_t *cert = (certificate_t*)value;
515
516 add(this, type, cert->get_ref(cert));
517 break;
518 }
519 case AUTH_RULE_CRL_VALIDATION:
520 case AUTH_RULE_OCSP_VALIDATION:
521 case AUTH_RULE_AUTH_CLASS:
522 case AUTH_RULE_EAP_TYPE:
523 case AUTH_RULE_EAP_VENDOR:
524 {
525 add(this, type, (uintptr_t)value);
526 break;
527 }
528 case AUTH_RULE_IDENTITY:
529 case AUTH_RULE_EAP_IDENTITY:
530 case AUTH_RULE_AC_GROUP:
531 {
532 identification_t *id = (identification_t*)value;
533
534 add(this, type, id->clone(id));
535 break;
536 }
537 case AUTH_HELPER_IM_HASH_URL:
538 case AUTH_HELPER_SUBJECT_HASH_URL:
539 {
540 add(this, type, strdup((char*)value));
541 break;
542 }
543 }
544 }
545 enumerator->destroy(enumerator);
546 }
547 else
548 {
549 entry_t *entry;
550
551 while (other->entries->remove_first(other->entries,
552 (void**)&entry) == SUCCESS)
553 {
554 this->entries->insert_last(this->entries, entry);
555 }
556 }
557 }
558
559 /**
560 * Implementation of auth_cfg_t.equals.
561 */
562 static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other)
563 {
564 enumerator_t *e1, *e2;
565 entry_t *i1, *i2;
566 bool equal = TRUE, found;
567
568 if (this->entries->get_count(this->entries) !=
569 other->entries->get_count(other->entries))
570 {
571 return FALSE;
572 }
573 e1 = this->entries->create_enumerator(this->entries);
574 while (e1->enumerate(e1, &i1))
575 {
576 found = FALSE;
577 e2 = other->entries->create_enumerator(other->entries);
578 while (e2->enumerate(e2, &i2))
579 {
580 if (i1->type == i2->type)
581 {
582 switch (i1->type)
583 {
584 case AUTH_RULE_AUTH_CLASS:
585 case AUTH_RULE_EAP_TYPE:
586 case AUTH_RULE_EAP_VENDOR:
587 case AUTH_RULE_CRL_VALIDATION:
588 case AUTH_RULE_OCSP_VALIDATION:
589 {
590 if (i1->value == i2->value)
591 {
592 found = TRUE;
593 break;
594 }
595 continue;
596 }
597 case AUTH_RULE_CA_CERT:
598 case AUTH_RULE_IM_CERT:
599 case AUTH_RULE_SUBJECT_CERT:
600 case AUTH_HELPER_IM_CERT:
601 case AUTH_HELPER_SUBJECT_CERT:
602 {
603 certificate_t *c1, *c2;
604
605 c1 = (certificate_t*)i1->value;
606 c2 = (certificate_t*)i2->value;
607
608 if (c1->equals(c1, c2))
609 {
610 found = TRUE;
611 break;
612 }
613 continue;
614 }
615 case AUTH_RULE_IDENTITY:
616 case AUTH_RULE_EAP_IDENTITY:
617 case AUTH_RULE_AC_GROUP:
618 {
619 identification_t *id1, *id2;
620
621 id1 = (identification_t*)i1->value;
622 id2 = (identification_t*)i2->value;
623
624 if (id1->equals(id1, id2))
625 {
626 found = TRUE;
627 break;
628 }
629 continue;
630 }
631 case AUTH_HELPER_IM_HASH_URL:
632 case AUTH_HELPER_SUBJECT_HASH_URL:
633 {
634 if (streq(i1->value, i2->value))
635 {
636 found = TRUE;
637 break;
638 }
639 continue;
640 }
641 }
642 break;
643 }
644 }
645 e2->destroy(e2);
646 if (!found)
647 {
648 equal = FALSE;
649 break;
650 }
651 }
652 e1->destroy(e1);
653 return equal;
654 }
655
656 /**
657 * Implementation of auth_cfg_t.purge
658 */
659 static void purge(private_auth_cfg_t *this, bool keep_ca)
660 {
661 entry_t *entry;
662 linked_list_t *cas;
663
664 cas = linked_list_create();
665 while (this->entries->remove_last(this->entries, (void**)&entry) == SUCCESS)
666 {
667 if (keep_ca && entry->type == AUTH_RULE_CA_CERT)
668 {
669 cas->insert_first(cas, entry);
670 }
671 else
672 {
673 destroy_entry_value(entry);
674 free(entry);
675 }
676 }
677 while (cas->remove_last(cas, (void**)&entry) == SUCCESS)
678 {
679 this->entries->insert_first(this->entries, entry);
680 }
681 cas->destroy(cas);
682 }
683
684 /**
685 * Implementation of auth_cfg_t.clone
686 */
687 static auth_cfg_t* clone_(private_auth_cfg_t *this)
688 {
689 enumerator_t *enumerator;
690 auth_cfg_t *clone;
691 entry_t *entry;
692
693 clone = auth_cfg_create();
694 enumerator = this->entries->create_enumerator(this->entries);
695 while (enumerator->enumerate(enumerator, &entry))
696 {
697 switch (entry->type)
698 {
699 case AUTH_RULE_IDENTITY:
700 case AUTH_RULE_EAP_IDENTITY:
701 case AUTH_RULE_AC_GROUP:
702 {
703 identification_t *id = (identification_t*)entry->value;
704 clone->add(clone, entry->type, id->clone(id));
705 break;
706 }
707 case AUTH_RULE_CA_CERT:
708 case AUTH_RULE_IM_CERT:
709 case AUTH_RULE_SUBJECT_CERT:
710 case AUTH_HELPER_IM_CERT:
711 case AUTH_HELPER_SUBJECT_CERT:
712 {
713 certificate_t *cert = (certificate_t*)entry->value;
714 clone->add(clone, entry->type, cert->get_ref(cert));
715 break;
716 }
717 case AUTH_HELPER_IM_HASH_URL:
718 case AUTH_HELPER_SUBJECT_HASH_URL:
719 {
720 clone->add(clone, entry->type, strdup(entry->value));
721 break;
722 }
723 case AUTH_RULE_AUTH_CLASS:
724 case AUTH_RULE_EAP_TYPE:
725 case AUTH_RULE_EAP_VENDOR:
726 case AUTH_RULE_CRL_VALIDATION:
727 case AUTH_RULE_OCSP_VALIDATION:
728 clone->add(clone, entry->type, (uintptr_t)entry->value);
729 break;
730 }
731 }
732 enumerator->destroy(enumerator);
733 return clone;
734 }
735
736 /**
737 * Implementation of auth_cfg_t.destroy
738 */
739 static void destroy(private_auth_cfg_t *this)
740 {
741 purge(this, FALSE);
742 this->entries->destroy(this->entries);
743 free(this);
744 }
745
746 /*
747 * see header file
748 */
749 auth_cfg_t *auth_cfg_create()
750 {
751 private_auth_cfg_t *this = malloc_thing(private_auth_cfg_t);
752
753 this->public.add = (void(*)(auth_cfg_t*, auth_rule_t type, ...))add;
754 this->public.get = (void*(*)(auth_cfg_t*, auth_rule_t type))get;
755 this->public.create_enumerator = (enumerator_t*(*)(auth_cfg_t*))create_enumerator;
756 this->public.replace = (void(*)(auth_cfg_t*,enumerator_t*,auth_rule_t,...))replace;
757 this->public.complies = (bool(*)(auth_cfg_t*, auth_cfg_t *,bool))complies;
758 this->public.merge = (void(*)(auth_cfg_t*, auth_cfg_t *other,bool))merge;
759 this->public.purge = (void(*)(auth_cfg_t*,bool))purge;
760 this->public.equals = (bool(*)(auth_cfg_t*, auth_cfg_t *other))equals;
761 this->public.clone = (auth_cfg_t*(*)(auth_cfg_t*))clone_;
762 this->public.destroy = (void(*)(auth_cfg_t*))destroy;
763
764 this->entries = linked_list_create();
765
766 return &this->public;
767 }
768