1/*
2 * Copyright (c) 2008-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * SecPolicyServer.c - Trust policies dealing with certificate revocation.
26 */
27
28#include <securityd/SecPolicyServer.h>
29#include <Security/SecPolicyInternal.h>
30#include <Security/SecPolicyPriv.h>
31#include <utilities/SecIOFormat.h>
32#include <securityd/asynchttp.h>
33#include <securityd/policytree.h>
34#include <CoreFoundation/CFTimeZone.h>
35#include <wctype.h>
36#include <libDER/oids.h>
37#include <CoreFoundation/CFNumber.h>
38#include <Security/SecCertificateInternal.h>
39#include <AssertMacros.h>
40#include <utilities/debugging.h>
41#include <security_asn1/SecAsn1Coder.h>
42#include <security_asn1/ocspTemplates.h>
43#include <security_asn1/oidsalg.h>
44#include <security_asn1/oidsocsp.h>
45#include <CommonCrypto/CommonDigest.h>
46#include <Security/SecFramework.h>
47#include <Security/SecPolicyInternal.h>
48#include <Security/SecTrustPriv.h>
49#include <Security/SecInternal.h>
50#include <CFNetwork/CFHTTPMessage.h>
51#include <CFNetwork/CFHTTPStream.h>
52#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
53#include <asl.h>
54#include <securityd/SecOCSPRequest.h>
55#include <securityd/SecOCSPResponse.h>
56#include <securityd/asynchttp.h>
57#include <securityd/SecTrustServer.h>
58#include <securityd/SecOCSPCache.h>
59#include <utilities/array_size.h>
60#include <utilities/SecCFWrappers.h>
61#include "OTATrustUtilities.h"
62
63#define ocspdErrorLog(args...)     asl_log(NULL, NULL, ASL_LEVEL_ERR, ## args)
64
65/* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */
66#ifndef DUMP_OCSPRESPONSES
67#define DUMP_OCSPRESPONSES  0
68#endif
69
70#if DUMP_OCSPRESPONSES
71
72#include <unistd.h>
73#include <fcntl.h>
74
75static void secdumpdata(CFDataRef data, const char *name) {
76    int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0666);
77    write(fd, CFDataGetBytePtr(data), CFDataGetLength(data));
78    close(fd);
79}
80
81#endif
82
83
84/********************************************************
85 ****************** SecPolicy object ********************
86 ********************************************************/
87
88static CFMutableDictionaryRef gSecPolicyLeafCallbacks = NULL;
89static CFMutableDictionaryRef gSecPolicyPathCallbacks = NULL;
90
91static CFArrayRef SecPolicyAnchorDigestsForEVPolicy(const DERItem *policyOID)
92{
93	CFArrayRef result = NULL;
94	SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
95	if (NULL == otapkiRef)
96	{
97		return result;
98	}
99
100	CFDictionaryRef evToPolicyAnchorDigest = SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef);
101	CFRelease(otapkiRef);
102
103    if (NULL == evToPolicyAnchorDigest)
104    {
105        return result;
106    }
107
108    CFArrayRef roots = NULL;
109    CFStringRef oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, policyOID);
110    if (oid && evToPolicyAnchorDigest)
111	{
112        result = (CFArrayRef)CFDictionaryGetValue(evToPolicyAnchorDigest, oid);
113		if (roots && CFGetTypeID(result) != CFArrayGetTypeID())
114		{
115            ocspdErrorLog("EVRoot.plist has non array value");
116            result = NULL;
117        }
118        CFRelease(oid);
119    }
120    CFReleaseSafe(evToPolicyAnchorDigest);
121    return result;
122}
123
124
125static bool SecPolicyIsEVPolicy(const DERItem *policyOID) {
126    return SecPolicyAnchorDigestsForEVPolicy(policyOID);
127}
128
129static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate,
130    policy_set_t valid_policies) {
131    /* Ensure that this certificate is a valid anchor for one of the
132       certificate policy oids specified in the leaf. */
133    CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
134    policy_set_t ix;
135    bool good_ev_anchor = false;
136    for (ix = valid_policies; ix; ix = ix->oid_next) {
137        CFArrayRef digests = SecPolicyAnchorDigestsForEVPolicy(&ix->oid);
138        if (digests && CFArrayContainsValue(digests,
139            CFRangeMake(0, CFArrayGetCount(digests)), digest)) {
140            secdebug("ev", "found anchor for policy oid");
141            good_ev_anchor = true;
142            break;
143        }
144    }
145    require_quiet(good_ev_anchor, notEV);
146
147    CFAbsoluteTime october2006 = 178761600;
148    if (SecCertificateVersion(certificate) >= 3
149        && SecCertificateNotValidBefore(certificate) >= october2006) {
150        const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
151        require_quiet(bc && bc->isCA == true, notEV);
152        SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
153        require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
154            == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV);
155    }
156
157    CFAbsoluteTime jan2011 = 315532800;
158    if (SecCertificateNotValidBefore(certificate) < jan2011) {
159        /* At least MD5, SHA-1 with RSA 2048 or ECC NIST P-256. */
160    } else {
161        /* At least SHA-1, SHA-256, SHA-384 or SHA-512 with RSA 2048 or
162           ECC NIST P-256. */
163    }
164
165    return true;
166notEV:
167    return false;
168}
169
170static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate) {
171    const SecCECertificatePolicies *cp;
172    cp = SecCertificateGetCertificatePolicies(certificate);
173    require_quiet(cp && cp->numPolicies > 0, notEV);
174    /* SecCertificateGetCRLDistributionPoints() is a noop right now */
175#if 0
176    CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate);
177    require_quiet(cdp && CFArrayGetCount(cdp) > 0, notEV);
178#endif
179    const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
180    require_quiet(bc && bc->isCA == true, notEV);
181    SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
182    require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign))
183        == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV);
184    CFAbsoluteTime jan2011 = 315532800;
185    if (SecCertificateNotValidBefore(certificate) < jan2011) {
186        /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
187    } else {
188        /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
189           ECC NIST P-256. */
190    }
191
192    return true;
193notEV:
194    return false;
195}
196
197bool SecPolicySubscriberCertificateCouldBeEV(SecCertificateRef certificate) {
198    /* 3. Subscriber Certificate. */
199
200    /* (a) certificate Policies */
201    const SecCECertificatePolicies *cp;
202    cp = SecCertificateGetCertificatePolicies(certificate);
203    require_quiet(cp && cp->numPolicies > 0, notEV);
204    /* Now find at least one policy in here that has a qualifierID of id-qt 2
205       and a policyQualifier that is a URI to the CPS and an EV policy OID. */
206    uint32_t ix = 0;
207    bool found_ev_anchor_for_leaf_policy = false;
208    for (ix = 0; ix < cp->numPolicies; ++ix) {
209        if (SecPolicyIsEVPolicy(&cp->policies[ix].policyIdentifier)) {
210            found_ev_anchor_for_leaf_policy = true;
211        }
212    }
213    require_quiet(found_ev_anchor_for_leaf_policy, notEV);
214
215    /* SecCertificateGetCRLDistributionPoints() is a noop right now */
216#if 0
217    /* (b) cRLDistributionPoint
218       (c) authorityInformationAccess */
219    CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate);
220    if (cdp) {
221        require_quiet(CFArrayGetCount(cdp) > 0, notEV);
222    } else {
223        CFArrayRef or = SecCertificateGetOCSPResponders(certificate);
224        require_quiet(or && CFArrayGetCount(or) > 0, notEV);
225        //CFArrayRef ci = SecCertificateGetCAIssuers(certificate);
226    }
227#endif
228
229    /* (d) basicConstraints
230       If present, the cA field MUST be set false. */
231    const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
232    if (bc) {
233        require_quiet(bc->isCA == false, notEV);
234    }
235
236    /* (e) keyUsage. */
237    SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
238    if (ku) {
239        require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) == 0, notEV);
240    }
241
242#if 0
243    /* The EV Cert Spec errata specifies this, though this is a check for SSL
244       not specifically EV. */
245
246    /* (e) extKeyUsage
247
248Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */
249    SecCertificateCopyExtendedKeyUsage(certificate);
250#endif
251
252    CFAbsoluteTime jan2011 = 315532800;
253    if (SecCertificateNotValidAfter(certificate) < jan2011) {
254        /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */
255    } else {
256        /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or
257           ECC NIST P-256. */
258    }
259
260    return true;
261notEV:
262    return false;
263}
264
265/********************************************************
266 **************** SecPolicy Callbacks *******************
267 ********************************************************/
268static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc,
269	CFStringRef key) {
270}
271
272static void SecPolicyCheckIdLinkage(SecPVCRef pvc,
273	CFStringRef key) {
274	CFIndex ix, count = SecPVCGetCertificateCount(pvc);
275	CFDataRef parentSubjectKeyID = NULL;
276	for (ix = count - 1; ix >= 0; --ix) {
277		SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
278		/* If the previous certificate in the chain had a SubjectKeyID,
279		   make sure it matches the current certificates AuthorityKeyID. */
280		if (parentSubjectKeyID) {
281			/* @@@ According to RFC 2459 neither AuthorityKeyID nor
282			   SubjectKeyID can be critical.  Currenty we don't check
283			   for this. */
284			CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(cert);
285			if (authorityKeyID) {
286				if (!CFEqual(parentSubjectKeyID, authorityKeyID)) {
287					/* AuthorityKeyID doesn't match issuers SubjectKeyID. */
288					if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
289						return;
290				}
291			}
292		}
293
294		parentSubjectKeyID = SecCertificateGetSubjectKeyID(cert);
295	}
296}
297
298static bool keyusage_allows(SecKeyUsage keyUsage, CFTypeRef xku) {
299    if (!xku || CFGetTypeID(xku) != CFNumberGetTypeID())
300        return false;
301
302    SInt32 dku;
303    CFNumberGetValue((CFNumberRef)xku, kCFNumberSInt32Type, &dku);
304    SecKeyUsage ku = (SecKeyUsage)dku;
305    return (keyUsage & ku) == ku;
306}
307
308static void SecPolicyCheckKeyUsage(SecPVCRef pvc,
309	CFStringRef key) {
310    SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
311    SecKeyUsage keyUsage = SecCertificateGetKeyUsage(leaf);
312    bool match = false;
313    SecPolicyRef policy = SecPVCGetPolicy(pvc);
314    CFTypeRef xku = CFDictionaryGetValue(policy->_options, key);
315    if (isArray(xku)) {
316        CFIndex ix, count = CFArrayGetCount(xku);
317        for (ix = 0; ix < count; ++ix) {
318            CFTypeRef ku = CFArrayGetValueAtIndex(xku, ix);
319            if (keyusage_allows(keyUsage, ku)) {
320                match = true;
321                break;
322            }
323        }
324    } else {
325        match = keyusage_allows(keyUsage, xku);
326    }
327    if (!match) {
328        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
329    }
330}
331
332static bool extendedkeyusage_allows(CFArrayRef extendedKeyUsage,
333                                    CFTypeRef xeku) {
334    if (!xeku || CFGetTypeID(xeku) != CFDataGetTypeID())
335        return false;
336    if (extendedKeyUsage) {
337        CFRange all = { 0, CFArrayGetCount(extendedKeyUsage) };
338        return CFArrayContainsValue(extendedKeyUsage, all, xeku);
339    } else {
340        /* Certificate has no extended key usage, only a match if the policy
341           contains a 0 length CFDataRef. */
342        return CFDataGetLength((CFDataRef)xeku) == 0;
343    }
344}
345
346/* AUDIT[securityd](done):
347   policy->_options is a caller provided dictionary, only its cf type has
348   been checked.
349 */
350static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc, CFStringRef key) {
351    SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
352    CFArrayRef leafExtendedKeyUsage = SecCertificateCopyExtendedKeyUsage(leaf);
353    bool match = false;
354    SecPolicyRef policy = SecPVCGetPolicy(pvc);
355    CFTypeRef xeku = CFDictionaryGetValue(policy->_options, key);
356    if (isArray(xeku)) {
357        CFIndex ix, count = CFArrayGetCount(xeku);
358        for (ix = 0; ix < count; ix++) {
359            CFTypeRef eku = CFArrayGetValueAtIndex(xeku, ix);
360            if (extendedkeyusage_allows(leafExtendedKeyUsage, eku)) {
361                match = true;
362                break;
363            }
364        }
365    } else {
366        match = extendedkeyusage_allows(leafExtendedKeyUsage, xeku);
367    }
368    CFReleaseSafe(leafExtendedKeyUsage);
369    if (!match) {
370        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
371    }
372}
373
374#if 0
375static void SecPolicyCheckBasicContraintsCommon(SecPVCRef pvc,
376	CFStringRef key, bool strict) {
377	CFIndex ix, count = SecPVCGetCertificateCount(pvc);
378	for (ix = 0; ix < count; ++ix) {
379		SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
380		const SecCEBasicConstraints *bc =
381			SecCertificateGetBasicConstraints(cert);
382		if (bc) {
383			if (strict) {
384				if (ix == 0) {
385					/* Leaf certificate has basic constraints extension. */
386					if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
387						return;
388				} else if (!bc->critical) {
389					/* Basic constraints extension is not marked critical. */
390					if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
391						return;
392				}
393			}
394
395			if (ix > 0 || count == 1) {
396				if (!bc->isCA) {
397					/* Non leaf certificate marked as isCA false. */
398					if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
399						return;
400				}
401
402				if (bc->pathLenConstraintPresent) {
403					if (bc->pathLenConstraint < (uint32_t)(ix - 1)) {
404#if 0
405						/* @@@ If a self signed certificate is issued by
406						   another cert that is trusted, then we are supposed
407						   to treat the self signed cert itself as the anchor
408						   for path length purposes. */
409						CFIndex ssix = SecCertificatePathSelfSignedIndex(path);
410						if (ssix >= 0 && ix >= ssix) {
411							/* It's ok if the pathLenConstraint isn't met for
412							   certificates signing a self signed cert in the
413							   chain. */
414						} else
415#endif
416						{
417							/* Path Length Constraint Exceeded. */
418							if (!SecPVCSetResult(pvc, key, ix,
419								kCFBooleanFalse))
420								return;
421						}
422					}
423				}
424			}
425		} else if (strict && ix > 0) {
426			/* In strict mode all CA certificates *MUST* have a critical
427			   basic constraints extension and the leaf certificate
428			   *MUST NOT* have a basic constraints extension. */
429			/* CA certificate is missing basicConstraints extension. */
430			if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
431				return;
432		}
433	}
434}
435#endif
436
437static void SecPolicyCheckBasicContraints(SecPVCRef pvc,
438	CFStringRef key) {
439	//SecPolicyCheckBasicContraintsCommon(pvc, key, false);
440}
441
442static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc,
443	CFStringRef key) {
444	CFIndex ix, count = SecPVCGetCertificateCount(pvc);
445	for (ix = 0; ix < count; ++ix) {
446		SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
447		/* If the certificate has a subject, or
448		   if it doesn't, and it's the leaf and not self signed,
449		   and also has a critical subjectAltName extension it's valid. */
450		if (!SecCertificateHasSubject(cert)) {
451			if (ix == 0 && count > 1) {
452				if (!SecCertificateHasCriticalSubjectAltName(cert)) {
453					/* Leaf certificate with empty subject does not have
454					   a critical subject alt name extension. */
455					if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
456						return;
457				}
458			} else {
459				/* CA certificate has empty subject. */
460				if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
461					return;
462			}
463		}
464	}
465}
466
467static void SecPolicyCheckQualifiedCertStatements(SecPVCRef pvc,
468	CFStringRef key) {
469}
470
471/* Compare hostname suffix to domain name.
472   This function does not process wildcards, and allows hostname to match
473   any subdomain level of the provided domain.
474
475   To match, the last domain length chars of hostname must equal domain,
476   and the character immediately preceding domain in hostname (if any)
477   must be a dot. This means that domain 'bar.com' will match hostname
478   values 'host.bar.com' or 'host.sub.bar.com', but not 'host.foobar.com'.
479
480   Characters in each string are converted to lowercase for the comparison.
481   Trailing '.' characters in both names will be ignored.
482
483   Returns true on match, else false.
484 */
485static bool SecDomainSuffixMatch(CFStringRef hostname, CFStringRef domain) {
486	CFStringInlineBuffer hbuf, dbuf;
487	UniChar hch, dch;
488	CFIndex hix, dix,
489		hlength = CFStringGetLength(hostname),
490		dlength = CFStringGetLength(domain);
491	CFRange hrange = { 0, hlength }, drange = { 0, dlength };
492	CFStringInitInlineBuffer(hostname, &hbuf, hrange);
493	CFStringInitInlineBuffer(domain, &dbuf, drange);
494
495	if((hlength == 0) || (dlength == 0)) {
496		/* trivial case with at least one empty name */
497		return (hlength == dlength) ? true : false;
498	}
499
500	/* trim off trailing dots */
501	hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hlength-1);
502	dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dlength-1);
503	if(hch == '.') {
504		hrange.length = --hlength;
505	}
506	if(dch == '.') {
507		drange.length = --dlength;
508	}
509
510	/* trim off leading dot in suffix, if present */
511	dch = CFStringGetCharacterFromInlineBuffer(&dbuf, 0);
512	if((dlength > 0) && (dch == '.')) {
513		drange.location++;
514		drange.length = --dlength;
515	}
516
517	if(hlength < dlength) {
518		return false;
519	}
520
521	/* perform case-insensitive comparison of domain suffix */
522	for (hix = (hlength-dlength),
523		 dix = drange.location; dix < drange.length; dix++) {
524		hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix);
525		dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dix);
526		if (towlower(hch) != towlower(dch)) {
527			return false;
528		}
529	}
530
531	/* require a dot prior to domain suffix, unless hostname == domain */
532	if(hlength > dlength) {
533		hch = CFStringGetCharacterFromInlineBuffer(&hbuf, (hlength-(dlength+1)));
534		if(hch != '.') {
535			return false;
536		}
537	}
538
539	return true;
540}
541
542/* Compare hostname, to a server name obtained from the server's cert
543   Obtained from the SubjectAltName or the CommonName entry in the Subject.
544   Limited wildcard checking is performed here as outlined in
545
546   RFC 2818 Section 3.1.  Server Identity
547
548   [...] Names may contain the wildcard
549   character * which is considered to match any single domain name
550   component or component fragment. E.g., *.a.com matches foo.a.com but
551   not bar.foo.a.com. f*.com matches foo.com but not bar.com.
552   [...]
553
554   Trailing '.' characters in the hostname will be ignored.
555
556   Returns true on match, else false.
557 */
558static bool SecDNSMatch(CFStringRef hostname, CFStringRef servername) {
559	CFStringInlineBuffer hbuf, sbuf;
560	CFIndex hix, six,
561		hlength = CFStringGetLength(hostname),
562		slength = CFStringGetLength(servername);
563	CFRange hrange = { 0, hlength }, srange = { 0, slength };
564	CFStringInitInlineBuffer(hostname, &hbuf, hrange);
565	CFStringInitInlineBuffer(servername, &sbuf, srange);
566
567	for (hix = six = 0; six < slength; ++six) {
568		UniChar hch, sch = CFStringGetCharacterFromInlineBuffer(&sbuf, six);
569		if (sch == '*') {
570			if (six + 1 >= slength) {
571				/* Trailing '*' in servername, match until end of hostname or
572				   trailing '.'.  */
573				do {
574					if (hix >= hlength) {
575						/* If we reach the end of the hostname we have a
576						   match. */
577						return true;
578					}
579					hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
580				} while (hch != '.');
581				/* We reached the end of servername and found a '.' in
582				   hostname.  Return true if hostname has a single
583				   trailing '.' return false if there is anything after it. */
584				return hix == hlength;
585			}
586
587			/* Grab the character after the '*'. */
588			sch = CFStringGetCharacterFromInlineBuffer(&sbuf, ++six);
589			if (sch != '.') {
590				/* We have something of the form '*foo.com'.  Or '**.com'
591				   We don't deal with that yet, since it might require
592				   backtracking. Also RFC 2818 doesn't seem to require it. */
593				return false;
594			}
595
596			/* We're looking at the '.' after the '*' in something of the
597			   form 'foo*.com' or '*.com'. Match until next '.' in hostname. */
598			do {
599				/* Since we're not at the end of servername yet (that case
600				   was handled above), running out of chars in hostname
601				   means we don't have a match. */
602				if (hix >= hlength)
603					return false;
604				hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
605			} while (hch != '.');
606		} else {
607			/* We're looking at a non wildcard character in the servername.
608			   If we reached the end of hostname it's not a match. */
609			if (hix >= hlength)
610				return false;
611
612			/* Otherwise make sure the hostname matches the character in the
613			   servername, case insensitively. */
614			hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++);
615			if (towlower(hch) != towlower(sch))
616				return false;
617		}
618	}
619
620	if (hix < hlength) {
621		/* We reached the end of servername but we have one or more characters
622		   left to compare against in the hostname. */
623		if (hix + 1 == hlength &&
624			CFStringGetCharacterFromInlineBuffer(&hbuf, hix) == '.') {
625			/* Hostname has a single trailing '.', we're ok with that. */
626			return true;
627		}
628		/* Anything else is not a match. */
629		return false;
630	}
631
632	return true;
633}
634
635#define kSecPolicySHA1Size 20
636static const UInt8 kAppleCorpCASHA1[kSecPolicySHA1Size] = {
637    0xA1, 0x71, 0xDC, 0xDE, 0xE0, 0x8B, 0x1B, 0xAE, 0x30, 0xA1,
638    0xAE, 0x6C, 0xC6, 0xD4, 0x03, 0x3B, 0xFD, 0xEF, 0x91, 0xCE
639};
640
641/* Check whether hostname is in a particular set of allowed domains.
642   Returns true if OK, false if not allowed.
643 */
644static bool SecPolicyCheckDomain(SecPVCRef pvc, CFStringRef hostname)
645{
646	CFIndex count = SecPVCGetCertificateCount(pvc);
647	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
648	CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert);
649
650	/* is this chain anchored by kAppleCorpCASHA1? */
651	CFDataRef corpSHA1 = CFDataCreateWithBytesNoCopy(NULL,
652	    kAppleCorpCASHA1, kSecPolicySHA1Size, kCFAllocatorNull);
653	bool isCorpSHA1 = (corpSHA1 && CFEqual(anchorSHA1, corpSHA1));
654	CFReleaseSafe(corpSHA1);
655	if (isCorpSHA1) {
656		/* limit hostname to specified domains */
657		const CFStringRef dnlist[] = {
658		    CFSTR("apple.com"),
659			CFSTR("icloud.com"),
660		};
661		unsigned int idx, dncount=2;
662		for (idx = 0; idx < dncount; idx++) {
663			if (SecDomainSuffixMatch(hostname, dnlist[idx])) {
664				return true;
665			}
666		}
667		return false;
668	}
669	/* %%% other CA pinning checks TBA */
670
671	return true;
672}
673
674/* AUDIT[securityd](done):
675   policy->_options is a caller provided dictionary, only its cf type has
676   been checked.
677 */
678static void SecPolicyCheckSSLHostname(SecPVCRef pvc,
679	CFStringRef key) {
680	/* @@@ Consider what to do if the caller passes in no hostname.  Should
681	   we then still fail if the leaf has no dnsNames or IPAddresses at all? */
682	SecPolicyRef policy = SecPVCGetPolicy(pvc);
683	CFStringRef hostName = (CFStringRef)
684		CFDictionaryGetValue(policy->_options, key);
685    if (!isString(hostName)) {
686        /* @@@ We can't return an error here and making the evaluation fail
687           won't help much either. */
688        return;
689    }
690
691	SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
692	bool dnsMatch = false;
693	CFArrayRef dnsNames = SecCertificateCopyDNSNames(leaf);
694	if (dnsNames) {
695		CFIndex ix, count = CFArrayGetCount(dnsNames);
696		for (ix = 0; ix < count; ++ix) {
697			CFStringRef dns = (CFStringRef)CFArrayGetValueAtIndex(dnsNames, ix);
698			if (SecDNSMatch(hostName, dns)) {
699				dnsMatch = true;
700				break;
701			}
702		}
703		CFRelease(dnsNames);
704	}
705
706    if (!dnsMatch) {
707        /* Maybe hostname is an IPv4 or IPv6 address, let's compare against
708           the values returned by SecCertificateCopyIPAddresses() instead. */
709        CFArrayRef ipAddresses = SecCertificateCopyIPAddresses(leaf);
710        if (ipAddresses) {
711            CFIndex ix, count = CFArrayGetCount(ipAddresses);
712            for (ix = 0; ix < count; ++ix) {
713                CFStringRef ipAddress = (CFStringRef)CFArrayGetValueAtIndex(ipAddresses, ix);
714                if (!CFStringCompare(hostName, ipAddress, kCFCompareCaseInsensitive)) {
715                    dnsMatch = true;
716                    break;
717                }
718            }
719            CFRelease(ipAddresses);
720        }
721    }
722
723	if (!dnsMatch) {
724		/* Hostname mismatch or no hostnames found in certificate. */
725		SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
726	}
727	else if (!SecPolicyCheckDomain(pvc, hostName)) {
728		/* Hostname match, but domain not allowed for this CA */
729		SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
730	}
731
732    if ((dnsMatch || pvc->details)
733        && SecPolicySubscriberCertificateCouldBeEV(leaf)) {
734        secdebug("policy", "enabling optionally_ev");
735        pvc->optionally_ev = true;
736        /* optionally_ev => check_revocation, so we don't enable revocation
737           checking here, since we don't want it on for non EV ssl certs.  */
738#if 0
739        /* Check revocation status if the certificate asks for it (and we
740           support it) currently we only support ocsp. */
741        CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(leaf);
742        if (ocspResponders) {
743            SecPVCSetCheckRevocation(pvc);
744        }
745#endif
746    }
747}
748
749/* AUDIT[securityd](done):
750 policy->_options is a caller provided dictionary, only its cf type has
751 been checked.
752 */
753static void SecPolicyCheckEmail(SecPVCRef pvc, CFStringRef key) {
754	SecPolicyRef policy = SecPVCGetPolicy(pvc);
755	CFStringRef email = (CFStringRef)CFDictionaryGetValue(policy->_options, key);
756	bool match = false;
757    if (!isString(email)) {
758        /* We can't return an error here and making the evaluation fail
759         won't help much either. */
760        return;
761    }
762
763	SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
764	CFArrayRef addrs = SecCertificateCopyRFC822Names(leaf);
765	if (addrs) {
766		CFIndex ix, count = CFArrayGetCount(addrs);
767		for (ix = 0; ix < count; ++ix) {
768			CFStringRef addr = (CFStringRef)CFArrayGetValueAtIndex(addrs, ix);
769			if (!CFStringCompare(email, addr, kCFCompareCaseInsensitive)) {
770				match = true;
771				break;
772			}
773		}
774		CFRelease(addrs);
775	}
776
777	if (!match) {
778		/* Hostname mismatch or no hostnames found in certificate. */
779		SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
780    }
781}
782
783static void SecPolicyCheckValidIntermediates(SecPVCRef pvc,
784	CFStringRef key) {
785	CFIndex ix, count = SecPVCGetCertificateCount(pvc);
786	CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
787	for (ix = 1; ix < count - 1; ++ix) {
788		SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
789		if (!SecCertificateIsValid(cert, verifyTime)) {
790			/* Intermediate certificate has expired. */
791			if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
792				return;
793		}
794	}
795}
796
797static void SecPolicyCheckValidLeaf(SecPVCRef pvc,
798	CFStringRef key) {
799	CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
800	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
801	if (!SecCertificateIsValid(cert, verifyTime)) {
802		/* Leaf certificate has expired. */
803		if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
804			return;
805	}
806}
807
808static void SecPolicyCheckValidRoot(SecPVCRef pvc,
809	CFStringRef key) {
810	CFIndex ix, count = SecPVCGetCertificateCount(pvc);
811	CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
812	ix = count - 1;
813	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
814	if (!SecCertificateIsValid(cert, verifyTime)) {
815		/* Root certificate has expired. */
816		if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse))
817			return;
818	}
819}
820
821/* AUDIT[securityd](done):
822   policy->_options is a caller provided dictionary, only its cf type has
823   been checked.
824 */
825static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc,
826	CFStringRef key) {
827    CFIndex count = SecPVCGetCertificateCount(pvc);
828    if (count < 2) {
829		/* Can't check intermediates common name if there is no intermediate. */
830		SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
831        return;
832    }
833
834	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 1);
835	SecPolicyRef policy = SecPVCGetPolicy(pvc);
836    CFStringRef commonName =
837        (CFStringRef)CFDictionaryGetValue(policy->_options, key);
838    if (!isString(commonName)) {
839        /* @@@ We can't return an error here and making the evaluation fail
840           won't help much either. */
841        return;
842    }
843    CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
844    if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
845        !CFEqual(commonName, CFArrayGetValueAtIndex(commonNames, 0))) {
846		/* Common Name mismatch. */
847		SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
848	}
849    CFReleaseSafe(commonNames);
850}
851
852/* AUDIT[securityd](done):
853   policy->_options is a caller provided dictionary, only its cf type has
854   been checked.
855 */
856static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc,
857	CFStringRef key) {
858	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
859	SecPolicyRef policy = SecPVCGetPolicy(pvc);
860	CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options,
861		key);
862    if (!isString(common_name)) {
863        /* @@@ We can't return an error here and making the evaluation fail
864           won't help much either. */
865        return;
866    }
867	CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
868	if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
869		!CFEqual(common_name, CFArrayGetValueAtIndex(commonNames, 0))) {
870		/* Common Name mismatch. */
871		SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
872	}
873	CFReleaseSafe(commonNames);
874}
875
876/* AUDIT[securityd](done):
877   policy->_options is a caller provided dictionary, only its cf type has
878   been checked.
879 */
880static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc,
881	CFStringRef key) {
882	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
883	SecPolicyRef policy = SecPVCGetPolicy(pvc);
884    CFStringRef prefix = (CFStringRef)CFDictionaryGetValue(policy->_options,
885		key);
886    if (!isString(prefix)) {
887        /* @@@ We can't return an error here and making the evaluation fail
888           won't help much either. */
889        return;
890    }
891    CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
892    if (!commonNames || CFArrayGetCount(commonNames) != 1 ||
893        !CFStringHasPrefix(CFArrayGetValueAtIndex(commonNames, 0), prefix)) {
894		/* Common Name prefix mismatch. */
895		SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
896	}
897    CFReleaseSafe(commonNames);
898}
899
900/* AUDIT[securityd](done):
901   policy->_options is a caller provided dictionary, only its cf type has
902   been checked.
903 */
904static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc,
905	CFStringRef key) {
906	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
907	SecPolicyRef policy = SecPVCGetPolicy(pvc);
908	CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options,
909		key);
910    if (!isString(common_name)) {
911        /* @@@ We can't return an error here and making the evaluation fail
912           won't help much either. */
913        return;
914    }
915	CFArrayRef commonNames = SecCertificateCopyCommonNames(cert);
916	if (!commonNames || CFArrayGetCount(commonNames) != 1) {
917        CFStringRef cert_common_name = CFArrayGetValueAtIndex(commonNames, 0);
918        CFStringRef test_common_name = common_name ?
919            CFStringCreateWithFormat(kCFAllocatorDefault,
920                NULL, CFSTR("TEST %@ TEST"), common_name) :
921            NULL;
922		if (!CFEqual(common_name, cert_common_name) &&
923            (!test_common_name || !CFEqual(test_common_name, cert_common_name)))
924                /* Common Name mismatch. */
925                SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
926        CFReleaseSafe(test_common_name);
927	}
928	CFReleaseSafe(commonNames);
929}
930
931/* AUDIT[securityd](done):
932   policy->_options is a caller provided dictionary, only its cf type has
933   been checked.
934 */
935static void SecPolicyCheckNotValidBefore(SecPVCRef pvc,
936	CFStringRef key) {
937	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
938	SecPolicyRef policy = SecPVCGetPolicy(pvc);
939    CFDateRef date = (CFDateRef)CFDictionaryGetValue(policy->_options, key);
940    if (!isDate(date)) {
941        /* @@@ We can't return an error here and making the evaluation fail
942           won't help much either. */
943        return;
944    }
945	CFAbsoluteTime at = CFDateGetAbsoluteTime(date);
946	if (SecCertificateNotValidBefore(cert) <= at) {
947		/* Leaf certificate has not valid before that is too old. */
948		if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
949			return;
950	}
951}
952
953/* AUDIT[securityd](done):
954   policy->_options is a caller provided dictionary, only its cf type has
955   been checked.
956 */
957static void SecPolicyCheckChainLength(SecPVCRef pvc,
958	CFStringRef key) {
959	CFIndex count = SecPVCGetCertificateCount(pvc);
960	SecPolicyRef policy = SecPVCGetPolicy(pvc);
961    CFNumberRef chainLength =
962        (CFNumberRef)CFDictionaryGetValue(policy->_options, key);
963    CFIndex value;
964    if (!chainLength || CFGetTypeID(chainLength) != CFNumberGetTypeID() ||
965        !CFNumberGetValue(chainLength, kCFNumberCFIndexType, &value)) {
966        /* @@@ We can't return an error here and making the evaluation fail
967           won't help much either. */
968        return;
969    }
970    if (value != count) {
971		/* Chain length doesn't match policy requirement. */
972		if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse))
973			return;
974    }
975}
976
977/* AUDIT[securityd](done):
978   policy->_options is a caller provided dictionary, only its cf type has
979   been checked.
980 */
981static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc,
982	CFStringRef key) {
983    CFIndex count = SecPVCGetCertificateCount(pvc);
984	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
985	SecPolicyRef policy = SecPVCGetPolicy(pvc);
986    CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
987    CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert);
988
989    bool foundMatch = false;
990
991    if (isData(value))
992        foundMatch = CFEqual(anchorSHA1, value);
993    else if (isArray(value))
994        foundMatch = CFArrayContainsValue((CFArrayRef) value, CFRangeMake(0, CFArrayGetCount((CFArrayRef) value)), anchorSHA1);
995    else {
996        /* @@@ We only support Data and Array but we can't return an error here so.
997               we let the evaluation fail (not much help) and assert in debug. */
998        assert(false);
999    }
1000
1001    if (!foundMatch)
1002        if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA1, 0, kCFBooleanFalse))
1003            return;
1004
1005    return;
1006}
1007
1008/* AUDIT[securityd](done):
1009   policy->_options is a caller provided dictionary, only its cf type has
1010   been checked.
1011 */
1012static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc,
1013	CFStringRef key) {
1014	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1015	SecPolicyRef policy = SecPVCGetPolicy(pvc);
1016	CFStringRef org = (CFStringRef)CFDictionaryGetValue(policy->_options,
1017		key);
1018    if (!isString(org)) {
1019        /* @@@ We can't return an error here and making the evaluation fail
1020           won't help much either. */
1021        return;
1022    }
1023	CFArrayRef organization = SecCertificateCopyOrganization(cert);
1024	if (!organization || CFArrayGetCount(organization) != 1 ||
1025		!CFEqual(org, CFArrayGetValueAtIndex(organization, 0))) {
1026		/* Leaf Subject Organization mismatch. */
1027		SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1028	}
1029	CFReleaseSafe(organization);
1030}
1031
1032static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc,
1033	CFStringRef key) {
1034	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1035	SecPolicyRef policy = SecPVCGetPolicy(pvc);
1036	CFStringRef orgUnit = (CFStringRef)CFDictionaryGetValue(policy->_options,
1037		key);
1038    if (!isString(orgUnit)) {
1039        /* @@@ We can't return an error here and making the evaluation fail
1040           won't help much either. */
1041        return;
1042    }
1043	CFArrayRef organizationalUnit = SecCertificateCopyOrganizationalUnit(cert);
1044	if (!organizationalUnit || CFArrayGetCount(organizationalUnit) != 1 ||
1045		!CFEqual(orgUnit, CFArrayGetValueAtIndex(organizationalUnit, 0))) {
1046		/* Leaf Subject Organizational Unit mismatch. */
1047		SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1048	}
1049	CFReleaseSafe(organizationalUnit);
1050}
1051
1052/* AUDIT[securityd](done):
1053   policy->_options is a caller provided dictionary, only its cf type has
1054   been checked.
1055 */
1056static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc,
1057	CFStringRef key) {
1058	SecPolicyRef policy = SecPVCGetPolicy(pvc);
1059	CFArrayRef trustedServerNames = (CFArrayRef)
1060		CFDictionaryGetValue(policy->_options, key);
1061    /* No names specified means we accept any name. */
1062    if (!trustedServerNames)
1063        return;
1064    if (!isArray(trustedServerNames)) {
1065        /* @@@ We can't return an error here and making the evaluation fail
1066           won't help much either. */
1067        return;
1068    }
1069
1070    CFIndex tsnCount = CFArrayGetCount(trustedServerNames);
1071	SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1072	bool dnsMatch = false;
1073	CFArrayRef dnsNames = SecCertificateCopyDNSNames(leaf);
1074	if (dnsNames) {
1075		CFIndex ix, count = CFArrayGetCount(dnsNames);
1076        // @@@ This is O(N^2) unfortunately we can't do better easily unless
1077        // we don't do wildcard matching. */
1078		for (ix = 0; !dnsMatch && ix < count; ++ix) {
1079			CFStringRef dns = (CFStringRef)CFArrayGetValueAtIndex(dnsNames, ix);
1080            CFIndex tix;
1081            for (tix = 0; tix < tsnCount; ++tix) {
1082                CFStringRef serverName =
1083                    (CFStringRef)CFArrayGetValueAtIndex(trustedServerNames, tix);
1084                if (!isString(serverName)) {
1085                    /* @@@ We can't return an error here and making the
1086                       evaluation fail won't help much either. */
1087                    CFReleaseSafe(dnsNames);
1088                    return;
1089                }
1090                /* we purposefully reverse the arguments here such that dns names
1091                   from the cert are matched against a server name list, where
1092                   the server names list can contain wildcards and the dns name
1093                   cannot.  References: http://support.microsoft.com/kb/941123
1094                   It's easy to find occurrences where people tried to use
1095                   wildcard certificates and were told that those don't work
1096                   in this context. */
1097                if (SecDNSMatch(dns, serverName)) {
1098                    dnsMatch = true;
1099                    break;
1100                }
1101            }
1102		}
1103		CFRelease(dnsNames);
1104	}
1105
1106	if (!dnsMatch) {
1107		/* Hostname mismatch or no hostnames found in certificate. */
1108		SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1109	}
1110}
1111
1112static const unsigned char UTN_USERFirst_Hardware_Serial[][16] = {
1113{ 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 },
1114{ 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 },
1115{ 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 },
1116{ 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 },
1117{ 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 },
1118{ 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 },
1119{ 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 },
1120{ 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e },
1121{ 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } };
1122
1123static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer[] = {
1124  0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
1125  0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02,
1126  0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
1127  0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43,
1128  0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
1129  0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
1130  0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31,
1131  0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54,
1132  0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45,
1133  0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f,
1134  0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
1135  0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48,
1136  0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45
1137};
1138static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len = 151;
1139
1140
1141static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc,
1142	CFStringRef key) {
1143	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1144    CFDataRef issuer = cert ? SecCertificateGetNormalizedIssuerContent(cert) : NULL;
1145
1146    if (issuer && (CFDataGetLength(issuer) == (CFIndex)UTN_USERFirst_Hardware_Normalized_Issuer_len) &&
1147        (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer, CFDataGetBytePtr(issuer),
1148            UTN_USERFirst_Hardware_Normalized_Issuer_len)))
1149    {
1150        CFDataRef serial = SecCertificateCopySerialNumber(cert);
1151        if (serial) {
1152            CFIndex serial_length = CFDataGetLength(serial);
1153            const uint8_t *serial_ptr = CFDataGetBytePtr(serial);
1154
1155            while ((serial_length > 0) && (*serial_ptr == 0)) {
1156                serial_ptr++;
1157                serial_length--;
1158            }
1159
1160            if (serial_length == (CFIndex)sizeof(*UTN_USERFirst_Hardware_Serial)) {
1161                unsigned int i;
1162                for (i = 0; i < array_size(UTN_USERFirst_Hardware_Serial); i++)
1163                {
1164                    if (0 == memcmp(UTN_USERFirst_Hardware_Serial[i],
1165                        serial_ptr, sizeof(*UTN_USERFirst_Hardware_Serial)))
1166                    {
1167                        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1168                        CFReleaseSafe(serial);
1169                        return;
1170                    }
1171                }
1172            }
1173            CFRelease(serial);
1174        }
1175    }
1176
1177	SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1178	if (NULL != otapkiRef)
1179	{
1180		CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
1181		CFRelease(otapkiRef);
1182		if (NULL != blackListedKeys)
1183		{
1184			/* Check for blacklisted intermediates keys. */
1185			CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
1186			if (dgst)
1187			{
1188				/* Check dgst against blacklist. */
1189				if (CFSetContainsValue(blackListedKeys, dgst))
1190				{
1191					SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1192				}
1193				CFRelease(dgst);
1194			}
1195			CFRelease(blackListedKeys);
1196		}
1197	}
1198}
1199
1200static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc, CFStringRef key)
1201{
1202	SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
1203	if (NULL != otapkiRef)
1204	{
1205		CFSetRef grayListedKeys = SecOTAPKICopyGrayList(otapkiRef);
1206		CFRelease(otapkiRef);
1207		if (NULL != grayListedKeys)
1208		{
1209			SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1210
1211			CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
1212			if (dgst)
1213			{
1214				/* Check dgst against gray. */
1215				if (CFSetContainsValue(grayListedKeys, dgst))
1216				{
1217					SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1218				}
1219				CFRelease(dgst);
1220			}
1221			CFRelease(grayListedKeys);
1222		}
1223	}
1224 }
1225
1226static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc, CFStringRef key)
1227{
1228	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0);
1229    SecPolicyRef policy = SecPVCGetPolicy(pvc);
1230    CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1231
1232    if (value && SecCertificateHasMarkerExtension(cert, value))
1233        return;
1234
1235    SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1236}
1237
1238static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc, CFStringRef key)
1239{
1240    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1241    SecPolicyRef policy = SecPVCGetPolicy(pvc);
1242    CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1243
1244    for (ix = 1; ix < count - 1; ix++) {
1245        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1246        if (SecCertificateHasMarkerExtension(cert, value))
1247            return;
1248    }
1249    SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1250}
1251
1252
1253
1254/****************************************************************************
1255 *********************** New rfc5280 Chain Validation ***********************
1256 ****************************************************************************/
1257
1258#if 0
1259typedef struct cert_path *cert_path_t;
1260struct cert_path {
1261    int length;
1262};
1263
1264typedef struct x500_name *x500_name_t;
1265struct x500_name {
1266};
1267
1268typedef struct algorithm_id *algorithm_id_t;
1269struct algorithm_id {
1270    oid_t algorithm_oid;
1271    der_t parameters;
1272};
1273
1274typedef struct trust_anchor *trust_anchor_t;
1275struct trust_anchor {
1276    x500_name_t issuer_name;
1277    algorithm_id_t public_key_algorithm; /* includes optional params */
1278    SecKeyRef public_key;
1279};
1280
1281typedef struct certificate_policy *certificate_policy_t;
1282struct certificate_policy {
1283    policy_qualifier_t qualifiers;
1284    oid_t oid;
1285    SLIST_ENTRY(certificate_policy) policies;
1286};
1287
1288typedef struct policy_mapping *policy_mapping_t;
1289struct policy_mapping {
1290    SLIST_ENTRY(policy_mapping) mappings;
1291    oid_t issuer_domain_policy;
1292    oid_t subject_domain_policy;
1293};
1294
1295typedef struct root_name *root_name_t;
1296struct root_name {
1297};
1298#endif
1299
1300struct policy_tree_add_ctx {
1301    oid_t p_oid;
1302    policy_qualifier_t p_q;
1303};
1304
1305/* For each node of depth i-1 in the valid_policy_tree where P-OID is in the expected_policy_set, create a child node as follows: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */
1306static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) {
1307    struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1308    policy_set_t policy_set;
1309    for (policy_set = node->expected_policy_set;
1310        policy_set;
1311        policy_set = policy_set->oid_next) {
1312        if (oid_equal(policy_set->oid, info->p_oid)) {
1313            policy_tree_add_child(node, &info->p_oid, info->p_q);
1314            return true;
1315        }
1316    }
1317    return false;
1318}
1319
1320/* If the valid_policy_tree includes a node of depth i-1 with the valid_policy anyPolicy, generate a child node with the following values: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */
1321static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) {
1322    struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
1323    if (oid_equal(node->valid_policy, oidAnyPolicy)) {
1324        policy_tree_add_child(node, &info->p_oid, info->p_q);
1325        return true;
1326    }
1327    return false;
1328}
1329
1330/* Return true iff node has a child with a valid_policy equal to oid. */
1331static bool policy_tree_has_child_with_oid(policy_tree_t node,
1332    const oid_t *oid) {
1333    policy_tree_t child;
1334    for (child = node->children; child; child = child->siblings) {
1335        if (oid_equal(child->valid_policy, (*oid))) {
1336            return true;
1337        }
1338    }
1339    return false;
1340}
1341
1342/* For each node in the valid_policy_tree of depth i-1, for each value in the expected_policy_set (including anyPolicy) that does not appear in a child node, create a child node with the following values: set the valid_policy to the value from the expected_policy_set in the parent node, set the qualifier_set to AP-Q, and set the expected_policy_set to the value in the valid_policy from this node. */
1343static bool policy_tree_add_expected(policy_tree_t node, void *ctx) {
1344    policy_qualifier_t p_q = (policy_qualifier_t)ctx;
1345    policy_set_t policy_set;
1346    bool added_node = false;
1347    for (policy_set = node->expected_policy_set;
1348        policy_set;
1349        policy_set = policy_set->oid_next) {
1350        if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) {
1351            policy_tree_add_child(node, &policy_set->oid, p_q);
1352            added_node = true;
1353        }
1354    }
1355    return added_node;
1356}
1357
1358#if 0
1359/* For each node where ID-P is the valid_policy, set expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */
1360static bool policy_tree_map(policy_tree_t node, void *ctx) {
1361    /* Can't map oidAnyPolicy. */
1362    if (oid_equal(node->valid_policy, oidAnyPolicy))
1363        return false;
1364
1365    const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1366    uint32_t mapping_ix, mapping_count = pm->numMappings;
1367    policy_set_t policy_set = NULL;
1368    /* First count how many mappings match this nodes valid_policy. */
1369    for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1370        const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1371        if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
1372            policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set));
1373            p_node->oid = mapping->subjectDomainPolicy;
1374            p_node->oid_next = policy_set ? policy_set : NULL;
1375            policy_set = p_node;
1376        }
1377    }
1378    if (policy_set) {
1379        policy_tree_set_expected_policy(node, policy_set);
1380        return true;
1381    }
1382    return false;
1383}
1384#endif
1385
1386#define POLICY_MAPPING 0
1387#define POLICY_SUBTREES 0
1388
1389/* rfc5280 basic cert processing. */
1390static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc,
1391	CFStringRef key) {
1392    /* Inputs */
1393    //cert_path_t path;
1394    CFIndex count = SecPVCGetCertificateCount(pvc);
1395    /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */
1396    assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
1397    uint32_t n = (uint32_t)count;
1398    bool is_anchored = SecPVCIsAnchored(pvc);
1399    if (is_anchored) {
1400        /* If the anchor is trusted we don't procces the last cert in the
1401           chain (root). */
1402        n--;
1403    } else {
1404        /* Add a detail for the root not being trusted. */
1405        if (SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted,
1406            n - 1, kCFBooleanFalse, true))
1407            return;
1408    }
1409
1410    CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc);
1411    //policy_set_t user_initial_policy_set = NULL;
1412    //trust_anchor_t anchor;
1413    bool initial_policy_mapping_inhibit = false;
1414    bool initial_explicit_policy = false;
1415    bool initial_any_policy_inhibit = false;
1416#if POLICY_SUBTREES
1417    root_name_t initial_permitted_subtrees = NULL;
1418    root_name_t initial_excluded_subtrees = NULL;
1419#endif
1420
1421    /* Initialization */
1422    pvc->valid_policy_tree = policy_tree_create(&oidAnyPolicy, NULL);
1423#if POLICY_SUBTREES
1424    root_name_t permitted_subtrees = initial_permitted_subtrees;
1425    root_name_t excluded_subtrees = initial_excluded_subtrees;
1426#endif
1427    uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1;
1428    uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1;
1429    uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1;
1430
1431#if 0
1432    /* Path builder ensures we only get cert chains with proper issuer
1433       chaining with valid signatures along the way. */
1434    algorithm_id_t working_public_key_algorithm = anchor->public_key_algorithm;
1435    SecKeyRef working_public_key = anchor->public_key;
1436    x500_name_t working_issuer_name = anchor->issuer_name;
1437#endif
1438    uint32_t i, max_path_length = n;
1439    SecCertificateRef cert = NULL;
1440    for (i = 1; i <= n; ++i) {
1441        /* Process Cert */
1442        cert = SecPVCGetCertificateAtIndex(pvc, n - i);
1443        bool is_self_issued = SecPVCIsCertificateAtIndexSelfSigned(pvc, n - i);
1444
1445        /* (a) Verify the basic certificate information. */
1446        /* @@@ Ensure that cert was signed with working_public_key_algorithm
1447           using the working_public_key and the working_public_key_parameters. */
1448#if 1
1449        /* Already done by chain builder. */
1450        if (!SecCertificateIsValid(cert, verify_time)) {
1451            CFStringRef fail_key = i == n ? kSecPolicyCheckValidLeaf : kSecPolicyCheckValidIntermediates;
1452            if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse))
1453                return;
1454        }
1455#endif
1456#if 0
1457        /* Check revocation status if the certificate asks for it. */
1458        CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
1459        if (ocspResponders) {
1460            SecPVCSetCheckRevocation(pvc);
1461        }
1462#endif
1463        /* @@@ cert.issuer == working_issuer_name. */
1464
1465#if POLICY_SUBTREES
1466        /* (b) (c) */
1467        if (!is_self_issued || i == n) {
1468            /* Verify that the subject name is within one of the permitted_subtrees for X.500 distinguished names, and verify that each of the alternative names in the subjectAltName extension (critical or non-critical) is within one of the permitted_subtrees for that name type. */
1469            /* Verify that the subject name is not within any of the excluded_subtrees for X.500 distinguished names, and verify that each of the alternative names in the subjectAltName extension (critical or non-critical) is not within any of the excluded_subtrees for that name type. */
1470        }
1471#endif
1472        /* (d) */
1473        if (pvc->valid_policy_tree) {
1474            const SecCECertificatePolicies *cp =
1475                SecCertificateGetCertificatePolicies(cert);
1476            size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1477            for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1478                const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1479                oid_t p_oid = policy->policyIdentifier;
1480                policy_qualifier_t p_q = &policy->policyQualifiers;
1481                struct policy_tree_add_ctx ctx = { p_oid, p_q };
1482                if (!oid_equal(p_oid, oidAnyPolicy)) {
1483                    if (!policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1484                        policy_tree_add_if_match, &ctx)) {
1485                        policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1486                        policy_tree_add_if_any, &ctx);
1487                    }
1488                }
1489            }
1490            /* The certificate policies extension includes the policy
1491               anyPolicy with the qualifier set AP-Q and either
1492               (a) inhibit_anyPolicy is greater than 0 or
1493               (b) i < n and the certificate is self-issued. */
1494            if (inhibit_any_policy > 0 || (i < n && is_self_issued)) {
1495                for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1496                    const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1497                    oid_t p_oid = policy->policyIdentifier;
1498                    policy_qualifier_t p_q = &policy->policyQualifiers;
1499                    if (oid_equal(p_oid, oidAnyPolicy)) {
1500                        policy_tree_walk_depth(pvc->valid_policy_tree, i - 1,
1501                            policy_tree_add_expected, (void *)p_q);
1502                    }
1503                }
1504            }
1505            policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1506            /* (e) */
1507            if (!cp) {
1508                if (pvc->valid_policy_tree)
1509                    policy_tree_prune(&pvc->valid_policy_tree);
1510            }
1511        }
1512        /* (f) Verify that either explicit_policy is greater than 0 or the
1513           valid_policy_tree is not equal to NULL. */
1514        if (!pvc->valid_policy_tree && explicit_policy == 0) {
1515            /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1516            if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse, true))
1517                return;
1518        }
1519        /* If Last Cert in Path */
1520        if (i == n)
1521            break;
1522
1523        /* Prepare for Next Cert */
1524#if POLICY_MAPPING
1525        /* (a) verify that anyPolicy does not appear as an
1526           issuerDomainPolicy or a subjectDomainPolicy */
1527        CFDictionaryRef pm = SecCertificateGetPolicyMappings(cert);
1528        if (pm) {
1529            uint32_t mapping_ix, mapping_count = pm->numMappings;
1530            for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1531                const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1532                if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy)
1533                    || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) {
1534                    /* Policy mapping uses anyPolicy, illegal. */
1535                    if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse))
1536                        return;
1537                }
1538            }
1539            /* (b) */
1540            /* (1) If the policy_mapping variable is greater than 0 */
1541            if (policy_mapping > 0) {
1542                if (!policy_tree_walk_depth(pvc->valid_policy_tree, i,
1543                    policy_tree_map, (void *)pm)) {
1544                        /* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1 that has a valid_policy of anyPolicy as follows:
1545
1546            (i)    set the valid_policy to ID-P;
1547
1548            (ii)   set the qualifier_set to the qualifier set of the
1549                   policy anyPolicy in the certificate policies
1550                   extension of certificate i; and
1551    (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */
1552                    }
1553            } else {
1554    #if 0
1555                /* (i)    delete each node of depth i in the valid_policy_tree
1556                   where ID-P is the valid_policy. */
1557                struct policy_tree_map_ctx ctx = { idp_oid, sdp_oid };
1558                policy_tree_walk_depth(pvc->valid_policy_tree, i,
1559                    policy_tree_delete_if_match, &ctx);
1560    #endif
1561                /* (ii)   If there is a node in the valid_policy_tree of depth
1562                   i-1 or less without any child nodes, delete that
1563                   node.  Repeat this step until there are no nodes of
1564                   depth i-1 or less without children. */
1565                policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1);
1566            }
1567        }
1568#endif /* POLICY_MAPPING */
1569        /* (c)(d)(e)(f) */
1570        //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert);
1571        //working_public_key = SecCertificateCopyPublicKey(cert);
1572        //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1573        //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1574#if POLICY_SUBTREES
1575        /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables as follows:
1576 */
1577        /* @@@ handle name constraints. */
1578#endif
1579        /* (h) */
1580        if (!is_self_issued) {
1581            if (explicit_policy)
1582                explicit_policy--;
1583            if (policy_mapping)
1584                policy_mapping--;
1585            if (inhibit_any_policy)
1586                inhibit_any_policy--;
1587        }
1588        /* (i) */
1589        const SecCEPolicyConstraints *pc =
1590            SecCertificateGetPolicyConstraints(cert);
1591        if (pc) {
1592            if (pc->requireExplicitPolicyPresent
1593                && pc->requireExplicitPolicy < explicit_policy) {
1594                explicit_policy = pc->requireExplicitPolicy;
1595            }
1596            if (pc->inhibitPolicyMappingPresent
1597                && pc->inhibitPolicyMapping < policy_mapping) {
1598                policy_mapping = pc->inhibitPolicyMapping;
1599            }
1600        }
1601        /* (j) */
1602        uint32_t iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert);
1603        if (iap < inhibit_any_policy) {
1604            inhibit_any_policy = iap;
1605        }
1606        /* (k) */
1607		const SecCEBasicConstraints *bc =
1608			SecCertificateGetBasicConstraints(cert);
1609#if 0 /* Checked in chain builder pre signature verify already. */
1610        if (!bc || !bc->isCA) {
1611            /* Basic constraints not present or not marked as isCA, illegal. */
1612            if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints,
1613                n - i, kCFBooleanFalse))
1614                return;
1615        }
1616#endif
1617        /* (l) */
1618        if (!is_self_issued) {
1619            if (max_path_length > 0) {
1620                max_path_length--;
1621            } else {
1622                /* max_path_len exceeded, illegal. */
1623                if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints,
1624                    n - i, kCFBooleanFalse))
1625                    return;
1626            }
1627        }
1628        /* (m) */
1629        if (bc && bc->pathLenConstraintPresent
1630            && bc->pathLenConstraint < max_path_length) {
1631            max_path_length = bc->pathLenConstraint;
1632        }
1633#if 0 /* Checked in chain builder pre signature verify already. */
1634        /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
1635        SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
1636        if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
1637            if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
1638                n - i, kCFBooleanFalse, true))
1639                return;
1640        }
1641#endif
1642        /* (o) Recognize and process any other critical extension present in the certificate. Process any other recognized non-critical extension present in the certificate that is relevant to path processing. */
1643        if (SecCertificateHasUnknownCriticalExtension(cert)) {
1644			/* Certificate contains one or more unknown critical extensions. */
1645			if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1646                n - i, kCFBooleanFalse))
1647				return;
1648		}
1649    }
1650    /* Wrap up */
1651    cert = SecPVCGetCertificateAtIndex(pvc, 0);
1652    /* (a) */
1653    if (explicit_policy)
1654        explicit_policy--;
1655    /* (b) */
1656    const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert);
1657    if (pc) {
1658        if (pc->requireExplicitPolicyPresent
1659            && pc->requireExplicitPolicy == 0) {
1660            explicit_policy = 0;
1661        }
1662    }
1663    /* (c) */
1664    //working_public_key = SecCertificateCopyPublicKey(cert);
1665    /* (d) */
1666    /* If the subjectPublicKeyInfo field of the certificate contains an algorithm field with null parameters or parameters are omitted, compare the certificate subjectPublicKey algorithm to the working_public_key_algorithm. If the certificate subjectPublicKey algorithm and the
1667working_public_key_algorithm are different, set the working_public_key_parameters to null. */
1668    //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert);
1669    /* (e) */
1670    //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert);
1671    /* (f) Recognize and process any other critical extension present in the certificate n. Process any other recognized non-critical extension present in certificate n that is relevant to path processing. */
1672    if (SecCertificateHasUnknownCriticalExtension(cert)) {
1673        /* Certificate contains one or more unknown critical extensions. */
1674        if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions,
1675                             0, kCFBooleanFalse))
1676            return;
1677    }
1678    /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
1679
1680    if (pvc->valid_policy_tree) {
1681#if !defined(NDEBUG)
1682        policy_tree_dump(pvc->valid_policy_tree);
1683#endif
1684        /* (g3c4) */
1685        //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
1686    }
1687
1688    /* If either (1) the value of explicit_policy variable is greater than
1689       zero or (2) the valid_policy_tree is not NULL, then path processing
1690       has succeeded. */
1691    if (!pvc->valid_policy_tree && explicit_policy == 0) {
1692        /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1693        if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, 0, kCFBooleanFalse, true))
1694            return;
1695    }
1696}
1697
1698static policy_set_t policies_for_cert(SecCertificateRef cert) {
1699    policy_set_t policies = NULL;
1700    const SecCECertificatePolicies *cp =
1701        SecCertificateGetCertificatePolicies(cert);
1702    size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1703    for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1704        policy_set_add(&policies, &cp->policies[policy_ix].policyIdentifier);
1705    }
1706    return policies;
1707}
1708
1709static void SecPolicyCheckEV(SecPVCRef pvc,
1710	CFStringRef key) {
1711	CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1712    policy_set_t valid_policies = NULL;
1713
1714	for (ix = 0; ix < count; ++ix) {
1715		SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1716        policy_set_t policies = policies_for_cert(cert);
1717        if (ix == 0) {
1718            /* Subscriber */
1719            /* anyPolicy in the leaf isn't allowed for EV, so only init
1720               valid_policies if we have real policies. */
1721            if (!policy_set_contains(policies, &oidAnyPolicy)) {
1722                valid_policies = policies;
1723                policies = NULL;
1724            }
1725        } else if (ix < count - 1) {
1726            /* Subordinate CA */
1727            if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) {
1728                secdebug("ev", "subordinate certificate is not ev");
1729                if (SecPVCSetResultForced(pvc, key,
1730                    ix, kCFBooleanFalse, true)) {
1731                    policy_set_free(valid_policies);
1732                    policy_set_free(policies);
1733                    return;
1734                }
1735            }
1736            policy_set_intersect(&valid_policies, policies);
1737        } else {
1738            /* Root CA */
1739            if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) {
1740                secdebug("ev", "anchor certificate is not ev");
1741                if (SecPVCSetResultForced(pvc, key,
1742                    ix, kCFBooleanFalse, true)) {
1743                    policy_set_free(valid_policies);
1744                    policy_set_free(policies);
1745                    return;
1746                }
1747            }
1748        }
1749        policy_set_free(policies);
1750        if (!valid_policies) {
1751            secdebug("ev", "valid_policies set is empty: chain not ev");
1752            /* If we ever get into a state where no policies are valid anymore
1753               this can't be an ev chain. */
1754            if (SecPVCSetResultForced(pvc, key,
1755                ix, kCFBooleanFalse, true)) {
1756                return;
1757            }
1758        }
1759	}
1760
1761    policy_set_free(valid_policies);
1762
1763    /* (a) EV Subscriber Certificates   Each EV Certificate issued by the CA to a
1764Subscriber MUST contain an OID defined by the CA in the certificate’s
1765certificatePolicies extension that: (i) indicates which CA policy statement relates
1766to that certificate, (ii) asserts the CA’s adherence to and compliance with these
1767Guidelines, and (iii), by pre-agreement with the Application Software Vendor,
1768marks the certificate as being an EV Certificate.
1769(b) EV Subordinate CA Certificates
1770(1) Certificates issued to Subordinate CAs that are not controlled by the issuing
1771CA MUST contain one or more OIDs defined by the issuing CA that
1772explicitly identify the EV Policies that are implemented by the Subordinate
1773CA;
1774(2) Certificates issued to Subordinate CAs that are controlled by the Root CA
1775MAY contain the special anyPolicy OID (2.5.29.32.0).
1776(c) Root CA Certificates  Root CA Certificates SHOULD NOT contain the
1777certificatePolicies or extendedKeyUsage extensions.
1778*/
1779}
1780
1781
1782static void SecPolicyCheckCertificatePolicyOid(SecPVCRef pvc, CFStringRef key)
1783{
1784	CFIndex ix, count = SecPVCGetCertificateCount(pvc);
1785    SecPolicyRef policy = SecPVCGetPolicy(pvc);
1786    CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
1787	DERItem	key_value;
1788	key_value.data = NULL;
1789	key_value.length = 0;
1790
1791	if (CFGetTypeID(value) == CFDataGetTypeID())
1792	{
1793		CFDataRef key_data = (CFDataRef)value;
1794		key_value.data = (DERByte *)CFDataGetBytePtr(key_data);
1795		key_value.length = (DERSize)CFDataGetLength(key_data);
1796
1797		for (ix = 0; ix < count; ix++) {
1798	        SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
1799            policy_set_t policies = policies_for_cert(cert);
1800
1801			if (policy_set_contains(policies, &key_value)) {
1802				return;
1803			}
1804		}
1805		SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
1806	}
1807}
1808
1809
1810static void SecPolicyCheckRevocation(SecPVCRef pvc,
1811	CFStringRef key) {
1812    SecPVCSetCheckRevocation(pvc);
1813}
1814
1815static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc,
1816	CFStringRef key) {
1817    SecPathBuilderSetCanAccessNetwork(pvc->builder, false);
1818}
1819
1820// MARK: -
1821// MARK: SecRVCRef
1822/********************************************************
1823 ****************** SecRVCRef Functions *****************
1824 ********************************************************/
1825
1826/* Revocation verification context. */
1827struct OpaqueSecRVC {
1828    /* Will contain the response data. */
1829    asynchttp_t http;
1830
1831    /* Pointer to the pvc for this revocation check. */
1832    SecPVCRef pvc;
1833
1834    /* The ocsp request we send to each responder. */
1835    SecOCSPRequestRef ocspRequest;
1836
1837    /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */
1838    CFIndex certIX;
1839
1840    /* Index in array returned by SecCertificateGetOCSPResponders() for current
1841       responder. */
1842    CFIndex responderIX;
1843
1844    /* URL of current responder. */
1845    CFURLRef responder;
1846
1847    /* Date until which this revocation status is valid. */
1848    CFAbsoluteTime nextUpdate;
1849
1850    bool done;
1851};
1852typedef struct OpaqueSecRVC *SecRVCRef;
1853
1854static void SecRVCDelete(SecRVCRef rvc) {
1855    secdebug("alloc", "%p", rvc);
1856    asynchttp_free(&rvc->http);
1857    SecOCSPRequestFinalize(rvc->ocspRequest);
1858}
1859
1860/* Return the next responder we should contact for this rvc or NULL if we
1861   exhausted them all. */
1862static CFURLRef SecRVCGetNextResponder(SecRVCRef rvc) {
1863    SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
1864    CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
1865    if (ocspResponders) {
1866        CFIndex responderCount = CFArrayGetCount(ocspResponders);
1867        while (rvc->responderIX < responderCount) {
1868            CFURLRef responder = CFArrayGetValueAtIndex(ocspResponders, rvc->responderIX);
1869            rvc->responderIX++;
1870            CFStringRef scheme = CFURLCopyScheme(responder);
1871            if (scheme) {
1872                /* We only support http and https responders currently. */
1873                bool valid_responder = (CFEqual(CFSTR("http"), scheme) ||
1874                                        CFEqual(CFSTR("https"), scheme));
1875                CFRelease(scheme);
1876                if (valid_responder)
1877                    return responder;
1878            }
1879        }
1880    }
1881    return NULL;
1882}
1883
1884/* Fire off an async http request for this certs revocation status, return
1885   false if request was queued, true if we're done. */
1886static bool SecRVCFetchNext(SecRVCRef rvc) {
1887    while ((rvc->responder = SecRVCGetNextResponder(rvc))) {
1888        CFDataRef request = SecOCSPRequestGetDER(rvc->ocspRequest);
1889        if (!request)
1890            goto errOut;
1891
1892        if (!asyncHttpPost(rvc->responder, request, &rvc->http)) {
1893            /* Async request was posted, wait for reply. */
1894            return false;
1895        }
1896    }
1897
1898errOut:
1899    rvc->done = true;
1900    return true;
1901}
1902
1903/* Proccess a verified ocsp response for a given cert. Return true if the
1904   certificate status was obtained. */
1905static bool SecOCSPSingleResponseProccess(SecOCSPSingleResponseRef this,
1906    SecRVCRef rvc) {
1907    bool proccessed;
1908	switch (this->certStatus) {
1909    case CS_Good:
1910        secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX);
1911        /* @@@ Mark cert as valid until a given date (nextUpdate if we have one)
1912           in the info dictionary. */
1913        //cert.revokeCheckGood(true);
1914        rvc->nextUpdate = this->nextUpdate;
1915        proccessed = true;
1916        break;
1917    case CS_Revoked:
1918        secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX);
1919        /* @@@ Mark cert as revoked (with reason) at revocation date in
1920           the info dictionary, or perhaps we should use a different key per
1921           reason?   That way a client using exceptions can ignore some but
1922           not all reasons. */
1923        SInt32 reason = this->crlReason;
1924        CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
1925        SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX,
1926            cfreason, true);
1927        CFRelease(cfreason);
1928        proccessed = true;
1929        break;
1930    case CS_Unknown:
1931        /* not an error, no per-cert status, nothing here */
1932        secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX);
1933        proccessed = false;
1934        break;
1935    default:
1936        secdebug("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex,
1937            (int)this->certStatus, rvc->certIX);
1938        proccessed = false;
1939        break;
1940	}
1941
1942	return proccessed;
1943}
1944
1945static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecRVCRef rvc) {
1946    bool trusted;
1947    SecCertificatePathRef issuer = SecCertificatePathCopyFromParent(rvc->pvc->path, rvc->certIX + 1);
1948    SecCertificatePathRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer);
1949    CFRelease(issuer);
1950
1951    if (signer) {
1952        if (signer == issuer) {
1953            /* We already know we trust issuer since it's the path we are
1954               trying to verify minus the leaf. */
1955            secdebug("ocsp", "ocsp responder: %@ response signed by issuer",
1956                rvc->responder);
1957            trusted = true;
1958        } else {
1959            secdebug("ocsp",
1960                "ocsp responder: %@ response signed by cert issued by issuer",
1961                rvc->responder);
1962            /* @@@ Now check that we trust signer. */
1963            const void *ocspSigner = SecPolicyCreateOCSPSigner();
1964            CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault,
1965                &ocspSigner, 1, &kCFTypeArrayCallBacks);
1966            CFRelease(ocspSigner);
1967            CFAbsoluteTime verifyTime = SecOCSPResponseVerifyTime(ocspResponse);
1968            struct OpaqueSecPVC ospvc;
1969            SecPVCInit(&ospvc, rvc->pvc->builder, policies, verifyTime);
1970            CFRelease(policies);
1971            SecPVCSetPath(&ospvc, signer, NULL);
1972            SecPVCLeafChecks(&ospvc);
1973            if (ospvc.result) {
1974                bool completed = SecPVCPathChecks(&ospvc);
1975                /* If completed is false we are waiting for a callback, this
1976                   shouldn't happen since we aren't asking for details, no
1977                   revocation checking is done. */
1978                if (!completed) {
1979                    ocspdErrorLog("SecPVCPathChecks unexpectedly started "
1980                        "background job!");
1981                    /* @@@ assert() or abort here perhaps? */
1982                }
1983            }
1984            if (ospvc.result) {
1985                secdebug("ocsp", "response satisfies ocspSigner policy (%@)",
1986                    rvc->responder);
1987                trusted = true;
1988            } else {
1989                /* @@@ We don't trust the cert so don't use this response. */
1990                ocspdErrorLog("ocsp response signed by certificate which "
1991                    "does not satisfy ocspSigner policy");
1992                trusted = false;
1993            }
1994            SecPVCDelete(&ospvc);
1995        }
1996
1997        CFRelease(signer);
1998    } else {
1999        /* @@@ No signer found for this ocsp response, discard it. */
2000        secdebug("ocsp", "ocsp responder: %@ no signer found for response",
2001            rvc->responder);
2002        trusted = false;
2003    }
2004
2005#if DUMP_OCSPRESPONSES
2006    char buf[40];
2007    snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der",
2008        rvc->certIX, (trusted ? "t" : "u"));
2009    secdumpdata(ocspResponse->data, buf);
2010#endif
2011
2012    return trusted;
2013}
2014
2015/* Callback from async http code after an ocsp response has been received. */
2016static void SecOCSPFetchCompleted(asynchttp_t *http, CFTimeInterval maxAge) {
2017    SecRVCRef rvc = (SecRVCRef)http->info;
2018    SecPVCRef pvc = rvc->pvc;
2019    SecOCSPResponseRef ocspResponse = NULL;
2020    if (http->response) {
2021        CFDataRef data = CFHTTPMessageCopyBody(http->response);
2022        if (data) {
2023            /* Parse the returned data as if it's an ocspResponse. */
2024            ocspResponse = SecOCSPResponseCreate(data, maxAge);
2025            CFRelease(data);
2026        }
2027    }
2028
2029    if (ocspResponse) {
2030        SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse);
2031        if (orStatus == kSecOCSPSuccess) {
2032            SecOCSPSingleResponseRef sr =
2033                SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest);
2034            if (!sr) {
2035                /* The ocsp response didn't have a singleResponse for the cert
2036                   we are looking for, let's try the next responder. */
2037                secdebug("ocsp",
2038                    "ocsp responder: %@ did not include status of requested cert",
2039                    rvc->responder);
2040            } else {
2041                /* We got a singleResponse for the cert we are interested in,
2042                   let's proccess it. */
2043                /* @@@ If the responder doesn't have the ocsp-nocheck extension
2044                   we should check whether the leaf was revoked (we are
2045                   already checking the rest of the chain). */
2046                /* Check the OCSP response signature and verify the
2047                   response. */
2048                if (SecOCSPResponseVerify(ocspResponse, rvc)) {
2049                    secdebug("ocsp","responder: %@ sent proper response",
2050                        rvc->responder);
2051
2052                    if (SecOCSPSingleResponseProccess(sr, rvc)) {
2053                        if (rvc->nextUpdate == 0) {
2054                            rvc->nextUpdate =
2055                                SecOCSPResponseGetExpirationTime(ocspResponse);
2056                        }
2057                        /* If the singleResponse had meaningful information, we
2058                           cache the response. */
2059                        SecOCSPCacheAddResponse(ocspResponse, rvc->responder);
2060                        rvc->done = true;
2061                    }
2062                }
2063                SecOCSPSingleResponseDestroy(sr);
2064            }
2065        } else {
2066            /* ocsp response not ok.  Let's try next responder. */
2067            secdebug("ocsp", "responder: %@ returned status: %d",
2068                rvc->responder, orStatus);
2069#if 0
2070            if (!SecPVCSetResultForced(pvc, kSecPolicyCheckRevocation,
2071                rvc->certIX, kCFBooleanFalse, true))
2072                return;
2073#endif
2074        }
2075        SecOCSPResponseFinalize(ocspResponse);
2076    }
2077
2078    if (!rvc->done) {
2079        /* Clear the data for the next response. */
2080        asynchttp_free(http);
2081        SecRVCFetchNext(rvc);
2082    }
2083
2084    if (rvc->done) {
2085        SecRVCDelete(rvc);
2086        if (!--pvc->asyncJobCount) {
2087            SecPathBuilderStep(pvc->builder);
2088        }
2089    }
2090}
2091
2092static void SecRVCInit(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) {
2093    secdebug("alloc", "%p", rvc);
2094    rvc->pvc = pvc;
2095    rvc->certIX = certIX;
2096    rvc->http.queue = SecPathBuilderGetQueue(pvc->builder);
2097    rvc->http.completed = SecOCSPFetchCompleted;
2098    rvc->http.info = rvc;
2099    rvc->ocspRequest = NULL;
2100    rvc->responderIX = 0;
2101    rvc->responder = NULL;
2102    rvc->nextUpdate = 0;
2103    rvc->done = false;
2104}
2105
2106
2107static bool SecPVCCheckRevocation(SecPVCRef pvc) {
2108    secdebug("ocsp", "checking revocation");
2109	CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
2110    bool completed = true;
2111    if (certCount <= 1) {
2112		/* Can't verify without an issuer; we're done */
2113        return completed;
2114    }
2115    if (!SecPVCIsAnchored(pvc)) {
2116        /* We can't check revocation for chains without a trusted anchor. */
2117        return completed;
2118    }
2119    certCount--;
2120
2121#if 0
2122    /* @@@ Implement getting this value from the client.
2123       Optional responder passed in though policy. */
2124    CFURLRef localResponder = NULL;
2125    /* Generate a nonce in outgoing request if true. */
2126	bool genNonce = false;
2127    /* Require a nonce in response if true. */
2128	bool requireRespNonce = false;
2129	bool cacheReadDisable = false;
2130	bool cacheWriteDisable = false;
2131#endif
2132
2133    if (pvc->rvcs) {
2134        /* We have done revocation checking already, we're done. */
2135        secdebug("ocsp", "Not rechecking revocation");
2136        return completed;
2137    }
2138
2139    /* Setup things so we check revocation status of all certs except the
2140       anchor. */
2141    pvc->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount);
2142
2143#if 0
2144    /* Lookup cached revocation data for each certificate. */
2145	for (certIX = 0; certIX < certCount; ++certIX) {
2146		SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
2147        CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
2148		if (ocspResponders) {
2149            /* First look though passed in ocsp responses. */
2150            //SecPVCGetOCSPResponseForCertificateAtIndex(pvc, ix, singleResponse);
2151
2152            /* Then look though shared cache (we don't care which responder
2153               something came from here). */
2154            CFDataRef ocspResponse = SecOCSPCacheCopyMatching(SecCertIDRef certID, NULL);
2155
2156            /* Now let's parse the response. */
2157            if (decodeOCSPResponse(ocspResp)) {
2158                secdebug("ocsp", "response ok: %@", ocspResp);
2159            } else {
2160                secdebug("ocsp", "response bad: %@", ocspResp);
2161                /* ocsp response not ok. */
2162                if (!SecPVCSetResultForced(pvc, key, ix, kCFBooleanFalse, true))
2163                    return completed;
2164            }
2165            CFReleaseSafe(ocspResp);
2166		} else {
2167            /* Check if certificate has any crl distributionPoints. */
2168            CFArrayRef distributionPoints = SecCertificateGetCRLDistributionPoints(cert);
2169            if (distributionPoints) {
2170                /* Look for a cached CRL and potentially delta CRL for this certificate. */
2171            }
2172        }
2173	}
2174#endif
2175
2176    /* Note that if we are multi threaded and a job completes after it
2177       is started but before we return from this function, we don't want
2178       a callback to decrement asyncJobCount to zero before we finish issuing
2179       all the jobs. To avoid this we pretend we issued certCount async jobs,
2180       and decrement pvc->asyncJobCount for each cert that we don't start a
2181       background fetch for. */
2182    pvc->asyncJobCount = (unsigned int) certCount;
2183
2184    /* Loop though certificates again and issue an ocsp fetch if the
2185       revocation status checking isn't done yet. */
2186	for (certIX = 0; certIX < certCount; ++certIX) {
2187        secdebug("ocsp", "checking revocation for cert: %ld", certIX);
2188        SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
2189        SecRVCInit(rvc, pvc, certIX);
2190        if (rvc->done)
2191            continue;
2192
2193        SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc,
2194            rvc->certIX);
2195        /* The certIX + 1 is ok here since certCount is always at least 1
2196           less than the actual number of certs. */
2197        SecCertificateRef issuer = SecPVCGetCertificateAtIndex(rvc->pvc,
2198            rvc->certIX + 1);
2199
2200        rvc->ocspRequest = SecOCSPRequestCreate(cert, issuer);
2201        SecOCSPResponseRef ocspResponse;
2202        ocspResponse = SecOCSPCacheCopyMatching(rvc->ocspRequest, NULL);
2203        if (ocspResponse) {
2204            SecOCSPSingleResponseRef sr =
2205                SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest);
2206            if (!sr) {
2207                /* The cached ocsp response didn't have a singleResponse for
2208                   the cert we are looking for, it's shouldn't be in the cache. */
2209                secdebug("ocsp", "cached ocsp response did not include status"
2210                    " of requested cert");
2211            } else {
2212                /* We got a singleResponse for the cert we are interested in,
2213                   let's proccess it. */
2214
2215                /* @@@ If the responder doesn't have the ocsp-nocheck extension
2216                   we should check whether the leaf was revoked (we are
2217                   already checking the rest of the chain). */
2218                /* Recheck the OCSP response signature and verify the
2219                   response. */
2220                if (SecOCSPResponseVerify(ocspResponse, rvc)) {
2221                    secdebug("ocsp","cached response still has valid signature");
2222
2223                    if (SecOCSPSingleResponseProccess(sr, rvc)) {
2224                        CFAbsoluteTime expTime =
2225                            SecOCSPResponseGetExpirationTime(ocspResponse);
2226                        if (rvc->nextUpdate == 0 || expTime < rvc->nextUpdate)
2227                            rvc->nextUpdate = expTime;
2228                        rvc->done = true;
2229                    }
2230                }
2231                SecOCSPSingleResponseDestroy(sr);
2232            }
2233            SecOCSPResponseFinalize(ocspResponse);
2234        }
2235
2236        /* Unless we succefully checked the revocation status of this cert
2237           based on the cache, Attempt to fire off an async http request
2238           for this certs revocation status. */
2239        bool fetch_done = true;
2240        if (rvc->done || !SecPathBuilderCanAccessNetwork(pvc->builder) ||
2241            (fetch_done = SecRVCFetchNext(rvc))) {
2242            /* We got a cache hit or we aren't allowed to access the network,
2243               or the async http post failed. */
2244            SecRVCDelete(rvc);
2245            /* We didn't really start a background job for this cert. */
2246            pvc->asyncJobCount--;
2247        } else if (!fetch_done) {
2248            /* We started at least one background fetch. */
2249            completed = false;
2250        }
2251    }
2252
2253    /* Return false if we started any background jobs. */
2254    /* We can't just return !pvc->asyncJobCount here, since if we started any
2255       jobs the completion callback will be called eventually and it will call
2256       SecPathBuilderStep(). If for some reason everything completed before we
2257       get here we still want the outer SecPathBuilderStep() to terminate so we
2258       keep track of whether we started any jobs and return false if so. */
2259    return completed;
2260}
2261
2262
2263void SecPolicyServerInitalize(void) {
2264	gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2265		&kCFTypeDictionaryKeyCallBacks, NULL);
2266	gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2267		&kCFTypeDictionaryKeyCallBacks, NULL);
2268	CFDictionaryAddValue(gSecPolicyPathCallbacks,
2269		kSecPolicyCheckBasicCertificateProcessing,
2270        SecPolicyCheckBasicCertificateProcessing);
2271	CFDictionaryAddValue(gSecPolicyPathCallbacks,
2272		kSecPolicyCheckCriticalExtensions, SecPolicyCheckCriticalExtensions);
2273	CFDictionaryAddValue(gSecPolicyPathCallbacks,
2274		kSecPolicyCheckIdLinkage, SecPolicyCheckIdLinkage);
2275	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2276		kSecPolicyCheckKeyUsage, SecPolicyCheckKeyUsage);
2277	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2278		kSecPolicyCheckExtendedKeyUsage, SecPolicyCheckExtendedKeyUsage);
2279	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2280		kSecPolicyCheckBasicContraints, SecPolicyCheckBasicContraints);
2281	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2282		kSecPolicyCheckNonEmptySubject, SecPolicyCheckNonEmptySubject);
2283	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2284		kSecPolicyCheckQualifiedCertStatements,
2285		SecPolicyCheckQualifiedCertStatements);
2286	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2287		kSecPolicyCheckSSLHostname, SecPolicyCheckSSLHostname);
2288	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2289        kSecPolicyCheckEmail, SecPolicyCheckEmail);
2290	CFDictionaryAddValue(gSecPolicyPathCallbacks,
2291		kSecPolicyCheckValidIntermediates, SecPolicyCheckValidIntermediates);
2292	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2293		kSecPolicyCheckValidLeaf, SecPolicyCheckValidLeaf);
2294	CFDictionaryAddValue(gSecPolicyPathCallbacks,
2295		kSecPolicyCheckValidRoot, SecPolicyCheckValidRoot);
2296	CFDictionaryAddValue(gSecPolicyPathCallbacks,
2297		kSecPolicyCheckIssuerCommonName, SecPolicyCheckIssuerCommonName);
2298	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2299		kSecPolicyCheckSubjectCommonNamePrefix,
2300		SecPolicyCheckSubjectCommonNamePrefix);
2301	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2302		kSecPolicyCheckSubjectCommonName,
2303		SecPolicyCheckSubjectCommonName);
2304	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2305		kSecPolicyCheckNotValidBefore,
2306		SecPolicyCheckNotValidBefore);
2307	CFDictionaryAddValue(gSecPolicyPathCallbacks,
2308		kSecPolicyCheckChainLength, SecPolicyCheckChainLength);
2309	CFDictionaryAddValue(gSecPolicyPathCallbacks,
2310		kSecPolicyCheckAnchorSHA1, SecPolicyCheckAnchorSHA1);
2311	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2312		kSecPolicyCheckSubjectOrganization,
2313		SecPolicyCheckSubjectOrganization);
2314	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2315		kSecPolicyCheckSubjectOrganizationalUnit,
2316		SecPolicyCheckSubjectOrganizationalUnit);
2317	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2318		kSecPolicyCheckEAPTrustedServerNames,
2319        SecPolicyCheckEAPTrustedServerNames);
2320	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2321		kSecPolicyCheckSubjectCommonNameTEST,
2322		SecPolicyCheckSubjectCommonNameTEST);
2323	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2324		kSecPolicyCheckRevocation,
2325		SecPolicyCheckRevocation);
2326	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2327		kSecPolicyCheckNoNetworkAccess,
2328		SecPolicyCheckNoNetworkAccess);
2329    CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2330        kSecPolicyCheckBlackListedLeaf,
2331        SecPolicyCheckBlackListedLeaf);
2332	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2333        kSecPolicyCheckGrayListedLeaf,
2334        SecPolicyCheckGrayListedLeaf);
2335    CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2336        kSecPolicyCheckLeafMarkerOid,
2337        SecPolicyCheckLeafMarkerOid);
2338    CFDictionaryAddValue(gSecPolicyPathCallbacks,
2339        kSecPolicyCheckIntermediateMarkerOid,
2340        SecPolicyCheckIntermediateMarkerOid);
2341	CFDictionaryAddValue(gSecPolicyLeafCallbacks,
2342		kSecPolicyCheckCertificatePolicy,
2343		SecPolicyCheckCertificatePolicyOid);
2344}
2345
2346/* AUDIT[securityd](done):
2347   array (ok) is a caller provided array, only its cf type has
2348   been checked.
2349   The options (ok) field ends up in policy->_options unchecked, so every access
2350   of policy->_options needs to be validated.
2351 */
2352static SecPolicyRef SecPolicyCreateWithArray(CFArrayRef array) {
2353    SecPolicyRef policy = NULL;
2354    require_quiet(array && CFArrayGetCount(array) == 2, errOut);
2355    CFStringRef oid = (CFStringRef)CFArrayGetValueAtIndex(array, 0);
2356    require_quiet(isString(oid), errOut);
2357    CFDictionaryRef options = (CFDictionaryRef)CFArrayGetValueAtIndex(array, 1);
2358    require_quiet(isDictionary(options), errOut);
2359    policy = SecPolicyCreate(oid, options);
2360errOut:
2361    return policy;
2362}
2363
2364/* AUDIT[securityd](done):
2365   value (ok) is an element in a caller provided array.
2366 */
2367static void deserializePolicy(const void *value, void *context) {
2368    CFArrayRef policyArray = (CFArrayRef)value;
2369    if (isArray(policyArray)) {
2370        CFTypeRef deserializedPolicy = SecPolicyCreateWithArray(policyArray);
2371        if (deserializedPolicy) {
2372            CFArrayAppendValue((CFMutableArrayRef)context, deserializedPolicy);
2373            CFRelease(deserializedPolicy);
2374        }
2375    }
2376}
2377
2378/* AUDIT[securityd](done):
2379   serializedPolicies (ok) is a caller provided array, only its cf type has
2380   been checked.
2381 */
2382CFArrayRef SecPolicyArrayDeserialize(CFArrayRef serializedPolicies) {
2383    CFMutableArrayRef result = NULL;
2384    require_quiet(isArray(serializedPolicies), errOut);
2385    CFIndex count = CFArrayGetCount(serializedPolicies);
2386    result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
2387    CFRange all_policies = { 0, count };
2388    CFArrayApplyFunction(serializedPolicies, all_policies, deserializePolicy, result);
2389errOut:
2390    return result;
2391}
2392
2393// MARK: -
2394// MARK: SecPVCRef
2395/********************************************************
2396 ****************** SecPVCRef Functions *****************
2397 ********************************************************/
2398
2399void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies,
2400    CFAbsoluteTime verifyTime) {
2401    secdebug("alloc", "%p", pvc);
2402    // Weird logging policies crashes.
2403    //secdebug("policy", "%@", policies);
2404    pvc->builder = builder;
2405    pvc->policies = policies;
2406    if (policies)
2407        CFRetain(policies);
2408    pvc->verifyTime = verifyTime;
2409    pvc->path = NULL;
2410    pvc->details = NULL;
2411    pvc->info = NULL;
2412    pvc->valid_policy_tree = NULL;
2413    pvc->callbacks = NULL;
2414    pvc->policyIX = 0;
2415    pvc->rvcs = NULL;
2416    pvc->asyncJobCount = 0;
2417    pvc->check_revocation = false;
2418    pvc->optionally_ev = false;
2419    pvc->is_ev = false;
2420	pvc->result = true;
2421}
2422
2423static void SecPVCDeleteRVCs(SecPVCRef pvc) {
2424    secdebug("alloc", "%p", pvc);
2425    if (pvc->rvcs) {
2426        free(pvc->rvcs);
2427        pvc->rvcs = NULL;
2428    }
2429}
2430
2431void SecPVCDelete(SecPVCRef pvc) {
2432    secdebug("alloc", "%p", pvc);
2433    CFReleaseNull(pvc->policies);
2434    CFReleaseNull(pvc->details);
2435    CFReleaseNull(pvc->info);
2436    if (pvc->valid_policy_tree) {
2437        policy_tree_prune(&pvc->valid_policy_tree);
2438    }
2439    SecPVCDeleteRVCs(pvc);
2440}
2441
2442void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathRef path,
2443    CF_CONSUMED CFArrayRef details) {
2444    secdebug("policy", "%@", path);
2445    if (pvc->path != path) {
2446        /* Changing path makes us clear the Revocation Verification Contexts */
2447        SecPVCDeleteRVCs(pvc);
2448        pvc->path = path;
2449    }
2450    pvc->details = details;
2451    CFReleaseNull(pvc->info);
2452    if (pvc->valid_policy_tree) {
2453        policy_tree_prune(&pvc->valid_policy_tree);
2454    }
2455    pvc->policyIX = 0;
2456	pvc->result = true;
2457}
2458
2459SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) {
2460	return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX);
2461}
2462
2463CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) {
2464	return SecCertificatePathGetCount(pvc->path);
2465}
2466
2467SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) {
2468	return SecCertificatePathGetCertificateAtIndex(pvc->path, ix);
2469}
2470
2471bool SecPVCIsCertificateAtIndexSelfSigned(SecPVCRef pvc, CFIndex ix) {
2472    return SecCertificatePathSelfSignedIndex(pvc->path) == ix;
2473}
2474
2475void SecPVCSetCheckRevocation(SecPVCRef pvc) {
2476    pvc->check_revocation = true;
2477    secdebug("ocsp", "deferred revocation checking enabled");
2478}
2479
2480bool SecPVCIsAnchored(SecPVCRef pvc) {
2481    return SecCertificatePathIsAnchored(pvc->path);
2482}
2483
2484CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) {
2485	return pvc->verifyTime;
2486}
2487
2488/* AUDIT[securityd](done):
2489   policy->_options is a caller provided dictionary, only its cf type has
2490   been checked.
2491 */
2492bool SecPVCSetResultForced(SecPVCRef pvc,
2493	CFStringRef key, CFIndex ix, CFTypeRef result, bool force) {
2494
2495    secdebug("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key,
2496        (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf"
2497            : (pvc->callbacks == gSecPolicyPathCallbacks ? "path"
2498                : "custom")),
2499        (force ? "force" : ""), result);
2500
2501    /* If this is not something the current policy cares about ignore
2502       this error and return true so our caller continues evaluation. */
2503    if (!force) {
2504        /* @@@ The right long term fix might be to check if none of the passed
2505           in policies contain this key, since not all checks are run for all
2506           policies. */
2507        SecPolicyRef policy = SecPVCGetPolicy(pvc);
2508        if (policy && !CFDictionaryContainsKey(policy->_options, key))
2509            return true;
2510    }
2511
2512	/* @@@ Check to see if the SecTrustSettings for the certificate in question
2513	   tell us to ignore this error. */
2514	pvc->result = false;
2515	if (!pvc->details)
2516		return false;
2517
2518	CFMutableDictionaryRef detail =
2519		(CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix);
2520
2521	/* Perhaps detail should have an array of results per key?  As it stands
2522       in the case of multiple policy failures the last failure stands.  */
2523	CFDictionarySetValue(detail, key, result);
2524
2525	return true;
2526}
2527
2528bool SecPVCSetResult(SecPVCRef pvc,
2529	CFStringRef key, CFIndex ix, CFTypeRef result) {
2530    return SecPVCSetResultForced(pvc, key, ix, result, false);
2531}
2532
2533/* AUDIT[securityd](done):
2534   key(ok) is a caller provided.
2535   value(ok, unused) is a caller provided.
2536 */
2537static void SecPVCValidateKey(const void *key, const void *value,
2538	void *context) {
2539	SecPVCRef pvc = (SecPVCRef)context;
2540
2541	/* If our caller doesn't want full details and we failed earlier there is
2542	   no point in doing additional checks. */
2543	if (!pvc->result && !pvc->details)
2544		return;
2545
2546	SecPolicyCheckFunction fcn = (SecPolicyCheckFunction)
2547		CFDictionaryGetValue(pvc->callbacks, key);
2548
2549	if (!fcn) {
2550#if 0
2551    /* Why not to have optional policy checks rant:
2552       Not all keys are in all dictionaries anymore, so why not make checks
2553       optional?  This way a client can ask for something and the server will
2554       do a best effort based on the supported flags.  It works since they are
2555       synchronized now, but we need some debug checking here for now. */
2556		pvc->result = false;
2557#endif
2558        if (pvc->callbacks == gSecPolicyLeafCallbacks) {
2559            if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) {
2560                pvc->result = false;
2561            }
2562        } else if (pvc->callbacks == gSecPolicyPathCallbacks) {
2563            if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) {
2564                pvc->result = false;
2565            }
2566        } else {
2567            /* Non standard valdation phase, nothing is optional. */
2568            pvc->result = false;
2569        }
2570		return;
2571	}
2572
2573	fcn(pvc, (CFStringRef)key);
2574}
2575
2576/* AUDIT[securityd](done):
2577   policy->_options is a caller provided dictionary, only its cf type has
2578   been checked.
2579 */
2580bool SecPVCLeafChecks(SecPVCRef pvc) {
2581    pvc->result = true;
2582    CFArrayRef policies = pvc->policies;
2583	CFIndex ix, count = CFArrayGetCount(policies);
2584	for (ix = 0; ix < count; ++ix) {
2585		SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix);
2586        pvc->policyIX = ix;
2587        /* Validate all keys for all policies. */
2588        pvc->callbacks = gSecPolicyLeafCallbacks;
2589        CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
2590        if (!pvc->result && !pvc->details)
2591            return pvc->result;
2592	}
2593
2594    return pvc->result;
2595}
2596
2597bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) {
2598    /* Check stuff common to intermediate and anchors. */
2599	CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc);
2600	SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2601    bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
2602        && SecPVCIsAnchored(pvc));
2603	if (!SecCertificateIsValid(cert, verifyTime)) {
2604		/* Certificate has expired. */
2605		if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckValidRoot
2606            : kSecPolicyCheckValidIntermediates, ix, kCFBooleanFalse))
2607            goto errOut;
2608	}
2609
2610    if (is_anchor) {
2611        /* Perform anchor specific checks. */
2612        /* Don't think we have any of these. */
2613    } else {
2614        /* Perform intermediate specific checks. */
2615
2616        /* (k) */
2617		const SecCEBasicConstraints *bc =
2618			SecCertificateGetBasicConstraints(cert);
2619        if (!bc || !bc->isCA) {
2620            /* Basic constraints not present or not marked as isCA, illegal. */
2621            if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicContraints,
2622                ix, kCFBooleanFalse, true))
2623                goto errOut;
2624        }
2625        /* Consider adding (l) max_path_length checking here. */
2626
2627        /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */
2628        SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert);
2629        if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) {
2630            if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage,
2631                ix, kCFBooleanFalse, true))
2632                goto errOut;
2633        }
2634    }
2635
2636errOut:
2637    return pvc->result;
2638}
2639
2640bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) {
2641    /* Check stuff common to intermediate and anchors. */
2642
2643	SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
2644	if (NULL != otapkiRef)
2645	{
2646		CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef);
2647		CFRelease(otapkiRef);
2648		if (NULL != blackListedKeys)
2649		{
2650			SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2651		    bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
2652		                      && SecPVCIsAnchored(pvc));
2653		    if (!is_anchor) {
2654		        /* Check for blacklisted intermediates keys. */
2655		        CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
2656		        if (dgst) {
2657		            /* Check dgst against blacklist. */
2658		            if (CFSetContainsValue(blackListedKeys, dgst)) {
2659		                SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey,
2660		                                      ix, kCFBooleanFalse, true);
2661		            }
2662		            CFRelease(dgst);
2663		        }
2664		    }
2665			CFRelease(blackListedKeys);
2666		    return pvc->result;
2667		}
2668	}
2669	// Assume OK
2670	return true;
2671}
2672
2673bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix)
2674{
2675    /* Check stuff common to intermediate and anchors. */
2676	SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef();
2677	if (NULL != otapkiRef)
2678	{
2679		CFSetRef grayListKeys = SecOTAPKICopyGrayList(otapkiRef);
2680		CFRelease(otapkiRef);
2681		if (NULL != grayListKeys)
2682		{
2683			SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
2684		    bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1
2685		                      && SecPVCIsAnchored(pvc));
2686		    if (!is_anchor) {
2687		        /* Check for gray listed intermediates keys. */
2688		        CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert);
2689		        if (dgst) {
2690		            /* Check dgst against gray list. */
2691		            if (CFSetContainsValue(grayListKeys, dgst)) {
2692		                SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey,
2693		                                      ix, kCFBooleanFalse, true);
2694		            }
2695		            CFRelease(dgst);
2696		        }
2697		    }
2698			CFRelease(grayListKeys);
2699		    return pvc->result;
2700		}
2701	}
2702	// Assume ok
2703	return true;
2704}
2705
2706/* AUDIT[securityd](done):
2707   policy->_options is a caller provided dictionary, only its cf type has
2708   been checked.
2709 */
2710bool SecPVCPathChecks(SecPVCRef pvc) {
2711    secdebug("policy", "begin path: %@", pvc->path);
2712    bool completed = true;
2713    /* This needs to be initialized before we call any function that might call
2714       SecPVCSetResultForced(). */
2715    pvc->policyIX = 0;
2716    SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage);
2717    if (pvc->result || pvc->details) {
2718        SecPolicyCheckBasicCertificateProcessing(pvc,
2719            kSecPolicyCheckBasicCertificateProcessing);
2720    }
2721
2722    CFArrayRef policies = pvc->policies;
2723	CFIndex count = CFArrayGetCount(policies);
2724	for (; pvc->policyIX < count; ++pvc->policyIX) {
2725        /* Validate all keys for all policies. */
2726        pvc->callbacks = gSecPolicyPathCallbacks;
2727		SecPolicyRef policy = SecPVCGetPolicy(pvc);
2728        CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc);
2729        if (!pvc->result && !pvc->details)
2730            return completed;
2731	}
2732
2733    /* Check the things we can't check statically for the certificate path. */
2734    /* Critical Extensions, chainLength. */
2735
2736    /* Policy tests. */
2737    pvc->is_ev = false;
2738    if ((pvc->result || pvc->details) && pvc->optionally_ev) {
2739        bool pre_ev_check_result = pvc->result;
2740        SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation);
2741        pvc->is_ev = pvc->result;
2742        /* If ev checking failed, we still want to accept this chain
2743           as a non EV one, if it was valid as such. */
2744        pvc->result = pre_ev_check_result;
2745    }
2746    /* Check revocation only if the chain is valid so far.  Then only check
2747       revocation if the client asked for it explicitly or is_ev is
2748       true. */
2749    if (pvc->result && (pvc->is_ev || pvc->check_revocation)) {
2750        completed = SecPVCCheckRevocation(pvc);
2751    }
2752
2753//errOut:
2754    secdebug("policy", "end %strusted completed: %d path: %@",
2755        (pvc->result ? "" : "not "), completed, pvc->path);
2756    return completed;
2757}
2758
2759/* This function returns 0 to indicate revocation checking was not completed
2760   for this certificate chain, otherwise return to date at which the first
2761   piece of revocation checking info we used expires.  */
2762CFAbsoluteTime SecPVCGetEarliestNextUpdate(SecPVCRef pvc) {
2763	CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc);
2764    CFAbsoluteTime enu = 0;
2765    if (certCount <= 1 || !pvc->rvcs) {
2766        return enu;
2767    }
2768    certCount--;
2769
2770	for (certIX = 0; certIX < certCount; ++certIX) {
2771        SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX];
2772        if (rvc->nextUpdate == 0) {
2773            if (certIX > 0) {
2774                /* We allow for CA certs to not be revocation checked if they
2775                   have no ocspResponders to check against, but the leaf
2776                   must be checked in order for us to claim we did revocation
2777                   checking. */
2778                SecCertificateRef cert =
2779                    SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
2780                CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert);
2781                if (!ocspResponders || CFArrayGetCount(ocspResponders) == 0) {
2782                    /* We can't check this cert so we don't consider it a soft
2783                       failure that we didn't. Ideally we should support crl
2784                       checking and remove this workaround, since that more
2785                       strict. */
2786                    continue;
2787                }
2788            }
2789            secdebug("ocsp", "revocation checking soft failure for cert: %ld",
2790                certIX);
2791            enu = rvc->nextUpdate;
2792            break;
2793        }
2794        if (enu == 0 || rvc->nextUpdate < enu) {
2795            enu = rvc->nextUpdate;
2796        }
2797#if 0
2798        /* Perhaps we don't want to do this since some policies might
2799           ignore the certificate experation but still use revocation
2800           checking. */
2801
2802        /* Earliest certificate expiration date. */
2803		SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX);
2804        CFAbsoluteTime nva = SecCertificateNotValidAfter(cert);
2805        if (nva && (enu == 0 || nva < enu)
2806            enu = nva;
2807#endif
2808    }
2809
2810    secdebug("ocsp", "revocation valid until: %lg", enu);
2811    return enu;
2812}
2813