]> git.saurik.com Git - apple/security.git/blob - sec/Security/SecTrust.c
Security-55471.14.tar.gz
[apple/security.git] / sec / Security / SecTrust.c
1 /*
2 * Copyright (c) 2006-2013 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 * SecTrust.c - CoreFoundation based certificate trust evaluator
24 *
25 * Created by Michael Brouwer on 10/17/06.
26 */
27
28 #include <Security/SecTrustPriv.h>
29 #include <Security/SecItemPriv.h>
30 #include <Security/SecCertificateInternal.h>
31 #include <Security/SecCertificatePath.h>
32 #include <Security/SecFramework.h>
33 #include <Security/SecPolicyInternal.h>
34 #include <utilities/SecIOFormat.h>
35 #include <CoreFoundation/CFRuntime.h>
36 #include <CoreFoundation/CFSet.h>
37 #include <CoreFoundation/CFString.h>
38 #include <CoreFoundation/CFNumber.h>
39 #include <CoreFoundation/CFArray.h>
40 #include <CoreFoundation/CFPropertyList.h>
41 #include <AssertMacros.h>
42 #include <stdbool.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <pthread.h>
46 #include <Security/SecBasePriv.h>
47 #include <utilities/SecCFError.h>
48 #include <utilities/SecCFWrappers.h>
49 #include <utilities/SecCertificateTrace.h>
50
51 #include "SecRSAKey.h"
52 #include <libDER/oids.h>
53 #include <utilities/debugging.h>
54 #include <Security/SecInternal.h>
55 #include <ipc/securityd_client.h>
56 #include <SecuritydXPC.h>
57 #include <securityd/SecTrustServer.h>
58
59 #define SEC_CONST_DECL(k,v) CFTypeRef k = (CFTypeRef)(CFSTR(v));
60
61 SEC_CONST_DECL (kSecTrustInfoExtendedValidationKey, "ExtendedValidation");
62 SEC_CONST_DECL (kSecTrustInfoCompanyNameKey, "CompanyName");
63 SEC_CONST_DECL (kSecTrustInfoRevocationKey, "Revocation");
64 SEC_CONST_DECL (kSecTrustInfoRevocationValidUntilKey, "RevocationValidUntil");
65
66 /* Public trust result constants */
67 SEC_CONST_DECL (kSecTrustEvaluationDate, "TrustEvaluationDate");
68 SEC_CONST_DECL (kSecTrustExtendedValidation, "TrustExtendedValidation");
69 SEC_CONST_DECL (kSecTrustOrganizationName, "Organization");
70 SEC_CONST_DECL (kSecTrustResultValue, "TrustResultValue");
71 SEC_CONST_DECL (kSecTrustRevocationChecked, "TrustRevocationChecked");
72 SEC_CONST_DECL (kSecTrustRevocationValidUntilDate, "TrustExpirationDate");
73 SEC_CONST_DECL (kSecTrustResultDetails, "TrustResultDetails");
74
75 #pragma mark -
76 #pragma mark SecTrust
77
78 /********************************************************
79 ****************** SecTrust object *********************
80 ********************************************************/
81 struct __SecTrust {
82 CFRuntimeBase _base;
83 CFArrayRef _certificates;
84 CFArrayRef _anchors;
85 CFTypeRef _policies;
86 CFArrayRef _responses;
87 CFDateRef _verifyDate;
88 SecCertificatePathRef _chain;
89 SecKeyRef _publicKey;
90 CFArrayRef _details;
91 CFDictionaryRef _info;
92 CFArrayRef _exceptions;
93
94 /* Note that a value of kSecTrustResultInvalid (0)
95 * indicates the trust must be (re)evaluated; any
96 * functions which modify trust parameters in a way
97 * that would invalidate the current result must set
98 * this value back to kSecTrustResultInvalid.
99 */
100 SecTrustResultType _trustResult;
101
102 /* If true we don't trust any anchors other than the ones in _anchors. */
103 bool _anchorsOnly;
104
105 /* Master switch to permit or disable network use in policy evaluation */
106 SecNetworkPolicy _networkPolicy;
107 };
108
109 /* CFRuntime registration data. */
110 static pthread_once_t kSecTrustRegisterClass = PTHREAD_ONCE_INIT;
111 static CFTypeID kSecTrustTypeID = _kCFRuntimeNotATypeID;
112
113 /* Forward declarations of static functions. */
114 static CFStringRef SecTrustDescribe(CFTypeRef cf);
115 static void SecTrustDestroy(CFTypeRef cf);
116 static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust);
117
118 /* Static functions. */
119 static CF_RETURNS_RETAINED CFStringRef SecTrustDescribe(CFTypeRef cf) {
120 SecTrustRef trust = (SecTrustRef)cf;
121 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
122 CFSTR("<SecTrustRef: %p>"), trust);
123 }
124
125 static void SecTrustDestroy(CFTypeRef cf) {
126 SecTrustRef trust = (SecTrustRef)cf;
127 CFReleaseSafe(trust->_certificates);
128 CFReleaseSafe(trust->_policies);
129 CFReleaseSafe(trust->_responses);
130 CFReleaseSafe(trust->_verifyDate);
131 CFReleaseSafe(trust->_anchors);
132 CFReleaseSafe(trust->_chain);
133 CFReleaseSafe(trust->_publicKey);
134 CFReleaseSafe(trust->_details);
135 CFReleaseSafe(trust->_info);
136 CFReleaseSafe(trust->_exceptions);
137 }
138
139 static void SecTrustRegisterClass(void) {
140 static const CFRuntimeClass kSecTrustClass = {
141 0, /* version */
142 "SecTrust", /* class name */
143 NULL, /* init */
144 NULL, /* copy */
145 SecTrustDestroy, /* dealloc */
146 NULL, /* equal */
147 NULL, /* hash */
148 NULL, /* copyFormattingDesc */
149 SecTrustDescribe /* copyDebugDesc */
150 };
151
152 kSecTrustTypeID = _CFRuntimeRegisterClass(&kSecTrustClass);
153 }
154
155 /* Public API functions. */
156 CFTypeID SecTrustGetTypeID(void) {
157 pthread_once(&kSecTrustRegisterClass, SecTrustRegisterClass);
158 return kSecTrustTypeID;
159 }
160
161 OSStatus SecTrustCreateWithCertificates(CFTypeRef certificates,
162 CFTypeRef policies, SecTrustRef *trust) {
163 OSStatus status = errSecParam;
164 CFAllocatorRef allocator = kCFAllocatorDefault;
165 CFArrayRef l_certs = NULL, l_policies = NULL;
166 SecTrustRef result = NULL;
167
168 check(certificates);
169 check(trust);
170 CFTypeID certType = CFGetTypeID(certificates);
171 if (certType == CFArrayGetTypeID()) {
172 /* We need at least 1 certificate. */
173 require_quiet(CFArrayGetCount(certificates) > 0, errOut);
174 l_certs = CFArrayCreateCopy(allocator, certificates);
175 } else if (certType == SecCertificateGetTypeID()) {
176 l_certs = CFArrayCreate(allocator, &certificates, 1,
177 &kCFTypeArrayCallBacks);
178 } else {
179 goto errOut;
180 }
181 if (!l_certs) {
182 status = errSecAllocate;
183 goto errOut;
184 }
185
186 if (!policies) {
187 CFTypeRef policy = SecPolicyCreateBasicX509();
188 l_policies = CFArrayCreate(allocator, &policy, 1,
189 &kCFTypeArrayCallBacks);
190 CFRelease(policy);
191 } else if (CFGetTypeID(policies) == CFArrayGetTypeID()) {
192 l_policies = CFArrayCreateCopy(allocator, policies);
193 } else if (CFGetTypeID(policies) == SecPolicyGetTypeID()) {
194 l_policies = CFArrayCreate(allocator, &policies, 1,
195 &kCFTypeArrayCallBacks);
196 } else {
197 goto errOut;
198 }
199 if (!l_policies) {
200 status = errSecAllocate;
201 goto errOut;
202 }
203
204 CFIndex size = sizeof(struct __SecTrust);
205 require_quiet(result = (SecTrustRef)_CFRuntimeCreateInstance(allocator,
206 SecTrustGetTypeID(), size - sizeof(CFRuntimeBase), 0), errOut);
207 memset((char*)result + sizeof(result->_base), 0,
208 sizeof(*result) - sizeof(result->_base));
209 status = errSecSuccess;
210
211 errOut:
212 if (status) {
213 CFReleaseSafe(result);
214 CFReleaseSafe(l_certs);
215 CFReleaseSafe(l_policies);
216 } else {
217 result->_certificates = l_certs;
218 result->_policies = l_policies;
219 *trust = result;
220 }
221 return status;
222 }
223
224 static void SetTrustSetNeedsEvaluation(SecTrustRef trust) {
225 check(trust);
226 if (trust) {
227 trust->_trustResult = kSecTrustResultInvalid;
228 }
229 }
230
231 OSStatus SecTrustSetAnchorCertificatesOnly(SecTrustRef trust,
232 Boolean anchorCertificatesOnly) {
233 if (!trust) {
234 return errSecParam;
235 }
236 SetTrustSetNeedsEvaluation(trust);
237 trust->_anchorsOnly = anchorCertificatesOnly;
238
239 return errSecSuccess;
240 }
241
242 OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust,
243 CFArrayRef anchorCertificates) {
244 if (!trust) {
245 return errSecParam;
246 }
247 SetTrustSetNeedsEvaluation(trust);
248 if (anchorCertificates)
249 CFRetain(anchorCertificates);
250 if (trust->_anchors)
251 CFRelease(trust->_anchors);
252 trust->_anchors = anchorCertificates;
253 trust->_anchorsOnly = (anchorCertificates != NULL);
254
255 return errSecSuccess;
256 }
257
258 OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust,
259 CFArrayRef *anchors) {
260 if (!trust|| !anchors) {
261 return errSecParam;
262 }
263 CFArrayRef anchorsArray = NULL;
264 if (trust->_anchors) {
265 anchorsArray = CFArrayCreateCopy(kCFAllocatorDefault, trust->_anchors);
266 if (!anchorsArray) {
267 return errSecAllocate;
268 }
269 }
270 *anchors = anchorsArray;
271 return errSecSuccess;
272 }
273
274 OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef responseData) {
275 if (!trust) {
276 return errSecParam;
277 }
278 SetTrustSetNeedsEvaluation(trust);
279 CFArrayRef responseArray = NULL;
280 if (responseData) {
281 if (CFGetTypeID(responseData) == CFArrayGetTypeID()) {
282 responseArray = CFArrayCreateCopy(kCFAllocatorDefault, responseData);
283 } else if (CFGetTypeID(responseData) == CFDataGetTypeID()) {
284 responseArray = CFArrayCreate(kCFAllocatorDefault, &responseData, 1,
285 &kCFTypeArrayCallBacks);
286 } else {
287 return errSecParam;
288 }
289 }
290 if (trust->_responses)
291 CFRelease(trust->_responses);
292 trust->_responses = responseArray;
293
294 return errSecSuccess;
295 }
296
297 OSStatus SecTrustSetVerifyDate(SecTrustRef trust, CFDateRef verifyDate) {
298 if (!trust) {
299 return errSecParam;
300 }
301 SetTrustSetNeedsEvaluation(trust);
302 check(verifyDate);
303 CFRetainSafe(verifyDate);
304 if (trust->_verifyDate)
305 CFRelease(trust->_verifyDate);
306 trust->_verifyDate = verifyDate;
307
308 return errSecSuccess;
309 }
310
311 OSStatus SecTrustSetPolicies(SecTrustRef trust, CFTypeRef newPolicies) {
312 if (!trust || !newPolicies) {
313 return errSecParam;
314 }
315 SetTrustSetNeedsEvaluation(trust);
316 check(newPolicies);
317
318 CFArrayRef policyArray = NULL;
319 if (CFGetTypeID(newPolicies) == CFArrayGetTypeID()) {
320 policyArray = CFArrayCreateCopy(kCFAllocatorDefault, newPolicies);
321 } else if (CFGetTypeID(newPolicies) == SecPolicyGetTypeID()) {
322 policyArray = CFArrayCreate(kCFAllocatorDefault, &newPolicies, 1,
323 &kCFTypeArrayCallBacks);
324 } else {
325 return errSecParam;
326 }
327
328 if (trust->_policies)
329 CFRelease(trust->_policies);
330 trust->_policies = policyArray;
331
332 return errSecSuccess;
333 }
334
335 OSStatus SecTrustCopyPolicies(SecTrustRef trust, CFArrayRef *policies) {
336 if (!trust|| !policies) {
337 return errSecParam;
338 }
339 if (!trust->_policies) {
340 return errSecInternal;
341 }
342 CFArrayRef policyArray = CFArrayCreateCopy(kCFAllocatorDefault, trust->_policies);
343 if (!policyArray) {
344 return errSecAllocate;
345 }
346 *policies = policyArray;
347 return errSecSuccess;
348 }
349
350 OSStatus SecTrustSetNetworkFetchAllowed(SecTrustRef trust, Boolean allowFetch) {
351 if (!trust) {
352 return errSecParam;
353 }
354 trust->_networkPolicy = (allowFetch) ? useNetworkEnabled : useNetworkDisabled;
355 return errSecSuccess;
356 }
357
358 OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, Boolean *allowFetch) {
359 if (!trust || !allowFetch) {
360 return errSecParam;
361 }
362 Boolean allowed = false;
363 SecNetworkPolicy netPolicy = trust->_networkPolicy;
364 if (netPolicy == useNetworkDefault) {
365 // network fetch is enabled by default for SSL only
366 CFIndex idx, count = (trust->_policies) ? CFArrayGetCount(trust->_policies) : 0;
367 for (idx=0; idx<count; idx++) {
368 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(trust->_policies, idx);
369 if (policy) {
370 CFDictionaryRef props = SecPolicyCopyProperties(policy);
371 if (props) {
372 CFTypeRef value = (CFTypeRef)CFDictionaryGetValue(props, kSecPolicyOid);
373 if (value) {
374 if (CFEqual(value, kSecPolicyAppleSSL)) {
375 allowed = true;
376 }
377 }
378 CFRelease(props);
379 }
380 }
381 }
382 } else {
383 // caller has explicitly set the network policy
384 allowed = (netPolicy == useNetworkEnabled);
385 }
386 *allowFetch = allowed;
387 return errSecSuccess;
388 }
389
390 CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) {
391 CFAbsoluteTime verifyTime;
392 if (trust && trust->_verifyDate) {
393 verifyTime = CFDateGetAbsoluteTime(trust->_verifyDate);
394 } else {
395 verifyTime = CFAbsoluteTimeGetCurrent();
396 /* Record the verifyDate we ended up using. */
397 if (trust) {
398 trust->_verifyDate = CFDateCreate(CFGetAllocator(trust), verifyTime);
399 }
400 }
401 return verifyTime;
402 }
403
404 CFArrayRef SecTrustGetDetails(SecTrustRef trust) {
405 if (!trust) {
406 return NULL;
407 }
408 SecTrustEvaluateIfNecessary(trust);
409 return trust->_details;
410 }
411
412 OSStatus SecTrustGetTrustResult(SecTrustRef trust,
413 SecTrustResultType *result) {
414 if (!trust || !result) {
415 return errSecParam;
416 }
417 *result = trust->_trustResult;
418 return errSecSuccess;
419 }
420
421 static CFStringRef kSecCertificateDetailSHA1Digest = CFSTR("SHA1Digest");
422
423 static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix) {
424 if (!trust->_exceptions || ix >= CFArrayGetCount(trust->_exceptions))
425 return NULL;
426 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(trust->_exceptions, ix);
427 if (CFGetTypeID(exception) != CFDictionaryGetTypeID())
428 return NULL;
429
430 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
431 if (!certificate)
432 return NULL;
433
434 /* If the exception contains the current certificates sha1Digest in the
435 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
436 CFDataRef sha1Digest = SecCertificateGetSHA1Digest(certificate);
437 CFTypeRef digestValue = CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest);
438 if (!digestValue || !CFEqual(sha1Digest, digestValue))
439 exception = NULL;
440
441 return exception;
442 }
443
444 struct SecTrustCheckExceptionContext {
445 CFDictionaryRef exception;
446 bool exceptionNotFound;
447 };
448
449 static void SecTrustCheckException(const void *key, const void *value, void *context) {
450 struct SecTrustCheckExceptionContext *cec = (struct SecTrustCheckExceptionContext *)context;
451 if (cec->exception) {
452 CFTypeRef exceptionValue = CFDictionaryGetValue(cec->exception, key);
453 if (!exceptionValue || !CFEqual(value, exceptionValue)) {
454 cec->exceptionNotFound = true;
455 }
456 } else {
457 cec->exceptionNotFound = true;
458 }
459 }
460
461
462 OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *result) {
463 if (!trust) {
464 return errSecParam;
465 }
466 OSStatus status = SecTrustEvaluateIfNecessary(trust);
467 if (status || !result)
468 return status;
469
470 /* post-process trust result based on exceptions */
471 SecTrustResultType trustResult = trust->_trustResult;
472 if (trustResult == kSecTrustResultUnspecified) {
473 /* If leaf is in exceptions -> proceed, otherwise unspecified. */
474 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
475 trustResult = kSecTrustResultProceed;
476 } else if (trustResult == kSecTrustResultRecoverableTrustFailure) {
477 /* If we have exceptions get details and match to exceptions. */
478 CFIndex pathLength = CFArrayGetCount(trust->_details);
479 struct SecTrustCheckExceptionContext context = {};
480 CFIndex ix;
481 for (ix = 0; ix < pathLength; ++ix) {
482 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(trust->_details, ix);
483
484 if ((ix == 0) && CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedLeaf))
485 {
486 trustResult = kSecTrustResultFatalTrustFailure;
487 goto DoneCheckingTrust;
488 }
489
490 if (CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedKey))
491 {
492 trustResult = kSecTrustResultFatalTrustFailure;
493 goto DoneCheckingTrust;
494 }
495
496 context.exception = SecTrustGetExceptionForCertificateAtIndex(trust, ix);
497 CFDictionaryApplyFunction(detail, SecTrustCheckException, &context);
498 if (context.exceptionNotFound) {
499 break;
500 }
501 }
502 if (!context.exceptionNotFound)
503 trustResult = kSecTrustResultProceed;
504 }
505 DoneCheckingTrust:
506 trust->_trustResult = trustResult;
507
508 #if DEBUG
509 /* log to syslog when there is a trust failure */
510 if (trustResult != kSecTrustResultProceed &&
511 trustResult != kSecTrustResultConfirm &&
512 trustResult != kSecTrustResultUnspecified) {
513 CFStringRef failureDesc = SecTrustCopyFailureDescription(trust);
514 secerror("%@", failureDesc);
515 CFRelease(failureDesc);
516 }
517 #endif
518
519
520 *result = trustResult;
521
522 return status;
523 }
524
525 OSStatus SecTrustEvaluateAsync(SecTrustRef trust,
526 dispatch_queue_t queue, SecTrustCallback result)
527 {
528 dispatch_async(queue, ^{
529 SecTrustResultType trustResult;
530 if (errSecSuccess != SecTrustEvaluate(trust, &trustResult)) {
531 trustResult = kSecTrustResultInvalid;
532 }
533 result(trust, trustResult);
534 });
535 return errSecSuccess;
536 }
537
538 static bool SecXPCDictionarySetCertificates(xpc_object_t message, const char *key, CFArrayRef certificates, CFErrorRef *error) {
539 xpc_object_t xpc_certificates = SecCertificateArrayCopyXPCArray(certificates, error);
540 if (!xpc_certificates)
541 return false;
542
543 xpc_dictionary_set_value(message, key, xpc_certificates);
544 xpc_release(xpc_certificates);
545
546 return true;
547 }
548
549 static bool SecXPCDictionarySetPolicies(xpc_object_t message, const char *key, CFArrayRef policies, CFErrorRef *error) {
550 xpc_object_t xpc_policies = SecPolicyArrayCopyXPCArray(policies, error);
551 if (!xpc_policies)
552 return false;
553 xpc_dictionary_set_value(message, key, xpc_policies);
554 xpc_release(xpc_policies);
555 return true;
556 }
557
558 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message, const char *key, SecCertificatePathRef *path, CFErrorRef *error) {
559 xpc_object_t xpc_path = xpc_dictionary_get_value(message, key);
560 if (!xpc_path) {
561 *path = NULL;
562 return true;
563 }
564 *path = SecCertificatePathCreateWithXPCArray(xpc_path, error);
565 return *path;
566 }
567
568 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message, const char *key, CFErrorRef *error) {
569 int64_t value = xpc_dictionary_get_int64(message, key);
570 if (!value) {
571 SecError(errSecInternal, error, CFSTR("object for key %s is 0"), key);
572 }
573 return (int)value;
574 }
575
576 static SecTrustResultType certs_anchors_bool_policies_date_ag_to_details_info_chain_int_error_request(enum SecXPCOperation op, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, CFArrayRef policies, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef *details, CFDictionaryRef *info, SecCertificatePathRef *chain, CFErrorRef *error)
577 {
578 __block SecTrustResultType tr = kSecTrustResultInvalid;
579 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
580 if (!SecXPCDictionarySetCertificates(message, kSecTrustCertificatesKey, certificates, error))
581 return false;
582 if (anchors && !SecXPCDictionarySetCertificates(message, kSecTrustAnchorsKey, anchors, error))
583 return false;
584 if (anchorsOnly)
585 xpc_dictionary_set_bool(message, kSecTrustAnchorsOnlyKey, anchorsOnly);
586 if (!SecXPCDictionarySetPolicies(message, kSecTrustPoliciesKey, policies, error))
587 return false;
588 xpc_dictionary_set_double(message, kSecTrustVerifyDateKey, verifyTime);
589 return true;
590 }, ^bool(xpc_object_t response, CFErrorRef *error) {
591 secdebug("trust", "response: %@", response);
592 return SecXPCDictionaryCopyArrayOptional(response, kSecTrustDetailsKey, details, error) &&
593 SecXPCDictionaryCopyDictionaryOptional(response, kSecTrustInfoKey, info, error) &&
594 SecXPCDictionaryCopyChainOptional(response, kSecTrustChainKey, chain, error) &&
595 ((tr = SecXPCDictionaryGetNonZeroInteger(response, kSecTrustResultKey, error)) != kSecTrustResultInvalid);
596 });
597 return tr;
598 }
599
600 static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust) {
601 check(trust);
602 if (!trust)
603 return errSecParam;
604
605 if (trust->_trustResult != kSecTrustResultInvalid)
606 return errSecSuccess;
607
608 trust->_trustResult = kSecTrustResultOtherError; /* to avoid potential recursion */
609
610 CFReleaseNull(trust->_chain);
611 CFReleaseNull(trust->_details);
612 CFReleaseNull(trust->_info);
613
614 /* @@@ Consider an optimization where we keep a side dictionary with the SHA1 hash of ever SecCertificateRef we send, so we only send potential duplicates once, and have the server respond with either just the SHA1 hash of a certificate, or the complete certificate in the response depending on whether the client already sent it, so we don't send back certificates to the client it already has. */
615 return SecOSStatusWith(^bool (CFErrorRef *error) {
616 trust->_trustResult = SECURITYD_XPC(sec_trust_evaluate, certs_anchors_bool_policies_date_ag_to_details_info_chain_int_error_request, trust->_certificates, trust->_anchors, trust->_anchorsOnly, trust->_policies, SecTrustGetVerifyTime(trust), SecAccessGroupsGetCurrent(), &trust->_details, &trust->_info, &trust->_chain, error);
617 if (trust->_trustResult == kSecTrustResultInvalid /* TODO check domain */ &&
618 SecErrorGetOSStatus(*error) == errSecNotAvailable &&
619 CFArrayGetCount(trust->_certificates)) {
620 /* We failed to talk to securityd. The only time this should
621 happen is when we are running prior to launchd enabling
622 registration of services. This currently happens when we
623 are running from the ramdisk. To make ASR happy we initialize
624 _chain and return success with a failure as the trustResult, to
625 make it seem like we did a cert evaluation, so ASR can extract
626 the public key from the leaf. */
627 trust->_chain = SecCertificatePathCreate(NULL, (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0));
628 if (error)
629 CFReleaseNull(*error);
630 return true;
631 }
632 return trust->_trustResult != kSecTrustResultInvalid;
633 });
634 }
635
636 /* Helper for the qsort below. */
637 static int compare_strings(const void *a1, const void *a2) {
638 CFStringRef s1 = *(CFStringRef *)a1;
639 CFStringRef s2 = *(CFStringRef *)a2;
640 return (int) CFStringCompare(s1, s2, kCFCompareForcedOrdering);
641 }
642
643 CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust) {
644 CFMutableStringRef reason = CFStringCreateMutable(NULL, 0);
645 CFArrayRef details = SecTrustGetDetails(trust);
646 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
647 for (CFIndex ix = 0; ix < pathLength; ++ix) {
648 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
649 CFIndex dCount = CFDictionaryGetCount(detail);
650 if (dCount) {
651 if (ix == 0)
652 CFStringAppend(reason, CFSTR(" [leaf"));
653 else if (ix == pathLength - 1)
654 CFStringAppend(reason, CFSTR(" [root"));
655 else
656 CFStringAppendFormat(reason, NULL, CFSTR(" [ca%" PRIdCFIndex ), ix);
657
658 const void *keys[dCount];
659 CFDictionaryGetKeysAndValues(detail, &keys[0], NULL);
660 qsort(&keys[0], dCount, sizeof(keys[0]), compare_strings);
661 for (CFIndex kix = 0; kix < dCount; ++kix) {
662 CFStringRef key = keys[kix];
663 const void *value = CFDictionaryGetValue(detail, key);
664 CFStringAppendFormat(reason, NULL, CFSTR(" %@%@"), key,
665 (CFGetTypeID(value) == CFBooleanGetTypeID()
666 ? CFSTR("") : value));
667 }
668 CFStringAppend(reason, CFSTR("]"));
669 }
670 }
671 return reason;
672 }
673
674 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust) {
675 if (!trust) {
676 return NULL;
677 }
678 if (!trust->_publicKey) {
679 if (!trust->_chain) {
680 /* Trust hasn't been evaluated yet, first attempt to retrieve public key from leaf cert as is. */
681 trust->_publicKey = SecCertificateCopyPublicKey(SecTrustGetCertificateAtIndex(trust, 0));
682 #if 0
683 if (!trust->_publicKey) {
684 /* If this fails use the passed in certs in order as if they are a valid cert path an attempt to extract the key. */
685 SecCertificatePathRef path;
686 // SecCertificatePathCreateWithArray Would have crashed if this code was every called
687 // since it expected an array of CFDataRefs not an array of certificates.
688 path = SecCertificatePathCreateWithArray(trust->_certificates);
689 trust->_publicKey = SecCertificatePathCopyPublicKeyAtIndex(path, 0);
690 CFRelease(path);
691 }
692 #endif
693 if (!trust->_publicKey) {
694 /* Last resort, we evaluate the trust to get a _chain. */
695 SecTrustEvaluateIfNecessary(trust);
696 }
697 }
698 if (trust->_chain) {
699 trust->_publicKey = SecCertificatePathCopyPublicKeyAtIndex(trust->_chain, 0);
700 }
701 }
702
703 if (trust->_publicKey)
704 CFRetain(trust->_publicKey);
705
706 return trust->_publicKey;
707 }
708
709 CFIndex SecTrustGetCertificateCount(SecTrustRef trust) {
710 if (!trust) {
711 return 0;
712 }
713 SecTrustEvaluateIfNecessary(trust);
714 return (trust->_chain) ? SecCertificatePathGetCount(trust->_chain) : 1;
715 }
716
717 SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust,
718 CFIndex ix) {
719 if (!trust) {
720 return NULL;
721 }
722 if (ix == 0) {
723 return (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
724 }
725 SecTrustEvaluateIfNecessary(trust);
726 return (trust->_chain) ? SecCertificatePathGetCertificateAtIndex(trust->_chain, ix) : NULL;
727 }
728
729 CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust) {
730 if (!trust) {
731 return NULL;
732 }
733 SecTrustEvaluateIfNecessary(trust);
734 CFDictionaryRef info = trust->_info;
735 if (info)
736 CFRetain(info);
737 return info;
738 }
739
740 CFDataRef SecTrustCopyExceptions(SecTrustRef trust) {
741 CFArrayRef details = SecTrustGetDetails(trust);
742 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
743 CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault, pathLength, &kCFTypeArrayCallBacks);
744 CFIndex ix;
745 for (ix = 0; ix < pathLength; ++ix) {
746 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
747 CFIndex detailCount = CFDictionaryGetCount(detail);
748 CFMutableDictionaryRef exception;
749 if (ix == 0 || detailCount > 0) {
750 exception = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, detailCount + 1, detail);
751 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
752 CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
753 CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest);
754 } else {
755 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
756 exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0,
757 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
758 }
759 CFArrayAppendValue(exceptions, exception);
760 CFRelease(exception);
761 }
762
763 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
764 since it will never be empty). */
765 for (ix = pathLength; ix-- > 1;) {
766 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
767 if (CFDictionaryGetCount(exception) == 0) {
768 CFArrayRemoveValueAtIndex(exceptions, ix);
769 } else {
770 break;
771 }
772 }
773
774 CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
775 exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
776 CFRelease(exceptions);
777
778 return encodedExceptions;
779 }
780
781 bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) {
782 if (!trust) {
783 return false;
784 }
785 CFArrayRef exceptions = NULL;
786
787 if (NULL != encodedExceptions) {
788 exceptions = CFPropertyListCreateWithData(kCFAllocatorDefault,
789 encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
790 }
791
792 if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
793 CFRelease(exceptions);
794 exceptions = NULL;
795 }
796 CFReleaseSafe(trust->_exceptions);
797 trust->_exceptions = exceptions;
798
799 /* If there is a valid exception entry for our current leaf we're golden. */
800 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
801 return true;
802
803 /* The passed in exceptions didn't match our current leaf, so we discard it. */
804 CFReleaseNull(trust->_exceptions);
805 return false;
806 }
807
808 CFArrayRef SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
809 CFMutableArrayRef summary;
810 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
811 summary = SecCertificateCopySummaryProperties(certificate,
812 SecTrustGetVerifyTime(trust));
813 /* FIXME Add more details in the failure case. */
814
815 return summary;
816 }
817
818 CFArrayRef SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
819 CFArrayRef summary;
820 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
821 summary = SecCertificateCopyProperties(certificate);
822
823 return summary;
824 }
825
826 #if 0
827
828
829
830 /* Valid chain.
831 Can be on any non root cert in the chain.
832 Priority: Top down
833 Short circuit: Yes (No other errors matter after this one)
834 Non recoverable error
835 Trust UI: Invalid certificate chain linkage
836 Cert UI: Invalid linkage to parent certificate
837 */
838 CFStringRef kSecPolicyCheckIdLinkage = CFSTR("IdLinkage");
839
840 /* X.509 required checks.
841 Can be on any cert in the chain
842 Priority: Top down
843 Short circuit: Yes (No other errors matter after this one)
844 Non recoverable error
845 Trust UI: (One or more) unsupported critical extensions found.
846 */
847 /* If we have no names for the extention oids use:
848 Cert UI: One or more unsupported critical extensions found (Non recoverable error).
849 Cert UI: Unsupported 'foo', 'bar', baz' critical extensions found.
850 */
851 CFStringRef kSecPolicyCheckCriticalExtensions = CFSTR("CriticalExtensions");
852 /* Cert UI: Unsupported critical Qualified Certificate Statements extension found (Non recoverable error). */
853 CFStringRef kSecPolicyCheckQualifiedCertStatements = CFSTR("QualifiedCertStatements");
854 /* Cert UI: Certificate has an empty subject (and no critial subjectAltname). */
855
856 /* Trusted root.
857 Only apply to the anchor.
858 Priority: N/A
859 Short circuit: No (Under discussion)
860 Recoverable
861 Trust UI: Root certificate is not trusted (for this policy/app/host/whatever?)
862 Cert UI: Not a valid anchor
863 */
864 CFStringRef kSecPolicyCheckAnchorTrusted = CFSTR("AnchorTrusted");
865 CFStringRef kSecPolicyCheckAnchorSHA1 = CFSTR("AnchorSHA1");
866
867 /* Binding.
868 Only applies to leaf
869 Priority: N/A
870 Short Circuit: No
871 Recoverable
872 Trust UI: (Hostname|email address) mismatch
873 */
874 CFStringRef kSecPolicyCheckSSLHostname = CFSTR("SSLHostname");
875
876 /* Policy specific checks.
877 Can be on any cert in the chain
878 Priority: Top down
879 Short Circuit: No
880 Recoverable
881 Trust UI: Certificate chain is not valid for the current policy.
882 OR: (One or more) certificates in the chain are not valid for the current policy/application
883 */
884 CFStringRef kSecPolicyCheckNonEmptySubject = CFSTR("NonEmptySubject");
885 /* Cert UI: Non CA certificate used as CA.
886 Cert UI: CA certificate used as leaf.
887 Cert UI: Cert chain length exceeded.
888 Cert UI: Basic constraints extension not critical (non fatal).
889 Cert UI: Leaf certificate has basic constraints extension (non fatal).
890 */
891 CFStringRef kSecPolicyCheckBasicContraints = CFSTR("BasicContraints");
892 CFStringRef kSecPolicyCheckKeyUsage = CFSTR("KeyUsage");
893 CFStringRef kSecPolicyCheckExtendedKeyUsage = CFSTR("ExtendedKeyUsage");
894 /* Checks that the issuer of the leaf has exactly one Common Name and that it
895 matches the specified string. */
896 CFStringRef kSecPolicyCheckIssuerCommonName = CFSTR("IssuerCommonName");
897 /* Checks that the leaf has exactly one Common Name and that it has the
898 specified string as a prefix. */
899 CFStringRef kSecPolicyCheckSubjectCommonNamePrefix = CFSTR("SubjectCommonNamePrefix");
900 /* Check that the certificate chain length matches the specificed CFNumberRef
901 length. */
902 CFStringRef kSecPolicyCheckChainLength = CFSTR("ChainLength");
903 CFStringRef kSecPolicyCheckNotValidBefore = CFSTR("NotValidBefore");
904
905 /* Expiration.
906 Can be on any cert in the chain
907 Priority: Top down
908 Short Circuit: No
909 Recoverable
910 Trust UI: One or more certificates have expired or are not valid yet.
911 OS: The (root|intermidate|leaf) certificate (expired on 'date'|is not valid until 'date')
912 Cert UI: Certificate (expired on 'date'|is not valid until 'date')
913 */
914 CFStringRef kSecPolicyCheckValidIntermediates = CFSTR("ValidIntermediates");
915 CFStringRef kSecPolicyCheckValidLeaf = CFSTR("ValidLeaf");
916 CFStringRef kSecPolicyCheckValidRoot = CFSTR("ValidRoot");
917
918 #endif
919
920 struct TrustFailures {
921 bool badLinkage;
922 bool unknownCritExtn;
923 bool untrustedAnchor;
924 bool hostnameMismatch;
925 bool policyFail;
926 bool invalidCert;
927 };
928
929 static void applyDetailProperty(const void *_key, const void *_value,
930 void *context) {
931 CFStringRef key = (CFStringRef)_key;
932 struct TrustFailures *tf = (struct TrustFailures *)context;
933 if (CFGetTypeID(_value) != CFBooleanGetTypeID()) {
934 /* Value isn't a CFBooleanRef, oh no! */
935 return;
936 }
937 CFBooleanRef value = (CFBooleanRef)_value;
938 if (CFBooleanGetValue(value)) {
939 /* Not an actual failure so we don't report it. */
940 return;
941 }
942
943 /* @@@ FIXME: Report a different return value when something is in the
944 details but masked out by an exception and use that below for display
945 purposes. */
946 if (CFEqual(key, kSecPolicyCheckIdLinkage)) {
947 tf->badLinkage = true;
948 } else if (CFEqual(key, kSecPolicyCheckCriticalExtensions)
949 || CFEqual(key, kSecPolicyCheckQualifiedCertStatements)) {
950 tf->unknownCritExtn = true;
951 } else if (CFEqual(key, kSecPolicyCheckAnchorTrusted)
952 || CFEqual(key, kSecPolicyCheckAnchorSHA1)) {
953 tf->untrustedAnchor = true;
954 } else if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
955 tf->hostnameMismatch = true;
956 } else if (CFEqual(key, kSecPolicyCheckValidIntermediates)
957 || CFEqual(key, kSecPolicyCheckValidLeaf)
958 || CFEqual(key, kSecPolicyCheckValidLeaf)) {
959 tf->invalidCert = true;
960 } else
961 /* Anything else is a policy failure. */
962 #if 0
963 if (CFEqual(key, kSecPolicyCheckNonEmptySubject)
964 || CFEqual(key, kSecPolicyCheckBasicContraints)
965 || CFEqual(key, kSecPolicyCheckKeyUsage)
966 || CFEqual(key, kSecPolicyCheckExtendedKeyUsage)
967 || CFEqual(key, kSecPolicyCheckIssuerCommonName)
968 || CFEqual(key, kSecPolicyCheckSubjectCommonNamePrefix)
969 || CFEqual(key, kSecPolicyCheckChainLength)
970 || CFEqual(key, kSecPolicyCheckNotValidBefore))
971 #endif
972 {
973 tf->policyFail = true;
974 }
975 }
976
977 static void appendError(CFMutableArrayRef properties, CFStringRef error) {
978 CFStringRef localizedError = SecFrameworkCopyLocalizedString(error,
979 CFSTR("SecCertificate"));
980 appendProperty(properties, kSecPropertyTypeError, NULL, NULL,
981 localizedError);
982 CFReleaseNull(localizedError);
983 }
984
985 CFArrayRef SecTrustCopyProperties(SecTrustRef trust) {
986 CFArrayRef details = SecTrustGetDetails(trust);
987 if (!details)
988 return NULL;
989
990 struct TrustFailures tf = {};
991
992 CFIndex ix, count = CFArrayGetCount(details);
993 for (ix = 0; ix < count; ++ix) {
994 CFDictionaryRef detail = (CFDictionaryRef)
995 CFArrayGetValueAtIndex(details, ix);
996 /* We now have a detail dictionary for certificate at index ix, with
997 a key value pair for each failed policy check. Let's convert it
998 from Ro-Man form into something a Hu-Man can understand. */
999 CFDictionaryApplyFunction(detail, applyDetailProperty, &tf);
1000 }
1001
1002 CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, 0,
1003 &kCFTypeArrayCallBacks);
1004 /* The badLinkage and unknownCritExtn failures are short circuited, since
1005 you can't recover from those errors. */
1006 if (tf.badLinkage) {
1007 appendError(properties, CFSTR("Invalid certificate chain linkage."));
1008 } else if (tf.unknownCritExtn) {
1009 appendError(properties, CFSTR("One or more unsupported critical extensions found."));
1010 } else {
1011 if (tf.untrustedAnchor) {
1012 appendError(properties, CFSTR("Root certificate is not trusted."));
1013 }
1014 if (tf.hostnameMismatch) {
1015 appendError(properties, CFSTR("Hostname mismatch."));
1016 }
1017 if (tf.policyFail) {
1018 appendError(properties, CFSTR("Policy requirements not met."));
1019 }
1020 if (tf.invalidCert) {
1021 appendError(properties, CFSTR("One or more certificates have expired or are not valid yet."));
1022 }
1023 }
1024
1025 if (CFArrayGetCount(properties) == 0) {
1026 /* The certificate chain is trusted, return an empty plist */
1027 CFReleaseNull(properties);
1028 }
1029
1030 return properties;
1031 }
1032
1033 CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) {
1034 // Builds and returns a dictionary of evaluation results.
1035 if (!trust) {
1036 return NULL;
1037 }
1038 CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0,
1039 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1040
1041 // kSecTrustResultDetails (per-cert results)
1042 CFArrayRef details = SecTrustGetDetails(trust);
1043 if (details) {
1044 CFDictionarySetValue(results, (const void *)kSecTrustResultDetails, (const void *)details);
1045 }
1046
1047 // kSecTrustResultValue (overall trust result)
1048 CFNumberRef numValue = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
1049 if (numValue) {
1050 CFDictionarySetValue(results, (const void *)kSecTrustResultValue, (const void *)numValue);
1051 CFRelease(numValue);
1052 }
1053 if (trust->_trustResult == kSecTrustResultInvalid || !trust->_info)
1054 return results; // we have nothing more to add
1055
1056 // kSecTrustEvaluationDate
1057 CFDateRef evaluationDate = trust->_verifyDate;
1058 if (evaluationDate) {
1059 CFDictionarySetValue(results, (const void *)kSecTrustEvaluationDate, (const void *)evaluationDate);
1060 }
1061
1062 // kSecTrustExtendedValidation, kSecTrustOrganizationName
1063 CFDictionaryRef info = trust->_info;
1064 if (info) {
1065 CFBooleanRef evValue;
1066 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoExtendedValidationKey, (const void **)&evValue)) {
1067 CFDictionarySetValue(results, (const void *)kSecTrustExtendedValidation, (const void *)evValue);
1068 }
1069 CFStringRef organizationName;
1070 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCompanyNameKey, (const void **)&organizationName)) {
1071 CFDictionarySetValue(results, (const void *)kSecTrustOrganizationName, (const void *)organizationName);
1072 }
1073 }
1074
1075 #if 0
1076 //FIXME: need to add revocation results here
1077 // kSecTrustRevocationChecked, kSecTrustRevocationValidUntilDate
1078 CFTypeRef expirationDate;
1079 if (CFDictionaryGetValueIfPresent(mExtendedResult, kSecTrustExpirationDate, (const void **)&expirationDate)) {
1080 CFDictionarySetValue(results, (const void *)kSecTrustRevocationValidUntilDate, (const void *)expirationDate);
1081 CFDictionarySetValue(results, (const void *)kSecTrustRevocationChecked, (const void *)kCFBooleanTrue);
1082 }
1083 #endif
1084
1085 return results;
1086 }
1087
1088 // Return 0 upon error.
1089 static int to_int_error_request(enum SecXPCOperation op, CFErrorRef *error) {
1090 __block int64_t result = 0;
1091 securityd_send_sync_and_do(op, error, NULL, ^bool(xpc_object_t response, CFErrorRef *error) {
1092 result = xpc_dictionary_get_int64(response, kSecXPCKeyResult);
1093 if (!result)
1094 return SecError(errSecInternal, error, CFSTR("int64 missing in response"));
1095 return true;
1096 });
1097 return (int)result;
1098 }
1099
1100 // version 0 -> error, so we need to start at version 1 or later.
1101 OSStatus SecTrustGetOTAPKIAssetVersionNumber(int* versionNumber)
1102 {
1103 return SecOSStatusWith(^bool(CFErrorRef *error) {
1104 if (!versionNumber)
1105 return SecError(errSecParam, error, CFSTR("versionNumber is NULL"));
1106
1107 return (*versionNumber = SECURITYD_XPC(sec_ota_pki_asset_version, to_int_error_request, error)) != 0;
1108 });
1109 }
1110
1111 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
1112
1113 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary, const char *key, xpc_type_t type)
1114 {
1115 xpc_object_t value = xpc_dictionary_get_value(dictionary, key);
1116
1117 return value && (xpc_get_type(value) == type);
1118 }
1119
1120 OSStatus SecTrustOTAPKIGetUpdatedAsset(int* didUpdateAsset)
1121 {
1122 CFErrorRef error = NULL;
1123 do_if_registered(sec_ota_pki_get_new_asset, &error);
1124
1125 int64_t num = 0;
1126 xpc_object_t message = securityd_create_message(kSecXPCOpOTAPKIGetNewAsset, &error);
1127 if (message)
1128 {
1129 xpc_object_t response = securityd_message_with_reply_sync(message, &error);
1130
1131 if (response && xpc_dictionary_entry_is_type(response, kSecXPCKeyResult, XPC_TYPE_INT64))
1132 {
1133 num = (int64_t) xpc_dictionary_get_int64(response, kSecXPCKeyResult);
1134 xpc_release(response);
1135 }
1136
1137 xpc_release(message);
1138 }
1139
1140 if (NULL != didUpdateAsset)
1141 {
1142 *didUpdateAsset = (int)num;
1143 }
1144 return noErr;
1145 }
1146
1147
1148 #if 0
1149 // MARK: -
1150 // MARK: SecTrustNode
1151 /********************************************************
1152 **************** SecTrustNode object *******************
1153 ********************************************************/
1154 typedef uint8_t SecFetchingState;
1155 enum {
1156 kSecFetchingStatePassedIn = 0,
1157 kSecFetchingStateLocal,
1158 kSecFetchingStateFromURL,
1159 kSecFetchingStateDone,
1160 };
1161
1162 typedef uint8_t SecTrustState;
1163 enum {
1164 kSecTrustStateUnknown = 0,
1165 kSecTrustStateNotSigner,
1166 kSecTrustStateValidSigner,
1167 };
1168
1169 typedef struct __SecTrustNode *SecTrustNodeRef;
1170 struct __SecTrustNode {
1171 SecTrustNodeRef _child;
1172 SecCertificateRef _certificate;
1173
1174 /* Cached information about _certificate */
1175 bool _isAnchor;
1176 bool _isSelfSigned;
1177
1178 /* Set of all certificates we have ever considered as a parent. We use
1179 this to avoid having to recheck certs when we go to the next phase. */
1180 CFMutableSet _certificates;
1181
1182 /* Parents that are still partial chains we haven't yet considered. */
1183 CFMutableSet _partials;
1184 /* Parents that are still partial chains we have rejected. We reconsider
1185 these if we get to the final phase and we still haven't found a valid
1186 candidate. */
1187 CFMutableSet _rejected_partials;
1188
1189 /* Parents that are complete chains we haven't yet considered. */
1190 CFMutableSet _candidates;
1191 /* Parents that are complete chains we have rejected. */
1192 CFMutableSet _rejected_candidates;
1193
1194 /* State of candidate fetching. */
1195 SecFetchingState _fetchingState;
1196
1197 /* Trust state of _candidates[_candidateIndex] */
1198 SecTrustState _trustState;
1199 };
1200 typedef struct __SecTrustNode SecTrustNode;
1201
1202 /* CFRuntime registration data. */
1203 static pthread_once_t kSecTrustNodeRegisterClass = PTHREAD_ONCE_INIT;
1204 static CFTypeID kSecTrustNodeTypeID = _kCFRuntimeNotATypeID;
1205
1206 /* Forward declarations of static functions. */
1207 static CFStringRef SecTrustNodeDescribe(CFTypeRef cf);
1208 static void SecTrustNodeDestroy(CFTypeRef cf);
1209
1210 /* Static functions. */
1211 static CFStringRef SecTrustNodeDescribe(CFTypeRef cf) {
1212 SecTrustNodeRef node = (SecTrustNodeRef)cf;
1213 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
1214 CFSTR("<SecTrustNodeRef: %p>"), node);
1215 }
1216
1217 static void SecTrustNodeDestroy(CFTypeRef cf) {
1218 SecTrustNodeRef trust = (SecTrustNodeRef)cf;
1219 if (trust->_child) {
1220 free(trust->_child);
1221 }
1222 if (trust->_certificate) {
1223 free(trust->_certificate);
1224 }
1225 if (trust->_candidates) {
1226 CFRelease(trust->_candidates);
1227 }
1228 }
1229
1230 static void SecTrustNodeRegisterClass(void) {
1231 static const CFRuntimeClass kSecTrustNodeClass = {
1232 0, /* version */
1233 "SecTrustNode", /* class name */
1234 NULL, /* init */
1235 NULL, /* copy */
1236 SecTrustNodeDestroy, /* dealloc */
1237 NULL, /* equal */
1238 NULL, /* hash */
1239 NULL, /* copyFormattingDesc */
1240 SecTrustNodeDescribe /* copyDebugDesc */
1241 };
1242
1243 kSecTrustNodeTypeID = _CFRuntimeRegisterClass(&kSecTrustNodeClass);
1244 }
1245
1246 /* SecTrustNode API functions. */
1247 CFTypeID SecTrustNodeGetTypeID(void) {
1248 pthread_once(&kSecTrustNodeRegisterClass, SecTrustNodeRegisterClass);
1249 return kSecTrustNodeTypeID;
1250 }
1251
1252 SecTrustNodeRef SecTrustNodeCreate(SecTrustRef trust,
1253 SecCertificateRef certificate, SecTrustNodeRef child) {
1254 CFAllocatorRef allocator = kCFAllocatorDefault;
1255 check(trust);
1256 check(certificate);
1257
1258 CFIndex size = sizeof(struct __SecTrustNode);
1259 SecTrustNodeRef result = (SecTrustNodeRef)_CFRuntimeCreateInstance(
1260 allocator, SecTrustNodeGetTypeID(), size - sizeof(CFRuntimeBase), 0);
1261 if (!result)
1262 return NULL;
1263
1264 memset((char*)result + sizeof(result->_base), 0,
1265 sizeof(*result) - sizeof(result->_base));
1266 if (child) {
1267 CFRetain(child);
1268 result->_child = child;
1269 }
1270 CFRetain(certificate);
1271 result->_certificate = certificate;
1272 result->_isAnchor = SecTrustCertificateIsAnchor(certificate);
1273
1274 return result;
1275 }
1276
1277 SecCertificateRef SecTrustGetCertificate(SecTrustNodeRef node) {
1278 check(node);
1279 return node->_certificate;
1280 }
1281
1282 CFArrayRef SecTrustNodeCopyProperties(SecTrustNodeRef node,
1283 SecTrustRef trust) {
1284 check(node);
1285 check(trust);
1286 CFMutableArrayRef summary = SecCertificateCopySummaryProperties(
1287 node->_certificate, SecTrustGetVerifyTime(trust));
1288 /* FIXME Add more details in the failure case. */
1289 return summary;
1290 }
1291
1292 /* Attempt to verify this node's signature chain down to the child. */
1293 SecTrustState SecTrustNodeVerifySignatureChain(SecTrustNodeRef node) {
1294 /* FIXME */
1295 return kSecTrustStateUnknown;
1296 }
1297
1298
1299 /* See if the next candidate works. */
1300 SecTrustNodeRef SecTrustNodeCopyNextCandidate(SecTrustNodeRef node,
1301 SecTrustRef trust, SecFetchingState fetchingState) {
1302 check(node);
1303 check(trust);
1304
1305 CFAbsoluteTime verifyTime = SecTrustGetVerifyTime(trust);
1306
1307 for (;;) {
1308 /* If we have any unconsidered candidates left check those first. */
1309 while (node->_candidateIndex < CFArrayGetCount(node->_candidates)) {
1310 SecCertificateRef candidate = (SecCertificateRef)
1311 CFArrayGetValueAtIndex(node->_candidates, node->_candidateIndex);
1312 if (node->_fetchingState != kSecFetchingStateDone) {
1313 /* If we still have potential sources to fetch other candidates
1314 from we ignore expired candidates. */
1315 if (!SecCertificateIsValidOn(candidate, verifyTime)) {
1316 node->_candidateIndex++;
1317 continue;
1318 }
1319 }
1320
1321 SecTrustNodeRef parent = SecTrustNodeCreate(candidate, node);
1322 CFArrayRemoveValueAtIndex(node->_candidates, node->_candidateIndex);
1323 if (SecTrustNodeVerifySignatureChain(parent) ==
1324 kSecTrustStateNotSigner) {
1325 /* This candidate parent is not a valid signer of its
1326 child. */
1327 CFRelease(parent);
1328 /* If another signature failed further down the chain we need
1329 to backtrack down to whatever child is still a valid
1330 candidate and has additional candidates to consider.
1331 @@@ We really want to make the fetchingState a global of
1332 SecTrust itself as well and not have any node go beyond the
1333 current state of SecTrust if there are other (read cheap)
1334 options to consider. */
1335 continue;
1336 }
1337 return parent;
1338 }
1339
1340 /* We've run out of candidates in our current state so let's try to
1341 find some more. Note we fetch candidates in increasing order of
1342 cost in the hope we won't ever get to the more expensive fetching
1343 methods. */
1344 SecCertificateRef certificate = node->_certificate;
1345 switch (node->_fetchingState) {
1346 case kSecFetchingStatePassedIn:
1347 /* Get the list of candidates from SecTrust. */
1348 CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
1349 if (akid) {
1350 SecTrustAppendCandidatesWithAuthorityKeyID(akid, node->_candidates);
1351 } else {
1352 CFDataRef issuer =
1353 SecCertificateGetNormalizedIssuerContent(certificate);
1354 SecTrustAppendCandidatesWithSubject(issuer, node->_candidates);
1355 }
1356 node->_fetchingState = kSecFetchingStateLocal;
1357 break;
1358 case kSecFetchingStateLocal:
1359 /* Lookup candidates in the local database. */
1360 node->_fetchingState = kSecFetchingStateFromURL;
1361 break;
1362 case kSecFetchingStateFromURL:
1363 node->_fetchingState = kSecFetchingStateCheckExpired;
1364 break;
1365 case kSecFetchingStateCheckExpired:
1366 /* Time to start considering expired candidates as well. */
1367 node->_candidateIndex = 0;
1368 node->_fetchingState = kSecFetchingStateDone;
1369 break;
1370 case kSecFetchingStateDone;
1371 return NULL;
1372 }
1373 }
1374
1375 CFAllocatorRef allocator = CFGetAllocator(node);
1376
1377 /* A trust node has a number of states.
1378 1) Look for issuing certificates by asking SecTrust about known
1379 parent certificates.
1380 2) Look for issuing certificates in certificate databases (keychains)
1381 3) Look for issuing certificates by going out to the web if the nodes
1382 certificate has a issuer location URL.
1383 4) Look through expired or not yet valid candidates we have put aside.
1384
1385 We go though the stages 1 though 3 looking for candidate issuer
1386 certificates. If a candidate certificate is not valid at verifyTime
1387 we put it in a to be examined later queue. If a candidate certificate
1388 is valid we verify if it actually signed our certificate (if possible).
1389 If not we discard it and continue on to the next candidate certificate.
1390 If it is we return a new SecTrustNodeRef for that certificate. */
1391
1392 CFMutableArrayRef issuers = CFArrayCreateMutable(allocator, 0,
1393 &kCFTypeArrayCallBacks);
1394
1395 /* Find a node's parent. */
1396 certificate = node->_certificate;
1397 CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
1398 CFTypeRef candidates = NULL;
1399 if (akid) {
1400 candidates = (CFTypeRef)CFDictionaryGetValueForKey(skidDict, akid);
1401 if (candidates) {
1402 addValidIssuersFrom(issuers, certificate, candidates, true);
1403 }
1404 }
1405 if (!candidates) {
1406 CFDataRef issuer =
1407 SecCertificateGetNormalizedIssuerContent(certificate);
1408 candidates = (CFTypeRef)
1409 CFDictionaryGetValueForKey(subjectDict, issuer);
1410 addValidIssuersFrom(issuers, certificate, candidates, false);
1411 }
1412
1413 if (CFArrayGetCount(issuers) == 0) {
1414 /* O no! we can't find an issuer for this certificate. Let's see
1415 if we can find one in the local database. */
1416 }
1417
1418 return errSecSuccess;
1419 }
1420
1421 CFArrayRef SecTrustNodeCopyNextChain(SecTrustNodeRef node,
1422 SecTrustRef trust) {
1423 /* Return the next full chain that isn't a reject unless we are in
1424 a state where we consider returning rejects. */
1425
1426 switch (node->_fetchingState) {
1427 case kSecFetchingStatePassedIn:
1428 /* Get the list of candidates from SecTrust. */
1429 CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
1430 if (akid) {
1431 SecTrustAppendCandidatesWithAuthorityKeyID(akid, node->_candidates);
1432 } else {
1433 CFDataRef issuer =
1434 SecCertificateGetNormalizedIssuerContent(certificate);
1435 SecTrustAppendCandidatesWithSubject(issuer, node->_candidates);
1436 }
1437 node->_fetchingState = kSecFetchingStateLocal;
1438 break;
1439 case kSecFetchingStateLocal:
1440 /* Lookup candidates in the local database. */
1441 node->_fetchingState = kSecFetchingStateFromURL;
1442 break;
1443 case kSecFetchingStateFromURL:
1444 node->_fetchingState = kSecFetchingStateCheckExpired;
1445 break;
1446 case kSecFetchingStateCheckExpired:
1447 /* Time to start considering expired candidates as well. */
1448 node->_candidateIndex = 0;
1449 node->_fetchingState = kSecFetchingStateDone;
1450 break;
1451 case kSecFetchingStateDone;
1452 return NULL;
1453 }
1454 }
1455
1456 class Source {
1457 Iterator parentIterator(Cert);
1458 };
1459
1460 class NodeCache {
1461 Set nodes;
1462
1463 static bool unique(Node node) {
1464 if (nodes.contains(node))
1465 return false;
1466 nodes.add(node);
1467 return true;
1468 }
1469
1470 static bool isAnchor(Cert cert);
1471 };
1472
1473 class Node {
1474 Cert cert;
1475 Node child;
1476 int nextSource;
1477 Iterator parentIterator; /* For current source of parents. */
1478
1479 Node(Cert inCert) : child(nil), cert(inCert), nextSource(0) {}
1480 Node(Node inChild, Cert inCert) : child(inChild), cert(inCert),
1481 nextSource(0) {}
1482
1483 CertPath certPath() {
1484 CertPath path;
1485 Node node = this;
1486 while (node) {
1487 path.add(node.cert);
1488 node = node.child;
1489 }
1490 return path;
1491 }
1492
1493 void contains(Cert cert) {
1494 Node node = this;
1495 while (node) {
1496 if (cert == node.cert)
1497 return true;
1498 node = node.child;
1499 }
1500 return false;
1501 }
1502
1503 Node nextParent(Array currentSources) {
1504 for (;;) {
1505 if (!nextSource ||
1506 parentIterator == currentSources[nextSource - 1].end()) {
1507 if (nextSource == currentSources.count) {
1508 /* We ran out of parent sources. */
1509 return nil;
1510 }
1511 parentIterator = currentSources[nextSource++].begin();
1512 }
1513 Certificate cert = *parentIterator++;
1514 /* Check for cycles and self signed chains. */
1515 if (!contains(cert)) {
1516 Node node = Node(this, parent);
1517 if (!NodeCache.unique(node))
1518 return node;
1519 }
1520 }
1521 }
1522 };
1523
1524
1525 class PathBuilder {
1526 List nodes;
1527 List rejects;
1528 Array currentSources;
1529 Iterator nit;
1530 Array allSources;
1531 Iterator sourceIT;
1532 CertPath chain;
1533
1534 PathBuilder(Cert cert) {
1535 nodes.append(Node(cert));
1536 nit = nodes.begin();
1537 sourceIT = allSources.begin();
1538 }
1539
1540 nextAnchoredPath() {
1541 if (nit == nodes.end()) {
1542 /* We should add another source to the list of sources to
1543 search. */
1544 if (sourceIT == allSources.end()) {
1545 /* No more sources to add. */
1546 }
1547 currentSources += *sourceIT++;
1548 /* Resort nodes by size. */
1549 Nodes.sortBySize();
1550 nit = nodes.begin();
1551 /* Set the source list for all nodes. */
1552
1553 }
1554 while (Node node = *nit) {
1555 Node candidate = node.nextParent(currentSources);
1556 if (!candidate) {
1557 /* The current node has no more candidate parents so move
1558 along. */
1559 nit++;
1560 continue;
1561 }
1562
1563 if (candidate.isAnchored) {
1564 candidates.append(candidate);
1565 } else
1566 nodes.insert(candidate, nit);
1567 }
1568 }
1569
1570 findValidPath() {
1571 while (Node node = nextAnchoredPath()) {
1572 if (node.isValid()) {
1573 chain = node.certPath;
1574 break;
1575 }
1576 rejects.append(node);
1577 }
1578 }
1579 }
1580
1581
1582 #endif