2 * Copyright (c) 2017-2020 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 "trust/trustd/SecOCSPCache.h"
53 #include "trust/trustd/SecTrustStoreServer.h"
54 #include "trust/trustd/SecPinningDb.h"
55 #include "trust/trustd/SecPolicyServer.h"
56 #include "trust/trustd/SecRevocationDb.h"
57 #include "trust/trustd/SecTrustServer.h"
58 #include "keychain/securityd/spi.h"
59 #include "trust/trustd/SecTrustLoggingServer.h"
61 #include "trust/trustd/SecTrustExceptionResetCount.h"
65 #include <Security/SecTaskPriv.h>
66 #include <login/SessionAgentStatusCom.h>
67 #include "trust/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 __unused 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
);
384 static bool SecXPCTrustStoreSetCARevocationAdditions(SecurityClient
*client
, xpc_object_t event
,
385 xpc_object_t reply
, CFErrorRef
*error
) {
386 CFStringRef appID
= NULL
;
387 CFDictionaryRef additions
= NULL
;
388 if (!SecXPCDictionaryCopyStringOptional(event
, kSecTrustEventApplicationID
, &appID
, error
) || !appID
) {
389 /* We always want to set the app ID with the additions */
390 appID
= SecTaskCopyApplicationIdentifier(client
->task
);
392 (void)SecXPCDictionaryCopyDictionaryOptional(event
, kSecTrustRevocationAdditionsKey
, &additions
, error
);
393 bool result
= _SecTrustStoreSetCARevocationAdditions(appID
, additions
, error
);
394 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
395 CFReleaseNull(additions
);
396 CFReleaseNull(appID
);
400 static bool SecXPCTrustStoreCopyCARevocationAdditions(SecurityClient
* __unused client
, xpc_object_t event
,
401 xpc_object_t reply
, CFErrorRef
*error
) {
402 CFStringRef appID
= NULL
;
403 (void)SecXPCDictionaryCopyStringOptional(event
, kSecTrustEventApplicationID
, &appID
, error
);
404 CFDictionaryRef additions
= _SecTrustStoreCopyCARevocationAdditions(appID
, error
);
405 SecXPCDictionarySetPListOptional(reply
, kSecTrustRevocationAdditionsKey
, additions
, error
);
406 CFReleaseNull(additions
);
407 CFReleaseNull(appID
);
412 static bool SecXPCTrustGetExceptionResetCount(SecurityClient
* __unused client
, xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
413 uint64_t exceptionResetCount
= SecTrustServerGetExceptionResetCount(error
);
414 if (error
&& *error
) {
418 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, exceptionResetCount
);
422 static bool SecXPCTrustIncrementExceptionResetCount(SecurityClient
* __unused client
, xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
423 OSStatus status
= errSecInternal
;
424 bool result
= SecTrustServerIncrementExceptionResetCount(error
);
425 if (result
&& (!error
|| (error
&& !*error
))) {
426 status
= errSecSuccess
;
429 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, status
);
434 static bool SecXPC_Valid_Update(SecurityClient
* __unused client
, xpc_object_t __unused event
,
435 xpc_object_t reply
, CFErrorRef
*error
) {
436 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, SecRevocationDbUpdate(error
));
440 typedef bool(*SecXPCOperationHandler
)(SecurityClient
*client
, xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
);
443 CFStringRef entitlement
;
444 SecXPCOperationHandler handler
;
445 } SecXPCServerOperation
;
447 struct trustd_operations
{
448 SecXPCServerOperation trust_store_contains
;
449 SecXPCServerOperation trust_store_set_trust_settings
;
450 SecXPCServerOperation trust_store_remove_certificate
;
451 SecXPCServerOperation trust_store_copy_all
;
452 SecXPCServerOperation trust_store_copy_usage_constraints
;
453 SecXPCServerOperation ocsp_cache_flush
;
454 SecXPCServerOperation ota_pki_trust_store_version
;
455 SecXPCServerOperation ota_pki_asset_version
;
456 SecXPCServerOperation ota_pki_get_escrow_certs
;
457 SecXPCServerOperation ota_pki_get_new_asset
;
458 SecXPCServerOperation ota_pki_copy_trusted_ct_logs
;
459 SecXPCServerOperation ota_pki_copy_ct_log_for_keyid
;
460 SecXPCServerOperation networking_analytics_report
;
461 SecXPCServerOperation trust_store_set_ct_exceptions
;
462 SecXPCServerOperation trust_store_copy_ct_exceptions
;
463 SecXPCServerOperation ota_secexperiment_get_asset
;
464 SecXPCServerOperation ota_secexperiment_get_new_asset
;
466 SecXPCServerOperation trust_get_exception_reset_count
;
467 SecXPCServerOperation trust_increment_exception_reset_count
;
469 SecXPCServerOperation trust_store_set_ca_revocation_additions
;
470 SecXPCServerOperation trust_store_copy_ca_revocation_additions
;
471 SecXPCServerOperation valid_update
;
474 static struct trustd_operations trustd_ops
= {
475 .trust_store_contains
= { NULL
, SecXPCTrustStoreContains
},
476 .trust_store_set_trust_settings
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreSetTrustSettings
},
477 .trust_store_remove_certificate
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreRemoveCertificate
},
478 .trust_store_copy_all
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyAll
},
479 .trust_store_copy_usage_constraints
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyUsageConstraints
},
480 .ocsp_cache_flush
= { NULL
, SecXPC_OCSPCacheFlush
},
481 .ota_pki_trust_store_version
= { NULL
, SecXPC_OTAPKI_GetCurrentTrustStoreVersion
},
482 .ota_pki_asset_version
= { NULL
, SecXPC_OTAPKI_GetCurrentAssetVersion
},
483 .ota_pki_get_escrow_certs
= { NULL
, SecXPC_OTAPKI_GetEscrowCertificates
},
484 .ota_pki_get_new_asset
= { NULL
, SecXPC_OTAPKI_GetNewAsset
},
485 .ota_secexperiment_get_new_asset
= { NULL
, SecXPC_OTASecExperiment_GetNewAsset
},
486 .ota_secexperiment_get_asset
= { NULL
, SecXPC_OTASecExperiment_GetAsset
},
487 .ota_pki_copy_trusted_ct_logs
= { NULL
, SecXPC_OTAPKI_CopyTrustedCTLogs
},
488 .ota_pki_copy_ct_log_for_keyid
= { NULL
, SecXPC_OTAPKI_CopyCTLogForKeyID
},
489 .networking_analytics_report
= { NULL
, SecXPC_Networking_AnalyticsReport
},
490 .trust_store_set_ct_exceptions
= {kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreSetCTExceptions
},
491 .trust_store_copy_ct_exceptions
= {kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyCTExceptions
},
493 .trust_get_exception_reset_count
= { NULL
, SecXPCTrustGetExceptionResetCount
},
494 .trust_increment_exception_reset_count
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustIncrementExceptionResetCount
},
496 .trust_store_set_ca_revocation_additions
= {kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreSetCARevocationAdditions
},
497 .trust_store_copy_ca_revocation_additions
= {kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyCARevocationAdditions
},
498 .valid_update
= { NULL
, SecXPC_Valid_Update
},
501 static void trustd_xpc_dictionary_handler(const xpc_connection_t connection
, xpc_object_t event
) {
502 xpc_type_t type
= xpc_get_type(event
);
503 __block CFErrorRef error
= NULL
;
504 xpc_object_t xpcError
= NULL
;
505 xpc_object_t replyMessage
= NULL
;
506 CFDataRef clientAuditToken
= NULL
;
507 CFArrayRef domains
= NULL
;
508 SecurityClient client
= {
510 .accessGroups
= NULL
,
512 .uid
= xpc_connection_get_euid(connection
),
513 .allowSystemKeychain
= true,
514 .allowSyncBubbleKeychain
= false,
515 .isNetworkExtension
= false,
516 .canAccessNetworkExtensionAccessGroups
= false,
518 .inMultiUser
= false,
522 secdebug("serverxpc", "entering");
523 if (type
== XPC_TYPE_DICTIONARY
) {
524 replyMessage
= xpc_dictionary_create_reply(event
);
526 uint64_t operation
= xpc_dictionary_get_uint64(event
, kSecXPCKeyOperation
);
528 audit_token_t auditToken
= {};
529 xpc_connection_get_audit_token(connection
, &auditToken
);
531 client
.task
= SecTaskCreateWithAuditToken(kCFAllocatorDefault
, auditToken
);
532 clientAuditToken
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)&auditToken
, sizeof(auditToken
));
533 client
.accessGroups
= SecTaskCopyAccessGroups(client
.task
);
535 secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64
")", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), operation
);
537 if (operation
== sec_trust_evaluate_id
) {
538 CFArrayRef certificates
= NULL
, anchors
= NULL
, policies
= NULL
, responses
= NULL
, scts
= NULL
, trustedLogs
= NULL
, exceptions
= NULL
;
539 bool anchorsOnly
= xpc_dictionary_get_bool(event
, kSecTrustAnchorsOnlyKey
);
540 bool keychainsAllowed
= xpc_dictionary_get_bool(event
, kSecTrustKeychainsAllowedKey
);
542 if (SecXPCDictionaryCopyCertificates(event
, kSecTrustCertificatesKey
, &certificates
, &error
) &&
543 SecXPCDictionaryCopyCertificatesOptional(event
, kSecTrustAnchorsKey
, &anchors
, &error
) &&
544 SecXPCDictionaryCopyPoliciesOptional(event
, kSecTrustPoliciesKey
, &policies
, &error
) &&
545 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustResponsesKey
, &responses
, &error
) &&
546 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustSCTsKey
, &scts
, &error
) &&
547 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustTrustedLogsKey
, &trustedLogs
, &error
) &&
548 SecXPCDictionaryGetDouble(event
, kSecTrustVerifyDateKey
, &verifyTime
, &error
) &&
549 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustExceptionsKey
, &exceptions
, &error
)) {
550 // If we have no error yet, capture connection and reply in block and properly retain them.
551 xpc_retain(connection
);
552 CFRetainSafe(client
.task
);
553 CFRetainSafe(clientAuditToken
);
555 // Clear replyMessage so we don't send a synchronous reply.
556 xpc_object_t asyncReply
= replyMessage
;
559 SecTrustServerEvaluateBlock(SecTrustServerGetWorkloop(), clientAuditToken
, certificates
, anchors
, anchorsOnly
, keychainsAllowed
, policies
,
560 responses
, scts
, trustedLogs
, verifyTime
, client
.accessGroups
, exceptions
,
561 ^(SecTrustResultType tr
, CFArrayRef details
, CFDictionaryRef info
, CFArrayRef chain
,
562 CFErrorRef replyError
) {
563 // Send back reply now
565 CFRetain(replyError
);
567 xpc_dictionary_set_int64(asyncReply
, kSecTrustResultKey
, tr
);
568 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustDetailsKey
, details
, &replyError
) &&
569 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustInfoKey
, info
, &replyError
) &&
570 SecXPCDictionarySetChainOptional(asyncReply
, kSecTrustChainKey
, chain
, &replyError
);
573 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyError
);
574 xpc_object_t xpcReplyError
= SecCreateXPCObjectWithCFError(replyError
);
576 xpc_dictionary_set_value(asyncReply
, kSecXPCKeyError
, xpcReplyError
);
577 xpc_release(xpcReplyError
);
579 CFReleaseNull(replyError
);
581 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), asyncReply
);
584 xpc_connection_send_message(connection
, asyncReply
);
585 xpc_release(asyncReply
);
586 xpc_release(connection
);
587 CFReleaseSafe(client
.task
);
588 CFReleaseSafe(clientAuditToken
);
591 CFReleaseSafe(policies
);
592 CFReleaseSafe(anchors
);
593 CFReleaseSafe(certificates
);
594 CFReleaseSafe(responses
);
596 CFReleaseSafe(trustedLogs
);
597 CFReleaseSafe(exceptions
);
599 SecXPCServerOperation
*server_op
= NULL
;
601 case sec_trust_store_contains_id
:
602 server_op
= &trustd_ops
.trust_store_contains
;
604 case sec_trust_store_set_trust_settings_id
:
605 server_op
= &trustd_ops
.trust_store_set_trust_settings
;
607 case sec_trust_store_remove_certificate_id
:
608 server_op
= &trustd_ops
.trust_store_remove_certificate
;
610 case sec_trust_store_copy_all_id
:
611 server_op
= &trustd_ops
.trust_store_copy_all
;
613 case sec_trust_store_copy_usage_constraints_id
:
614 server_op
= &trustd_ops
.trust_store_copy_usage_constraints
;
616 case sec_ocsp_cache_flush_id
:
617 server_op
= &trustd_ops
.ocsp_cache_flush
;
619 case sec_ota_pki_trust_store_version_id
:
620 server_op
= &trustd_ops
.ota_pki_trust_store_version
;
622 case sec_ota_pki_asset_version_id
:
623 server_op
= &trustd_ops
.ota_pki_asset_version
;
625 case kSecXPCOpOTAGetEscrowCertificates
:
626 server_op
= &trustd_ops
.ota_pki_get_escrow_certs
;
628 case kSecXPCOpOTAPKIGetNewAsset
:
629 server_op
= &trustd_ops
.ota_pki_get_new_asset
;
631 case kSecXPCOpOTASecExperimentGetNewAsset
:
632 server_op
= &trustd_ops
.ota_secexperiment_get_new_asset
;
634 case kSecXPCOpOTASecExperimentGetAsset
:
635 server_op
= &trustd_ops
.ota_secexperiment_get_asset
;
637 case kSecXPCOpOTAPKICopyTrustedCTLogs
:
638 server_op
= &trustd_ops
.ota_pki_copy_trusted_ct_logs
;
640 case kSecXPCOpOTAPKICopyCTLogForKeyID
:
641 server_op
= &trustd_ops
.ota_pki_copy_ct_log_for_keyid
;
643 case kSecXPCOpNetworkingAnalyticsReport
:
644 server_op
= &trustd_ops
.networking_analytics_report
;
646 case kSecXPCOpSetCTExceptions
:
647 server_op
= &trustd_ops
.trust_store_set_ct_exceptions
;
649 case kSecXPCOpCopyCTExceptions
:
650 server_op
= &trustd_ops
.trust_store_copy_ct_exceptions
;
653 case sec_trust_get_exception_reset_count_id
:
654 server_op
= &trustd_ops
.trust_get_exception_reset_count
;
656 case sec_trust_increment_exception_reset_count_id
:
657 server_op
= &trustd_ops
.trust_increment_exception_reset_count
;
660 case kSecXPCOpSetCARevocationAdditions
:
661 server_op
= &trustd_ops
.trust_store_set_ca_revocation_additions
;
663 case kSecXPCOpCopyCARevocationAdditions
:
664 server_op
= &trustd_ops
.trust_store_copy_ca_revocation_additions
;
666 case kSecXPCOpValidUpdate
:
667 server_op
= &trustd_ops
.valid_update
;
672 if (server_op
&& server_op
->handler
) {
673 bool entitled
= true;
674 if (server_op
->entitlement
) {
675 entitled
= EntitlementPresentAndTrue(operation
, client
.task
, server_op
->entitlement
, &error
);
678 (void)server_op
->handler(&client
, event
, replyMessage
, &error
);
685 if(SecErrorGetOSStatus(error
) == errSecItemNotFound
)
686 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
687 else if (SecErrorGetOSStatus(error
) == errSecAuthNeeded
)
688 secwarning("Authentication is needed %@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
690 secerror("%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
692 xpcError
= SecCreateXPCObjectWithCFError(error
);
694 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyError
, xpcError
);
696 } else if (replyMessage
) {
697 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyMessage
);
700 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, &error
, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event
);
701 secerror("%@: returning error: %@", client
.task
, error
);
702 xpcError
= SecCreateXPCObjectWithCFError(error
);
703 replyMessage
= xpc_create_reply_with_format(event
, "{%string: %value}", kSecXPCKeyError
, xpcError
);
707 xpc_connection_send_message(connection
, replyMessage
);
708 xpc_release(replyMessage
);
711 xpc_release(xpcError
);
712 CFReleaseSafe(error
);
713 CFReleaseSafe(client
.accessGroups
);
714 CFReleaseSafe(client
.musr
);
715 CFReleaseSafe(client
.task
);
716 CFReleaseSafe(domains
);
717 CFReleaseSafe(clientAuditToken
);
720 static void trustd_xpc_init(const char *service_name
)
722 secdebug("serverxpc", "start");
723 xpc_connection_t listener
= xpc_connection_create_mach_service(service_name
, NULL
, XPC_CONNECTION_MACH_SERVICE_LISTENER
);
725 seccritical("security failed to register xpc listener for %s, exiting", service_name
);
729 xpc_connection_set_event_handler(listener
, ^(xpc_object_t connection
) {
730 if (xpc_get_type(connection
) == XPC_TYPE_CONNECTION
) {
731 xpc_connection_set_target_queue(connection
, SecTrustServerGetWorkloop());
732 xpc_connection_set_event_handler(connection
, ^(xpc_object_t event
) {
733 if (xpc_get_type(event
) == XPC_TYPE_DICTIONARY
) {
734 trustd_xpc_dictionary_handler(connection
, event
);
737 xpc_connection_activate(connection
);
740 xpc_connection_activate(listener
);
743 static void trustd_sandbox(void) {
745 char buf
[PATH_MAX
] = "";
747 if (!_set_user_dir_suffix("com.apple.trustd") ||
748 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
)) == 0 ||
749 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
750 secerror("failed to initialize temporary directory (%d): %s", errno
, strerror(errno
));
754 char *tempdir
= realpath(buf
, NULL
);
755 if (tempdir
== NULL
) {
756 secerror("failed to resolve temporary directory (%d): %s", errno
, strerror(errno
));
760 if (confstr(_CS_DARWIN_USER_CACHE_DIR
, buf
, sizeof(buf
)) == 0 ||
761 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
762 secerror("failed to initialize cache directory (%d): %s", errno
, strerror(errno
));
766 char *cachedir
= realpath(buf
, NULL
);
767 if (cachedir
== NULL
) {
768 secerror("failed to resolve cache directory (%d): %s", errno
, strerror(errno
));
772 const char *parameters
[] = {
774 "_DARWIN_CACHE_DIR", cachedir
,
778 char *sberror
= NULL
;
779 if (sandbox_init_with_parameters("com.apple.trustd", SANDBOX_NAMED
, parameters
, &sberror
) != 0) {
780 secerror("Failed to enter trustd sandbox: %{public}s", sberror
);
786 #else // !TARGET_OS_OSX
787 char buf
[PATH_MAX
] = "";
788 _set_user_dir_suffix("com.apple.trustd");
789 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
));
790 #endif // !TARGET_OS_OSX
793 int main(int argc
, char *argv
[])
795 DisableLocalization();
797 char *wait4debugger
= getenv("WAIT4DEBUGGER");
798 if (wait4debugger
&& !strcasecmp("YES", wait4debugger
)) {
799 seccritical("SIGSTOPing self, awaiting debugger");
800 kill(getpid(), SIGSTOP
);
801 seccritical("Again, for good luck (or bad debuggers)");
802 kill(getpid(), SIGSTOP
);
807 const char *serviceName
= kTrustdXPCServiceName
;
808 if (argc
> 1 && (!strcmp(argv
[1], "--agent"))) {
809 serviceName
= kTrustdAgentXPCServiceName
;
812 /* set up SQLite before some other component has a chance to create a database connection */
815 gTrustd
= &trustd_spi
;
817 /* Initialize static content */
818 SecPolicyServerInitialize(); // set up callbacks for policy checks
819 SecRevocationDbInitialize(); // set up revocation database if it doesn't already exist, or needs to be replaced
820 SecPinningDbInitialize(); // set up the pinning database
822 SecTrustLegacySourcesListenForKeychainEvents(); // set up the legacy keychain event listeners (for cache invalidation)
825 /* We're ready now. Go. */
826 trustd_xpc_init(serviceName
);