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>
62 #include <Security/SecTaskPriv.h>
63 #include <login/SessionAgentStatusCom.h>
64 #include <trustd/macOS/SecTrustOSXEntryPoints.h>
67 #include "OTATrustUtilities.h"
69 static struct trustd trustd_spi
= {
70 .sec_trust_store_for_domain
= SecTrustStoreForDomainName
,
71 .sec_trust_store_contains
= SecTrustStoreContainsCertificateWithDigest
,
72 .sec_trust_store_set_trust_settings
= _SecTrustStoreSetTrustSettings
,
73 .sec_trust_store_remove_certificate
= SecTrustStoreRemoveCertificateWithDigest
,
74 .sec_truststore_remove_all
= _SecTrustStoreRemoveAll
,
75 .sec_trust_evaluate
= SecTrustServerEvaluate
,
76 .sec_ota_pki_trust_store_version
= SecOTAPKIGetCurrentTrustStoreVersion
,
77 .sec_ota_pki_asset_version
= SecOTAPKIGetCurrentAssetVersion
,
78 .ota_CopyEscrowCertificates
= SecOTAPKICopyCurrentEscrowCertificates
,
79 .sec_ota_pki_get_new_asset
= SecOTAPKISignalNewAsset
,
80 .sec_trust_store_copy_all
= _SecTrustStoreCopyAll
,
81 .sec_trust_store_copy_usage_constraints
= _SecTrustStoreCopyUsageConstraints
,
82 .sec_ocsp_cache_flush
= SecOCSPCacheFlush
,
83 .sec_networking_analytics_report
= SecNetworkingAnalyticsReport
,
84 .sec_trust_store_set_ct_exceptions
= _SecTrustStoreSetCTExceptions
,
85 .sec_trust_store_copy_ct_exceptions
= _SecTrustStoreCopyCTExceptions
,
88 static bool SecXPCDictionarySetChainOptional(xpc_object_t message
, const char *key
, CFArrayRef path
, CFErrorRef
*error
) {
91 __block xpc_object_t xpc_chain
= NULL
;
92 require_action_quiet(xpc_chain
= xpc_array_create(NULL
, 0), exit
, SecError(errSecParam
, error
, CFSTR("xpc_array_create failed")));
93 CFArrayForEach(path
, ^(const void *value
) {
94 SecCertificateRef cert
= (SecCertificateRef
)value
;
95 if (xpc_chain
&& !SecCertificateAppendToXPCArray(cert
, xpc_chain
, error
)) {
96 xpc_release(xpc_chain
);
105 xpc_dictionary_set_value(message
, key
, xpc_chain
);
106 xpc_release(xpc_chain
);
110 static SecCertificateRef
SecXPCDictionaryCopyCertificate(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
112 const void *bytes
= xpc_dictionary_get_data(message
, key
, &length
);
114 SecCertificateRef certificate
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, bytes
, length
);
117 SecError(errSecDecode
, error
, CFSTR("object for key %s failed to create certificate from data"), key
);
119 SecError(errSecParam
, error
, CFSTR("object for key %s missing"), key
);
124 static bool SecXPCDictionaryCopyCertificates(xpc_object_t message
, const char *key
, CFArrayRef
*certificates
, CFErrorRef
*error
) {
125 xpc_object_t xpc_certificates
= xpc_dictionary_get_value(message
, key
);
126 if (!xpc_certificates
)
127 return SecError(errSecAllocate
, error
, CFSTR("no certs for key %s"), key
);
128 *certificates
= SecCertificateXPCArrayCopyArray(xpc_certificates
, error
);
129 return *certificates
;
132 static bool SecXPCDictionaryCopyCertificatesOptional(xpc_object_t message
, const char *key
, CFArrayRef
*certificates
, CFErrorRef
*error
) {
133 xpc_object_t xpc_certificates
= xpc_dictionary_get_value(message
, key
);
134 if (!xpc_certificates
) {
135 *certificates
= NULL
;
138 *certificates
= SecCertificateXPCArrayCopyArray(xpc_certificates
, error
);
139 return *certificates
;
142 static bool SecXPCDictionaryCopyPoliciesOptional(xpc_object_t message
, const char *key
, CFArrayRef
*policies
, CFErrorRef
*error
) {
143 xpc_object_t xpc_policies
= xpc_dictionary_get_value(message
, key
);
149 *policies
= SecPolicyXPCArrayCopyArray(xpc_policies
, error
);
150 return *policies
!= NULL
;
153 // Returns error if entitlement isn't present.
155 EntitlementPresentAndTrue(uint64_t op
, SecTaskRef clientTask
, CFStringRef entitlement
, CFErrorRef
*error
)
157 if (!SecTaskGetBooleanValueForEntitlement(clientTask
, entitlement
)) {
158 SecError(errSecMissingEntitlement
, error
, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation
)op
), clientTask
, entitlement
);
164 static SecTrustStoreRef
SecXPCDictionaryGetTrustStore(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
165 SecTrustStoreRef ts
= NULL
;
166 CFStringRef domain
= SecXPCDictionaryCopyString(message
, key
, error
);
168 ts
= SecTrustStoreForDomainName(domain
, error
);
174 static bool SecXPCTrustStoreContains(SecurityClient
* __unused client
, xpc_object_t event
,
175 xpc_object_t reply
, CFErrorRef
*error
) {
177 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
179 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
182 if (SecTrustStoreContainsCertificateWithDigest(ts
, digest
, &contains
, error
)) {
183 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, contains
);
186 CFReleaseNull(digest
);
192 static bool SecXPCTrustStoreSetTrustSettings(SecurityClient
* __unused client
, xpc_object_t event
,
193 xpc_object_t reply
, CFErrorRef
*error
) {
194 bool noError
= false;
195 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
197 SecCertificateRef certificate
= SecXPCDictionaryCopyCertificate(event
, kSecXPCKeyCertificate
, error
);
199 CFTypeRef trustSettingsDictOrArray
= NULL
;
200 if (SecXPCDictionaryCopyPListOptional(event
, kSecXPCKeySettings
, &trustSettingsDictOrArray
, error
)) {
201 bool result
= _SecTrustStoreSetTrustSettings(ts
, certificate
, trustSettingsDictOrArray
, error
);
202 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
204 CFReleaseSafe(trustSettingsDictOrArray
);
206 CFReleaseNull(certificate
);
212 static bool SecXPCTrustStoreRemoveCertificate(SecurityClient
* __unused client
, xpc_object_t event
,
213 xpc_object_t reply
, CFErrorRef
*error
) {
214 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
216 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
218 bool result
= SecTrustStoreRemoveCertificateWithDigest(ts
, digest
, error
);
219 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
220 CFReleaseNull(digest
);
227 static bool SecXPCTrustStoreCopyAll(SecurityClient
* __unused client
, xpc_object_t event
,
228 xpc_object_t reply
, CFErrorRef
*error
) {
229 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
231 CFArrayRef trustStoreContents
= NULL
;
232 if(_SecTrustStoreCopyAll(ts
, &trustStoreContents
, error
) && trustStoreContents
) {
233 SecXPCDictionarySetPList(reply
, kSecXPCKeyResult
, trustStoreContents
, error
);
234 CFReleaseNull(trustStoreContents
);
241 static bool SecXPCTrustStoreCopyUsageConstraints(SecurityClient
* __unused client
, xpc_object_t event
,
242 xpc_object_t reply
, CFErrorRef
*error
) {
244 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
246 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
248 CFArrayRef usageConstraints
= NULL
;
249 if(_SecTrustStoreCopyUsageConstraints(ts
, digest
, &usageConstraints
, error
) && usageConstraints
) {
250 SecXPCDictionarySetPList(reply
, kSecXPCKeyResult
, usageConstraints
, error
);
251 CFReleaseNull(usageConstraints
);
254 CFReleaseNull(digest
);
260 static bool SecXPC_OCSPCacheFlush(SecurityClient
* __unused client
, xpc_object_t __unused event
,
261 xpc_object_t __unused reply
, CFErrorRef
*error
) {
262 if(SecOCSPCacheFlush(error
)) {
268 static bool SecXPC_OTAPKI_GetCurrentTrustStoreVersion(SecurityClient
* __unused client
, xpc_object_t __unused event
,
269 xpc_object_t reply
, CFErrorRef
*error
) {
270 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, SecOTAPKIGetCurrentTrustStoreVersion(error
));
274 static bool SecXPC_OTAPKI_GetCurrentAssetVersion(SecurityClient
* __unused client
, xpc_object_t __unused event
,
275 xpc_object_t reply
, CFErrorRef
*error
) {
276 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, SecOTAPKIGetCurrentAssetVersion(error
));
280 static bool SecXPC_OTAPKI_GetEscrowCertificates(SecurityClient
* __unused client
, xpc_object_t event
,
281 xpc_object_t reply
, CFErrorRef
*error
) {
283 uint32_t escrowRootType
= (uint32_t)xpc_dictionary_get_uint64(event
, "escrowType");
284 CFArrayRef array
= SecOTAPKICopyCurrentEscrowCertificates(escrowRootType
, error
);
286 xpc_object_t xpc_array
= _CFXPCCreateXPCObjectFromCFObject(array
);
287 xpc_dictionary_set_value(reply
, kSecXPCKeyResult
, xpc_array
);
288 xpc_release(xpc_array
);
291 CFReleaseNull(array
);
295 static bool SecXPC_OTAPKI_GetNewAsset(SecurityClient
* __unused client
, xpc_object_t __unused event
,
296 xpc_object_t reply
, CFErrorRef
*error
) {
297 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, SecOTAPKISignalNewAsset(error
));
301 static bool SecXPC_Networking_AnalyticsReport(SecurityClient
* __unused client
, xpc_object_t event
,
302 xpc_object_t reply
, CFErrorRef
*error
) {
303 xpc_object_t attributes
= xpc_dictionary_get_dictionary(event
, kSecTrustEventAttributesKey
);
304 CFStringRef eventName
= SecXPCDictionaryCopyString(event
, kSecTrustEventNameKey
, error
);
306 if (attributes
&& eventName
) {
307 result
= SecNetworkingAnalyticsReport(eventName
, attributes
, error
);
309 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
310 CFReleaseNull(eventName
);
314 static bool SecXPCTrustStoreSetCTExceptions(SecurityClient
*client
, xpc_object_t event
,
315 xpc_object_t reply
, CFErrorRef
*error
) {
316 CFStringRef appID
= NULL
;
317 CFDictionaryRef exceptions
= NULL
;
318 if (!SecXPCDictionaryCopyStringOptional(event
, kSecTrustEventApplicationID
, &appID
, error
) || !appID
) {
319 /* We always want to set the app ID with the exceptions */
320 appID
= SecTaskCopyApplicationIdentifier(client
->task
);
322 (void)SecXPCDictionaryCopyDictionaryOptional(event
, kSecTrustExceptionsKey
, &exceptions
, error
);
323 bool result
= _SecTrustStoreSetCTExceptions(appID
, exceptions
, error
);
324 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
325 CFReleaseNull(exceptions
);
326 CFReleaseNull(appID
);
330 static bool SecXPCTrustStoreCopyCTExceptions(SecurityClient
* __unused client
, xpc_object_t event
,
331 xpc_object_t reply
, CFErrorRef
*error
) {
332 CFStringRef appID
= NULL
;
333 (void)SecXPCDictionaryCopyStringOptional(event
, kSecTrustEventApplicationID
, &appID
, error
);
334 CFDictionaryRef exceptions
= _SecTrustStoreCopyCTExceptions(appID
, error
);
335 SecXPCDictionarySetPListOptional(reply
, kSecTrustExceptionsKey
, exceptions
, error
);
336 CFReleaseNull(exceptions
);
337 CFReleaseNull(appID
);
341 typedef bool(*SecXPCOperationHandler
)(SecurityClient
*client
, xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
);
344 CFStringRef entitlement
;
345 SecXPCOperationHandler handler
;
346 } SecXPCServerOperation
;
348 struct trustd_operations
{
349 SecXPCServerOperation trust_store_contains
;
350 SecXPCServerOperation trust_store_set_trust_settings
;
351 SecXPCServerOperation trust_store_remove_certificate
;
352 SecXPCServerOperation trust_store_copy_all
;
353 SecXPCServerOperation trust_store_copy_usage_constraints
;
354 SecXPCServerOperation ocsp_cache_flush
;
355 SecXPCServerOperation ota_pki_trust_store_version
;
356 SecXPCServerOperation ota_pki_asset_version
;
357 SecXPCServerOperation ota_pki_get_escrow_certs
;
358 SecXPCServerOperation ota_pki_get_new_asset
;
359 SecXPCServerOperation networking_analytics_report
;
360 SecXPCServerOperation trust_store_set_ct_exceptions
;
361 SecXPCServerOperation trust_store_copy_ct_exceptions
;
364 static struct trustd_operations trustd_ops
= {
365 .trust_store_contains
= { NULL
, SecXPCTrustStoreContains
},
366 .trust_store_set_trust_settings
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreSetTrustSettings
},
367 .trust_store_remove_certificate
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreRemoveCertificate
},
368 .trust_store_copy_all
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyAll
},
369 .trust_store_copy_usage_constraints
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyUsageConstraints
},
370 .ocsp_cache_flush
= { NULL
, SecXPC_OCSPCacheFlush
},
371 .ota_pki_trust_store_version
= { NULL
, SecXPC_OTAPKI_GetCurrentTrustStoreVersion
},
372 .ota_pki_asset_version
= { NULL
, SecXPC_OTAPKI_GetCurrentAssetVersion
},
373 .ota_pki_get_escrow_certs
= { NULL
, SecXPC_OTAPKI_GetEscrowCertificates
},
374 .ota_pki_get_new_asset
= { NULL
, SecXPC_OTAPKI_GetNewAsset
},
375 .networking_analytics_report
= { NULL
, SecXPC_Networking_AnalyticsReport
},
376 .trust_store_set_ct_exceptions
= {kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreSetCTExceptions
},
377 .trust_store_copy_ct_exceptions
= {kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyCTExceptions
}
380 static void trustd_xpc_dictionary_handler(const xpc_connection_t connection
, xpc_object_t event
) {
381 xpc_type_t type
= xpc_get_type(event
);
382 __block CFErrorRef error
= NULL
;
383 xpc_object_t xpcError
= NULL
;
384 xpc_object_t replyMessage
= NULL
;
385 CFDataRef clientAuditToken
= NULL
;
386 CFArrayRef domains
= NULL
;
387 SecurityClient client
= {
389 .accessGroups
= NULL
,
391 .uid
= xpc_connection_get_euid(connection
),
392 .allowSystemKeychain
= true,
393 .allowSyncBubbleKeychain
= false,
394 .isNetworkExtension
= false,
395 .canAccessNetworkExtensionAccessGroups
= false,
397 .inMultiUser
= false,
401 secdebug("serverxpc", "entering");
402 if (type
== XPC_TYPE_DICTIONARY
) {
403 replyMessage
= xpc_dictionary_create_reply(event
);
405 uint64_t operation
= xpc_dictionary_get_uint64(event
, kSecXPCKeyOperation
);
407 audit_token_t auditToken
= {};
408 xpc_connection_get_audit_token(connection
, &auditToken
);
410 client
.task
= SecTaskCreateWithAuditToken(kCFAllocatorDefault
, auditToken
);
411 clientAuditToken
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)&auditToken
, sizeof(auditToken
));
412 client
.accessGroups
= SecTaskCopyAccessGroups(client
.task
);
414 secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64
")", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), operation
);
416 if (operation
== sec_trust_evaluate_id
) {
417 CFArrayRef certificates
= NULL
, anchors
= NULL
, policies
= NULL
, responses
= NULL
, scts
= NULL
, trustedLogs
= NULL
, exceptions
= NULL
;
418 bool anchorsOnly
= xpc_dictionary_get_bool(event
, kSecTrustAnchorsOnlyKey
);
419 bool keychainsAllowed
= xpc_dictionary_get_bool(event
, kSecTrustKeychainsAllowedKey
);
421 if (SecXPCDictionaryCopyCertificates(event
, kSecTrustCertificatesKey
, &certificates
, &error
) &&
422 SecXPCDictionaryCopyCertificatesOptional(event
, kSecTrustAnchorsKey
, &anchors
, &error
) &&
423 SecXPCDictionaryCopyPoliciesOptional(event
, kSecTrustPoliciesKey
, &policies
, &error
) &&
424 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustResponsesKey
, &responses
, &error
) &&
425 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustSCTsKey
, &scts
, &error
) &&
426 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustTrustedLogsKey
, &trustedLogs
, &error
) &&
427 SecXPCDictionaryGetDouble(event
, kSecTrustVerifyDateKey
, &verifyTime
, &error
) &&
428 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustExceptionsKey
, &exceptions
, &error
)) {
429 // If we have no error yet, capture connection and reply in block and properly retain them.
430 xpc_retain(connection
);
431 CFRetainSafe(client
.task
);
432 CFRetainSafe(clientAuditToken
);
434 // Clear replyMessage so we don't send a synchronous reply.
435 xpc_object_t asyncReply
= replyMessage
;
438 SecTrustServerEvaluateBlock(clientAuditToken
, certificates
, anchors
, anchorsOnly
, keychainsAllowed
, policies
,
439 responses
, scts
, trustedLogs
, verifyTime
, client
.accessGroups
, exceptions
,
440 ^(SecTrustResultType tr
, CFArrayRef details
, CFDictionaryRef info
, CFArrayRef chain
,
441 CFErrorRef replyError
) {
442 // Send back reply now
444 CFRetain(replyError
);
446 xpc_dictionary_set_int64(asyncReply
, kSecTrustResultKey
, tr
);
447 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustDetailsKey
, details
, &replyError
) &&
448 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustInfoKey
, info
, &replyError
) &&
449 SecXPCDictionarySetChainOptional(asyncReply
, kSecTrustChainKey
, chain
, &replyError
);
452 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyError
);
453 xpc_object_t xpcReplyError
= SecCreateXPCObjectWithCFError(replyError
);
455 xpc_dictionary_set_value(asyncReply
, kSecXPCKeyError
, xpcReplyError
);
456 xpc_release(xpcReplyError
);
458 CFReleaseNull(replyError
);
460 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), asyncReply
);
463 xpc_connection_send_message(connection
, asyncReply
);
464 xpc_release(asyncReply
);
465 xpc_release(connection
);
466 CFReleaseSafe(client
.task
);
467 CFReleaseSafe(clientAuditToken
);
470 CFReleaseSafe(policies
);
471 CFReleaseSafe(anchors
);
472 CFReleaseSafe(certificates
);
473 CFReleaseSafe(responses
);
475 CFReleaseSafe(trustedLogs
);
476 CFReleaseSafe(exceptions
);
478 SecXPCServerOperation
*server_op
= NULL
;
480 case sec_trust_store_contains_id
:
481 server_op
= &trustd_ops
.trust_store_contains
;
483 case sec_trust_store_set_trust_settings_id
:
484 server_op
= &trustd_ops
.trust_store_set_trust_settings
;
486 case sec_trust_store_remove_certificate_id
:
487 server_op
= &trustd_ops
.trust_store_remove_certificate
;
489 case sec_trust_store_copy_all_id
:
490 server_op
= &trustd_ops
.trust_store_copy_all
;
492 case sec_trust_store_copy_usage_constraints_id
:
493 server_op
= &trustd_ops
.trust_store_copy_usage_constraints
;
495 case sec_ocsp_cache_flush_id
:
496 server_op
= &trustd_ops
.ocsp_cache_flush
;
498 case sec_ota_pki_trust_store_version_id
:
499 server_op
= &trustd_ops
.ota_pki_trust_store_version
;
501 case sec_ota_pki_asset_version_id
:
502 server_op
= &trustd_ops
.ota_pki_asset_version
;
504 case kSecXPCOpOTAGetEscrowCertificates
:
505 server_op
= &trustd_ops
.ota_pki_get_escrow_certs
;
507 case kSecXPCOpOTAPKIGetNewAsset
:
508 server_op
= &trustd_ops
.ota_pki_get_new_asset
;
510 case kSecXPCOpNetworkingAnalyticsReport
:
511 server_op
= &trustd_ops
.networking_analytics_report
;
513 case kSecXPCOpSetCTExceptions
:
514 server_op
= &trustd_ops
.trust_store_set_ct_exceptions
;
516 case kSecXPCOpCopyCTExceptions
:
517 server_op
= &trustd_ops
.trust_store_copy_ct_exceptions
;
522 if (server_op
&& server_op
->handler
) {
523 bool entitled
= true;
524 if (server_op
->entitlement
) {
525 entitled
= EntitlementPresentAndTrue(operation
, client
.task
, server_op
->entitlement
, &error
);
528 (void)server_op
->handler(&client
, event
, replyMessage
, &error
);
535 if(SecErrorGetOSStatus(error
) == errSecItemNotFound
)
536 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
537 else if (SecErrorGetOSStatus(error
) == errSecAuthNeeded
)
538 secwarning("Authentication is needed %@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
540 secerror("%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
542 xpcError
= SecCreateXPCObjectWithCFError(error
);
544 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyError
, xpcError
);
546 } else if (replyMessage
) {
547 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyMessage
);
550 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, &error
, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event
);
551 secerror("%@: returning error: %@", client
.task
, error
);
552 xpcError
= SecCreateXPCObjectWithCFError(error
);
553 replyMessage
= xpc_create_reply_with_format(event
, "{%string: %value}", kSecXPCKeyError
, xpcError
);
557 xpc_connection_send_message(connection
, replyMessage
);
558 xpc_release(replyMessage
);
561 xpc_release(xpcError
);
562 CFReleaseSafe(error
);
563 CFReleaseSafe(client
.accessGroups
);
564 CFReleaseSafe(client
.musr
);
565 CFReleaseSafe(client
.task
);
566 CFReleaseSafe(domains
);
567 CFReleaseSafe(clientAuditToken
);
570 static void trustd_xpc_init(const char *service_name
)
572 secdebug("serverxpc", "start");
573 xpc_connection_t listener
= xpc_connection_create_mach_service(service_name
, NULL
, XPC_CONNECTION_MACH_SERVICE_LISTENER
);
575 seccritical("security failed to register xpc listener for %s, exiting", service_name
);
579 xpc_connection_set_event_handler(listener
, ^(xpc_object_t connection
) {
580 if (xpc_get_type(connection
) == XPC_TYPE_CONNECTION
) {
581 xpc_connection_set_event_handler(connection
, ^(xpc_object_t event
) {
582 if (xpc_get_type(event
) == XPC_TYPE_DICTIONARY
) {
583 trustd_xpc_dictionary_handler(connection
, event
);
586 xpc_connection_resume(connection
);
589 xpc_connection_resume(listener
);
592 static void trustd_delete_old_sqlite_keychain_files(CFStringRef baseFilename
) {
593 WithPathInKeychainDirectory(baseFilename
, ^(const char *utf8String
) {
594 (void)remove(utf8String
);
596 CFStringRef shmFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-shm"), baseFilename
);
597 WithPathInKeychainDirectory(shmFile
, ^(const char *utf8String
) {
598 (void)remove(utf8String
);
600 CFReleaseNull(shmFile
);
601 CFStringRef walFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-wal"), baseFilename
);
602 WithPathInKeychainDirectory(walFile
, ^(const char *utf8String
) {
603 (void)remove(utf8String
);
605 CFReleaseNull(walFile
);
606 CFStringRef journalFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-journal"), baseFilename
);
607 WithPathInKeychainDirectory(journalFile
, ^(const char *utf8String
) {
608 (void)remove(utf8String
);
610 CFReleaseNull(journalFile
);
614 static void trustd_delete_old_sqlite_user_cache_files(CFStringRef baseFilename
) {
615 WithPathInUserCacheDirectory(baseFilename
, ^(const char *utf8String
) {
616 (void)remove(utf8String
);
618 CFStringRef shmFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-shm"), baseFilename
);
619 WithPathInUserCacheDirectory(shmFile
, ^(const char *utf8String
) {
620 (void)remove(utf8String
);
622 CFReleaseNull(shmFile
);
623 CFStringRef walFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-wal"), baseFilename
);
624 WithPathInUserCacheDirectory(walFile
, ^(const char *utf8String
) {
625 (void)remove(utf8String
);
627 CFReleaseNull(walFile
);
628 CFStringRef journalFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-journal"), baseFilename
);
629 WithPathInUserCacheDirectory(journalFile
, ^(const char *utf8String
) {
630 (void)remove(utf8String
);
632 CFReleaseNull(journalFile
);
634 #endif // TARGET_OS_OSX
636 static void trustd_delete_old_files(void) {
637 /* We try to clean up after ourselves, but don't care if we succeed. */
638 WithPathInRevocationInfoDirectory(CFSTR("update-current"), ^(const char *utf8String
) {
639 (void)remove(utf8String
);
641 WithPathInRevocationInfoDirectory(CFSTR("update-full"), ^(const char *utf8String
) {
642 (void)remove(utf8String
);
644 WithPathInRevocationInfoDirectory(CFSTR("update-full.gz"), ^(const char *utf8String
) {
645 (void)remove(utf8String
);
648 trustd_delete_old_sqlite_keychain_files(CFSTR("trustd_health_analytics.db"));
649 trustd_delete_old_sqlite_keychain_files(CFSTR("trust_analytics.db"));
650 trustd_delete_old_sqlite_keychain_files(CFSTR("TLS_analytics.db"));
652 trustd_delete_old_sqlite_user_cache_files(CFSTR("trustd_health_analytics.db"));
653 trustd_delete_old_sqlite_user_cache_files(CFSTR("trust_analytics.db"));
654 trustd_delete_old_sqlite_user_cache_files(CFSTR("TLS_analytics.db"));
655 #endif //TARGET_OS_IPHONE
659 static void trustd_delete_old_caches(void) {
660 /* We try to clean up after ourselves, but don't care if we succeed. */
661 trustd_delete_old_sqlite_keychain_files(CFSTR("ocspcache.sqlite3"));
662 trustd_delete_old_sqlite_keychain_files(CFSTR("caissuercache.sqlite3"));
665 static void trustd_sandbox(void) {
666 char buf
[PATH_MAX
] = "";
668 if (!_set_user_dir_suffix("com.apple.trustd") ||
669 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
)) == 0 ||
670 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
671 secerror("failed to initialize temporary directory (%d): %s", errno
, strerror(errno
));
675 char *tempdir
= realpath(buf
, NULL
);
676 if (tempdir
== NULL
) {
677 secerror("failed to resolve temporary directory (%d): %s", errno
, strerror(errno
));
681 if (confstr(_CS_DARWIN_USER_CACHE_DIR
, buf
, sizeof(buf
)) == 0 ||
682 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
683 secerror("failed to initialize cache directory (%d): %s", errno
, strerror(errno
));
687 char *cachedir
= realpath(buf
, NULL
);
688 if (cachedir
== NULL
) {
689 secerror("failed to resolve cache directory (%d): %s", errno
, strerror(errno
));
693 const char *parameters
[] = {
695 "_DARWIN_CACHE_DIR", cachedir
,
699 char *sberror
= NULL
;
700 if (sandbox_init_with_parameters("com.apple.trustd", SANDBOX_NAMED
, parameters
, &sberror
) != 0) {
701 secerror("Failed to enter trustd sandbox: %{public}s", sberror
);
709 static void trustd_sandbox(void) {
710 char buf
[PATH_MAX
] = "";
711 _set_user_dir_suffix("com.apple.trustd");
712 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
));
716 int main(int argc
, char *argv
[])
718 char *wait4debugger
= getenv("WAIT4DEBUGGER");
719 if (wait4debugger
&& !strcasecmp("YES", wait4debugger
)) {
720 seccritical("SIGSTOPing self, awaiting debugger");
721 kill(getpid(), SIGSTOP
);
722 seccritical("Again, for good luck (or bad debuggers)");
723 kill(getpid(), SIGSTOP
);
726 /* <rdar://problem/15792007> Users with network home folders are unable to use/save password for Mail/Cal/Contacts/websites
727 Our process doesn't realize DB connections get invalidated when network home directory users logout
728 and their home gets unmounted. Exit our process and start fresh when user logs back in.
731 int sessionstatechanged_tok
;
732 notify_register_dispatch(kSA_SessionStateChangedNotification
, &sessionstatechanged_tok
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(int token __unused
) {
733 // we could be a process running as root.
734 // However, since root never logs out this isn't an issue.
735 if (SASSessionStateForUser(getuid()) == kSA_state_loggingout_pointofnoreturn
) {
736 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, 3ull*NSEC_PER_SEC
), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
737 xpc_transaction_exit_clean();
744 /* Before we enter the sandbox, we need to delete the old caches kept in ~/Library/Keychains
745 * After we enter the sandbox, we won't be able to access them. */
746 trustd_delete_old_caches();
751 /* Also clean up old files in our sandbox. After sandboxing, so that user dir suffix is set. */
752 trustd_delete_old_files();
754 const char *serviceName
= kTrustdXPCServiceName
;
755 if (argc
> 1 && (!strcmp(argv
[1], "--agent"))) {
756 serviceName
= kTrustdAgentXPCServiceName
;
759 /* set up SQLite before some other component has a chance to create a database connection */
762 gTrustd
= &trustd_spi
;
764 /* Initialize static content */
765 SecPolicyServerInitialize(); // set up callbacks for policy checks
766 SecRevocationDbInitialize(); // set up revocation database if it doesn't already exist, or needs to be replaced
767 SecPinningDbInitialize(); // set up the pinning database
769 SecTrustLegacySourcesListenForKeychainEvents(); // set up the legacy keychain event listeners (for cache invalidation)
772 /* We're ready now. Go. */
773 trustd_xpc_init(serviceName
);