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