2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <AssertMacros.h>
26 #include <TargetConditionals.h>
28 #include <Security/SecureObjectSync/SOSPeerInfo.h>
29 #include <Security/SecureObjectSync/SOSPeerInfoInternal.h>
30 #include <Security/SecureObjectSync/SOSPeerInfoPriv.h>
31 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
32 #include <Security/SecureObjectSync/SOSPeerInfoSecurityProperties.h>
33 #include <Security/SecureObjectSync/SOSCircle.h>
34 #include <Security/SecureObjectSync/SOSInternal.h>
35 #include <ipc/securityd_client.h>
37 #include <CoreFoundation/CFArray.h>
38 #include <dispatch/dispatch.h>
43 #include <utilities/SecCFWrappers.h>
44 #include <utilities/SecCFRelease.h>
45 #include <utilities/SecCFError.h>
46 #include <utilities/SecXPCError.h>
48 #include <utilities/der_plist.h>
49 #include <utilities/der_plist_internal.h>
50 #include <corecrypto/ccder.h>
51 #include <utilities/der_date.h>
53 #include <corecrypto/ccdigest.h>
54 #include <corecrypto/ccsha2.h>
57 #include <CoreFoundation/CoreFoundation.h>
58 #include <CoreFoundation/CFDate.h>
62 #if TARGET_OS_IPHONE || TARGET_OS_EMBEDDED
63 #include <MobileGestalt.h>
66 #include <Security/SecBase64.h>
67 #include <Security/SecKeyPriv.h>
68 #include <Security/SecOTR.h>
69 #include <Security/SecuritydXPC.h>
71 CFGiblisWithHashFor(SOSPeerInfo);
74 const CFStringRef kPIUserDefinedDeviceNameKey = CFSTR("ComputerName");
75 const CFStringRef kPIDeviceModelNameKey = CFSTR("ModelName");
76 const CFStringRef kPIMessageProtocolVersionKey = CFSTR("MessageProtocolVersion");
77 const CFStringRef kPIOSVersionKey = CFSTR("OSVersion");
79 // Description Dictionary Entries
80 static CFStringRef sPublicKeyKey = CFSTR("PublicSigningKey");
81 static CFStringRef sOctagonPublicKeyKey = CFSTR("OctagonPublicSigningKey");
82 const CFStringRef sGestaltKey = CFSTR("DeviceGestalt");
83 const CFStringRef sVersionKey = CFSTR("ConflictVersion");
84 static CFStringRef sCloudIdentityKey = CFSTR("CloudIdentity");
85 static CFStringRef sApplicationDate = CFSTR("ApplicationDate");
86 static CFStringRef sApplicationUsig = CFSTR("ApplicationUsig");
87 static CFStringRef sRetirementDate = CFSTR("RetirementDate");
90 CFStringRef kSOSPeerInfoDescriptionKey = CFSTR("SOSPeerInfoDescription");
91 CFStringRef kSOSPeerInfoSignatureKey = CFSTR("SOSPeerInfoSignature");
92 CFStringRef kSOSPeerInfoNameKey = CFSTR("SOSPeerInfoName");
94 //Peer Info V2 Dictionary IDS keys
95 CFStringRef sPreferIDS = CFSTR("PreferIDS");
96 CFStringRef sPreferIDSFragmentation = CFSTR("PreferIDFragmentation");
97 CFStringRef sPreferIDSACKModel = CFSTR("PreferIDSAckModel");
98 CFStringRef sTransportType = CFSTR("TransportType");
99 CFStringRef sDeviceID = CFSTR("DeviceID");
101 const CFStringRef peerIDLengthKey = CFSTR("idLength");
103 SOSPeerInfoRef SOSPeerInfoAllocate(CFAllocatorRef allocator) {
104 return CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
107 static SecKeyRef _SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer, CFStringRef keyDictionaryKey, CFErrorRef* error)
109 SecKeyRef result = NULL;
111 CFDataRef pubKeyBytes = asData(CFDictionaryGetValue(peer->description, keyDictionaryKey), error);
112 require_quiet(pubKeyBytes, fail);
114 CFAllocatorRef allocator = CFGetAllocator(peer);
115 result = SecKeyCreateFromPublicData(allocator, kSecECDSAAlgorithmID, pubKeyBytes);
117 require_quiet(SecAllocationError(result, error, CFSTR("Failed to create public key from data %@"), pubKeyBytes), fail);
123 SecKeyRef SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer, CFErrorRef* error) {
124 return _SOSPeerInfoCopyPubKey(peer, sPublicKeyKey, error);
127 SecKeyRef SOSPeerInfoCopyOctagonPubKey(SOSPeerInfoRef peer, CFErrorRef* error)
129 return _SOSPeerInfoCopyPubKey(peer, sOctagonPublicKeyKey, error);
132 CFDataRef SOSPeerInfoGetAutoAcceptInfo(SOSPeerInfoRef peer) {
133 CFDataRef pubKeyBytes = NULL;
135 pubKeyBytes = CFDictionaryGetValue(peer->description, sPublicKeyKey);
136 if (!pubKeyBytes || CFGetTypeID(pubKeyBytes) != CFDataGetTypeID()) {
143 static bool SOSDescriptionHash(SOSPeerInfoRef peer, const struct ccdigest_info *di, void *hashresult, CFErrorRef *error) {
144 ccdigest_di_decl(di, ctx);
145 ccdigest_init(di, ctx);
147 if(!SOSPeerInfoUpdateDigestWithDescription(peer, di, ctx_p, error)) return false;
148 ccdigest_final(di, ctx, hashresult);
154 static CFDataRef sosCopySignedHash(SecKeyRef privkey, const struct ccdigest_info *di, uint8_t *hbuf) {
156 size_t siglen = SIGLEN;
158 if((stat = SecKeyRawSign(privkey, kSecPaddingNone, hbuf, di->output_size, sig, &siglen)) != 0) {
161 return CFDataCreate(NULL, sig, (CFIndex)siglen);
164 static bool sosVerifyHash(SecKeyRef pubkey, const struct ccdigest_info *di, uint8_t *hbuf, CFDataRef signature) {
165 return SecKeyRawVerify(pubkey, kSecPaddingNone, hbuf, di->output_size,
166 CFDataGetBytePtr(signature), CFDataGetLength(signature)) == errSecSuccess;
169 bool SOSPeerInfoSign(SecKeyRef privKey, SOSPeerInfoRef peer, CFErrorRef *error) {
171 const struct ccdigest_info *di = ccsha256_di();
172 uint8_t hbuf[di->output_size];
173 CFDataRef newSignature = NULL;
175 require_action_quiet(SOSDescriptionHash(peer, di, hbuf, error), fail,
176 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to hash description for peer"), NULL, error));
178 newSignature = sosCopySignedHash(privKey, di, hbuf);
179 require_action_quiet(newSignature, fail, SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to sign peerinfo for peer"), NULL, error));
181 CFReleaseNull(peer->signature);
182 peer->signature = newSignature;
187 CFReleaseNull(newSignature);
191 // Return true (1) if the signature verifies.
192 bool SOSPeerInfoVerify(SOSPeerInfoRef peer, CFErrorRef *error) {
194 const struct ccdigest_info *di = ccsha256_di();
195 uint8_t hbuf[di->output_size];
197 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(peer, error);
198 require_quiet(pubKey, error_out);
200 require_quiet(SOSDescriptionHash(peer, di, hbuf, error), error_out);
202 require_action_quiet(sosVerifyHash(pubKey, di, hbuf, peer->signature), error_out,
203 SOSErrorCreate(kSOSErrorBadSignature, error, NULL,
204 CFSTR("Signature didn't verify for %@"), peer));
208 CFReleaseNull(pubKey);
212 void SOSPeerInfoSetVersionNumber(SOSPeerInfoRef pi, int version) {
213 pi->version = version;
214 CFNumberRef versionNumber = CFNumberCreateWithCFIndex(NULL, pi->version);
215 CFDictionarySetValue(pi->description, sVersionKey, versionNumber);
216 CFReleaseNull(versionNumber);
219 static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator,
220 CFDictionaryRef gestalt, CFDataRef backup_key,
221 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS,
222 CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel,
223 CFSetRef enabledViews,
224 SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error,
225 void (^ description_modifier)(CFMutableDictionaryRef description)) {
226 SOSPeerInfoRef pi = CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
227 pi->gestalt = gestalt;
228 CFRetain(pi->gestalt);
230 pi->version = SOSPeerInfoGetPeerProtocolVersion(pi);
231 CFDataRef publicBytes = NULL;
232 CFDataRef octagonPublicBytes = NULL;
233 CFNumberRef versionNumber = NULL;
235 SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(signingKey);
236 if (publicKey == NULL) {
237 SOSCreateError(kSOSErrorBadKey, CFSTR("Unable to get public"), NULL, error);
242 OSStatus result = SecKeyCopyPublicBytes(publicKey, &publicBytes);
244 if (result != errSecSuccess) {
245 SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error);
250 SecKeyRef octagonPublicKey = SecKeyCreatePublicFromPrivate(octagonSigningKey);
251 if (octagonPublicKey == NULL) {
252 SOSCreateError(kSOSErrorBadKey, CFSTR("Unable to get public key"), NULL, error);
257 result = SecKeyCopyPublicBytes(octagonPublicKey, &octagonPublicBytes);
259 if (result != errSecSuccess) {
260 SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error);
265 pi->signature = CFDataCreateMutable(allocator, 0);
267 versionNumber = CFNumberCreateWithCFIndex(NULL, pi->version);
269 pi->description = CFDictionaryCreateMutableForCFTypesWith(allocator,
270 sVersionKey, versionNumber,
271 sPublicKeyKey, publicBytes,
272 sOctagonPublicKeyKey, octagonPublicBytes,
273 sGestaltKey, pi->gestalt,
277 description_modifier(pi->description);
280 pi->id = SOSCopyIDOfKey(publicKey, error);
281 CFReleaseNull(publicKey);
282 CFReleaseNull(octagonPublicKey);
284 require_quiet(pi->id, exit);
286 // ================ V2 Additions Start
288 if(!SOSPeerInfoUpdateToV2(pi, error)) {
293 // V2DictionarySetValue handles NULL as remove
294 if (backup_key != NULL) SOSPeerInfoV2DictionarySetValue(pi, sBackupKeyKey, backup_key);
295 SOSPeerInfoV2DictionarySetValue(pi, sDeviceID, IDSID);
296 SOSPeerInfoV2DictionarySetValue(pi, sTransportType, transportType);
297 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDS, preferIDS);
298 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSFragmentation, preferFragmentation);
299 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSACKModel, preferAckModel);
300 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, enabledViews);
302 // ================ V2 Additions End
304 if (!SOSPeerInfoSign(signingKey, pi, error)) {
310 CFReleaseNull(versionNumber);
311 CFReleaseNull(publicBytes);
312 CFReleaseNull(octagonPublicBytes);
316 SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error) {
317 return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, octagonSigningKey, error, ^(CFMutableDictionaryRef description) {});
320 SOSPeerInfoRef SOSPeerInfoCreateWithTransportAndViews(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key,
321 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS,
322 CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error)
324 return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, IDSID, transportType, preferIDS, preferFragmentation, preferAckModel, enabledViews, signingKey, octagonSigningKey, error, ^(CFMutableDictionaryRef description) {});
328 SOSPeerInfoRef SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error) {
329 return SOSPeerInfoCreate_Internal(allocator, gestalt, NULL, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, octagonSigningKey, error, ^(CFMutableDictionaryRef description) {
330 CFDictionarySetValue(description, sCloudIdentityKey, kCFBooleanTrue);
336 SOSPeerInfoRef SOSPeerInfoCreateCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFErrorRef* error) {
337 if(!toCopy) return NULL;
338 SOSPeerInfoRef pi = CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
340 pi->description = CFDictionaryCreateMutableCopy(allocator, 0, toCopy->description);
341 pi->signature = CFDataCreateCopy(allocator, toCopy->signature);
343 pi->gestalt = CFDictionaryCreateCopy(allocator, toCopy->gestalt);
344 pi->id = CFStringCreateCopy(allocator, toCopy->id);
346 pi->version = toCopy->version;
347 if(!SOSPeerInfoVersionHasV2Data(pi)) SOSPeerInfoExpandV2Data(pi, error);
353 bool SOSPeerInfoVersionIsCurrent(SOSPeerInfoRef pi) {
354 return pi->version >= PEERINFO_CURRENT_VERSION;
357 bool SOSPeerInfoVersionHasV2Data(SOSPeerInfoRef pi) {
358 return pi->version >= kSOSPeerV2BaseVersion;
361 SOSPeerInfoRef SOSPeerInfoCreateCurrentCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
362 CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS, CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews,
363 SecKeyRef signingKey, CFErrorRef* error) {
365 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
366 if(!SOSPeerInfoVersionHasV2Data(pi)) SOSPeerInfoUpdateToV2(pi, error);
368 //SOSPeerInfoSetSerialNumber(pi);
371 SOSPeerInfoV2DictionarySetValue(pi, sDeviceID, IDSID);
374 SOSPeerInfoV2DictionarySetValue(pi, sTransportType, transportType);
377 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDS, preferIDS);
379 if (preferFragmentation) {
380 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSFragmentation, preferFragmentation);
382 if (preferAckModel) {
383 SOSPeerInfoV2DictionarySetValue(pi, sPreferIDSACKModel, preferAckModel);
386 SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, enabledViews);
389 if(!SOSPeerInfoSign(signingKey, pi, error)) {
397 static SOSPeerInfoRef SOSPeerInfoCopyWithModification(CFAllocatorRef allocator, SOSPeerInfoRef original,
398 SecKeyRef signingKey, CFErrorRef *error,
399 bool (^modification)(SOSPeerInfoRef peerToModify, CFErrorRef *error)) {
401 SOSPeerInfoRef result = NULL;
402 SOSPeerInfoRef copy = SOSPeerInfoCreateCopy(allocator, original, error);
404 require_quiet(modification(copy, error), fail);
406 require_quiet(SOSPeerInfoSign(signingKey, copy, error), fail);
408 CFTransferRetained(result, copy);
416 SOSPeerInfoRef SOSPeerInfoCopyWithGestaltUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) {
417 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
418 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
419 if(!gestalt || !peerToModify) return false;
420 CFRetainAssign(peerToModify->gestalt, gestalt);
421 CFDictionarySetValue(peerToModify->description, sGestaltKey, peerToModify->gestalt);
428 SOSPeerInfoRef SOSPeerInfoCopyWithBackupKeyUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDataRef backupKey, SecKeyRef signingKey, CFErrorRef *error) {
429 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
430 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
431 if (backupKey != NULL)
432 SOSPeerInfoV2DictionarySetValue(peerToModify, sBackupKeyKey, backupKey);
434 SOSPeerInfoV2DictionaryRemoveValue(peerToModify, sBackupKeyKey);
439 static CFDictionaryRef SOSPeerInfoUpdateAndCopyRecord(SOSPeerInfoRef peer, CFStringRef dsid, CFDictionaryRef escrowRecord){
441 CFMutableDictionaryRef existingEscrowRecords = SOSPeerInfoCopyEscrowRecord(peer);
443 if(escrowRecord == NULL && existingEscrowRecords != NULL)
445 CFDictionaryRemoveValue(existingEscrowRecords, dsid);
446 return existingEscrowRecords;
449 if(existingEscrowRecords == NULL)
450 existingEscrowRecords = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
452 CFDictionarySetValue(existingEscrowRecords, dsid, escrowRecord);
454 return existingEscrowRecords;
458 SOSPeerInfoRef SOSPeerInfoCopyWithEscrowRecordUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef dsid, CFDictionaryRef escrowRecord, SecKeyRef signingKey, CFErrorRef *error) {
459 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
460 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
462 CFDictionaryRef updatedEscrowRecords = SOSPeerInfoUpdateAndCopyRecord(peerToModify, dsid, escrowRecord);
463 SOSPeerInfoV2DictionarySetValue(peerToModify, sEscrowRecord, updatedEscrowRecords);
464 CFReleaseNull(updatedEscrowRecords);
469 SOSPeerInfoRef SOSPeerInfoCopyWithReplacedEscrowRecords(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef escrowRecords, SecKeyRef signingKey, CFErrorRef *error) {
470 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
471 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
472 if(escrowRecords != NULL)
473 SOSPeerInfoV2DictionarySetValue(peerToModify, sEscrowRecord, escrowRecords);
479 CFDataRef SOSPeerInfoCopyBackupKey(SOSPeerInfoRef peer) {
480 return SOSPeerInfoV2DictionaryCopyData(peer, sBackupKeyKey);
483 CFMutableDictionaryRef SOSPeerInfoCopyEscrowRecord(SOSPeerInfoRef peer){
484 return SOSPeerInfoV2DictionaryCopyDictionary(peer, sEscrowRecord);
487 bool SOSPeerInfoHasBackupKey(SOSPeerInfoRef peer) {
488 CFDataRef bk = SOSPeerInfoCopyBackupKey(peer);
489 bool success = bk != NULL;
494 SOSPeerInfoRef SOSPeerInfoCopyWithViewsChange(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
495 SOSViewActionCode action, CFStringRef viewname, SOSViewResultCode *retval,
496 SecKeyRef signingKey, CFErrorRef* error) {
497 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
498 if(action == kSOSCCViewEnable) {
499 *retval = SOSViewsEnable(pi, viewname, error);
500 require((kSOSCCViewMember == *retval), exit);
501 } else if(action == kSOSCCViewDisable) {
502 *retval = SOSViewsDisable(pi, viewname, error);
503 require((kSOSCCViewNotMember == *retval), exit);
506 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, *retval = kSOSCCGeneralViewError);
515 CFStringRef sPingKey = CFSTR("Ping");
517 SOSPeerInfoRef SOSPeerInfoCopyWithPing(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, SecKeyRef signingKey, CFErrorRef* error) {
518 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
519 CFDataRef ping = CFDataCreateWithRandomBytes(8);
520 SOSPeerInfoV2DictionarySetValue(pi, sPingKey, ping);
521 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(pi, error);
522 require_quiet(pub_key, exit);
523 pi->id = SOSCopyIDOfKey(pub_key, error);
524 require_quiet(pi->id, exit);
525 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, CFReleaseNull(pi));
528 CFReleaseNull(pub_key);
533 SOSViewResultCode SOSPeerInfoViewStatus(SOSPeerInfoRef pi, CFStringRef view, CFErrorRef *error) {
534 return SOSViewsQuery(pi, view, error);
538 SOSPeerInfoRef SOSPeerInfoCopyWithSecurityPropertyChange(CFAllocatorRef allocator, SOSPeerInfoRef toCopy,
539 SOSSecurityPropertyActionCode action, CFStringRef property, SOSSecurityPropertyResultCode *retval,
540 SecKeyRef signingKey, CFErrorRef* error) {
541 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, toCopy, error);
542 if(action == kSOSCCSecurityPropertyEnable) {
543 *retval = SOSSecurityPropertyEnable(pi, property, error);
544 require((kSOSCCSecurityPropertyValid == *retval), exit);
545 } else if(action == kSOSCCSecurityPropertyDisable) {
546 *retval = SOSSecurityPropertyDisable(pi, property, error);
547 require((kSOSCCSecurityPropertyNotValid == *retval), exit);
550 require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, *retval = kSOSCCGeneralViewError);
558 SOSViewResultCode SOSPeerInfoSecurityPropertyStatus(SOSPeerInfoRef pi, CFStringRef property, CFErrorRef *error) {
559 return SOSSecurityPropertyQuery(pi, property, error);
564 static void SOSPeerInfoDestroy(CFTypeRef aObj) {
565 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
568 CFReleaseNull(pi->description);
569 CFReleaseNull(pi->signature);
570 CFReleaseNull(pi->gestalt);
571 CFReleaseNull(pi->id);
572 if(pi->v2Dictionary) CFReleaseNull(pi->v2Dictionary);
575 static Boolean SOSPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
576 SOSPeerInfoRef lpeer = (SOSPeerInfoRef) lhs;
577 SOSPeerInfoRef rpeer = (SOSPeerInfoRef) rhs;
578 if(!lpeer || !rpeer) return false;
579 return CFEqualSafe(lpeer->description, rpeer->description) && CFEqualSafe(lpeer->signature, rpeer->signature);
583 CFComparisonResult SOSPeerInfoCompareByID(const void *val1, const void *val2, void *context) {
584 // The code below is necessary but not sufficient; not returning a CFComparisonResult
585 // It probably is OK to say that a NULL is < <non-NULL>
586 if (val1 == NULL || val2 == NULL) {
587 ptrdiff_t dv = val1 - val2;
588 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
591 CFStringRef v1 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val1);
592 CFStringRef v2 = SOSPeerInfoGetPeerID((SOSPeerInfoRef) val2);
593 if (v1 == NULL || v2 == NULL) {
594 ptrdiff_t dv = (const void *)v1 - (const void *)v2;
595 return dv < 0 ? kCFCompareLessThan : dv == 0 ? kCFCompareEqualTo : kCFCompareGreaterThan;
598 return CFStringCompare(v1, v2, 0);
601 static CFHashCode SOSPeerInfoHash(CFTypeRef cf) {
602 SOSPeerInfoRef peer = (SOSPeerInfoRef) cf;
604 return CFHash(peer->description) ^ CFHash(peer->signature);
608 static char boolToChars(bool val, char truechar, char falsechar) {
609 return val? truechar: falsechar;
612 static CFStringRef isKnown(CFStringRef ref) {
613 return ref? ref: CFSTR("Unknown ");
616 static CFStringRef copyDescriptionWithFormatOptions(CFTypeRef aObj, CFDictionaryRef formatOptions){
618 SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
621 CFStringRef description = NULL;
622 // Get the format options we care about:
623 bool retired = SOSPeerInfoIsRetirementTicket(pi);
624 bool selfValid = SOSPeerInfoVerify(pi, NULL);
625 bool backingUp = SOSPeerInfoHasBackupKey(pi);
626 bool isKVS = SOSPeerInfoKVSOnly(pi);
627 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
628 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
629 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
631 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
632 CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
634 // Calculate the truncated length
636 CFStringRef objectPrefix = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions, CFSTR("PI@%p"), pi);
638 description = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions,
639 CFSTR("<%@: [name: %20@] [%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]"),
641 isKnown(SOSPeerInfoGetPeerName(pi)),
644 boolToChars(selfValid, 'S', 's'),
645 boolToChars(retired, 'R', 'r'),
646 boolToChars(backingUp, 'B', 'b'),
647 boolToChars(isKVS, 'K', 'I'),
649 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(peerID),
650 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
653 CFReleaseNull(peerID);
654 CFReleaseNull(deviceID);
655 CFReleaseNull(serialNum);
656 CFReleaseNull(objectPrefix);
661 static CFStringRef SOSPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
663 CFStringRef description = NULL;
665 description = copyDescriptionWithFormatOptions(aObj, formatOptions);
670 void SOSPeerInfoLogState(char *category, SOSPeerInfoRef pi, SecKeyRef pubKey, CFStringRef myPID, char sigchr) {
672 bool appValid = SOSPeerInfoApplicationVerify(pi, pubKey, NULL);
673 bool retired = SOSPeerInfoIsRetirementTicket(pi);
674 bool selfValid = SOSPeerInfoVerify(pi, NULL);
675 bool backingUp = SOSPeerInfoHasBackupKey(pi);
676 bool isMe = CFEqualSafe(SOSPeerInfoGetPeerID(pi), myPID) == true;
677 bool isKVS = SOSPeerInfoKVSOnly(pi);
678 CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
679 CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
680 CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
682 CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
683 CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
685 secnotice(category, "PI: [name: %-20@] [%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]", isKnown(SOSPeerInfoGetPeerName(pi)),
686 boolToChars(isMe, 'M', 'm'),
687 boolToChars(appValid, 'A', 'a'),
688 boolToChars(selfValid, 'S', 's'),
689 boolToChars(retired, 'R', 'r'),
690 boolToChars(backingUp, 'B', 'b'),
691 boolToChars(isKVS, 'K', 'I'),
693 isKnown(SOSPeerInfoGetPeerDeviceType(pi)), isKnown(peerID),
694 isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
696 CFReleaseNull(peerID);
697 CFReleaseNull(deviceID);
698 CFReleaseNull(serialNum);
701 CFDictionaryRef SOSPeerInfoCopyPeerGestalt(SOSPeerInfoRef pi) {
702 CFRetain(pi->gestalt);
706 CFDictionaryRef SOSPeerGetGestalt(SOSPeerInfoRef pi){
710 CFStringRef SOSPeerInfoGetPeerName(SOSPeerInfoRef peer) {
711 return SOSPeerInfoLookupGestaltValue(peer, kPIUserDefinedDeviceNameKey);
714 CFStringRef SOSPeerInfoGetPeerDeviceType(SOSPeerInfoRef peer) {
715 return SOSPeerInfoLookupGestaltValue(peer, kPIDeviceModelNameKey);
718 CFIndex SOSPeerInfoGetPeerProtocolVersion(SOSPeerInfoRef peer) {
719 CFIndex version = PEERINFO_CURRENT_VERSION;
720 CFTypeRef val = SOSPeerInfoLookupGestaltValue(peer, kPIMessageProtocolVersionKey);
721 if (val && CFGetTypeID(val) == CFNumberGetTypeID())
722 CFNumberGetValue(val, kCFNumberCFIndexType, &version);
726 CFTypeRef SOSPeerInfoLookupGestaltValue(SOSPeerInfoRef pi, CFStringRef key) {
727 return CFDictionaryGetValue(pi->gestalt, key);
730 CFStringRef SOSPeerInfoGetPeerID(SOSPeerInfoRef pi) {
731 return pi ? pi->id : NULL;
734 bool SOSPeerInfoPeerIDEqual(SOSPeerInfoRef pi, CFStringRef myPeerID) {
735 return CFEqualSafe(myPeerID, SOSPeerInfoGetPeerID(pi));
738 CFIndex SOSPeerInfoGetVersion(SOSPeerInfoRef pi) {
742 bool SOSPeerInfoUpdateDigestWithPublicKeyBytes(SOSPeerInfoRef peer, const struct ccdigest_info *di,
743 ccdigest_ctx_t ctx, CFErrorRef *error) {
744 CFDataRef pubKeyBytes = CFDictionaryGetValue(peer->description, sPublicKeyKey);
747 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Digest failed – no public key"));
751 ccdigest_update(di, ctx, CFDataGetLength(pubKeyBytes), CFDataGetBytePtr(pubKeyBytes));
756 bool SOSPeerInfoUpdateDigestWithDescription(SOSPeerInfoRef peer, const struct ccdigest_info *di,
757 ccdigest_ctx_t ctx, CFErrorRef *error) {
758 if(SOSPeerInfoVersionHasV2Data(peer)) SOSPeerInfoPackV2Data(peer);
759 size_t description_size = der_sizeof_plist(peer->description, error);
760 uint8_t data_begin[description_size];
761 uint8_t *data_end = data_begin + description_size;
762 uint8_t *encoded = der_encode_plist(peer->description, error, data_begin, data_end);
765 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, NULL, CFSTR("Description encode failed"));
769 ccdigest_update(di, ctx, description_size, data_begin);
775 static CFDataRef sosCreateDate() {
776 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
777 size_t bufsiz = der_sizeof_date(now, NULL);
779 der_encode_date(now, NULL, buf, buf+bufsiz);
781 return CFDataCreate(NULL, buf, bufsiz);
784 static CFDateRef sosCreateCFDate(CFDataRef sosdate) {
786 der_decode_date(NULL, 0, &date, NULL, CFDataGetBytePtr(sosdate),
787 CFDataGetBytePtr(sosdate) + CFDataGetLength(sosdate));
791 static bool sospeer_application_hash(SOSPeerInfoRef pi, const struct ccdigest_info *di, uint8_t *hbuf) {
792 CFDataRef appdate = asData(CFDictionaryGetValue(pi->description, sApplicationDate), NULL);
793 if(!appdate) return false;
794 ccdigest_di_decl(di, ctx);
795 ccdigest_init(di, ctx);
796 ccdigest_update(di, ctx, CFDataGetLength(appdate), CFDataGetBytePtr(appdate));
797 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes(pi, di, ctx, NULL)) return false;
798 ccdigest_final(di, ctx, hbuf);
802 SOSPeerInfoRef SOSPeerInfoCopyAsApplication(SOSPeerInfoRef original, SecKeyRef userkey, SecKeyRef peerkey, CFErrorRef *error) {
803 SOSPeerInfoRef result = NULL;
804 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(kCFAllocatorDefault, original, error);
806 const struct ccdigest_info *di = ccsha256_di();
807 uint8_t hbuf[di->output_size];
808 CFDataRef usersig = NULL;
810 CFDataRef creationDate = sosCreateDate();
811 CFDictionarySetValue(pi->description, sApplicationDate, creationDate);
812 CFReleaseNull(creationDate);
814 // Create User Application Signature
815 require_action_quiet(sospeer_application_hash(pi, di, hbuf), fail,
816 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
818 usersig = sosCopySignedHash(userkey, di, hbuf);
819 require_action_quiet(usersig, fail,
820 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to sign public key hash for peer"), NULL, error));
822 CFDictionarySetValue(pi->description, sApplicationUsig, usersig);
824 require_quiet(SOSPeerInfoSign(peerkey, pi, error), fail);
830 CFReleaseNull(usersig);
835 bool SOSPeerInfoApplicationVerify(SOSPeerInfoRef pi, SecKeyRef userkey, CFErrorRef *error) {
836 const struct ccdigest_info *di = ccsha256_di();
837 uint8_t hbuf[di->output_size];
840 CFDataRef usig = CFDictionaryGetValue(pi->description, sApplicationUsig);
841 require_action_quiet(usig, exit,
842 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not an applicant"), NULL, error));
843 // Verify User Application Signature
844 require_action_quiet(sospeer_application_hash(pi, di, hbuf), exit,
845 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Failed to create hash for peer applicant"), NULL, error));
846 require_action_quiet(sosVerifyHash(userkey, di, hbuf, usig), exit,
847 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("user signature of public key hash fails to verify"), NULL, error));
849 result = SOSPeerInfoVerify(pi, error);
856 static CF_RETURNS_RETAINED CFDateRef sosPeerInfoGetDate(SOSPeerInfoRef pi, CFStringRef entry) {
858 CFDataRef sosdate = CFDictionaryGetValue(pi->description, entry);
859 if(!sosdate) return NULL;
860 CFDateRef date = sosCreateCFDate(sosdate);
865 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetApplicationDate(SOSPeerInfoRef pi) {
866 return sosPeerInfoGetDate(pi, sApplicationDate);
869 CF_RETURNS_RETAINED CFDateRef SOSPeerInfoGetRetirementDate(SOSPeerInfoRef pi) {
870 return sosPeerInfoGetDate(pi, sRetirementDate);
879 CFStringRef SOSPeerGestaltGetName(CFDictionaryRef gestalt) {
880 CFStringRef name = SOSPeerGestaltGetAnswer(gestalt, kPIUserDefinedDeviceNameKey);
881 return isString(name) ? name : NULL;
884 CFTypeRef SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt, CFStringRef question) {
885 return gestalt ? CFDictionaryGetValue(gestalt, question) : NULL;
893 SOSPeerInfoRef SOSPeerInfoCreateRetirementTicket(CFAllocatorRef allocator, SecKeyRef privKey, SOSPeerInfoRef peer, CFErrorRef *error) {
895 SOSPeerInfoRef pi = SOSPeerInfoCreateCopy(allocator, peer, error);
899 // Fill out Resignation Date
900 CFDataRef resignationDate = sosCreateDate();
901 CFDictionaryAddValue(pi->description, sRetirementDate, resignationDate);
902 CFReleaseNull(resignationDate);
904 require(SOSPeerInfoSign(privKey, pi, error), fail);
913 CFStringRef SOSPeerInfoInspectRetirementTicket(SOSPeerInfoRef pi, CFErrorRef *error) {
914 CFStringRef retval = NULL;
915 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
916 CFDateRef retirement = NULL;
918 require_quiet(SOSPeerInfoVerify(pi, error), err);
920 retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
921 require_action_quiet(retirement, err,
922 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Peer is not retired"), NULL, error));
924 require_action_quiet(CFDateCompare(now, retirement, NULL) == kCFCompareGreaterThan, err,
925 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Retirement date is after current date"), NULL, error));
927 retval = SOSPeerInfoGetPeerID(pi);
931 CFReleaseNull(retirement);
935 bool SOSPeerInfoRetireRetirementTicket(size_t max_seconds, SOSPeerInfoRef pi) {
936 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
937 CFDateRef retirement = sosCreateCFDate(CFDictionaryGetValue(pi->description, sRetirementDate));
938 CFTimeInterval timediff = CFDateGetTimeIntervalSinceDate(now, retirement); // diff in seconds
940 CFReleaseNull(retirement);
941 if(timediff > (max_seconds)) return true;
945 bool SOSPeerInfoIsRetirementTicket(SOSPeerInfoRef pi) {
946 CFDataRef flag = CFDictionaryGetValue(pi->description, sRetirementDate);
950 bool SOSPeerInfoIsCloudIdentity(SOSPeerInfoRef pi) {
951 CFTypeRef value = CFDictionaryGetValue(pi->description, sCloudIdentityKey);
952 return CFEqualSafe(value, kCFBooleanTrue);
955 SOSPeerInfoRef SOSPeerInfoUpgradeSignatures(CFAllocatorRef allocator, SecKeyRef privKey, SecKeyRef peerKey, SOSPeerInfoRef peer, CFErrorRef *error) {
956 SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(privKey);
957 SOSPeerInfoRef retval = NULL;
959 retval = SOSPeerInfoCopyAsApplication(peer, privKey, peerKey, error);
960 CFReleaseNull(pubKey);
964 CFBooleanRef SOSPeerInfoCopyIDSPreference(SOSPeerInfoRef peer){
965 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDS);
966 return (preference ? preference : CFRetain(kCFBooleanFalse));
970 SOSPeerInfoRef SOSPeerInfoSetIDSPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
971 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
972 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
973 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDS, preference);
978 CFBooleanRef SOSPeerInfoCopyIDSFragmentationPreference(SOSPeerInfoRef peer){
979 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDSFragmentation);
980 return (preference ? preference : CFRetain(kCFBooleanFalse));
983 CFBooleanRef SOSPeerInfoCopyIDSACKModelPreference(SOSPeerInfoRef peer){
984 CFBooleanRef preference = (CFBooleanRef)SOSPeerInfoV2DictionaryCopyBoolean(peer, sPreferIDSACKModel);
985 return (preference ? preference : CFRetain(kCFBooleanFalse));
988 SOSPeerInfoRef SOSPeerInfoSetIDSFragmentationPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
989 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
990 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
991 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDSFragmentation, preference);
996 SOSPeerInfoRef SOSPeerInfoSetIDSACKModelPreference(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFBooleanRef preference, SecKeyRef signingKey, CFErrorRef *error){
997 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
998 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
999 SOSPeerInfoV2DictionarySetValue(peerToModify, sPreferIDSACKModel, preference);
1004 bool SOSPeerInfoTransportTypeIs(SOSPeerInfoRef pi, CFStringRef transportType) {
1005 return SOSPeerInfoV2DictionaryHasStringValue(pi, sTransportType, transportType);
1008 CFStringRef SOSPeerInfoCopyTransportType(SOSPeerInfoRef peer){
1009 CFStringRef transportType = (CFStringRef)SOSPeerInfoV2DictionaryCopyString(peer, sTransportType);
1010 return (transportType ? transportType : CFRetain(SOSTransportMessageTypeKVS));
1013 SOSPeerInfoRef SOSPeerInfoSetTransportType(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef transportType, SecKeyRef signingKey, CFErrorRef *error){
1015 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1016 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1017 SOSPeerInfoV2DictionarySetValue(peerToModify, sTransportType, transportType);
1022 bool SOSPeerInfoKVSOnly(SOSPeerInfoRef pi) {
1023 CFStringRef transportType = SOSPeerInfoCopyTransportType(pi);
1024 bool retval = CFEqualSafe(transportType, SOSTransportMessageTypeKVS);
1025 CFReleaseNull(transportType);
1029 bool SOSPeerInfoHasDeviceID(SOSPeerInfoRef peer) {
1030 return SOSPeerInfoV2DictionaryHasString(peer, sDeviceID);
1033 CFStringRef SOSPeerInfoCopyDeviceID(SOSPeerInfoRef peer){
1034 return (CFStringRef)SOSPeerInfoV2DictionaryCopyString(peer, sDeviceID);
1037 SOSPeerInfoRef SOSPeerInfoSetDeviceID(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef IDS, SecKeyRef signingKey, CFErrorRef *error){
1039 return SOSPeerInfoCopyWithModification(allocator, toCopy, signingKey, error,
1040 ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *error) {
1041 SOSPeerInfoV2DictionarySetValue(peerToModify, sDeviceID, IDS);
1046 bool SOSPeerInfoShouldUseIDSTransport(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1047 return SOSPeerInfoHasDeviceID(myPeer) && SOSPeerInfoTransportTypeIs(myPeer, SOSTransportMessageTypeIDSV2) &&
1048 SOSPeerInfoHasDeviceID(theirPeer) && SOSPeerInfoTransportTypeIs(theirPeer, SOSTransportMessageTypeIDSV2);
1051 bool SOSPeerInfoShouldUseIDSMessageFragmentation(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1053 bool success = false;
1055 CFBooleanRef myPreference = SOSPeerInfoCopyIDSFragmentationPreference(myPeer);
1057 CFBooleanRef theirPreference = SOSPeerInfoCopyIDSFragmentationPreference(theirPeer);
1058 secnotice("IDS Transport", "mypreference: %@, theirpreference: %@", myPreference, theirPreference);
1059 if((myPreference == kCFBooleanTrue && theirPreference == kCFBooleanTrue))
1062 CFReleaseNull(myPreference);
1063 CFReleaseNull(theirPreference);
1067 bool SOSPeerInfoShouldUseACKModel(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer){
1068 bool success = false;
1070 CFBooleanRef myPreference = SOSPeerInfoCopyIDSACKModelPreference(myPeer);
1072 CFBooleanRef theirPreference = SOSPeerInfoCopyIDSACKModelPreference(theirPeer);
1073 secnotice("IDS Transport", "mypreference: %@, theirpreference: %@", myPreference, theirPreference);
1074 if((myPreference == kCFBooleanTrue && theirPreference == kCFBooleanTrue))
1077 CFReleaseNull(myPreference);
1078 CFReleaseNull(theirPreference);
1083 SOSPeerInfoDeviceClass SOSPeerInfoGetClass(SOSPeerInfoRef pi) {
1084 static CFDictionaryRef devID2Class = NULL;
1085 static dispatch_once_t onceToken = 0;
1087 dispatch_once(&onceToken, ^{
1088 CFNumberRef cfSOSPeerInfo_macOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_macOS);
1089 CFNumberRef cfSOSPeerInfo_iOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iOS);
1090 CFNumberRef cfSOSPeerInfo_iCloud = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_iCloud);
1091 // CFNumberRef cfSOSPeerInfo_watchOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_watchOS);
1092 // CFNumberRef cfSOSPeerInfo_tvOS = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSPeerInfo_tvOS);
1094 devID2Class = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
1095 CFSTR("Mac Pro"), cfSOSPeerInfo_macOS,
1096 CFSTR("MacBook"), cfSOSPeerInfo_macOS,
1097 CFSTR("MacBook Pro"), cfSOSPeerInfo_macOS,
1098 CFSTR("iCloud"), cfSOSPeerInfo_iCloud,
1099 CFSTR("iMac"), cfSOSPeerInfo_macOS,
1100 CFSTR("iPad"), cfSOSPeerInfo_iOS,
1101 CFSTR("iPhone"), cfSOSPeerInfo_iOS,
1102 CFSTR("iPod touch"), cfSOSPeerInfo_iOS,
1104 CFReleaseNull(cfSOSPeerInfo_macOS);
1105 CFReleaseNull(cfSOSPeerInfo_iOS);
1106 CFReleaseNull(cfSOSPeerInfo_iCloud);
1108 SOSPeerInfoDeviceClass retval = SOSPeerInfo_unknown;
1109 CFStringRef dt = SOSPeerInfoGetPeerDeviceType(pi);
1110 require_quiet(dt, errOut);
1111 CFNumberRef classNum = CFDictionaryGetValue(devID2Class, dt);
1112 require_quiet(classNum, errOut);
1114 require_quiet(CFNumberGetValue(classNum, kCFNumberCFIndexType, &tmp), errOut);
1115 retval = (SOSPeerInfoDeviceClass) tmp;