2 * Copyright (C) 2007-2009 Martin Willi
3 * Copyright (C) 2008 Tobias Brunner
4 * Hochschule fuer Technik Rapperswil
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>.
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
21 #include <utils/linked_list.h>
22 #include <utils/identification.h>
24 #include <credentials/certificates/certificate.h>
26 ENUM(auth_class_names
, AUTH_CLASS_ANY
, AUTH_CLASS_EAP
,
33 ENUM(auth_rule_names
, AUTH_RULE_IDENTITY
, AUTH_HELPER_SUBJECT_HASH_URL
,
42 "RULE_CRL_VALIDATION",
43 "RULE_OCSP_VALIDATION",
46 "HELPER_SUBJECT_CERT",
48 "HELPER_SUBJECT_HASH_URL",
51 typedef struct private_auth_cfg_t private_auth_cfg_t
;
54 * private data of item_set
56 struct private_auth_cfg_t
{
66 linked_list_t
*entries
;
69 typedef struct entry_t entry_t
;
74 /** associated value */
79 * enumerator for auth_cfg_t.create_enumerator()
82 /** implements enumerator_t */
84 /** inner enumerator from linked_list_t */
91 * enumerate function for item_enumerator_t
93 static bool enumerate(entry_enumerator_t
*this, auth_rule_t
*type
, void **value
)
97 if (this->inner
->enumerate(this->inner
, &entry
))
99 this->current
= entry
;
101 *value
= entry
->value
;
108 * destroy function for item_enumerator_t
110 static void entry_enumerator_destroy(entry_enumerator_t
*this)
112 this->inner
->destroy(this->inner
);
117 * Implementation of auth_cfg_t.create_enumerator.
119 static enumerator_t
* create_enumerator(private_auth_cfg_t
*this)
121 entry_enumerator_t
*enumerator
;
123 enumerator
= malloc_thing(entry_enumerator_t
);
124 enumerator
->inner
= this->entries
->create_enumerator(this->entries
);
125 enumerator
->public.enumerate
= (void*)enumerate
;
126 enumerator
->public.destroy
= (void*)entry_enumerator_destroy
;
127 enumerator
->current
= NULL
;
128 return &enumerator
->public;
132 * Destroy the value associated with an entry
134 static void destroy_entry_value(entry_t
*entry
)
138 case AUTH_RULE_IDENTITY
:
139 case AUTH_RULE_EAP_IDENTITY
:
140 case AUTH_RULE_AAA_IDENTITY
:
141 case AUTH_RULE_GROUP
:
143 identification_t
*id
= (identification_t
*)entry
->value
;
147 case AUTH_RULE_CA_CERT
:
148 case AUTH_RULE_IM_CERT
:
149 case AUTH_RULE_SUBJECT_CERT
:
150 case AUTH_HELPER_IM_CERT
:
151 case AUTH_HELPER_SUBJECT_CERT
:
152 case AUTH_HELPER_REVOCATION_CERT
:
154 certificate_t
*cert
= (certificate_t
*)entry
->value
;
158 case AUTH_RULE_CERT_POLICY
:
159 case AUTH_HELPER_IM_HASH_URL
:
160 case AUTH_HELPER_SUBJECT_HASH_URL
:
165 case AUTH_RULE_AUTH_CLASS
:
166 case AUTH_RULE_EAP_TYPE
:
167 case AUTH_RULE_EAP_VENDOR
:
168 case AUTH_RULE_CRL_VALIDATION
:
169 case AUTH_RULE_OCSP_VALIDATION
:
170 case AUTH_RULE_RSA_STRENGTH
:
171 case AUTH_RULE_ECDSA_STRENGTH
:
177 * Implementation of auth_cfg_t.replace.
179 static void replace(auth_cfg_t
*this, entry_enumerator_t
*enumerator
,
180 auth_rule_t type
, ...)
182 if (enumerator
->current
)
186 va_start(args
, type
);
188 destroy_entry_value(enumerator
->current
);
189 enumerator
->current
->type
= type
;
192 case AUTH_RULE_AUTH_CLASS
:
193 case AUTH_RULE_EAP_TYPE
:
194 case AUTH_RULE_EAP_VENDOR
:
195 case AUTH_RULE_CRL_VALIDATION
:
196 case AUTH_RULE_OCSP_VALIDATION
:
197 case AUTH_RULE_RSA_STRENGTH
:
198 case AUTH_RULE_ECDSA_STRENGTH
:
200 enumerator
->current
->value
= (void*)(uintptr_t)va_arg(args
, u_int
);
202 case AUTH_RULE_IDENTITY
:
203 case AUTH_RULE_EAP_IDENTITY
:
204 case AUTH_RULE_AAA_IDENTITY
:
205 case AUTH_RULE_GROUP
:
206 case AUTH_RULE_CA_CERT
:
207 case AUTH_RULE_IM_CERT
:
208 case AUTH_RULE_SUBJECT_CERT
:
209 case AUTH_RULE_CERT_POLICY
:
210 case AUTH_HELPER_IM_CERT
:
211 case AUTH_HELPER_SUBJECT_CERT
:
212 case AUTH_HELPER_IM_HASH_URL
:
213 case AUTH_HELPER_SUBJECT_HASH_URL
:
214 case AUTH_HELPER_REVOCATION_CERT
:
216 enumerator
->current
->value
= va_arg(args
, void*);
224 * Implementation of auth_cfg_t.get.
226 static void* get(private_auth_cfg_t
*this, auth_rule_t type
)
228 enumerator_t
*enumerator
;
229 void *current_value
, *best_value
= NULL
;
230 auth_rule_t current_type
;
233 enumerator
= create_enumerator(this);
234 while (enumerator
->enumerate(enumerator
, ¤t_type
, ¤t_value
))
236 if (type
== current_type
)
238 if (type
== AUTH_RULE_CRL_VALIDATION
||
239 type
== AUTH_RULE_OCSP_VALIDATION
)
240 { /* for CRL/OCSP validation, always get() the highest value */
241 if (!found
|| current_value
> best_value
)
243 best_value
= current_value
;
248 best_value
= current_value
;
253 enumerator
->destroy(enumerator
);
260 /* use some sane defaults if we don't find an entry */
261 case AUTH_RULE_AUTH_CLASS
:
262 return (void*)AUTH_CLASS_ANY
;
263 case AUTH_RULE_EAP_TYPE
:
264 return (void*)EAP_NAK
;
265 case AUTH_RULE_EAP_VENDOR
:
266 case AUTH_RULE_RSA_STRENGTH
:
267 case AUTH_RULE_ECDSA_STRENGTH
:
269 case AUTH_RULE_CRL_VALIDATION
:
270 case AUTH_RULE_OCSP_VALIDATION
:
271 return (void*)VALIDATION_FAILED
;
272 case AUTH_RULE_IDENTITY
:
273 case AUTH_RULE_EAP_IDENTITY
:
274 case AUTH_RULE_AAA_IDENTITY
:
275 case AUTH_RULE_GROUP
:
276 case AUTH_RULE_CA_CERT
:
277 case AUTH_RULE_IM_CERT
:
278 case AUTH_RULE_SUBJECT_CERT
:
279 case AUTH_RULE_CERT_POLICY
:
280 case AUTH_HELPER_IM_CERT
:
281 case AUTH_HELPER_SUBJECT_CERT
:
282 case AUTH_HELPER_IM_HASH_URL
:
283 case AUTH_HELPER_SUBJECT_HASH_URL
:
284 case AUTH_HELPER_REVOCATION_CERT
:
291 * Implementation of auth_cfg_t.add.
293 static void add(private_auth_cfg_t
*this, auth_rule_t type
, ...)
295 entry_t
*entry
= malloc_thing(entry_t
);
298 va_start(args
, type
);
302 case AUTH_RULE_AUTH_CLASS
:
303 case AUTH_RULE_EAP_TYPE
:
304 case AUTH_RULE_EAP_VENDOR
:
305 case AUTH_RULE_CRL_VALIDATION
:
306 case AUTH_RULE_OCSP_VALIDATION
:
307 case AUTH_RULE_RSA_STRENGTH
:
308 case AUTH_RULE_ECDSA_STRENGTH
:
310 entry
->value
= (void*)(uintptr_t)va_arg(args
, u_int
);
312 case AUTH_RULE_IDENTITY
:
313 case AUTH_RULE_EAP_IDENTITY
:
314 case AUTH_RULE_AAA_IDENTITY
:
315 case AUTH_RULE_GROUP
:
316 case AUTH_RULE_CA_CERT
:
317 case AUTH_RULE_IM_CERT
:
318 case AUTH_RULE_SUBJECT_CERT
:
319 case AUTH_RULE_CERT_POLICY
:
320 case AUTH_HELPER_IM_CERT
:
321 case AUTH_HELPER_SUBJECT_CERT
:
322 case AUTH_HELPER_IM_HASH_URL
:
323 case AUTH_HELPER_SUBJECT_HASH_URL
:
324 case AUTH_HELPER_REVOCATION_CERT
:
326 entry
->value
= va_arg(args
, void*);
330 this->entries
->insert_last(this->entries
, entry
);
334 * Implementation of auth_cfg_t.complies.
336 static bool complies(private_auth_cfg_t
*this, auth_cfg_t
*constraints
,
339 enumerator_t
*e1
, *e2
;
340 bool success
= TRUE
, has_group
= FALSE
, group_match
= FALSE
;
344 e1
= constraints
->create_enumerator(constraints
);
345 while (e1
->enumerate(e1
, &t1
, &value
))
349 case AUTH_RULE_CA_CERT
:
350 case AUTH_RULE_IM_CERT
:
352 certificate_t
*c1
, *c2
;
354 c1
= (certificate_t
*)value
;
357 e2
= create_enumerator(this);
358 while (e2
->enumerate(e2
, &t2
, &c2
))
360 if ((t2
== AUTH_RULE_CA_CERT
|| t2
== AUTH_RULE_IM_CERT
) &&
367 if (!success
&& log_error
)
369 DBG1(DBG_CFG
, "constraint check failed: peer not "
370 "authenticated by CA '%Y'.", c1
->get_subject(c1
));
374 case AUTH_RULE_SUBJECT_CERT
:
376 certificate_t
*c1
, *c2
;
378 c1
= (certificate_t
*)value
;
379 c2
= get(this, AUTH_RULE_SUBJECT_CERT
);
380 if (!c2
|| !c1
->equals(c1
, c2
))
385 DBG1(DBG_CFG
, "constraint check failed: peer not "
386 "authenticated with peer cert '%Y'.",
387 c1
->get_subject(c1
));
392 case AUTH_RULE_CRL_VALIDATION
:
393 case AUTH_RULE_OCSP_VALIDATION
:
397 e2
= create_enumerator(this);
398 while (e2
->enumerate(e2
, &t2
, &validated
))
402 switch ((uintptr_t)value
)
404 case VALIDATION_FAILED
:
407 case VALIDATION_SKIPPED
:
408 if (validated
== VALIDATION_SKIPPED
)
413 case VALIDATION_GOOD
:
414 if (validated
== VALIDATION_GOOD
)
423 DBG1(DBG_CFG
, "constraint check failed: "
424 "%N is %N, but requires at least %N",
426 cert_validation_names
, validated
,
427 cert_validation_names
, (uintptr_t)value
);
436 case AUTH_RULE_IDENTITY
:
437 case AUTH_RULE_EAP_IDENTITY
:
438 case AUTH_RULE_AAA_IDENTITY
:
440 identification_t
*id1
, *id2
;
442 id1
= (identification_t
*)value
;
444 if (!id2
|| !id2
->matches(id2
, id1
))
449 DBG1(DBG_CFG
, "constraint check failed: %sidentity '%Y'"
450 " required ", t1
== AUTH_RULE_IDENTITY ?
"" :
456 case AUTH_RULE_AUTH_CLASS
:
458 if ((uintptr_t)value
!= AUTH_CLASS_ANY
&&
459 (uintptr_t)value
!= (uintptr_t)get(this, t1
))
464 DBG1(DBG_CFG
, "constraint requires %N authentication, "
465 "but %N was used", auth_class_names
, (uintptr_t)value
,
466 auth_class_names
, (uintptr_t)get(this, t1
));
471 case AUTH_RULE_EAP_TYPE
:
473 if ((uintptr_t)value
!= (uintptr_t)get(this, t1
))
478 DBG1(DBG_CFG
, "constraint requires %N, "
479 "but %N was used", eap_type_names
, (uintptr_t)value
,
480 eap_type_names
, (uintptr_t)get(this, t1
));
485 case AUTH_RULE_EAP_VENDOR
:
487 if ((uintptr_t)value
!= (uintptr_t)get(this, t1
))
492 DBG1(DBG_CFG
, "constraint requires EAP vendor %d, "
493 "but %d was used", (uintptr_t)value
,
494 (uintptr_t)get(this, t1
));
499 case AUTH_RULE_GROUP
:
501 identification_t
*id1
, *id2
;
503 /* for groups, a match of a single group is sufficient */
505 id1
= (identification_t
*)value
;
506 e2
= create_enumerator(this);
507 while (e2
->enumerate(e2
, &t2
, &id2
))
509 if (t2
== AUTH_RULE_GROUP
&& id2
->matches(id2
, id1
))
517 case AUTH_RULE_RSA_STRENGTH
:
518 case AUTH_RULE_ECDSA_STRENGTH
:
522 e2
= create_enumerator(this);
523 while (e2
->enumerate(e2
, &t2
, &strength
))
527 if ((uintptr_t)value
> strength
)
532 DBG1(DBG_CFG
, "constraint requires %d bit "
533 "public keys, but %d bit key used",
534 (uintptr_t)value
, strength
);
538 else if (t2
== AUTH_RULE_RSA_STRENGTH
)
543 DBG1(DBG_CFG
, "constraint requires %d bit ECDSA, "
544 "but RSA used", (uintptr_t)value
);
547 else if (t2
== AUTH_RULE_ECDSA_STRENGTH
)
552 DBG1(DBG_CFG
, "constraint requires %d bit RSA, "
553 "but ECDSA used", (uintptr_t)value
);
560 case AUTH_RULE_CERT_POLICY
:
566 e2
= create_enumerator(this);
567 while (e2
->enumerate(e2
, &t2
, &oid2
))
569 if (t2
== t1
&& streq(oid1
, oid2
))
576 if (!success
&& log_error
)
578 DBG1(DBG_CFG
, "constraint requires cert policy %s", oid1
);
582 case AUTH_HELPER_IM_CERT
:
583 case AUTH_HELPER_SUBJECT_CERT
:
584 case AUTH_HELPER_IM_HASH_URL
:
585 case AUTH_HELPER_SUBJECT_HASH_URL
:
586 case AUTH_HELPER_REVOCATION_CERT
:
597 if (has_group
&& !group_match
)
601 DBG1(DBG_CFG
, "constraint check failed: group membership required");
609 * Implementation of auth_cfg_t.merge.
611 static void merge(private_auth_cfg_t
*this, private_auth_cfg_t
*other
, bool copy
)
614 { /* nothing to merge */
619 enumerator_t
*enumerator
;
623 enumerator
= create_enumerator(other
);
624 while (enumerator
->enumerate(enumerator
, &type
, &value
))
628 case AUTH_RULE_CA_CERT
:
629 case AUTH_RULE_IM_CERT
:
630 case AUTH_RULE_SUBJECT_CERT
:
631 case AUTH_HELPER_IM_CERT
:
632 case AUTH_HELPER_SUBJECT_CERT
:
633 case AUTH_HELPER_REVOCATION_CERT
:
635 certificate_t
*cert
= (certificate_t
*)value
;
637 add(this, type
, cert
->get_ref(cert
));
640 case AUTH_RULE_CRL_VALIDATION
:
641 case AUTH_RULE_OCSP_VALIDATION
:
642 case AUTH_RULE_AUTH_CLASS
:
643 case AUTH_RULE_EAP_TYPE
:
644 case AUTH_RULE_EAP_VENDOR
:
645 case AUTH_RULE_RSA_STRENGTH
:
646 case AUTH_RULE_ECDSA_STRENGTH
:
648 add(this, type
, (uintptr_t)value
);
651 case AUTH_RULE_IDENTITY
:
652 case AUTH_RULE_EAP_IDENTITY
:
653 case AUTH_RULE_AAA_IDENTITY
:
654 case AUTH_RULE_GROUP
:
656 identification_t
*id
= (identification_t
*)value
;
658 add(this, type
, id
->clone(id
));
661 case AUTH_RULE_CERT_POLICY
:
662 case AUTH_HELPER_IM_HASH_URL
:
663 case AUTH_HELPER_SUBJECT_HASH_URL
:
665 add(this, type
, strdup((char*)value
));
670 enumerator
->destroy(enumerator
);
676 while (other
->entries
->remove_first(other
->entries
,
677 (void**)&entry
) == SUCCESS
)
679 this->entries
->insert_last(this->entries
, entry
);
685 * Implementation of auth_cfg_t.equals.
687 static bool equals(private_auth_cfg_t
*this, private_auth_cfg_t
*other
)
689 enumerator_t
*e1
, *e2
;
691 bool equal
= TRUE
, found
;
693 if (this->entries
->get_count(this->entries
) !=
694 other
->entries
->get_count(other
->entries
))
698 e1
= this->entries
->create_enumerator(this->entries
);
699 while (e1
->enumerate(e1
, &i1
))
702 e2
= other
->entries
->create_enumerator(other
->entries
);
703 while (e2
->enumerate(e2
, &i2
))
705 if (i1
->type
== i2
->type
)
709 case AUTH_RULE_AUTH_CLASS
:
710 case AUTH_RULE_EAP_TYPE
:
711 case AUTH_RULE_EAP_VENDOR
:
712 case AUTH_RULE_CRL_VALIDATION
:
713 case AUTH_RULE_OCSP_VALIDATION
:
714 case AUTH_RULE_RSA_STRENGTH
:
715 case AUTH_RULE_ECDSA_STRENGTH
:
717 if (i1
->value
== i2
->value
)
724 case AUTH_RULE_CA_CERT
:
725 case AUTH_RULE_IM_CERT
:
726 case AUTH_RULE_SUBJECT_CERT
:
727 case AUTH_HELPER_IM_CERT
:
728 case AUTH_HELPER_SUBJECT_CERT
:
729 case AUTH_HELPER_REVOCATION_CERT
:
731 certificate_t
*c1
, *c2
;
733 c1
= (certificate_t
*)i1
->value
;
734 c2
= (certificate_t
*)i2
->value
;
736 if (c1
->equals(c1
, c2
))
743 case AUTH_RULE_IDENTITY
:
744 case AUTH_RULE_EAP_IDENTITY
:
745 case AUTH_RULE_AAA_IDENTITY
:
746 case AUTH_RULE_GROUP
:
748 identification_t
*id1
, *id2
;
750 id1
= (identification_t
*)i1
->value
;
751 id2
= (identification_t
*)i2
->value
;
753 if (id1
->equals(id1
, id2
))
760 case AUTH_RULE_CERT_POLICY
:
761 case AUTH_HELPER_IM_HASH_URL
:
762 case AUTH_HELPER_SUBJECT_HASH_URL
:
764 if (streq(i1
->value
, i2
->value
))
787 * Implementation of auth_cfg_t.purge
789 static void purge(private_auth_cfg_t
*this, bool keep_ca
)
794 cas
= linked_list_create();
795 while (this->entries
->remove_last(this->entries
, (void**)&entry
) == SUCCESS
)
797 if (keep_ca
&& entry
->type
== AUTH_RULE_CA_CERT
)
799 cas
->insert_first(cas
, entry
);
803 destroy_entry_value(entry
);
807 while (cas
->remove_last(cas
, (void**)&entry
) == SUCCESS
)
809 this->entries
->insert_first(this->entries
, entry
);
815 * Implementation of auth_cfg_t.clone
817 static auth_cfg_t
* clone_(private_auth_cfg_t
*this)
819 enumerator_t
*enumerator
;
823 clone
= auth_cfg_create();
824 enumerator
= this->entries
->create_enumerator(this->entries
);
825 while (enumerator
->enumerate(enumerator
, &entry
))
829 case AUTH_RULE_IDENTITY
:
830 case AUTH_RULE_EAP_IDENTITY
:
831 case AUTH_RULE_AAA_IDENTITY
:
832 case AUTH_RULE_GROUP
:
834 identification_t
*id
= (identification_t
*)entry
->value
;
835 clone
->add(clone
, entry
->type
, id
->clone(id
));
838 case AUTH_RULE_CA_CERT
:
839 case AUTH_RULE_IM_CERT
:
840 case AUTH_RULE_SUBJECT_CERT
:
841 case AUTH_HELPER_IM_CERT
:
842 case AUTH_HELPER_SUBJECT_CERT
:
843 case AUTH_HELPER_REVOCATION_CERT
:
845 certificate_t
*cert
= (certificate_t
*)entry
->value
;
846 clone
->add(clone
, entry
->type
, cert
->get_ref(cert
));
849 case AUTH_RULE_CERT_POLICY
:
850 case AUTH_HELPER_IM_HASH_URL
:
851 case AUTH_HELPER_SUBJECT_HASH_URL
:
853 clone
->add(clone
, entry
->type
, strdup(entry
->value
));
856 case AUTH_RULE_AUTH_CLASS
:
857 case AUTH_RULE_EAP_TYPE
:
858 case AUTH_RULE_EAP_VENDOR
:
859 case AUTH_RULE_CRL_VALIDATION
:
860 case AUTH_RULE_OCSP_VALIDATION
:
861 case AUTH_RULE_RSA_STRENGTH
:
862 case AUTH_RULE_ECDSA_STRENGTH
:
863 clone
->add(clone
, entry
->type
, (uintptr_t)entry
->value
);
867 enumerator
->destroy(enumerator
);
872 * Implementation of auth_cfg_t.destroy
874 static void destroy(private_auth_cfg_t
*this)
877 this->entries
->destroy(this->entries
);
884 auth_cfg_t
*auth_cfg_create()
886 private_auth_cfg_t
*this = malloc_thing(private_auth_cfg_t
);
888 this->public.add
= (void(*)(auth_cfg_t
*, auth_rule_t type
, ...))add
;
889 this->public.get
= (void*(*)(auth_cfg_t
*, auth_rule_t type
))get
;
890 this->public.create_enumerator
= (enumerator_t
*(*)(auth_cfg_t
*))create_enumerator
;
891 this->public.replace
= (void(*)(auth_cfg_t
*,enumerator_t
*,auth_rule_t
,...))replace
;
892 this->public.complies
= (bool(*)(auth_cfg_t
*, auth_cfg_t
*,bool))complies
;
893 this->public.merge
= (void(*)(auth_cfg_t
*, auth_cfg_t
*other
,bool))merge
;
894 this->public.purge
= (void(*)(auth_cfg_t
*,bool))purge
;
895 this->public.equals
= (bool(*)(auth_cfg_t
*, auth_cfg_t
*other
))equals
;
896 this->public.clone
= (auth_cfg_t
*(*)(auth_cfg_t
*))clone_
;
897 this->public.destroy
= (void(*)(auth_cfg_t
*))destroy
;
899 this->entries
= linked_list_create();
901 return &this->public;