]> git.saurik.com Git - apple/security.git/blob - OSX/trustd/trustd.c
Security-58286.51.6.tar.gz
[apple/security.git] / OSX / trustd / trustd.c
1 /*
2 * Copyright (c) 2017-2018 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
24 #include <AssertMacros.h>
25 #include <sandbox.h>
26 #include <dirhelper_priv.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <pwd.h>
30 #include <notify.h>
31 #include <xpc/private.h>
32 #include <xpc/xpc.h>
33 #include <CoreFoundation/CFStream.h>
34 #include <os/assumes.h>
35
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>
44
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>
60
61 #if TARGET_OS_OSX
62 #include <Security/SecTaskPriv.h>
63 #include <login/SessionAgentStatusCom.h>
64 #include <trustd/macOS/SecTrustOSXEntryPoints.h>
65 #endif
66
67 #include "OTATrustUtilities.h"
68
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 .ota_CopyEscrowCertificates = SecOTAPKICopyCurrentEscrowCertificates,
78 .sec_ota_pki_get_new_asset = SecOTAPKISignalNewAsset,
79 .sec_trust_store_copy_all = _SecTrustStoreCopyAll,
80 .sec_trust_store_copy_usage_constraints = _SecTrustStoreCopyUsageConstraints,
81 .sec_ocsp_cache_flush = SecOCSPCacheFlush,
82 .sec_tls_analytics_report = SecTLSAnalyticsReport,
83 };
84
85 static bool SecXPCDictionarySetChainOptional(xpc_object_t message, const char *key, CFArrayRef path, CFErrorRef *error) {
86 if (!path)
87 return true;
88 __block xpc_object_t xpc_chain = NULL;
89 require_action_quiet(xpc_chain = xpc_array_create(NULL, 0), exit, SecError(errSecParam, error, CFSTR("xpc_array_create failed")));
90 CFArrayForEach(path, ^(const void *value) {
91 SecCertificateRef cert = (SecCertificateRef)value;
92 if (xpc_chain && !SecCertificateAppendToXPCArray(cert, xpc_chain, error)) {
93 xpc_release(xpc_chain);
94 xpc_chain = NULL;
95 }
96 });
97
98 exit:
99 if (!xpc_chain)
100 return false;
101
102 xpc_dictionary_set_value(message, key, xpc_chain);
103 xpc_release(xpc_chain);
104 return true;
105 }
106
107 static SecCertificateRef SecXPCDictionaryCopyCertificate(xpc_object_t message, const char *key, CFErrorRef *error) {
108 size_t length = 0;
109 const void *bytes = xpc_dictionary_get_data(message, key, &length);
110 if (bytes) {
111 SecCertificateRef certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length);
112 if (certificate)
113 return certificate;
114 SecError(errSecDecode, error, CFSTR("object for key %s failed to create certificate from data"), key);
115 } else {
116 SecError(errSecParam, error, CFSTR("object for key %s missing"), key);
117 }
118 return NULL;
119 }
120
121 static bool SecXPCDictionaryCopyCertificates(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) {
122 xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key);
123 if (!xpc_certificates)
124 return SecError(errSecAllocate, error, CFSTR("no certs for key %s"), key);
125 *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error);
126 return *certificates;
127 }
128
129 static bool SecXPCDictionaryCopyCertificatesOptional(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) {
130 xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key);
131 if (!xpc_certificates) {
132 *certificates = NULL;
133 return true;
134 }
135 *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error);
136 return *certificates;
137 }
138
139 static bool SecXPCDictionaryCopyPoliciesOptional(xpc_object_t message, const char *key, CFArrayRef *policies, CFErrorRef *error) {
140 xpc_object_t xpc_policies = xpc_dictionary_get_value(message, key);
141 if (!xpc_policies) {
142 if (policies)
143 *policies = NULL;
144 return true;
145 }
146 *policies = SecPolicyXPCArrayCopyArray(xpc_policies, error);
147 return *policies != NULL;
148 }
149
150 // Returns error if entitlement isn't present.
151 static bool
152 EntitlementPresentAndTrue(uint64_t op, SecTaskRef clientTask, CFStringRef entitlement, CFErrorRef *error)
153 {
154 if (!SecTaskGetBooleanValueForEntitlement(clientTask, entitlement)) {
155 SecError(errSecMissingEntitlement, error, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation)op), clientTask, entitlement);
156 return false;
157 }
158 return true;
159 }
160
161 static SecTrustStoreRef SecXPCDictionaryGetTrustStore(xpc_object_t message, const char *key, CFErrorRef *error) {
162 SecTrustStoreRef ts = NULL;
163 CFStringRef domain = SecXPCDictionaryCopyString(message, key, error);
164 if (domain) {
165 ts = SecTrustStoreForDomainName(domain, error);
166 CFRelease(domain);
167 }
168 return ts;
169 }
170
171 static bool SecXPCTrustStoreContains(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
172 bool result = false;
173 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
174 if (ts) {
175 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
176 if (digest) {
177 bool contains;
178 if (SecTrustStoreContainsCertificateWithDigest(ts, digest, &contains, error)) {
179 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, contains);
180 result = true;
181 }
182 CFReleaseNull(digest);
183 }
184 }
185 return result;
186 }
187
188 static bool SecXPCTrustStoreSetTrustSettings(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
189 bool noError = false;
190 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
191 if (ts) {
192 SecCertificateRef certificate = SecXPCDictionaryCopyCertificate(event, kSecXPCKeyCertificate, error);
193 if (certificate) {
194 CFTypeRef trustSettingsDictOrArray = NULL;
195 if (SecXPCDictionaryCopyPListOptional(event, kSecXPCKeySettings, &trustSettingsDictOrArray, error)) {
196 bool result = _SecTrustStoreSetTrustSettings(ts, certificate, trustSettingsDictOrArray, error);
197 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result);
198 noError = true;
199 CFReleaseSafe(trustSettingsDictOrArray);
200 }
201 CFReleaseNull(certificate);
202 }
203 }
204 return noError;
205 }
206
207 static bool SecXPCTrustStoreRemoveCertificate(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
208 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
209 if (ts) {
210 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
211 if (digest) {
212 bool result = SecTrustStoreRemoveCertificateWithDigest(ts, digest, error);
213 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result);
214 CFReleaseNull(digest);
215 return true;
216 }
217 }
218 return false;
219 }
220
221 static bool SecXPCTrustStoreCopyAll(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
222 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
223 if (ts) {
224 CFArrayRef trustStoreContents = NULL;
225 if(_SecTrustStoreCopyAll(ts, &trustStoreContents, error) && trustStoreContents) {
226 SecXPCDictionarySetPList(reply, kSecXPCKeyResult, trustStoreContents, error);
227 CFReleaseNull(trustStoreContents);
228 return true;
229 }
230 }
231 return false;
232 }
233
234 static bool SecXPCTrustStoreCopyUsageConstraints(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
235 bool result = false;
236 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
237 if (ts) {
238 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
239 if (digest) {
240 CFArrayRef usageConstraints = NULL;
241 if(_SecTrustStoreCopyUsageConstraints(ts, digest, &usageConstraints, error) && usageConstraints) {
242 SecXPCDictionarySetPList(reply, kSecXPCKeyResult, usageConstraints, error);
243 CFReleaseNull(usageConstraints);
244 result = true;
245 }
246 CFReleaseNull(digest);
247 }
248 }
249 return result;
250 }
251
252 static bool SecXPC_OCSPCacheFlush(xpc_object_t __unused event, xpc_object_t __unused reply, CFErrorRef *error) {
253 if(SecOCSPCacheFlush(error)) {
254 return true;
255 }
256 return false;
257 }
258
259 static bool SecXPC_OTAPKI_GetAssetVersion(xpc_object_t __unused event, xpc_object_t reply, CFErrorRef *error) {
260 xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTAPKIGetCurrentTrustStoreVersion(error));
261 return true;
262 }
263
264 static bool SecXPC_OTAPKI_GetEscrowCertificates(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
265 bool result = false;
266 uint32_t escrowRootType = (uint32_t)xpc_dictionary_get_uint64(event, "escrowType");
267 CFArrayRef array = SecOTAPKICopyCurrentEscrowCertificates(escrowRootType, error);
268 if (array) {
269 xpc_object_t xpc_array = _CFXPCCreateXPCObjectFromCFObject(array);
270 xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_array);
271 xpc_release(xpc_array);
272 result = true;
273 }
274 CFReleaseNull(array);
275 return result;
276 }
277
278 static bool SecXPC_OTAPKI_GetNewAsset(xpc_object_t __unused event, xpc_object_t reply, CFErrorRef *error) {
279 xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTAPKISignalNewAsset(error));
280 return true;
281 }
282
283 static bool SecXPC_TLS_AnalyticsReport(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
284 xpc_object_t attributes = xpc_dictionary_get_dictionary(event, kSecTrustEventAttributesKey);
285 CFStringRef eventName = SecXPCDictionaryCopyString(event, kSecTrustEventNameKey, error);
286 bool result = false;
287 if (attributes && eventName) {
288 result = SecTLSAnalyticsReport(eventName, attributes, error);
289 }
290 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result);
291 CFReleaseNull(eventName);
292 return result;
293 }
294
295 typedef bool(*SecXPCOperationHandler)(xpc_object_t event, xpc_object_t reply, CFErrorRef *error);
296
297 typedef struct {
298 CFStringRef entitlement;
299 SecXPCOperationHandler handler;
300 } SecXPCServerOperation;
301
302 struct trustd_operations {
303 SecXPCServerOperation trust_store_contains;
304 SecXPCServerOperation trust_store_set_trust_settings;
305 SecXPCServerOperation trust_store_remove_certificate;
306 SecXPCServerOperation trust_store_copy_all;
307 SecXPCServerOperation trust_store_copy_usage_constraints;
308 SecXPCServerOperation ocsp_cache_flush;
309 SecXPCServerOperation ota_pki_trust_store_version;
310 SecXPCServerOperation ota_pki_get_escrow_certs;
311 SecXPCServerOperation ota_pki_get_new_asset;
312 SecXPCServerOperation tls_analytics_report;
313 };
314
315 static struct trustd_operations trustd_ops = {
316 .trust_store_contains = { NULL, SecXPCTrustStoreContains },
317 .trust_store_set_trust_settings = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreSetTrustSettings },
318 .trust_store_remove_certificate = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreRemoveCertificate },
319 .trust_store_copy_all = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyAll },
320 .trust_store_copy_usage_constraints = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyUsageConstraints },
321 .ocsp_cache_flush = { NULL, SecXPC_OCSPCacheFlush },
322 .ota_pki_trust_store_version = { NULL, SecXPC_OTAPKI_GetAssetVersion },
323 .ota_pki_get_escrow_certs = { NULL, SecXPC_OTAPKI_GetEscrowCertificates },
324 .ota_pki_get_new_asset = { NULL, SecXPC_OTAPKI_GetNewAsset },
325 .tls_analytics_report = { NULL, SecXPC_TLS_AnalyticsReport },
326 };
327
328 static void trustd_xpc_dictionary_handler(const xpc_connection_t connection, xpc_object_t event) {
329 xpc_type_t type = xpc_get_type(event);
330 __block CFErrorRef error = NULL;
331 xpc_object_t xpcError = NULL;
332 xpc_object_t replyMessage = NULL;
333 CFDataRef clientAuditToken = NULL;
334 CFArrayRef domains = NULL;
335 SecurityClient client = {
336 .task = NULL,
337 .accessGroups = NULL,
338 .musr = NULL,
339 .uid = xpc_connection_get_euid(connection),
340 .allowSystemKeychain = true,
341 .allowSyncBubbleKeychain = false,
342 .isNetworkExtension = false,
343 .canAccessNetworkExtensionAccessGroups = false,
344 #if TARGET_OS_IPHONE
345 .inMultiUser = false,
346 #endif
347 };
348
349 secdebug("serverxpc", "entering");
350 if (type == XPC_TYPE_DICTIONARY) {
351 // TODO: Find out what we're dispatching.
352 replyMessage = xpc_dictionary_create_reply(event);
353
354
355 uint64_t operation = xpc_dictionary_get_uint64(event, kSecXPCKeyOperation);
356
357 audit_token_t auditToken = {};
358 xpc_connection_get_audit_token(connection, &auditToken);
359
360 client.task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken);
361 clientAuditToken = CFDataCreate(kCFAllocatorDefault, (const UInt8*)&auditToken, sizeof(auditToken));
362 client.accessGroups = SecTaskCopyAccessGroups(client.task);
363
364 secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64 ")", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), operation);
365
366 if (operation == sec_trust_evaluate_id) {
367 CFArrayRef certificates = NULL, anchors = NULL, policies = NULL, responses = NULL, scts = NULL, trustedLogs = NULL, exceptions = NULL;
368 bool anchorsOnly = xpc_dictionary_get_bool(event, kSecTrustAnchorsOnlyKey);
369 bool keychainsAllowed = xpc_dictionary_get_bool(event, kSecTrustKeychainsAllowedKey);
370 double verifyTime;
371 if (SecXPCDictionaryCopyCertificates(event, kSecTrustCertificatesKey, &certificates, &error) &&
372 SecXPCDictionaryCopyCertificatesOptional(event, kSecTrustAnchorsKey, &anchors, &error) &&
373 SecXPCDictionaryCopyPoliciesOptional(event, kSecTrustPoliciesKey, &policies, &error) &&
374 SecXPCDictionaryCopyCFDataArrayOptional(event, kSecTrustResponsesKey, &responses, &error) &&
375 SecXPCDictionaryCopyCFDataArrayOptional(event, kSecTrustSCTsKey, &scts, &error) &&
376 SecXPCDictionaryCopyArrayOptional(event, kSecTrustTrustedLogsKey, &trustedLogs, &error) &&
377 SecXPCDictionaryGetDouble(event, kSecTrustVerifyDateKey, &verifyTime, &error) &&
378 SecXPCDictionaryCopyArrayOptional(event, kSecTrustExceptionsKey, &exceptions, &error)) {
379 // If we have no error yet, capture connection and reply in block and properly retain them.
380 xpc_retain(connection);
381 CFRetainSafe(client.task);
382 CFRetainSafe(clientAuditToken);
383
384 // Clear replyMessage so we don't send a synchronous reply.
385 xpc_object_t asyncReply = replyMessage;
386 replyMessage = NULL;
387
388 SecTrustServerEvaluateBlock(clientAuditToken, certificates, anchors, anchorsOnly, keychainsAllowed, policies,
389 responses, scts, trustedLogs, verifyTime, client.accessGroups, exceptions,
390 ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain,
391 CFErrorRef replyError) {
392 // Send back reply now
393 if (replyError) {
394 CFRetain(replyError);
395 } else {
396 xpc_dictionary_set_int64(asyncReply, kSecTrustResultKey, tr);
397 SecXPCDictionarySetPListOptional(asyncReply, kSecTrustDetailsKey, details, &replyError) &&
398 SecXPCDictionarySetPListOptional(asyncReply, kSecTrustInfoKey, info, &replyError) &&
399 SecXPCDictionarySetChainOptional(asyncReply, kSecTrustChainKey, chain, &replyError);
400 }
401 if (replyError) {
402 secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyError);
403 xpc_object_t xpcReplyError = SecCreateXPCObjectWithCFError(replyError);
404 if (xpcReplyError) {
405 xpc_dictionary_set_value(asyncReply, kSecXPCKeyError, xpcReplyError);
406 xpc_release(xpcReplyError);
407 }
408 CFReleaseNull(replyError);
409 } else {
410 secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), asyncReply);
411 }
412 #if TARGET_OS_IPHONE
413 // Ensure that we remain dirty for two seconds after ending the client's transaction to avoid jetsam loops.
414 // Refer to rdar://problem/38044831 for more details.
415 static dispatch_queue_t dirty_timer_queue = NULL;
416 static dispatch_source_t dirty_timer = NULL;
417 static bool has_transcation = false;
418 static dispatch_once_t onceToken;
419 dispatch_once(&onceToken, ^{
420 dirty_timer_queue = dispatch_queue_create("dirty timer queue", DISPATCH_QUEUE_SERIAL);
421 dirty_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dirty_timer_queue);
422 dispatch_source_set_event_handler(dirty_timer, ^{
423 /* timer fired, end the transaction */
424 os_assumes(has_transcation);
425 xpc_transaction_end();
426 has_transcation = false;
427 });
428 });
429
430 dispatch_sync(dirty_timer_queue, ^{
431 /* reset the timer for 2 seconds from now */
432 dispatch_source_set_timer(dirty_timer, dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC),
433 DISPATCH_TIME_FOREVER, 100 * NSEC_PER_MSEC);
434 if (!has_transcation) {
435 /* timer is not running/not holding a transaction, start transaction */
436 xpc_transaction_begin();
437 has_transcation = true;
438 }
439 static dispatch_once_t onceToken2;
440 dispatch_once(&onceToken2, ^{
441 dispatch_resume(dirty_timer);
442 });
443 });
444 #endif
445 xpc_connection_send_message(connection, asyncReply);
446 xpc_release(asyncReply);
447 xpc_release(connection);
448 CFReleaseSafe(client.task);
449 CFReleaseSafe(clientAuditToken);
450 });
451 }
452 CFReleaseSafe(policies);
453 CFReleaseSafe(anchors);
454 CFReleaseSafe(certificates);
455 CFReleaseSafe(responses);
456 CFReleaseSafe(scts);
457 CFReleaseSafe(trustedLogs);
458 CFReleaseSafe(exceptions);
459 } else {
460 SecXPCServerOperation *server_op = NULL;
461 switch (operation) {
462 case sec_trust_store_contains_id:
463 server_op = &trustd_ops.trust_store_contains;
464 break;
465 case sec_trust_store_set_trust_settings_id:
466 server_op = &trustd_ops.trust_store_set_trust_settings;
467 break;
468 case sec_trust_store_remove_certificate_id:
469 server_op = &trustd_ops.trust_store_remove_certificate;
470 break;
471 case sec_trust_store_copy_all_id:
472 server_op = &trustd_ops.trust_store_copy_all;
473 break;
474 case sec_trust_store_copy_usage_constraints_id:
475 server_op = &trustd_ops.trust_store_copy_usage_constraints;
476 break;
477 case sec_ocsp_cache_flush_id:
478 server_op = &trustd_ops.ocsp_cache_flush;
479 break;
480 case sec_ota_pki_trust_store_version_id:
481 server_op = &trustd_ops.ota_pki_trust_store_version;
482 break;
483 case kSecXPCOpOTAGetEscrowCertificates:
484 server_op = &trustd_ops.ota_pki_get_escrow_certs;
485 break;
486 case kSecXPCOpOTAPKIGetNewAsset:
487 server_op = &trustd_ops.ota_pki_get_new_asset;
488 break;
489 case kSecXPCOpTLSAnaltyicsReport:
490 server_op = &trustd_ops.tls_analytics_report;
491 default:
492 break;
493 }
494 if (server_op && server_op->handler) {
495 bool entitled = true;
496 if (server_op->entitlement) {
497 entitled = EntitlementPresentAndTrue(operation, client.task, server_op->entitlement, &error);
498 }
499 if (entitled) {
500 (void)server_op->handler(event, replyMessage, &error);
501 }
502 }
503 }
504
505 if (error)
506 {
507 if(SecErrorGetOSStatus(error) == errSecItemNotFound)
508 secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error);
509 else if (SecErrorGetOSStatus(error) == errSecAuthNeeded)
510 secwarning("Authentication is needed %@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error);
511 else
512 secerror("%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error);
513
514 xpcError = SecCreateXPCObjectWithCFError(error);
515 if (replyMessage) {
516 xpc_dictionary_set_value(replyMessage, kSecXPCKeyError, xpcError);
517 }
518 } else if (replyMessage) {
519 secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyMessage);
520 }
521 } else {
522 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, &error, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event);
523 secerror("%@: returning error: %@", client.task, error);
524 xpcError = SecCreateXPCObjectWithCFError(error);
525 replyMessage = xpc_create_reply_with_format(event, "{%string: %value}", kSecXPCKeyError, xpcError);
526 }
527
528 if (replyMessage) {
529 xpc_connection_send_message(connection, replyMessage);
530 xpc_release(replyMessage);
531 }
532 if (xpcError)
533 xpc_release(xpcError);
534 CFReleaseSafe(error);
535 CFReleaseSafe(client.accessGroups);
536 CFReleaseSafe(client.musr);
537 CFReleaseSafe(client.task);
538 CFReleaseSafe(domains);
539 CFReleaseSafe(clientAuditToken);
540 }
541
542 static void trustd_xpc_init(const char *service_name)
543 {
544 secdebug("serverxpc", "start");
545 xpc_connection_t listener = xpc_connection_create_mach_service(service_name, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
546 if (!listener) {
547 seccritical("security failed to register xpc listener for %s, exiting", service_name);
548 abort();
549 }
550
551 xpc_connection_set_event_handler(listener, ^(xpc_object_t connection) {
552 if (xpc_get_type(connection) == XPC_TYPE_CONNECTION) {
553 xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
554 if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
555 xpc_retain(connection);
556 xpc_retain(event);
557 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
558 trustd_xpc_dictionary_handler(connection, event);
559 xpc_release(event);
560 xpc_release(connection);
561 });
562 }
563 });
564 xpc_connection_resume(connection);
565 }
566 });
567 xpc_connection_resume(listener);
568 }
569
570 static void trustd_delete_old_sqlite_keychain_files(CFStringRef baseFilename) {
571 WithPathInKeychainDirectory(baseFilename, ^(const char *utf8String) {
572 (void)remove(utf8String);
573 });
574 CFStringRef shmFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-shm"), baseFilename);
575 WithPathInKeychainDirectory(shmFile, ^(const char *utf8String) {
576 (void)remove(utf8String);
577 });
578 CFReleaseNull(shmFile);
579 CFStringRef walFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-wal"), baseFilename);
580 WithPathInKeychainDirectory(walFile, ^(const char *utf8String) {
581 (void)remove(utf8String);
582 });
583 CFReleaseNull(walFile);
584 CFStringRef journalFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-journal"), baseFilename);
585 WithPathInKeychainDirectory(journalFile, ^(const char *utf8String) {
586 (void)remove(utf8String);
587 });
588 CFReleaseNull(journalFile);
589 }
590
591 #if TARGET_OS_OSX
592 static void trustd_delete_old_sqlite_user_cache_files(CFStringRef baseFilename) {
593 WithPathInUserCacheDirectory(baseFilename, ^(const char *utf8String) {
594 (void)remove(utf8String);
595 });
596 CFStringRef shmFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-shm"), baseFilename);
597 WithPathInUserCacheDirectory(shmFile, ^(const char *utf8String) {
598 (void)remove(utf8String);
599 });
600 CFReleaseNull(shmFile);
601 CFStringRef walFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-wal"), baseFilename);
602 WithPathInUserCacheDirectory(walFile, ^(const char *utf8String) {
603 (void)remove(utf8String);
604 });
605 CFReleaseNull(walFile);
606 CFStringRef journalFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-journal"), baseFilename);
607 WithPathInUserCacheDirectory(journalFile, ^(const char *utf8String) {
608 (void)remove(utf8String);
609 });
610 CFReleaseNull(journalFile);
611 }
612 #endif // TARGET_OS_OSX
613
614 static void trustd_delete_old_files(void) {
615 /* We try to clean up after ourselves, but don't care if we succeed. */
616 WithPathInRevocationInfoDirectory(CFSTR("update-current"), ^(const char *utf8String) {
617 (void)remove(utf8String);
618 });
619 WithPathInRevocationInfoDirectory(CFSTR("update-full"), ^(const char *utf8String) {
620 (void)remove(utf8String);
621 });
622 WithPathInRevocationInfoDirectory(CFSTR("update-full.gz"), ^(const char *utf8String) {
623 (void)remove(utf8String);
624 });
625 #if TARGET_OS_IPHONE
626 trustd_delete_old_sqlite_keychain_files(CFSTR("trustd_health_analytics.db"));
627 trustd_delete_old_sqlite_keychain_files(CFSTR("trust_analytics.db"));
628 trustd_delete_old_sqlite_keychain_files(CFSTR("TLS_analytics.db"));
629 #else
630 trustd_delete_old_sqlite_user_cache_files(CFSTR("trustd_health_analytics.db"));
631 trustd_delete_old_sqlite_user_cache_files(CFSTR("trust_analytics.db"));
632 trustd_delete_old_sqlite_user_cache_files(CFSTR("TLS_analytics.db"));
633 #endif //TARGET_OS_IPHONE
634 }
635
636 #if TARGET_OS_OSX
637 static void trustd_delete_old_caches(void) {
638 /* We try to clean up after ourselves, but don't care if we succeed. */
639 trustd_delete_old_sqlite_keychain_files(CFSTR("ocspcache.sqlite3"));
640 trustd_delete_old_sqlite_keychain_files(CFSTR("caissuercache.sqlite3"));
641 }
642
643 static void trustd_sandbox(void) {
644 char buf[PATH_MAX] = "";
645
646 if (!_set_user_dir_suffix("com.apple.trustd") ||
647 confstr(_CS_DARWIN_USER_TEMP_DIR, buf, sizeof(buf)) == 0 ||
648 (mkdir(buf, 0700) && errno != EEXIST)) {
649 secerror("failed to initialize temporary directory (%d): %s", errno, strerror(errno));
650 exit(EXIT_FAILURE);
651 }
652
653 char *tempdir = realpath(buf, NULL);
654 if (tempdir == NULL) {
655 secerror("failed to resolve temporary directory (%d): %s", errno, strerror(errno));
656 exit(EXIT_FAILURE);
657 }
658
659 if (confstr(_CS_DARWIN_USER_CACHE_DIR, buf, sizeof(buf)) == 0 ||
660 (mkdir(buf, 0700) && errno != EEXIST)) {
661 secerror("failed to initialize cache directory (%d): %s", errno, strerror(errno));
662 exit(EXIT_FAILURE);
663 }
664
665 char *cachedir = realpath(buf, NULL);
666 if (cachedir == NULL) {
667 secerror("failed to resolve cache directory (%d): %s", errno, strerror(errno));
668 exit(EXIT_FAILURE);
669 }
670
671 const char *parameters[] = {
672 "_TMPDIR", tempdir,
673 "_DARWIN_CACHE_DIR", cachedir,
674 NULL
675 };
676
677 char *sberror = NULL;
678 if (sandbox_init_with_parameters("com.apple.trustd", SANDBOX_NAMED, parameters, &sberror) != 0) {
679 secerror("Failed to enter trustd sandbox: %{public}s", sberror);
680 exit(EXIT_FAILURE);
681 }
682
683 free(tempdir);
684 free(cachedir);
685 }
686 #else
687 static void trustd_sandbox(void) {
688 char buf[PATH_MAX] = "";
689 _set_user_dir_suffix("com.apple.trustd");
690 confstr(_CS_DARWIN_USER_TEMP_DIR, buf, sizeof(buf));
691 }
692 #endif
693
694 static void trustd_cfstream_init() {
695 CFReadStreamRef rs = CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8*) "", 0, kCFAllocatorNull);
696 CFReadStreamSetDispatchQueue(rs, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
697 CFReadStreamSetDispatchQueue(rs, NULL);
698 CFRelease(rs);
699 }
700
701 int main(int argc, char *argv[])
702 {
703 char *wait4debugger = getenv("WAIT4DEBUGGER");
704 if (wait4debugger && !strcasecmp("YES", wait4debugger)) {
705 seccritical("SIGSTOPing self, awaiting debugger");
706 kill(getpid(), SIGSTOP);
707 seccritical("Again, for good luck (or bad debuggers)");
708 kill(getpid(), SIGSTOP);
709 }
710
711 /* <rdar://problem/15792007> Users with network home folders are unable to use/save password for Mail/Cal/Contacts/websites
712 Our process doesn't realize DB connections get invalidated when network home directory users logout
713 and their home gets unmounted. Exit our process and start fresh when user logs back in.
714 */
715 #if TARGET_OS_OSX
716 int sessionstatechanged_tok;
717 notify_register_dispatch(kSA_SessionStateChangedNotification, &sessionstatechanged_tok, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(int token __unused) {
718 // we could be a process running as root.
719 // However, since root never logs out this isn't an issue.
720 if (SASSessionStateForUser(getuid()) == kSA_state_loggingout_pointofnoreturn) {
721 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3ull*NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
722 xpc_transaction_exit_clean();
723 });
724 }
725 });
726 #endif
727
728 #if TARGET_OS_OSX
729 /* Before we enter the sandbox, we need to delete the old caches kept in ~/Library/Keychains
730 * After we enter the sandbox, we won't be able to access them. */
731 trustd_delete_old_caches();
732 #endif
733
734 trustd_sandbox();
735
736 /* Also clean up old files in our sandbox. After sandboxing, so that user dir suffix is set. */
737 trustd_delete_old_files();
738
739 const char *serviceName = kTrustdXPCServiceName;
740 if (argc > 1 && (!strcmp(argv[1], "--agent"))) {
741 serviceName = kTrustdAgentXPCServiceName;
742 }
743
744 /* set up SQLite before some other component has a chance to create a database connection */
745 _SecDbServerSetup();
746
747 /* <rdar://problem/33635964> Force legacy CFStream run loop initialization before any NSURLSession usage */
748 trustd_cfstream_init();
749
750 gTrustd = &trustd_spi;
751
752 /* Initialize static content */
753 SecPolicyServerInitialize(); // set up callbacks for policy checks
754 SecRevocationDbInitialize(); // set up revocation database if it doesn't already exist, or needs to be replaced
755 SecPinningDbInitialize(); // set up the pinning database
756 #if TARGET_OS_OSX
757 SecTrustLegacySourcesListenForKeychainEvents(); // set up the legacy keychain event listeners (for cache invalidation)
758 #endif
759
760 /* We're ready now. Go. */
761 trustd_xpc_init(serviceName);
762 dispatch_main();
763 }