]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecCertificateServer.c
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / sec / securityd / SecCertificateServer.c
1 /*
2 * Copyright (c) 2017 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 * SecCertificateServer.c - SecCertificate and SecCertificatePathVC types
26 * with additonal validation context.
27 */
28
29 #include <CoreFoundation/CoreFoundation.h>
30 #include <AssertMacros.h>
31
32 #include <libDER/libDER.h>
33 #include <libDER/oidsPriv.h>
34
35 #include <Security/SecCertificate.h>
36 #include <Security/SecCertificatePriv.h>
37 #include <Security/SecCertificateInternal.h>
38 #include <Security/SecItem.h>
39 #include <Security/SecInternal.h>
40 #include <Security/oids.h>
41
42 #include <utilities/SecIOFormat.h>
43 #include <utilities/SecCFError.h>
44 #include <utilities/SecCFWrappers.h>
45 #include <utilities/debugging.h>
46
47 #include <securityd/policytree.h>
48 #include <securityd/SecPolicyServer.h>
49 #include <securityd/SecCertificateServer.h>
50 #include <securityd/SecRevocationServer.h>
51
52 // MARK: -
53 // MARK: SecCertificateVC
54 /********************************************************
55 ************* SecCertificateVC object ***************
56 ********************************************************/
57
58 struct SecCertificateVC {
59 CFRuntimeBase _base;
60 SecCertificateRef certificate;
61 CFArrayRef usageConstraints;
62 bool optionallyEV;
63 bool isWeakHash;
64 bool require_revocation_response;
65 };
66 CFGiblisWithHashFor(SecCertificateVC)
67
68 static void SecCertificateVCDestroy(CFTypeRef cf) {
69 SecCertificateVCRef cvc = (SecCertificateVCRef) cf;
70 CFReleaseNull(cvc->certificate);
71 CFReleaseNull(cvc->usageConstraints);
72 }
73
74 static Boolean SecCertificateVCCompare(CFTypeRef cf1, CFTypeRef cf2) {
75 SecCertificateVCRef cv1 = (SecCertificateVCRef) cf1;
76 SecCertificateVCRef cv2 = (SecCertificateVCRef) cf2;
77 if (!CFEqual(cv1->certificate, cv2->certificate)) {
78 return false;
79 }
80 /* CertificateVCs are the same if either does not have usage constraints. */
81 if (cv1->usageConstraints && cv2->usageConstraints &&
82 !CFEqual(cv1->usageConstraints, cv2->usageConstraints)) {
83 return false;
84 }
85
86 return true;
87 }
88
89 static CFHashCode SecCertificateVCHash(CFTypeRef cf) {
90 SecCertificateVCRef cvc = (SecCertificateVCRef) cf;
91 CFHashCode hashCode = 0;
92 hashCode += CFHash(cvc->certificate);
93 if (cvc->usageConstraints) {
94 hashCode += CFHash(cvc->usageConstraints);
95 }
96 return hashCode;
97 }
98
99 static CFStringRef SecCertificateVCCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
100 SecCertificateVCRef cvc = (SecCertificateVCRef)cf;
101 return CFCopyDescription(cvc->certificate);
102 }
103
104 static bool SecCertificateVCCouldBeEV(SecCertificateRef certificate) {
105 CFMutableDictionaryRef keySizes = NULL;
106 CFNumberRef rsaSize = NULL, ecSize = NULL;
107 bool isEV = false;
108
109 /* 3. Subscriber Certificate. */
110
111 /* (a) certificate Policies */
112 const SecCECertificatePolicies *cp;
113 cp = SecCertificateGetCertificatePolicies(certificate);
114 require_quiet(cp && cp->numPolicies > 0, notEV);
115 /* Now find at least one policy in here that has a qualifierID of id-qt 2
116 and a policyQualifier that is a URI to the CPS and an EV policy OID. */
117 uint32_t ix = 0;
118 bool found_ev_anchor_for_leaf_policy = false;
119 for (ix = 0; ix < cp->numPolicies; ++ix) {
120 if (SecPolicyIsEVPolicy(&cp->policies[ix].policyIdentifier)) {
121 found_ev_anchor_for_leaf_policy = true;
122 }
123 }
124 require_quiet(found_ev_anchor_for_leaf_policy, notEV);
125
126 /* (b) cRLDistributionPoint
127 (c) authorityInformationAccess
128 BRv1.3.4: MUST be present with OCSP Responder unless stapled response.
129 */
130
131 /* (d) basicConstraints
132 If present, the cA field MUST be set false. */
133 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate);
134 if (bc) {
135 require_action_quiet(bc->isCA == false, notEV,
136 secnotice("ev", "Leaf has invalid basic constraints"));
137 }
138
139 /* (e) keyUsage. */
140 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate);
141 if (ku) {
142 require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) == 0, notEV,
143 secnotice("ev", "Leaf has invalid key usage %u", ku));
144 }
145
146 #if 0
147 /* The EV Cert Spec errata specifies this, though this is a check for SSL
148 not specifically EV. */
149
150 /* (e) extKeyUsage
151
152 Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */
153 SecCertificateCopyExtendedKeyUsage(certificate);
154 #endif
155
156 /* 6.1.5 Key Sizes */
157 CFAbsoluteTime jan2014 = 410227200;
158 require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV);
159 require_quiet(keySizes = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks,
160 &kCFTypeDictionaryValueCallBacks), notEV);
161 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeEC, ecSize);
162 if (SecCertificateNotValidBefore(certificate) < jan2014) {
163 /* At least RSA 1024 or ECC NIST P-256. */
164 require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 1024), notEV);
165 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize);
166 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
167 secnotice("ev", "Leaf's public key is too small for issuance before 2014"));
168 } else {
169 /* At least RSA 2028 or ECC NIST P-256. */
170 require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV);
171 CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize);
172 require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV,
173 secnotice("ev", "Leaf's public key is too small for issuance after 2013"));
174 }
175
176 /* 6.3.2 Validity Periods */
177 CFAbsoluteTime jul2016 = 489024000;
178 CFAbsoluteTime notAfter = SecCertificateNotValidAfter(certificate);
179 CFAbsoluteTime notBefore = SecCertificateNotValidBefore(certificate);
180 if (SecCertificateNotValidBefore(certificate) < jul2016) {
181 /* Validity Period no greater than 60 months.
182 60 months is no more than 5 years and 2 leap days. */
183 CFAbsoluteTime maxPeriod = 60*60*24*(365*5+2);
184 require_action_quiet(notAfter - notBefore <= maxPeriod, notEV,
185 secnotice("ev", "Leaf's validity period is more than 60 months"));
186 } else {
187 /* Validity Period no greater than 39 months.
188 39 months is no more than 3 years, 2 31-day months,
189 1 30-day month, and 1 leap day */
190 CFAbsoluteTime maxPeriod = 60*60*24*(365*3+2*31+30+1);
191 require_action_quiet(notAfter - notBefore <= maxPeriod, notEV,
192 secnotice("ev", "Leaf has validity period longer than 39 months and issued after 30 June 2016"));
193 }
194
195 /* 7.1.3 Algorithm Object Identifiers */
196 CFAbsoluteTime jan2016 = 473299200;
197 if (SecCertificateNotValidBefore(certificate) > jan2016) {
198 /* SHA-2 only */
199 require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate) > kSecSignatureHashAlgorithmSHA1,
200 notEV, secnotice("ev", "Leaf was issued with SHA-1 after 2015"));
201 }
202
203 isEV = true;
204
205 notEV:
206 CFReleaseNull(rsaSize);
207 CFReleaseNull(ecSize);
208 CFReleaseNull(keySizes);
209 return isEV;
210 }
211
212
213 SecCertificateVCRef SecCertificateVCCreate(SecCertificateRef certificate, CFArrayRef usageConstraints) {
214 if (!certificate) { return NULL; }
215 CFIndex size = sizeof(struct SecCertificateVC);
216 SecCertificateVCRef result =
217 (SecCertificateVCRef)_CFRuntimeCreateInstance(kCFAllocatorDefault,
218 SecCertificateVCGetTypeID(), size - sizeof(CFRuntimeBase), 0);
219 if (!result)
220 return NULL;
221 result->certificate = CFRetainSafe(certificate);
222 result->isWeakHash = SecCertificateIsWeakHash(certificate);
223 result->optionallyEV = SecCertificateVCCouldBeEV(certificate);
224
225 CFArrayRef emptyArray = NULL;
226 if (!usageConstraints) {
227 require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result));
228 usageConstraints = emptyArray;
229 }
230 result->usageConstraints = CFRetainSafe(usageConstraints);
231 exit:
232 CFReleaseNull(emptyArray);
233 return result;
234 }
235
236 // MARK: -
237 // MARK: SecCertificatePathVC
238 /********************************************************
239 ************* SecCertificatePathVC object ***************
240 ********************************************************/
241 struct SecCertificatePathVC {
242 CFRuntimeBase _base;
243 CFIndex count;
244
245 /* Index of next parent source to search for parents. */
246 CFIndex nextParentSource;
247
248 /* Index of last certificate in chain who's signature has been verified.
249 0 means nothing has been checked. 1 means the leaf has been verified
250 against it's issuer, etc. */
251 CFIndex lastVerifiedSigner;
252
253 /* Index of first self issued certificate in the chain. -1 mean there is
254 none. 0 means the leaf is self signed. */
255 CFIndex selfIssued;
256
257 /* True iff cert at index selfIssued does in fact self verify. */
258 bool isSelfSigned;
259
260 /* True if the root of this path is an anchor. Trustedness of the
261 * anchor is determined by the PVC. */
262 bool isAnchored;
263
264 policy_tree_t policy_tree;
265 uint8_t policy_tree_verification_result;
266
267 bool isEV;
268 bool isCT;
269 bool is_allowlisted;
270 bool hasStrongHashes;
271
272 void * rvcs;
273 CFIndex rvcCount;
274
275 /* This is the score of the path after determining acceptance. */
276 CFIndex score;
277
278 bool pathValidated;
279
280 SecCertificateVCRef certificates[];
281 };
282 CFGiblisWithHashFor(SecCertificatePathVC)
283
284 static void SecCertificatePathVCPrunePolicyTree(SecCertificatePathVCRef certificatePath) {
285 if (certificatePath->policy_tree) {
286 policy_tree_prune(&certificatePath->policy_tree);
287 }
288 }
289
290 static void SecCertificatePathVCDeleteRVCs(SecCertificatePathVCRef path) {
291 if (path->rvcs) {
292 CFIndex certIX, certCount = path->rvcCount;
293 for (certIX = 0; certIX < certCount; ++certIX) {
294 SecRVCRef rvc = &((SecRVCRef)path->rvcs)[certIX];
295 SecRVCDelete(rvc);
296 }
297 free(path->rvcs);
298 path->rvcs = NULL;
299 }
300 }
301
302 static void SecCertificatePathVCDestroy(CFTypeRef cf) {
303 SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf;
304 CFIndex ix;
305 SecCertificatePathVCDeleteRVCs(certificatePath);
306 SecCertificatePathVCPrunePolicyTree(certificatePath);
307 for (ix = 0; ix < certificatePath->count; ++ix) {
308 CFReleaseNull(certificatePath->certificates[ix]);
309 }
310 }
311
312 static Boolean SecCertificatePathVCCompare(CFTypeRef cf1, CFTypeRef cf2) {
313 SecCertificatePathVCRef cp1 = (SecCertificatePathVCRef) cf1;
314 SecCertificatePathVCRef cp2 = (SecCertificatePathVCRef) cf2;
315 if (cp1->count != cp2->count)
316 return false;
317 CFIndex ix;
318 for (ix = 0; ix < cp1->count; ++ix) {
319 if (!CFEqual(cp1->certificates[ix], cp2->certificates[ix]))
320 return false;
321 }
322
323 return true;
324 }
325
326 static CFHashCode SecCertificatePathVCHash(CFTypeRef cf) {
327 SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf;
328 CFHashCode hashCode = 0;
329 CFIndex ix;
330 for (ix = 0; ix < certificatePath->count; ++ix) {
331 hashCode += CFHash(certificatePath->certificates[ix]);
332 }
333 return hashCode;
334 }
335
336 static CFStringRef SecCertificatePathVCCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
337 SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf;
338 CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0);
339 CFStringRef typeStr = CFCopyTypeIDDescription(CFGetTypeID(cf));
340 CFStringAppendFormat(desc, NULL,
341 CFSTR("<%@ certs: "), typeStr);
342 CFRelease(typeStr);
343 CFIndex ix;
344 for (ix = 0; ix < certificatePath->count; ++ix) {
345 if (ix > 0) {
346 CFStringAppend(desc, CFSTR(", "));
347 }
348 CFStringRef str = CFCopyDescription(certificatePath->certificates[ix]);
349 CFStringAppend(desc, str);
350 CFRelease(str);
351 }
352 CFStringAppend(desc, CFSTR(" >"));
353
354 return desc;
355 }
356
357 /* Create a new certificate path from an old one. */
358 SecCertificatePathVCRef SecCertificatePathVCCreate(SecCertificatePathVCRef path,
359 SecCertificateRef certificate, CFArrayRef usageConstraints) {
360 CFAllocatorRef allocator = kCFAllocatorDefault;
361 check(certificate);
362 CFIndex count;
363 CFIndex selfIssued, lastVerifiedSigner;
364 bool isSelfSigned;
365 if (path) {
366 count = path->count + 1;
367 lastVerifiedSigner = path->lastVerifiedSigner;
368 selfIssued = path->selfIssued;
369 isSelfSigned = path->isSelfSigned;
370 } else {
371 count = 1;
372 lastVerifiedSigner = 0;
373 selfIssued = -1;
374 isSelfSigned = false;
375 }
376
377 CFIndex size = sizeof(struct SecCertificatePathVC) +
378 count * sizeof(SecCertificateRef);
379 SecCertificatePathVCRef result =
380 (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator,
381 SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0);
382 if (!result)
383 return NULL;
384
385 memset((char*)result + sizeof(result->_base), 0,
386 sizeof(*result) - sizeof(result->_base));
387
388 result->count = count;
389 result->lastVerifiedSigner = lastVerifiedSigner;
390 result->selfIssued = selfIssued;
391 result->isSelfSigned = isSelfSigned;
392 CFIndex ix;
393 for (ix = 0; ix < count - 1; ++ix) {
394 result->certificates[ix] = path->certificates[ix];
395 CFRetain(result->certificates[ix]);
396 }
397
398 SecCertificateVCRef cvc = SecCertificateVCCreate(certificate, usageConstraints);
399 result->certificates[count - 1] = cvc;
400
401 return result;
402 }
403
404 SecCertificatePathVCRef SecCertificatePathVCCopyFromParent(
405 SecCertificatePathVCRef path, CFIndex skipCount) {
406 CFAllocatorRef allocator = kCFAllocatorDefault;
407 CFIndex count;
408 CFIndex selfIssued, lastVerifiedSigner;
409 bool isSelfSigned;
410
411 /* Ensure we are at least returning a path of length 1. */
412 if (skipCount < 0 || path->count < 1 + skipCount)
413 return NULL;
414
415 count = path->count - skipCount;
416 lastVerifiedSigner = path->lastVerifiedSigner > skipCount
417 ? path->lastVerifiedSigner - skipCount : 0;
418 selfIssued = path->selfIssued >= skipCount
419 ? path->selfIssued - skipCount : -1;
420 isSelfSigned = path->selfIssued >= 0 ? path->isSelfSigned : false;
421
422 CFIndex size = sizeof(struct SecCertificatePathVC) +
423 count * sizeof(SecCertificateRef);
424 SecCertificatePathVCRef result =
425 (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator,
426 SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0);
427 if (!result)
428 return NULL;
429
430 memset((char*)result + sizeof(result->_base), 0,
431 sizeof(*result) - sizeof(result->_base));
432
433 result->count = count;
434 result->lastVerifiedSigner = lastVerifiedSigner;
435 result->selfIssued = selfIssued;
436 result->isSelfSigned = isSelfSigned;
437 result->isAnchored = path->isAnchored;
438 CFIndex ix;
439 for (ix = 0; ix < count; ++ix) {
440 CFIndex pathIX = ix + skipCount;
441 result->certificates[ix] = path->certificates[pathIX];
442 CFRetain(result->certificates[ix]);
443 }
444
445 return result;
446 }
447
448 SecCertificatePathVCRef SecCertificatePathVCCopyAddingLeaf(SecCertificatePathVCRef path,
449 SecCertificateRef leaf) {
450 CFAllocatorRef allocator = kCFAllocatorDefault;
451 CFIndex count;
452 CFIndex selfIssued, lastVerifiedSigner;
453 bool isSelfSigned;
454
455 /* First make sure the new leaf is signed by path's current leaf. */
456 SecKeyRef issuerKey = SecCertificatePathVCCopyPublicKeyAtIndex(path, 0);
457 if (!issuerKey)
458 return NULL;
459 OSStatus status = SecCertificateIsSignedBy(leaf, issuerKey);
460 CFRelease(issuerKey);
461 if (status)
462 return NULL;
463
464 count = path->count + 1;
465 lastVerifiedSigner = path->lastVerifiedSigner + 1;
466 selfIssued = path->selfIssued;
467 isSelfSigned = path->isSelfSigned;
468
469 CFIndex size = sizeof(struct SecCertificatePathVC) +
470 count * sizeof(SecCertificateRef);
471 SecCertificatePathVCRef result =
472 (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator,
473 SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0);
474 if (!result)
475 return NULL;
476
477 memset((char*)result + sizeof(result->_base), 0,
478 sizeof(*result) - sizeof(result->_base));
479
480 result->count = count;
481 result->lastVerifiedSigner = lastVerifiedSigner;
482 result->selfIssued = selfIssued;
483 result->isSelfSigned = isSelfSigned;
484 result->isAnchored = path->isAnchored;
485
486 CFIndex ix;
487 for (ix = 1; ix < count; ++ix) {
488 result->certificates[ix] = path->certificates[ix - 1];
489 CFRetain(result->certificates[ix]);
490 }
491 SecCertificateVCRef leafVC = SecCertificateVCCreate(leaf, NULL);
492 result->certificates[0] = leafVC;
493
494 return result;
495 }
496
497 CFArrayRef SecCertificatePathVCCopyCertificates(SecCertificatePathVCRef path) {
498 CFMutableArrayRef outCerts = NULL;
499 size_t count = path->count;
500 require_quiet(outCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit);
501 SecCertificatePathVCForEachCertificate(path, ^(SecCertificateRef cert, bool * __unused stop) {
502 CFArrayAppendValue(outCerts, cert);
503 });
504 exit:
505 return outCerts;
506 }
507
508 SecCertificatePathRef SecCertificatePathVCCopyCertificatePath(SecCertificatePathVCRef path) {
509 CFArrayRef certs = SecCertificatePathVCCopyCertificates(path);
510 SecCertificatePathRef newPath = SecCertificatePathCreateWithCertificates(certs, NULL);
511 CFReleaseNull(certs);
512 return newPath;
513 }
514
515 /* Record the fact that we found our own root cert as our parent
516 certificate. */
517 void SecCertificatePathVCSetSelfIssued(
518 SecCertificatePathVCRef certificatePath) {
519 if (certificatePath->selfIssued >= 0) {
520 secdebug("trust", "%@ is already issued at %" PRIdCFIndex, certificatePath,
521 certificatePath->selfIssued);
522 return;
523 }
524 secdebug("trust", "%@ is self issued", certificatePath);
525 certificatePath->selfIssued = certificatePath->count - 1;
526
527 /* now check that the selfIssued cert was actually self-signed */
528 if (certificatePath->selfIssued >= 0 && !certificatePath->isSelfSigned) {
529 SecCertificateVCRef certVC = certificatePath->certificates[certificatePath->selfIssued];
530 Boolean isSelfSigned = false;
531 OSStatus status = SecCertificateIsSelfSigned(certVC->certificate, &isSelfSigned);
532 if ((status == errSecSuccess) && isSelfSigned) {
533 certificatePath->isSelfSigned = true;
534 } else {
535 certificatePath->selfIssued = -1;
536 }
537 }
538 }
539
540 void SecCertificatePathVCSetIsAnchored(
541 SecCertificatePathVCRef certificatePath) {
542 secdebug("trust", "%@ is anchored", certificatePath);
543 certificatePath->isAnchored = true;
544
545 /* Now check if that anchor (last cert) was actually self-signed.
546 * In the non-anchor case, this is handled by SecCertificatePathVCSetSelfIssued.
547 * Because anchored chains immediately go into the candidate bucket in the trust
548 * server, we need to ensure that the self-signed/self-issued members are set
549 * for the purposes of scoring. */
550 if (!certificatePath->isSelfSigned && certificatePath->count > 0) {
551 SecCertificateVCRef certVC = certificatePath->certificates[certificatePath->count - 1];
552 Boolean isSelfSigned = false;
553 OSStatus status = SecCertificateIsSelfSigned(certVC->certificate, &isSelfSigned);
554 if ((status == errSecSuccess) && isSelfSigned) {
555 certificatePath->isSelfSigned = true;
556 if (certificatePath->selfIssued == -1) {
557 certificatePath->selfIssued = certificatePath->count - 1;
558 }
559 }
560 }
561 }
562
563 /* Return the index of the first non anchor certificate in the chain that is
564 self signed counting from the leaf up. Return -1 if there is none. */
565 CFIndex SecCertificatePathVCSelfSignedIndex(
566 SecCertificatePathVCRef certificatePath) {
567 if (certificatePath->isSelfSigned)
568 return certificatePath->selfIssued;
569 return -1;
570 }
571
572 Boolean SecCertificatePathVCIsAnchored(
573 SecCertificatePathVCRef certificatePath) {
574 return certificatePath->isAnchored;
575 }
576
577
578 void SecCertificatePathVCSetNextSourceIndex(
579 SecCertificatePathVCRef certificatePath, CFIndex sourceIndex) {
580 certificatePath->nextParentSource = sourceIndex;
581 }
582
583 CFIndex SecCertificatePathVCGetNextSourceIndex(
584 SecCertificatePathVCRef certificatePath) {
585 return certificatePath->nextParentSource;
586 }
587
588 CFIndex SecCertificatePathVCGetCount(
589 SecCertificatePathVCRef certificatePath) {
590 check(certificatePath);
591 return certificatePath ? certificatePath->count : 0;
592 }
593
594 SecCertificateRef SecCertificatePathVCGetCertificateAtIndex(
595 SecCertificatePathVCRef certificatePath, CFIndex ix) {
596 check(certificatePath && ix >= 0 && ix < certificatePath->count);
597 return (certificatePath->certificates[ix])->certificate;
598 }
599
600 void SecCertificatePathVCForEachCertificate(SecCertificatePathVCRef path, void(^operation)(SecCertificateRef certificate, bool *stop)) {
601 bool stop = false;
602 CFIndex ix, count = path->count;
603 for (ix = 0; ix < count; ++ix) {
604 SecCertificateVCRef cvc = path->certificates[ix];
605 operation(cvc->certificate, &stop);
606 if (stop) { break; }
607 }
608 }
609
610 CFIndex SecCertificatePathVCGetIndexOfCertificate(SecCertificatePathVCRef path,
611 SecCertificateRef certificate) {
612 CFIndex ix, count = path->count;
613 for (ix = 0; ix < count; ++ix) {
614 SecCertificateVCRef cvc = path->certificates[ix];
615 if (CFEqual(cvc->certificate, certificate))
616 return ix;
617 }
618 return kCFNotFound;
619 }
620
621 /* Return the root certificate for certificatePath. Note that root is just
622 the top of the path as far as it is constructed. It may or may not be
623 trusted or self signed. */
624 SecCertificateRef SecCertificatePathVCGetRoot(
625 SecCertificatePathVCRef certificatePath) {
626 return SecCertificatePathVCGetCertificateAtIndex(certificatePath,
627 SecCertificatePathVCGetCount(certificatePath) - 1);
628 }
629
630 SecKeyRef SecCertificatePathVCCopyPublicKeyAtIndex(
631 SecCertificatePathVCRef certificatePath, CFIndex ix) {
632 SecCertificateRef certificate =
633 SecCertificatePathVCGetCertificateAtIndex(certificatePath, ix);
634 #if TARGET_OS_OSX
635 return SecCertificateCopyPublicKey_ios(certificate);
636 #else
637 return SecCertificateCopyPublicKey(certificate);
638 #endif
639 }
640
641 CFArrayRef SecCertificatePathVCGetUsageConstraintsAtIndex(
642 SecCertificatePathVCRef certificatePath, CFIndex ix) {
643 SecCertificateVCRef cvc = certificatePath->certificates[ix];
644 return cvc->usageConstraints;
645 }
646
647 void SecCertificatePathVCSetUsageConstraintsAtIndex(SecCertificatePathVCRef certificatePath,
648 CFArrayRef newConstraints, CFIndex ix) {
649 CFArrayRef emptyArray = NULL;
650 if (!newConstraints) {
651 require_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit);
652 newConstraints = emptyArray;
653 }
654
655 SecCertificateVCRef cvc = certificatePath->certificates[ix];
656 cvc->usageConstraints = CFRetainSafe(newConstraints);
657 exit:
658 CFReleaseNull(emptyArray);
659 return;
660 }
661
662 SecPathVerifyStatus SecCertificatePathVCVerify(SecCertificatePathVCRef certificatePath) {
663 check(certificatePath);
664 if (!certificatePath)
665 return kSecPathVerifyFailed;
666 for (;
667 certificatePath->lastVerifiedSigner < certificatePath->count - 1;
668 ++certificatePath->lastVerifiedSigner) {
669 SecKeyRef issuerKey =
670 SecCertificatePathVCCopyPublicKeyAtIndex(certificatePath,
671 certificatePath->lastVerifiedSigner + 1);
672 if (!issuerKey)
673 return kSecPathVerifiesUnknown;
674 SecCertificateVCRef cvc = certificatePath->certificates[certificatePath->lastVerifiedSigner];
675 OSStatus status = SecCertificateIsSignedBy(cvc->certificate,
676 issuerKey);
677 CFRelease(issuerKey);
678 if (status) {
679 return kSecPathVerifyFailed;
680 }
681 }
682
683 return kSecPathVerifySuccess;
684 }
685
686 bool SecCertificatePathVCIsValid(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime) {
687 __block bool result = true;
688 SecCertificatePathVCForEachCertificate(certificatePath, ^(SecCertificateRef certificate, bool *stop) {
689 if (!SecCertificateIsValid(certificate, verifyTime)) {
690 result = false;
691 }
692 });
693 return result;
694 }
695
696 bool SecCertificatePathVCHasWeakHash(SecCertificatePathVCRef certificatePath) {
697 CFIndex ix, count = certificatePath->count;
698
699 if (certificatePath->hasStrongHashes) {
700 return false;
701 }
702
703 if (SecCertificatePathVCIsAnchored(certificatePath)) {
704 /* For anchored paths, don't check the hash algorithm of the anchored cert,
705 * since we already decided to trust it. */
706 count--;
707 }
708 for (ix = 0; ix < count; ++ix) {
709 if (certificatePath->certificates[ix]->isWeakHash) {
710 return true;
711 }
712 }
713 certificatePath->hasStrongHashes = true;
714 return false;
715 }
716
717 bool SecCertificatePathVCHasWeakKeySize(SecCertificatePathVCRef certificatePath) {
718 __block CFDictionaryRef keySizes = NULL;
719 CFNumberRef rsaSize = NULL, ecSize = NULL;
720 __block bool result = false;
721
722 /* RSA key sizes are 2048-bit or larger. EC key sizes are P-224 or larger. */
723 require(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), errOut);
724 require(ecSize = CFNumberCreateWithCFIndex(NULL, 224), errOut);
725 const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC };
726 const void *values[] = { rsaSize, ecSize };
727 require(keySizes = CFDictionaryCreate(NULL, keys, values, 2,
728 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
729 SecCertificatePathVCForEachCertificate(certificatePath, ^(SecCertificateRef certificate, bool *stop) {
730 if (!SecCertificateIsAtLeastMinKeySize(certificate, keySizes)) {
731 result = true;
732 *stop = true;
733 }
734 });
735
736 errOut:
737 CFReleaseSafe(keySizes);
738 CFReleaseSafe(rsaSize);
739 CFReleaseSafe(ecSize);
740 return result;
741 }
742
743 /* Return a score for this certificate chain. */
744 CFIndex SecCertificatePathVCScore(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime) {
745 CFIndex score = 0;
746
747 /* Paths that don't verify score terribly.c */
748 if (certificatePath->lastVerifiedSigner != certificatePath->count - 1) {
749 secdebug("trust", "lvs: %" PRIdCFIndex " count: %" PRIdCFIndex,
750 certificatePath->lastVerifiedSigner, certificatePath->count);
751 score -= 100000;
752 }
753
754 if (certificatePath->isAnchored) {
755 /* Anchored paths for the win! */
756 score += 10000;
757 }
758
759 if (certificatePath->isSelfSigned && (certificatePath->selfIssued == certificatePath->count - 1)) {
760 /* Chains that terminate in a self-signed certificate are preferred,
761 even if they don't end in an anchor. */
762 score += 1000;
763 /* Shorter chains ending in a self-signed cert are preferred. */
764 score -= 1 * certificatePath->count;
765 } else {
766 /* Longer chains are preferred when the chain doesn't end in a self-signed cert. */
767 score += 1 * certificatePath->count;
768 }
769
770 if (SecCertificatePathVCIsValid(certificatePath, verifyTime)) {
771 score += 100;
772 }
773
774 if (!SecCertificatePathVCHasWeakHash(certificatePath)) {
775 score += 10;
776 }
777
778 if (!SecCertificatePathVCHasWeakKeySize(certificatePath)) {
779 score += 10;
780 }
781
782 return score;
783 }
784
785 CFIndex SecCertificatePathVCGetScore(SecCertificatePathVCRef certificatePath) {
786 if (!certificatePath) { return 0; }
787 return certificatePath->score;
788 }
789
790 void SecCertificatePathVCSetScore(SecCertificatePathVCRef certificatePath, CFIndex score) {
791 /* We may "score" the same path twice -- if we "accept" a path but then
792 * decide to keep looking for a better one, we we process the same path
793 * again in "reject" which creates a lower score. Don't replace a higher
794 * score with a lower score. Use reset below to post-reject a path. */
795 if (score > certificatePath->score) {
796 certificatePath->score = score;
797 }
798 }
799
800 void SecCertificatePathVCResetScore(SecCertificatePathVCRef certificatePath) {
801 certificatePath->score = 0;
802 }
803
804 void *SecCertificatePathVCGetRVCAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix) {
805 if (ix >= certificatePath->rvcCount) {
806 return NULL;
807 }
808 return &((SecRVCRef)certificatePath->rvcs)[ix];
809 }
810
811 bool SecCertificatePathVCIsRevocationDone(SecCertificatePathVCRef certificatePath) {
812 return (bool)certificatePath->rvcs;
813 }
814
815 void SecCertificatePathVCAllocateRVCs(SecCertificatePathVCRef certificatePath, CFIndex certCount) {
816 certificatePath->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount);
817 certificatePath->rvcCount = certCount;
818 }
819
820 /* Return 0 if any certs revocation checking failed, or the earliest date on
821 which one of the used revocation validation tokens (ocsp response or
822 crl) expires. */
823 /* This function returns 0 to indicate revocation checking was not completed
824 for this certificate chain, otherwise returns the date at which the first
825 piece of revocation checking info we used expires. */
826 CFAbsoluteTime SecCertificatePathVCGetEarliestNextUpdate(SecCertificatePathVCRef path) {
827 CFIndex certIX, certCount = path->count;
828 CFAbsoluteTime enu = NULL_TIME;
829 if (certCount <= 1 || !path->rvcs) {
830 return enu;
831 }
832
833 for (certIX = 0; certIX < path->rvcCount; ++certIX) {
834 SecRVCRef rvc = &((SecRVCRef)path->rvcs)[certIX];
835 CFAbsoluteTime thisCertNextUpdate = SecRVCGetEarliestNextUpdate(rvc);
836 if (thisCertNextUpdate == 0) {
837 if (certIX > 0) {
838 /* We allow for CA certs to not be revocation checked if they
839 have no ocspResponders nor CRLDPs to check against, but the leaf
840 must be checked in order for us to claim we did revocation
841 checking. */
842 SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, rvc->certIX);
843 CFArrayRef ocspResponders = NULL;
844 ocspResponders = SecCertificateGetOCSPResponders(cert);
845 #if ENABLE_CRLS
846 CFArrayRef crlDPs = NULL;
847 crlDPs = SecCertificateGetCRLDistributionPoints(cert);
848 #endif
849 if ((!ocspResponders || CFArrayGetCount(ocspResponders) == 0)
850 #if ENABLE_CRLS
851 && (!crlDPs || CFArrayGetCount(crlDPs) == 0)
852 #endif
853 ) {
854 /* We can't check this cert so we don't consider it a soft
855 failure that we didn't. Ideally we should support crl
856 checking and remove this workaround, since that more
857 strict. */
858 continue;
859 }
860 }
861 secdebug("rvc", "revocation checking soft failure for cert: %ld",
862 certIX);
863 enu = thisCertNextUpdate;
864 break;
865 }
866 if (enu == 0 || thisCertNextUpdate < enu) {
867 enu = thisCertNextUpdate;
868 }
869 }
870
871 secdebug("rvc", "revocation valid until: %lg", enu);
872 return enu;
873 }
874
875 bool SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath,
876 CFIndex ix) {
877 if (ix > certificatePath->count - 1) { return false; }
878 SecCertificateVCRef cvc = certificatePath->certificates[ix];
879 return cvc->require_revocation_response;
880 }
881
882 void SecCertificatePathVCSetRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath,
883 CFIndex ix) {
884 if (ix > certificatePath->count - 1) { return; }
885 SecCertificateVCRef cvc = certificatePath->certificates[ix];
886 cvc->require_revocation_response = true;
887 }
888
889 bool SecCertificatePathVCIsPathValidated(SecCertificatePathVCRef certificatePath) {
890 if (!certificatePath) { return false; }
891 return certificatePath->pathValidated;
892 }
893
894 void SecCertificatePathVCSetPathValidated(SecCertificatePathVCRef certificatePath) {
895 certificatePath->pathValidated = true;
896 }
897
898 bool SecCertificatePathVCIsEV(SecCertificatePathVCRef certificatePath) {
899 if (!certificatePath) { return false; }
900 return certificatePath->isEV;
901 }
902
903 void SecCertificatePathVCSetIsEV(SecCertificatePathVCRef certificatePath, bool isEV) {
904 certificatePath->isEV = isEV;
905 }
906
907 bool SecCertificatePathVCIsOptionallyEV(SecCertificatePathVCRef certificatePath) {
908 if (!certificatePath) { return false; }
909 return certificatePath->certificates[0]->optionallyEV;
910 }
911
912 bool SecCertificatePathVCIsCT(SecCertificatePathVCRef certificatePath) {
913 if (!certificatePath) { return false; }
914 return certificatePath->isCT;
915 }
916
917 void SecCertificatePathVCSetIsCT(SecCertificatePathVCRef certificatePath, bool isCT) {
918 certificatePath->isCT = isCT;
919 }
920
921 bool SecCertificatePathVCIsAllowlisted(SecCertificatePathVCRef certificatePath) {
922 if (!certificatePath) { return false; }
923 return certificatePath->is_allowlisted;
924 }
925
926 void SecCertificatePathVCSetIsAllowlisted(SecCertificatePathVCRef certificatePath, bool isAllowlisted) {
927 certificatePath->is_allowlisted = isAllowlisted;
928 }
929
930 /* MARK: policy_tree path verification */
931 struct policy_tree_add_ctx {
932 oid_t p_oid;
933 policy_qualifier_t p_q;
934 };
935
936 /* 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}. */
937 static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) {
938 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
939 policy_set_t policy_set;
940 for (policy_set = node->expected_policy_set;
941 policy_set;
942 policy_set = policy_set->oid_next) {
943 if (oid_equal(policy_set->oid, info->p_oid)) {
944 policy_tree_add_child(node, &info->p_oid, info->p_q);
945 return true;
946 }
947 }
948 return false;
949 }
950
951 /* 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}. */
952 static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) {
953 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
954 if (oid_equal(node->valid_policy, oidAnyPolicy)) {
955 policy_tree_add_child(node, &info->p_oid, info->p_q);
956 return true;
957 }
958 return false;
959 }
960
961 /* Return true iff node has a child with a valid_policy equal to oid. */
962 static bool policy_tree_has_child_with_oid(policy_tree_t node,
963 const oid_t *oid) {
964 policy_tree_t child;
965 for (child = node->children; child; child = child->siblings) {
966 if (oid_equal(child->valid_policy, (*oid))) {
967 return true;
968 }
969 }
970 return false;
971 }
972
973 /* 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. */
974 static bool policy_tree_add_expected(policy_tree_t node, void *ctx) {
975 policy_qualifier_t p_q = (policy_qualifier_t)ctx;
976 policy_set_t policy_set;
977 bool added_node = false;
978 for (policy_set = node->expected_policy_set;
979 policy_set;
980 policy_set = policy_set->oid_next) {
981 if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) {
982 policy_tree_add_child(node, &policy_set->oid, p_q);
983 added_node = true;
984 }
985 }
986 return added_node;
987 }
988
989 /* 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. */
990 static bool policy_tree_map_if_match(policy_tree_t node, void *ctx) {
991 /* Can't map oidAnyPolicy. */
992 if (oid_equal(node->valid_policy, oidAnyPolicy))
993 return false;
994
995 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
996 size_t mapping_ix, mapping_count = pm->numMappings;
997 policy_set_t policy_set = NULL;
998 /* Generate the policy_set of sdps for matching idp */
999 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1000 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1001 if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
1002 policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set));
1003 p_node->oid = mapping->subjectDomainPolicy;
1004 p_node->oid_next = policy_set ? policy_set : NULL;
1005 policy_set = p_node;
1006 }
1007 }
1008 if (policy_set) {
1009 policy_tree_set_expected_policy(node, policy_set);
1010 return true;
1011 }
1012 return false;
1013 }
1014
1015 /* 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:
1016 (i) set the valid_policy to ID-P;
1017 (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i; and
1018 (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. */
1019 static bool policy_tree_map_if_any(policy_tree_t node, void *ctx) {
1020 if (!oid_equal(node->valid_policy, oidAnyPolicy)) {
1021 return false;
1022 }
1023
1024 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1025 size_t mapping_ix, mapping_count = pm->numMappings;
1026 CFMutableDictionaryRef mappings = NULL;
1027 CFDataRef idp = NULL;
1028 CFDataRef sdp = NULL;
1029 require_quiet(mappings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
1030 &kCFTypeDictionaryValueCallBacks),
1031 errOut);
1032 /* First we need to walk the mappings to generate the dictionary idp->sdps */
1033 for (mapping_ix = 0; mapping_ix < mapping_count; mapping_ix++) {
1034 oid_t issuerDomainPolicy = pm->mappings[mapping_ix].issuerDomainPolicy;
1035 oid_t subjectDomainPolicy = pm->mappings[mapping_ix].subjectDomainPolicy;
1036 idp = CFDataCreateWithBytesNoCopy(NULL, issuerDomainPolicy.data, issuerDomainPolicy.length, kCFAllocatorNull);
1037 sdp = CFDataCreateWithBytesNoCopy(NULL, subjectDomainPolicy.data, subjectDomainPolicy.length, kCFAllocatorNull);
1038 CFMutableArrayRef sdps = (CFMutableArrayRef)CFDictionaryGetValue(mappings, idp);
1039 if (sdps) {
1040 CFArrayAppendValue(sdps, sdp);
1041 } else {
1042 require_quiet(sdps = CFArrayCreateMutable(kCFAllocatorDefault, 0,
1043 &kCFTypeArrayCallBacks), errOut);
1044 CFArrayAppendValue(sdps, sdp);
1045 CFDictionarySetValue(mappings, idp, sdps);
1046 CFRelease(sdps);
1047 }
1048 CFReleaseNull(idp);
1049 CFReleaseNull(sdp);
1050 }
1051
1052 /* Now we use the dictionary to generate the new nodes */
1053 CFDictionaryForEach(mappings, ^(const void *key, const void *value) {
1054 CFDataRef idp = key;
1055 CFArrayRef sdps = value;
1056
1057 /* (i) set the valid_policy to ID-P; */
1058 oid_t p_oid;
1059 p_oid.data = (uint8_t *)CFDataGetBytePtr(idp);
1060 p_oid.length = CFDataGetLength(idp);
1061
1062 /* (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i */
1063 policy_qualifier_t p_q = node->qualifier_set;
1064
1065 /* (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. */
1066 __block policy_set_t p_expected = NULL;
1067 CFArrayForEach(sdps, ^(const void *value) {
1068 policy_set_t p_node = (policy_set_t)malloc(sizeof(*p_expected));
1069 p_node->oid.data = (void *)CFDataGetBytePtr(value);
1070 p_node->oid.length = CFDataGetLength(value);
1071 p_node->oid_next = p_expected ? p_expected : NULL;
1072 p_expected = p_node;
1073 });
1074
1075 policy_tree_add_sibling(node, &p_oid, p_q, p_expected);
1076 });
1077 CFReleaseNull(mappings);
1078 return true;
1079
1080 errOut:
1081 CFReleaseNull(mappings);
1082 CFReleaseNull(idp);
1083 CFReleaseNull(sdp);
1084 return false;
1085 }
1086
1087 static bool policy_tree_map_delete_if_match(policy_tree_t node, void *ctx) {
1088 /* Can't map oidAnyPolicy. */
1089 if (oid_equal(node->valid_policy, oidAnyPolicy))
1090 return false;
1091
1092 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1093 size_t mapping_ix, mapping_count = pm->numMappings;
1094 /* If this node matches any of the idps, delete it. */
1095 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1096 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1097 if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
1098 policy_tree_remove_node(&node);
1099 break;
1100 }
1101 }
1102 return true;
1103 }
1104
1105 bool SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecCertificatePathVCRef path, CFIndex ix) {
1106 /* The SecCertificatePath only tells us the last self-issued cert.
1107 * The chain may have more than one self-issued cert, so we need to
1108 * do the comparison. */
1109 bool result = false;
1110 SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, ix);
1111 CFDataRef issuer = SecCertificateCopyNormalizedIssuerSequence(cert);
1112 CFDataRef subject = SecCertificateCopyNormalizedSubjectSequence(cert);
1113 if (issuer && subject && CFEqual(issuer, subject)) {
1114 result = true;
1115 }
1116 CFReleaseNull(issuer);
1117 CFReleaseNull(subject);
1118 return result;
1119 }
1120
1121 enum {
1122 kSecPolicyTreeVerificationUnknown = 0,
1123 kSecPolicyTreeVerificationFalse,
1124 kSecPolicyTreeVerificationTrue,
1125 };
1126
1127 /* RFC 5280 policy tree processing */
1128 bool SecCertificatePathVCVerifyPolicyTree(SecCertificatePathVCRef path, bool anchor_trusted) {
1129 if (!path) { return false; }
1130 if (path->policy_tree_verification_result != kSecPolicyTreeVerificationUnknown) {
1131 return (path->policy_tree_verification_result == kSecPolicyTreeVerificationTrue);
1132 }
1133
1134 /* Path Validation initialization */
1135 bool result = false;
1136 path->policy_tree_verification_result = kSecPolicyTreeVerificationFalse;
1137 bool initial_policy_mapping_inhibit = false;
1138 bool initial_explicit_policy = false;
1139 bool initial_any_policy_inhibit = false;
1140
1141 SecCertificatePathVCPrunePolicyTree(path);
1142 path->policy_tree = policy_tree_create(&oidAnyPolicy, NULL);
1143
1144 assert((unsigned long)path->count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
1145 uint32_t n = (uint32_t)path->count;
1146 if (anchor_trusted) {
1147 n--;
1148 }
1149
1150 uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1;
1151 uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1;
1152 uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1;
1153
1154 SecCertificateRef cert = NULL;
1155 uint32_t i;
1156 for (i = 1; i <= n; ++i) {
1157 /* Process Cert */
1158 cert = SecCertificatePathVCGetCertificateAtIndex(path, n - i);
1159 bool is_self_issued = SecCertificatePathVCIsCertificateAtIndexSelfIssued(path, n - i);
1160
1161 /* (d) */
1162 if (path->policy_tree) {
1163 const SecCECertificatePolicies *cp =
1164 SecCertificateGetCertificatePolicies(cert);
1165 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1166 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1167 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1168 oid_t p_oid = policy->policyIdentifier;
1169 policy_qualifier_t p_q = &policy->policyQualifiers;
1170 struct policy_tree_add_ctx ctx = { p_oid, p_q };
1171 if (!oid_equal(p_oid, oidAnyPolicy)) {
1172 if (!policy_tree_walk_depth(path->policy_tree, i - 1,
1173 policy_tree_add_if_match, &ctx)) {
1174 policy_tree_walk_depth(path->policy_tree, i - 1,
1175 policy_tree_add_if_any, &ctx);
1176 }
1177 }
1178 }
1179 /* The certificate policies extension includes the policy
1180 anyPolicy with the qualifier set AP-Q and either
1181 (a) inhibit_anyPolicy is greater than 0 or
1182 (b) i < n and the certificate is self-issued. */
1183 if (inhibit_any_policy > 0 || (i < n && is_self_issued)) {
1184 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1185 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1186 oid_t p_oid = policy->policyIdentifier;
1187 policy_qualifier_t p_q = &policy->policyQualifiers;
1188 if (oid_equal(p_oid, oidAnyPolicy)) {
1189 policy_tree_walk_depth(path->policy_tree, i - 1,
1190 policy_tree_add_expected, (void *)p_q);
1191 }
1192 }
1193 }
1194
1195 policy_tree_prune_childless(&path->policy_tree, i - 1);
1196 /* (e) */
1197 if (!cp) {
1198 SecCertificatePathVCPrunePolicyTree(path);
1199 }
1200 }
1201
1202 /* (f) Verify that either explicit_policy is greater than 0 or the
1203 valid_policy_tree is not equal to NULL. */
1204 if (!path->policy_tree && explicit_policy == 0) {
1205 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1206 secnotice("policy", "policy tree failure on cert %u", n - i);
1207 goto errOut;
1208 }
1209 /* If Last Cert in Path */
1210 if (i == n)
1211 break;
1212
1213 /* Prepare for Next Cert */
1214 /* (a) verify that anyPolicy does not appear as an
1215 issuerDomainPolicy or a subjectDomainPolicy */
1216 const SecCEPolicyMappings *pm = SecCertificateGetPolicyMappings(cert);
1217 if (pm && pm->present) {
1218 size_t mapping_ix, mapping_count = pm->numMappings;
1219 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1220 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1221 if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy)
1222 || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) {
1223 /* Policy mapping uses anyPolicy, illegal. */
1224 secnotice("policy", "policy mapping anyPolicy failure %u", n - i);
1225 goto errOut;
1226 }
1227 }
1228
1229 /* (b) */
1230 /* (1) If the policy_mapping variable is greater than 0 */
1231 if (policy_mapping > 0 && path->policy_tree) {
1232 if (!policy_tree_walk_depth(path->policy_tree, i,
1233 policy_tree_map_if_match, (void *)pm)) {
1234 /* 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. */
1235 policy_tree_walk_depth(path->policy_tree, i, policy_tree_map_if_any, (void *)pm);
1236 }
1237 } else if (path->policy_tree) {
1238 /* (i) delete each node of depth i in the valid_policy_tree
1239 where ID-P is the valid_policy. */
1240 policy_tree_walk_depth(path->policy_tree, i,
1241 policy_tree_map_delete_if_match, (void *)pm);
1242 /* (ii) If there is a node in the valid_policy_tree of depth
1243 i-1 or less without any child nodes, delete that
1244 node. Repeat this step until there are no nodes of
1245 depth i-1 or less without children. */
1246 policy_tree_prune_childless(&path->policy_tree, i - 1);
1247 }
1248 }
1249
1250 /* (h) */
1251 if (!is_self_issued) {
1252 if (explicit_policy)
1253 explicit_policy--;
1254 if (policy_mapping)
1255 policy_mapping--;
1256 if (inhibit_any_policy)
1257 inhibit_any_policy--;
1258 }
1259 /* (i) */
1260 const SecCEPolicyConstraints *pc =
1261 SecCertificateGetPolicyConstraints(cert);
1262 if (pc) {
1263 if (pc->requireExplicitPolicyPresent
1264 && pc->requireExplicitPolicy < explicit_policy) {
1265 explicit_policy = pc->requireExplicitPolicy;
1266 }
1267 if (pc->inhibitPolicyMappingPresent
1268 && pc->inhibitPolicyMapping < policy_mapping) {
1269 policy_mapping = pc->inhibitPolicyMapping;
1270 }
1271 }
1272 /* (j) */
1273 const SecCEInhibitAnyPolicy *iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert);
1274 if (iap && iap->skipCerts < inhibit_any_policy) {
1275 inhibit_any_policy = iap->skipCerts;
1276 }
1277
1278 } /* end of path for loop */
1279
1280 /* Wrap up */
1281 cert = SecCertificatePathVCGetCertificateAtIndex(path, 0);
1282 /* (a) */
1283 if (explicit_policy)
1284 explicit_policy--;
1285 /* (b) */
1286 const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert);
1287 if (pc) {
1288 if (pc->requireExplicitPolicyPresent
1289 && pc->requireExplicitPolicy == 0) {
1290 explicit_policy = 0;
1291 }
1292 }
1293
1294 /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
1295
1296 if (path->policy_tree) {
1297 #if !defined(NDEBUG)
1298 policy_tree_dump(path->policy_tree);
1299 #endif
1300 /* (g3c4) */
1301 //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
1302 }
1303
1304 /* If either (1) the value of explicit_policy variable is greater than
1305 zero or (2) the valid_policy_tree is not NULL, then path processing
1306 has succeeded. */
1307 if (!path->policy_tree && explicit_policy == 0) {
1308 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1309 secnotice("policy", "policy tree failure on leaf");
1310 goto errOut;
1311 }
1312
1313 path->policy_tree_verification_result = kSecPolicyTreeVerificationTrue;
1314 result = true;
1315
1316 errOut:
1317 return result;
1318 }