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