]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecuritydXPC.c
Security-59306.101.1.tar.gz
[apple/security.git] / OSX / sec / Security / SecuritydXPC.c
1 /*
2 * Copyright (c) 2012-2014 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
25 #include <Security/SecuritydXPC.h>
26 #include <Security/SecCFAllocator.h>
27 #include <ipc/securityd_client.h>
28 #include <utilities/SecCFError.h>
29 #include <utilities/SecDb.h>
30 #include <utilities/SecCFWrappers.h>
31 #include <utilities/der_plist.h>
32
33 // TODO Shorten these string values to save ipc bandwidth.
34 const char *kSecXPCKeyOperation = "operation";
35 const char *kSecXPCKeyResult = "status";
36 const char *kSecXPCKeyEndpoint = "endpoint";
37 const char *kSecXPCKeyError = "error";
38 const char *kSecXPCKeyClientToken = "client";
39 const char *kSecXPCKeyPeerInfoArray = "peer-infos";
40 const char *kSecXPCKeyPeerInfo = "peer-info";
41 const char *kSecXPCKeyUserLabel = "userlabel";
42 const char *kSecXPCKeyBackup = "backup";
43 const char *kSecXPCKeyKeybag = "keybag";
44 const char *kSecXPCKeyFlags = "flags";
45 const char *kSecXPCKeyUserPassword = "password";
46 const char *kSecXPCKeyEMCSBackup = "emcsbackup";
47 const char *kSecXPCKeyDSID = "dsid";
48 const char *kSecXPCKeyQuery = "query";
49 const char *kSecXPCKeyAttributesToUpdate = "attributesToUpdate";
50 const char *kSecXPCKeyDomain = "domain";
51 const char *kSecXPCKeyDigest = "digest";
52 const char *kSecXPCKeyCertificate = "cert";
53 const char *kSecXPCKeySettings = "settings";
54 const char *kSecXPCKeyOTAFileDirectory = "path";
55 const char *kSecXPCLimitInMinutes = "limitMinutes";
56 const char *kSecXPCPublicPeerId = "publicPeerId"; // Public peer id
57 const char *kSecXPCOTRSession = "otrsess"; // OTR session bytes
58 const char *kSecXPCData = "data"; // Data to process
59 const char *kSecXPCOTRReady = "otrrdy"; // OTR ready for messages
60 const char *kSecXPCKeyViewName = "viewname";
61 const char *kSecXPCKeyViewActionCode = "viewactioncode";
62 const char *kSecXPCKeyHSA2AutoAcceptInfo = "autoacceptinfo";
63 const char *kSecXPCKeyString = "cfstring";
64 const char *kSecXPCKeyArray = "cfarray";
65 const char *kSecXPCKeySet = "cfset";
66 const char *kSecXPCKeySet2 = "cfset2";
67 const char *kSecXPCKeyNewPublicBackupKey = "newPublicBackupKey";
68 const char *kSecXPCKeyRecoveryPublicKey = "RecoveryPublicKey";
69 const char *kSecXPCKeyIncludeV0 = "includeV0";
70 const char *kSecXPCKeyReason = "reason";
71 const char *kSecXPCKeyEnabledViewsKey = "enabledViews";
72 const char *kSecXPCKeyDisabledViewsKey = "disabledViews";
73 const char *kSecXPCKeyEscrowLabel = "escrow";
74 const char *kSecXPCKeyTriesLabel = "tries";
75 const char *kSecXPCKeyFileDescriptor = "fileDescriptor";
76 const char *kSecXPCKeyAccessGroups = "accessGroups";
77 const char *kSecXPCKeyClasses = "classes";
78 const char *kSecXPCKeyNormalizedIssuer = "normIssuer";
79 const char *kSecXPCKeySerialNumber = "serialNum";
80 const char *kSecXPCKeyBackupKeybagIdentifier = "backupKeybagID";
81 const char *kSecXPCKeyBackupKeybagPath = "backupKeybagPath";
82 const char *kSecXPCVersion = "version";
83 const char *kSecXPCKeySignInAnalytics = "signinanalytics";
84 //
85 // XPC Functions for both client and server.
86 //
87
88
89 CFStringRef SOSCCGetOperationDescription(enum SecXPCOperation op)
90 {
91 switch (op) {
92 case kSecXPCOpAccountSetToNew:
93 return CFSTR("AccountSetToNew");
94 case kSecXPCOpOTAGetEscrowCertificates:
95 return CFSTR("OTAGetEscrowCertificates");
96 case kSecXPCOpOTAPKIGetNewAsset:
97 return CFSTR("OTAPKIGetNewAsset");
98 case kSecXPCOpOTASecExperimentGetNewAsset:
99 return CFSTR("OTASecExperimentGetNewAsset");
100 case kSecXPCOpOTASecExperimentGetAsset:
101 return CFSTR("OTASecExperimentGetAsset");
102 case kSecXPCOpAcceptApplicants:
103 return CFSTR("AcceptApplicants");
104 case kSecXPCOpBailFromCircle:
105 return CFSTR("BailFromCircle");
106 case kSecXPCOpCanAuthenticate:
107 return CFSTR("CanAuthenticate");
108 case kSecXPCOpCopyApplicantPeerInfo:
109 return CFSTR("CopyApplicantPeerInfo");
110 case kSecXPCOpCopyConcurringPeerPeerInfo:
111 return CFSTR("CopyConcurringPeerPeerInfo");
112 case kSecXPCOpCopyEngineState:
113 return CFSTR("CopyEngineState");
114 case kSecXPCOpCopyGenerationPeerInfo:
115 return CFSTR("CopyGenerationPeerInfo");
116 case kSecXPCOpCopyMyPeerInfo:
117 return CFSTR("CopyMyPeerInfo");
118 case kSecXPCOpCopyNotValidPeerPeerInfo:
119 return CFSTR("CopyNotValidPeerPeerInfo");
120 case kSecXPCOpCopyPeerPeerInfo:
121 return CFSTR("CopyPeerPeerInfo");
122 case kSecXPCOpCopyRetirementPeerInfo:
123 return CFSTR("CopyRetirementPeerInfo");
124 case kSecXPCOpCopyValidPeerPeerInfo:
125 return CFSTR("CopyValidPeerPeerInfo");
126 case kSecXPCOpCopyViewUnawarePeerInfo:
127 return CFSTR("CopyViewUnawarePeerInfo");
128 case kSecXPCOpDeviceInCircle:
129 return CFSTR("DeviceInCircle");
130 case kSecXPCOpGetLastDepartureReason:
131 return CFSTR("GetLastDepartureReason");
132 case kSecXPCOpLoggedOutOfAccount:
133 return CFSTR("LoggedOutOfAccount");
134 case kSecXPCOpProcessSyncWithAllPeers:
135 return CFSTR("ProcessSyncWithAllPeers");
136 case kSecXPCOpProcessSyncWithPeers:
137 return CFSTR("ProcessSyncWithPeers");
138 case kSecXPCOpProcessUnlockNotification:
139 return CFSTR("ProcessUnlockNotification");
140 case kSecXPCOpPurgeUserCredentials:
141 return CFSTR("PurgeUserCredentials");
142 case kSecXPCOpRejectApplicants:
143 return CFSTR("RejectApplicants");
144 case kSecXPCOpRemoveThisDeviceFromCircle:
145 return CFSTR("RemoveThisDeviceFromCircle");
146 case kSecXPCOpRemoveThisDeviceFromCircleWithAnalytics:
147 return CFSTR("RemoveThisDeviceFromCircleWithAnalytics");
148 case kSecXPCOpRemovePeersFromCircle:
149 return CFSTR("RemovePeersFromCircle");
150 case kSecXPCOpRemovePeersFromCircleWithAnalytics:
151 return CFSTR("RemovePeersFromCircleWithAnalytics");
152 case kSecXPCOpRequestToJoin:
153 return CFSTR("RequestToJoin");
154 case kSecXPCOpRequestToJoinWithAnalytics:
155 return CFSTR("RequestToJoinWithAnalytics");
156 case kSecXPCOpRequestToJoinAfterRestore:
157 return CFSTR("RequestToJoinAfterRestore");
158 case kSecXPCOpRequestToJoinAfterRestoreWithAnalytics:
159 return CFSTR("RequestToJoinAfterRestoreWithAnalytics");
160 case kSecXPCOpResetToEmpty:
161 return CFSTR("ResetToEmpty");
162 case kSecXPCOpResetToEmptyWithAnalytics:
163 return CFSTR("ResetToEmptyWithAnalytics");
164 case kSecXPCOpResetToOffering:
165 return CFSTR("ResetToOffering");
166 case kSecXPCOpRollKeys:
167 return CFSTR("RollKeys");
168 case kSecXPCOpSetBagForAllSlices:
169 return CFSTR("SetBagForAllSlices");
170 case kSecXPCOpSetLastDepartureReason:
171 return CFSTR("SetLastDepartureReason");
172 case kSecXPCOpSetNewPublicBackupKey:
173 return CFSTR("SetNewPublicBackupKey");
174 case kSecXPCOpSetUserCredentials:
175 return CFSTR("SetUserCredentials");
176 case kSecXPCOpSetUserCredentialsAndDSID:
177 return CFSTR("SetUserCredentialsAndDSID");
178 case kSecXPCOpSetUserCredentialsAndDSIDWithAnalytics:
179 return CFSTR("SetUserCredentialsAndDSIDWithAnalytics");
180 case kSecXPCOpTryUserCredentials:
181 return CFSTR("TryUserCredentials");
182 case kSecXPCOpValidateUserPublic:
183 return CFSTR("ValidateUserPublic");
184 case kSecXPCOpView:
185 return CFSTR("View");
186 case sec_add_shared_web_credential_id:
187 return CFSTR("add_shared_web_credential");
188 case sec_copy_shared_web_credential_id:
189 return CFSTR("copy_shared_web_credential");
190 case sec_delete_all_id:
191 return CFSTR("delete_all");
192 case sec_get_log_settings_id:
193 return CFSTR("get_log_settings");
194 case sec_item_add_id:
195 return CFSTR("add");
196 case sec_item_backup_copy_names_id:
197 return CFSTR("backup_copy_names");
198 case sec_item_backup_handoff_fd_id:
199 return CFSTR("backup_handoff_fd");
200 case sec_item_backup_restore_id:
201 return CFSTR("backup_restore");
202 case sec_item_backup_set_confirmed_manifest_id:
203 return CFSTR("backup_set_confirmed_manifest");
204 case sec_item_copy_matching_id:
205 return CFSTR("copy_matching");
206 case sec_item_delete_id:
207 return CFSTR("delete");
208 case sec_item_update_id:
209 return CFSTR("update");
210 case sec_keychain_backup_id:
211 return CFSTR("keychain_backup");
212 case sec_keychain_backup_syncable_id:
213 return CFSTR("keychain_backup_syncable");
214 case sec_keychain_restore_id:
215 return CFSTR("keychain_restore");
216 case sec_keychain_restore_syncable_id:
217 return CFSTR("keychain_restore_syncable");
218 case sec_keychain_sync_update_message_id:
219 return CFSTR("keychain_sync_update_message");
220 case sec_ota_pki_trust_store_version_id:
221 return CFSTR("ota_pki_trust_store_version");
222 case sec_ota_pki_asset_version_id:
223 return CFSTR("ota_pki_asset_version");
224 case sec_otr_session_create_remote_id:
225 return CFSTR("otr_session_create_remote");
226 case sec_otr_session_process_packet_remote_id:
227 return CFSTR("otr_session_process_packet_remote");
228 case sec_set_circle_log_settings_id:
229 return CFSTR("set_circle_log_settings");
230 case sec_set_xpc_log_settings_id:
231 return CFSTR("set_xpc_log_settings");
232 case sec_trust_evaluate_id:
233 return CFSTR("trust_evaluate");
234 case sec_trust_store_contains_id:
235 return CFSTR("trust_store_contains");
236 case sec_trust_store_remove_certificate_id:
237 return CFSTR("trust_store_remove_certificate");
238 case sec_trust_store_set_trust_settings_id:
239 return CFSTR("trust_store_set_trust_settings");
240 case sec_trust_store_copy_all_id:
241 return CFSTR("trust_store_copy_all");
242 case sec_trust_store_copy_usage_constraints_id:
243 return CFSTR("trust_store_copy_usage_constraints");
244 case sec_ocsp_cache_flush_id:
245 return CFSTR("ocsp_cache_flush");
246 case soscc_EnsurePeerRegistration_id:
247 return CFSTR("EnsurePeerRegistration");
248 case kSecXPCOpWhoAmI:
249 return CFSTR("WhoAmI");
250 case kSecXPCOpTransmogrifyToSyncBubble:
251 return CFSTR("TransmogrifyToSyncBubble");
252 case sec_item_update_token_items_id:
253 return CFSTR("UpdateTokenItems");
254 case sec_delete_items_with_access_groups_id:
255 return CFSTR("sec_delete_items_with_access_groups_id");
256 case kSecXPCOpPeersHaveViewsEnabled:
257 return CFSTR("kSecXPCOpPeersHaveViewsEnabled");
258 case kSecXPCOpRegisterRecoveryPublicKey:
259 return CFSTR("RegisterRecoveryPublicKey");
260 case kSecXPCOpGetRecoveryPublicKey:
261 return CFSTR("GetRecoveryPublicKey");
262 case kSecXPCOpMessageFromPeerIsPending:
263 return CFSTR("MessageFromPeerIsPending");
264 case kSecXPCOpSendToPeerIsPending:
265 return CFSTR("SendToPeerIsPending");
266 case sec_item_copy_parent_certificates_id:
267 return CFSTR("copy_parent_certificates");
268 case sec_item_certificate_exists_id:
269 return CFSTR("certificate_exists");
270 case kSecXPCOpBackupKeybagAdd:
271 return CFSTR("KeybagAdd");
272 case kSecXPCOpBackupKeybagDelete:
273 return CFSTR("KeybagDelete");
274 case kSecXPCOpKeychainControlEndpoint:
275 return CFSTR("KeychainControlEndpoint");
276 case kSecXPCOpNetworkingAnalyticsReport:
277 return CFSTR("NetworkingAnalyticsReport");
278 case kSecXPCOpSetCTExceptions:
279 return CFSTR("SetCTExceptions");
280 case kSecXPCOpCopyCTExceptions:
281 return CFSTR("CopyCTExceptions");
282 case sec_trust_get_exception_reset_count_id:
283 return CFSTR("GetExceptionResetCount");
284 case sec_trust_increment_exception_reset_count_id:
285 return CFSTR("IncrementExceptionResetCount");
286 default:
287 return CFSTR("Unknown xpc operation");
288 }
289 }
290
291 bool SecXPCDictionarySetPList(xpc_object_t message, const char *key, CFTypeRef object, CFErrorRef *error)
292 {
293 if (!object)
294 return SecError(errSecParam, error, CFSTR("object for key %s is NULL"), key);
295
296 size_t size = der_sizeof_plist(object, error);
297 if (!size)
298 return false;
299 uint8_t *der = malloc(size);
300 uint8_t *der_end = der + size;
301 uint8_t *der_start = der_encode_plist(object, error, der, der_end);
302 if (!der_start) {
303 free(der);
304 return false;
305 }
306
307 assert(der == der_start);
308 xpc_dictionary_set_data(message, key, der_start, der_end - der_start);
309 free(der);
310 return true;
311 }
312
313 bool SecXPCDictionarySetPListOptional(xpc_object_t message, const char *key, CFTypeRef object, CFErrorRef *error) {
314 return !object || SecXPCDictionarySetPList(message, key, object, error);
315 }
316
317 bool SecXPCDictionarySetData(xpc_object_t message, const char *key, CFDataRef data, CFErrorRef *error)
318 {
319 if (!data)
320 return SecError(errSecParam, error, CFSTR("data for key %s is NULL"), key);
321
322 xpc_dictionary_set_data(message, key, CFDataGetBytePtr(data), CFDataGetLength(data));
323 return true;
324 }
325
326 bool SecXPCDictionarySetBool(xpc_object_t message, const char *key, bool value, CFErrorRef *error)
327 {
328 xpc_dictionary_set_bool(message, key, value);
329 return true;
330 }
331
332 bool SecXPCDictionarySetString(xpc_object_t message, const char *key, CFStringRef string, CFErrorRef *error)
333 {
334 if (!string)
335 return SecError(errSecParam, error, CFSTR("string for key %s is NULL"), key);
336
337 __block bool ok = true;
338 CFStringPerformWithCString(string, ^(const char *utf8Str) {
339 if (utf8Str)
340 xpc_dictionary_set_string(message, key, utf8Str);
341 else
342 ok = SecError(errSecParam, error, CFSTR("failed to convert string for key %s to utf8"), key);
343 });
344 return ok;
345 }
346
347 bool SecXPCDictionarySetStringOptional(xpc_object_t message, const char *key, CFStringRef string, CFErrorRef *error) {
348 return !string || SecXPCDictionarySetString(message, key, string, error);
349 }
350
351 bool SecXPCDictionarySetDataOptional(xpc_object_t message, const char *key, CFDataRef data, CFErrorRef *error) {
352 return !data || SecXPCDictionarySetData(message, key, data, error);
353 }
354
355 bool SecXPCDictionarySetInt64(xpc_object_t message, const char *key, int64_t value, CFErrorRef *error) {
356 xpc_dictionary_set_int64(message, key, value);
357 return true;
358 }
359
360 bool SecXPCDictionarySetFileDescriptor(xpc_object_t message, const char *key, int fd, CFErrorRef *error) {
361 xpc_dictionary_set_fd(message, key, fd);
362 return true;
363 }
364
365 int SecXPCDictionaryDupFileDescriptor(xpc_object_t message, const char *key, CFErrorRef *error) {
366 int fd = xpc_dictionary_dup_fd(message, key);
367 if (fd < 0)
368 SecError(errSecParam, error, CFSTR("missing fd for key %s"), key);
369
370 return fd;
371 }
372
373 CFSetRef SecXPCDictionaryCopySet(xpc_object_t message, const char *key, CFErrorRef *error) {
374 CFTypeRef obj = SecXPCDictionaryCopyPList(message, key, error);
375 CFSetRef set = copyIfSet(obj, error);
376 if (obj && !set) {
377 CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(obj));
378 SecError(errSecParam, error, CFSTR("object for key %s not set but %@"), key, description);
379 CFReleaseNull(description);
380 }
381 CFReleaseNull(obj);
382 return set;
383 }
384
385 CFArrayRef SecXPCDictionaryCopyArray(xpc_object_t message, const char *key, CFErrorRef *error) {
386 CFTypeRef array = SecXPCDictionaryCopyPList(message, key, error);
387 if (array) {
388 CFTypeID type_id = CFGetTypeID(array);
389 if (type_id != CFArrayGetTypeID()) {
390 CFStringRef description = CFCopyTypeIDDescription(type_id);
391 SecError(errSecParam, error, CFSTR("object for key %s not array but %@"), key, description);
392 CFReleaseNull(description);
393 CFReleaseNull(array);
394 }
395 }
396 return (CFArrayRef)array;
397 }
398
399 bool SecXPCDictionaryCopyArrayOptional(xpc_object_t message, const char *key, CFArrayRef *parray, CFErrorRef *error) {
400 if (!xpc_dictionary_get_value(message, key)) {
401 *parray = NULL;
402 return true;
403 }
404 *parray = SecXPCDictionaryCopyArray(message, key, error);
405 return *parray;
406 }
407
408 CFDataRef SecXPCDictionaryCopyData(xpc_object_t message, const char *key, CFErrorRef *error) {
409 CFDataRef data = NULL;
410 size_t size = 0;
411 const uint8_t *bytes = xpc_dictionary_get_data(message, key, &size);
412 if (!bytes) {
413 SecError(errSecParam, error, CFSTR("no data for key %s"), key);
414 return NULL;
415 }
416
417 data = CFDataCreate(kCFAllocatorDefault, bytes, size);
418 if (!data)
419 SecError(errSecParam, error, CFSTR("failed to create data for key %s"), key);
420
421 return data;
422 }
423
424 bool SecXPCDictionaryGetBool(xpc_object_t message, const char *key, CFErrorRef *__unused error) {
425 return xpc_dictionary_get_bool(message, key);
426 }
427
428 bool SecXPCDictionaryGetDouble(xpc_object_t message, const char *key, double *pvalue, CFErrorRef *error) {
429 *pvalue = xpc_dictionary_get_double(message, key);
430 if (*pvalue == NAN) {
431 return SecError(errSecParam, error, CFSTR("object for key %s bad double"), key);
432 }
433 return true;
434 }
435
436 bool SecXPCDictionaryCopyDataOptional(xpc_object_t message, const char *key, CFDataRef *pdata, CFErrorRef *error) {
437 size_t size = 0;
438 if (!xpc_dictionary_get_data(message, key, &size)) {
439 *pdata = NULL;
440 return true;
441 }
442 *pdata = SecXPCDictionaryCopyData(message, key, error);
443 return *pdata;
444 }
445
446 bool SecXPCDictionaryCopyURLOptional(xpc_object_t message, const char *key, CFURLRef *purl, CFErrorRef *error) {
447 size_t size = 0;
448 if (!xpc_dictionary_get_data(message, key, &size)) {
449 *purl = NULL;
450 return true;
451 }
452 CFDataRef data = SecXPCDictionaryCopyData(message, key, error);
453 if (data) {
454 *purl = CFURLCreateWithBytes(kCFAllocatorDefault, CFDataGetBytePtr(data), CFDataGetLength(data), kCFStringEncodingUTF8, NULL);
455 }
456 CFReleaseNull(data);
457 return *purl;
458 }
459
460 CFDictionaryRef SecXPCDictionaryCopyDictionary(xpc_object_t message, const char *key, CFErrorRef *error) {
461 CFTypeRef dict = SecXPCDictionaryCopyPList(message, key, error);
462 if (dict) {
463 CFTypeID type_id = CFGetTypeID(dict);
464 if (type_id != CFDictionaryGetTypeID()) {
465 CFStringRef description = CFCopyTypeIDDescription(type_id);
466 SecError(errSecParam, error, CFSTR("object for key %s not dictionary but %@"), key, description);
467 CFReleaseNull(description);
468 CFReleaseNull(dict);
469 }
470 }
471 return (CFDictionaryRef)dict;
472 }
473
474 bool SecXPCDictionaryCopyDictionaryOptional(xpc_object_t message, const char *key, CFDictionaryRef *pdictionary, CFErrorRef *error) {
475 if (!xpc_dictionary_get_value(message, key)) {
476 *pdictionary = NULL;
477 return true;
478 }
479 *pdictionary = SecXPCDictionaryCopyDictionary(message, key, error);
480 return *pdictionary;
481 }
482
483 CFTypeRef SecXPCDictionaryCopyPList(xpc_object_t message, const char *key, CFErrorRef *error)
484 {
485 CFTypeRef cfobject = NULL;
486 size_t size = 0;
487 const uint8_t *der = xpc_dictionary_get_data(message, key, &size);
488 if (!der) {
489 SecError(errSecParam, error, CFSTR("no object for key %s"), key);
490 return NULL;
491 }
492
493 const uint8_t *der_end = der + size;
494 /* use the sensitive allocator so that the dictionary is zeroized upon deallocation */
495 const uint8_t *decode_end = der_decode_plist(SecCFAllocatorZeroize(), kCFPropertyListImmutable,
496 &cfobject, error, der, der_end);
497 if (decode_end != der_end) {
498 SecError(errSecParam, error, CFSTR("trailing garbage after der decoded object for key %s"), key);
499 CFReleaseNull(cfobject);
500 }
501
502 /* zeroize xpc value as it may have contained raw key material */
503 cc_clear(size, (void *)der);
504
505 return cfobject;
506 }
507
508 bool SecXPCDictionaryCopyPListOptional(xpc_object_t message, const char *key, CFTypeRef *pobject, CFErrorRef *error) {
509 size_t size = 0;
510 if (!xpc_dictionary_get_data(message, key, &size)) {
511 *pobject = NULL;
512 return true;
513 }
514 *pobject = SecXPCDictionaryCopyPList(message, key, error);
515 return *pobject;
516 }
517
518 CFStringRef SecXPCDictionaryCopyString(xpc_object_t message, const char *key, CFErrorRef *error) {
519 const char *string = xpc_dictionary_get_string(message, key);
520 if (string) {
521 CFStringRef result = CFStringCreateWithCString(kCFAllocatorDefault, string, kCFStringEncodingUTF8);
522 if (!result) {
523 SecError(errSecAllocate, error, CFSTR("object for key %s failed to convert %s to CFString"), key, string);
524 }
525 return result;
526 } else {
527 SecError(errSecParam, error, CFSTR("object for key %s not string"), key);
528 return NULL;
529 }
530 }
531
532 bool SecXPCDictionaryCopyStringOptional(xpc_object_t message, const char *key, CFStringRef *pstring, CFErrorRef *error) {
533 if (!xpc_dictionary_get_value(message, key)) {
534 *pstring = NULL;
535 return true;
536 }
537 *pstring = SecXPCDictionaryCopyString(message, key, error);
538 return *pstring;
539 }
540
541 static CFDataRef CFDataCreateWithXPCArrayAtIndex(xpc_object_t xpc_data_array, size_t index, CFErrorRef *error) {
542 CFDataRef data = NULL;
543 size_t length = 0;
544 const uint8_t *bytes = xpc_array_get_data(xpc_data_array, index, &length);
545 if (bytes) {
546 data = CFDataCreate(kCFAllocatorDefault, bytes, length);
547 }
548 if (!data)
549 SecError(errSecParam, error, CFSTR("data_array[%zu] failed to decode"), index);
550
551 return data;
552 }
553
554 static CFArrayRef CFDataXPCArrayCopyArray(xpc_object_t xpc_data_array, CFErrorRef *error) {
555 CFMutableArrayRef data_array = NULL;
556 require_action_quiet(xpc_get_type(xpc_data_array) == XPC_TYPE_ARRAY, exit,
557 SecError(errSecParam, error, CFSTR("data_array xpc value is not an array")));
558 size_t count = xpc_array_get_count(xpc_data_array);
559 require_action_quiet(data_array = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit,
560 SecError(errSecAllocate, error, CFSTR("failed to create CFArray of capacity %zu"), count));
561
562 size_t ix;
563 for (ix = 0; ix < count; ++ix) {
564 CFDataRef data = CFDataCreateWithXPCArrayAtIndex(xpc_data_array, ix, error);
565 if (!data) {
566 CFRelease(data_array);
567 return NULL;
568 }
569 CFArraySetValueAtIndex(data_array, ix, data);
570 CFRelease(data);
571 }
572
573 exit:
574 return data_array;
575 }
576
577 bool SecXPCDictionaryCopyCFDataArrayOptional(xpc_object_t message, const char *key, CFArrayRef *data_array, CFErrorRef *error) {
578 xpc_object_t xpc_data_array = xpc_dictionary_get_value(message, key);
579 if (!xpc_data_array) {
580 if (data_array)
581 *data_array = NULL;
582 return true;
583 }
584 *data_array = CFDataXPCArrayCopyArray(xpc_data_array, error);
585 return *data_array != NULL;
586 }