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