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