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/SOSCircle.h>
33 #include <Security/SecureObjectSync/SOSAccountPriv.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 const CFStringRef sGestaltKey
= CFSTR("DeviceGestalt");
82 const CFStringRef sVersionKey
= CFSTR("ConflictVersion");
83 static CFStringRef sCloudIdentityKey
= CFSTR("CloudIdentity");
84 static CFStringRef sApplicationDate
= CFSTR("ApplicationDate");
85 static CFStringRef sApplicationUsig
= CFSTR("ApplicationUsig");
86 static CFStringRef sRetirementDate
= CFSTR("RetirementDate");
89 CFStringRef kSOSPeerInfoDescriptionKey
= CFSTR("SOSPeerInfoDescription");
90 CFStringRef kSOSPeerInfoSignatureKey
= CFSTR("SOSPeerInfoSignature");
91 CFStringRef kSOSPeerInfoNameKey
= CFSTR("SOSPeerInfoName");
93 //Peer Info V2 Dictionary IDS keys
94 CFStringRef sPreferIDS
= CFSTR("PreferIDS");
95 CFStringRef sPreferIDSFragmentation
= CFSTR("PreferIDFragmentation");
96 CFStringRef sTransportType
= CFSTR("TransportType");
97 CFStringRef sDeviceID
= CFSTR("DeviceID");
99 const CFStringRef peerIDLengthKey
= CFSTR("idLength");
101 SOSPeerInfoRef
SOSPeerInfoAllocate(CFAllocatorRef allocator
) {
102 return CFTypeAllocate(SOSPeerInfo
, struct __OpaqueSOSPeerInfo
, allocator
);
105 SecKeyRef
SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer
, CFErrorRef
* error
) {
106 SecKeyRef result
= NULL
;
108 CFDataRef pubKeyBytes
= asData(CFDictionaryGetValue(peer
->description
, sPublicKeyKey
), error
);
109 require_quiet(pubKeyBytes
, fail
);
111 CFAllocatorRef allocator
= CFGetAllocator(peer
);
112 result
= SecKeyCreateFromPublicData(allocator
, kSecECDSAAlgorithmID
, pubKeyBytes
);
114 require_quiet(SecAllocationError(result
, error
, CFSTR("Failed to create public key from data %@"), pubKeyBytes
), fail
);
120 CFDataRef
SOSPeerInfoGetAutoAcceptInfo(SOSPeerInfoRef peer
) {
121 CFDataRef pubKeyBytes
= NULL
;
123 pubKeyBytes
= CFDictionaryGetValue(peer
->description
, sPublicKeyKey
);
124 if (!pubKeyBytes
|| CFGetTypeID(pubKeyBytes
) != CFDataGetTypeID()) {
131 static bool SOSDescriptionHash(SOSPeerInfoRef peer
, const struct ccdigest_info
*di
, void *hashresult
, CFErrorRef
*error
) {
132 ccdigest_di_decl(di
, ctx
);
133 ccdigest_init(di
, ctx
);
135 if(!SOSPeerInfoUpdateDigestWithDescription(peer
, di
, ctx_p
, error
)) return false;
136 ccdigest_final(di
, ctx
, hashresult
);
142 static CFDataRef
sosSignHash(SecKeyRef privkey
, const struct ccdigest_info
*di
, uint8_t *hbuf
) {
144 size_t siglen
= SIGLEN
;
146 if((stat
= SecKeyRawSign(privkey
, kSecPaddingNone
, hbuf
, di
->output_size
, sig
, &siglen
)) != 0) {
149 return CFDataCreate(NULL
, sig
, (CFIndex
)siglen
);
152 static bool sosVerifyHash(SecKeyRef pubkey
, const struct ccdigest_info
*di
, uint8_t *hbuf
, CFDataRef signature
) {
153 return SecKeyRawVerify(pubkey
, kSecPaddingNone
, hbuf
, di
->output_size
,
154 CFDataGetBytePtr(signature
), CFDataGetLength(signature
)) == errSecSuccess
;
157 bool SOSPeerInfoSign(SecKeyRef privKey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
159 const struct ccdigest_info
*di
= ccsha256_di();
160 uint8_t hbuf
[di
->output_size
];
161 CFDataRef newSignature
= NULL
;
163 require_action_quiet(SOSDescriptionHash(peer
, di
, hbuf
, error
), fail
,
164 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to hash description for peer"), NULL
, error
));
166 newSignature
= sosSignHash(privKey
, di
, hbuf
);
167 require_action_quiet(newSignature
, fail
, SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to sign peerinfo for peer"), NULL
, error
));
169 CFReleaseNull(peer
->signature
);
170 peer
->signature
= newSignature
;
175 CFReleaseNull(newSignature
);
179 // Return true (1) if the signature verifies.
180 bool SOSPeerInfoVerify(SOSPeerInfoRef peer
, CFErrorRef
*error
) {
182 const struct ccdigest_info
*di
= ccsha256_di();
183 uint8_t hbuf
[di
->output_size
];
185 SecKeyRef pubKey
= SOSPeerInfoCopyPubKey(peer
, error
);
186 require_quiet(pubKey
, error_out
);
188 require_quiet(SOSDescriptionHash(peer
, di
, hbuf
, error
), error_out
);
190 require_action_quiet(sosVerifyHash(pubKey
, di
, hbuf
, peer
->signature
), error_out
,
191 SOSErrorCreate(kSOSErrorBadSignature
, error
, NULL
,
192 CFSTR("Signature didn't verify for %@"), peer
));
196 CFReleaseNull(pubKey
);
200 void SOSPeerInfoSetVersionNumber(SOSPeerInfoRef pi
, int version
) {
201 pi
->version
= version
;
202 CFNumberRef versionNumber
= CFNumberCreateWithCFIndex(NULL
, pi
->version
);
203 CFDictionarySetValue(pi
->description
, sVersionKey
, versionNumber
);
204 CFReleaseNull(versionNumber
);
207 static SOSPeerInfoRef
SOSPeerInfoCreate_Internal(CFAllocatorRef allocator
,
208 CFDictionaryRef gestalt
, CFDataRef backup_key
,
209 CFStringRef IDSID
, CFStringRef transportType
, CFBooleanRef preferIDS
,
210 CFBooleanRef preferFragmentation
, CFSetRef enabledViews
,
211 SecKeyRef signingKey
, CFErrorRef
* error
,
212 void (^ description_modifier
)(CFMutableDictionaryRef description
)) {
213 SOSPeerInfoRef pi
= CFTypeAllocate(SOSPeerInfo
, struct __OpaqueSOSPeerInfo
, allocator
);
214 pi
->gestalt
= gestalt
;
215 CFRetain(pi
->gestalt
);
217 pi
->version
= SOSPeerInfoGetPeerProtocolVersion(pi
);
218 CFDataRef publicBytes
= NULL
;
219 CFNumberRef versionNumber
= NULL
;
221 SecKeyRef publicKey
= SecKeyCreatePublicFromPrivate(signingKey
);
222 if (publicKey
== NULL
) {
223 SOSCreateError(kSOSErrorBadKey
, CFSTR("Unable to get public"), NULL
, error
);
228 OSStatus result
= SecKeyCopyPublicBytes(publicKey
, &publicBytes
);
230 if (result
!= errSecSuccess
) {
231 SOSCreateError(kSOSErrorBadKey
, CFSTR("Failed to export public bytes"), NULL
, error
);
236 pi
->signature
= CFDataCreateMutable(allocator
, 0);
238 versionNumber
= CFNumberCreateWithCFIndex(NULL
, pi
->version
);
240 pi
->description
= CFDictionaryCreateMutableForCFTypesWith(allocator
,
241 sVersionKey
, versionNumber
,
242 sPublicKeyKey
, publicBytes
,
243 sGestaltKey
, pi
->gestalt
,
247 description_modifier(pi
->description
);
250 pi
->id
= SOSCopyIDOfKey(publicKey
, error
);
251 CFReleaseNull(publicKey
);
253 require_quiet(pi
->id
, exit
);
255 // ================ V2 Additions Start
257 if(!SOSPeerInfoUpdateToV2(pi
, error
)) {
262 // V2DictionarySetValue handles NULL as remove
263 if (backup_key
!= NULL
) SOSPeerInfoV2DictionarySetValue(pi
, sBackupKeyKey
, backup_key
);
264 SOSPeerInfoV2DictionarySetValue(pi
, sDeviceID
, IDSID
);
265 SOSPeerInfoV2DictionarySetValue(pi
, sTransportType
, transportType
);
266 SOSPeerInfoV2DictionarySetValue(pi
, sPreferIDS
, preferIDS
);
267 SOSPeerInfoV2DictionarySetValue(pi
, sPreferIDSFragmentation
, preferFragmentation
);
269 SOSPeerInfoV2DictionarySetValue(pi
, sViewsKey
, enabledViews
);
271 // ================ V2 Additions End
273 if (!SOSPeerInfoSign(signingKey
, pi
, error
)) {
279 CFReleaseNull(versionNumber
);
280 CFReleaseNull(publicBytes
);
284 SOSPeerInfoRef
SOSPeerInfoCreate(CFAllocatorRef allocator
, CFDictionaryRef gestalt
, CFDataRef backup_key
, SecKeyRef signingKey
, CFErrorRef
* error
) {
285 return SOSPeerInfoCreate_Internal(allocator
, gestalt
, backup_key
, NULL
, NULL
, NULL
, NULL
, NULL
, signingKey
, error
, ^(CFMutableDictionaryRef description
) {});
288 SOSPeerInfoRef
SOSPeerInfoCreateWithTransportAndViews(CFAllocatorRef allocator
, CFDictionaryRef gestalt
, CFDataRef backup_key
,
289 CFStringRef IDSID
, CFStringRef transportType
, CFBooleanRef preferIDS
,
290 CFBooleanRef preferFragmentation
, CFSetRef enabledViews
,
291 SecKeyRef signingKey
, CFErrorRef
* error
)
293 return SOSPeerInfoCreate_Internal(allocator
, gestalt
, backup_key
, IDSID
, transportType
, preferIDS
, preferFragmentation
, enabledViews
, signingKey
, error
, ^(CFMutableDictionaryRef description
) {});
297 SOSPeerInfoRef
SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator
, CFDictionaryRef gestalt
, SecKeyRef signingKey
, CFErrorRef
* error
) {
298 return SOSPeerInfoCreate_Internal(allocator
, gestalt
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, signingKey
, error
, ^(CFMutableDictionaryRef description
) {
299 CFDictionarySetValue(description
, sCloudIdentityKey
, kCFBooleanTrue
);
305 SOSPeerInfoRef
SOSPeerInfoCreateCopy(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFErrorRef
* error
) {
306 if(!toCopy
) return NULL
;
307 SOSPeerInfoRef pi
= CFTypeAllocate(SOSPeerInfo
, struct __OpaqueSOSPeerInfo
, allocator
);
309 pi
->description
= CFDictionaryCreateMutableCopy(allocator
, 0, toCopy
->description
);
310 pi
->signature
= CFDataCreateCopy(allocator
, toCopy
->signature
);
312 pi
->gestalt
= CFDictionaryCreateCopy(allocator
, toCopy
->gestalt
);
313 pi
->id
= CFStringCreateCopy(allocator
, toCopy
->id
);
315 pi
->version
= toCopy
->version
;
316 if(!SOSPeerInfoVersionHasV2Data(pi
)) SOSPeerInfoExpandV2Data(pi
, error
);
322 bool SOSPeerInfoVersionIsCurrent(SOSPeerInfoRef pi
) {
323 return pi
->version
>= PEERINFO_CURRENT_VERSION
;
326 bool SOSPeerInfoVersionHasV2Data(SOSPeerInfoRef pi
) {
327 return pi
->version
>= kSOSPeerV2BaseVersion
;
330 SOSPeerInfoRef
SOSPeerInfoCreateCurrentCopy(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
,
331 CFStringRef IDSID
, CFStringRef transportType
, CFBooleanRef preferIDS
, CFBooleanRef preferFragmentation
,CFSetRef enabledViews
,
332 SecKeyRef signingKey
, CFErrorRef
* error
) {
334 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(allocator
, toCopy
, error
);
335 if(!SOSPeerInfoVersionHasV2Data(pi
)) SOSPeerInfoUpdateToV2(pi
, error
);
337 SOSPeerInfoSetSerialNumber(pi
);
340 SOSPeerInfoV2DictionarySetValue(pi
, sDeviceID
, IDSID
);
343 SOSPeerInfoV2DictionarySetValue(pi
, sTransportType
, transportType
);
346 SOSPeerInfoV2DictionarySetValue(pi
, sPreferIDS
, preferIDS
);
348 if (sPreferIDSFragmentation
) {
349 SOSPeerInfoV2DictionarySetValue(pi
, sPreferIDSFragmentation
, preferFragmentation
);
352 SOSPeerInfoV2DictionarySetValue(pi
, sViewsKey
, enabledViews
);
355 if(!SOSPeerInfoSign(signingKey
, pi
, error
)) {
363 static SOSPeerInfoRef
SOSPeerInfoCopyWithModification(CFAllocatorRef allocator
, SOSPeerInfoRef original
,
364 SecKeyRef signingKey
, CFErrorRef
*error
,
365 bool (^modification
)(SOSPeerInfoRef peerToModify
, CFErrorRef
*error
)) {
367 SOSPeerInfoRef result
= NULL
;
368 SOSPeerInfoRef copy
= SOSPeerInfoCreateCopy(allocator
, original
, error
);
370 require_quiet(modification(copy
, error
), fail
);
372 require_quiet(SOSPeerInfoSign(signingKey
, copy
, error
), fail
);
374 CFTransferRetained(result
, copy
);
382 SOSPeerInfoRef
SOSPeerInfoCopyWithGestaltUpdate(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFDictionaryRef gestalt
, SecKeyRef signingKey
, CFErrorRef
* error
) {
383 return SOSPeerInfoCopyWithModification(allocator
, toCopy
, signingKey
, error
,
384 ^bool(SOSPeerInfoRef peerToModify
, CFErrorRef
*error
) {
385 if(!gestalt
|| !peerToModify
) return false;
386 CFRetainAssign(peerToModify
->gestalt
, gestalt
);
387 CFDictionarySetValue(peerToModify
->description
, sGestaltKey
, peerToModify
->gestalt
);
394 SOSPeerInfoRef
SOSPeerInfoCopyWithBackupKeyUpdate(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFDataRef backupKey
, SecKeyRef signingKey
, CFErrorRef
*error
) {
395 return SOSPeerInfoCopyWithModification(allocator
, toCopy
, signingKey
, error
,
396 ^bool(SOSPeerInfoRef peerToModify
, CFErrorRef
*error
) {
397 if (backupKey
!= NULL
)
398 SOSPeerInfoV2DictionarySetValue(peerToModify
, sBackupKeyKey
, backupKey
);
400 SOSPeerInfoV2DictionaryRemoveValue(peerToModify
, sBackupKeyKey
);
405 static CFDictionaryRef
SOSPeerInfoUpdateAndCopyRecord(SOSPeerInfoRef peer
, CFStringRef dsid
, CFDictionaryRef escrowRecord
){
407 CFMutableDictionaryRef existingEscrowRecords
= SOSPeerInfoCopyEscrowRecord(peer
);
409 if(escrowRecord
== NULL
&& existingEscrowRecords
!= NULL
)
411 CFDictionaryRemoveValue(existingEscrowRecords
, dsid
);
412 return existingEscrowRecords
;
415 if(existingEscrowRecords
== NULL
)
416 existingEscrowRecords
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
418 CFDictionarySetValue(existingEscrowRecords
, dsid
, escrowRecord
);
420 return existingEscrowRecords
;
424 SOSPeerInfoRef
SOSPeerInfoCopyWithEscrowRecordUpdate(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFStringRef dsid
, CFDictionaryRef escrowRecord
, SecKeyRef signingKey
, CFErrorRef
*error
) {
425 return SOSPeerInfoCopyWithModification(allocator
, toCopy
, signingKey
, error
,
426 ^bool(SOSPeerInfoRef peerToModify
, CFErrorRef
*error
) {
428 CFDictionaryRef updatedEscrowRecords
= SOSPeerInfoUpdateAndCopyRecord(peerToModify
, dsid
, escrowRecord
);
429 SOSPeerInfoV2DictionarySetValue(peerToModify
, sEscrowRecord
, updatedEscrowRecords
);
430 CFReleaseNull(updatedEscrowRecords
);
435 SOSPeerInfoRef
SOSPeerInfoCopyWithReplacedEscrowRecords(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFDictionaryRef escrowRecords
, SecKeyRef signingKey
, CFErrorRef
*error
) {
436 return SOSPeerInfoCopyWithModification(allocator
, toCopy
, signingKey
, error
,
437 ^bool(SOSPeerInfoRef peerToModify
, CFErrorRef
*error
) {
438 if(escrowRecords
!= NULL
)
439 SOSPeerInfoV2DictionarySetValue(peerToModify
, sEscrowRecord
, escrowRecords
);
445 CFDataRef
SOSPeerInfoCopyBackupKey(SOSPeerInfoRef peer
) {
446 return SOSPeerInfoV2DictionaryCopyData(peer
, sBackupKeyKey
);
449 CFMutableDictionaryRef
SOSPeerInfoCopyEscrowRecord(SOSPeerInfoRef peer
){
450 return SOSPeerInfoV2DictionaryCopyDictionary(peer
, sEscrowRecord
);
453 bool SOSPeerInfoHasBackupKey(SOSPeerInfoRef peer
) {
454 CFDataRef bk
= SOSPeerInfoCopyBackupKey(peer
);
455 bool success
= bk
!= NULL
;
460 SOSPeerInfoRef
SOSPeerInfoCopyWithViewsChange(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
,
461 SOSViewActionCode action
, CFStringRef viewname
, SOSViewResultCode
*retval
,
462 SecKeyRef signingKey
, CFErrorRef
* error
) {
463 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(allocator
, toCopy
, error
);
464 if(action
== kSOSCCViewEnable
) {
465 *retval
= SOSViewsEnable(pi
, viewname
, error
);
466 require((kSOSCCViewMember
== *retval
), exit
);
467 } else if(action
== kSOSCCViewDisable
) {
468 *retval
= SOSViewsDisable(pi
, viewname
, error
);
469 require((kSOSCCViewNotMember
== *retval
), exit
);
472 require_action_quiet(SOSPeerInfoSign(signingKey
, pi
, error
), exit
, *retval
= kSOSCCGeneralViewError
);
481 CFStringRef sPingKey
= CFSTR("Ping");
483 SOSPeerInfoRef
SOSPeerInfoCopyWithPing(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, SecKeyRef signingKey
, CFErrorRef
* error
) {
484 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(allocator
, toCopy
, error
);
485 CFDataRef ping
= CFDataCreateWithRandomBytes(8);
486 SOSPeerInfoV2DictionarySetValue(pi
, sPingKey
, ping
);
487 SecKeyRef pub_key
= SOSPeerInfoCopyPubKey(pi
, error
);
488 require_quiet(pub_key
, exit
);
489 pi
->id
= SOSCopyIDOfKey(pub_key
, error
);
490 require_quiet(pi
->id
, exit
);
491 require_action_quiet(SOSPeerInfoSign(signingKey
, pi
, error
), exit
, CFReleaseNull(pi
));
494 CFReleaseNull(pub_key
);
499 SOSViewResultCode
SOSPeerInfoViewStatus(SOSPeerInfoRef pi
, CFStringRef view
, CFErrorRef
*error
) {
500 return SOSViewsQuery(pi
, view
, error
);
504 SOSPeerInfoRef
SOSPeerInfoCopyWithSecurityPropertyChange(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
,
505 SOSSecurityPropertyActionCode action
, CFStringRef property
, SOSSecurityPropertyResultCode
*retval
,
506 SecKeyRef signingKey
, CFErrorRef
* error
) {
507 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(allocator
, toCopy
, error
);
508 if(action
== kSOSCCSecurityPropertyEnable
) {
509 *retval
= SOSSecurityPropertyEnable(pi
, property
, error
);
510 require((kSOSCCSecurityPropertyValid
== *retval
), exit
);
511 } else if(action
== kSOSCCSecurityPropertyDisable
) {
512 *retval
= SOSSecurityPropertyDisable(pi
, property
, error
);
513 require((kSOSCCSecurityPropertyNotValid
== *retval
), exit
);
516 require_action_quiet(SOSPeerInfoSign(signingKey
, pi
, error
), exit
, *retval
= kSOSCCGeneralViewError
);
524 SOSViewResultCode
SOSPeerInfoSecurityPropertyStatus(SOSPeerInfoRef pi
, CFStringRef property
, CFErrorRef
*error
) {
525 return SOSSecurityPropertyQuery(pi
, property
, error
);
530 static void SOSPeerInfoDestroy(CFTypeRef aObj
) {
531 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) aObj
;
534 CFReleaseNull(pi
->description
);
535 CFReleaseNull(pi
->signature
);
536 CFReleaseNull(pi
->gestalt
);
537 CFReleaseNull(pi
->id
);
538 if(pi
->v2Dictionary
) CFReleaseNull(pi
->v2Dictionary
);
539 if(pi
->secproperties
) CFReleaseNull(pi
->secproperties
);
542 static Boolean
SOSPeerInfoCompare(CFTypeRef lhs
, CFTypeRef rhs
) {
543 SOSPeerInfoRef lpeer
= (SOSPeerInfoRef
) lhs
;
544 SOSPeerInfoRef rpeer
= (SOSPeerInfoRef
) rhs
;
545 if(!lpeer
|| !rpeer
) return false;
546 return CFEqualSafe(lpeer
->description
, rpeer
->description
) && CFEqualSafe(lpeer
->signature
, rpeer
->signature
);
550 CFComparisonResult
SOSPeerInfoCompareByID(const void *val1
, const void *val2
, void *context
) {
551 // The code below is necessary but not sufficient; not returning a CFComparisonResult
552 // It probably is OK to say that a NULL is < <non-NULL>
553 if (val1
== NULL
|| val2
== NULL
) {
554 ptrdiff_t dv
= val1
- val2
;
555 return dv
< 0 ? kCFCompareLessThan
: dv
== 0 ? kCFCompareEqualTo
: kCFCompareGreaterThan
;
558 CFStringRef v1
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
) val1
);
559 CFStringRef v2
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
) val2
);
560 if (v1
== NULL
|| v2
== NULL
) {
561 ptrdiff_t dv
= (const void *)v1
- (const void *)v2
;
562 return dv
< 0 ? kCFCompareLessThan
: dv
== 0 ? kCFCompareEqualTo
: kCFCompareGreaterThan
;
565 return CFStringCompare(v1
, v2
, 0);
568 static CFHashCode
SOSPeerInfoHash(CFTypeRef cf
) {
569 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) cf
;
571 return CFHash(peer
->description
) ^ CFHash(peer
->signature
);
574 static CFStringRef
copyDescriptionWithFormatOptions(CFTypeRef aObj
, CFDictionaryRef formatOptions
){
576 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) aObj
;
577 CFStringRef description
= NULL
;
580 // Get the format options we care about:
581 CFNumberRef peerIDLengthNumber
= formatOptions
? CFDictionaryGetValue(formatOptions
, peerIDLengthKey
) : NULL
;
582 bool useSyncDFormat
= formatOptions
&& CFDictionaryContainsKey(formatOptions
, CFSTR("SyncD"));
584 // Calculate the truncated length
585 CFIndex truncatedLength
= CFStringGetLength(pi
->id
);
586 if (isNumber(peerIDLengthNumber
)) {
587 CFIndex peerIDMaximumLength
= truncatedLength
;
588 CFNumberGetValue(peerIDLengthNumber
, kCFNumberCFIndexType
, &peerIDMaximumLength
);
589 truncatedLength
= MIN(truncatedLength
, peerIDMaximumLength
);
591 CFStringRef displayPeerID
= CFStringCreateWithSubstring(kCFAllocatorDefault
, pi
->id
, CFRangeMake(0, truncatedLength
));
593 CFStringRef objectPrefix
= useSyncDFormat
? CFSTR("PI") :
594 CFStringCreateWithFormat(kCFAllocatorDefault
, formatOptions
, CFSTR("PeerInfo@%p"), pi
);
596 CFStringRef osVersion
= CFDictionaryGetValue(pi
->gestalt
, kPIOSVersionKey
);
598 CFStringRef transportType
= SOSPeerInfoV2DictionaryCopyString(pi
, sTransportType
);
599 CFStringRef deviceID
= SOSPeerInfoV2DictionaryCopyString(pi
, sDeviceID
);
601 description
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<%@: %s%s '%@' %@ %@ %@ %@ %@ %ld>"),
603 SOSPeerInfoIsRetirementTicket(pi
) ? "R" : "-",
604 SOSPeerInfoHasBackupKey(pi
) ? "B" : "-",
605 CFDictionaryGetValue(pi
->gestalt
, kPIUserDefinedDeviceNameKey
),
606 CFDictionaryGetValue(pi
->gestalt
, kPIDeviceModelNameKey
),
607 osVersion
? osVersion
: CFSTR("????"),
608 transportType
? transportType
: CFSTR("KVS"),
609 deviceID
? deviceID
: CFSTR(""),
613 CFReleaseNull(transportType
);
614 CFReleaseNull(deviceID
);
616 CFReleaseNull(objectPrefix
);
617 CFReleaseNull(displayPeerID
);
622 static CFStringRef
SOSPeerInfoCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOptions
) {
624 CFStringRef description
= NULL
;
626 description
= copyDescriptionWithFormatOptions(aObj
, formatOptions
);
631 static char boolToChars(bool val
, char truechar
, char falsechar
) {
632 return val
? truechar
: falsechar
;
635 static CFStringRef
isKnown(CFStringRef ref
) {
636 return ref
? ref
: CFSTR("Unknown ");
639 void SOSPeerInfoLogState(char *category
, SOSPeerInfoRef pi
, SecKeyRef pubKey
, CFStringRef myPID
, char sigchr
) {
641 bool appValid
= SOSPeerInfoApplicationVerify(pi
, pubKey
, NULL
);
642 bool retired
= SOSPeerInfoIsRetirementTicket(pi
);
643 bool selfValid
= SOSPeerInfoVerify(pi
, NULL
);
644 bool backingUp
= SOSPeerInfoHasBackupKey(pi
);
645 bool isMe
= CFEqualSafe(SOSPeerInfoGetPeerID(pi
), myPID
) == true;
646 bool isKVS
= SOSPeerInfoKVSOnly(pi
);
647 CFStringRef osVersion
= CFDictionaryGetValue(pi
->gestalt
, kPIOSVersionKey
);
648 CFStringRef tmp
= SOSPeerInfoV2DictionaryCopyString(pi
, sDeviceID
);
649 CFStringRef deviceID
= CFStringCreateTruncatedCopy(tmp
, 8);
651 CFStringRef serialNum
= SOSPeerInfoCopySerialNumber(pi
);
652 CFStringRef peerID
= CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi
), 8);
654 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
)),
655 boolToChars(isMe
, 'M', 'm'),
656 boolToChars(appValid
, 'A', 'a'),
657 boolToChars(selfValid
, 'S', 's'),
658 boolToChars(retired
, 'R', 'r'),
659 boolToChars(backingUp
, 'B', 'b'),
660 boolToChars(isKVS
, 'K', 'I'),
662 isKnown(SOSPeerInfoGetPeerDeviceType(pi
)), isKnown(peerID
),
663 isKnown(osVersion
), isKnown(deviceID
), isKnown(serialNum
));
665 CFReleaseNull(peerID
);
666 CFReleaseNull(deviceID
);
667 CFReleaseNull(serialNum
);
670 CFDictionaryRef
SOSPeerInfoCopyPeerGestalt(SOSPeerInfoRef pi
) {
671 CFRetain(pi
->gestalt
);
675 CFDictionaryRef
SOSPeerGetGestalt(SOSPeerInfoRef pi
){
679 CFStringRef
SOSPeerInfoGetPeerName(SOSPeerInfoRef peer
) {
680 return SOSPeerInfoLookupGestaltValue(peer
, kPIUserDefinedDeviceNameKey
);
683 CFStringRef
SOSPeerInfoGetPeerDeviceType(SOSPeerInfoRef peer
) {
684 return SOSPeerInfoLookupGestaltValue(peer
, kPIDeviceModelNameKey
);
687 CFIndex
SOSPeerInfoGetPeerProtocolVersion(SOSPeerInfoRef peer
) {
688 CFIndex version
= PEERINFO_CURRENT_VERSION
;
689 CFTypeRef val
= SOSPeerInfoLookupGestaltValue(peer
, kPIMessageProtocolVersionKey
);
690 if (val
&& CFGetTypeID(val
) == CFNumberGetTypeID())
691 CFNumberGetValue(val
, kCFNumberCFIndexType
, &version
);
695 CFTypeRef
SOSPeerInfoLookupGestaltValue(SOSPeerInfoRef pi
, CFStringRef key
) {
696 return CFDictionaryGetValue(pi
->gestalt
, key
);
699 CFStringRef
SOSPeerInfoGetPeerID(SOSPeerInfoRef pi
) {
700 return pi
? pi
->id
: NULL
;
703 bool SOSPeerInfoPeerIDEqual(SOSPeerInfoRef pi
, CFStringRef myPeerID
) {
704 return CFEqualSafe(myPeerID
, SOSPeerInfoGetPeerID(pi
));
707 CFIndex
SOSPeerInfoGetVersion(SOSPeerInfoRef pi
) {
711 bool SOSPeerInfoUpdateDigestWithPublicKeyBytes(SOSPeerInfoRef peer
, const struct ccdigest_info
*di
,
712 ccdigest_ctx_t ctx
, CFErrorRef
*error
) {
713 CFDataRef pubKeyBytes
= CFDictionaryGetValue(peer
->description
, sPublicKeyKey
);
716 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, NULL
, error
, NULL
, CFSTR("Digest failed – no public key"));
720 ccdigest_update(di
, ctx
, CFDataGetLength(pubKeyBytes
), CFDataGetBytePtr(pubKeyBytes
));
725 bool SOSPeerInfoUpdateDigestWithDescription(SOSPeerInfoRef peer
, const struct ccdigest_info
*di
,
726 ccdigest_ctx_t ctx
, CFErrorRef
*error
) {
727 if(SOSPeerInfoVersionHasV2Data(peer
)) SOSPeerInfoPackV2Data(peer
);
728 size_t description_size
= der_sizeof_plist(peer
->description
, error
);
729 uint8_t data_begin
[description_size
];
730 uint8_t *data_end
= data_begin
+ description_size
;
731 uint8_t *encoded
= der_encode_plist(peer
->description
, error
, data_begin
, data_end
);
734 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, NULL
, error
, NULL
, CFSTR("Description encode failed"));
738 ccdigest_update(di
, ctx
, description_size
, data_begin
);
744 static CFDataRef
sosCreateDate() {
745 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
746 size_t bufsiz
= der_sizeof_date(now
, NULL
);
748 der_encode_date(now
, NULL
, buf
, buf
+bufsiz
);
750 return CFDataCreate(NULL
, buf
, bufsiz
);
753 static CFDateRef
sosCreateCFDate(CFDataRef sosdate
) {
755 der_decode_date(NULL
, 0, &date
, NULL
, CFDataGetBytePtr(sosdate
),
756 CFDataGetBytePtr(sosdate
) + CFDataGetLength(sosdate
));
760 static bool sospeer_application_hash(SOSPeerInfoRef pi
, const struct ccdigest_info
*di
, uint8_t *hbuf
) {
761 CFDataRef appdate
= asData(CFDictionaryGetValue(pi
->description
, sApplicationDate
), NULL
);
762 if(!appdate
) return false;
763 ccdigest_di_decl(di
, ctx
);
764 ccdigest_init(di
, ctx
);
765 ccdigest_update(di
, ctx
, CFDataGetLength(appdate
), CFDataGetBytePtr(appdate
));
766 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes(pi
, di
, ctx
, NULL
)) return false;
767 ccdigest_final(di
, ctx
, hbuf
);
771 SOSPeerInfoRef
SOSPeerInfoCopyAsApplication(SOSPeerInfoRef original
, SecKeyRef userkey
, SecKeyRef peerkey
, CFErrorRef
*error
) {
772 SOSPeerInfoRef result
= NULL
;
773 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(kCFAllocatorDefault
, original
, error
);
775 const struct ccdigest_info
*di
= ccsha256_di();
776 uint8_t hbuf
[di
->output_size
];
777 CFDataRef usersig
= NULL
;
779 CFDataRef creationDate
= sosCreateDate();
780 CFDictionarySetValue(pi
->description
, sApplicationDate
, creationDate
);
781 CFReleaseNull(creationDate
);
783 // Create User Application Signature
784 require_action_quiet(sospeer_application_hash(pi
, di
, hbuf
), fail
,
785 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to create hash for peer applicant"), NULL
, error
));
787 usersig
= sosSignHash(userkey
, di
, hbuf
);
788 require_action_quiet(usersig
, fail
,
789 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to sign public key hash for peer"), NULL
, error
));
791 CFDictionarySetValue(pi
->description
, sApplicationUsig
, usersig
);
793 require_quiet(SOSPeerInfoSign(peerkey
, pi
, error
), fail
);
799 CFReleaseNull(usersig
);
804 bool SOSPeerInfoApplicationVerify(SOSPeerInfoRef pi
, SecKeyRef userkey
, CFErrorRef
*error
) {
805 const struct ccdigest_info
*di
= ccsha256_di();
806 uint8_t hbuf
[di
->output_size
];
809 CFDataRef usig
= CFDictionaryGetValue(pi
->description
, sApplicationUsig
);
810 require_action_quiet(usig
, exit
,
811 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Peer is not an applicant"), NULL
, error
));
812 // Verify User Application Signature
813 require_action_quiet(sospeer_application_hash(pi
, di
, hbuf
), exit
,
814 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to create hash for peer applicant"), NULL
, error
));
815 require_action_quiet(sosVerifyHash(userkey
, di
, hbuf
, usig
), exit
,
816 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("user signature of public key hash fails to verify"), NULL
, error
));
818 result
= SOSPeerInfoVerify(pi
, error
);
825 static CF_RETURNS_RETAINED CFDateRef
sosPeerInfoGetDate(SOSPeerInfoRef pi
, CFStringRef entry
) {
827 CFDataRef sosdate
= CFDictionaryGetValue(pi
->description
, entry
);
828 if(!sosdate
) return NULL
;
829 CFDateRef date
= sosCreateCFDate(sosdate
);
834 CF_RETURNS_RETAINED CFDateRef
SOSPeerInfoGetApplicationDate(SOSPeerInfoRef pi
) {
835 return sosPeerInfoGetDate(pi
, sApplicationDate
);
838 CF_RETURNS_RETAINED CFDateRef
SOSPeerInfoGetRetirementDate(SOSPeerInfoRef pi
) {
839 return sosPeerInfoGetDate(pi
, sRetirementDate
);
848 CFStringRef
SOSPeerGestaltGetName(CFDictionaryRef gestalt
) {
849 CFStringRef name
= SOSPeerGestaltGetAnswer(gestalt
, kPIUserDefinedDeviceNameKey
);
850 return isString(name
) ? name
: NULL
;
853 CFTypeRef
SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt
, CFStringRef question
) {
854 return gestalt
? CFDictionaryGetValue(gestalt
, question
) : NULL
;
862 SOSPeerInfoRef
SOSPeerInfoCreateRetirementTicket(CFAllocatorRef allocator
, SecKeyRef privKey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
864 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(allocator
, peer
, error
);
868 // Fill out Resignation Date
869 CFDataRef resignationDate
= sosCreateDate();
870 CFDictionaryAddValue(pi
->description
, sRetirementDate
, resignationDate
);
871 CFReleaseNull(resignationDate
);
873 require(SOSPeerInfoSign(privKey
, pi
, error
), fail
);
882 CFStringRef
SOSPeerInfoInspectRetirementTicket(SOSPeerInfoRef pi
, CFErrorRef
*error
) {
883 CFStringRef retval
= NULL
;
884 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
885 CFDateRef retirement
= NULL
;
887 require_quiet(SOSPeerInfoVerify(pi
, error
), err
);
889 retirement
= asDate(sosCreateCFDate(CFDictionaryGetValue(pi
->description
, sRetirementDate
)), error
);
891 require_action_quiet(retirement
, err
,
892 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Peer is not retired"), NULL
, error
));
894 require_action_quiet(CFDateCompare(now
, retirement
, NULL
) == kCFCompareGreaterThan
, err
,
895 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Retirement date is after current date"), NULL
, error
));
897 retval
= SOSPeerInfoGetPeerID(pi
);
901 CFReleaseNull(retirement
);
905 bool SOSPeerInfoRetireRetirementTicket(size_t max_seconds
, SOSPeerInfoRef pi
) {
906 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
907 CFDateRef retirement
= sosCreateCFDate(CFDictionaryGetValue(pi
->description
, sRetirementDate
));
908 CFTimeInterval timediff
= CFDateGetTimeIntervalSinceDate(now
, retirement
); // diff in seconds
910 CFReleaseNull(retirement
);
911 if(timediff
> (max_seconds
)) return true;
915 bool SOSPeerInfoIsRetirementTicket(SOSPeerInfoRef pi
) {
916 CFDataRef flag
= CFDictionaryGetValue(pi
->description
, sRetirementDate
);
920 bool SOSPeerInfoIsCloudIdentity(SOSPeerInfoRef pi
) {
921 CFTypeRef value
= CFDictionaryGetValue(pi
->description
, sCloudIdentityKey
);
922 return CFEqualSafe(value
, kCFBooleanTrue
);
925 SOSPeerInfoRef
SOSPeerInfoUpgradeSignatures(CFAllocatorRef allocator
, SecKeyRef privKey
, SecKeyRef peerKey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
926 SecKeyRef pubKey
= SecKeyCreatePublicFromPrivate(privKey
);
927 SOSPeerInfoRef retval
= NULL
;
929 retval
= SOSPeerInfoCopyAsApplication(peer
, privKey
, peerKey
, error
);
930 CFReleaseNull(pubKey
);
934 CFBooleanRef
SOSPeerInfoCopyIDSPreference(SOSPeerInfoRef peer
){
935 CFBooleanRef preference
= (CFBooleanRef
)SOSPeerInfoV2DictionaryCopyBoolean(peer
, sPreferIDS
);
936 return (preference
? preference
: CFRetain(kCFBooleanFalse
));
940 SOSPeerInfoRef
SOSPeerInfoSetIDSPreference(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFBooleanRef preference
, SecKeyRef signingKey
, CFErrorRef
*error
){
941 return SOSPeerInfoCopyWithModification(allocator
, toCopy
, signingKey
, error
,
942 ^bool(SOSPeerInfoRef peerToModify
, CFErrorRef
*error
) {
943 SOSPeerInfoV2DictionarySetValue(peerToModify
, sPreferIDS
, preference
);
948 CFBooleanRef
SOSPeerInfoCopyIDSFragmentationPreference(SOSPeerInfoRef peer
){
949 CFBooleanRef preference
= (CFBooleanRef
)SOSPeerInfoV2DictionaryCopyBoolean(peer
, sPreferIDSFragmentation
);
950 return (preference
? preference
: CFRetain(kCFBooleanFalse
));
953 SOSPeerInfoRef
SOSPeerInfoSetIDSFragmentationPreference(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFBooleanRef preference
, SecKeyRef signingKey
, CFErrorRef
*error
){
954 return SOSPeerInfoCopyWithModification(allocator
, toCopy
, signingKey
, error
,
955 ^bool(SOSPeerInfoRef peerToModify
, CFErrorRef
*error
) {
956 SOSPeerInfoV2DictionarySetValue(peerToModify
, sPreferIDSFragmentation
, preference
);
962 CFStringRef
SOSPeerInfoCopyTransportType(SOSPeerInfoRef peer
){
963 CFStringRef transportType
= (CFStringRef
)SOSPeerInfoV2DictionaryCopyString(peer
, sTransportType
);
964 return (transportType
? transportType
: CFRetain(SOSTransportMessageTypeKVS
));
967 SOSPeerInfoRef
SOSPeerInfoSetTransportType(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFStringRef transportType
, SecKeyRef signingKey
, CFErrorRef
*error
){
969 return SOSPeerInfoCopyWithModification(allocator
, toCopy
, signingKey
, error
,
970 ^bool(SOSPeerInfoRef peerToModify
, CFErrorRef
*error
) {
971 SOSPeerInfoV2DictionarySetValue(peerToModify
, sTransportType
, transportType
);
976 bool SOSPeerInfoKVSOnly(SOSPeerInfoRef pi
) {
977 CFStringRef transportType
= SOSPeerInfoCopyTransportType(pi
);
978 bool retval
= CFEqualSafe(transportType
, SOSTransportMessageTypeKVS
);
979 CFReleaseNull(transportType
);
983 bool SOSPeerInfoHasDeviceID(SOSPeerInfoRef peer
) {
984 return SOSPeerInfoV2DictionaryHasString(peer
, sDeviceID
);
987 CFStringRef
SOSPeerInfoCopyDeviceID(SOSPeerInfoRef peer
){
988 return (CFStringRef
)SOSPeerInfoV2DictionaryCopyString(peer
, sDeviceID
);
991 SOSPeerInfoRef
SOSPeerInfoSetDeviceID(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFStringRef IDS
, SecKeyRef signingKey
, CFErrorRef
*error
){
993 return SOSPeerInfoCopyWithModification(allocator
, toCopy
, signingKey
, error
,
994 ^bool(SOSPeerInfoRef peerToModify
, CFErrorRef
*error
) {
995 SOSPeerInfoV2DictionarySetValue(peerToModify
, sDeviceID
, IDS
);
999 bool SOSPeerInfoShouldUseIDSTransport(SOSPeerInfoRef myPeer
, SOSPeerInfoRef theirPeer
){
1001 CFStringRef myTransportType
= SOSPeerInfoCopyTransportType(myPeer
);
1002 CFStringRef theirTransportType
= SOSPeerInfoCopyTransportType(theirPeer
);
1004 bool success
= false;
1006 //sync only if we are the new IDS fragmented system
1007 if((CFStringCompare(myTransportType
, SOSTransportMessageTypeIDSV2
, 0) == 0 && CFStringCompare(theirTransportType
, SOSTransportMessageTypeIDSV2
, 0) == 0))
1012 CFReleaseSafe(myTransportType
);
1013 CFReleaseSafe(theirTransportType
);
1019 bool SOSPeerInfoShouldUseIDSMessageFragmentation(SOSPeerInfoRef myPeer
, SOSPeerInfoRef theirPeer
){
1021 bool success
= false;
1023 CFBooleanRef myPreference
= SOSPeerInfoCopyIDSFragmentationPreference(myPeer
);
1025 CFBooleanRef theirPreference
= SOSPeerInfoCopyIDSFragmentationPreference(theirPeer
);
1026 secerror("mypreference: %@, theirpreference: %@", myPreference
, theirPreference
);
1027 if((myPreference
== kCFBooleanTrue
&& theirPreference
== kCFBooleanTrue
))
1030 CFReleaseNull(myPreference
);
1031 CFReleaseNull(theirPreference
);