Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/plugins/constraints/constraints_validator.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2010 Martin Willi
3
 *
4
 * Copyright (C) secunet Security Networks AG
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 "constraints_validator.h"
18
19
#include <utils/debug.h>
20
#include <asn1/asn1.h>
21
#include <collections/linked_list.h>
22
#include <credentials/certificates/x509.h>
23
24
typedef struct private_constraints_validator_t private_constraints_validator_t;
25
26
/**
27
 * Private data of an constraints_validator_t object.
28
 */
29
struct private_constraints_validator_t {
30
31
  /**
32
   * Public constraints_validator_t interface.
33
   */
34
  constraints_validator_t public;
35
};
36
37
/**
38
 * Check pathlen constraint of issuer certificate
39
 */
40
static bool check_pathlen(x509_t *issuer, int pathlen)
41
0
{
42
0
  u_int pathlen_constraint;
43
44
0
  pathlen_constraint = issuer->get_constraint(issuer, X509_PATH_LEN);
45
0
  if (pathlen_constraint != X509_NO_CONSTRAINT &&
46
0
    pathlen > pathlen_constraint)
47
0
  {
48
0
    DBG1(DBG_CFG, "path length of %d violates constraint of %d",
49
0
       pathlen, pathlen_constraint);
50
0
    return FALSE;
51
0
  }
52
0
  return TRUE;
53
0
}
54
55
/**
56
 * Check if a FQDN constraint matches
57
 */
58
static bool fqdn_matches(identification_t *constraint, identification_t *id)
59
0
{
60
0
  chunk_t c, i, diff;
61
62
0
  c = constraint->get_encoding(constraint);
63
0
  i = id->get_encoding(id);
64
65
0
  if (!c.len || i.len < c.len)
66
0
  {
67
0
    return FALSE;
68
0
  }
69
0
  diff = chunk_create(i.ptr, i.len - c.len);
70
0
  if (!chunk_equals(c, chunk_skip(i, diff.len)))
71
0
  {
72
0
    return FALSE;
73
0
  }
74
0
  if (!diff.len)
75
0
  {
76
0
    return TRUE;
77
0
  }
78
0
  if (c.ptr[0] == '.' || diff.ptr[diff.len - 1] == '.')
79
0
  {
80
0
    return TRUE;
81
0
  }
82
0
  return FALSE;
83
0
}
84
85
/**
86
 * Check if a RFC822 constraint matches
87
 */
88
static bool email_matches(identification_t *constraint, identification_t *id)
89
0
{
90
0
  chunk_t c, i, diff;
91
92
0
  c = constraint->get_encoding(constraint);
93
0
  i = id->get_encoding(id);
94
95
0
  if (!c.len || i.len < c.len)
96
0
  {
97
0
    return FALSE;
98
0
  }
99
0
  if (memchr(c.ptr, '@', c.len))
100
0
  { /* constraint is a full email address */
101
0
    return chunk_equals(c, i);
102
0
  }
103
0
  diff = chunk_create(i.ptr, i.len - c.len);
104
0
  if (!diff.len || !chunk_equals(c, chunk_skip(i, diff.len)))
105
0
  {
106
0
    return FALSE;
107
0
  }
108
0
  if (c.ptr[0] == '.')
109
0
  { /* constraint is domain, suffix match */
110
0
    return TRUE;
111
0
  }
112
0
  if (diff.ptr[diff.len - 1] == '@')
113
0
  { /* constraint is host specific, only username can be appended */
114
0
    return TRUE;
115
0
  }
116
0
  return FALSE;
117
0
}
118
119
/**
120
 * Check if a DN constraint matches (RDN prefix match)
121
 */
122
static bool dn_matches(identification_t *constraint, identification_t *id)
123
0
{
124
0
  enumerator_t *ec, *ei;
125
0
  id_part_t pc, pi;
126
0
  chunk_t cc, ci;
127
0
  bool match = TRUE;
128
129
0
  ec = constraint->create_part_enumerator(constraint);
130
0
  ei = id->create_part_enumerator(id);
131
0
  while (ec->enumerate(ec, &pc, &cc))
132
0
  {
133
0
    if (!ei->enumerate(ei, &pi, &ci) ||
134
0
      pi != pc || !chunk_equals(cc, ci))
135
0
    {
136
0
      match = FALSE;
137
0
      break;
138
0
    }
139
0
  }
140
0
  ec->destroy(ec);
141
0
  ei->destroy(ei);
142
143
0
  return match;
144
0
}
145
146
/**
147
 * Check if the given identity type matches the type of NameConstraint
148
 */
149
static bool type_matches(id_type_t constraint, id_type_t id)
150
0
{
151
0
  switch (constraint)
152
0
  {
153
0
    case ID_FQDN:
154
0
    case ID_RFC822_ADDR:
155
0
    case ID_DER_ASN1_DN:
156
0
      return constraint == id;
157
0
    case ID_IPV4_ADDR_SUBNET:
158
0
      return id == ID_IPV4_ADDR;
159
0
    case ID_IPV6_ADDR_SUBNET:
160
0
      return id == ID_IPV6_ADDR;
161
0
    default:
162
0
      return FALSE;
163
0
  }
164
0
}
165
166
/**
167
 * Check if a certificate matches to a NameConstraint
168
 */
169
static bool name_constraint_matches(identification_t *constraint,
170
                  certificate_t *cert, bool permitted)
171
0
{
172
0
  x509_t *x509 = (x509_t*)cert;
173
0
  enumerator_t *enumerator;
174
0
  identification_t *id;
175
0
  id_type_t type;
176
0
  bool matches = permitted;
177
178
0
  type = constraint->get_type(constraint);
179
0
  if (type == ID_DER_ASN1_DN)
180
0
  {
181
0
    matches = dn_matches(constraint, cert->get_subject(cert));
182
0
    if (matches != permitted)
183
0
    {
184
0
      return matches;
185
0
    }
186
0
  }
187
188
0
  enumerator = x509->create_subjectAltName_enumerator(x509);
189
0
  while (enumerator->enumerate(enumerator, &id))
190
0
  {
191
0
    if (type_matches(type, id->get_type(id)))
192
0
    {
193
0
      switch (type)
194
0
      {
195
0
        case ID_FQDN:
196
0
          matches = fqdn_matches(constraint, id);
197
0
          break;
198
0
        case ID_RFC822_ADDR:
199
0
          matches = email_matches(constraint, id);
200
0
          break;
201
0
        case ID_DER_ASN1_DN:
202
0
          matches = dn_matches(constraint, id);
203
0
          break;
204
0
        case ID_IPV4_ADDR_SUBNET:
205
0
        case ID_IPV6_ADDR_SUBNET:
206
0
          matches = id->matches(id, constraint);
207
0
          break;
208
0
        default:
209
0
          DBG1(DBG_CFG, "%N NameConstraint matching not implemented",
210
0
             id_type_names, type);
211
0
          matches = FALSE;
212
0
          break;
213
0
      }
214
0
    }
215
0
    if (matches != permitted)
216
0
    {
217
0
      break;
218
0
    }
219
0
  }
220
0
  enumerator->destroy(enumerator);
221
222
0
  return matches;
223
0
}
224
225
/**
226
 * Check if a permitted or excluded NameConstraint has been inherited to sub-CA
227
 */
228
static bool name_constraint_inherited(identification_t *constraint,
229
                    x509_t *x509, bool permitted)
230
0
{
231
0
  enumerator_t *enumerator;
232
0
  identification_t *id, *a, *b;
233
0
  bool inherited = FALSE;
234
0
  id_type_t type;
235
236
0
  if (!(x509->get_flags(x509) & X509_CA))
237
0
  { /* not a sub-CA, not required */
238
0
    return TRUE;
239
0
  }
240
241
0
  type = constraint->get_type(constraint);
242
0
  enumerator = x509->create_name_constraint_enumerator(x509, permitted);
243
0
  while (enumerator->enumerate(enumerator, &id))
244
0
  {
245
0
    if (id->get_type(id) == type)
246
0
    {
247
0
      if (permitted)
248
0
      { /* permitted constraint can be narrowed */
249
0
        a = constraint;
250
0
        b = id;
251
0
      }
252
0
      else
253
0
      { /* excluded constraint can be widened */
254
0
        a = id;
255
0
        b = constraint;
256
0
      }
257
0
      switch (type)
258
0
      {
259
0
        case ID_FQDN:
260
0
          inherited = fqdn_matches(a, b);
261
0
          break;
262
0
        case ID_RFC822_ADDR:
263
0
          inherited = email_matches(a, b);
264
0
          break;
265
0
        case ID_DER_ASN1_DN:
266
0
          inherited = dn_matches(a, b);
267
0
          break;
268
0
        default:
269
0
          DBG1(DBG_CFG, "%N NameConstraint matching not implemented",
270
0
             id_type_names, type);
271
0
          inherited = FALSE;
272
0
          break;
273
0
      }
274
0
    }
275
0
    if (inherited)
276
0
    {
277
0
      break;
278
0
    }
279
0
  }
280
0
  enumerator->destroy(enumerator);
281
0
  return inherited;
282
0
}
283
284
/**
285
 * Check name constraints
286
 */
287
static bool check_name_constraints(certificate_t *subject, x509_t *issuer)
288
0
{
289
0
  enumerator_t *enumerator;
290
0
  identification_t *constraint;
291
292
0
  enumerator = issuer->create_name_constraint_enumerator(issuer, TRUE);
293
0
  while (enumerator->enumerate(enumerator, &constraint))
294
0
  {
295
0
    if (!name_constraint_matches(constraint, subject, TRUE))
296
0
    {
297
0
      DBG1(DBG_CFG, "certificate '%Y' does not match permitted name "
298
0
         "constraint '%Y'", subject->get_subject(subject), constraint);
299
0
      enumerator->destroy(enumerator);
300
0
      return FALSE;
301
0
    }
302
0
    if (!name_constraint_inherited(constraint, (x509_t*)subject, TRUE))
303
0
    {
304
0
      DBG1(DBG_CFG, "intermediate CA '%Y' does not inherit permitted name "
305
0
         "constraint '%Y'", subject->get_subject(subject), constraint);
306
0
      enumerator->destroy(enumerator);
307
0
      return FALSE;
308
0
    }
309
0
  }
310
0
  enumerator->destroy(enumerator);
311
312
0
  enumerator = issuer->create_name_constraint_enumerator(issuer, FALSE);
313
0
  while (enumerator->enumerate(enumerator, &constraint))
314
0
  {
315
0
    if (name_constraint_matches(constraint, subject, FALSE))
316
0
    {
317
0
      DBG1(DBG_CFG, "certificate '%Y' matches excluded name "
318
0
         "constraint '%Y'", subject->get_subject(subject), constraint);
319
0
      enumerator->destroy(enumerator);
320
0
      return FALSE;
321
0
    }
322
0
    if (!name_constraint_inherited(constraint, (x509_t*)subject, FALSE))
323
0
    {
324
0
      DBG1(DBG_CFG, "intermediate CA '%Y' does not inherit excluded name "
325
0
         "constraint '%Y'", subject->get_subject(subject), constraint);
326
0
      enumerator->destroy(enumerator);
327
0
      return FALSE;
328
0
    }
329
0
  }
330
0
  enumerator->destroy(enumerator);
331
0
  return TRUE;
332
0
}
333
334
/**
335
 * Special OID for anyPolicy
336
 */
337
static chunk_t any_policy = chunk_from_chars(0x55,0x1d,0x20,0x00);
338
339
/**
340
 * Check if an issuer certificate has a given policy OID
341
 */
342
static bool has_policy(x509_t *issuer, chunk_t oid)
343
0
{
344
0
  x509_policy_mapping_t *mapping;
345
0
  x509_cert_policy_t *policy;
346
0
  enumerator_t *enumerator;
347
348
0
  enumerator = issuer->create_cert_policy_enumerator(issuer);
349
0
  while (enumerator->enumerate(enumerator, &policy))
350
0
  {
351
0
    if (chunk_equals(oid, policy->oid) ||
352
0
      chunk_equals(any_policy, policy->oid))
353
0
    {
354
0
      enumerator->destroy(enumerator);
355
0
      return TRUE;
356
0
    }
357
0
  }
358
0
  enumerator->destroy(enumerator);
359
360
  /* fall back to a mapped policy */
361
0
  enumerator = issuer->create_policy_mapping_enumerator(issuer);
362
0
  while (enumerator->enumerate(enumerator, &mapping))
363
0
  {
364
0
    if (chunk_equals(mapping->subject, oid))
365
0
    {
366
0
      enumerator->destroy(enumerator);
367
0
      return TRUE;
368
0
    }
369
0
  }
370
0
  enumerator->destroy(enumerator);
371
0
  return FALSE;
372
0
}
373
374
/**
375
 * Check certificatePolicies.
376
 */
377
static bool check_policy(x509_t *subject, x509_t *issuer)
378
0
{
379
0
  certificate_t *cert DBG_UNUSED = (certificate_t*)subject;
380
0
  x509_policy_mapping_t *mapping;
381
0
  x509_cert_policy_t *policy;
382
0
  enumerator_t *enumerator;
383
0
  char *oid;
384
385
  /* verify if policyMappings in subject are valid */
386
0
  enumerator = subject->create_policy_mapping_enumerator(subject);
387
0
  while (enumerator->enumerate(enumerator, &mapping))
388
0
  {
389
0
    if (!has_policy(issuer, mapping->issuer))
390
0
    {
391
0
      oid = asn1_oid_to_string(mapping->issuer);
392
0
      DBG1(DBG_CFG, "certificate '%Y' maps policy from %s, but issuer "
393
0
         "misses it", cert->get_subject(cert), oid);
394
0
      free(oid);
395
0
      enumerator->destroy(enumerator);
396
0
      return FALSE;
397
0
    }
398
0
  }
399
0
  enumerator->destroy(enumerator);
400
401
0
  enumerator = subject->create_cert_policy_enumerator(subject);
402
0
  while (enumerator->enumerate(enumerator, &policy))
403
0
  {
404
0
    if (!has_policy(issuer, policy->oid))
405
0
    {
406
0
      oid = asn1_oid_to_string(policy->oid);
407
0
      DBG1(DBG_CFG, "policy %s missing in issuing certificate '%Y'",
408
0
         oid, cert->get_issuer(cert));
409
0
      free(oid);
410
0
      enumerator->destroy(enumerator);
411
0
      return FALSE;
412
0
    }
413
0
  }
414
0
  enumerator->destroy(enumerator);
415
416
0
  return TRUE;
417
0
}
418
419
/**
420
 * Check if a given policy is valid under a trustchain
421
 */
422
static bool is_policy_valid(linked_list_t *chain, chunk_t oid)
423
0
{
424
0
  x509_policy_mapping_t *mapping;
425
0
  x509_cert_policy_t *policy;
426
0
  x509_t *issuer;
427
0
  enumerator_t *issuers, *policies, *mappings;
428
0
  bool found = TRUE;
429
430
0
  issuers = chain->create_enumerator(chain);
431
0
  while (issuers->enumerate(issuers, &issuer))
432
0
  {
433
0
    int maxmap = 8;
434
435
0
    while (found)
436
0
    {
437
0
      found = FALSE;
438
439
0
      policies = issuer->create_cert_policy_enumerator(issuer);
440
0
      while (policies->enumerate(policies, &policy))
441
0
      {
442
0
        if (chunk_equals(oid, policy->oid) ||
443
0
          chunk_equals(any_policy, policy->oid))
444
0
        {
445
0
          found = TRUE;
446
0
          break;
447
0
        }
448
0
      }
449
0
      policies->destroy(policies);
450
0
      if (found)
451
0
      {
452
0
        break;
453
0
      }
454
      /* fall back to a mapped policy */
455
0
      mappings = issuer->create_policy_mapping_enumerator(issuer);
456
0
      while (mappings->enumerate(mappings, &mapping))
457
0
      {
458
0
        if (chunk_equals(mapping->subject, oid))
459
0
        {
460
0
          oid = mapping->issuer;
461
0
          found = TRUE;
462
0
          break;
463
0
        }
464
0
      }
465
0
      mappings->destroy(mappings);
466
0
      if (--maxmap == 0)
467
0
      {
468
0
        found = FALSE;
469
0
        break;
470
0
      }
471
0
    }
472
0
    if (!found)
473
0
    {
474
0
      break;
475
0
    }
476
0
  }
477
0
  issuers->destroy(issuers);
478
479
0
  return found;
480
0
}
481
482
/**
483
 * Check len certificates in trustchain for inherited policies
484
 */
485
static bool has_policy_chain(linked_list_t *chain, x509_t *subject, int len)
486
0
{
487
0
  enumerator_t *enumerator;
488
0
  x509_t *issuer;
489
0
  bool valid = TRUE;
490
491
0
  enumerator = chain->create_enumerator(chain);
492
0
  while (len-- > 0 && enumerator->enumerate(enumerator, &issuer))
493
0
  {
494
0
    if (!check_policy(subject, issuer))
495
0
    {
496
0
      valid = FALSE;
497
0
      break;
498
0
    }
499
0
    subject = issuer;
500
0
  }
501
0
  enumerator->destroy(enumerator);
502
0
  return valid;
503
0
}
504
505
/**
506
 * Check len certificates in trustchain to have no policyMappings
507
 */
508
static bool has_no_policy_mapping(linked_list_t *chain, int len)
509
0
{
510
0
  enumerator_t *enumerator, *mappings;
511
0
  x509_policy_mapping_t *mapping;
512
0
  certificate_t *cert DBG_UNUSED;
513
0
  x509_t *x509;
514
0
  bool valid = TRUE;
515
516
0
  enumerator = chain->create_enumerator(chain);
517
0
  while (len-- > 0 && enumerator->enumerate(enumerator, &x509))
518
0
  {
519
0
    mappings = x509->create_policy_mapping_enumerator(x509);
520
0
    valid = !mappings->enumerate(mappings, &mapping);
521
0
    mappings->destroy(mappings);
522
0
    if (!valid)
523
0
    {
524
0
      cert = (certificate_t*)x509;
525
0
      DBG1(DBG_CFG, "found policyMapping in certificate '%Y', but "
526
0
         "inhibitPolicyMapping in effect", cert->get_subject(cert));
527
0
      break;
528
0
    }
529
0
  }
530
0
  enumerator->destroy(enumerator);
531
0
  return valid;
532
0
}
533
534
/**
535
 * Check len certificates in trustchain to have no anyPolicies
536
 */
537
static bool has_no_any_policy(linked_list_t *chain, int len)
538
0
{
539
0
  enumerator_t *enumerator, *policies;
540
0
  x509_cert_policy_t *policy;
541
0
  certificate_t *cert DBG_UNUSED;
542
0
  x509_t *x509;
543
0
  bool valid = TRUE;
544
545
0
  enumerator = chain->create_enumerator(chain);
546
0
  while (len-- > 0 && enumerator->enumerate(enumerator, &x509))
547
0
  {
548
0
    policies = x509->create_cert_policy_enumerator(x509);
549
0
    while (policies->enumerate(policies, &policy))
550
0
    {
551
0
      if (chunk_equals(policy->oid, any_policy))
552
0
      {
553
0
        cert = (certificate_t*)x509;
554
0
        DBG1(DBG_CFG, "found anyPolicy in certificate '%Y', but "
555
0
           "inhibitAnyPolicy in effect", cert->get_subject(cert));
556
0
        valid = FALSE;
557
0
        break;
558
0
      }
559
0
    }
560
0
    policies->destroy(policies);
561
0
  }
562
0
  enumerator->destroy(enumerator);
563
0
  return valid;
564
0
}
565
566
/**
567
 * Check requireExplicitPolicy and inhibitPolicyMapping constraints
568
 */
569
static bool check_policy_constraints(x509_t *issuer, u_int pathlen,
570
                   auth_cfg_t *auth)
571
0
{
572
0
  certificate_t *subject;
573
0
  bool valid = TRUE;
574
575
0
  subject = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
576
0
  if (subject)
577
0
  {
578
0
    if (subject->get_type(subject) == CERT_X509)
579
0
    {
580
0
      x509_cert_policy_t *policy;
581
0
      enumerator_t *enumerator;
582
0
      linked_list_t *chain;
583
0
      certificate_t *cert;
584
0
      auth_rule_t rule;
585
0
      x509_t *x509;
586
0
      int len = 0;
587
0
      u_int expl, inh;
588
0
      char *oid;
589
590
      /* prepare trustchain to validate */
591
0
      chain = linked_list_create();
592
0
      enumerator = auth->create_enumerator(auth);
593
0
      while (enumerator->enumerate(enumerator, &rule, &cert))
594
0
      {
595
0
        if (rule == AUTH_RULE_IM_CERT &&
596
0
          cert->get_type(cert) == CERT_X509)
597
0
        {
598
0
          chain->insert_last(chain, cert);
599
0
        }
600
0
      }
601
0
      enumerator->destroy(enumerator);
602
0
      chain->insert_last(chain, issuer);
603
604
      /* search for requireExplicitPolicy constraints */
605
0
      enumerator = chain->create_enumerator(chain);
606
0
      while (enumerator->enumerate(enumerator, &x509))
607
0
      {
608
0
        expl = x509->get_constraint(x509, X509_REQUIRE_EXPLICIT_POLICY);
609
0
        if (expl != X509_NO_CONSTRAINT)
610
0
        {
611
0
          if (!has_policy_chain(chain, (x509_t*)subject, len - expl))
612
0
          {
613
0
            valid = FALSE;
614
0
            break;
615
0
          }
616
0
        }
617
0
        len++;
618
0
      }
619
0
      enumerator->destroy(enumerator);
620
621
      /* search for inhibitPolicyMapping/inhibitAnyPolicy constraints */
622
0
      len = 0;
623
0
      chain->insert_first(chain, subject);
624
0
      enumerator = chain->create_enumerator(chain);
625
0
      while (enumerator->enumerate(enumerator, &x509))
626
0
      {
627
0
        inh = x509->get_constraint(x509, X509_INHIBIT_POLICY_MAPPING);
628
0
        if (inh != X509_NO_CONSTRAINT)
629
0
        {
630
0
          if (!has_no_policy_mapping(chain, len - inh))
631
0
          {
632
0
            valid = FALSE;
633
0
            break;
634
0
          }
635
0
        }
636
0
        inh = x509->get_constraint(x509, X509_INHIBIT_ANY_POLICY);
637
0
        if (inh != X509_NO_CONSTRAINT)
638
0
        {
639
0
          if (!has_no_any_policy(chain, len - inh))
640
0
          {
641
0
            valid = FALSE;
642
0
            break;
643
0
          }
644
0
        }
645
0
        len++;
646
0
      }
647
0
      enumerator->destroy(enumerator);
648
649
0
      if (valid)
650
0
      {
651
0
        x509 = (x509_t*)subject;
652
653
0
        enumerator = x509->create_cert_policy_enumerator(x509);
654
0
        while (enumerator->enumerate(enumerator, &policy))
655
0
        {
656
0
          oid = asn1_oid_to_string(policy->oid);
657
0
          if (oid)
658
0
          {
659
0
            if (is_policy_valid(chain, policy->oid))
660
0
            {
661
0
              auth->add(auth, AUTH_RULE_CERT_POLICY, oid);
662
0
            }
663
0
            else
664
0
            {
665
0
              DBG1(DBG_CFG, "certificate policy %s for '%Y' "
666
0
                 "not allowed by trustchain, ignored",
667
0
                 oid, subject->get_subject(subject));
668
0
              free(oid);
669
0
            }
670
0
          }
671
0
        }
672
0
        enumerator->destroy(enumerator);
673
0
      }
674
0
      chain->destroy(chain);
675
0
    }
676
0
  }
677
0
  return valid;
678
0
}
679
680
METHOD(cert_validator_t, validate, bool,
681
  private_constraints_validator_t *this, certificate_t *subject,
682
  certificate_t *issuer, u_int pathlen, bool anchor, auth_cfg_t *auth)
683
0
{
684
0
  if (issuer->get_type(issuer) == CERT_X509 &&
685
0
    subject->get_type(subject) == CERT_X509)
686
0
  {
687
0
    if (!check_pathlen((x509_t*)issuer, pathlen))
688
0
    {
689
0
      lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_EXCEEDED_PATH_LEN,
690
0
                  subject);
691
0
      return FALSE;
692
0
    }
693
0
    if (!check_name_constraints(subject, (x509_t*)issuer))
694
0
    {
695
0
      lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_POLICY_VIOLATION,
696
0
                  subject);
697
0
      return FALSE;
698
0
    }
699
0
    if (anchor)
700
0
    {
701
0
      if (!check_policy_constraints((x509_t*)issuer, pathlen, auth))
702
0
      {
703
0
        lib->credmgr->call_hook(lib->credmgr,
704
0
                    CRED_HOOK_POLICY_VIOLATION, issuer);
705
0
        return FALSE;
706
0
      }
707
0
    }
708
0
  }
709
0
  return TRUE;
710
0
}
711
712
METHOD(constraints_validator_t, destroy, void,
713
  private_constraints_validator_t *this)
714
0
{
715
0
  free(this);
716
0
}
717
718
/**
719
 * See header
720
 */
721
constraints_validator_t *constraints_validator_create()
722
0
{
723
0
  private_constraints_validator_t *this;
724
725
0
  INIT(this,
726
0
    .public = {
727
0
      .validator.validate = _validate,
728
0
      .destroy = _destroy,
729
0
    },
730
0
  );
731
732
0
  return &this->public;
733
0
}