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