]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecCertificateServer.c
Security-58286.41.2.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 /* Is the the issuer of the last cert a subject of a previous cert in the chain.See <rdar://33136765>. */
687 bool SecCertificatePathVCIsCycleInGraph(SecCertificatePathVCRef path) {
688 bool isCircle = false;
689 CFDataRef issuer = SecCertificateGetNormalizedIssuerContent(SecCertificatePathVCGetRoot(path));
690 if (!issuer) { return isCircle; }
691 CFIndex ix = path->count - 2;
692 for (; ix >= 0; ix--) {
693 SecCertificateVCRef cvc = path->certificates[ix];
694 CFDataRef subject = SecCertificateGetNormalizedSubjectContent(cvc->certificate);
695 if (subject && CFEqual(issuer, subject)) {
696 isCircle = true;
697 break;
698 }
699 }
700 return isCircle;
701 }
702
703 bool SecCertificatePathVCIsValid(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime) {
704 __block bool result = true;
705 SecCertificatePathVCForEachCertificate(certificatePath, ^(SecCertificateRef certificate, bool *stop) {
706 if (!SecCertificateIsValid(certificate, verifyTime)) {
707 result = false;
708 }
709 });
710 return result;
711 }
712
713 bool SecCertificatePathVCHasWeakHash(SecCertificatePathVCRef certificatePath) {
714 CFIndex ix, count = certificatePath->count;
715
716 if (certificatePath->hasStrongHashes) {
717 return false;
718 }
719
720 if (SecCertificatePathVCIsAnchored(certificatePath)) {
721 /* For anchored paths, don't check the hash algorithm of the anchored cert,
722 * since we already decided to trust it. */
723 count--;
724 }
725 for (ix = 0; ix < count; ++ix) {
726 if (certificatePath->certificates[ix]->isWeakHash) {
727 return true;
728 }
729 }
730 certificatePath->hasStrongHashes = true;
731 return false;
732 }
733
734 bool SecCertificatePathVCHasWeakKeySize(SecCertificatePathVCRef certificatePath) {
735 __block CFDictionaryRef keySizes = NULL;
736 CFNumberRef rsaSize = NULL, ecSize = NULL;
737 __block bool result = false;
738
739 /* RSA key sizes are 2048-bit or larger. EC key sizes are P-224 or larger. */
740 require(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), errOut);
741 require(ecSize = CFNumberCreateWithCFIndex(NULL, 224), errOut);
742 const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC };
743 const void *values[] = { rsaSize, ecSize };
744 require(keySizes = CFDictionaryCreate(NULL, keys, values, 2,
745 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
746 SecCertificatePathVCForEachCertificate(certificatePath, ^(SecCertificateRef certificate, bool *stop) {
747 if (!SecCertificateIsAtLeastMinKeySize(certificate, keySizes)) {
748 result = true;
749 *stop = true;
750 }
751 });
752
753 errOut:
754 CFReleaseSafe(keySizes);
755 CFReleaseSafe(rsaSize);
756 CFReleaseSafe(ecSize);
757 return result;
758 }
759
760 /* Return a score for this certificate chain. */
761 CFIndex SecCertificatePathVCScore(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime) {
762 CFIndex score = 0;
763
764 /* Paths that don't verify score terribly.c */
765 if (certificatePath->lastVerifiedSigner != certificatePath->count - 1) {
766 secdebug("trust", "lvs: %" PRIdCFIndex " count: %" PRIdCFIndex,
767 certificatePath->lastVerifiedSigner, certificatePath->count);
768 score -= 100000;
769 }
770
771 if (certificatePath->isAnchored) {
772 /* Anchored paths for the win! */
773 score += 10000;
774 }
775
776 if (certificatePath->isSelfSigned && (certificatePath->selfIssued == certificatePath->count - 1)) {
777 /* Chains that terminate in a self-signed certificate are preferred,
778 even if they don't end in an anchor. */
779 score += 1000;
780 /* Shorter chains ending in a self-signed cert are preferred. */
781 score -= 1 * certificatePath->count;
782 } else {
783 /* Longer chains are preferred when the chain doesn't end in a self-signed cert. */
784 score += 1 * certificatePath->count;
785 }
786
787 if (SecCertificatePathVCIsValid(certificatePath, verifyTime)) {
788 score += 100;
789 }
790
791 if (!SecCertificatePathVCHasWeakHash(certificatePath)) {
792 score += 10;
793 }
794
795 if (!SecCertificatePathVCHasWeakKeySize(certificatePath)) {
796 score += 10;
797 }
798
799 return score;
800 }
801
802 CFIndex SecCertificatePathVCGetScore(SecCertificatePathVCRef certificatePath) {
803 if (!certificatePath) { return 0; }
804 return certificatePath->score;
805 }
806
807 void SecCertificatePathVCSetScore(SecCertificatePathVCRef certificatePath, CFIndex score) {
808 /* We may "score" the same path twice -- if we "accept" a path but then
809 * decide to keep looking for a better one, we we process the same path
810 * again in "reject" which creates a lower score. Don't replace a higher
811 * score with a lower score. Use reset below to post-reject a path. */
812 if (score > certificatePath->score) {
813 certificatePath->score = score;
814 }
815 }
816
817 void SecCertificatePathVCResetScore(SecCertificatePathVCRef certificatePath) {
818 certificatePath->score = 0;
819 }
820
821 void *SecCertificatePathVCGetRVCAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix) {
822 if (ix >= certificatePath->rvcCount) {
823 return NULL;
824 }
825 return &((SecRVCRef)certificatePath->rvcs)[ix];
826 }
827
828 bool SecCertificatePathVCIsRevocationDone(SecCertificatePathVCRef certificatePath) {
829 return (bool)certificatePath->rvcs;
830 }
831
832 void SecCertificatePathVCAllocateRVCs(SecCertificatePathVCRef certificatePath, CFIndex certCount) {
833 certificatePath->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount);
834 certificatePath->rvcCount = certCount;
835 }
836
837 /* Return 0 if any certs revocation checking failed, or the earliest date on
838 which one of the used revocation validation tokens (ocsp response or
839 crl) expires. */
840 /* This function returns 0 to indicate revocation checking was not completed
841 for this certificate chain, otherwise returns the date at which the first
842 piece of revocation checking info we used expires. */
843 CFAbsoluteTime SecCertificatePathVCGetEarliestNextUpdate(SecCertificatePathVCRef path) {
844 CFIndex certIX, certCount = path->count;
845 CFAbsoluteTime enu = NULL_TIME;
846 if (certCount <= 1 || !path->rvcs) {
847 return enu;
848 }
849
850 for (certIX = 0; certIX < path->rvcCount; ++certIX) {
851 SecRVCRef rvc = &((SecRVCRef)path->rvcs)[certIX];
852 CFAbsoluteTime thisCertNextUpdate = SecRVCGetEarliestNextUpdate(rvc);
853 if (thisCertNextUpdate == 0) {
854 if (certIX > 0) {
855 /* We allow for CA certs to not be revocation checked if they
856 have no ocspResponders nor CRLDPs to check against, but the leaf
857 must be checked in order for us to claim we did revocation
858 checking. */
859 SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, rvc->certIX);
860 CFArrayRef ocspResponders = NULL;
861 ocspResponders = SecCertificateGetOCSPResponders(cert);
862 #if ENABLE_CRLS
863 CFArrayRef crlDPs = NULL;
864 crlDPs = SecCertificateGetCRLDistributionPoints(cert);
865 #endif
866 if ((!ocspResponders || CFArrayGetCount(ocspResponders) == 0)
867 #if ENABLE_CRLS
868 && (!crlDPs || CFArrayGetCount(crlDPs) == 0)
869 #endif
870 ) {
871 /* We can't check this cert so we don't consider it a soft
872 failure that we didn't. Ideally we should support crl
873 checking and remove this workaround, since that more
874 strict. */
875 continue;
876 }
877 }
878 secdebug("rvc", "revocation checking soft failure for cert: %ld",
879 certIX);
880 enu = thisCertNextUpdate;
881 break;
882 }
883 if (enu == 0 || thisCertNextUpdate < enu) {
884 enu = thisCertNextUpdate;
885 }
886 }
887
888 secdebug("rvc", "revocation valid until: %lg", enu);
889 return enu;
890 }
891
892 bool SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath,
893 CFIndex ix) {
894 if (ix > certificatePath->count - 1) { return false; }
895 SecCertificateVCRef cvc = certificatePath->certificates[ix];
896 return cvc->require_revocation_response;
897 }
898
899 void SecCertificatePathVCSetRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath,
900 CFIndex ix) {
901 if (ix > certificatePath->count - 1) { return; }
902 SecCertificateVCRef cvc = certificatePath->certificates[ix];
903 cvc->require_revocation_response = true;
904 }
905
906 bool SecCertificatePathVCIsPathValidated(SecCertificatePathVCRef certificatePath) {
907 if (!certificatePath) { return false; }
908 return certificatePath->pathValidated;
909 }
910
911 void SecCertificatePathVCSetPathValidated(SecCertificatePathVCRef certificatePath) {
912 certificatePath->pathValidated = true;
913 }
914
915 bool SecCertificatePathVCIsEV(SecCertificatePathVCRef certificatePath) {
916 if (!certificatePath) { return false; }
917 return certificatePath->isEV;
918 }
919
920 void SecCertificatePathVCSetIsEV(SecCertificatePathVCRef certificatePath, bool isEV) {
921 certificatePath->isEV = isEV;
922 }
923
924 bool SecCertificatePathVCIsOptionallyEV(SecCertificatePathVCRef certificatePath) {
925 if (!certificatePath) { return false; }
926 return certificatePath->certificates[0]->optionallyEV;
927 }
928
929 bool SecCertificatePathVCIsCT(SecCertificatePathVCRef certificatePath) {
930 if (!certificatePath) { return false; }
931 return certificatePath->isCT;
932 }
933
934 void SecCertificatePathVCSetIsCT(SecCertificatePathVCRef certificatePath, bool isCT) {
935 certificatePath->isCT = isCT;
936 }
937
938 bool SecCertificatePathVCIsAllowlisted(SecCertificatePathVCRef certificatePath) {
939 if (!certificatePath) { return false; }
940 return certificatePath->is_allowlisted;
941 }
942
943 void SecCertificatePathVCSetIsAllowlisted(SecCertificatePathVCRef certificatePath, bool isAllowlisted) {
944 certificatePath->is_allowlisted = isAllowlisted;
945 }
946
947 /* MARK: policy_tree path verification */
948 struct policy_tree_add_ctx {
949 oid_t p_oid;
950 policy_qualifier_t p_q;
951 };
952
953 /* 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}. */
954 static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) {
955 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
956 policy_set_t policy_set;
957 for (policy_set = node->expected_policy_set;
958 policy_set;
959 policy_set = policy_set->oid_next) {
960 if (oid_equal(policy_set->oid, info->p_oid)) {
961 policy_tree_add_child(node, &info->p_oid, info->p_q);
962 return true;
963 }
964 }
965 return false;
966 }
967
968 /* 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}. */
969 static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) {
970 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx;
971 if (oid_equal(node->valid_policy, oidAnyPolicy)) {
972 policy_tree_add_child(node, &info->p_oid, info->p_q);
973 return true;
974 }
975 return false;
976 }
977
978 /* Return true iff node has a child with a valid_policy equal to oid. */
979 static bool policy_tree_has_child_with_oid(policy_tree_t node,
980 const oid_t *oid) {
981 policy_tree_t child;
982 for (child = node->children; child; child = child->siblings) {
983 if (oid_equal(child->valid_policy, (*oid))) {
984 return true;
985 }
986 }
987 return false;
988 }
989
990 /* 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. */
991 static bool policy_tree_add_expected(policy_tree_t node, void *ctx) {
992 policy_qualifier_t p_q = (policy_qualifier_t)ctx;
993 policy_set_t policy_set;
994 bool added_node = false;
995 for (policy_set = node->expected_policy_set;
996 policy_set;
997 policy_set = policy_set->oid_next) {
998 if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) {
999 policy_tree_add_child(node, &policy_set->oid, p_q);
1000 added_node = true;
1001 }
1002 }
1003 return added_node;
1004 }
1005
1006 /* 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. */
1007 static bool policy_tree_map_if_match(policy_tree_t node, void *ctx) {
1008 /* Can't map oidAnyPolicy. */
1009 if (oid_equal(node->valid_policy, oidAnyPolicy))
1010 return false;
1011
1012 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1013 size_t mapping_ix, mapping_count = pm->numMappings;
1014 policy_set_t policy_set = NULL;
1015 /* Generate the policy_set of sdps for matching idp */
1016 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1017 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1018 if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
1019 policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set));
1020 p_node->oid = mapping->subjectDomainPolicy;
1021 p_node->oid_next = policy_set ? policy_set : NULL;
1022 policy_set = p_node;
1023 }
1024 }
1025 if (policy_set) {
1026 policy_tree_set_expected_policy(node, policy_set);
1027 return true;
1028 }
1029 return false;
1030 }
1031
1032 /* 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:
1033 (i) set the valid_policy to ID-P;
1034 (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i; and
1035 (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. */
1036 static bool policy_tree_map_if_any(policy_tree_t node, void *ctx) {
1037 if (!oid_equal(node->valid_policy, oidAnyPolicy)) {
1038 return false;
1039 }
1040
1041 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1042 size_t mapping_ix, mapping_count = pm->numMappings;
1043 CFMutableDictionaryRef mappings = NULL;
1044 CFDataRef idp = NULL;
1045 CFDataRef sdp = NULL;
1046 require_quiet(mappings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
1047 &kCFTypeDictionaryValueCallBacks),
1048 errOut);
1049 /* First we need to walk the mappings to generate the dictionary idp->sdps */
1050 for (mapping_ix = 0; mapping_ix < mapping_count; mapping_ix++) {
1051 oid_t issuerDomainPolicy = pm->mappings[mapping_ix].issuerDomainPolicy;
1052 oid_t subjectDomainPolicy = pm->mappings[mapping_ix].subjectDomainPolicy;
1053 idp = CFDataCreateWithBytesNoCopy(NULL, issuerDomainPolicy.data, issuerDomainPolicy.length, kCFAllocatorNull);
1054 sdp = CFDataCreateWithBytesNoCopy(NULL, subjectDomainPolicy.data, subjectDomainPolicy.length, kCFAllocatorNull);
1055 CFMutableArrayRef sdps = (CFMutableArrayRef)CFDictionaryGetValue(mappings, idp);
1056 if (sdps) {
1057 CFArrayAppendValue(sdps, sdp);
1058 } else {
1059 require_quiet(sdps = CFArrayCreateMutable(kCFAllocatorDefault, 0,
1060 &kCFTypeArrayCallBacks), errOut);
1061 CFArrayAppendValue(sdps, sdp);
1062 CFDictionarySetValue(mappings, idp, sdps);
1063 CFRelease(sdps);
1064 }
1065 CFReleaseNull(idp);
1066 CFReleaseNull(sdp);
1067 }
1068
1069 /* Now we use the dictionary to generate the new nodes */
1070 CFDictionaryForEach(mappings, ^(const void *key, const void *value) {
1071 CFDataRef idp = key;
1072 CFArrayRef sdps = value;
1073
1074 /* (i) set the valid_policy to ID-P; */
1075 oid_t p_oid;
1076 p_oid.data = (uint8_t *)CFDataGetBytePtr(idp);
1077 p_oid.length = CFDataGetLength(idp);
1078
1079 /* (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i */
1080 policy_qualifier_t p_q = node->qualifier_set;
1081
1082 /* (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. */
1083 __block policy_set_t p_expected = NULL;
1084 CFArrayForEach(sdps, ^(const void *value) {
1085 policy_set_t p_node = (policy_set_t)malloc(sizeof(*p_expected));
1086 p_node->oid.data = (void *)CFDataGetBytePtr(value);
1087 p_node->oid.length = CFDataGetLength(value);
1088 p_node->oid_next = p_expected ? p_expected : NULL;
1089 p_expected = p_node;
1090 });
1091
1092 policy_tree_add_sibling(node, &p_oid, p_q, p_expected);
1093 });
1094 CFReleaseNull(mappings);
1095 return true;
1096
1097 errOut:
1098 CFReleaseNull(mappings);
1099 CFReleaseNull(idp);
1100 CFReleaseNull(sdp);
1101 return false;
1102 }
1103
1104 static bool policy_tree_map_delete_if_match(policy_tree_t node, void *ctx) {
1105 /* Can't map oidAnyPolicy. */
1106 if (oid_equal(node->valid_policy, oidAnyPolicy))
1107 return false;
1108
1109 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx;
1110 size_t mapping_ix, mapping_count = pm->numMappings;
1111 /* If this node matches any of the idps, delete it. */
1112 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1113 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1114 if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) {
1115 policy_tree_remove_node(&node);
1116 break;
1117 }
1118 }
1119 return true;
1120 }
1121
1122 bool SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecCertificatePathVCRef path, CFIndex ix) {
1123 /* The SecCertificatePath only tells us the last self-issued cert.
1124 * The chain may have more than one self-issued cert, so we need to
1125 * do the comparison. */
1126 bool result = false;
1127 SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, ix);
1128 CFDataRef issuer = SecCertificateCopyNormalizedIssuerSequence(cert);
1129 CFDataRef subject = SecCertificateCopyNormalizedSubjectSequence(cert);
1130 if (issuer && subject && CFEqual(issuer, subject)) {
1131 result = true;
1132 }
1133 CFReleaseNull(issuer);
1134 CFReleaseNull(subject);
1135 return result;
1136 }
1137
1138 enum {
1139 kSecPolicyTreeVerificationUnknown = 0,
1140 kSecPolicyTreeVerificationFalse,
1141 kSecPolicyTreeVerificationTrue,
1142 };
1143
1144 /* RFC 5280 policy tree processing */
1145 bool SecCertificatePathVCVerifyPolicyTree(SecCertificatePathVCRef path, bool anchor_trusted) {
1146 if (!path) { return false; }
1147 if (path->policy_tree_verification_result != kSecPolicyTreeVerificationUnknown) {
1148 return (path->policy_tree_verification_result == kSecPolicyTreeVerificationTrue);
1149 }
1150
1151 /* Path Validation initialization */
1152 bool result = false;
1153 path->policy_tree_verification_result = kSecPolicyTreeVerificationFalse;
1154 bool initial_policy_mapping_inhibit = false;
1155 bool initial_explicit_policy = false;
1156 bool initial_any_policy_inhibit = false;
1157
1158 SecCertificatePathVCPrunePolicyTree(path);
1159 path->policy_tree = policy_tree_create(&oidAnyPolicy, NULL);
1160
1161 assert((unsigned long)path->count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
1162 uint32_t n = (uint32_t)path->count;
1163 if (anchor_trusted) {
1164 n--;
1165 }
1166
1167 uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1;
1168 uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1;
1169 uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1;
1170
1171 SecCertificateRef cert = NULL;
1172 uint32_t i;
1173 for (i = 1; i <= n; ++i) {
1174 /* Process Cert */
1175 cert = SecCertificatePathVCGetCertificateAtIndex(path, n - i);
1176 bool is_self_issued = SecCertificatePathVCIsCertificateAtIndexSelfIssued(path, n - i);
1177
1178 /* (d) */
1179 if (path->policy_tree) {
1180 const SecCECertificatePolicies *cp =
1181 SecCertificateGetCertificatePolicies(cert);
1182 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0;
1183 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1184 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1185 oid_t p_oid = policy->policyIdentifier;
1186 policy_qualifier_t p_q = &policy->policyQualifiers;
1187 struct policy_tree_add_ctx ctx = { p_oid, p_q };
1188 if (!oid_equal(p_oid, oidAnyPolicy)) {
1189 if (!policy_tree_walk_depth(path->policy_tree, i - 1,
1190 policy_tree_add_if_match, &ctx)) {
1191 policy_tree_walk_depth(path->policy_tree, i - 1,
1192 policy_tree_add_if_any, &ctx);
1193 }
1194 }
1195 }
1196 /* The certificate policies extension includes the policy
1197 anyPolicy with the qualifier set AP-Q and either
1198 (a) inhibit_anyPolicy is greater than 0 or
1199 (b) i < n and the certificate is self-issued. */
1200 if (inhibit_any_policy > 0 || (i < n && is_self_issued)) {
1201 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) {
1202 const SecCEPolicyInformation *policy = &cp->policies[policy_ix];
1203 oid_t p_oid = policy->policyIdentifier;
1204 policy_qualifier_t p_q = &policy->policyQualifiers;
1205 if (oid_equal(p_oid, oidAnyPolicy)) {
1206 policy_tree_walk_depth(path->policy_tree, i - 1,
1207 policy_tree_add_expected, (void *)p_q);
1208 }
1209 }
1210 }
1211
1212 policy_tree_prune_childless(&path->policy_tree, i - 1);
1213 /* (e) */
1214 if (!cp) {
1215 SecCertificatePathVCPrunePolicyTree(path);
1216 }
1217 }
1218
1219 /* (f) Verify that either explicit_policy is greater than 0 or the
1220 valid_policy_tree is not equal to NULL. */
1221 if (!path->policy_tree && explicit_policy == 0) {
1222 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1223 secnotice("policy", "policy tree failure on cert %u", n - i);
1224 goto errOut;
1225 }
1226 /* If Last Cert in Path */
1227 if (i == n)
1228 break;
1229
1230 /* Prepare for Next Cert */
1231 /* (a) verify that anyPolicy does not appear as an
1232 issuerDomainPolicy or a subjectDomainPolicy */
1233 const SecCEPolicyMappings *pm = SecCertificateGetPolicyMappings(cert);
1234 if (pm && pm->present) {
1235 size_t mapping_ix, mapping_count = pm->numMappings;
1236 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) {
1237 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix];
1238 if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy)
1239 || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) {
1240 /* Policy mapping uses anyPolicy, illegal. */
1241 secnotice("policy", "policy mapping anyPolicy failure %u", n - i);
1242 goto errOut;
1243 }
1244 }
1245
1246 /* (b) */
1247 /* (1) If the policy_mapping variable is greater than 0 */
1248 if (policy_mapping > 0 && path->policy_tree) {
1249 if (!policy_tree_walk_depth(path->policy_tree, i,
1250 policy_tree_map_if_match, (void *)pm)) {
1251 /* 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. */
1252 policy_tree_walk_depth(path->policy_tree, i, policy_tree_map_if_any, (void *)pm);
1253 }
1254 } else if (path->policy_tree) {
1255 /* (i) delete each node of depth i in the valid_policy_tree
1256 where ID-P is the valid_policy. */
1257 policy_tree_walk_depth(path->policy_tree, i,
1258 policy_tree_map_delete_if_match, (void *)pm);
1259 /* (ii) If there is a node in the valid_policy_tree of depth
1260 i-1 or less without any child nodes, delete that
1261 node. Repeat this step until there are no nodes of
1262 depth i-1 or less without children. */
1263 policy_tree_prune_childless(&path->policy_tree, i - 1);
1264 }
1265 }
1266
1267 /* (h) */
1268 if (!is_self_issued) {
1269 if (explicit_policy)
1270 explicit_policy--;
1271 if (policy_mapping)
1272 policy_mapping--;
1273 if (inhibit_any_policy)
1274 inhibit_any_policy--;
1275 }
1276 /* (i) */
1277 const SecCEPolicyConstraints *pc =
1278 SecCertificateGetPolicyConstraints(cert);
1279 if (pc) {
1280 if (pc->requireExplicitPolicyPresent
1281 && pc->requireExplicitPolicy < explicit_policy) {
1282 explicit_policy = pc->requireExplicitPolicy;
1283 }
1284 if (pc->inhibitPolicyMappingPresent
1285 && pc->inhibitPolicyMapping < policy_mapping) {
1286 policy_mapping = pc->inhibitPolicyMapping;
1287 }
1288 }
1289 /* (j) */
1290 const SecCEInhibitAnyPolicy *iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert);
1291 if (iap && iap->skipCerts < inhibit_any_policy) {
1292 inhibit_any_policy = iap->skipCerts;
1293 }
1294
1295 } /* end of path for loop */
1296
1297 /* Wrap up */
1298 cert = SecCertificatePathVCGetCertificateAtIndex(path, 0);
1299 /* (a) */
1300 if (explicit_policy)
1301 explicit_policy--;
1302 /* (b) */
1303 const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert);
1304 if (pc) {
1305 if (pc->requireExplicitPolicyPresent
1306 && pc->requireExplicitPolicy == 0) {
1307 explicit_policy = 0;
1308 }
1309 }
1310
1311 /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */
1312
1313 if (path->policy_tree) {
1314 #if !defined(NDEBUG)
1315 policy_tree_dump(path->policy_tree);
1316 #endif
1317 /* (g3c4) */
1318 //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1);
1319 }
1320
1321 /* If either (1) the value of explicit_policy variable is greater than
1322 zero or (2) the valid_policy_tree is not NULL, then path processing
1323 has succeeded. */
1324 if (!path->policy_tree && explicit_policy == 0) {
1325 /* valid_policy_tree is empty and explicit policy is 0, illegal. */
1326 secnotice("policy", "policy tree failure on leaf");
1327 goto errOut;
1328 }
1329
1330 path->policy_tree_verification_result = kSecPolicyTreeVerificationTrue;
1331 result = true;
1332
1333 errOut:
1334 return result;
1335 }