]> git.saurik.com Git - apple/security.git/blob - Security/sec/securityd/SecTrustServer.c
Security-57031.1.35.tar.gz
[apple/security.git] / Security / sec / securityd / SecTrustServer.c
1 /*
2 * Copyright (c) 2006-2010,2012-2014 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 * SecTrustServer.c - certificate trust evaluation engine
24 *
25 *
26 */
27
28 #include <securityd/SecTrustServer.h>
29 #include <securityd/SecPolicyServer.h>
30 #include <securityd/SecTrustStoreServer.h>
31 #include <securityd/SecCAIssuerRequest.h>
32 #include <securityd/SecItemServer.h>
33
34 #include <utilities/SecIOFormat.h>
35 #include <utilities/SecDispatchRelease.h>
36
37 #include <Security/SecTrustPriv.h>
38 #include <Security/SecItem.h>
39 #include <Security/SecCertificateInternal.h>
40 #include <Security/SecCertificatePath.h>
41 #include <Security/SecFramework.h>
42 #include <Security/SecPolicyInternal.h>
43 #include <CoreFoundation/CFRuntime.h>
44 #include <CoreFoundation/CFSet.h>
45 #include <CoreFoundation/CFString.h>
46 #include <CoreFoundation/CFNumber.h>
47 #include <CoreFoundation/CFArray.h>
48 #include <CoreFoundation/CFPropertyList.h>
49 #include <AssertMacros.h>
50 #include <stdbool.h>
51 #include <string.h>
52 #include <stdlib.h>
53 #include <limits.h>
54 #include <Security/SecBase.h>
55 #include "SecRSAKey.h"
56 #include <libDER/oids.h>
57 #include <utilities/debugging.h>
58 #include <utilities/SecCFWrappers.h>
59 #include <Security/SecInternal.h>
60 #include <ipc/securityd_client.h>
61 #include <CommonCrypto/CommonDigest.h>
62 #include "OTATrustUtilities.h"
63
64
65 /********************************************************
66 ***************** OTA Trust support ********************
67 ********************************************************/
68
69
70 #ifndef SECITEM_SHIM_OSX
71
72 static CFArrayRef subject_to_anchors(CFDataRef nic);
73 static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets);
74
75 static CFArrayRef subject_to_anchors(CFDataRef nic)
76 {
77 CFArrayRef result = NULL;
78
79 if (NULL == nic)
80 {
81 return result;
82 }
83
84 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
85 if (NULL == otapkiref)
86 {
87 return result;
88 }
89
90 CFDictionaryRef lookupTable = SecOTAPKICopyAnchorLookupTable(otapkiref);
91 CFRelease(otapkiref);
92
93 if (NULL == lookupTable)
94 {
95 return result;
96 }
97
98 unsigned char subject_digest[CC_SHA1_DIGEST_LENGTH];
99 memset(subject_digest, 0, CC_SHA1_DIGEST_LENGTH);
100
101 (void)CC_SHA1(CFDataGetBytePtr(nic), (CC_LONG)CFDataGetLength(nic), subject_digest);
102 CFDataRef sha1Digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subject_digest, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
103
104
105 result = (CFArrayRef)CFDictionaryGetValue(lookupTable, sha1Digest);
106 CFReleaseSafe(lookupTable);
107 CFReleaseSafe(sha1Digest);
108
109 return result;
110 }
111
112 static CFArrayRef CopyCertDataFromIndices(CFArrayRef offsets)
113 {
114 CFMutableArrayRef result = NULL;
115
116 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
117 if (NULL == otapkiref)
118 {
119 return result;
120 }
121
122 const char* anchorTable = SecOTAPKIGetAnchorTable(otapkiref);
123 if (NULL == anchorTable)
124 {
125 CFReleaseSafe(otapkiref);
126 return result;
127 }
128
129 CFIndex num_offsets = CFArrayGetCount(offsets);
130
131 result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
132
133 for (CFIndex idx = 0; idx < num_offsets; idx++)
134 {
135 CFNumberRef offset = (CFNumberRef)CFArrayGetValueAtIndex(offsets, idx);
136 uint32_t offset_value = 0;
137 if (CFNumberGetValue(offset, kCFNumberSInt32Type, &offset_value))
138 {
139 char* pDataPtr = (char *)(anchorTable + offset_value);
140 //int32_t record_length = *((int32_t * )pDataPtr);
141 //record_length = record_length;
142 pDataPtr += sizeof(uint32_t);
143
144 int32_t cert_data_length = *((int32_t * )pDataPtr);
145 pDataPtr += sizeof(uint32_t);
146
147 CFDataRef cert_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)pDataPtr,
148 cert_data_length, kCFAllocatorNull);
149 if (NULL != cert_data)
150 {
151 CFArrayAppendValue(result, cert_data);
152 CFReleaseSafe(cert_data);
153 }
154 }
155 }
156 CFReleaseSafe(otapkiref);
157 return result;
158 }
159
160 static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets)
161 {
162 CFMutableArrayRef result = NULL;
163
164 CFArrayRef cert_data_array = CopyCertDataFromIndices(offsets);
165
166 if (NULL != cert_data_array)
167 {
168 result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
169 CFIndex num_cert_datas = CFArrayGetCount(cert_data_array);
170 for (CFIndex idx = 0; idx < num_cert_datas; idx++)
171 {
172 CFDataRef cert_data = (CFDataRef)CFArrayGetValueAtIndex(cert_data_array, idx);
173 if (NULL != cert_data)
174 {
175 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_data);
176 if (NULL != cert)
177 {
178 CFArrayAppendValue(result, cert);
179 CFRelease(cert);
180 }
181 }
182 }
183 CFRelease(cert_data_array);
184 }
185 return result;
186
187 }
188 #endif
189
190 /********************************************************
191 *************** END OTA Trust support ******************
192 ********************************************************/
193
194 #define MAX_CHAIN_LENGTH 15
195
196 /* Forward declaration for use in SecCertificateSource. */
197 static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents);
198
199
200 // MARK: -
201 // MARK: SecCertificateSource
202 /********************************************************
203 ************ SecCertificateSource object ***************
204 ********************************************************/
205
206 typedef struct SecCertificateSource *SecCertificateSourceRef;
207 typedef void(*SecCertificateSourceParents)(void *, CFArrayRef);
208 typedef bool(*CopyParents)(SecCertificateSourceRef source,
209 SecCertificateRef certificate, void *context, SecCertificateSourceParents);
210 typedef bool(*Contains)(SecCertificateSourceRef source,
211 SecCertificateRef certificate);
212
213 struct SecCertificateSource {
214 CopyParents copyParents;
215 Contains contains;
216 };
217
218 static bool SecCertificateSourceCopyParents(SecCertificateSourceRef source,
219 SecCertificateRef certificate,
220 void *context, SecCertificateSourceParents callback) {
221 return source->copyParents(source, certificate, context, callback);
222 }
223
224 static bool SecCertificateSourceContains(SecCertificateSourceRef source,
225 SecCertificateRef certificate) {
226 return source->contains(source, certificate);
227 }
228
229 // MARK: -
230 // MARK: SecItemCertificateSource
231 /********************************************************
232 *********** SecItemCertificateSource object ************
233 ********************************************************/
234 struct SecItemCertificateSource {
235 struct SecCertificateSource base;
236 CFArrayRef accessGroups;
237 };
238 typedef struct SecItemCertificateSource *SecItemCertificateSourceRef;
239
240 static CFTypeRef SecItemCertificateSourceResultsPost(CFTypeRef raw_results) {
241 if (isArray(raw_results)) {
242 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(raw_results), &kCFTypeArrayCallBacks);
243 CFArrayForEach(raw_results, ^(const void *value) {
244 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, value);
245 if (cert) {
246 CFArrayAppendValue(result, cert);
247 CFRelease(cert);
248 }
249 });
250 return result;
251 } else if (isData(raw_results)) {
252 return SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)raw_results);
253 }
254 return NULL;
255 }
256
257 static bool SecItemCertificateSourceCopyParents(
258 SecCertificateSourceRef source, SecCertificateRef certificate,
259 void *context, SecCertificateSourceParents callback) {
260 SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source;
261 /* FIXME: Search for things other than just subject of our issuer if we
262 have a subjectID or authorityKeyIdentifier. */
263 CFDataRef normalizedIssuer =
264 SecCertificateGetNormalizedIssuerContent(certificate);
265 const void *keys[] = {
266 kSecClass,
267 kSecReturnData,
268 kSecMatchLimit,
269 kSecAttrSubject
270 },
271 *values[] = {
272 kSecClassCertificate,
273 kCFBooleanTrue,
274 kSecMatchLimitAll,
275 normalizedIssuer
276 };
277 CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4,
278 NULL, NULL);
279 CFTypeRef results = NULL;
280 /* We can make this async or run this on a queue now easily. */
281 CFErrorRef localError = NULL;
282 if (!_SecItemCopyMatching(query, msource->accessGroups, &results, &localError)) {
283 if (CFErrorGetCode(localError) != errSecItemNotFound) {
284 secdebug("trust", "_SecItemCopyMatching: %@", localError);
285 }
286 CFRelease(localError);
287 }
288 CFRelease(query);
289 CFTypeRef certs = SecItemCertificateSourceResultsPost(results);
290 CFReleaseSafe(results);
291 callback(context, certs);
292 CFReleaseSafe(certs);
293 return true;
294 }
295
296 static bool SecItemCertificateSourceContains(SecCertificateSourceRef source,
297 SecCertificateRef certificate) {
298 SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source;
299 /* Lookup a certificate by issuer and serial number. */
300 CFDataRef normalizedSubject =
301 SecCertificateGetNormalizedSubjectContent(certificate);
302 CFDataRef serialNumber =
303 SecCertificateCopySerialNumber(certificate);
304 const void *keys[] = {
305 kSecClass,
306 kSecMatchLimit,
307 kSecAttrIssuer,
308 kSecAttrSerialNumber
309 },
310 *values[] = {
311 kSecClassCertificate,
312 kSecMatchLimitOne,
313 normalizedSubject,
314 serialNumber
315 };
316 CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 5,
317 NULL, NULL);
318 CFErrorRef localError = NULL;
319 CFTypeRef results = NULL;
320 bool ok = _SecItemCopyMatching(query, msource->accessGroups, &results, &localError);
321 CFRelease(query);
322 CFRelease(serialNumber);
323 CFReleaseSafe(results);
324 if (!ok) {
325 if (CFErrorGetCode(localError) != errSecItemNotFound) {
326 secdebug("trust", "_SecItemCopyMatching: %@", localError);
327 }
328 CFRelease(localError);
329 return false;
330 }
331 return true;
332 }
333
334 static SecCertificateSourceRef SecItemCertificateSourceCreate(CFArrayRef accessGroups) {
335 SecItemCertificateSourceRef result = (SecItemCertificateSourceRef)malloc(sizeof(*result));
336 result->base.copyParents = SecItemCertificateSourceCopyParents;
337 result->base.contains = SecItemCertificateSourceContains;
338 result->accessGroups = accessGroups;
339 CFRetainSafe(accessGroups);
340 return (SecCertificateSourceRef)result;
341 }
342
343 static void SecItemCertificateSourceDestroy(SecCertificateSourceRef source) {
344 SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source;
345 CFReleaseSafe(msource->accessGroups);
346 free(msource);
347 }
348
349 // MARK: -
350 // MARK: SecSystemAnchorSource
351 /********************************************************
352 *********** SecSystemAnchorSource object ************
353 ********************************************************/
354
355 static bool SecSystemAnchorSourceCopyParents(
356 SecCertificateSourceRef source, SecCertificateRef certificate,
357 void *context, SecCertificateSourceParents callback) {
358 #ifndef SECITEM_SHIM_OSX
359 CFArrayRef parents = NULL;
360 CFArrayRef anchors = NULL;
361 SecOTAPKIRef otapkiref = NULL;
362
363 CFDataRef nic = SecCertificateGetNormalizedIssuerContent(certificate);
364 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
365 It does not matter since we would be returning the wrong anchors */
366 assert((unsigned long)CFDataGetLength(nic)<UINT_MAX); /* Debug check. correct as long as CFIndex is signed long */
367
368 otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
369 require_quiet(otapkiref, errOut);
370 anchors = subject_to_anchors(nic);
371 require_quiet(anchors, errOut);
372 parents = CopyCertsFromIndices(anchors);
373
374 errOut:
375 callback(context, parents);
376 CFReleaseSafe(parents);
377 CFReleaseSafe(otapkiref);
378 #endif
379 return true;
380 }
381
382 /* Quick thought: we can eliminate this method if we search anchor sources
383 before all others and we remember if we got a cert from an anchorsource. */
384 static bool SecSystemAnchorSourceContains(SecCertificateSourceRef source,
385 SecCertificateRef certificate) {
386 bool result = false;
387 #ifndef SECITEM_SHIM_OSX
388 CFArrayRef anchors = NULL;
389 SecOTAPKIRef otapkiref = NULL;
390 CFArrayRef cert_datas = NULL;
391
392 CFDataRef nic = SecCertificateGetNormalizedSubjectContent(certificate);
393 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
394 It does not matter since we would be returning the wrong anchors */
395 assert((unsigned long)CFDataGetLength(nic)<UINT_MAX); /* Debug check. correct as long as CFIndex is signed long */
396
397 otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
398 require_quiet(otapkiref, errOut);
399 anchors = subject_to_anchors(nic);
400 require_quiet(anchors, errOut);
401 cert_datas = CopyCertDataFromIndices(anchors);
402 require_quiet(cert_datas, errOut);
403
404 CFIndex cert_length = SecCertificateGetLength(certificate);
405 const UInt8 *cert_data_ptr = SecCertificateGetBytePtr(certificate);
406
407 CFIndex num_cert_datas = CFArrayGetCount(cert_datas);
408 for (CFIndex idx = 0; idx < num_cert_datas; idx++)
409 {
410 CFDataRef cert_data = (CFDataRef)CFArrayGetValueAtIndex(cert_datas, idx);
411
412 if (NULL != cert_data)
413 {
414 if (CFGetTypeID(cert_data) == CFDataGetTypeID())
415 {
416 CFIndex aCert_Length = CFDataGetLength(cert_data);
417 const UInt8* aCert_Data_Ptr = CFDataGetBytePtr(cert_data);
418
419 if (aCert_Length == cert_length)
420 {
421 if (!memcmp(cert_data_ptr, aCert_Data_Ptr, cert_length))
422 {
423 result = true;
424 break;
425 }
426 }
427 }
428 }
429 }
430
431 errOut:
432 CFReleaseSafe(cert_datas);
433 CFReleaseSafe(otapkiref);
434 #endif
435 return result;
436 }
437
438
439
440 struct SecCertificateSource kSecSystemAnchorSource = {
441 SecSystemAnchorSourceCopyParents,
442 SecSystemAnchorSourceContains
443 };
444
445 // MARK: -
446 // MARK: SecUserAnchorSource
447 /********************************************************
448 *********** SecUserAnchorSource object ************
449 ********************************************************/
450 static bool SecUserAnchorSourceCopyParents(
451 SecCertificateSourceRef source, SecCertificateRef certificate,
452 void *context, SecCertificateSourceParents callback) {
453 CFArrayRef parents = SecTrustStoreCopyParents(
454 SecTrustStoreForDomain(kSecTrustStoreDomainUser), certificate, NULL);
455 callback(context, parents);
456 CFReleaseSafe(parents);
457 return true;
458 }
459
460 static bool SecUserAnchorSourceContains(SecCertificateSourceRef source,
461 SecCertificateRef certificate) {
462 return SecTrustStoreContains(
463 SecTrustStoreForDomain(kSecTrustStoreDomainUser), certificate);
464 }
465
466 struct SecCertificateSource kSecUserAnchorSource = {
467 SecUserAnchorSourceCopyParents,
468 SecUserAnchorSourceContains
469 };
470
471 // MARK: -
472 // MARK: SecMemoryCertificateSource
473 /********************************************************
474 *********** SecMemoryCertificateSource object ************
475 ********************************************************/
476 struct SecMemoryCertificateSource {
477 struct SecCertificateSource base;
478 CFMutableSetRef certificates;
479 CFMutableDictionaryRef subjects;
480 };
481 typedef struct SecMemoryCertificateSource *SecMemoryCertificateSourceRef;
482
483 static bool SecMemoryCertificateSourceCopyParents(
484 SecCertificateSourceRef source, SecCertificateRef certificate,
485 void *context, SecCertificateSourceParents callback) {
486 SecMemoryCertificateSourceRef msource =
487 (SecMemoryCertificateSourceRef)source;
488 CFDataRef normalizedIssuer =
489 SecCertificateGetNormalizedIssuerContent(certificate);
490 CFArrayRef parents = CFDictionaryGetValue(msource->subjects,
491 normalizedIssuer);
492 /* FIXME filter parents by subjectID if certificate has an
493 authorityKeyIdentifier. */
494 secdebug("trust", "%@ parents -> %@", certificate, parents);
495 callback(context, parents);
496 return true;
497 }
498
499 static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source,
500 SecCertificateRef certificate) {
501 SecMemoryCertificateSourceRef msource =
502 (SecMemoryCertificateSourceRef)source;
503 return CFSetContainsValue(msource->certificates, certificate);
504 }
505
506 static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict,
507 const void *key, const void *value) {
508 if (!key)
509 return;
510
511 CFMutableArrayRef values =
512 (CFMutableArrayRef)CFDictionaryGetValue(dict, key);
513 if (!values) {
514 values = CFArrayCreateMutable(kCFAllocatorDefault, 0,
515 &kCFTypeArrayCallBacks);
516 CFDictionaryAddValue(dict, key, values);
517 CFRelease(values);
518 }
519
520 if (values)
521 CFArrayAppendValue(values, value);
522 }
523
524 static void SecMemoryCertificateSourceApplierFunction(const void *value,
525 void *context) {
526 SecMemoryCertificateSourceRef msource =
527 (SecMemoryCertificateSourceRef)context;
528 SecCertificateRef certificate = (SecCertificateRef)value;
529
530 /* CFSet's API has no way to combine these 2 operations into 1 sadly. */
531 if (CFSetContainsValue(msource->certificates, certificate))
532 return;
533 CFSetAddValue(msource->certificates, certificate);
534
535 CFDataRef key = SecCertificateGetNormalizedSubjectContent(certificate);
536 dictAddValueToArrayForKey(msource->subjects, key, value);
537 }
538
539 static SecCertificateSourceRef SecMemoryCertificateSourceCreate(
540 CFArrayRef certificates) {
541 SecMemoryCertificateSourceRef result = (SecMemoryCertificateSourceRef)
542 malloc(sizeof(*result));
543 result->base.copyParents = SecMemoryCertificateSourceCopyParents;
544 result->base.contains = SecMemoryCertificateSourceContains;
545 CFIndex count = CFArrayGetCount(certificates);
546 result->certificates = CFSetCreateMutable(kCFAllocatorDefault, count,
547 &kCFTypeSetCallBacks);
548 result->subjects = CFDictionaryCreateMutable(kCFAllocatorDefault,
549 count, &kCFTypeDictionaryKeyCallBacks,
550 &kCFTypeDictionaryValueCallBacks);
551 CFRange range = { 0, count };
552 CFArrayApplyFunction(certificates, range,
553 SecMemoryCertificateSourceApplierFunction, result);
554
555 return (SecCertificateSourceRef)result;
556 }
557
558 static void SecMemoryCertificateSourceDestroy(
559 SecCertificateSourceRef source) {
560 SecMemoryCertificateSourceRef msource =
561 (SecMemoryCertificateSourceRef)source;
562 CFRelease(msource->certificates);
563 CFRelease(msource->subjects);
564 free(msource);
565 }
566
567 // MARK: -
568 // MARK: SecCAIssuerCertificateSource
569 /********************************************************
570 ********* SecCAIssuerCertificateSource object **********
571 ********************************************************/
572 static bool SecCAIssuerCertificateSourceCopyParents(
573 SecCertificateSourceRef source, SecCertificateRef certificate,
574 void *context, SecCertificateSourceParents callback) {
575 return SecCAIssuerCopyParents(certificate, SecPathBuilderGetQueue((SecPathBuilderRef)context), context, callback);
576 }
577
578 static bool SecCAIssuerCertificateSourceContains(
579 SecCertificateSourceRef source, SecCertificateRef certificate) {
580 return false;
581 }
582
583 struct SecCertificateSource kSecCAIssuerSource = {
584 SecCAIssuerCertificateSourceCopyParents,
585 SecCAIssuerCertificateSourceContains
586 };
587
588 // MARK: -
589 // MARK: SecPathBuilder
590 /********************************************************
591 *************** SecPathBuilder object ******************
592 ********************************************************/
593 struct SecPathBuilder {
594 dispatch_queue_t queue;
595 SecCertificateSourceRef certificateSource;
596 SecCertificateSourceRef itemCertificateSource;
597 SecCertificateSourceRef anchorSource;
598 CFMutableArrayRef anchorSources;
599 CFIndex nextParentSource;
600 CFMutableArrayRef parentSources;
601
602 /* Hashed set of all paths we've constructed so far, used to prevent
603 re-considering a path that was already constructed once before.
604 Note that this is the only container in which certificatePath
605 objects are retained.
606 Every certificatePath being considered is always in allPaths and in at
607 most one of partialPaths, rejectedPaths, candidatePath or extendedPaths
608 all of which don't retain their values. */
609 CFMutableSetRef allPaths;
610
611 /* No trusted anchor, satisfies the linking to intermediates for all
612 policies (unless considerRejected is true). */
613 CFMutableArrayRef partialPaths;
614 /* No trusted anchor, does not satisfy linking to intermediates for all
615 policies. */
616 CFMutableArrayRef rejectedPaths;
617 /* Trusted anchor, satisfies the policies so far. */
618 CFMutableArrayRef candidatePaths;
619
620 CFIndex partialIX;
621
622 CFArrayRef leafDetails;
623
624 CFIndex rejectScore;
625
626 bool considerRejected;
627 bool considerPartials;
628 bool canAccessNetwork;
629
630 struct OpaqueSecPVC path;
631 SecCertificatePathRef bestPath;
632 bool bestPathIsEV;
633
634 CFIndex activations;
635 bool (*state)(SecPathBuilderRef);
636 SecPathBuilderCompleted completed;
637 const void *context;
638 };
639
640 /* State functions. Return false if a async job was scheduled, return
641 true to execute the next state. */
642 static bool SecPathBuilderGetNext(SecPathBuilderRef builder);
643 static bool SecPathBuilderValidatePath(SecPathBuilderRef builder);
644 static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder);
645 static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder);
646 static bool SecPathBuilderReportResult(SecPathBuilderRef builder);
647
648 /* Forward declarations. */
649 static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder,
650 SecCertificateRef certificate);
651
652 /* IDEA: policies could be made cabable of replacing incoming anchors and
653 anchorsOnly argument values. For example some policies require the
654 Apple Inc. CA and not any other anchor. This can be done in
655 SecPathBuilderLeafCertificateChecks since this only runs once. */
656 static void SecPathBuilderLeafCertificateChecks(SecPathBuilderRef builder,
657 SecCertificatePathRef path) {
658 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(
659 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
660 &kCFTypeDictionaryValueCallBacks);
661 builder->leafDetails = CFArrayCreate(kCFAllocatorDefault,
662 (const void **)&certDetail, 1, &kCFTypeArrayCallBacks);
663 CFRelease(certDetail);
664 SecPVCRef pvc = &builder->path;
665 SecPVCSetPath(pvc, path, builder->leafDetails);
666 builder->considerRejected = !SecPVCLeafChecks(pvc);
667 }
668
669 static void SecPathBuilderInit(SecPathBuilderRef builder,
670 CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly,
671 CFArrayRef policies, CFAbsoluteTime verifyTime, CFArrayRef accessGroups,
672 SecPathBuilderCompleted completed, const void *context) {
673 secdebug("alloc", "%p", builder);
674 CFAllocatorRef allocator = kCFAllocatorDefault;
675
676 builder->queue = dispatch_queue_create("builder", DISPATCH_QUEUE_SERIAL);
677
678 builder->nextParentSource = 1;
679 builder->considerPartials = false;
680 builder->canAccessNetwork = true;
681
682 builder->anchorSources = CFArrayCreateMutable(allocator, 0, NULL);
683 builder->parentSources = CFArrayCreateMutable(allocator, 0, NULL);
684 builder->allPaths = CFSetCreateMutable(allocator, 0,
685 &kCFTypeSetCallBacks);
686
687 builder->partialPaths = CFArrayCreateMutable(allocator, 0, NULL);
688 builder->rejectedPaths = CFArrayCreateMutable(allocator, 0, NULL);
689 builder->candidatePaths = CFArrayCreateMutable(allocator, 0, NULL);
690 builder->partialIX = 0;
691
692 /* Init the policy verification context. */
693 SecPVCInit(&builder->path, builder, policies, verifyTime);
694 builder->bestPath = NULL;
695 builder->bestPathIsEV = false;
696 builder->rejectScore = 0;
697
698 /* Let's create all the certificate sources we might want to use. */
699 builder->certificateSource =
700 SecMemoryCertificateSourceCreate(certificates);
701 if (anchors)
702 builder->anchorSource = SecMemoryCertificateSourceCreate(anchors);
703 else
704 builder->anchorSource = NULL;
705
706 /* We always search certificateSource for parents since it includes the
707 leaf itself and it might be self signed. */
708 CFArrayAppendValue(builder->parentSources, builder->certificateSource);
709 if (builder->anchorSource) {
710 CFArrayAppendValue(builder->anchorSources, builder->anchorSource);
711 }
712 builder->itemCertificateSource = SecItemCertificateSourceCreate(accessGroups);
713 CFArrayAppendValue(builder->parentSources, builder->itemCertificateSource);
714 if (anchorsOnly) {
715 /* Add the system and user anchor certificate db to the search list
716 if we don't explicitly trust them. */
717 CFArrayAppendValue(builder->parentSources, &kSecSystemAnchorSource);
718 CFArrayAppendValue(builder->parentSources, &kSecUserAnchorSource);
719 } else {
720 /* Only add the system and user anchor certificate db to the
721 anchorSources if we are supposed to trust them. */
722 CFArrayAppendValue(builder->anchorSources, &kSecSystemAnchorSource);
723 CFArrayAppendValue(builder->anchorSources, &kSecUserAnchorSource);
724 }
725 CFArrayAppendValue(builder->parentSources, &kSecCAIssuerSource);
726
727 /* Now let's get the leaf cert and turn it into a path. */
728 SecCertificateRef leaf =
729 (SecCertificateRef)CFArrayGetValueAtIndex(certificates, 0);
730 SecCertificatePathRef path = SecCertificatePathCreate(NULL, leaf);
731 CFSetAddValue(builder->allPaths, path);
732 CFArrayAppendValue(builder->partialPaths, path);
733 if (SecPathBuilderIsAnchor(builder, leaf)) {
734 SecCertificatePathSetIsAnchored(path);
735 CFArrayAppendValue(builder->candidatePaths, path);
736 }
737 SecPathBuilderLeafCertificateChecks(builder, path);
738 CFRelease(path);
739
740 builder->activations = 0;
741 builder->state = SecPathBuilderGetNext;
742 builder->completed = completed;
743 builder->context = context;
744 }
745
746 SecPathBuilderRef SecPathBuilderCreate(CFArrayRef certificates,
747 CFArrayRef anchors, bool anchorsOnly, CFArrayRef policies,
748 CFAbsoluteTime verifyTime, CFArrayRef accessGroups,
749 SecPathBuilderCompleted completed, const void *context) {
750 SecPathBuilderRef builder = malloc(sizeof(*builder));
751 SecPathBuilderInit(builder, certificates, anchors, anchorsOnly,
752 policies, verifyTime, accessGroups, completed, context);
753 return builder;
754 }
755
756 static void SecPathBuilderDestroy(SecPathBuilderRef builder) {
757 secdebug("alloc", "%p", builder);
758 dispatch_release_null(builder->queue);
759 if (builder->anchorSource)
760 SecMemoryCertificateSourceDestroy(builder->anchorSource);
761 if (builder->certificateSource)
762 SecMemoryCertificateSourceDestroy(builder->certificateSource);
763 if (builder->itemCertificateSource)
764 SecItemCertificateSourceDestroy(builder->itemCertificateSource);
765 CFReleaseSafe(builder->anchorSources);
766 CFReleaseSafe(builder->parentSources);
767 CFReleaseSafe(builder->allPaths);
768 CFReleaseSafe(builder->partialPaths);
769 CFReleaseSafe(builder->rejectedPaths);
770 CFReleaseSafe(builder->candidatePaths);
771 CFReleaseSafe(builder->leafDetails);
772
773 SecPVCDelete(&builder->path);
774 }
775
776 bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder) {
777 return builder->canAccessNetwork;
778 }
779
780 void SecPathBuilderSetCanAccessNetwork(SecPathBuilderRef builder, bool allow) {
781 if (builder->canAccessNetwork != allow) {
782 builder->canAccessNetwork = allow;
783 if (allow) {
784 secdebug("http", "network access re-enabled by policy");
785 /* re-enabling network_access re-adds kSecCAIssuerSource as
786 a parent source. */
787 CFArrayAppendValue(builder->parentSources, &kSecCAIssuerSource);
788 } else {
789 secdebug("http", "network access disabled by policy");
790 /* disabling network_access removes kSecCAIssuerSource from
791 the list of parent sources. */
792 CFIndex ix = CFArrayGetFirstIndexOfValue(builder->parentSources,
793 CFRangeMake(0, CFArrayGetCount(builder->parentSources)),
794 &kSecCAIssuerSource);
795 if (ix >= 0)
796 CFArrayRemoveValueAtIndex(builder->parentSources, ix);
797 }
798 }
799 }
800
801 static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder,
802 SecCertificateRef certificate) {
803 /* We always look through all anchor sources. */
804 CFIndex count = CFArrayGetCount(builder->anchorSources);
805 CFIndex ix;
806 for (ix = 0; ix < count; ++ix) {
807 SecCertificateSourceRef source = (SecCertificateSourceRef)
808 CFArrayGetValueAtIndex(builder->anchorSources, ix);
809 if (SecCertificateSourceContains(source, certificate)) {
810 return true;
811 }
812 }
813 return false;
814 }
815
816 /* Return false if path is not a partial, if path was a valid candidate it
817 will have been added to builder->candidatePaths, if path was rejected
818 by the parent certificate checks (because it's expired or some other
819 static chaining check failed) it will have been added to rejectedPaths.
820 Return true path if path is a partial. */
821 static bool SecPathBuilderIsPartial(SecPathBuilderRef builder,
822 SecCertificatePathRef path) {
823 SecPVCRef pvc = &builder->path;
824 SecPVCSetPath(pvc, path, NULL);
825
826 if (!builder->considerRejected && !SecPVCParentCertificateChecks(pvc,
827 SecPVCGetCertificateCount(pvc) - 1)) {
828 secdebug("trust", "Found rejected path %@", path);
829 CFArrayAppendValue(builder->rejectedPaths, path);
830 return false;
831 }
832
833 SecPathVerifyStatus vstatus = SecCertificatePathVerify(path);
834 /* Candidate paths with failed signatures are discarded. */
835 if (vstatus == kSecPathVerifyFailed) {
836 secdebug("trust", "Verify failed for path %@", path);
837 return false;
838 }
839
840 if (vstatus == kSecPathVerifySuccess) {
841 /* The signature chain verified sucessfully, now let's find
842 out if we have an anchor for path. */
843 if (SecCertificatePathIsAnchored(path)) {
844 secdebug("trust", "Adding candidate %@", path);
845 CFArrayAppendValue(builder->candidatePaths, path);
846 return false;
847 }
848 }
849
850 return true;
851 }
852
853 /* Given the builder, a partial chain partial and the parents array, construct
854 a SecCertificatePath for each parent. After discarding previously
855 considered paths and paths with cycles, sort out which array each path
856 should go in, if any. */
857 static void SecPathBuilderProccessParents(SecPathBuilderRef builder,
858 SecCertificatePathRef partial, CFArrayRef parents) {
859 CFIndex rootIX = SecCertificatePathGetCount(partial) - 1;
860 CFIndex num_parents = parents ? CFArrayGetCount(parents) : 0;
861 CFIndex parentIX;
862 bool is_anchor = SecCertificatePathGetNextSourceIndex(partial) <=
863 CFArrayGetCount(builder->anchorSources);
864 secdebug("trust", "found %" PRIdCFIndex " candidate %s", num_parents,
865 (is_anchor ? "anchors" : "parents"));
866 for (parentIX = 0; parentIX < num_parents; ++parentIX) {
867 SecCertificateRef parent = (SecCertificateRef)
868 CFArrayGetValueAtIndex(parents, parentIX);
869 CFIndex ixOfParent = SecCertificatePathGetIndexOfCertificate(partial,
870 parent);
871 if (ixOfParent != kCFNotFound) {
872 /* partial already contains parent. Let's not add the same
873 certificate again. */
874 if (ixOfParent == rootIX) {
875 /* parent is equal to the root of the partial, so partial
876 looks to be self issued. */
877 SecCertificatePathSetSelfIssued(partial);
878 }
879 continue;
880 }
881
882 /* FIXME Add more sanity checks to see that parent really can be
883 a parent of partial_root. subjectKeyID == authorityKeyID,
884 signature algorithm matches public key algorithm, etc. */
885 SecCertificatePathRef path = SecCertificatePathCreate(partial, parent);
886 if (!path)
887 continue;
888 if (!CFSetContainsValue(builder->allPaths, path)) {
889 CFSetAddValue(builder->allPaths, path);
890 if (is_anchor)
891 SecCertificatePathSetIsAnchored(path);
892 if (SecPathBuilderIsPartial(builder, path)) {
893 /* Insert path right at the current position since it's a new
894 candiate partial. */
895 CFArrayInsertValueAtIndex(builder->partialPaths,
896 ++builder->partialIX, path);
897 secdebug("trust", "Adding partial for parent %" PRIdCFIndex "/%" PRIdCFIndex " %@",
898 parentIX + 1, num_parents, path);
899 }
900 secdebug("trust", "found new path %@", path);
901 }
902 CFRelease(path);
903 }
904 }
905
906 /* Callback for the SecPathBuilderGetNext() functions call to
907 SecCertificateSourceCopyParents(). */
908 static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents) {
909 SecPathBuilderRef builder = (SecPathBuilderRef)context;
910 SecCertificatePathRef partial = (SecCertificatePathRef)
911 CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX);
912 secdebug("async", "%@ parents %@", partial, parents);
913 SecPathBuilderProccessParents(builder, partial, parents);
914
915 builder->state = SecPathBuilderGetNext;
916 SecPathBuilderStep(builder);
917 }
918
919 static bool SecPathBuilderGetNext(SecPathBuilderRef builder) {
920 /* If we have any candidates left to go return those first. */
921 if (CFArrayGetCount(builder->candidatePaths)) {
922 SecCertificatePathRef path = (SecCertificatePathRef)
923 CFArrayGetValueAtIndex(builder->candidatePaths, 0);
924 CFArrayRemoveValueAtIndex(builder->candidatePaths, 0);
925 secdebug("trust", "SecPathBuilderGetNext returning candidate %@",
926 path);
927 SecPVCSetPath(&builder->path, path, NULL);
928 builder->state = SecPathBuilderValidatePath;
929 return true;
930 }
931
932 /* If we are considering rejected chains we check each rejected path
933 with SecPathBuilderIsPartial() which checks the signature chain and
934 either drops the path if it's not properly signed, add it as a
935 candidate if it has a trusted anchor, or adds it as a partial
936 to be considered once we finish considering all the rejects. */
937 if (builder->considerRejected) {
938 CFIndex rejectedIX = CFArrayGetCount(builder->rejectedPaths);
939 if (rejectedIX) {
940 rejectedIX--;
941 SecCertificatePathRef path = (SecCertificatePathRef)
942 CFArrayGetValueAtIndex(builder->rejectedPaths, rejectedIX);
943 if (SecPathBuilderIsPartial(builder, path)) {
944 CFArrayInsertValueAtIndex(builder->partialPaths,
945 ++builder->partialIX, path);
946 }
947 CFArrayRemoveValueAtIndex(builder->rejectedPaths, rejectedIX);
948
949 /* Keep going until we have moved all rejected partials into
950 the regular partials or candidates array. */
951 return true;
952 }
953 }
954
955 /* If builder->partialIX is < 0 we have considered all partial chains
956 this block must ensure partialIX >= 0 if execution continues past
957 it's end. */
958 if (builder->partialIX < 0) {
959 CFIndex num_sources = CFArrayGetCount(builder->parentSources);
960 if (builder->nextParentSource < num_sources) {
961 builder->nextParentSource++;
962 secdebug("trust", "broading search to %" PRIdCFIndex "/%" PRIdCFIndex " sources",
963 builder->nextParentSource, num_sources);
964 } else {
965 /* We've run out of new sources to consider so let's look at
966 rejected chains and after that even consider partials
967 directly.
968 FIXME we might not want to consider partial paths that
969 are subsets of other partial paths, or not consider them
970 at all if we already have an anchored reject. */
971 if (!builder->considerRejected) {
972 builder->considerRejected = true;
973 secdebug("trust", "considering rejected paths");
974 } else if (!builder->considerPartials) {
975 builder->considerPartials = true;
976 secdebug("trust", "considering partials");
977 } else {
978 /* We're all out of options, so we can't produce any more
979 candidates. Let's calculate details and return the best
980 path we found. */
981 builder->state = SecPathBuilderComputeDetails;
982 return true;
983 }
984 }
985 builder->partialIX = CFArrayGetCount(builder->partialPaths) - 1;
986 secdebug("trust", "re-checking %" PRIdCFIndex " partials", builder->partialIX + 1);
987 return true;
988 }
989
990 /* We know builder->partialIX >= 0 if we get here. */
991 SecCertificatePathRef partial = (SecCertificatePathRef)
992 CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX);
993 /* Don't try to extend partials anymore once we are in the considerPartials
994 state, since at this point every partial has been extended with every
995 possible parentSource already. */
996 if (builder->considerPartials) {
997 --builder->partialIX;
998 SecPVCSetPath(&builder->path, partial, NULL);
999 builder->state = SecPathBuilderValidatePath;
1000 return true;
1001 }
1002
1003 /* Attempt to extend this partial path with another certificate. This
1004 should give us a list of potential parents to consider. */
1005 secdebug("trust", "looking for parents of partial %" PRIdCFIndex "/%" PRIdCFIndex ": %@",
1006 builder->partialIX + 1, CFArrayGetCount(builder->partialPaths),
1007 partial);
1008
1009 /* Attempt to extend partial, leaving all possible extended versions
1010 of partial in builder->extendedPaths. */
1011 CFIndex sourceIX = SecCertificatePathGetNextSourceIndex(partial);
1012 CFIndex num_anchor_sources = CFArrayGetCount(builder->anchorSources);
1013 if (sourceIX < num_anchor_sources + builder->nextParentSource) {
1014 SecCertificateSourceRef source;
1015 if (sourceIX < num_anchor_sources) {
1016 source = (SecCertificateSourceRef)
1017 CFArrayGetValueAtIndex(builder->anchorSources, sourceIX);
1018 secdebug("trust", "searching anchor source %" PRIdCFIndex "/%" PRIdCFIndex, sourceIX + 1,
1019 num_anchor_sources);
1020 } else {
1021 CFIndex parentIX = sourceIX - num_anchor_sources;
1022 source = (SecCertificateSourceRef)
1023 CFArrayGetValueAtIndex(builder->parentSources, parentIX);
1024 secdebug("trust", "searching parent source %" PRIdCFIndex "/%" PRIdCFIndex, parentIX + 1,
1025 builder->nextParentSource);
1026 }
1027 SecCertificatePathSetNextSourceIndex(partial, sourceIX + 1);
1028 SecCertificateRef root = SecCertificatePathGetRoot(partial);
1029 return SecCertificateSourceCopyParents(source, root,
1030 builder, SecPathBuilderExtendPaths);
1031 } else {
1032 --builder->partialIX;
1033 }
1034
1035 return true;
1036 }
1037
1038 /* One or more of the policies did not accept the candidate path. */
1039 static void SecPathBuilderReject(SecPathBuilderRef builder) {
1040 check(builder);
1041 SecPVCRef pvc = &builder->path;
1042
1043 builder->state = SecPathBuilderGetNext;
1044
1045 if (builder->bestPathIsEV && !pvc->is_ev) {
1046 /* We never replace an ev reject with a non ev reject. */
1047 return;
1048 }
1049
1050 CFIndex rejectScore = builder->rejectScore;
1051 CFIndex score = SecCertificatePathScore(builder->path.path,
1052 SecPVCGetVerifyTime(&builder->path));
1053
1054 /* The current chain is valid for EV, but revocation checking failed. We
1055 replace any previously accepted or rejected non EV chains with the
1056 current one. */
1057 if (pvc->is_ev && !builder->bestPathIsEV) {
1058 rejectScore = 0;
1059 }
1060
1061 #if 0
1062 if (pvc->is_ev) {
1063 /* Since this means we found a valid ev chain that was revoked,
1064 we might want to switch directly to the
1065 SecPathBuilderComputeDetails state here if we think further
1066 searching for new chains is pointless. For now we'll keep
1067 going, since we could accept an alternate EV certification
1068 path that isn't revoked. */
1069 builder->state = SecPathBuilderComputeDetails;
1070 }
1071 #endif
1072
1073 /* Do this last so that changes to rejectScore above will take affect. */
1074 if (!builder->bestPath || score > rejectScore) {
1075 if (builder->bestPath) {
1076 secdebug("reject",
1077 "replacing %sev %s score: %ld with %sev reject score: %" PRIdCFIndex " %@",
1078 (builder->bestPathIsEV ? "" : "non "),
1079 (builder->rejectScore == INTPTR_MAX ? "accept" : "reject"),
1080 builder->rejectScore,
1081 (pvc->is_ev ? "" : "non "), (long)score, builder->path.path);
1082 } else {
1083 secdebug("reject", "%sev reject score: %" PRIdCFIndex " %@",
1084 (pvc->is_ev ? "" : "non "), score, builder->path.path);
1085 }
1086
1087 builder->rejectScore = score;
1088 builder->bestPath = pvc->path;
1089 builder->bestPathIsEV = pvc->is_ev;
1090 } else {
1091 secdebug("reject", "%sev reject score: %" PRIdCFIndex " lower than %" PRIdCFIndex " %@",
1092 (pvc->is_ev ? "" : "non "), score, rejectScore, builder->path.path);
1093 }
1094 }
1095
1096 /* All policies accepted the candidate path. */
1097 static void SecPathBuilderAccept(SecPathBuilderRef builder) {
1098 check(builder);
1099 SecPVCRef pvc = &builder->path;
1100 if (pvc->is_ev || !builder->bestPathIsEV) {
1101 secdebug("accept", "replacing %sev accept with %sev %@",
1102 (builder->bestPathIsEV ? "" : "non "),
1103 (pvc->is_ev ? "" : "non "), builder->path.path);
1104 builder->rejectScore = INTPTR_MAX; /* CFIndex is signed long which is INTPTR_T */
1105 builder->bestPathIsEV = pvc->is_ev;
1106 builder->bestPath = pvc->path;
1107 }
1108
1109 /* If we found the best accept we can we want to switch directly to the
1110 SecPathBuilderComputeDetails state here, since we're done. */
1111 if (pvc->is_ev || !pvc->optionally_ev)
1112 builder->state = SecPathBuilderComputeDetails;
1113 else
1114 builder->state = SecPathBuilderGetNext;
1115 }
1116
1117 /* Return true iff a given path satisfies all the specified policies at
1118 verifyTime. */
1119 static bool SecPathBuilderValidatePath(SecPathBuilderRef builder) {
1120 SecPVCRef pvc = &builder->path;
1121
1122 if (builder->considerRejected) {
1123 SecPathBuilderReject(builder);
1124 return true;
1125 }
1126
1127 builder->state = SecPathBuilderDidValidatePath;
1128 return SecPVCPathChecks(pvc);
1129 }
1130
1131 static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder) {
1132 SecPVCRef pvc = &builder->path;
1133 if (pvc->result) {
1134 SecPathBuilderAccept(builder);
1135 } else {
1136 SecPathBuilderReject(builder);
1137 }
1138 assert(builder->state != SecPathBuilderDidValidatePath);
1139 return true;
1140 }
1141
1142 static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder) {
1143 // foobar
1144 SecPVCRef pvc = &builder->path;
1145 #if 0
1146 if (!builder->caller_wants_details) {
1147 SecPVCSetPath(pvc, builder->bestPath, NULL);
1148 pvc->result = builder->rejectScore == INTPTR_MAX;
1149 builder->state = SecPathBuilderReportResult;
1150 return true;
1151 }
1152 #endif
1153 CFIndex ix, pathLength = SecCertificatePathGetCount(builder->bestPath);
1154 CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault,
1155 pathLength, builder->leafDetails);
1156 CFRetainSafe(details);
1157 SecPVCSetPath(pvc, builder->bestPath, details);
1158 /* Only report on EV stuff if the bestPath actually was valid for EV. */
1159 pvc->optionally_ev = builder->bestPathIsEV;
1160 pvc->info = CFDictionaryCreateMutable(kCFAllocatorDefault,
1161 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1162 for (ix = 1; ix < pathLength; ++ix) {
1163 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(
1164 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
1165 &kCFTypeDictionaryValueCallBacks);
1166 CFArrayAppendValue(details, certDetail);
1167 CFRelease(certDetail);
1168 SecPVCParentCertificateChecks(pvc, ix);
1169 SecPVCGrayListedKeyChecks(pvc, ix);
1170 SecPVCBlackListedKeyChecks(pvc, ix);
1171 }
1172 builder->state = SecPathBuilderReportResult;
1173 bool completed = SecPVCPathChecks(pvc);
1174
1175 /* Reject the certificate if it was accepted before but we failed it now. */
1176 if (builder->rejectScore == INTPTR_MAX && !pvc->result) {
1177 builder->rejectScore = 0;
1178 }
1179
1180 CFReleaseSafe(details);
1181
1182 return completed;
1183 }
1184
1185 static bool SecPathBuilderReportResult(SecPathBuilderRef builder) {
1186 SecPVCRef pvc = &builder->path;
1187 if (pvc->info && pvc->is_ev && pvc->result) {
1188 CFDictionarySetValue(pvc->info, kSecTrustInfoExtendedValidationKey,
1189 kCFBooleanTrue);
1190 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1191 CFStringRef leafCompanyName = SecCertificateCopyCompanyName(leaf);
1192 if (leafCompanyName) {
1193 CFDictionarySetValue(pvc->info, kSecTrustInfoCompanyNameKey,
1194 leafCompanyName);
1195 CFRelease(leafCompanyName);
1196 }
1197 if (pvc->rvcs) {
1198 CFAbsoluteTime nextUpdate = SecPVCGetEarliestNextUpdate(pvc);
1199 if (nextUpdate == 0) {
1200 CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationKey,
1201 kCFBooleanFalse);
1202 } else {
1203 CFDateRef validUntil = CFDateCreate(kCFAllocatorDefault, nextUpdate);
1204 CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationValidUntilKey,
1205 validUntil);
1206 CFRelease(validUntil);
1207 CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationKey,
1208 kCFBooleanTrue);
1209 }
1210 }
1211 }
1212
1213 /* This will trigger the outer step function to call the completion
1214 function. */
1215 builder->state = NULL;
1216 return false;
1217 }
1218
1219 /* @function SecPathBuilderStep
1220 @summary This is the core of the async engine.
1221 @description Return false iff job is complete, true if a network request
1222 is pending.
1223 builder->state is a function pointer which is to be invoked.
1224 If you call this function from within a builder->state invocation it
1225 immediately returns true.
1226 Otherwise the following steps are repeated endlessly (unless a step returns)
1227 builder->state is invoked. If it returns true and builder->state is still
1228 non NULL this proccess is repeated.
1229 If a state returns false, SecPathBuilder will return true
1230 if builder->state is non NULL.
1231 If builder->state is NULL then regardless of what the state function returns
1232 the completion callback will be invoked and the builder will be deallocated.
1233 */
1234 bool SecPathBuilderStep(SecPathBuilderRef builder) {
1235 if (builder->activations) {
1236 secdebug("async", "activations: %lu returning true",
1237 builder->activations);
1238 return true;
1239 }
1240
1241 secdebug("async", "activations: %lu", builder->activations);
1242 builder->activations++;
1243 while (builder->state && builder->state(builder));
1244 --builder->activations;
1245
1246 if (builder->state) {
1247 secdebug("async", "waiting for async reply, exiting");
1248 /* A state returned false, it's waiting for network traffic. Let's
1249 return. */
1250 return true;
1251 }
1252
1253 if (builder->activations) {
1254 /* There is still at least one other running instance of this builder
1255 somewhere on the stack, we let that instance take care of sending
1256 the client a response. */
1257 return false;
1258 }
1259
1260 SecTrustResultType result = (builder->rejectScore == INTPTR_MAX
1261 ? kSecTrustResultUnspecified : kSecTrustResultRecoverableTrustFailure);
1262
1263 secdebug("trust", "completed: %@ details: %@ result: %d",
1264 builder->bestPath, builder->path.details, result);
1265
1266 if (builder->completed) {
1267 builder->completed(builder->context, builder->bestPath,
1268 builder->path.details, builder->path.info, result);
1269 }
1270
1271 /* Finally, destroy the builder and free it. */
1272 SecPathBuilderDestroy(builder);
1273 free(builder);
1274
1275 return false;
1276 }
1277
1278 dispatch_queue_t SecPathBuilderGetQueue(SecPathBuilderRef builder) {
1279 return builder->queue;
1280 }
1281
1282 // MARK: -
1283 // MARK: SecTrustServer
1284 /********************************************************
1285 ****************** SecTrustServer **********************
1286 ********************************************************/
1287
1288 typedef void (^SecTrustServerEvaluationCompleted)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error);
1289
1290 static void
1291 SecTrustServerEvaluateCompleted(const void *userData,
1292 SecCertificatePathRef chain, CFArrayRef details, CFDictionaryRef info,
1293 SecTrustResultType result) {
1294 SecTrustServerEvaluationCompleted evaluated = (SecTrustServerEvaluationCompleted)userData;
1295 evaluated(result, details, info, chain, NULL);
1296 Block_release(evaluated);
1297 }
1298
1299 void
1300 SecTrustServerEvaluateBlock(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, CFArrayRef policies, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error)) {
1301 SecTrustServerEvaluationCompleted userData = Block_copy(evaluated);
1302 /* Call the actual evaluator function. */
1303 SecPathBuilderRef builder = SecPathBuilderCreate(certificates, anchors,
1304 anchorsOnly, policies,
1305 verifyTime, accessGroups,
1306 SecTrustServerEvaluateCompleted, userData);
1307 dispatch_async(builder->queue, ^{ SecPathBuilderStep(builder); });
1308 }
1309
1310
1311 // NO_SERVER Shim code only, xpc interface should call SecTrustServerEvaluateBlock() directly
1312 SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, CFArrayRef policies, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef *pdetails, CFDictionaryRef *pinfo, SecCertificatePathRef *pchain, CFErrorRef *perror) {
1313 dispatch_semaphore_t done = dispatch_semaphore_create(0);
1314 __block SecTrustResultType result = kSecTrustResultInvalid;
1315 SecTrustServerEvaluateBlock(certificates, anchors, anchorsOnly, policies, verifyTime, accessGroups, ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error) {
1316 result = tr;
1317 if (tr == kSecTrustResultInvalid) {
1318 if (perror) {
1319 *perror = error;
1320 CFRetainSafe(error);
1321 }
1322 } else {
1323 if (pdetails) {
1324 *pdetails = details;
1325 CFRetainSafe(details);
1326 }
1327 if (pinfo) {
1328 *pinfo = info;
1329 CFRetainSafe(info);
1330 }
1331 if (pchain) {
1332 *pchain = chain;
1333 CFRetainSafe(chain);
1334 }
1335 }
1336 dispatch_semaphore_signal(done);
1337 });
1338 dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
1339
1340 return result;
1341 }