/ OSX / sec / Security / SecuritydXPC.c
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          case kSecXPCOpSetTransparentConnectionPins:
283              return CFSTR("SetTransparentConnectionPins");
284          case kSecXPCOpCopyTransparentConnectionPins:
285              return CFSTR("CopyTransparentConnectionPins");
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      return SecXPCDictionarySetPListWithRepair(message, key, object, false, error);
294  }
295  
296  bool SecXPCDictionarySetPListWithRepair(xpc_object_t message, const char *key, CFTypeRef object, bool repair, CFErrorRef *error)
297  {
298      if (!object)
299          return SecError(errSecParam, error, CFSTR("object for key %s is NULL"), key);
300  
301      size_t size = der_sizeof_plist(object, error);
302      if (!size) {
303          return false;
304      }
305      uint8_t *der = malloc(size);
306      uint8_t *der_end = der + size;
307      uint8_t *der_start = der_encode_plist_repair(object, error, repair, der, der_end);
308      if (!der_start) {
309          free(der);
310          return false;
311      }
312  
313      assert(der == der_start);
314      xpc_dictionary_set_data(message, key, der_start, der_end - der_start);
315      free(der);
316      return true;
317  }
318  
319  bool SecXPCDictionarySetPListOptional(xpc_object_t message, const char *key, CFTypeRef object, CFErrorRef *error) {
320      return !object || SecXPCDictionarySetPList(message, key, object, error);
321  }
322  
323  bool SecXPCDictionarySetData(xpc_object_t message, const char *key, CFDataRef data, CFErrorRef *error)
324  {
325      if (!data)
326          return SecError(errSecParam, error, CFSTR("data for key %s is NULL"), key);
327  
328      xpc_dictionary_set_data(message, key, CFDataGetBytePtr(data), CFDataGetLength(data));
329      return true;
330  }
331  
332  bool SecXPCDictionarySetBool(xpc_object_t message, const char *key, bool value, CFErrorRef *error)
333  {
334      xpc_dictionary_set_bool(message, key, value);
335      return true;
336  }
337  
338  bool SecXPCDictionarySetString(xpc_object_t message, const char *key, CFStringRef string, CFErrorRef *error)
339  {
340      if (!string)
341          return SecError(errSecParam, error, CFSTR("string for key %s is NULL"), key);
342  
343      __block bool ok = true;
344      CFStringPerformWithCString(string, ^(const char *utf8Str) {
345          if (utf8Str)
346              xpc_dictionary_set_string(message, key, utf8Str);
347          else
348              ok = SecError(errSecParam, error, CFSTR("failed to convert string for key %s to utf8"), key);
349      });
350      return ok;
351  }
352  
353  bool SecXPCDictionarySetStringOptional(xpc_object_t message, const char *key, CFStringRef string, CFErrorRef *error) {
354      return !string || SecXPCDictionarySetString(message, key, string, error);
355  }
356  
357  bool SecXPCDictionarySetDataOptional(xpc_object_t message, const char *key, CFDataRef data, CFErrorRef *error) {
358      return !data || SecXPCDictionarySetData(message, key, data, error);
359  }
360  
361  bool SecXPCDictionarySetInt64(xpc_object_t message, const char *key, int64_t value, CFErrorRef *error) {
362      xpc_dictionary_set_int64(message, key, value);
363      return true;
364  }
365  
366  bool SecXPCDictionarySetFileDescriptor(xpc_object_t message, const char *key, int fd, CFErrorRef *error) {
367      xpc_dictionary_set_fd(message, key, fd);
368      return true;
369  }
370  
371  int SecXPCDictionaryDupFileDescriptor(xpc_object_t message, const char *key, CFErrorRef *error) {
372      int fd = xpc_dictionary_dup_fd(message, key);
373      if (fd < 0)
374          SecError(errSecParam, error, CFSTR("missing fd for key %s"), key);
375  
376      return fd;
377  }
378  
379  CFSetRef SecXPCDictionaryCopySet(xpc_object_t message, const char *key, CFErrorRef *error) {
380      CFTypeRef obj = SecXPCDictionaryCopyPList(message, key, error);
381      CFSetRef set = copyIfSet(obj, error);
382      if (obj && !set) {
383          CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(obj));
384          SecError(errSecParam, error, CFSTR("object for key %s not set but %@"), key, description);
385          CFReleaseNull(description);
386      }
387      CFReleaseNull(obj);
388      return set;
389  }
390  
391  CFArrayRef SecXPCDictionaryCopyArray(xpc_object_t message, const char *key, CFErrorRef *error) {
392      CFTypeRef array = SecXPCDictionaryCopyPList(message, key, error);
393      if (array) {
394          CFTypeID type_id = CFGetTypeID(array);
395          if (type_id != CFArrayGetTypeID()) {
396              CFStringRef description = CFCopyTypeIDDescription(type_id);
397              SecError(errSecParam, error, CFSTR("object for key %s not array but %@"), key, description);
398              CFReleaseNull(description);
399              CFReleaseNull(array);
400          }
401      }
402      return (CFArrayRef)array;
403  }
404  
405  bool SecXPCDictionaryCopyArrayOptional(xpc_object_t message, const char *key, CFArrayRef *parray, CFErrorRef *error) {
406      if (!xpc_dictionary_get_value(message, key)) {
407          *parray = NULL;
408          return true;
409      }
410      *parray = SecXPCDictionaryCopyArray(message, key, error);
411      return *parray;
412  }
413  
414  CFDataRef SecXPCDictionaryCopyData(xpc_object_t message, const char *key, CFErrorRef *error) {
415      CFDataRef data = NULL;
416      size_t size = 0;
417      const uint8_t *bytes = xpc_dictionary_get_data(message, key, &size);
418      if (!bytes) {
419          SecError(errSecParam, error, CFSTR("no data for key %s"), key);
420          return NULL;
421      }
422  
423      data = CFDataCreate(kCFAllocatorDefault, bytes, size);
424      if (!data)
425          SecError(errSecParam, error, CFSTR("failed to create data for key %s"), key);
426  
427      return data;
428  }
429  
430  bool SecXPCDictionaryGetBool(xpc_object_t message, const char *key, CFErrorRef *__unused error) {
431      return xpc_dictionary_get_bool(message, key);
432  }
433  
434  bool SecXPCDictionaryGetDouble(xpc_object_t message, const char *key, double *pvalue, CFErrorRef *error) {
435      *pvalue = xpc_dictionary_get_double(message, key);
436      if (*pvalue == NAN) {
437          return SecError(errSecParam, error, CFSTR("object for key %s bad double"), key);
438      }
439      return true;
440  }
441  
442  bool SecXPCDictionaryCopyDataOptional(xpc_object_t message, const char *key, CFDataRef *pdata, CFErrorRef *error) {
443      size_t size = 0;
444      if (!xpc_dictionary_get_data(message, key, &size)) {
445          *pdata = NULL;
446          return true;
447      }
448      *pdata = SecXPCDictionaryCopyData(message, key, error);
449      return *pdata;
450  }
451  
452  bool SecXPCDictionaryCopyURLOptional(xpc_object_t message, const char *key, CFURLRef *purl, CFErrorRef *error) {
453      size_t size = 0;
454      if (!xpc_dictionary_get_data(message, key, &size)) {
455          *purl = NULL;
456          return true;
457      }
458      CFDataRef data = SecXPCDictionaryCopyData(message, key, error);
459      if (data) {
460          *purl = CFURLCreateWithBytes(kCFAllocatorDefault, CFDataGetBytePtr(data), CFDataGetLength(data), kCFStringEncodingUTF8, NULL);
461      }
462      CFReleaseNull(data);
463      return *purl;
464  }
465  
466  CFDictionaryRef SecXPCDictionaryCopyDictionary(xpc_object_t message, const char *key, CFErrorRef *error) {
467      CFTypeRef dict = SecXPCDictionaryCopyPList(message, key, error);
468      if (dict) {
469          CFTypeID type_id = CFGetTypeID(dict);
470          if (type_id != CFDictionaryGetTypeID()) {
471              CFStringRef description = CFCopyTypeIDDescription(type_id);
472              SecError(errSecParam, error, CFSTR("object for key %s not dictionary but %@"), key, description);
473              CFReleaseNull(description);
474              CFReleaseNull(dict);
475          }
476      }
477      return (CFDictionaryRef)dict;
478  }
479  
480  bool SecXPCDictionaryCopyDictionaryOptional(xpc_object_t message, const char *key, CFDictionaryRef *pdictionary, CFErrorRef *error) {
481      if (!xpc_dictionary_get_value(message, key)) {
482          *pdictionary = NULL;
483          return true;
484      }
485      *pdictionary = SecXPCDictionaryCopyDictionary(message, key, error);
486      return *pdictionary;
487  }
488  
489  CFTypeRef SecXPCDictionaryCopyPList(xpc_object_t message, const char *key, CFErrorRef *error)
490  {
491      CFTypeRef cfobject = NULL;
492      size_t size = 0;
493      const uint8_t *der = xpc_dictionary_get_data(message, key, &size);
494      if (!der) {
495          SecError(errSecParam, error, CFSTR("no object for key %s"), key);
496          return NULL;
497      }
498  
499      const uint8_t *der_end = der + size;
500      /* use the sensitive allocator so that the dictionary is zeroized upon deallocation */
501      const uint8_t *decode_end = der_decode_plist(SecCFAllocatorZeroize(),
502                                            &cfobject, error, der, der_end);
503      if (decode_end != der_end) {
504          CFStringRef description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("trailing garbage after der decoded object for key %s"), key);
505          SecError(errSecParam, error, CFSTR("%@"), description);
506          if (error) {    // The no-error case is handled in SecError directly
507              secerror("xpc: %@", *error);
508          }
509          __security_simulatecrash(description, __sec_exception_code_CorruptItem);
510          CFReleaseNull(description);
511          CFReleaseNull(cfobject);
512      }
513  
514      /* zeroize xpc value as it may have contained raw key material */
515      cc_clear(size, (void *)der);
516  
517      return cfobject;
518  }
519  
520  bool SecXPCDictionaryCopyPListOptional(xpc_object_t message, const char *key, CFTypeRef *pobject, CFErrorRef *error) {
521      size_t size = 0;
522      if (!xpc_dictionary_get_data(message, key, &size)) {
523          *pobject = NULL;
524          return true;
525      }
526      *pobject = SecXPCDictionaryCopyPList(message, key, error);
527      return *pobject;
528  }
529  
530  CFStringRef SecXPCDictionaryCopyString(xpc_object_t message, const char *key, CFErrorRef *error) {
531      const char *string = xpc_dictionary_get_string(message, key);
532      if (string) {
533          CFStringRef result = CFStringCreateWithCString(kCFAllocatorDefault, string, kCFStringEncodingUTF8);
534          if (!result) {
535              SecError(errSecAllocate, error, CFSTR("object for key %s failed to convert %s to CFString"), key, string);
536          }
537          return result;
538      } else {
539          SecError(errSecParam, error, CFSTR("object for key %s not string"), key);
540          return NULL;
541      }
542  }
543  
544  bool SecXPCDictionaryCopyStringOptional(xpc_object_t message, const char *key, CFStringRef *pstring, CFErrorRef *error) {
545      if (!xpc_dictionary_get_value(message, key)) {
546          *pstring = NULL;
547          return true;
548      }
549      *pstring = SecXPCDictionaryCopyString(message, key, error);
550      return *pstring;
551  }
552  
553  static CFDataRef CFDataCreateWithXPCArrayAtIndex(xpc_object_t xpc_data_array, size_t index, CFErrorRef *error) {
554      CFDataRef data = NULL;
555      size_t length = 0;
556      const uint8_t *bytes = xpc_array_get_data(xpc_data_array, index, &length);
557      if (bytes) {
558          data = CFDataCreate(kCFAllocatorDefault, bytes, length);
559      }
560      if (!data)
561          SecError(errSecParam, error, CFSTR("data_array[%zu] failed to decode"), index);
562  
563      return data;
564  }
565  
566  static CFArrayRef CFDataXPCArrayCopyArray(xpc_object_t xpc_data_array, CFErrorRef *error) {
567      CFMutableArrayRef data_array = NULL;
568      require_action_quiet(xpc_get_type(xpc_data_array) == XPC_TYPE_ARRAY, exit,
569                           SecError(errSecParam, error, CFSTR("data_array xpc value is not an array")));
570      size_t count = xpc_array_get_count(xpc_data_array);
571      require_action_quiet(data_array = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit,
572                           SecError(errSecAllocate, error, CFSTR("failed to create CFArray of capacity %zu"), count));
573  
574      size_t ix;
575      for (ix = 0; ix < count; ++ix) {
576          CFDataRef data = CFDataCreateWithXPCArrayAtIndex(xpc_data_array, ix, error);
577          if (!data) {
578              CFRelease(data_array);
579              return NULL;
580          }
581          CFArraySetValueAtIndex(data_array, ix, data);
582          CFRelease(data);
583      }
584  
585  exit:
586      return data_array;
587  }
588  
589  bool SecXPCDictionaryCopyCFDataArrayOptional(xpc_object_t message, const char *key, CFArrayRef *data_array, CFErrorRef *error) {
590      xpc_object_t xpc_data_array = xpc_dictionary_get_value(message, key);
591      if (!xpc_data_array) {
592          if (data_array)
593              *data_array = NULL;
594          return true;
595      }
596      *data_array = CFDataXPCArrayCopyArray(xpc_data_array, error);
597      return *data_array != NULL;
598  }