2 * Copyright (c) 2017-2018 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <AssertMacros.h>
26 #include <dirhelper_priv.h>
28 #include <sys/types.h>
31 #include <xpc/private.h>
33 #include <CoreFoundation/CFStream.h>
34 #include <os/assumes.h>
36 #include <Security/SecuritydXPC.h>
37 #include <Security/SecTrustStore.h>
38 #include <Security/SecCertificateInternal.h>
39 #include <Security/SecEntitlements.h>
40 #include <Security/SecTrustInternal.h>
41 #include <Security/SecPolicyPriv.h>
42 #include <Security/SecItem.h>
43 #include <Security/SecItemPriv.h>
45 #include <ipc/securityd_client.h>
46 #include <ipc/server_entitlement_helpers.h>
47 #include <utilities/SecCFWrappers.h>
48 #include <utilities/SecDb.h>
49 #include <utilities/SecFileLocations.h>
50 #include <utilities/debugging.h>
51 #include <utilities/SecXPCError.h>
52 #include <securityd/SecOCSPCache.h>
53 #include <securityd/SecTrustStoreServer.h>
54 #include <securityd/SecPinningDb.h>
55 #include <securityd/SecPolicyServer.h>
56 #include <securityd/SecRevocationDb.h>
57 #include <securityd/SecTrustServer.h>
58 #include <securityd/spi.h>
59 #include <securityd/SecTrustLoggingServer.h>
61 #include <securityd/SecTrustExceptionResetCount.h>
65 #include <Security/SecTaskPriv.h>
66 #include <login/SessionAgentStatusCom.h>
67 #include <trustd/macOS/SecTrustOSXEntryPoints.h>
70 #include "OTATrustUtilities.h"
71 #include "trustd_spi.h"
73 static bool SecXPCDictionarySetChainOptional(xpc_object_t message
, const char *key
, CFArrayRef path
, CFErrorRef
*error
) {
76 __block xpc_object_t xpc_chain
= NULL
;
77 require_action_quiet(xpc_chain
= xpc_array_create(NULL
, 0), exit
, SecError(errSecParam
, error
, CFSTR("xpc_array_create failed")));
78 CFArrayForEach(path
, ^(const void *value
) {
79 SecCertificateRef cert
= (SecCertificateRef
)value
;
80 if (xpc_chain
&& !SecCertificateAppendToXPCArray(cert
, xpc_chain
, error
)) {
81 xpc_release(xpc_chain
);
90 xpc_dictionary_set_value(message
, key
, xpc_chain
);
91 xpc_release(xpc_chain
);
95 static SecCertificateRef
SecXPCDictionaryCopyCertificate(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
97 const void *bytes
= xpc_dictionary_get_data(message
, key
, &length
);
99 SecCertificateRef certificate
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, bytes
, length
);
102 SecError(errSecDecode
, error
, CFSTR("object for key %s failed to create certificate from data"), key
);
104 SecError(errSecParam
, error
, CFSTR("object for key %s missing"), key
);
109 static bool SecXPCDictionaryCopyCertificates(xpc_object_t message
, const char *key
, CFArrayRef
*certificates
, CFErrorRef
*error
) {
110 xpc_object_t xpc_certificates
= xpc_dictionary_get_value(message
, key
);
111 if (!xpc_certificates
)
112 return SecError(errSecAllocate
, error
, CFSTR("no certs for key %s"), key
);
113 *certificates
= SecCertificateXPCArrayCopyArray(xpc_certificates
, error
);
114 return *certificates
;
117 static bool SecXPCDictionaryCopyCertificatesOptional(xpc_object_t message
, const char *key
, CFArrayRef
*certificates
, CFErrorRef
*error
) {
118 xpc_object_t xpc_certificates
= xpc_dictionary_get_value(message
, key
);
119 if (!xpc_certificates
) {
120 *certificates
= NULL
;
123 *certificates
= SecCertificateXPCArrayCopyArray(xpc_certificates
, error
);
124 return *certificates
;
127 static bool SecXPCDictionaryCopyPoliciesOptional(xpc_object_t message
, const char *key
, CFArrayRef
*policies
, CFErrorRef
*error
) {
128 xpc_object_t xpc_policies
= xpc_dictionary_get_value(message
, key
);
134 *policies
= SecPolicyXPCArrayCopyArray(xpc_policies
, error
);
135 return *policies
!= NULL
;
138 // Returns error if entitlement isn't present.
140 EntitlementPresentAndTrue(uint64_t op
, SecTaskRef clientTask
, CFStringRef entitlement
, CFErrorRef
*error
)
142 if (!SecTaskGetBooleanValueForEntitlement(clientTask
, entitlement
)) {
143 SecError(errSecMissingEntitlement
, error
, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation
)op
), clientTask
, entitlement
);
149 static SecTrustStoreRef
SecXPCDictionaryGetTrustStore(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
150 SecTrustStoreRef ts
= NULL
;
151 CFStringRef domain
= SecXPCDictionaryCopyString(message
, key
, error
);
153 ts
= SecTrustStoreForDomainName(domain
, error
);
159 static bool SecXPCTrustStoreContains(SecurityClient
* __unused client
, xpc_object_t event
,
160 xpc_object_t reply
, CFErrorRef
*error
) {
162 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
164 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
167 if (SecTrustStoreContainsCertificateWithDigest(ts
, digest
, &contains
, error
)) {
168 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, contains
);
171 CFReleaseNull(digest
);
177 static bool SecXPCTrustStoreSetTrustSettings(SecurityClient
* __unused client
, xpc_object_t event
,
178 xpc_object_t reply
, CFErrorRef
*error
) {
179 bool noError
= false;
180 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
182 SecCertificateRef certificate
= SecXPCDictionaryCopyCertificate(event
, kSecXPCKeyCertificate
, error
);
184 CFTypeRef trustSettingsDictOrArray
= NULL
;
185 if (SecXPCDictionaryCopyPListOptional(event
, kSecXPCKeySettings
, &trustSettingsDictOrArray
, error
)) {
186 bool result
= _SecTrustStoreSetTrustSettings(ts
, certificate
, trustSettingsDictOrArray
, error
);
187 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
189 CFReleaseSafe(trustSettingsDictOrArray
);
191 CFReleaseNull(certificate
);
197 static bool SecXPCTrustStoreRemoveCertificate(SecurityClient
* __unused client
, xpc_object_t event
,
198 xpc_object_t reply
, CFErrorRef
*error
) {
199 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
201 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
203 bool result
= SecTrustStoreRemoveCertificateWithDigest(ts
, digest
, error
);
204 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
205 CFReleaseNull(digest
);
212 static bool SecXPCTrustStoreCopyAll(SecurityClient
* __unused client
, xpc_object_t event
,
213 xpc_object_t reply
, CFErrorRef
*error
) {
214 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
216 CFArrayRef trustStoreContents
= NULL
;
217 if(_SecTrustStoreCopyAll(ts
, &trustStoreContents
, error
) && trustStoreContents
) {
218 SecXPCDictionarySetPList(reply
, kSecXPCKeyResult
, trustStoreContents
, error
);
219 CFReleaseNull(trustStoreContents
);
226 static bool SecXPCTrustStoreCopyUsageConstraints(SecurityClient
* __unused client
, xpc_object_t event
,
227 xpc_object_t reply
, CFErrorRef
*error
) {
229 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
231 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
233 CFArrayRef usageConstraints
= NULL
;
234 if(_SecTrustStoreCopyUsageConstraints(ts
, digest
, &usageConstraints
, error
) && usageConstraints
) {
235 SecXPCDictionarySetPList(reply
, kSecXPCKeyResult
, usageConstraints
, error
);
236 CFReleaseNull(usageConstraints
);
239 CFReleaseNull(digest
);
245 static bool SecXPC_OCSPCacheFlush(SecurityClient
* __unused client
, xpc_object_t __unused event
,
246 xpc_object_t __unused reply
, CFErrorRef
*error
) {
247 if(SecOCSPCacheFlush(error
)) {
253 static bool SecXPC_OTAPKI_GetCurrentTrustStoreVersion(SecurityClient
* __unused client
, xpc_object_t __unused event
,
254 xpc_object_t reply
, CFErrorRef
*error
) {
255 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, SecOTAPKIGetCurrentTrustStoreVersion(error
));
259 static bool SecXPC_OTAPKI_GetCurrentAssetVersion(SecurityClient
* __unused client
, xpc_object_t __unused event
,
260 xpc_object_t reply
, CFErrorRef
*error
) {
261 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, SecOTAPKIGetCurrentAssetVersion(error
));
265 static bool SecXPC_OTAPKI_GetEscrowCertificates(SecurityClient
* __unused client
, xpc_object_t event
,
266 xpc_object_t reply
, CFErrorRef
*error
) {
268 uint32_t escrowRootType
= (uint32_t)xpc_dictionary_get_uint64(event
, "escrowType");
269 CFArrayRef array
= SecOTAPKICopyCurrentEscrowCertificates(escrowRootType
, error
);
271 xpc_object_t xpc_array
= _CFXPCCreateXPCObjectFromCFObject(array
);
272 xpc_dictionary_set_value(reply
, kSecXPCKeyResult
, xpc_array
);
273 xpc_release(xpc_array
);
276 CFReleaseNull(array
);
280 static bool SecXPC_OTAPKI_GetNewAsset(SecurityClient
* __unused client
, xpc_object_t __unused event
,
281 xpc_object_t reply
, CFErrorRef
*error
) {
282 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, SecOTAPKISignalNewAsset(error
));
286 static bool SecXPC_OTASecExperiment_GetNewAsset(SecurityClient
* __unused client
, xpc_object_t __unused event
,
287 xpc_object_t reply
, CFErrorRef
*error
) {
288 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, SecOTASecExperimentGetNewAsset(error
));
292 static bool SecXPC_OTASecExperiment_GetAsset(SecurityClient
* __unused client
, xpc_object_t __unused event
,
293 xpc_object_t reply
, CFErrorRef
*error
) {
295 CFDictionaryRef asset
= SecOTASecExperimentCopyAsset(error
);
297 xpc_object_t xpc_dict
= _CFXPCCreateXPCObjectFromCFObject(asset
);
299 xpc_dictionary_set_value(reply
, kSecXPCKeyResult
, xpc_dict
);
300 xpc_release(xpc_dict
);
304 CFReleaseNull(asset
);
308 static bool SecXPC_OTAPKI_CopyTrustedCTLogs(SecurityClient
* __unused client
, xpc_object_t event
,
309 xpc_object_t reply
, CFErrorRef
*error
) {
311 CFDictionaryRef trustedLogs
= SecOTAPKICopyCurrentTrustedCTLogs(error
);
313 xpc_object_t xpc_dictionary
= _CFXPCCreateXPCObjectFromCFObject(trustedLogs
);
314 if (xpc_dictionary
) {
315 xpc_dictionary_set_value(reply
, kSecXPCKeyResult
, xpc_dictionary
);
316 xpc_release(xpc_dictionary
);
320 CFReleaseNull(trustedLogs
);
324 static bool SecXPC_OTAPKI_CopyCTLogForKeyID(SecurityClient
* __unused client
, xpc_object_t event
,
325 xpc_object_t reply
, CFErrorRef
*error
) {
328 const void *bytes
= xpc_dictionary_get_data(event
, kSecXPCData
, &length
);
329 CFDataRef keyID
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, bytes
, length
, kCFAllocatorNull
);
331 CFDictionaryRef logDict
= SecOTAPKICopyCTLogForKeyID(keyID
, error
);
333 xpc_object_t xpc_dictionary
= _CFXPCCreateXPCObjectFromCFObject(logDict
);
334 xpc_dictionary_set_value(reply
, kSecXPCKeyResult
, xpc_dictionary
);
335 xpc_release(xpc_dictionary
);
336 CFReleaseNull(logDict
);
339 CFReleaseNull(keyID
);
344 static bool SecXPC_Networking_AnalyticsReport(SecurityClient
* __unused client
, xpc_object_t event
,
345 xpc_object_t reply
, CFErrorRef
*error
) {
346 xpc_object_t attributes
= xpc_dictionary_get_dictionary(event
, kSecTrustEventAttributesKey
);
347 CFStringRef eventName
= SecXPCDictionaryCopyString(event
, kSecTrustEventNameKey
, error
);
349 if (attributes
&& eventName
) {
350 result
= SecNetworkingAnalyticsReport(eventName
, attributes
, error
);
352 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
353 CFReleaseNull(eventName
);
357 static bool SecXPCTrustStoreSetCTExceptions(SecurityClient
*client
, xpc_object_t event
,
358 xpc_object_t reply
, CFErrorRef
*error
) {
359 CFStringRef appID
= NULL
;
360 CFDictionaryRef exceptions
= NULL
;
361 if (!SecXPCDictionaryCopyStringOptional(event
, kSecTrustEventApplicationID
, &appID
, error
) || !appID
) {
362 /* We always want to set the app ID with the exceptions */
363 appID
= SecTaskCopyApplicationIdentifier(client
->task
);
365 (void)SecXPCDictionaryCopyDictionaryOptional(event
, kSecTrustExceptionsKey
, &exceptions
, error
);
366 bool result
= _SecTrustStoreSetCTExceptions(appID
, exceptions
, error
);
367 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
368 CFReleaseNull(exceptions
);
369 CFReleaseNull(appID
);
373 static bool SecXPCTrustStoreCopyCTExceptions(SecurityClient
* __unused client
, xpc_object_t event
,
374 xpc_object_t reply
, CFErrorRef
*error
) {
375 CFStringRef appID
= NULL
;
376 (void)SecXPCDictionaryCopyStringOptional(event
, kSecTrustEventApplicationID
, &appID
, error
);
377 CFDictionaryRef exceptions
= _SecTrustStoreCopyCTExceptions(appID
, error
);
378 SecXPCDictionarySetPListOptional(reply
, kSecTrustExceptionsKey
, exceptions
, error
);
379 CFReleaseNull(exceptions
);
380 CFReleaseNull(appID
);
385 static bool SecXPCTrustGetExceptionResetCount(SecurityClient
* __unused client
, xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
386 uint64_t exceptionResetCount
= SecTrustServerGetExceptionResetCount(error
);
387 if (error
&& *error
) {
391 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, exceptionResetCount
);
395 static bool SecXPCTrustIncrementExceptionResetCount(SecurityClient
* __unused client
, xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
396 OSStatus status
= errSecInternal
;
397 bool result
= SecTrustServerIncrementExceptionResetCount(error
);
398 if (result
&& (!error
|| (error
&& !*error
))) {
399 status
= errSecSuccess
;
402 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, status
);
407 typedef bool(*SecXPCOperationHandler
)(SecurityClient
*client
, xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
);
410 CFStringRef entitlement
;
411 SecXPCOperationHandler handler
;
412 } SecXPCServerOperation
;
414 struct trustd_operations
{
415 SecXPCServerOperation trust_store_contains
;
416 SecXPCServerOperation trust_store_set_trust_settings
;
417 SecXPCServerOperation trust_store_remove_certificate
;
418 SecXPCServerOperation trust_store_copy_all
;
419 SecXPCServerOperation trust_store_copy_usage_constraints
;
420 SecXPCServerOperation ocsp_cache_flush
;
421 SecXPCServerOperation ota_pki_trust_store_version
;
422 SecXPCServerOperation ota_pki_asset_version
;
423 SecXPCServerOperation ota_pki_get_escrow_certs
;
424 SecXPCServerOperation ota_pki_get_new_asset
;
425 SecXPCServerOperation ota_pki_copy_trusted_ct_logs
;
426 SecXPCServerOperation ota_pki_copy_ct_log_for_keyid
;
427 SecXPCServerOperation networking_analytics_report
;
428 SecXPCServerOperation trust_store_set_ct_exceptions
;
429 SecXPCServerOperation trust_store_copy_ct_exceptions
;
430 SecXPCServerOperation ota_secexperiment_get_asset
;
431 SecXPCServerOperation ota_secexperiment_get_new_asset
;
433 SecXPCServerOperation trust_get_exception_reset_count
;
434 SecXPCServerOperation trust_increment_exception_reset_count
;
438 static struct trustd_operations trustd_ops
= {
439 .trust_store_contains
= { NULL
, SecXPCTrustStoreContains
},
440 .trust_store_set_trust_settings
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreSetTrustSettings
},
441 .trust_store_remove_certificate
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreRemoveCertificate
},
442 .trust_store_copy_all
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyAll
},
443 .trust_store_copy_usage_constraints
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyUsageConstraints
},
444 .ocsp_cache_flush
= { NULL
, SecXPC_OCSPCacheFlush
},
445 .ota_pki_trust_store_version
= { NULL
, SecXPC_OTAPKI_GetCurrentTrustStoreVersion
},
446 .ota_pki_asset_version
= { NULL
, SecXPC_OTAPKI_GetCurrentAssetVersion
},
447 .ota_pki_get_escrow_certs
= { NULL
, SecXPC_OTAPKI_GetEscrowCertificates
},
448 .ota_pki_get_new_asset
= { NULL
, SecXPC_OTAPKI_GetNewAsset
},
449 .ota_secexperiment_get_new_asset
= { NULL
, SecXPC_OTASecExperiment_GetNewAsset
},
450 .ota_secexperiment_get_asset
= { NULL
, SecXPC_OTASecExperiment_GetAsset
},
451 .ota_pki_copy_trusted_ct_logs
= { NULL
, SecXPC_OTAPKI_CopyTrustedCTLogs
},
452 .ota_pki_copy_ct_log_for_keyid
= { NULL
, SecXPC_OTAPKI_CopyCTLogForKeyID
},
453 .networking_analytics_report
= { NULL
, SecXPC_Networking_AnalyticsReport
},
454 .trust_store_set_ct_exceptions
= {kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreSetCTExceptions
},
455 .trust_store_copy_ct_exceptions
= {kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyCTExceptions
},
457 .trust_get_exception_reset_count
= { NULL
, SecXPCTrustGetExceptionResetCount
},
458 .trust_increment_exception_reset_count
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustIncrementExceptionResetCount
},
462 static void trustd_xpc_dictionary_handler(const xpc_connection_t connection
, xpc_object_t event
) {
463 xpc_type_t type
= xpc_get_type(event
);
464 __block CFErrorRef error
= NULL
;
465 xpc_object_t xpcError
= NULL
;
466 xpc_object_t replyMessage
= NULL
;
467 CFDataRef clientAuditToken
= NULL
;
468 CFArrayRef domains
= NULL
;
469 SecurityClient client
= {
471 .accessGroups
= NULL
,
473 .uid
= xpc_connection_get_euid(connection
),
474 .allowSystemKeychain
= true,
475 .allowSyncBubbleKeychain
= false,
476 .isNetworkExtension
= false,
477 .canAccessNetworkExtensionAccessGroups
= false,
479 .inMultiUser
= false,
483 secdebug("serverxpc", "entering");
484 if (type
== XPC_TYPE_DICTIONARY
) {
485 replyMessage
= xpc_dictionary_create_reply(event
);
487 uint64_t operation
= xpc_dictionary_get_uint64(event
, kSecXPCKeyOperation
);
489 audit_token_t auditToken
= {};
490 xpc_connection_get_audit_token(connection
, &auditToken
);
492 client
.task
= SecTaskCreateWithAuditToken(kCFAllocatorDefault
, auditToken
);
493 clientAuditToken
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)&auditToken
, sizeof(auditToken
));
494 client
.accessGroups
= SecTaskCopyAccessGroups(client
.task
);
496 secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64
")", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), operation
);
498 if (operation
== sec_trust_evaluate_id
) {
499 CFArrayRef certificates
= NULL
, anchors
= NULL
, policies
= NULL
, responses
= NULL
, scts
= NULL
, trustedLogs
= NULL
, exceptions
= NULL
;
500 bool anchorsOnly
= xpc_dictionary_get_bool(event
, kSecTrustAnchorsOnlyKey
);
501 bool keychainsAllowed
= xpc_dictionary_get_bool(event
, kSecTrustKeychainsAllowedKey
);
503 if (SecXPCDictionaryCopyCertificates(event
, kSecTrustCertificatesKey
, &certificates
, &error
) &&
504 SecXPCDictionaryCopyCertificatesOptional(event
, kSecTrustAnchorsKey
, &anchors
, &error
) &&
505 SecXPCDictionaryCopyPoliciesOptional(event
, kSecTrustPoliciesKey
, &policies
, &error
) &&
506 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustResponsesKey
, &responses
, &error
) &&
507 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustSCTsKey
, &scts
, &error
) &&
508 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustTrustedLogsKey
, &trustedLogs
, &error
) &&
509 SecXPCDictionaryGetDouble(event
, kSecTrustVerifyDateKey
, &verifyTime
, &error
) &&
510 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustExceptionsKey
, &exceptions
, &error
)) {
511 // If we have no error yet, capture connection and reply in block and properly retain them.
512 xpc_retain(connection
);
513 CFRetainSafe(client
.task
);
514 CFRetainSafe(clientAuditToken
);
516 // Clear replyMessage so we don't send a synchronous reply.
517 xpc_object_t asyncReply
= replyMessage
;
520 SecTrustServerEvaluateBlock(SecTrustServerGetWorkloop(), clientAuditToken
, certificates
, anchors
, anchorsOnly
, keychainsAllowed
, policies
,
521 responses
, scts
, trustedLogs
, verifyTime
, client
.accessGroups
, exceptions
,
522 ^(SecTrustResultType tr
, CFArrayRef details
, CFDictionaryRef info
, CFArrayRef chain
,
523 CFErrorRef replyError
) {
524 // Send back reply now
526 CFRetain(replyError
);
528 xpc_dictionary_set_int64(asyncReply
, kSecTrustResultKey
, tr
);
529 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustDetailsKey
, details
, &replyError
) &&
530 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustInfoKey
, info
, &replyError
) &&
531 SecXPCDictionarySetChainOptional(asyncReply
, kSecTrustChainKey
, chain
, &replyError
);
534 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyError
);
535 xpc_object_t xpcReplyError
= SecCreateXPCObjectWithCFError(replyError
);
537 xpc_dictionary_set_value(asyncReply
, kSecXPCKeyError
, xpcReplyError
);
538 xpc_release(xpcReplyError
);
540 CFReleaseNull(replyError
);
542 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), asyncReply
);
545 xpc_connection_send_message(connection
, asyncReply
);
546 xpc_release(asyncReply
);
547 xpc_release(connection
);
548 CFReleaseSafe(client
.task
);
549 CFReleaseSafe(clientAuditToken
);
552 CFReleaseSafe(policies
);
553 CFReleaseSafe(anchors
);
554 CFReleaseSafe(certificates
);
555 CFReleaseSafe(responses
);
557 CFReleaseSafe(trustedLogs
);
558 CFReleaseSafe(exceptions
);
560 SecXPCServerOperation
*server_op
= NULL
;
562 case sec_trust_store_contains_id
:
563 server_op
= &trustd_ops
.trust_store_contains
;
565 case sec_trust_store_set_trust_settings_id
:
566 server_op
= &trustd_ops
.trust_store_set_trust_settings
;
568 case sec_trust_store_remove_certificate_id
:
569 server_op
= &trustd_ops
.trust_store_remove_certificate
;
571 case sec_trust_store_copy_all_id
:
572 server_op
= &trustd_ops
.trust_store_copy_all
;
574 case sec_trust_store_copy_usage_constraints_id
:
575 server_op
= &trustd_ops
.trust_store_copy_usage_constraints
;
577 case sec_ocsp_cache_flush_id
:
578 server_op
= &trustd_ops
.ocsp_cache_flush
;
580 case sec_ota_pki_trust_store_version_id
:
581 server_op
= &trustd_ops
.ota_pki_trust_store_version
;
583 case sec_ota_pki_asset_version_id
:
584 server_op
= &trustd_ops
.ota_pki_asset_version
;
586 case kSecXPCOpOTAGetEscrowCertificates
:
587 server_op
= &trustd_ops
.ota_pki_get_escrow_certs
;
589 case kSecXPCOpOTAPKIGetNewAsset
:
590 server_op
= &trustd_ops
.ota_pki_get_new_asset
;
592 case kSecXPCOpOTASecExperimentGetNewAsset
:
593 server_op
= &trustd_ops
.ota_secexperiment_get_new_asset
;
595 case kSecXPCOpOTASecExperimentGetAsset
:
596 server_op
= &trustd_ops
.ota_secexperiment_get_asset
;
598 case kSecXPCOpOTAPKICopyTrustedCTLogs
:
599 server_op
= &trustd_ops
.ota_pki_copy_trusted_ct_logs
;
601 case kSecXPCOpOTAPKICopyCTLogForKeyID
:
602 server_op
= &trustd_ops
.ota_pki_copy_ct_log_for_keyid
;
604 case kSecXPCOpNetworkingAnalyticsReport
:
605 server_op
= &trustd_ops
.networking_analytics_report
;
607 case kSecXPCOpSetCTExceptions
:
608 server_op
= &trustd_ops
.trust_store_set_ct_exceptions
;
610 case kSecXPCOpCopyCTExceptions
:
611 server_op
= &trustd_ops
.trust_store_copy_ct_exceptions
;
614 case sec_trust_get_exception_reset_count_id
:
615 server_op
= &trustd_ops
.trust_get_exception_reset_count
;
617 case sec_trust_increment_exception_reset_count_id
:
618 server_op
= &trustd_ops
.trust_increment_exception_reset_count
;
624 if (server_op
&& server_op
->handler
) {
625 bool entitled
= true;
626 if (server_op
->entitlement
) {
627 entitled
= EntitlementPresentAndTrue(operation
, client
.task
, server_op
->entitlement
, &error
);
630 (void)server_op
->handler(&client
, event
, replyMessage
, &error
);
637 if(SecErrorGetOSStatus(error
) == errSecItemNotFound
)
638 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
639 else if (SecErrorGetOSStatus(error
) == errSecAuthNeeded
)
640 secwarning("Authentication is needed %@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
642 secerror("%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
644 xpcError
= SecCreateXPCObjectWithCFError(error
);
646 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyError
, xpcError
);
648 } else if (replyMessage
) {
649 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyMessage
);
652 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, &error
, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event
);
653 secerror("%@: returning error: %@", client
.task
, error
);
654 xpcError
= SecCreateXPCObjectWithCFError(error
);
655 replyMessage
= xpc_create_reply_with_format(event
, "{%string: %value}", kSecXPCKeyError
, xpcError
);
659 xpc_connection_send_message(connection
, replyMessage
);
660 xpc_release(replyMessage
);
663 xpc_release(xpcError
);
664 CFReleaseSafe(error
);
665 CFReleaseSafe(client
.accessGroups
);
666 CFReleaseSafe(client
.musr
);
667 CFReleaseSafe(client
.task
);
668 CFReleaseSafe(domains
);
669 CFReleaseSafe(clientAuditToken
);
672 static void trustd_xpc_init(const char *service_name
)
674 secdebug("serverxpc", "start");
675 xpc_connection_t listener
= xpc_connection_create_mach_service(service_name
, NULL
, XPC_CONNECTION_MACH_SERVICE_LISTENER
);
677 seccritical("security failed to register xpc listener for %s, exiting", service_name
);
681 xpc_connection_set_event_handler(listener
, ^(xpc_object_t connection
) {
682 if (xpc_get_type(connection
) == XPC_TYPE_CONNECTION
) {
683 xpc_connection_set_target_queue(connection
, SecTrustServerGetWorkloop());
684 xpc_connection_set_event_handler(connection
, ^(xpc_object_t event
) {
685 if (xpc_get_type(event
) == XPC_TYPE_DICTIONARY
) {
686 trustd_xpc_dictionary_handler(connection
, event
);
689 xpc_connection_activate(connection
);
692 xpc_connection_activate(listener
);
695 static void trustd_sandbox(void) {
697 char buf
[PATH_MAX
] = "";
699 if (!_set_user_dir_suffix("com.apple.trustd") ||
700 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
)) == 0 ||
701 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
702 secerror("failed to initialize temporary directory (%d): %s", errno
, strerror(errno
));
706 char *tempdir
= realpath(buf
, NULL
);
707 if (tempdir
== NULL
) {
708 secerror("failed to resolve temporary directory (%d): %s", errno
, strerror(errno
));
712 if (confstr(_CS_DARWIN_USER_CACHE_DIR
, buf
, sizeof(buf
)) == 0 ||
713 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
714 secerror("failed to initialize cache directory (%d): %s", errno
, strerror(errno
));
718 char *cachedir
= realpath(buf
, NULL
);
719 if (cachedir
== NULL
) {
720 secerror("failed to resolve cache directory (%d): %s", errno
, strerror(errno
));
724 const char *parameters
[] = {
726 "_DARWIN_CACHE_DIR", cachedir
,
730 char *sberror
= NULL
;
731 if (sandbox_init_with_parameters("com.apple.trustd", SANDBOX_NAMED
, parameters
, &sberror
) != 0) {
732 secerror("Failed to enter trustd sandbox: %{public}s", sberror
);
738 #else // !TARGET_OS_OSX
739 char buf
[PATH_MAX
] = "";
740 _set_user_dir_suffix("com.apple.trustd");
741 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
));
742 #endif // !TARGET_OS_OSX
745 int main(int argc
, char *argv
[])
747 DisableLocalization();
749 char *wait4debugger
= getenv("WAIT4DEBUGGER");
750 if (wait4debugger
&& !strcasecmp("YES", wait4debugger
)) {
751 seccritical("SIGSTOPing self, awaiting debugger");
752 kill(getpid(), SIGSTOP
);
753 seccritical("Again, for good luck (or bad debuggers)");
754 kill(getpid(), SIGSTOP
);
759 const char *serviceName
= kTrustdXPCServiceName
;
760 if (argc
> 1 && (!strcmp(argv
[1], "--agent"))) {
761 serviceName
= kTrustdAgentXPCServiceName
;
764 /* set up SQLite before some other component has a chance to create a database connection */
767 gTrustd
= &trustd_spi
;
769 /* Initialize static content */
770 SecPolicyServerInitialize(); // set up callbacks for policy checks
771 SecRevocationDbInitialize(); // set up revocation database if it doesn't already exist, or needs to be replaced
772 SecPinningDbInitialize(); // set up the pinning database
774 SecTrustLegacySourcesListenForKeychainEvents(); // set up the legacy keychain event listeners (for cache invalidation)
777 /* We're ready now. Go. */
778 trustd_xpc_init(serviceName
);