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