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 }