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