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