]> git.saurik.com Git - apple/security.git/blob - OSX/trustd/trustd.c
Security-58286.240.4.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 .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,
86 };
87
88 static bool SecXPCDictionarySetChainOptional(xpc_object_t message, const char *key, CFArrayRef path, CFErrorRef *error) {
89 if (!path)
90 return true;
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);
97 xpc_chain = NULL;
98 }
99 });
100
101 exit:
102 if (!xpc_chain)
103 return false;
104
105 xpc_dictionary_set_value(message, key, xpc_chain);
106 xpc_release(xpc_chain);
107 return true;
108 }
109
110 static SecCertificateRef SecXPCDictionaryCopyCertificate(xpc_object_t message, const char *key, CFErrorRef *error) {
111 size_t length = 0;
112 const void *bytes = xpc_dictionary_get_data(message, key, &length);
113 if (bytes) {
114 SecCertificateRef certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length);
115 if (certificate)
116 return certificate;
117 SecError(errSecDecode, error, CFSTR("object for key %s failed to create certificate from data"), key);
118 } else {
119 SecError(errSecParam, error, CFSTR("object for key %s missing"), key);
120 }
121 return NULL;
122 }
123
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;
130 }
131
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;
136 return true;
137 }
138 *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error);
139 return *certificates;
140 }
141
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);
144 if (!xpc_policies) {
145 if (policies)
146 *policies = NULL;
147 return true;
148 }
149 *policies = SecPolicyXPCArrayCopyArray(xpc_policies, error);
150 return *policies != NULL;
151 }
152
153 // Returns error if entitlement isn't present.
154 static bool
155 EntitlementPresentAndTrue(uint64_t op, SecTaskRef clientTask, CFStringRef entitlement, CFErrorRef *error)
156 {
157 if (!SecTaskGetBooleanValueForEntitlement(clientTask, entitlement)) {
158 SecError(errSecMissingEntitlement, error, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation)op), clientTask, entitlement);
159 return false;
160 }
161 return true;
162 }
163
164 static SecTrustStoreRef SecXPCDictionaryGetTrustStore(xpc_object_t message, const char *key, CFErrorRef *error) {
165 SecTrustStoreRef ts = NULL;
166 CFStringRef domain = SecXPCDictionaryCopyString(message, key, error);
167 if (domain) {
168 ts = SecTrustStoreForDomainName(domain, error);
169 CFRelease(domain);
170 }
171 return ts;
172 }
173
174 static bool SecXPCTrustStoreContains(SecurityClient * __unused client, xpc_object_t event,
175 xpc_object_t reply, CFErrorRef *error) {
176 bool result = false;
177 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
178 if (ts) {
179 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
180 if (digest) {
181 bool contains;
182 if (SecTrustStoreContainsCertificateWithDigest(ts, digest, &contains, error)) {
183 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, contains);
184 result = true;
185 }
186 CFReleaseNull(digest);
187 }
188 }
189 return result;
190 }
191
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);
196 if (ts) {
197 SecCertificateRef certificate = SecXPCDictionaryCopyCertificate(event, kSecXPCKeyCertificate, error);
198 if (certificate) {
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);
203 noError = true;
204 CFReleaseSafe(trustSettingsDictOrArray);
205 }
206 CFReleaseNull(certificate);
207 }
208 }
209 return noError;
210 }
211
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);
215 if (ts) {
216 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
217 if (digest) {
218 bool result = SecTrustStoreRemoveCertificateWithDigest(ts, digest, error);
219 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result);
220 CFReleaseNull(digest);
221 return true;
222 }
223 }
224 return false;
225 }
226
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);
230 if (ts) {
231 CFArrayRef trustStoreContents = NULL;
232 if(_SecTrustStoreCopyAll(ts, &trustStoreContents, error) && trustStoreContents) {
233 SecXPCDictionarySetPList(reply, kSecXPCKeyResult, trustStoreContents, error);
234 CFReleaseNull(trustStoreContents);
235 return true;
236 }
237 }
238 return false;
239 }
240
241 static bool SecXPCTrustStoreCopyUsageConstraints(SecurityClient * __unused client, xpc_object_t event,
242 xpc_object_t reply, CFErrorRef *error) {
243 bool result = false;
244 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
245 if (ts) {
246 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
247 if (digest) {
248 CFArrayRef usageConstraints = NULL;
249 if(_SecTrustStoreCopyUsageConstraints(ts, digest, &usageConstraints, error) && usageConstraints) {
250 SecXPCDictionarySetPList(reply, kSecXPCKeyResult, usageConstraints, error);
251 CFReleaseNull(usageConstraints);
252 result = true;
253 }
254 CFReleaseNull(digest);
255 }
256 }
257 return result;
258 }
259
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)) {
263 return true;
264 }
265 return false;
266 }
267
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));
271 return true;
272 }
273
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));
277 return true;
278 }
279
280 static bool SecXPC_OTAPKI_GetEscrowCertificates(SecurityClient * __unused client, xpc_object_t event,
281 xpc_object_t reply, CFErrorRef *error) {
282 bool result = false;
283 uint32_t escrowRootType = (uint32_t)xpc_dictionary_get_uint64(event, "escrowType");
284 CFArrayRef array = SecOTAPKICopyCurrentEscrowCertificates(escrowRootType, error);
285 if (array) {
286 xpc_object_t xpc_array = _CFXPCCreateXPCObjectFromCFObject(array);
287 xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_array);
288 xpc_release(xpc_array);
289 result = true;
290 }
291 CFReleaseNull(array);
292 return result;
293 }
294
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));
298 return true;
299 }
300
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);
305 bool result = false;
306 if (attributes && eventName) {
307 result = SecNetworkingAnalyticsReport(eventName, attributes, error);
308 }
309 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result);
310 CFReleaseNull(eventName);
311 return result;
312 }
313
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);
321 }
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);
327 return false;
328 }
329
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);
338 return false;
339 }
340
341 typedef bool(*SecXPCOperationHandler)(SecurityClient *client, xpc_object_t event, xpc_object_t reply, CFErrorRef *error);
342
343 typedef struct {
344 CFStringRef entitlement;
345 SecXPCOperationHandler handler;
346 } SecXPCServerOperation;
347
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;
362 };
363
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 }
378 };
379
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 = {
388 .task = NULL,
389 .accessGroups = NULL,
390 .musr = NULL,
391 .uid = xpc_connection_get_euid(connection),
392 .allowSystemKeychain = true,
393 .allowSyncBubbleKeychain = false,
394 .isNetworkExtension = false,
395 .canAccessNetworkExtensionAccessGroups = false,
396 #if TARGET_OS_IPHONE
397 .inMultiUser = false,
398 #endif
399 };
400
401 secdebug("serverxpc", "entering");
402 if (type == XPC_TYPE_DICTIONARY) {
403 replyMessage = xpc_dictionary_create_reply(event);
404
405 uint64_t operation = xpc_dictionary_get_uint64(event, kSecXPCKeyOperation);
406
407 audit_token_t auditToken = {};
408 xpc_connection_get_audit_token(connection, &auditToken);
409
410 client.task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken);
411 clientAuditToken = CFDataCreate(kCFAllocatorDefault, (const UInt8*)&auditToken, sizeof(auditToken));
412 client.accessGroups = SecTaskCopyAccessGroups(client.task);
413
414 secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64 ")", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), operation);
415
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);
420 double verifyTime;
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);
433
434 // Clear replyMessage so we don't send a synchronous reply.
435 xpc_object_t asyncReply = replyMessage;
436 replyMessage = NULL;
437
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
443 if (replyError) {
444 CFRetain(replyError);
445 } else {
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);
450 }
451 if (replyError) {
452 secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyError);
453 xpc_object_t xpcReplyError = SecCreateXPCObjectWithCFError(replyError);
454 if (xpcReplyError) {
455 xpc_dictionary_set_value(asyncReply, kSecXPCKeyError, xpcReplyError);
456 xpc_release(xpcReplyError);
457 }
458 CFReleaseNull(replyError);
459 } else {
460 secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), asyncReply);
461 }
462
463 xpc_connection_send_message(connection, asyncReply);
464 xpc_release(asyncReply);
465 xpc_release(connection);
466 CFReleaseSafe(client.task);
467 CFReleaseSafe(clientAuditToken);
468 });
469 }
470 CFReleaseSafe(policies);
471 CFReleaseSafe(anchors);
472 CFReleaseSafe(certificates);
473 CFReleaseSafe(responses);
474 CFReleaseSafe(scts);
475 CFReleaseSafe(trustedLogs);
476 CFReleaseSafe(exceptions);
477 } else {
478 SecXPCServerOperation *server_op = NULL;
479 switch (operation) {
480 case sec_trust_store_contains_id:
481 server_op = &trustd_ops.trust_store_contains;
482 break;
483 case sec_trust_store_set_trust_settings_id:
484 server_op = &trustd_ops.trust_store_set_trust_settings;
485 break;
486 case sec_trust_store_remove_certificate_id:
487 server_op = &trustd_ops.trust_store_remove_certificate;
488 break;
489 case sec_trust_store_copy_all_id:
490 server_op = &trustd_ops.trust_store_copy_all;
491 break;
492 case sec_trust_store_copy_usage_constraints_id:
493 server_op = &trustd_ops.trust_store_copy_usage_constraints;
494 break;
495 case sec_ocsp_cache_flush_id:
496 server_op = &trustd_ops.ocsp_cache_flush;
497 break;
498 case sec_ota_pki_trust_store_version_id:
499 server_op = &trustd_ops.ota_pki_trust_store_version;
500 break;
501 case sec_ota_pki_asset_version_id:
502 server_op = &trustd_ops.ota_pki_asset_version;
503 break;
504 case kSecXPCOpOTAGetEscrowCertificates:
505 server_op = &trustd_ops.ota_pki_get_escrow_certs;
506 break;
507 case kSecXPCOpOTAPKIGetNewAsset:
508 server_op = &trustd_ops.ota_pki_get_new_asset;
509 break;
510 case kSecXPCOpNetworkingAnalyticsReport:
511 server_op = &trustd_ops.networking_analytics_report;
512 break;
513 case kSecXPCOpSetCTExceptions:
514 server_op = &trustd_ops.trust_store_set_ct_exceptions;
515 break;
516 case kSecXPCOpCopyCTExceptions:
517 server_op = &trustd_ops.trust_store_copy_ct_exceptions;
518 break;
519 default:
520 break;
521 }
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);
526 }
527 if (entitled) {
528 (void)server_op->handler(&client, event, replyMessage, &error);
529 }
530 }
531 }
532
533 if (error)
534 {
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);
539 else
540 secerror("%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error);
541
542 xpcError = SecCreateXPCObjectWithCFError(error);
543 if (replyMessage) {
544 xpc_dictionary_set_value(replyMessage, kSecXPCKeyError, xpcError);
545 }
546 } else if (replyMessage) {
547 secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyMessage);
548 }
549 } else {
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);
554 }
555
556 if (replyMessage) {
557 xpc_connection_send_message(connection, replyMessage);
558 xpc_release(replyMessage);
559 }
560 if (xpcError)
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);
568 }
569
570 static void trustd_xpc_init(const char *service_name)
571 {
572 secdebug("serverxpc", "start");
573 xpc_connection_t listener = xpc_connection_create_mach_service(service_name, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
574 if (!listener) {
575 seccritical("security failed to register xpc listener for %s, exiting", service_name);
576 abort();
577 }
578
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);
584 }
585 });
586 xpc_connection_resume(connection);
587 }
588 });
589 xpc_connection_resume(listener);
590 }
591
592 static void trustd_delete_old_sqlite_keychain_files(CFStringRef baseFilename) {
593 WithPathInKeychainDirectory(baseFilename, ^(const char *utf8String) {
594 (void)remove(utf8String);
595 });
596 CFStringRef shmFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-shm"), baseFilename);
597 WithPathInKeychainDirectory(shmFile, ^(const char *utf8String) {
598 (void)remove(utf8String);
599 });
600 CFReleaseNull(shmFile);
601 CFStringRef walFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-wal"), baseFilename);
602 WithPathInKeychainDirectory(walFile, ^(const char *utf8String) {
603 (void)remove(utf8String);
604 });
605 CFReleaseNull(walFile);
606 CFStringRef journalFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-journal"), baseFilename);
607 WithPathInKeychainDirectory(journalFile, ^(const char *utf8String) {
608 (void)remove(utf8String);
609 });
610 CFReleaseNull(journalFile);
611 }
612
613 #if TARGET_OS_OSX
614 static void trustd_delete_old_sqlite_user_cache_files(CFStringRef baseFilename) {
615 WithPathInUserCacheDirectory(baseFilename, ^(const char *utf8String) {
616 (void)remove(utf8String);
617 });
618 CFStringRef shmFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-shm"), baseFilename);
619 WithPathInUserCacheDirectory(shmFile, ^(const char *utf8String) {
620 (void)remove(utf8String);
621 });
622 CFReleaseNull(shmFile);
623 CFStringRef walFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-wal"), baseFilename);
624 WithPathInUserCacheDirectory(walFile, ^(const char *utf8String) {
625 (void)remove(utf8String);
626 });
627 CFReleaseNull(walFile);
628 CFStringRef journalFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-journal"), baseFilename);
629 WithPathInUserCacheDirectory(journalFile, ^(const char *utf8String) {
630 (void)remove(utf8String);
631 });
632 CFReleaseNull(journalFile);
633 }
634 #endif // TARGET_OS_OSX
635
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);
640 });
641 WithPathInRevocationInfoDirectory(CFSTR("update-full"), ^(const char *utf8String) {
642 (void)remove(utf8String);
643 });
644 WithPathInRevocationInfoDirectory(CFSTR("update-full.gz"), ^(const char *utf8String) {
645 (void)remove(utf8String);
646 });
647 #if TARGET_OS_IPHONE
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"));
651 #else
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
656 }
657
658 #if TARGET_OS_OSX
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"));
663 }
664
665 static void trustd_sandbox(void) {
666 char buf[PATH_MAX] = "";
667
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));
672 exit(EXIT_FAILURE);
673 }
674
675 char *tempdir = realpath(buf, NULL);
676 if (tempdir == NULL) {
677 secerror("failed to resolve temporary directory (%d): %s", errno, strerror(errno));
678 exit(EXIT_FAILURE);
679 }
680
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));
684 exit(EXIT_FAILURE);
685 }
686
687 char *cachedir = realpath(buf, NULL);
688 if (cachedir == NULL) {
689 secerror("failed to resolve cache directory (%d): %s", errno, strerror(errno));
690 exit(EXIT_FAILURE);
691 }
692
693 const char *parameters[] = {
694 "_TMPDIR", tempdir,
695 "_DARWIN_CACHE_DIR", cachedir,
696 NULL
697 };
698
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);
702 exit(EXIT_FAILURE);
703 }
704
705 free(tempdir);
706 free(cachedir);
707 }
708 #else
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));
713 }
714 #endif
715
716 int main(int argc, char *argv[])
717 {
718 DisableLocalization();
719
720 char *wait4debugger = getenv("WAIT4DEBUGGER");
721 if (wait4debugger && !strcasecmp("YES", wait4debugger)) {
722 seccritical("SIGSTOPing self, awaiting debugger");
723 kill(getpid(), SIGSTOP);
724 seccritical("Again, for good luck (or bad debuggers)");
725 kill(getpid(), SIGSTOP);
726 }
727
728 /* <rdar://problem/15792007> Users with network home folders are unable to use/save password for Mail/Cal/Contacts/websites
729 Our process doesn't realize DB connections get invalidated when network home directory users logout
730 and their home gets unmounted. Exit our process and start fresh when user logs back in.
731 */
732 #if TARGET_OS_OSX
733 int sessionstatechanged_tok;
734 notify_register_dispatch(kSA_SessionStateChangedNotification, &sessionstatechanged_tok, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(int token __unused) {
735 // we could be a process running as root.
736 // However, since root never logs out this isn't an issue.
737 if (SASSessionStateForUser(getuid()) == kSA_state_loggingout_pointofnoreturn) {
738 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3ull*NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
739 xpc_transaction_exit_clean();
740 });
741 }
742 });
743 #endif
744
745 #if TARGET_OS_OSX
746 /* Before we enter the sandbox, we need to delete the old caches kept in ~/Library/Keychains
747 * After we enter the sandbox, we won't be able to access them. */
748 trustd_delete_old_caches();
749 #endif
750
751 trustd_sandbox();
752
753 /* Also clean up old files in our sandbox. After sandboxing, so that user dir suffix is set. */
754 trustd_delete_old_files();
755
756 const char *serviceName = kTrustdXPCServiceName;
757 if (argc > 1 && (!strcmp(argv[1], "--agent"))) {
758 serviceName = kTrustdAgentXPCServiceName;
759 }
760
761 /* set up SQLite before some other component has a chance to create a database connection */
762 _SecDbServerSetup();
763
764 gTrustd = &trustd_spi;
765
766 /* Initialize static content */
767 SecPolicyServerInitialize(); // set up callbacks for policy checks
768 SecRevocationDbInitialize(); // set up revocation database if it doesn't already exist, or needs to be replaced
769 SecPinningDbInitialize(); // set up the pinning database
770 #if TARGET_OS_OSX
771 SecTrustLegacySourcesListenForKeychainEvents(); // set up the legacy keychain event listeners (for cache invalidation)
772 #endif
773
774 /* We're ready now. Go. */
775 trustd_xpc_init(serviceName);
776 dispatch_main();
777 }