]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecuritydXPC.c
Security-59754.80.3.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 kSecXPCOpRemovePeersFromCircle:
147 return CFSTR("RemovePeersFromCircle");
148 case kSecXPCOpRequestToJoin:
149 return CFSTR("RequestToJoin");
150 case kSecXPCOpRequestToJoinAfterRestore:
151 return CFSTR("RequestToJoinAfterRestore");
152 case kSecXPCOpResetToEmpty:
153 return CFSTR("ResetToEmpty");
154 case kSecXPCOpResetToOffering:
155 return CFSTR("ResetToOffering");
156 case kSecXPCOpRollKeys:
157 return CFSTR("RollKeys");
158 case kSecXPCOpSetBagForAllSlices:
159 return CFSTR("SetBagForAllSlices");
160 case kSecXPCOpSetLastDepartureReason:
161 return CFSTR("SetLastDepartureReason");
162 case kSecXPCOpSetNewPublicBackupKey:
163 return CFSTR("SetNewPublicBackupKey");
164 case kSecXPCOpSetUserCredentials:
165 return CFSTR("SetUserCredentials");
166 case kSecXPCOpSetUserCredentialsAndDSID:
167 return CFSTR("SetUserCredentialsAndDSID");
168 case kSecXPCOpTryUserCredentials:
169 return CFSTR("TryUserCredentials");
170 case kSecXPCOpValidateUserPublic:
171 return CFSTR("ValidateUserPublic");
172 case kSecXPCOpView:
173 return CFSTR("View");
174 case sec_add_shared_web_credential_id:
175 return CFSTR("add_shared_web_credential");
176 case sec_copy_shared_web_credential_id:
177 return CFSTR("copy_shared_web_credential");
178 case sec_delete_all_id:
179 return CFSTR("delete_all");
180 case sec_get_log_settings_id:
181 return CFSTR("get_log_settings");
182 case sec_item_add_id:
183 return CFSTR("add");
184 case sec_item_backup_copy_names_id:
185 return CFSTR("backup_copy_names");
186 case sec_item_backup_ensure_copy_view_id:
187 return CFSTR("backup_register_view");
188 case sec_item_backup_handoff_fd_id:
189 return CFSTR("backup_handoff_fd");
190 case sec_item_backup_restore_id:
191 return CFSTR("backup_restore");
192 case sec_item_backup_set_confirmed_manifest_id:
193 return CFSTR("backup_set_confirmed_manifest");
194 case sec_item_copy_matching_id:
195 return CFSTR("copy_matching");
196 case sec_item_delete_id:
197 return CFSTR("delete");
198 case sec_item_update_id:
199 return CFSTR("update");
200 case sec_keychain_backup_id:
201 return CFSTR("keychain_backup");
202 case sec_keychain_backup_syncable_id:
203 return CFSTR("keychain_backup_syncable");
204 case sec_keychain_restore_id:
205 return CFSTR("keychain_restore");
206 case sec_keychain_restore_syncable_id:
207 return CFSTR("keychain_restore_syncable");
208 case sec_keychain_sync_update_message_id:
209 return CFSTR("keychain_sync_update_message");
210 case sec_ota_pki_trust_store_version_id:
211 return CFSTR("ota_pki_trust_store_version");
212 case sec_ota_pki_asset_version_id:
213 return CFSTR("ota_pki_asset_version");
214 case sec_otr_session_create_remote_id:
215 return CFSTR("otr_session_create_remote");
216 case sec_otr_session_process_packet_remote_id:
217 return CFSTR("otr_session_process_packet_remote");
218 case sec_set_circle_log_settings_id:
219 return CFSTR("set_circle_log_settings");
220 case sec_set_xpc_log_settings_id:
221 return CFSTR("set_xpc_log_settings");
222 case sec_trust_evaluate_id:
223 return CFSTR("trust_evaluate");
224 case sec_trust_store_contains_id:
225 return CFSTR("trust_store_contains");
226 case sec_trust_store_remove_certificate_id:
227 return CFSTR("trust_store_remove_certificate");
228 case sec_trust_store_set_trust_settings_id:
229 return CFSTR("trust_store_set_trust_settings");
230 case sec_trust_store_copy_all_id:
231 return CFSTR("trust_store_copy_all");
232 case sec_trust_store_copy_usage_constraints_id:
233 return CFSTR("trust_store_copy_usage_constraints");
234 case sec_ocsp_cache_flush_id:
235 return CFSTR("ocsp_cache_flush");
236 case soscc_EnsurePeerRegistration_id:
237 return CFSTR("EnsurePeerRegistration");
238 case kSecXPCOpWhoAmI:
239 return CFSTR("WhoAmI");
240 case kSecXPCOpTransmogrifyToSyncBubble:
241 return CFSTR("TransmogrifyToSyncBubble");
242 case sec_item_update_token_items_for_access_groups_id:
243 return CFSTR("UpdateTokenItems");
244 case sec_delete_items_with_access_groups_id:
245 return CFSTR("sec_delete_items_with_access_groups_id");
246 case kSecXPCOpPeersHaveViewsEnabled:
247 return CFSTR("kSecXPCOpPeersHaveViewsEnabled");
248 case kSecXPCOpRegisterRecoveryPublicKey:
249 return CFSTR("RegisterRecoveryPublicKey");
250 case kSecXPCOpGetRecoveryPublicKey:
251 return CFSTR("GetRecoveryPublicKey");
252 case kSecXPCOpMessageFromPeerIsPending:
253 return CFSTR("MessageFromPeerIsPending");
254 case kSecXPCOpSendToPeerIsPending:
255 return CFSTR("SendToPeerIsPending");
256 case sec_item_copy_parent_certificates_id:
257 return CFSTR("copy_parent_certificates");
258 case sec_item_certificate_exists_id:
259 return CFSTR("certificate_exists");
260 case kSecXPCOpBackupKeybagAdd:
261 return CFSTR("KeybagAdd");
262 case kSecXPCOpBackupKeybagDelete:
263 return CFSTR("KeybagDelete");
264 case kSecXPCOpKeychainControlEndpoint:
265 return CFSTR("KeychainControlEndpoint");
266 case kSecXPCOpNetworkingAnalyticsReport:
267 return CFSTR("NetworkingAnalyticsReport");
268 case kSecXPCOpSetCTExceptions:
269 return CFSTR("SetCTExceptions");
270 case kSecXPCOpCopyCTExceptions:
271 return CFSTR("CopyCTExceptions");
272 case sec_trust_get_exception_reset_count_id:
273 return CFSTR("GetExceptionResetCount");
274 case sec_trust_increment_exception_reset_count_id:
275 return CFSTR("IncrementExceptionResetCount");
276 case kSecXPCOpSetCARevocationAdditions:
277 return CFSTR("SetCARevocationAdditions");
278 case kSecXPCOpCopyCARevocationAdditions:
279 return CFSTR("CopyCARevocationAdditions");
280 case kSecXPCOpValidUpdate:
281 return CFSTR("ValidUpdate");
282 default:
283 return CFSTR("Unknown xpc operation");
284 }
285 }
286
287 bool SecXPCDictionarySetPList(xpc_object_t message, const char *key, CFTypeRef object, CFErrorRef *error)
288 {
289 return SecXPCDictionarySetPListWithRepair(message, key, object, false, error);
290 }
291
292 bool SecXPCDictionarySetPListWithRepair(xpc_object_t message, const char *key, CFTypeRef object, bool repair, CFErrorRef *error)
293 {
294 if (!object)
295 return SecError(errSecParam, error, CFSTR("object for key %s is NULL"), key);
296
297 size_t size = der_sizeof_plist(object, error);
298 if (!size) {
299 return false;
300 }
301 uint8_t *der = malloc(size);
302 uint8_t *der_end = der + size;
303 uint8_t *der_start = der_encode_plist_repair(object, error, repair, der, der_end);
304 if (!der_start) {
305 free(der);
306 return false;
307 }
308
309 assert(der == der_start);
310 xpc_dictionary_set_data(message, key, der_start, der_end - der_start);
311 free(der);
312 return true;
313 }
314
315 bool SecXPCDictionarySetPListOptional(xpc_object_t message, const char *key, CFTypeRef object, CFErrorRef *error) {
316 return !object || SecXPCDictionarySetPList(message, key, object, error);
317 }
318
319 bool SecXPCDictionarySetData(xpc_object_t message, const char *key, CFDataRef data, CFErrorRef *error)
320 {
321 if (!data)
322 return SecError(errSecParam, error, CFSTR("data for key %s is NULL"), key);
323
324 xpc_dictionary_set_data(message, key, CFDataGetBytePtr(data), CFDataGetLength(data));
325 return true;
326 }
327
328 bool SecXPCDictionarySetBool(xpc_object_t message, const char *key, bool value, CFErrorRef *error)
329 {
330 xpc_dictionary_set_bool(message, key, value);
331 return true;
332 }
333
334 bool SecXPCDictionarySetString(xpc_object_t message, const char *key, CFStringRef string, CFErrorRef *error)
335 {
336 if (!string)
337 return SecError(errSecParam, error, CFSTR("string for key %s is NULL"), key);
338
339 __block bool ok = true;
340 CFStringPerformWithCString(string, ^(const char *utf8Str) {
341 if (utf8Str)
342 xpc_dictionary_set_string(message, key, utf8Str);
343 else
344 ok = SecError(errSecParam, error, CFSTR("failed to convert string for key %s to utf8"), key);
345 });
346 return ok;
347 }
348
349 bool SecXPCDictionarySetStringOptional(xpc_object_t message, const char *key, CFStringRef string, CFErrorRef *error) {
350 return !string || SecXPCDictionarySetString(message, key, string, error);
351 }
352
353 bool SecXPCDictionarySetDataOptional(xpc_object_t message, const char *key, CFDataRef data, CFErrorRef *error) {
354 return !data || SecXPCDictionarySetData(message, key, data, error);
355 }
356
357 bool SecXPCDictionarySetInt64(xpc_object_t message, const char *key, int64_t value, CFErrorRef *error) {
358 xpc_dictionary_set_int64(message, key, value);
359 return true;
360 }
361
362 bool SecXPCDictionarySetFileDescriptor(xpc_object_t message, const char *key, int fd, CFErrorRef *error) {
363 xpc_dictionary_set_fd(message, key, fd);
364 return true;
365 }
366
367 int SecXPCDictionaryDupFileDescriptor(xpc_object_t message, const char *key, CFErrorRef *error) {
368 int fd = xpc_dictionary_dup_fd(message, key);
369 if (fd < 0)
370 SecError(errSecParam, error, CFSTR("missing fd for key %s"), key);
371
372 return fd;
373 }
374
375 CFSetRef SecXPCDictionaryCopySet(xpc_object_t message, const char *key, CFErrorRef *error) {
376 CFTypeRef obj = SecXPCDictionaryCopyPList(message, key, error);
377 CFSetRef set = copyIfSet(obj, error);
378 if (obj && !set) {
379 CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(obj));
380 SecError(errSecParam, error, CFSTR("object for key %s not set but %@"), key, description);
381 CFReleaseNull(description);
382 }
383 CFReleaseNull(obj);
384 return set;
385 }
386
387 CFArrayRef SecXPCDictionaryCopyArray(xpc_object_t message, const char *key, CFErrorRef *error) {
388 CFTypeRef array = SecXPCDictionaryCopyPList(message, key, error);
389 if (array) {
390 CFTypeID type_id = CFGetTypeID(array);
391 if (type_id != CFArrayGetTypeID()) {
392 CFStringRef description = CFCopyTypeIDDescription(type_id);
393 SecError(errSecParam, error, CFSTR("object for key %s not array but %@"), key, description);
394 CFReleaseNull(description);
395 CFReleaseNull(array);
396 }
397 }
398 return (CFArrayRef)array;
399 }
400
401 bool SecXPCDictionaryCopyArrayOptional(xpc_object_t message, const char *key, CFArrayRef *parray, CFErrorRef *error) {
402 if (!xpc_dictionary_get_value(message, key)) {
403 *parray = NULL;
404 return true;
405 }
406 *parray = SecXPCDictionaryCopyArray(message, key, error);
407 return *parray;
408 }
409
410 CFDataRef SecXPCDictionaryCopyData(xpc_object_t message, const char *key, CFErrorRef *error) {
411 CFDataRef data = NULL;
412 size_t size = 0;
413 const uint8_t *bytes = xpc_dictionary_get_data(message, key, &size);
414 if (!bytes) {
415 SecError(errSecParam, error, CFSTR("no data for key %s"), key);
416 return NULL;
417 }
418
419 data = CFDataCreate(kCFAllocatorDefault, bytes, size);
420 if (!data)
421 SecError(errSecParam, error, CFSTR("failed to create data for key %s"), key);
422
423 return data;
424 }
425
426 bool SecXPCDictionaryGetBool(xpc_object_t message, const char *key, CFErrorRef *__unused error) {
427 return xpc_dictionary_get_bool(message, key);
428 }
429
430 bool SecXPCDictionaryGetDouble(xpc_object_t message, const char *key, double *pvalue, CFErrorRef *error) {
431 *pvalue = xpc_dictionary_get_double(message, key);
432 if (*pvalue == NAN) {
433 return SecError(errSecParam, error, CFSTR("object for key %s bad double"), key);
434 }
435 return true;
436 }
437
438 bool SecXPCDictionaryCopyDataOptional(xpc_object_t message, const char *key, CFDataRef *pdata, CFErrorRef *error) {
439 size_t size = 0;
440 if (!xpc_dictionary_get_data(message, key, &size)) {
441 *pdata = NULL;
442 return true;
443 }
444 *pdata = SecXPCDictionaryCopyData(message, key, error);
445 return *pdata;
446 }
447
448 bool SecXPCDictionaryCopyURLOptional(xpc_object_t message, const char *key, CFURLRef *purl, CFErrorRef *error) {
449 size_t size = 0;
450 if (!xpc_dictionary_get_data(message, key, &size)) {
451 *purl = NULL;
452 return true;
453 }
454 CFDataRef data = SecXPCDictionaryCopyData(message, key, error);
455 if (data) {
456 *purl = CFURLCreateWithBytes(kCFAllocatorDefault, CFDataGetBytePtr(data), CFDataGetLength(data), kCFStringEncodingUTF8, NULL);
457 }
458 CFReleaseNull(data);
459 return *purl;
460 }
461
462 CFDictionaryRef SecXPCDictionaryCopyDictionary(xpc_object_t message, const char *key, CFErrorRef *error) {
463 CFTypeRef dict = SecXPCDictionaryCopyPList(message, key, error);
464 if (dict) {
465 CFTypeID type_id = CFGetTypeID(dict);
466 if (type_id != CFDictionaryGetTypeID()) {
467 CFStringRef description = CFCopyTypeIDDescription(type_id);
468 SecError(errSecParam, error, CFSTR("object for key %s not dictionary but %@"), key, description);
469 CFReleaseNull(description);
470 CFReleaseNull(dict);
471 }
472 }
473 return (CFDictionaryRef)dict;
474 }
475
476 bool SecXPCDictionaryCopyDictionaryOptional(xpc_object_t message, const char *key, CFDictionaryRef *pdictionary, CFErrorRef *error) {
477 if (!xpc_dictionary_get_value(message, key)) {
478 *pdictionary = NULL;
479 return true;
480 }
481 *pdictionary = SecXPCDictionaryCopyDictionary(message, key, error);
482 return *pdictionary;
483 }
484
485 CFTypeRef SecXPCDictionaryCopyPList(xpc_object_t message, const char *key, CFErrorRef *error)
486 {
487 CFTypeRef cfobject = NULL;
488 size_t size = 0;
489 const uint8_t *der = xpc_dictionary_get_data(message, key, &size);
490 if (!der) {
491 SecError(errSecParam, error, CFSTR("no object for key %s"), key);
492 return NULL;
493 }
494
495 const uint8_t *der_end = der + size;
496 /* use the sensitive allocator so that the dictionary is zeroized upon deallocation */
497 const uint8_t *decode_end = der_decode_plist(SecCFAllocatorZeroize(),
498 &cfobject, error, der, der_end);
499 if (decode_end != der_end) {
500 CFStringRef description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("trailing garbage after der decoded object for key %s"), key);
501 SecError(errSecParam, error, CFSTR("%@"), description);
502 if (error) { // The no-error case is handled in SecError directly
503 secerror("xpc: %@", *error);
504 }
505 __security_simulatecrash(description, __sec_exception_code_CorruptItem);
506 CFReleaseNull(description);
507 CFReleaseNull(cfobject);
508 }
509
510 /* zeroize xpc value as it may have contained raw key material */
511 cc_clear(size, (void *)der);
512
513 return cfobject;
514 }
515
516 bool SecXPCDictionaryCopyPListOptional(xpc_object_t message, const char *key, CFTypeRef *pobject, CFErrorRef *error) {
517 size_t size = 0;
518 if (!xpc_dictionary_get_data(message, key, &size)) {
519 *pobject = NULL;
520 return true;
521 }
522 *pobject = SecXPCDictionaryCopyPList(message, key, error);
523 return *pobject;
524 }
525
526 CFStringRef SecXPCDictionaryCopyString(xpc_object_t message, const char *key, CFErrorRef *error) {
527 const char *string = xpc_dictionary_get_string(message, key);
528 if (string) {
529 CFStringRef result = CFStringCreateWithCString(kCFAllocatorDefault, string, kCFStringEncodingUTF8);
530 if (!result) {
531 SecError(errSecAllocate, error, CFSTR("object for key %s failed to convert %s to CFString"), key, string);
532 }
533 return result;
534 } else {
535 SecError(errSecParam, error, CFSTR("object for key %s not string"), key);
536 return NULL;
537 }
538 }
539
540 bool SecXPCDictionaryCopyStringOptional(xpc_object_t message, const char *key, CFStringRef *pstring, CFErrorRef *error) {
541 if (!xpc_dictionary_get_value(message, key)) {
542 *pstring = NULL;
543 return true;
544 }
545 *pstring = SecXPCDictionaryCopyString(message, key, error);
546 return *pstring;
547 }
548
549 static CFDataRef CFDataCreateWithXPCArrayAtIndex(xpc_object_t xpc_data_array, size_t index, CFErrorRef *error) {
550 CFDataRef data = NULL;
551 size_t length = 0;
552 const uint8_t *bytes = xpc_array_get_data(xpc_data_array, index, &length);
553 if (bytes) {
554 data = CFDataCreate(kCFAllocatorDefault, bytes, length);
555 }
556 if (!data)
557 SecError(errSecParam, error, CFSTR("data_array[%zu] failed to decode"), index);
558
559 return data;
560 }
561
562 static CFArrayRef CFDataXPCArrayCopyArray(xpc_object_t xpc_data_array, CFErrorRef *error) {
563 CFMutableArrayRef data_array = NULL;
564 require_action_quiet(xpc_get_type(xpc_data_array) == XPC_TYPE_ARRAY, exit,
565 SecError(errSecParam, error, CFSTR("data_array xpc value is not an array")));
566 size_t count = xpc_array_get_count(xpc_data_array);
567 require_action_quiet(data_array = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit,
568 SecError(errSecAllocate, error, CFSTR("failed to create CFArray of capacity %zu"), count));
569
570 size_t ix;
571 for (ix = 0; ix < count; ++ix) {
572 CFDataRef data = CFDataCreateWithXPCArrayAtIndex(xpc_data_array, ix, error);
573 if (!data) {
574 CFRelease(data_array);
575 return NULL;
576 }
577 CFArraySetValueAtIndex(data_array, ix, data);
578 CFRelease(data);
579 }
580
581 exit:
582 return data_array;
583 }
584
585 bool SecXPCDictionaryCopyCFDataArrayOptional(xpc_object_t message, const char *key, CFArrayRef *data_array, CFErrorRef *error) {
586 xpc_object_t xpc_data_array = xpc_dictionary_get_value(message, key);
587 if (!xpc_data_array) {
588 if (data_array)
589 *data_array = NULL;
590 return true;
591 }
592 *data_array = CFDataXPCArrayCopyArray(xpc_data_array, error);
593 return *data_array != NULL;
594 }