2 * Created by Michael Brouwer on 6/22/12.
3 * Copyright 2012 Apple Inc. All Rights Reserved.
7 * SOSCircle.c - Implementation of the secure object syncing transport
10 #include <AssertMacros.h>
12 #include <CoreFoundation/CFArray.h>
13 #include <SecureObjectSync/SOSCircle.h>
14 #include <SecureObjectSync/SOSCloudCircleInternal.h>
15 #include <SecureObjectSync/SOSInternal.h>
16 #include <SecureObjectSync/SOSEngine.h>
17 #include <SecureObjectSync/SOSPeer.h>
18 #include <CoreFoundation/CoreFoundation.h>
19 #include <Security/SecFramework.h>
21 #include <Security/SecKey.h>
22 #include <Security/SecKeyPriv.h>
24 #include <utilities/SecCFWrappers.h>
25 //#include "ckdUtilities.h"
27 #include <utilities/der_plist.h>
28 #include <utilities/der_plist_internal.h>
30 #include <corecrypto/ccder.h>
31 #include <corecrypto/ccdigest.h>
32 #include <corecrypto/ccsha2.h>
38 kOnlyCompatibleVersion
= 1, // Sometime in the future this name will be improved to reflect history.
40 kAlwaysIncompatibleVersion
= UINT64_MAX
,
43 struct __OpaqueSOSCircle
{
47 CFNumberRef generation
;
48 CFMutableArrayRef peers
;
49 CFMutableArrayRef applicants
;
50 CFMutableArrayRef rejected_applicants
;
52 CFMutableDictionaryRef signatures
;
55 CFGiblisWithCompareFor(SOSCircle
);
57 // Move the next 2 lines to SOSPeer if we need it.
58 static void SOSPeerRelease(CFAllocatorRef allocator
, const void *value
) {
59 SOSPeerDispose((SOSPeerRef
)value
);
62 static const CFDictionaryValueCallBacks dispose_peer_callbacks
= { .release
= SOSPeerRelease
};
64 SOSCircleRef
SOSCircleCreate(CFAllocatorRef allocator
, CFStringRef name
, CFErrorRef
*error
) {
65 SOSCircleRef c
= CFTypeAllocate(SOSCircle
, struct __OpaqueSOSCircle
, allocator
);
70 c
->name
= CFStringCreateCopy(allocator
, name
);
71 c
->generation
= CFNumberCreate(allocator
, kCFNumberSInt64Type
, &gen
);
72 c
->peers
= CFArrayCreateMutableForCFTypes(allocator
);
73 c
->applicants
= CFArrayCreateMutableForCFTypes(allocator
);
74 c
->rejected_applicants
= CFArrayCreateMutableForCFTypes(allocator
);
75 c
->signatures
= CFDictionaryCreateMutableForCFTypes(allocator
);
80 static CFNumberRef
SOSCircleGenerationCopy(CFNumberRef generation
) {
82 CFAllocatorRef allocator
= CFGetAllocator(generation
);
83 CFNumberGetValue(generation
, kCFNumberSInt64Type
, &value
);
84 return CFNumberCreate(allocator
, kCFNumberSInt64Type
, &value
);
87 SOSCircleRef
SOSCircleCopyCircle(CFAllocatorRef allocator
, SOSCircleRef otherCircle
, CFErrorRef
*error
)
89 SOSCircleRef c
= CFTypeAllocate(SOSCircle
, struct __OpaqueSOSCircle
, allocator
);
92 c
->name
= CFStringCreateCopy(allocator
, otherCircle
->name
);
93 c
->generation
= SOSCircleGenerationCopy(otherCircle
->generation
);
94 c
->peers
= CFArrayCreateMutableCopy(allocator
, 0, otherCircle
->peers
);
95 c
->applicants
= CFArrayCreateMutableCopy(allocator
, 0, otherCircle
->applicants
);
96 c
->rejected_applicants
= CFArrayCreateMutableCopy(allocator
, 0, otherCircle
->rejected_applicants
);
97 c
->signatures
= CFDictionaryCreateMutableCopy(allocator
, 0, otherCircle
->signatures
);
103 void SOSCircleAssertStable(SOSCircleRef circle
)
106 assert(circle
->name
);
107 assert(circle
->generation
);
108 assert(circle
->peers
);
109 assert(circle
->applicants
);
110 assert(circle
->rejected_applicants
);
111 assert(circle
->signatures
);
115 SOSCircleRef
SOSCircleConvertAndAssertStable(CFTypeRef circleAsType
)
117 if (CFGetTypeID(circleAsType
) != SOSCircleGetTypeID())
120 SOSCircleRef circle
= (SOSCircleRef
) circleAsType
;
122 SOSCircleAssertStable(circle
);
128 static Boolean
SOSCircleCompare(CFTypeRef lhs
, CFTypeRef rhs
) {
129 if (CFGetTypeID(lhs
) != SOSCircleGetTypeID()
130 || CFGetTypeID(rhs
) != SOSCircleGetTypeID())
133 SOSCircleRef left
= SOSCircleConvertAndAssertStable(lhs
);
134 SOSCircleRef right
= SOSCircleConvertAndAssertStable(rhs
);
136 // TODO: we should be doing set equality for peers and applicants.
137 return NULL
!= left
&& NULL
!= right
138 && CFEqual(left
->generation
, right
->generation
)
139 && CFEqual(left
->peers
, right
->peers
)
140 && CFEqual(left
->applicants
, right
->applicants
)
141 && CFEqual(left
->rejected_applicants
, right
->rejected_applicants
)
142 && CFEqual(left
->signatures
, right
->signatures
);
146 static bool SOSCircleDigestArray(const struct ccdigest_info
*di
, CFMutableArrayRef array
, void *hash_result
, CFErrorRef
*error
)
148 __block
bool success
= true;
149 ccdigest_di_decl(di
, array_digest
);
150 const void * a_digest
= array_digest
;
152 ccdigest_init(di
, array_digest
);
153 CFArraySortValues(array
, CFRangeMake(0, CFArrayGetCount(array
)), SOSPeerInfoCompareByID
, SOSPeerCmpPubKeyHash
);
154 CFArrayForEach(array
, ^(const void *peer
) {
155 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes((SOSPeerInfoRef
)peer
, di
, a_digest
, error
))
158 ccdigest_final(di
, array_digest
, hash_result
);
163 static bool SOSCircleHash(const struct ccdigest_info
*di
, SOSCircleRef circle
, void *hash_result
, CFErrorRef
*error
) {
164 ccdigest_di_decl(di
, circle_digest
);
165 ccdigest_init(di
, circle_digest
);
166 int64_t gen
= SOSCircleGetGenerationSint(circle
);
167 ccdigest_update(di
, circle_digest
, sizeof(gen
), &gen
);
169 SOSCircleDigestArray(di
, circle
->peers
, hash_result
, error
);
170 ccdigest_update(di
, circle_digest
, di
->output_size
, hash_result
);
171 ccdigest_final(di
, circle_digest
, hash_result
);
175 static bool SOSCircleSetSignature(SOSCircleRef circle
, SecKeyRef pubkey
, CFDataRef signature
, CFErrorRef
*error
) {
178 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubkey
, error
);
179 require_quiet(pubKeyID
, fail
);
180 CFDictionarySetValue(circle
->signatures
, pubKeyID
, signature
);
184 CFReleaseSafe(pubKeyID
);
188 static bool SOSCircleRemoveSignatures(SOSCircleRef circle
, CFErrorRef
*error
) {
189 CFDictionaryRemoveAllValues(circle
->signatures
);
193 static CFDataRef
SOSCircleGetSignature(SOSCircleRef circle
, SecKeyRef pubkey
, CFErrorRef
*error
) {
194 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubkey
, error
);
195 CFDataRef result
= NULL
;
196 require_quiet(pubKeyID
, fail
);
198 CFTypeRef value
= (CFDataRef
)CFDictionaryGetValue(circle
->signatures
, pubKeyID
);
200 if (isData(value
)) result
= (CFDataRef
) value
;
203 CFReleaseSafe(pubKeyID
);
207 bool SOSCircleSign(SOSCircleRef circle
, SecKeyRef privKey
, CFErrorRef
*error
) {
208 if (!privKey
) return false; // Really assertion but not always true for now.
209 CFAllocatorRef allocator
= CFGetAllocator(circle
);
211 size_t tmplen
= 4096;
212 const struct ccdigest_info
*di
= ccsha256_di();
213 uint8_t hash_result
[di
->output_size
];
215 SOSCircleHash(di
, circle
, hash_result
, error
);
216 OSStatus stat
= SecKeyRawSign(privKey
, kSecPaddingNone
, hash_result
, di
->output_size
, tmp
, &tmplen
);
218 // TODO - Create a CFErrorRef;
219 secerror("Bad Circle SecKeyRawSign, stat: %ld", (long)stat
);
220 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Circle SecKeyRawSign"), (error
!= NULL
) ? *error
: NULL
, error
);
223 CFDataRef signature
= CFDataCreate(allocator
, tmp
, tmplen
);
224 SecKeyRef publicKey
= SecKeyCreatePublicFromPrivate(privKey
);
225 SOSCircleSetSignature(circle
, publicKey
, signature
, error
);
226 CFReleaseNull(publicKey
);
227 CFRelease(signature
);
231 bool SOSCircleVerifySignatureExists(SOSCircleRef circle
, SecKeyRef pubKey
, CFErrorRef
*error
) {
234 secerror("SOSCircleVerifySignatureExists no pubKey");
235 SOSCreateError(kSOSErrorBadFormat
, CFSTR("SOSCircleVerifySignatureExists no pubKey"), (error
!= NULL
) ? *error
: NULL
, error
);
238 CFDataRef signature
= SOSCircleGetSignature(circle
, pubKey
, error
);
239 return NULL
!= signature
;
242 bool SOSCircleVerify(SOSCircleRef circle
, SecKeyRef pubKey
, CFErrorRef
*error
) {
243 const struct ccdigest_info
*di
= ccsha256_di();
244 uint8_t hash_result
[di
->output_size
];
246 SOSCircleHash(di
, circle
, hash_result
, error
);
248 CFDataRef signature
= SOSCircleGetSignature(circle
, pubKey
, error
);
249 if(!signature
) return false;
251 return SecKeyRawVerify(pubKey
, kSecPaddingNone
, hash_result
, di
->output_size
,
252 CFDataGetBytePtr(signature
), CFDataGetLength(signature
)) == errSecSuccess
;
255 bool SOSCircleVerifyPeerSigned(SOSCircleRef circle
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
256 SecKeyRef pub_key
= SOSPeerInfoCopyPubKey(peer
);
257 bool result
= SOSCircleVerify(circle
, pub_key
, error
);
258 CFReleaseSafe(pub_key
);
263 static CFIndex
CFArrayRemoveAllPassing(CFMutableArrayRef array
, bool (^test
)(const void *) ){
264 CFIndex numberRemoved
= 0;
266 CFIndex position
= 0;
267 while (position
< CFArrayGetCount(array
) && !test(CFArrayGetValueAtIndex(array
, position
)))
270 while (position
< CFArrayGetCount(array
)) {
271 CFArrayRemoveValueAtIndex(array
, position
);
273 while (position
< CFArrayGetCount(array
) && !test(CFArrayGetValueAtIndex(array
, position
)))
277 return numberRemoved
;
280 static CFIndex
CFArrayRemoveAllWithMatchingID(CFMutableArrayRef array
, SOSPeerInfoRef peerInfo
) {
281 CFStringRef peer_id
= SOSPeerInfoGetPeerID(peerInfo
);
283 return CFArrayRemoveAllPassing(array
, ^ bool (const void *element
) {
284 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) element
;
286 return CFEqual(peer_id
, SOSPeerInfoGetPeerID(peer
));
290 static void SOSCircleRejectNonValidApplicants(SOSCircleRef circle
, SecKeyRef pubkey
) {
291 CFArrayRef applicants
= SOSCircleCopyApplicants(circle
, NULL
);
292 CFArrayForEach(applicants
, ^(const void *value
) {
293 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
294 if(!SOSPeerInfoApplicationVerify(pi
, pubkey
, NULL
)) {
295 CFArrayRemoveAllWithMatchingID(circle
->applicants
, pi
);
296 CFArrayAppendValue(circle
->rejected_applicants
, pi
);
301 bool SOSCircleGenerationSign(SOSCircleRef circle
, SecKeyRef user_approver
, SOSFullPeerInfoRef peerinfo
, CFErrorRef
*error
) {
303 SecKeyRef ourKey
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, error
);
304 require_quiet(ourKey
, fail
);
306 SOSCircleRemoveRetired(circle
, error
); // Prune off retirees since we're signing this one
307 CFArrayRemoveAllValues(circle
->rejected_applicants
); // Dump rejects so we clean them up sometime.
308 SOSCircleRejectNonValidApplicants(circle
, SecKeyCreatePublicFromPrivate(user_approver
));
309 SOSCircleGenerationIncrement(circle
);
310 require_quiet(SOSCircleRemoveSignatures(circle
, error
), fail
);
311 require_quiet(SOSCircleSign(circle
, user_approver
, error
), fail
);
312 require_quiet(SOSCircleSign(circle
, ourKey
, error
), fail
);
314 CFReleaseNull(ourKey
);
318 CFReleaseNull(ourKey
);
323 bool SOSCircleConcordanceSign(SOSCircleRef circle
, SOSFullPeerInfoRef peerinfo
, CFErrorRef
*error
) {
324 bool success
= false;
325 SecKeyRef ourKey
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, error
);
326 require_quiet(ourKey
, exit
);
328 success
= SOSCircleSign(circle
, ourKey
, error
);
331 CFReleaseNull(ourKey
);
335 static inline SOSConcordanceStatus
CheckPeerStatus(SOSCircleRef circle
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
336 SOSConcordanceStatus result
= kSOSConcordanceNoPeer
;
337 SecKeyRef pubKey
= SOSPeerInfoCopyPubKey(peer
);
339 require_action_quiet(SOSCircleHasActivePeer(circle
, peer
, error
), exit
, result
= kSOSConcordanceNoPeer
);
340 require_action_quiet(SOSCircleVerifySignatureExists(circle
, pubKey
, error
), exit
, result
= kSOSConcordanceNoPeerSig
);
341 require_action_quiet(SOSCircleVerify(circle
, pubKey
, error
), exit
, result
= kSOSConcordanceBadPeerSig
);
343 result
= kSOSConcordanceTrusted
;
346 CFReleaseNull(pubKey
);
350 static inline SOSConcordanceStatus
CombineStatus(SOSConcordanceStatus status1
, SOSConcordanceStatus status2
)
352 if (status1
== kSOSConcordanceTrusted
|| status2
== kSOSConcordanceTrusted
)
353 return kSOSConcordanceTrusted
;
355 if (status1
== kSOSConcordanceBadPeerSig
|| status2
== kSOSConcordanceBadPeerSig
)
356 return kSOSConcordanceBadPeerSig
;
358 if (status1
== kSOSConcordanceNoPeerSig
|| status2
== kSOSConcordanceNoPeerSig
)
359 return kSOSConcordanceNoPeerSig
;
364 static inline bool SOSCircleIsEmpty(SOSCircleRef circle
) {
365 return SOSCircleCountPeers(circle
) == 0;
368 static inline bool SOSCircleIsOffering(SOSCircleRef circle
) {
369 return SOSCircleCountPeers(circle
) == 1;
372 static inline bool SOSCircleIsResignOffering(SOSCircleRef circle
, SecKeyRef pubkey
) {
373 return SOSCircleCountActiveValidPeers(circle
, pubkey
) == 1;
376 static inline SOSConcordanceStatus
GetSignersStatus(SOSCircleRef signers_circle
, SOSCircleRef status_circle
,
377 SecKeyRef user_pubKey
, SOSPeerInfoRef exclude
, CFErrorRef
*error
) {
378 CFStringRef excluded_id
= exclude
? SOSPeerInfoGetPeerID(exclude
) : NULL
;
380 __block SOSConcordanceStatus status
= kSOSConcordanceNoPeer
;
381 SOSCircleForEachActiveValidPeer(signers_circle
, user_pubKey
, ^(SOSPeerInfoRef peer
) {
382 SOSConcordanceStatus peerStatus
= CheckPeerStatus(status_circle
, peer
, error
);
384 if (peerStatus
== kSOSConcordanceNoPeerSig
&&
385 (CFEqualSafe(SOSPeerInfoGetPeerID(peer
), excluded_id
) || SOSPeerInfoIsCloudIdentity(peer
)))
386 peerStatus
= kSOSConcordanceNoPeer
;
388 status
= CombineStatus(status
, peerStatus
); // TODO: Use multiple error gathering.
394 static inline bool isOlderGeneration(SOSCircleRef current
, SOSCircleRef proposed
) {
395 return CFNumberCompare(current
->generation
, proposed
->generation
, NULL
) == kCFCompareGreaterThan
;
398 bool SOSCircleSharedTrustedPeers(SOSCircleRef current
, SOSCircleRef proposed
, SOSPeerInfoRef me
) {
399 __block
bool retval
= false;
400 SOSCircleForEachPeer(current
, ^(SOSPeerInfoRef peer
) {
401 if(!CFEqual(me
, peer
) && SOSCircleHasPeer(proposed
, peer
, NULL
)) retval
= true;
406 static void SOSCircleUpgradePeersByCircle(SOSCircleRef known_circle
, SOSCircleRef proposed_circle
) {
407 SOSCircleForEachPeer(known_circle
, ^(SOSPeerInfoRef known_peer
) {
408 SOSPeerInfoRef proposed_peer
= SOSCircleCopyPeerInfo(proposed_circle
, SOSPeerInfoGetPeerID(known_peer
), NULL
);
409 if(proposed_peer
&& CFEqualSafe(proposed_peer
, known_peer
) != 0) {
410 SOSCircleUpdatePeerInfo(known_circle
, proposed_peer
);
415 SOSConcordanceStatus
SOSCircleConcordanceTrust(SOSCircleRef known_circle
, SOSCircleRef proposed_circle
,
416 SecKeyRef known_pubkey
, SecKeyRef user_pubkey
,
417 SOSPeerInfoRef exclude
, CFErrorRef
*error
) {
419 if(user_pubkey
== NULL
) {
420 SOSCreateError(kSOSErrorPublicKeyAbsent
, CFSTR("Concordance with no public key"), NULL
, error
);
421 return kSOSConcordanceNoUserKey
; //TODO: - needs to return an error
424 if (SOSCircleIsEmpty(proposed_circle
)) {
425 return kSOSConcordanceTrusted
;
428 if(!SOSCircleVerifySignatureExists(proposed_circle
, user_pubkey
, error
)) {
429 SOSCreateError(kSOSErrorBadSignature
, CFSTR("No public signature"), (error
!= NULL
) ? *error
: NULL
, error
);
430 return kSOSConcordanceNoUserSig
;
433 if(!SOSCircleVerify(proposed_circle
, user_pubkey
, error
)) {
434 SOSCreateError(kSOSErrorBadSignature
, CFSTR("Bad public signature"), (error
!= NULL
) ? *error
: NULL
, error
);
435 return kSOSConcordanceBadUserSig
;
438 if (SOSCircleIsEmpty(known_circle
) || SOSCircleIsOffering(proposed_circle
)) {
439 return GetSignersStatus(proposed_circle
, proposed_circle
, user_pubkey
, NULL
, error
);
442 if(isOlderGeneration(known_circle
, proposed_circle
)) {
443 SOSCreateError(kSOSErrorReplay
, CFSTR("Bad generation"), NULL
, error
);
444 return kSOSConcordanceGenOld
;
448 if(!SOSCircleVerify(known_circle
, user_pubkey
, error
)) {
449 SOSCircleUpgradePeersByCircle(known_circle
, proposed_circle
);
452 if(known_pubkey
== NULL
) known_pubkey
= user_pubkey
;
453 if(!SOSCircleVerify(known_circle
, known_pubkey
, error
)) known_pubkey
= user_pubkey
;
454 return GetSignersStatus(known_circle
, proposed_circle
, known_pubkey
, exclude
, error
);
458 static const uint8_t* der_decode_mutable_dictionary(CFAllocatorRef allocator
, CFOptionFlags mutability
,
459 CFMutableDictionaryRef
* dictionary
, CFErrorRef
*error
,
460 const uint8_t* der
, const uint8_t *der_end
)
462 CFDictionaryRef theDict
;
463 const uint8_t* result
= der_decode_dictionary(allocator
, mutability
, &theDict
, error
, der
, der_end
);
466 *dictionary
= (CFMutableDictionaryRef
)theDict
;
471 SOSCircleRef
SOSCircleCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
472 const uint8_t** der_p
, const uint8_t *der_end
) {
473 SOSCircleRef cir
= CFTypeAllocate(SOSCircle
, struct __OpaqueSOSCircle
, allocator
);
475 const uint8_t *sequence_end
;
478 cir
->generation
= NULL
;
480 cir
->applicants
= NULL
;
481 cir
->rejected_applicants
= NULL
;
482 cir
->signatures
= NULL
;
484 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
485 require_action_quiet(sequence_end
!= NULL
, fail
,
486 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Circle DER"), (error
!= NULL
) ? *error
: NULL
, error
));
489 uint64_t version
= 0;
490 *der_p
= ccder_decode_uint64(&version
, *der_p
, der_end
);
492 require_action_quiet(version
== kOnlyCompatibleVersion
, fail
,
493 SOSCreateError(kSOSErrorIncompatibleCircle
, CFSTR("Bad Circle Version"), NULL
, error
));
495 *der_p
= der_decode_string(allocator
, 0, &cir
->name
, error
, *der_p
, sequence_end
);
496 *der_p
= der_decode_number(allocator
, 0, &cir
->generation
, error
, *der_p
, sequence_end
);
498 cir
->peers
= SOSPeerInfoArrayCreateFromDER(allocator
, error
, der_p
, sequence_end
);
499 cir
->applicants
= SOSPeerInfoArrayCreateFromDER(allocator
, error
, der_p
, sequence_end
);
500 cir
->rejected_applicants
= SOSPeerInfoArrayCreateFromDER(allocator
, error
, der_p
, sequence_end
);
502 *der_p
= der_decode_mutable_dictionary(allocator
, kCFPropertyListMutableContainersAndLeaves
,
503 &cir
->signatures
, error
, *der_p
, sequence_end
);
505 require_action_quiet(*der_p
== sequence_end
, fail
,
506 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Circle DER"), (error
!= NULL
) ? *error
: NULL
, error
));
515 SOSCircleRef
SOSCircleCreateFromData(CFAllocatorRef allocator
, CFDataRef circleData
, CFErrorRef
*error
)
517 size_t size
= CFDataGetLength(circleData
);
518 const uint8_t *der
= CFDataGetBytePtr(circleData
);
519 SOSCircleRef inflated
= SOSCircleCreateFromDER(allocator
, error
, &der
, der
+ size
);
523 size_t SOSCircleGetDEREncodedSize(SOSCircleRef cir
, CFErrorRef
*error
) {
524 SOSCircleAssertStable(cir
);
525 size_t total_payload
= 0;
527 require_quiet(accumulate_size(&total_payload
, ccder_sizeof_uint64(kOnlyCompatibleVersion
)), fail
);
528 require_quiet(accumulate_size(&total_payload
, der_sizeof_string(cir
->name
, error
)), fail
);
529 require_quiet(accumulate_size(&total_payload
, der_sizeof_number(cir
->generation
, error
)), fail
);
530 require_quiet(accumulate_size(&total_payload
, SOSPeerInfoArrayGetDEREncodedSize(cir
->peers
, error
)), fail
);
531 require_quiet(accumulate_size(&total_payload
, SOSPeerInfoArrayGetDEREncodedSize(cir
->applicants
, error
)), fail
);
532 require_quiet(accumulate_size(&total_payload
, SOSPeerInfoArrayGetDEREncodedSize(cir
->rejected_applicants
, error
)), fail
);
533 require_quiet(accumulate_size(&total_payload
, der_sizeof_dictionary((CFDictionaryRef
) cir
->signatures
, error
)), fail
);
535 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, total_payload
);
538 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("don't know how to encode"), NULL
, error
);
542 uint8_t* SOSCircleEncodeToDER(SOSCircleRef cir
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
) {
543 SOSCircleAssertStable(cir
);
545 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
546 ccder_encode_uint64(kOnlyCompatibleVersion
, der
,
547 der_encode_string(cir
->name
, error
, der
,
548 der_encode_number(cir
->generation
, error
, der
,
549 SOSPeerInfoArrayEncodeToDER(cir
->peers
, error
, der
,
550 SOSPeerInfoArrayEncodeToDER(cir
->applicants
, error
, der
,
551 SOSPeerInfoArrayEncodeToDER(cir
->rejected_applicants
, error
, der
,
552 der_encode_dictionary((CFDictionaryRef
) cir
->signatures
, error
, der
, der_end
))))))));
555 CFDataRef
SOSCircleCreateIncompatibleCircleDER(CFErrorRef
* error
)
557 size_t total_payload
= 0;
558 size_t encoded_size
= 0;
560 uint8_t* der_end
= 0;
561 CFMutableDataRef result
= NULL
;
563 require_quiet(accumulate_size(&total_payload
, ccder_sizeof_uint64(kAlwaysIncompatibleVersion
)), fail
);
565 encoded_size
= ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, total_payload
);
567 result
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, encoded_size
);
569 der
= CFDataGetMutableBytePtr(result
);
570 der_end
= der
+ CFDataGetLength(result
);
572 der_end
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
573 ccder_encode_uint64(kAlwaysIncompatibleVersion
, der
, der_end
));
576 if (der
== NULL
|| der
!= der_end
)
577 CFReleaseNull(result
);
583 CFDataRef
SOSCircleCopyEncodedData(SOSCircleRef circle
, CFAllocatorRef allocator
, CFErrorRef
*error
)
585 size_t size
= SOSCircleGetDEREncodedSize(circle
, error
);
588 uint8_t buffer
[size
];
589 uint8_t* start
= SOSCircleEncodeToDER(circle
, error
, buffer
, buffer
+ sizeof(buffer
));
590 CFDataRef result
= CFDataCreate(kCFAllocatorDefault
, start
, size
);
594 static void SOSCircleDestroy(CFTypeRef aObj
) {
595 SOSCircleRef c
= (SOSCircleRef
) aObj
;
597 CFReleaseNull(c
->name
);
598 CFReleaseNull(c
->generation
);
599 CFReleaseNull(c
->peers
);
600 CFReleaseNull(c
->applicants
);
601 CFReleaseNull(c
->rejected_applicants
);
602 CFReleaseNull(c
->signatures
);
605 static CFStringRef
SOSCircleCopyDescription(CFTypeRef aObj
) {
606 SOSCircleRef c
= (SOSCircleRef
) aObj
;
608 SOSCircleAssertStable(c
);
610 return CFStringCreateWithFormat(NULL
, NULL
,
611 CFSTR("<SOSCircle@%p: [ \nName: %@, \nPeers: %@,\nApplicants: %@,\nRejects: %@,\nSignatures: %@\n ] >"),
612 c
, c
->name
, c
->peers
, c
->applicants
, c
->rejected_applicants
, c
->signatures
);
615 CFStringRef
SOSCircleGetName(SOSCircleRef circle
) {
617 assert(circle
->name
);
621 const char *SOSCircleGetNameC(SOSCircleRef circle
) {
622 CFStringRef name
= SOSCircleGetName(circle
);
625 return CFStringToCString(name
);
628 CFNumberRef
SOSCircleGetGeneration(SOSCircleRef circle
) {
630 assert(circle
->generation
);
631 return circle
->generation
;
634 int64_t SOSCircleGetGenerationSint(SOSCircleRef circle
) {
635 CFNumberRef gen
= SOSCircleGetGeneration(circle
);
638 CFNumberGetValue(gen
, kCFNumberSInt64Type
, &value
);
642 void SOSCircleGenerationIncrement(SOSCircleRef circle
) {
643 CFAllocatorRef allocator
= CFGetAllocator(circle
->generation
);
644 int64_t value
= SOSCircleGetGenerationSint(circle
);
646 circle
->generation
= CFNumberCreate(allocator
, kCFNumberSInt64Type
, &value
);
649 int SOSCircleCountPeers(SOSCircleRef circle
) {
650 SOSCircleAssertStable(circle
);
651 __block
int count
= 0;
652 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
658 int SOSCircleCountActivePeers(SOSCircleRef circle
) {
659 SOSCircleAssertStable(circle
);
660 __block
int count
= 0;
661 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
667 int SOSCircleCountActiveValidPeers(SOSCircleRef circle
, SecKeyRef pubkey
) {
668 SOSCircleAssertStable(circle
);
669 __block
int count
= 0;
670 SOSCircleForEachActiveValidPeer(circle
, pubkey
, ^(SOSPeerInfoRef peer
) {
676 int SOSCircleCountRetiredPeers(SOSCircleRef circle
) {
677 SOSCircleAssertStable(circle
);
678 __block
int count
= 0;
679 SOSCircleForEachRetiredPeer(circle
, ^(SOSPeerInfoRef peer
) {
685 int SOSCircleCountApplicants(SOSCircleRef circle
) {
686 SOSCircleAssertStable(circle
);
688 return (int)CFArrayGetCount(circle
->applicants
);
691 bool SOSCircleHasApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
692 SOSCircleAssertStable(circle
);
694 return CFArrayHasValueMatching(circle
->applicants
, ^bool(const void *value
) {
695 return SOSPeerInfoCompareByID(value
, peerInfo
, NULL
) == 0;
699 CFMutableArrayRef
SOSCircleCopyApplicants(SOSCircleRef circle
, CFAllocatorRef allocator
) {
700 SOSCircleAssertStable(circle
);
702 return CFArrayCreateMutableCopy(allocator
, 0, circle
->applicants
);
705 int SOSCircleCountRejectedApplicants(SOSCircleRef circle
) {
706 SOSCircleAssertStable(circle
);
708 return (int)CFArrayGetCount(circle
->rejected_applicants
);
711 bool SOSCircleHasRejectedApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
712 SOSCircleAssertStable(circle
);
714 return CFArrayHasValueMatching(circle
->rejected_applicants
, ^bool(const void *value
) {
715 return SOSPeerInfoCompareByID(value
, peerInfo
, NULL
) == 0;
719 SOSPeerInfoRef
SOSCircleCopyRejectedApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
720 SOSCircleAssertStable(circle
);
721 return (SOSPeerInfoRef
) CFArrayGetValueMatching(circle
->rejected_applicants
, ^bool(const void *value
) {
722 return SOSPeerInfoCompareByID(value
, peerInfo
, NULL
) == 0;
726 CFMutableArrayRef
SOSCircleCopyRejectedApplicants(SOSCircleRef circle
, CFAllocatorRef allocator
) {
727 SOSCircleAssertStable(circle
);
729 return CFArrayCreateMutableCopy(allocator
, 0, circle
->rejected_applicants
);
733 bool SOSCircleHasPeerWithID(SOSCircleRef circle
, CFStringRef peerid
, CFErrorRef
*error
) {
734 SOSCircleAssertStable(circle
);
735 __block
bool found
= false;
736 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
737 if(peerid
&& peer
&& CFEqualSafe(peerid
, SOSPeerInfoGetPeerID(peer
))) found
= true;
742 bool SOSCircleHasPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
743 return SOSCircleHasPeerWithID(circle
, SOSPeerInfoGetPeerID(peerInfo
), error
);
746 bool SOSCircleHasActivePeerWithID(SOSCircleRef circle
, CFStringRef peerid
, CFErrorRef
*error
) {
747 SOSCircleAssertStable(circle
);
748 __block
bool found
= false;
749 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
750 if(peerid
&& peer
&& CFEqualSafe(peerid
, SOSPeerInfoGetPeerID(peer
))) found
= true;
755 bool SOSCircleHasActivePeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
756 if(!peerInfo
) return false;
757 return SOSCircleHasActivePeerWithID(circle
, SOSPeerInfoGetPeerID(peerInfo
), error
);
762 bool SOSCircleResetToEmpty(SOSCircleRef circle
, CFErrorRef
*error
) {
763 CFArrayRemoveAllValues(circle
->applicants
);
764 CFArrayRemoveAllValues(circle
->peers
);
765 CFDictionaryRemoveAllValues(circle
->signatures
);
770 bool SOSCircleResetToOffering(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
){
772 return SOSCircleResetToEmpty(circle
, error
)
773 && SOSCircleRequestAdmission(circle
, user_privkey
, requestor
, error
)
774 && SOSCircleAcceptRequest(circle
, user_privkey
, requestor
, SOSFullPeerInfoGetPeerInfo(requestor
), error
);
777 CFIndex
SOSCircleRemoveRetired(SOSCircleRef circle
, CFErrorRef
*error
) {
778 CFIndex n
= CFArrayRemoveAllPassing(circle
->peers
, ^ bool (const void *element
) {
779 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) element
;
781 return SOSPeerInfoIsRetirementTicket(peer
);
787 static bool SOSCircleRecordAdmission(SOSCircleRef circle
, SecKeyRef user_pubkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
) {
788 SOSCircleAssertStable(circle
);
790 bool isPeer
= SOSCircleHasPeer(circle
, SOSFullPeerInfoGetPeerInfo(requestor
), error
);
792 require_action_quiet(!isPeer
, fail
, SOSCreateError(kSOSErrorAlreadyPeer
, CFSTR("Cannot request admission when already a peer"), NULL
, error
));
794 CFIndex total
= CFArrayRemoveAllWithMatchingID(circle
->applicants
, SOSFullPeerInfoGetPeerInfo(requestor
));
796 (void) total
; // Suppress unused warning in release code.
797 assert(total
<= 1); // We should at most be in the list once.
799 total
= CFArrayRemoveAllWithMatchingID(circle
->rejected_applicants
, SOSFullPeerInfoGetPeerInfo(requestor
));
801 (void) total
; // Suppress unused warning in release code.
802 assert(total
<= 1); // We should at most be in the list once.
805 // Refetch the current PeerInfo as the promtion above can change it.
806 CFArrayAppendValue(circle
->applicants
, SOSFullPeerInfoGetPeerInfo(requestor
));
815 bool SOSCircleRequestReadmission(SOSCircleRef circle
, SecKeyRef user_pubkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
) {
816 bool success
= false;
818 SOSPeerInfoRef peer
= SOSFullPeerInfoGetPeerInfo(requestor
);
819 require_quiet(SOSPeerInfoApplicationVerify(peer
, user_pubkey
, error
), fail
);
820 success
= SOSCircleRecordAdmission(circle
, user_pubkey
, requestor
, error
);
825 bool SOSCircleRequestAdmission(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
) {
826 bool success
= false;
828 SecKeyRef user_pubkey
= SecKeyCreatePublicFromPrivate(user_privkey
);
829 require_action_quiet(user_pubkey
, fail
, SOSCreateError(kSOSErrorBadKey
, CFSTR("No public key for key"), NULL
, error
));
831 require(SOSFullPeerInfoPromoteToApplication(requestor
, user_privkey
, error
), fail
);
833 success
= SOSCircleRecordAdmission(circle
, user_pubkey
, requestor
, error
);
835 CFReleaseNull(user_pubkey
);
840 bool SOSCircleUpdatePeerInfo(SOSCircleRef circle
, SOSPeerInfoRef replacement_peer_info
) {
841 __block
bool replaced
= false;
842 CFStringRef replacement_peer_id
= SOSPeerInfoGetPeerID(replacement_peer_info
);
844 CFMutableArrayModifyValues(circle
->peers
, ^const void *(const void *value
) {
845 if (CFEqual(replacement_peer_id
, SOSPeerInfoGetPeerID((SOSPeerInfoRef
) value
))
846 && !CFEqual(replacement_peer_info
, value
)) {
848 return replacement_peer_info
;
856 bool SOSCircleRemovePeer(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, SOSPeerInfoRef peer_to_remove
, CFErrorRef
*error
) {
857 SOSPeerInfoRef requestor_peer_info
= SOSFullPeerInfoGetPeerInfo(requestor
);
859 if (SOSCircleHasApplicant(circle
, peer_to_remove
, error
)) {
860 return SOSCircleRejectRequest(circle
, requestor
, peer_to_remove
, error
);
863 if (!SOSCircleHasPeer(circle
, requestor_peer_info
, error
)) {
864 SOSCreateError(kSOSErrorAlreadyPeer
, CFSTR("Must be peer to remove peer"), NULL
, error
);
868 CFArrayRemoveAllWithMatchingID(circle
->peers
, peer_to_remove
);
870 SOSCircleGenerationSign(circle
, user_privkey
, requestor
, error
);
875 bool SOSCircleAcceptRequest(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef device_approver
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
876 SOSCircleAssertStable(circle
);
878 CFIndex total
= CFArrayRemoveAllWithMatchingID(circle
->applicants
, peerInfo
);
879 SecKeyRef publicKey
= NULL
;
882 require_action_quiet(total
!= 0, fail
,
883 SOSCreateError(kSOSErrorNotApplicant
, CFSTR("Cannot accept non-applicant"), NULL
, error
));
885 publicKey
= SecKeyCreatePublicFromPrivate(user_privkey
);
886 require_quiet(SOSPeerInfoApplicationVerify(peerInfo
, publicKey
, error
), fail
);
890 CFArrayAppendValue(circle
->peers
, peerInfo
);
891 result
= SOSCircleGenerationSign(circle
, user_privkey
, device_approver
, error
);
892 secnotice("circle", "Accepted %@", peerInfo
);
895 CFReleaseNull(publicKey
);
899 bool SOSCircleWithdrawRequest(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
900 SOSCircleAssertStable(circle
);
905 CFArrayRemoveAllWithMatchingID(circle
->applicants
, peerInfo
);
912 bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
913 SOSCircleAssertStable(circle
);
918 CFArrayRemoveAllWithMatchingID(circle
->rejected_applicants
, peerInfo
);
926 bool SOSCircleRejectRequest(SOSCircleRef circle
, SOSFullPeerInfoRef device_rejector
,
927 SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
928 SOSCircleAssertStable(circle
);
930 if (CFEqual(SOSPeerInfoGetPeerID(peerInfo
), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector
))))
931 return SOSCircleWithdrawRequest(circle
, peerInfo
, error
);
933 CFIndex total
= CFArrayRemoveAllWithMatchingID(circle
->applicants
, peerInfo
);
936 SOSCreateError(kSOSErrorNotApplicant
, CFSTR("Cannot reject non-applicant"), NULL
, error
);
941 CFArrayAppendValue(circle
->rejected_applicants
, peerInfo
);
943 // TODO: Maybe we sign the rejection with device_rejector.
948 bool SOSCircleAcceptRequests(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef device_approver
,
950 // Returns true if we accepted someone and therefore have to post the circle back to KVS
951 __block
bool result
= false;
953 SOSCircleForEachApplicant(circle
, ^(SOSPeerInfoRef peer
) {
954 if (!SOSCircleAcceptRequest(circle
, user_privkey
, device_approver
, peer
, error
))
955 printf("error in SOSCircleAcceptRequest\n");
957 secnotice("circle", "Accepted peer: %@", peer
);
963 SOSCircleGenerationSign(circle
, user_privkey
, device_approver
, error
);
964 secnotice("circle", "Countersigned accepted requests");
970 bool SOSCirclePeerSigUpdate(SOSCircleRef circle
, SecKeyRef userPrivKey
, SOSFullPeerInfoRef fpi
,
972 // Returns true if we accepted someone and therefore have to post the circle back to KVS
973 __block
bool result
= false;
974 SecKeyRef userPubKey
= SecKeyCreatePublicFromPrivate(userPrivKey
);
976 // We're going to remove any applicants using a mismatched user key.
977 SOSCircleForEachApplicant(circle
, ^(SOSPeerInfoRef peer
) {
978 if(!SOSPeerInfoApplicationVerify(peer
, userPubKey
, NULL
)) {
979 if(!SOSCircleRejectRequest(circle
, fpi
, peer
, NULL
)) {
985 result
= SOSCircleUpdatePeerInfo(circle
, SOSFullPeerInfoGetPeerInfo(fpi
));
988 SOSCircleGenerationSign(circle
, userPrivKey
, fpi
, error
);
989 secnotice("circle", "Generation signed updated signatures on peerinfo");
995 SOSPeerInfoRef
SOSCircleCopyPeerInfo(SOSCircleRef circle
, CFStringRef peer_id
, CFErrorRef
*error
) {
996 __block SOSPeerInfoRef result
= NULL
;
998 CFArrayForEach(circle
->peers
, ^(const void *value
) {
999 if (result
== NULL
) {
1000 SOSPeerInfoRef tpi
= (SOSPeerInfoRef
)value
;
1001 if (CFEqual(SOSPeerInfoGetPeerID(tpi
), peer_id
))
1006 CFRetainSafe(result
);
1011 static inline void SOSCircleForEachPeerMatching(SOSCircleRef circle
,
1012 void (^action
)(SOSPeerInfoRef peer
),
1013 bool (^condition
)(SOSPeerInfoRef peer
)) {
1014 CFArrayForEach(circle
->peers
, ^(const void *value
) {
1015 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) value
;
1016 if (condition(peer
))
1021 void SOSCircleForEachPeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1022 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1023 return !SOSPeerInfoIsRetirementTicket(peer
) && !SOSPeerInfoIsCloudIdentity(peer
);
1027 void SOSCircleForEachRetiredPeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1028 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1029 return SOSPeerInfoIsRetirementTicket(peer
);
1033 void SOSCircleForEachActivePeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1034 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1039 void SOSCircleForEachActiveValidPeer(SOSCircleRef circle
, SecKeyRef user_public_key
, void (^action
)(SOSPeerInfoRef peer
)) {
1040 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1041 return SOSPeerInfoApplicationVerify(peer
, user_public_key
, NULL
);
1045 void SOSCircleForEachApplicant(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1046 CFArrayForEach(circle
->applicants
, ^(const void*value
) { action((SOSPeerInfoRef
) value
); } );
1050 CFMutableArrayRef
SOSCircleCopyPeers(SOSCircleRef circle
, CFAllocatorRef allocator
) {
1051 SOSCircleAssertStable(circle
);
1053 CFMutableArrayRef result
= CFArrayCreateMutableForCFTypes(allocator
);
1055 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
1056 CFArrayAppendValue(result
, peer
);
1062 CFMutableArrayRef
SOSCircleCopyConcurringPeers(SOSCircleRef circle
, CFErrorRef
* error
) {
1063 SOSCircleAssertStable(circle
);
1065 CFMutableArrayRef concurringPeers
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
1067 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
1068 CFErrorRef error
= NULL
;
1069 if (SOSCircleVerifyPeerSigned(circle
, peer
, &error
)) {
1070 CFArrayAppendValue(concurringPeers
, peer
);
1071 } else if (error
!= NULL
) {
1072 secerror("Error checking concurrence: %@", error
);
1074 CFReleaseNull(error
);
1077 return concurringPeers
;
1082 // Stuff above this line is really SOSCircleInfo below the line is the active SOSCircle functionality
1085 static SOSPeerRef
SOSCircleCopyPeer(SOSCircleRef circle
, SOSFullPeerInfoRef myRef
, SOSPeerSendBlock sendBlock
,
1086 CFStringRef peer_id
, CFErrorRef
*error
) {
1087 SOSPeerRef peer
= NULL
;
1088 SOSPeerInfoRef peer_info
= SOSCircleCopyPeerInfo(circle
, peer_id
, error
);
1089 //TODO: if (peer is legit member of us then good otherwise bail) {
1092 peer
= SOSPeerCreate(myRef
, peer_info
, error
, sendBlock
);
1093 CFReleaseNull(peer_info
);
1099 static bool SOSCircleDoWithPeer(SOSFullPeerInfoRef myRef
, SOSCircleRef circle
, SOSDataSourceFactoryRef factory
,
1100 SOSPeerSendBlock sendBlock
, CFStringRef peer_id
, bool readOnly
,
1101 CFErrorRef
* error
, bool (^do_action
)(SOSEngineRef engine
, SOSPeerRef peer
, CFErrorRef
*error
))
1103 bool success
= false;
1104 SOSEngineRef engine
= NULL
;
1105 SOSPeerRef peer
= NULL
;
1106 SOSDataSourceRef ds
= NULL
;
1108 peer
= SOSCircleCopyPeer(circle
, myRef
, sendBlock
, peer_id
, error
);
1109 require(peer
, exit
);
1111 ds
= factory
->create_datasource(factory
, SOSCircleGetName(circle
), readOnly
, error
);
1114 engine
= SOSEngineCreate(ds
, error
); // Hand off DS to engine.
1116 require(engine
, exit
);
1118 success
= do_action(engine
, peer
, error
);
1124 SOSEngineDispose(engine
);
1126 SOSPeerDispose(peer
);
1131 bool SOSCircleSyncWithPeer(SOSFullPeerInfoRef myRef
, SOSCircleRef circle
, SOSDataSourceFactoryRef factory
,
1132 SOSPeerSendBlock sendBlock
, CFStringRef peer_id
,
1135 return SOSCircleDoWithPeer(myRef
, circle
, factory
, sendBlock
, peer_id
, true, error
, ^bool(SOSEngineRef engine
, SOSPeerRef peer
, CFErrorRef
*error
) {
1136 return SOSPeerStartSync(peer
, engine
, error
) != kSOSPeerCoderFailure
;
1140 bool SOSCircleHandlePeerMessage(SOSCircleRef circle
, SOSFullPeerInfoRef myRef
, SOSDataSourceFactoryRef factory
,
1141 SOSPeerSendBlock sendBlock
, CFStringRef peer_id
,
1142 CFDataRef message
, CFErrorRef
*error
) {
1143 return SOSCircleDoWithPeer(myRef
, circle
, factory
, sendBlock
, peer_id
, false, error
, ^bool(SOSEngineRef engine
, SOSPeerRef peer
, CFErrorRef
*error
) {
1144 return SOSPeerHandleMessage(peer
, engine
, message
, error
) != kSOSPeerCoderFailure
;
1149 SOSFullPeerInfoRef
SOSCircleGetiCloudFullPeerInfoRef(SOSCircleRef circle
) {
1150 __block SOSFullPeerInfoRef cloud_full_peer
= NULL
;
1151 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
1152 if (SOSPeerInfoIsCloudIdentity(peer
)) {
1153 if (cloud_full_peer
== NULL
) {
1154 CFErrorRef localError
= NULL
;
1155 cloud_full_peer
= SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault
, peer
, &localError
);
1158 secerror("Found cloud peer in circle but can't make full peer: %@", localError
);
1159 CFReleaseNull(localError
);
1163 secerror("More than one cloud identity found in circle: %@", circle
);
1167 return cloud_full_peer
;