auth-cfg: Prefer merged rules over existing ones when moving them
[strongswan.git] / src / libstrongswan / credentials / auth_cfg.c
1 /*
2 * Copyright (C) 2008-2015 Tobias Brunner
3 * Copyright (C) 2007-2009 Martin Willi
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 <utils/debug.h>
21 #include <collections/array.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_XAUTH,
27 "any",
28 "public key",
29 "pre-shared key",
30 "EAP",
31 "XAuth",
32 );
33
34 ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_AC_CERT,
35 "RULE_IDENTITY",
36 "RULE_IDENTITY_LOOSE",
37 "RULE_AUTH_CLASS",
38 "RULE_AAA_IDENTITY",
39 "RULE_EAP_IDENTITY",
40 "RULE_EAP_TYPE",
41 "RULE_EAP_VENDOR",
42 "RULE_XAUTH_BACKEND",
43 "RULE_XAUTH_IDENTITY",
44 "RULE_CA_CERT",
45 "RULE_IM_CERT",
46 "RULE_SUBJECT_CERT",
47 "RULE_CRL_VALIDATION",
48 "RULE_OCSP_VALIDATION",
49 "RULE_GROUP",
50 "RULE_RSA_STRENGTH",
51 "RULE_ECDSA_STRENGTH",
52 "RULE_BLISS_STRENGTH",
53 "RULE_SIGNATURE_SCHEME",
54 "RULE_CERT_POLICY",
55 "HELPER_IM_CERT",
56 "HELPER_SUBJECT_CERT",
57 "HELPER_IM_HASH_URL",
58 "HELPER_SUBJECT_HASH_URL",
59 "HELPER_REVOCATION_CERT",
60 "HELPER_AC_CERT",
61 );
62
63 /**
64 * Check if the given rule is a rule for which there may be multiple values.
65 */
66 static inline bool is_multi_value_rule(auth_rule_t type)
67 {
68 switch (type)
69 {
70 case AUTH_RULE_AUTH_CLASS:
71 case AUTH_RULE_EAP_TYPE:
72 case AUTH_RULE_EAP_VENDOR:
73 case AUTH_RULE_RSA_STRENGTH:
74 case AUTH_RULE_ECDSA_STRENGTH:
75 case AUTH_RULE_BLISS_STRENGTH:
76 case AUTH_RULE_IDENTITY:
77 case AUTH_RULE_IDENTITY_LOOSE:
78 case AUTH_RULE_EAP_IDENTITY:
79 case AUTH_RULE_AAA_IDENTITY:
80 case AUTH_RULE_XAUTH_IDENTITY:
81 case AUTH_RULE_XAUTH_BACKEND:
82 case AUTH_HELPER_SUBJECT_CERT:
83 case AUTH_HELPER_SUBJECT_HASH_URL:
84 case AUTH_RULE_MAX:
85 return FALSE;
86 case AUTH_RULE_OCSP_VALIDATION:
87 case AUTH_RULE_CRL_VALIDATION:
88 case AUTH_RULE_GROUP:
89 case AUTH_RULE_SUBJECT_CERT:
90 case AUTH_RULE_CA_CERT:
91 case AUTH_RULE_IM_CERT:
92 case AUTH_RULE_CERT_POLICY:
93 case AUTH_RULE_SIGNATURE_SCHEME:
94 case AUTH_HELPER_IM_CERT:
95 case AUTH_HELPER_IM_HASH_URL:
96 case AUTH_HELPER_REVOCATION_CERT:
97 case AUTH_HELPER_AC_CERT:
98 return TRUE;
99 }
100 return FALSE;
101 }
102
103 typedef struct private_auth_cfg_t private_auth_cfg_t;
104
105 /**
106 * private data of item_set
107 */
108 struct private_auth_cfg_t {
109
110 /**
111 * public functions
112 */
113 auth_cfg_t public;
114
115 /**
116 * Array of entry_t
117 */
118 array_t *entries;
119 };
120
121 typedef struct entry_t entry_t;
122
123 struct entry_t {
124 /** rule type */
125 auth_rule_t type;
126 /** associated value */
127 void *value;
128 };
129
130 /**
131 * enumerator for auth_cfg_t.create_enumerator()
132 */
133 typedef struct {
134 /** implements enumerator_t */
135 enumerator_t public;
136 /** inner enumerator from linked_list_t */
137 enumerator_t *inner;
138 /** current entry */
139 entry_t *current;
140 /** types we have already enumerated */
141 bool enumerated[AUTH_RULE_MAX];
142 } entry_enumerator_t;
143
144 /**
145 * enumerate function for item_enumerator_t
146 */
147 static bool enumerate(entry_enumerator_t *this, auth_rule_t *type, void **value)
148 {
149 entry_t *entry;
150
151 while (this->inner->enumerate(this->inner, &entry))
152 {
153 if (!is_multi_value_rule(entry->type) && this->enumerated[entry->type])
154 {
155 continue;
156 }
157 this->enumerated[entry->type] = TRUE;
158 this->current = entry;
159 if (type)
160 {
161 *type = entry->type;
162 }
163 if (value)
164 {
165 *value = entry->value;
166 }
167 return TRUE;
168 }
169 return FALSE;
170 }
171
172 /**
173 * destroy function for item_enumerator_t
174 */
175 static void entry_enumerator_destroy(entry_enumerator_t *this)
176 {
177 this->inner->destroy(this->inner);
178 free(this);
179 }
180
181 METHOD(auth_cfg_t, create_enumerator, enumerator_t*,
182 private_auth_cfg_t *this)
183 {
184 entry_enumerator_t *enumerator;
185
186 INIT(enumerator,
187 .public = {
188 .enumerate = (void*)enumerate,
189 .destroy = (void*)entry_enumerator_destroy,
190 },
191 .inner = array_create_enumerator(this->entries),
192 );
193 return &enumerator->public;
194 }
195
196 /**
197 * Initialize an entry.
198 */
199 static void init_entry(entry_t *this, auth_rule_t type, va_list args)
200 {
201 this->type = type;
202 switch (type)
203 {
204 case AUTH_RULE_IDENTITY_LOOSE:
205 case AUTH_RULE_AUTH_CLASS:
206 case AUTH_RULE_EAP_TYPE:
207 case AUTH_RULE_EAP_VENDOR:
208 case AUTH_RULE_CRL_VALIDATION:
209 case AUTH_RULE_OCSP_VALIDATION:
210 case AUTH_RULE_RSA_STRENGTH:
211 case AUTH_RULE_ECDSA_STRENGTH:
212 case AUTH_RULE_BLISS_STRENGTH:
213 case AUTH_RULE_SIGNATURE_SCHEME:
214 /* integer type */
215 this->value = (void*)(uintptr_t)va_arg(args, u_int);
216 break;
217 case AUTH_RULE_IDENTITY:
218 case AUTH_RULE_EAP_IDENTITY:
219 case AUTH_RULE_AAA_IDENTITY:
220 case AUTH_RULE_XAUTH_BACKEND:
221 case AUTH_RULE_XAUTH_IDENTITY:
222 case AUTH_RULE_GROUP:
223 case AUTH_RULE_CA_CERT:
224 case AUTH_RULE_IM_CERT:
225 case AUTH_RULE_SUBJECT_CERT:
226 case AUTH_RULE_CERT_POLICY:
227 case AUTH_HELPER_IM_CERT:
228 case AUTH_HELPER_SUBJECT_CERT:
229 case AUTH_HELPER_IM_HASH_URL:
230 case AUTH_HELPER_SUBJECT_HASH_URL:
231 case AUTH_HELPER_REVOCATION_CERT:
232 case AUTH_HELPER_AC_CERT:
233 /* pointer type */
234 this->value = va_arg(args, void*);
235 break;
236 case AUTH_RULE_MAX:
237 this->value = NULL;
238 break;
239 }
240 }
241
242 /**
243 * Compare two entries for equality.
244 */
245 static bool entry_equals(entry_t *e1, entry_t *e2)
246 {
247 if (e1->type != e2->type)
248 {
249 return FALSE;
250 }
251 switch (e1->type)
252 {
253 case AUTH_RULE_IDENTITY_LOOSE:
254 case AUTH_RULE_AUTH_CLASS:
255 case AUTH_RULE_EAP_TYPE:
256 case AUTH_RULE_EAP_VENDOR:
257 case AUTH_RULE_CRL_VALIDATION:
258 case AUTH_RULE_OCSP_VALIDATION:
259 case AUTH_RULE_RSA_STRENGTH:
260 case AUTH_RULE_ECDSA_STRENGTH:
261 case AUTH_RULE_BLISS_STRENGTH:
262 case AUTH_RULE_SIGNATURE_SCHEME:
263 {
264 return e1->value == e2->value;
265 }
266 case AUTH_RULE_CA_CERT:
267 case AUTH_RULE_IM_CERT:
268 case AUTH_RULE_SUBJECT_CERT:
269 case AUTH_HELPER_IM_CERT:
270 case AUTH_HELPER_SUBJECT_CERT:
271 case AUTH_HELPER_REVOCATION_CERT:
272 case AUTH_HELPER_AC_CERT:
273 {
274 certificate_t *c1, *c2;
275
276 c1 = (certificate_t*)e1->value;
277 c2 = (certificate_t*)e2->value;
278
279 return c1->equals(c1, c2);
280 }
281 case AUTH_RULE_IDENTITY:
282 case AUTH_RULE_EAP_IDENTITY:
283 case AUTH_RULE_AAA_IDENTITY:
284 case AUTH_RULE_XAUTH_IDENTITY:
285 case AUTH_RULE_GROUP:
286 {
287 identification_t *id1, *id2;
288
289 id1 = (identification_t*)e1->value;
290 id2 = (identification_t*)e2->value;
291
292 return id1->equals(id1, id2);
293 }
294 case AUTH_RULE_CERT_POLICY:
295 case AUTH_RULE_XAUTH_BACKEND:
296 case AUTH_HELPER_IM_HASH_URL:
297 case AUTH_HELPER_SUBJECT_HASH_URL:
298 {
299 return streq(e1->value, e2->value);
300 }
301 case AUTH_RULE_MAX:
302 break;
303 }
304 return FALSE;
305 }
306
307 /**
308 * Destroy the value associated with an entry
309 */
310 static void destroy_entry_value(entry_t *entry)
311 {
312 switch (entry->type)
313 {
314 case AUTH_RULE_IDENTITY:
315 case AUTH_RULE_EAP_IDENTITY:
316 case AUTH_RULE_AAA_IDENTITY:
317 case AUTH_RULE_GROUP:
318 case AUTH_RULE_XAUTH_IDENTITY:
319 {
320 identification_t *id = (identification_t*)entry->value;
321 id->destroy(id);
322 break;
323 }
324 case AUTH_RULE_CA_CERT:
325 case AUTH_RULE_IM_CERT:
326 case AUTH_RULE_SUBJECT_CERT:
327 case AUTH_HELPER_IM_CERT:
328 case AUTH_HELPER_SUBJECT_CERT:
329 case AUTH_HELPER_REVOCATION_CERT:
330 case AUTH_HELPER_AC_CERT:
331 {
332 certificate_t *cert = (certificate_t*)entry->value;
333 cert->destroy(cert);
334 break;
335 }
336 case AUTH_RULE_CERT_POLICY:
337 case AUTH_RULE_XAUTH_BACKEND:
338 case AUTH_HELPER_IM_HASH_URL:
339 case AUTH_HELPER_SUBJECT_HASH_URL:
340 {
341 free(entry->value);
342 break;
343 }
344 case AUTH_RULE_IDENTITY_LOOSE:
345 case AUTH_RULE_AUTH_CLASS:
346 case AUTH_RULE_EAP_TYPE:
347 case AUTH_RULE_EAP_VENDOR:
348 case AUTH_RULE_CRL_VALIDATION:
349 case AUTH_RULE_OCSP_VALIDATION:
350 case AUTH_RULE_RSA_STRENGTH:
351 case AUTH_RULE_ECDSA_STRENGTH:
352 case AUTH_RULE_BLISS_STRENGTH:
353 case AUTH_RULE_SIGNATURE_SCHEME:
354 case AUTH_RULE_MAX:
355 break;
356 }
357 }
358
359 /**
360 * Implementation of auth_cfg_t.replace.
361 */
362 static void replace(private_auth_cfg_t *this, entry_enumerator_t *enumerator,
363 auth_rule_t type, ...)
364 {
365 if (enumerator->current)
366 {
367 entry_t *entry;
368 va_list args;
369
370 va_start(args, type);
371 entry = enumerator->current;
372 destroy_entry_value(entry);
373 entry->type = type;
374 switch (type)
375 {
376 case AUTH_RULE_IDENTITY_LOOSE:
377 case AUTH_RULE_AUTH_CLASS:
378 case AUTH_RULE_EAP_TYPE:
379 case AUTH_RULE_EAP_VENDOR:
380 case AUTH_RULE_CRL_VALIDATION:
381 case AUTH_RULE_OCSP_VALIDATION:
382 case AUTH_RULE_RSA_STRENGTH:
383 case AUTH_RULE_ECDSA_STRENGTH:
384 case AUTH_RULE_BLISS_STRENGTH:
385 case AUTH_RULE_SIGNATURE_SCHEME:
386 /* integer type */
387 entry->value = (void*)(uintptr_t)va_arg(args, u_int);
388 break;
389 case AUTH_RULE_IDENTITY:
390 case AUTH_RULE_EAP_IDENTITY:
391 case AUTH_RULE_AAA_IDENTITY:
392 case AUTH_RULE_XAUTH_BACKEND:
393 case AUTH_RULE_XAUTH_IDENTITY:
394 case AUTH_RULE_GROUP:
395 case AUTH_RULE_CA_CERT:
396 case AUTH_RULE_IM_CERT:
397 case AUTH_RULE_SUBJECT_CERT:
398 case AUTH_RULE_CERT_POLICY:
399 case AUTH_HELPER_IM_CERT:
400 case AUTH_HELPER_SUBJECT_CERT:
401 case AUTH_HELPER_IM_HASH_URL:
402 case AUTH_HELPER_SUBJECT_HASH_URL:
403 case AUTH_HELPER_REVOCATION_CERT:
404 case AUTH_HELPER_AC_CERT:
405 /* pointer type */
406 entry->value = va_arg(args, void*);
407 break;
408 case AUTH_RULE_MAX:
409 entry->value = NULL;
410 break;
411 }
412 va_end(args);
413 }
414 }
415
416 METHOD(auth_cfg_t, get, void*,
417 private_auth_cfg_t *this, auth_rule_t type)
418 {
419 enumerator_t *enumerator;
420 void *current_value, *best_value = NULL;
421 auth_rule_t current_type;
422 bool found = FALSE;
423
424 enumerator = create_enumerator(this);
425 while (enumerator->enumerate(enumerator, &current_type, &current_value))
426 {
427 if (type == current_type)
428 {
429 if (type == AUTH_RULE_CRL_VALIDATION ||
430 type == AUTH_RULE_OCSP_VALIDATION)
431 { /* for CRL/OCSP validation, always get() the highest value */
432 if (!found || current_value > best_value)
433 {
434 best_value = current_value;
435 }
436 found = TRUE;
437 continue;
438 }
439 best_value = current_value;
440 found = TRUE;
441 break;
442 }
443 }
444 enumerator->destroy(enumerator);
445 if (found)
446 {
447 return best_value;
448 }
449 switch (type)
450 {
451 /* use some sane defaults if we don't find an entry */
452 case AUTH_RULE_AUTH_CLASS:
453 return (void*)AUTH_CLASS_ANY;
454 case AUTH_RULE_EAP_TYPE:
455 return (void*)EAP_NAK;
456 case AUTH_RULE_EAP_VENDOR:
457 case AUTH_RULE_RSA_STRENGTH:
458 case AUTH_RULE_ECDSA_STRENGTH:
459 case AUTH_RULE_BLISS_STRENGTH:
460 return (void*)0;
461 case AUTH_RULE_SIGNATURE_SCHEME:
462 return (void*)HASH_UNKNOWN;
463 case AUTH_RULE_CRL_VALIDATION:
464 case AUTH_RULE_OCSP_VALIDATION:
465 return (void*)VALIDATION_FAILED;
466 case AUTH_RULE_IDENTITY_LOOSE:
467 return (void*)FALSE;
468 case AUTH_RULE_IDENTITY:
469 case AUTH_RULE_EAP_IDENTITY:
470 case AUTH_RULE_AAA_IDENTITY:
471 case AUTH_RULE_XAUTH_BACKEND:
472 case AUTH_RULE_XAUTH_IDENTITY:
473 case AUTH_RULE_GROUP:
474 case AUTH_RULE_CA_CERT:
475 case AUTH_RULE_IM_CERT:
476 case AUTH_RULE_SUBJECT_CERT:
477 case AUTH_RULE_CERT_POLICY:
478 case AUTH_HELPER_IM_CERT:
479 case AUTH_HELPER_SUBJECT_CERT:
480 case AUTH_HELPER_IM_HASH_URL:
481 case AUTH_HELPER_SUBJECT_HASH_URL:
482 case AUTH_HELPER_REVOCATION_CERT:
483 case AUTH_HELPER_AC_CERT:
484 case AUTH_RULE_MAX:
485 break;
486 }
487 return NULL;
488 }
489
490 /**
491 * Implementation of auth_cfg_t.add.
492 */
493 static void add(private_auth_cfg_t *this, auth_rule_t type, ...)
494 {
495 entry_t entry;
496 va_list args;
497
498 va_start(args, type);
499 init_entry(&entry, type, args);
500 va_end(args);
501
502 if (is_multi_value_rule(type))
503 { /* insert rules that may occur multiple times at the end */
504 array_insert(this->entries, ARRAY_TAIL, &entry);
505 }
506 else
507 { /* insert rules we expect only once at the front (get() will return
508 * the latest value) */
509 array_insert(this->entries, ARRAY_HEAD, &entry);
510 }
511 }
512
513 METHOD(auth_cfg_t, complies, bool,
514 private_auth_cfg_t *this, auth_cfg_t *constraints, bool log_error)
515 {
516 enumerator_t *e1, *e2;
517 bool success = TRUE, group_match = FALSE;
518 bool ca_match = FALSE, cert_match = FALSE;
519 identification_t *require_group = NULL;
520 certificate_t *require_ca = NULL, *require_cert = NULL;
521 signature_scheme_t scheme = SIGN_UNKNOWN;
522 u_int strength = 0;
523 auth_rule_t t1, t2;
524 char *key_type;
525 void *value;
526
527 e1 = constraints->create_enumerator(constraints);
528 while (e1->enumerate(e1, &t1, &value))
529 {
530 switch (t1)
531 {
532 case AUTH_RULE_CA_CERT:
533 case AUTH_RULE_IM_CERT:
534 {
535 certificate_t *cert;
536
537 /* for CA certs, a match of a single cert is sufficient */
538 require_ca = (certificate_t*)value;
539
540 e2 = create_enumerator(this);
541 while (e2->enumerate(e2, &t2, &cert))
542 {
543 if ((t2 == AUTH_RULE_CA_CERT || t2 == AUTH_RULE_IM_CERT) &&
544 cert->equals(cert, require_ca))
545 {
546 ca_match = TRUE;
547 }
548 }
549 e2->destroy(e2);
550 break;
551 }
552 case AUTH_RULE_SUBJECT_CERT:
553 {
554 certificate_t *cert;
555
556 /* for certs, a match of a single cert is sufficient */
557 require_cert = (certificate_t*)value;
558
559 e2 = create_enumerator(this);
560 while (e2->enumerate(e2, &t2, &cert))
561 {
562 if (t2 == AUTH_RULE_SUBJECT_CERT &&
563 cert->equals(cert, require_cert))
564 {
565 cert_match = TRUE;
566 }
567 }
568 e2->destroy(e2);
569 break;
570 }
571 case AUTH_RULE_CRL_VALIDATION:
572 case AUTH_RULE_OCSP_VALIDATION:
573 {
574 uintptr_t validated;
575
576 e2 = create_enumerator(this);
577 while (e2->enumerate(e2, &t2, &validated))
578 {
579 if (t2 == t1)
580 {
581 switch ((uintptr_t)value)
582 {
583 case VALIDATION_FAILED:
584 /* no constraint */
585 break;
586 case VALIDATION_SKIPPED:
587 if (validated == VALIDATION_SKIPPED)
588 {
589 break;
590 }
591 /* FALL */
592 case VALIDATION_GOOD:
593 if (validated == VALIDATION_GOOD)
594 {
595 break;
596 }
597 /* FALL */
598 default:
599 success = FALSE;
600 if (log_error)
601 {
602 DBG1(DBG_CFG, "constraint check failed: "
603 "%N is %N, but requires at least %N",
604 auth_rule_names, t1,
605 cert_validation_names, validated,
606 cert_validation_names, (uintptr_t)value);
607 }
608 break;
609 }
610 }
611 }
612 e2->destroy(e2);
613 break;
614 }
615 case AUTH_RULE_IDENTITY:
616 case AUTH_RULE_EAP_IDENTITY:
617 case AUTH_RULE_AAA_IDENTITY:
618 case AUTH_RULE_XAUTH_IDENTITY:
619 {
620 identification_t *id1, *id2;
621
622 id1 = (identification_t*)value;
623 id2 = get(this, t1);
624 if (!id2 || !id2->matches(id2, id1))
625 {
626 if (t1 == AUTH_RULE_IDENTITY &&
627 constraints->get(constraints, AUTH_RULE_IDENTITY_LOOSE))
628 { /* also verify identity against subjectAltNames */
629 certificate_t *cert;
630
631 cert = get(this, AUTH_HELPER_SUBJECT_CERT);
632 if (cert && cert->has_subject(cert, id1))
633 {
634 break;
635 }
636 }
637 success = FALSE;
638 if (log_error)
639 {
640 DBG1(DBG_CFG, "constraint check failed: %sidentity '%Y'"
641 " required ", t1 == AUTH_RULE_IDENTITY ? "" :
642 "EAP ", id1);
643 }
644 }
645 break;
646 }
647 case AUTH_RULE_AUTH_CLASS:
648 {
649 if ((uintptr_t)value != AUTH_CLASS_ANY &&
650 (uintptr_t)value != (uintptr_t)get(this, t1))
651 {
652 success = FALSE;
653 if (log_error)
654 {
655 DBG1(DBG_CFG, "constraint requires %N authentication, "
656 "but %N was used", auth_class_names, (uintptr_t)value,
657 auth_class_names, (uintptr_t)get(this, t1));
658 }
659 }
660 break;
661 }
662 case AUTH_RULE_EAP_TYPE:
663 {
664 if ((uintptr_t)value != (uintptr_t)get(this, t1) &&
665 (uintptr_t)value != EAP_DYNAMIC &&
666 (uintptr_t)value != EAP_RADIUS)
667 {
668 success = FALSE;
669 if (log_error)
670 {
671 DBG1(DBG_CFG, "constraint requires %N, "
672 "but %N was used", eap_type_names, (uintptr_t)value,
673 eap_type_names, (uintptr_t)get(this, t1));
674 }
675 }
676 break;
677 }
678 case AUTH_RULE_EAP_VENDOR:
679 {
680 if ((uintptr_t)value != (uintptr_t)get(this, t1))
681 {
682 success = FALSE;
683 if (log_error)
684 {
685 DBG1(DBG_CFG, "constraint requires EAP vendor %d, "
686 "but %d was used", (uintptr_t)value,
687 (uintptr_t)get(this, t1));
688 }
689 }
690 break;
691 }
692 case AUTH_RULE_GROUP:
693 {
694 identification_t *group;
695
696 /* for groups, a match of a single group is sufficient */
697 require_group = (identification_t*)value;
698 e2 = create_enumerator(this);
699 while (e2->enumerate(e2, &t2, &group))
700 {
701 if (t2 == AUTH_RULE_GROUP &&
702 group->matches(group, require_group))
703 {
704 group_match = TRUE;
705 }
706 }
707 e2->destroy(e2);
708 break;
709 }
710 case AUTH_RULE_RSA_STRENGTH:
711 case AUTH_RULE_ECDSA_STRENGTH:
712 case AUTH_RULE_BLISS_STRENGTH:
713 {
714 strength = (uintptr_t)value;
715 break;
716 }
717 case AUTH_RULE_SIGNATURE_SCHEME:
718 {
719 scheme = (uintptr_t)value;
720 break;
721 }
722 case AUTH_RULE_CERT_POLICY:
723 {
724 char *oid1, *oid2;
725
726 oid1 = (char*)value;
727 success = FALSE;
728 e2 = create_enumerator(this);
729 while (e2->enumerate(e2, &t2, &oid2))
730 {
731 if (t2 == t1 && streq(oid1, oid2))
732 {
733 success = TRUE;
734 break;
735 }
736 }
737 e2->destroy(e2);
738 if (!success && log_error)
739 {
740 DBG1(DBG_CFG, "constraint requires cert policy %s", oid1);
741 }
742 break;
743 }
744 case AUTH_RULE_IDENTITY_LOOSE:
745 /* just an indication when verifying AUTH_RULE_IDENTITY */
746 case AUTH_RULE_XAUTH_BACKEND:
747 /* not enforced, just a hint for local authentication */
748 case AUTH_HELPER_IM_CERT:
749 case AUTH_HELPER_SUBJECT_CERT:
750 case AUTH_HELPER_IM_HASH_URL:
751 case AUTH_HELPER_SUBJECT_HASH_URL:
752 case AUTH_HELPER_REVOCATION_CERT:
753 case AUTH_HELPER_AC_CERT:
754 case AUTH_RULE_MAX:
755 /* skip helpers */
756 continue;
757 }
758 if (!success)
759 {
760 break;
761 }
762 }
763 e1->destroy(e1);
764
765 /* Check if we have a matching constraint (or none at all) for used
766 * signature schemes. */
767 if (success && scheme != SIGN_UNKNOWN)
768 {
769 e2 = create_enumerator(this);
770 while (e2->enumerate(e2, &t2, &scheme))
771 {
772 if (t2 == AUTH_RULE_SIGNATURE_SCHEME)
773 {
774 success = FALSE;
775 e1 = constraints->create_enumerator(constraints);
776 while (e1->enumerate(e1, &t1, &value))
777 {
778 if (t1 == AUTH_RULE_SIGNATURE_SCHEME &&
779 (uintptr_t)value == scheme)
780 {
781 success = TRUE;
782 break;
783 }
784 }
785 e1->destroy(e1);
786 if (!success)
787 {
788 if (log_error)
789 {
790 DBG1(DBG_CFG, "signature scheme %N not acceptable",
791 signature_scheme_names, (int)scheme);
792 }
793 break;
794 }
795 }
796 }
797 e2->destroy(e2);
798 }
799
800 /* Check if we have a matching constraint (or none at all) for used
801 * public key strength */
802 if (success && strength)
803 {
804 e2 = create_enumerator(this);
805 while (e2->enumerate(e2, &t2, &strength))
806 {
807 switch (t2)
808 {
809 default:
810 continue;
811 case AUTH_RULE_RSA_STRENGTH:
812 key_type = "RSA";
813 break;
814 case AUTH_RULE_ECDSA_STRENGTH:
815 key_type = "ECDSA";
816 break;
817 case AUTH_RULE_BLISS_STRENGTH:
818 key_type = "BLISS";
819 break;
820 }
821 success = FALSE;
822 e1 = constraints->create_enumerator(constraints);
823 while (e1->enumerate(e1, &t1, &value))
824 {
825 if (t1 == t2 && (uintptr_t)value <= strength)
826 {
827 success = TRUE;
828 break;
829 }
830 }
831 e1->destroy(e1);
832 if (!success)
833 {
834 if (log_error)
835 {
836 DBG1(DBG_CFG, "%s-%d signatures not acceptable",
837 key_type, strength);
838 }
839 break;
840 }
841 }
842 e2->destroy(e2);
843 }
844
845 if (require_group && !group_match)
846 {
847 if (log_error)
848 {
849 DBG1(DBG_CFG, "constraint check failed: group membership to "
850 "'%Y' required", require_group);
851 }
852 return FALSE;
853 }
854 if (require_ca && !ca_match)
855 {
856 if (log_error)
857 {
858 DBG1(DBG_CFG, "constraint check failed: peer not "
859 "authenticated by CA '%Y'",
860 require_ca->get_subject(require_ca));
861 }
862 return FALSE;
863 }
864 if (require_cert && !cert_match)
865 {
866 if (log_error)
867 {
868 DBG1(DBG_CFG, "constraint check failed: peer not "
869 "authenticated with peer cert '%Y'",
870 require_cert->get_subject(require_cert));
871 }
872 return FALSE;
873 }
874 return success;
875 }
876
877 /**
878 * Implementation of auth_cfg_t.merge.
879 */
880 static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy)
881 {
882 if (!other)
883 { /* nothing to merge */
884 return;
885 }
886 if (copy)
887 {
888 enumerator_t *enumerator;
889 auth_rule_t type;
890 void *value;
891
892 /* this enumerator skips duplicates for rules we expect only once */
893 enumerator = create_enumerator(other);
894 while (enumerator->enumerate(enumerator, &type, &value))
895 {
896 switch (type)
897 {
898 case AUTH_RULE_CA_CERT:
899 case AUTH_RULE_IM_CERT:
900 case AUTH_RULE_SUBJECT_CERT:
901 case AUTH_HELPER_IM_CERT:
902 case AUTH_HELPER_SUBJECT_CERT:
903 case AUTH_HELPER_REVOCATION_CERT:
904 case AUTH_HELPER_AC_CERT:
905 {
906 certificate_t *cert = (certificate_t*)value;
907
908 add(this, type, cert->get_ref(cert));
909 break;
910 }
911 case AUTH_RULE_IDENTITY_LOOSE:
912 case AUTH_RULE_CRL_VALIDATION:
913 case AUTH_RULE_OCSP_VALIDATION:
914 case AUTH_RULE_AUTH_CLASS:
915 case AUTH_RULE_EAP_TYPE:
916 case AUTH_RULE_EAP_VENDOR:
917 case AUTH_RULE_RSA_STRENGTH:
918 case AUTH_RULE_ECDSA_STRENGTH:
919 case AUTH_RULE_BLISS_STRENGTH:
920 case AUTH_RULE_SIGNATURE_SCHEME:
921 {
922 add(this, type, (uintptr_t)value);
923 break;
924 }
925 case AUTH_RULE_IDENTITY:
926 case AUTH_RULE_EAP_IDENTITY:
927 case AUTH_RULE_AAA_IDENTITY:
928 case AUTH_RULE_GROUP:
929 case AUTH_RULE_XAUTH_IDENTITY:
930 {
931 identification_t *id = (identification_t*)value;
932
933 add(this, type, id->clone(id));
934 break;
935 }
936 case AUTH_RULE_XAUTH_BACKEND:
937 case AUTH_RULE_CERT_POLICY:
938 case AUTH_HELPER_IM_HASH_URL:
939 case AUTH_HELPER_SUBJECT_HASH_URL:
940 {
941 add(this, type, strdup((char*)value));
942 break;
943 }
944 case AUTH_RULE_MAX:
945 break;
946 }
947 }
948 enumerator->destroy(enumerator);
949 }
950 else
951 {
952 entry_t entry;
953
954 while (array_remove(other->entries, ARRAY_TAIL, &entry))
955 { /* keep order but prefer new values (esp. for single valued ones) */
956 array_insert(this->entries, ARRAY_HEAD, &entry);
957 }
958 array_compress(other->entries);
959 }
960 }
961
962 /**
963 * Compare two auth_cfg_t objects for equality.
964 */
965 static bool auth_cfg_equals(private_auth_cfg_t *this, private_auth_cfg_t *other)
966 {
967 enumerator_t *e1, *e2;
968 entry_t *i1, *i2;
969 bool equal = TRUE, found;
970
971 /* the rule count does not have to be equal for the two, as we only compare
972 * the first value found for some rules */
973 e1 = array_create_enumerator(this->entries);
974 while (e1->enumerate(e1, &i1))
975 {
976 found = FALSE;
977
978 e2 = array_create_enumerator(other->entries);
979 while (e2->enumerate(e2, &i2))
980 {
981 if (entry_equals(i1, i2))
982 {
983 found = TRUE;
984 break;
985 }
986 else if (i1->type == i2->type && !is_multi_value_rule(i1->type))
987 { /* we continue our search, only for multi valued rules */
988 break;
989 }
990 }
991 e2->destroy(e2);
992 if (!found)
993 {
994 equal = FALSE;
995 break;
996 }
997 }
998 e1->destroy(e1);
999 return equal;
1000 }
1001
1002 /**
1003 * Implementation of auth_cfg_t.equals.
1004 */
1005 static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other)
1006 {
1007 if (auth_cfg_equals(this, other))
1008 {
1009 /* as 'other' might contain entries that 'this' doesn't we also check
1010 * the other way around */
1011 return auth_cfg_equals(other, this);
1012 }
1013 return FALSE;
1014 }
1015
1016 METHOD(auth_cfg_t, purge, void,
1017 private_auth_cfg_t *this, bool keep_ca)
1018 {
1019 enumerator_t *enumerator;
1020 entry_t *entry;
1021
1022 enumerator = array_create_enumerator(this->entries);
1023 while (enumerator->enumerate(enumerator, &entry))
1024 {
1025 if (!keep_ca || entry->type != AUTH_RULE_CA_CERT)
1026 {
1027 destroy_entry_value(entry);
1028 array_remove_at(this->entries, enumerator);
1029 }
1030 }
1031 enumerator->destroy(enumerator);
1032
1033 array_compress(this->entries);
1034 }
1035
1036 METHOD(auth_cfg_t, clone_, auth_cfg_t*,
1037 private_auth_cfg_t *this)
1038 {
1039 enumerator_t *enumerator;
1040 auth_cfg_t *clone;
1041 auth_rule_t type;
1042 void *value;
1043
1044 clone = auth_cfg_create();
1045 /* this enumerator skips duplicates for rules we expect only once */
1046 enumerator = create_enumerator(this);
1047 while (enumerator->enumerate(enumerator, &type, &value))
1048 {
1049 switch (type)
1050 {
1051 case AUTH_RULE_IDENTITY:
1052 case AUTH_RULE_EAP_IDENTITY:
1053 case AUTH_RULE_AAA_IDENTITY:
1054 case AUTH_RULE_GROUP:
1055 case AUTH_RULE_XAUTH_IDENTITY:
1056 {
1057 identification_t *id = (identification_t*)value;
1058 clone->add(clone, type, id->clone(id));
1059 break;
1060 }
1061 case AUTH_RULE_CA_CERT:
1062 case AUTH_RULE_IM_CERT:
1063 case AUTH_RULE_SUBJECT_CERT:
1064 case AUTH_HELPER_IM_CERT:
1065 case AUTH_HELPER_SUBJECT_CERT:
1066 case AUTH_HELPER_REVOCATION_CERT:
1067 case AUTH_HELPER_AC_CERT:
1068 {
1069 certificate_t *cert = (certificate_t*)value;
1070 clone->add(clone, type, cert->get_ref(cert));
1071 break;
1072 }
1073 case AUTH_RULE_XAUTH_BACKEND:
1074 case AUTH_RULE_CERT_POLICY:
1075 case AUTH_HELPER_IM_HASH_URL:
1076 case AUTH_HELPER_SUBJECT_HASH_URL:
1077 {
1078 clone->add(clone, type, strdup(value));
1079 break;
1080 }
1081 case AUTH_RULE_IDENTITY_LOOSE:
1082 case AUTH_RULE_AUTH_CLASS:
1083 case AUTH_RULE_EAP_TYPE:
1084 case AUTH_RULE_EAP_VENDOR:
1085 case AUTH_RULE_CRL_VALIDATION:
1086 case AUTH_RULE_OCSP_VALIDATION:
1087 case AUTH_RULE_RSA_STRENGTH:
1088 case AUTH_RULE_ECDSA_STRENGTH:
1089 case AUTH_RULE_BLISS_STRENGTH:
1090 case AUTH_RULE_SIGNATURE_SCHEME:
1091 clone->add(clone, type, (uintptr_t)value);
1092 break;
1093 case AUTH_RULE_MAX:
1094 break;
1095 }
1096 }
1097 enumerator->destroy(enumerator);
1098 return clone;
1099 }
1100
1101 METHOD(auth_cfg_t, destroy, void,
1102 private_auth_cfg_t *this)
1103 {
1104 purge(this, FALSE);
1105 array_destroy(this->entries);
1106 free(this);
1107 }
1108
1109 /*
1110 * see header file
1111 */
1112 auth_cfg_t *auth_cfg_create()
1113 {
1114 private_auth_cfg_t *this;
1115
1116 INIT(this,
1117 .public = {
1118 .add = (void(*)(auth_cfg_t*, auth_rule_t type, ...))add,
1119 .get = _get,
1120 .create_enumerator = _create_enumerator,
1121 .replace = (void(*)(auth_cfg_t*,enumerator_t*,auth_rule_t,...))replace,
1122 .complies = _complies,
1123 .merge = (void(*)(auth_cfg_t*,auth_cfg_t*,bool))merge,
1124 .purge = _purge,
1125 .equals = (bool(*)(auth_cfg_t*,auth_cfg_t*))equals,
1126 .clone = _clone_,
1127 .destroy = _destroy,
1128 },
1129 .entries = array_create(sizeof(entry_t), 0),
1130 );
1131
1132 return &this->public;
1133 }