]> git.saurik.com Git - apple/security.git/blame - sec/SOSCircle/SecureObjectSync/SOSCircle.c
Security-55471.14.18.tar.gz
[apple/security.git] / sec / SOSCircle / SecureObjectSync / SOSCircle.c
CommitLineData
427c49bc
A
1/*
2 * Created by Michael Brouwer on 6/22/12.
3 * Copyright 2012 Apple Inc. All Rights Reserved.
4 */
5
6/*
7 * SOSCircle.c - Implementation of the secure object syncing transport
8 */
9
10#include <AssertMacros.h>
11
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>
20
21#include <Security/SecKey.h>
22#include <Security/SecKeyPriv.h>
23
24#include <utilities/SecCFWrappers.h>
25//#include "ckdUtilities.h"
26
27#include <utilities/der_plist.h>
28#include <utilities/der_plist_internal.h>
29
30#include <corecrypto/ccder.h>
31#include <corecrypto/ccdigest.h>
32#include <corecrypto/ccsha2.h>
33
34#include <stdlib.h>
35#include <assert.h>
36
37enum {
38 kOnlyCompatibleVersion = 1, // Sometime in the future this name will be improved to reflect history.
39
40 kAlwaysIncompatibleVersion = UINT64_MAX,
41};
42
43struct __OpaqueSOSCircle {
44 CFRuntimeBase _base;
45
46 CFStringRef name;
47 CFNumberRef generation;
48 CFMutableArrayRef peers;
49 CFMutableArrayRef applicants;
50 CFMutableArrayRef rejected_applicants;
51
52 CFMutableDictionaryRef signatures;
53};
54
55CFGiblisWithCompareFor(SOSCircle);
56
57// Move the next 2 lines to SOSPeer if we need it.
58static void SOSPeerRelease(CFAllocatorRef allocator, const void *value) {
59 SOSPeerDispose((SOSPeerRef)value);
60}
61
62static const CFDictionaryValueCallBacks dispose_peer_callbacks = { .release = SOSPeerRelease };
63
64SOSCircleRef SOSCircleCreate(CFAllocatorRef allocator, CFStringRef name, CFErrorRef *error) {
65 SOSCircleRef c = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
66 int64_t gen = 1;
67
68 assert(name);
69
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);
76
77 return c;
78}
79
80static CFNumberRef SOSCircleGenerationCopy(CFNumberRef generation) {
81 int64_t value;
82 CFAllocatorRef allocator = CFGetAllocator(generation);
83 CFNumberGetValue(generation, kCFNumberSInt64Type, &value);
84 return CFNumberCreate(allocator, kCFNumberSInt64Type, &value);
85}
86
87SOSCircleRef SOSCircleCopyCircle(CFAllocatorRef allocator, SOSCircleRef otherCircle, CFErrorRef *error)
88{
89 SOSCircleRef c = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
90
91 assert(otherCircle);
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);
98
99 return c;
100}
101
102static inline
103void SOSCircleAssertStable(SOSCircleRef circle)
104{
105 assert(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);
112}
113
114static inline
115SOSCircleRef SOSCircleConvertAndAssertStable(CFTypeRef circleAsType)
116{
117 if (CFGetTypeID(circleAsType) != SOSCircleGetTypeID())
118 return NULL;
119
120 SOSCircleRef circle = (SOSCircleRef) circleAsType;
121
122 SOSCircleAssertStable(circle);
123
124 return circle;
125}
126
127
128static Boolean SOSCircleCompare(CFTypeRef lhs, CFTypeRef rhs) {
129 if (CFGetTypeID(lhs) != SOSCircleGetTypeID()
130 || CFGetTypeID(rhs) != SOSCircleGetTypeID())
131 return false;
132
133 SOSCircleRef left = SOSCircleConvertAndAssertStable(lhs);
134 SOSCircleRef right = SOSCircleConvertAndAssertStable(rhs);
135
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);
143}
144
145
146static bool SOSCircleDigestArray(const struct ccdigest_info *di, CFMutableArrayRef array, void *hash_result, CFErrorRef *error)
147{
148 __block bool success = true;
149 ccdigest_di_decl(di, array_digest);
150 const void * a_digest = array_digest;
151
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))
156 success = false;
157 });
158 ccdigest_final(di, array_digest, hash_result);
159
160 return success;
161}
162
163static 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);
168
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);
172 return true;
173}
174
175static bool SOSCircleSetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFDataRef signature, CFErrorRef *error) {
176 bool result = false;
177
178 CFStringRef pubKeyID = SOSCopyIDOfKey(pubkey, error);
179 require_quiet(pubKeyID, fail);
180 CFDictionarySetValue(circle->signatures, pubKeyID, signature);
181 result = true;
182
183fail:
184 CFReleaseSafe(pubKeyID);
185 return result;
186}
187
188static bool SOSCircleRemoveSignatures(SOSCircleRef circle, CFErrorRef *error) {
189 CFDictionaryRemoveAllValues(circle->signatures);
190 return true;
191}
192
193static CFDataRef SOSCircleGetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFErrorRef *error) {
194 CFStringRef pubKeyID = SOSCopyIDOfKey(pubkey, error);
195 CFDataRef result = NULL;
196 require_quiet(pubKeyID, fail);
197
198 CFTypeRef value = (CFDataRef)CFDictionaryGetValue(circle->signatures, pubKeyID);
199
200 if (isData(value)) result = (CFDataRef) value;
201
202fail:
203 CFReleaseSafe(pubKeyID);
204 return result;
205}
206
207bool 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);
210 uint8_t tmp[4096];
211 size_t tmplen = 4096;
212 const struct ccdigest_info *di = ccsha256_di();
213 uint8_t hash_result[di->output_size];
214
215 SOSCircleHash(di, circle, hash_result, error);
216 OSStatus stat = SecKeyRawSign(privKey, kSecPaddingNone, hash_result, di->output_size, tmp, &tmplen);
217 if(stat) {
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);
221 return false;
222 };
223 CFDataRef signature = CFDataCreate(allocator, tmp, tmplen);
224 SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(privKey);
225 SOSCircleSetSignature(circle, publicKey, signature, error);
226 CFReleaseNull(publicKey);
227 CFRelease(signature);
228 return true;
229}
230
231bool SOSCircleVerifySignatureExists(SOSCircleRef circle, SecKeyRef pubKey, CFErrorRef *error) {
232 if(!pubKey) {
233 // TODO ErrorRef
234 secerror("SOSCircleVerifySignatureExists no pubKey");
235 SOSCreateError(kSOSErrorBadFormat, CFSTR("SOSCircleVerifySignatureExists no pubKey"), (error != NULL) ? *error : NULL, error);
236 return false;
237 }
238 CFDataRef signature = SOSCircleGetSignature(circle, pubKey, error);
239 return NULL != signature;
240}
241
242bool SOSCircleVerify(SOSCircleRef circle, SecKeyRef pubKey, CFErrorRef *error) {
243 const struct ccdigest_info *di = ccsha256_di();
244 uint8_t hash_result[di->output_size];
245
246 SOSCircleHash(di, circle, hash_result, error);
247
248 CFDataRef signature = SOSCircleGetSignature(circle, pubKey, error);
249 if(!signature) return false;
250
251 return SecKeyRawVerify(pubKey, kSecPaddingNone, hash_result, di->output_size,
252 CFDataGetBytePtr(signature), CFDataGetLength(signature)) == errSecSuccess;
253}
254
255bool 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);
259 return result;
260}
261
262
263static CFIndex CFArrayRemoveAllPassing(CFMutableArrayRef array, bool (^test)(const void *) ){
264 CFIndex numberRemoved = 0;
265
266 CFIndex position = 0;
267 while (position < CFArrayGetCount(array) && !test(CFArrayGetValueAtIndex(array, position)))
268 ++position;
269
270 while (position < CFArrayGetCount(array)) {
271 CFArrayRemoveValueAtIndex(array, position);
272 ++numberRemoved;
273 while (position < CFArrayGetCount(array) && !test(CFArrayGetValueAtIndex(array, position)))
274 ++position;
275 }
276
277 return numberRemoved;
278}
279
280static CFIndex CFArrayRemoveAllWithMatchingID(CFMutableArrayRef array, SOSPeerInfoRef peerInfo) {
281 CFStringRef peer_id = SOSPeerInfoGetPeerID(peerInfo);
e3d3b979 282 if (!peer_id) return 0;
427c49bc
A
283
284 return CFArrayRemoveAllPassing(array, ^ bool (const void *element) {
285 SOSPeerInfoRef peer = (SOSPeerInfoRef) element;
286
287 return CFEqual(peer_id, SOSPeerInfoGetPeerID(peer));
288 });
289}
290
291static void SOSCircleRejectNonValidApplicants(SOSCircleRef circle, SecKeyRef pubkey) {
292 CFArrayRef applicants = SOSCircleCopyApplicants(circle, NULL);
293 CFArrayForEach(applicants, ^(const void *value) {
294 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
295 if(!SOSPeerInfoApplicationVerify(pi, pubkey, NULL)) {
296 CFArrayRemoveAllWithMatchingID(circle->applicants, pi);
297 CFArrayAppendValue(circle->rejected_applicants, pi);
298 }
299 });
300}
301
302bool SOSCircleGenerationSign(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
303
304 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
305 require_quiet(ourKey, fail);
306
307 SOSCircleRemoveRetired(circle, error); // Prune off retirees since we're signing this one
308 CFArrayRemoveAllValues(circle->rejected_applicants); // Dump rejects so we clean them up sometime.
309 SOSCircleRejectNonValidApplicants(circle, SecKeyCreatePublicFromPrivate(user_approver));
310 SOSCircleGenerationIncrement(circle);
311 require_quiet(SOSCircleRemoveSignatures(circle, error), fail);
312 require_quiet(SOSCircleSign(circle, user_approver, error), fail);
313 require_quiet(SOSCircleSign(circle, ourKey, error), fail);
314
315 CFReleaseNull(ourKey);
316 return true;
317
318fail:
319 CFReleaseNull(ourKey);
320 return false;
321}
322
323
324bool SOSCircleConcordanceSign(SOSCircleRef circle, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
325 bool success = false;
326 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
327 require_quiet(ourKey, exit);
328
329 success = SOSCircleSign(circle, ourKey, error);
330
331exit:
332 CFReleaseNull(ourKey);
333 return success;
334}
335
336static inline SOSConcordanceStatus CheckPeerStatus(SOSCircleRef circle, SOSPeerInfoRef peer, CFErrorRef *error) {
337 SOSConcordanceStatus result = kSOSConcordanceNoPeer;
338 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(peer);
339
340 require_action_quiet(SOSCircleHasActivePeer(circle, peer, error), exit, result = kSOSConcordanceNoPeer);
341 require_action_quiet(SOSCircleVerifySignatureExists(circle, pubKey, error), exit, result = kSOSConcordanceNoPeerSig);
342 require_action_quiet(SOSCircleVerify(circle, pubKey, error), exit, result = kSOSConcordanceBadPeerSig);
343
344 result = kSOSConcordanceTrusted;
345
346exit:
347 CFReleaseNull(pubKey);
348 return result;
349}
350
351static inline SOSConcordanceStatus CombineStatus(SOSConcordanceStatus status1, SOSConcordanceStatus status2)
352{
353 if (status1 == kSOSConcordanceTrusted || status2 == kSOSConcordanceTrusted)
354 return kSOSConcordanceTrusted;
355
356 if (status1 == kSOSConcordanceBadPeerSig || status2 == kSOSConcordanceBadPeerSig)
357 return kSOSConcordanceBadPeerSig;
358
359 if (status1 == kSOSConcordanceNoPeerSig || status2 == kSOSConcordanceNoPeerSig)
360 return kSOSConcordanceNoPeerSig;
361
362 return status1;
363}
364
365static inline bool SOSCircleIsEmpty(SOSCircleRef circle) {
366 return SOSCircleCountPeers(circle) == 0;
367}
368
369static inline bool SOSCircleIsOffering(SOSCircleRef circle) {
370 return SOSCircleCountPeers(circle) == 1;
371}
372
373static inline bool SOSCircleIsResignOffering(SOSCircleRef circle, SecKeyRef pubkey) {
374 return SOSCircleCountActiveValidPeers(circle, pubkey) == 1;
375}
376
377static inline SOSConcordanceStatus GetSignersStatus(SOSCircleRef signers_circle, SOSCircleRef status_circle,
378 SecKeyRef user_pubKey, SOSPeerInfoRef exclude, CFErrorRef *error) {
379 CFStringRef excluded_id = exclude ? SOSPeerInfoGetPeerID(exclude) : NULL;
380
381 __block SOSConcordanceStatus status = kSOSConcordanceNoPeer;
382 SOSCircleForEachActiveValidPeer(signers_circle, user_pubKey, ^(SOSPeerInfoRef peer) {
383 SOSConcordanceStatus peerStatus = CheckPeerStatus(status_circle, peer, error);
384
385 if (peerStatus == kSOSConcordanceNoPeerSig &&
386 (CFEqualSafe(SOSPeerInfoGetPeerID(peer), excluded_id) || SOSPeerInfoIsCloudIdentity(peer)))
387 peerStatus = kSOSConcordanceNoPeer;
388
389 status = CombineStatus(status, peerStatus); // TODO: Use multiple error gathering.
390 });
391
392 return status;
393}
394
395static inline bool isOlderGeneration(SOSCircleRef current, SOSCircleRef proposed) {
396 return CFNumberCompare(current->generation, proposed->generation, NULL) == kCFCompareGreaterThan;
397}
398
399bool SOSCircleSharedTrustedPeers(SOSCircleRef current, SOSCircleRef proposed, SOSPeerInfoRef me) {
400 __block bool retval = false;
401 SOSCircleForEachPeer(current, ^(SOSPeerInfoRef peer) {
402 if(!CFEqual(me, peer) && SOSCircleHasPeer(proposed, peer, NULL)) retval = true;
403 });
404 return retval;
405}
406
407static void SOSCircleUpgradePeersByCircle(SOSCircleRef known_circle, SOSCircleRef proposed_circle) {
408 SOSCircleForEachPeer(known_circle, ^(SOSPeerInfoRef known_peer) {
409 SOSPeerInfoRef proposed_peer = SOSCircleCopyPeerInfo(proposed_circle, SOSPeerInfoGetPeerID(known_peer), NULL);
410 if(proposed_peer && CFEqualSafe(proposed_peer, known_peer) != 0) {
411 SOSCircleUpdatePeerInfo(known_circle, proposed_peer);
412 }
413 });
414}
415
416SOSConcordanceStatus SOSCircleConcordanceTrust(SOSCircleRef known_circle, SOSCircleRef proposed_circle,
417 SecKeyRef known_pubkey, SecKeyRef user_pubkey,
418 SOSPeerInfoRef exclude, CFErrorRef *error) {
419
420 if(user_pubkey == NULL) {
421 SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Concordance with no public key"), NULL, error);
422 return kSOSConcordanceNoUserKey; //TODO: - needs to return an error
423 }
424
425 if (SOSCircleIsEmpty(proposed_circle)) {
426 return kSOSConcordanceTrusted;
427 }
428
429 if(!SOSCircleVerifySignatureExists(proposed_circle, user_pubkey, error)) {
430 SOSCreateError(kSOSErrorBadSignature, CFSTR("No public signature"), (error != NULL) ? *error : NULL, error);
431 return kSOSConcordanceNoUserSig;
432 }
433
434 if(!SOSCircleVerify(proposed_circle, user_pubkey, error)) {
435 SOSCreateError(kSOSErrorBadSignature, CFSTR("Bad public signature"), (error != NULL) ? *error : NULL, error);
436 return kSOSConcordanceBadUserSig;
437 }
438
439 if (SOSCircleIsEmpty(known_circle) || SOSCircleIsOffering(proposed_circle)) {
440 return GetSignersStatus(proposed_circle, proposed_circle, user_pubkey, NULL, error);
441 }
442
443 if(isOlderGeneration(known_circle, proposed_circle)) {
444 SOSCreateError(kSOSErrorReplay, CFSTR("Bad generation"), NULL, error);
445 return kSOSConcordanceGenOld;
446 }
447
448
449 if(!SOSCircleVerify(known_circle, user_pubkey, error)) {
450 SOSCircleUpgradePeersByCircle(known_circle, proposed_circle);
451 }
452
453 if(known_pubkey == NULL) known_pubkey = user_pubkey;
454 if(!SOSCircleVerify(known_circle, known_pubkey, error)) known_pubkey = user_pubkey;
455 return GetSignersStatus(known_circle, proposed_circle, known_pubkey, exclude, error);
456}
457
458
459static const uint8_t* der_decode_mutable_dictionary(CFAllocatorRef allocator, CFOptionFlags mutability,
460 CFMutableDictionaryRef* dictionary, CFErrorRef *error,
461 const uint8_t* der, const uint8_t *der_end)
462{
463 CFDictionaryRef theDict;
464 const uint8_t* result = der_decode_dictionary(allocator, mutability, &theDict, error, der, der_end);
465
466 if (result != NULL)
467 *dictionary = (CFMutableDictionaryRef)theDict;
468
469 return result;
470}
471
472SOSCircleRef SOSCircleCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
473 const uint8_t** der_p, const uint8_t *der_end) {
474 SOSCircleRef cir = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
475
476 const uint8_t *sequence_end;
477
478 cir->name = NULL;
479 cir->generation = NULL;
480 cir->peers = NULL;
481 cir->applicants = NULL;
482 cir->rejected_applicants = NULL;
483 cir->signatures = NULL;
484
485 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
486 require_action_quiet(sequence_end != NULL, fail,
487 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Circle DER"), (error != NULL) ? *error : NULL, error));
488
489 // Version first.
490 uint64_t version = 0;
491 *der_p = ccder_decode_uint64(&version, *der_p, der_end);
492
493 require_action_quiet(version == kOnlyCompatibleVersion, fail,
494 SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("Bad Circle Version"), NULL, error));
495
496 *der_p = der_decode_string(allocator, 0, &cir->name, error, *der_p, sequence_end);
497 *der_p = der_decode_number(allocator, 0, &cir->generation, error, *der_p, sequence_end);
498
499 cir->peers = SOSPeerInfoArrayCreateFromDER(allocator, error, der_p, sequence_end);
500 cir->applicants = SOSPeerInfoArrayCreateFromDER(allocator, error, der_p, sequence_end);
501 cir->rejected_applicants = SOSPeerInfoArrayCreateFromDER(allocator, error, der_p, sequence_end);
502
503 *der_p = der_decode_mutable_dictionary(allocator, kCFPropertyListMutableContainersAndLeaves,
504 &cir->signatures, error, *der_p, sequence_end);
505
506 require_action_quiet(*der_p == sequence_end, fail,
507 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Circle DER"), (error != NULL) ? *error : NULL, error));
508
509 return cir;
510
511fail:
512 CFReleaseNull(cir);
513 return NULL;
514}
515
516SOSCircleRef SOSCircleCreateFromData(CFAllocatorRef allocator, CFDataRef circleData, CFErrorRef *error)
517{
518 size_t size = CFDataGetLength(circleData);
519 const uint8_t *der = CFDataGetBytePtr(circleData);
520 SOSCircleRef inflated = SOSCircleCreateFromDER(allocator, error, &der, der + size);
521 return inflated;
522}
523
524size_t SOSCircleGetDEREncodedSize(SOSCircleRef cir, CFErrorRef *error) {
525 SOSCircleAssertStable(cir);
526 size_t total_payload = 0;
527
528 require_quiet(accumulate_size(&total_payload, ccder_sizeof_uint64(kOnlyCompatibleVersion)), fail);
529 require_quiet(accumulate_size(&total_payload, der_sizeof_string(cir->name, error)), fail);
530 require_quiet(accumulate_size(&total_payload, der_sizeof_number(cir->generation, error)), fail);
531 require_quiet(accumulate_size(&total_payload, SOSPeerInfoArrayGetDEREncodedSize(cir->peers, error)), fail);
532 require_quiet(accumulate_size(&total_payload, SOSPeerInfoArrayGetDEREncodedSize(cir->applicants, error)), fail);
533 require_quiet(accumulate_size(&total_payload, SOSPeerInfoArrayGetDEREncodedSize(cir->rejected_applicants, error)), fail);
534 require_quiet(accumulate_size(&total_payload, der_sizeof_dictionary((CFDictionaryRef) cir->signatures, error)), fail);
535
536 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, total_payload);
537
538fail:
539 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
540 return 0;
541}
542
543uint8_t* SOSCircleEncodeToDER(SOSCircleRef cir, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) {
544 SOSCircleAssertStable(cir);
545
546 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
547 ccder_encode_uint64(kOnlyCompatibleVersion, der,
548 der_encode_string(cir->name, error, der,
549 der_encode_number(cir->generation, error, der,
550 SOSPeerInfoArrayEncodeToDER(cir->peers, error, der,
551 SOSPeerInfoArrayEncodeToDER(cir->applicants, error, der,
552 SOSPeerInfoArrayEncodeToDER(cir->rejected_applicants, error, der,
553 der_encode_dictionary((CFDictionaryRef) cir->signatures, error, der, der_end))))))));
554}
555
556CFDataRef SOSCircleCreateIncompatibleCircleDER(CFErrorRef* error)
557{
558 size_t total_payload = 0;
559 size_t encoded_size = 0;
560 uint8_t* der = 0;
561 uint8_t* der_end = 0;
562 CFMutableDataRef result = NULL;
563
564 require_quiet(accumulate_size(&total_payload, ccder_sizeof_uint64(kAlwaysIncompatibleVersion)), fail);
565
566 encoded_size = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, total_payload);
567
568 result = CFDataCreateMutableWithScratch(kCFAllocatorDefault, encoded_size);
569
570 der = CFDataGetMutableBytePtr(result);
571 der_end = der + CFDataGetLength(result);
572
573 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
574 ccder_encode_uint64(kAlwaysIncompatibleVersion, der, der_end));
575
576fail:
577 if (der == NULL || der != der_end)
578 CFReleaseNull(result);
579
580 return result;
581}
582
583
584CFDataRef SOSCircleCopyEncodedData(SOSCircleRef circle, CFAllocatorRef allocator, CFErrorRef *error)
585{
586 size_t size = SOSCircleGetDEREncodedSize(circle, error);
587 if (size == 0)
588 return NULL;
589 uint8_t buffer[size];
590 uint8_t* start = SOSCircleEncodeToDER(circle, error, buffer, buffer + sizeof(buffer));
591 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
592 return result;
593}
594
595static void SOSCircleDestroy(CFTypeRef aObj) {
596 SOSCircleRef c = (SOSCircleRef) aObj;
597
598 CFReleaseNull(c->name);
599 CFReleaseNull(c->generation);
600 CFReleaseNull(c->peers);
601 CFReleaseNull(c->applicants);
602 CFReleaseNull(c->rejected_applicants);
603 CFReleaseNull(c->signatures);
604}
605
606static CFStringRef SOSCircleCopyDescription(CFTypeRef aObj) {
607 SOSCircleRef c = (SOSCircleRef) aObj;
608
609 SOSCircleAssertStable(c);
610
611 return CFStringCreateWithFormat(NULL, NULL,
612 CFSTR("<SOSCircle@%p: [ \nName: %@, \nPeers: %@,\nApplicants: %@,\nRejects: %@,\nSignatures: %@\n ] >"),
613 c, c->name, c->peers, c->applicants, c->rejected_applicants, c->signatures);
614}
615
616CFStringRef SOSCircleGetName(SOSCircleRef circle) {
617 assert(circle);
618 assert(circle->name);
619 return circle->name;
620}
621
622const char *SOSCircleGetNameC(SOSCircleRef circle) {
623 CFStringRef name = SOSCircleGetName(circle);
624 if (!name)
625 return strdup("");
626 return CFStringToCString(name);
627}
628
629CFNumberRef SOSCircleGetGeneration(SOSCircleRef circle) {
630 assert(circle);
631 assert(circle->generation);
632 return circle->generation;
633}
634
635int64_t SOSCircleGetGenerationSint(SOSCircleRef circle) {
636 CFNumberRef gen = SOSCircleGetGeneration(circle);
637 int64_t value;
638 if(!gen) return 0;
639 CFNumberGetValue(gen, kCFNumberSInt64Type, &value);
640 return value;
641}
642
643void SOSCircleGenerationIncrement(SOSCircleRef circle) {
644 CFAllocatorRef allocator = CFGetAllocator(circle->generation);
645 int64_t value = SOSCircleGetGenerationSint(circle);
646 value++;
647 circle->generation = CFNumberCreate(allocator, kCFNumberSInt64Type, &value);
648}
649
650int SOSCircleCountPeers(SOSCircleRef circle) {
651 SOSCircleAssertStable(circle);
652 __block int count = 0;
653 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
654 ++count;
655 });
656 return count;
657}
658
659int SOSCircleCountActivePeers(SOSCircleRef circle) {
660 SOSCircleAssertStable(circle);
661 __block int count = 0;
662 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
663 ++count;
664 });
665 return count;
666}
667
668int SOSCircleCountActiveValidPeers(SOSCircleRef circle, SecKeyRef pubkey) {
669 SOSCircleAssertStable(circle);
670 __block int count = 0;
671 SOSCircleForEachActiveValidPeer(circle, pubkey, ^(SOSPeerInfoRef peer) {
672 ++count;
673 });
674 return count;
675}
676
677int SOSCircleCountRetiredPeers(SOSCircleRef circle) {
678 SOSCircleAssertStable(circle);
679 __block int count = 0;
680 SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) {
681 ++count;
682 });
683 return count;
684}
685
686int SOSCircleCountApplicants(SOSCircleRef circle) {
687 SOSCircleAssertStable(circle);
688
689 return (int)CFArrayGetCount(circle->applicants);
690}
691
692bool SOSCircleHasApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
693 SOSCircleAssertStable(circle);
694
695 return CFArrayHasValueMatching(circle->applicants, ^bool(const void *value) {
696 return SOSPeerInfoCompareByID(value, peerInfo, NULL) == 0;
697 });
698}
699
700CFMutableArrayRef SOSCircleCopyApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
701 SOSCircleAssertStable(circle);
702
703 return CFArrayCreateMutableCopy(allocator, 0, circle->applicants);
704}
705
706int SOSCircleCountRejectedApplicants(SOSCircleRef circle) {
707 SOSCircleAssertStable(circle);
708
709 return (int)CFArrayGetCount(circle->rejected_applicants);
710}
711
712bool SOSCircleHasRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
713 SOSCircleAssertStable(circle);
714
715 return CFArrayHasValueMatching(circle->rejected_applicants, ^bool(const void *value) {
716 return SOSPeerInfoCompareByID(value, peerInfo, NULL) == 0;
717 });
718}
719
720SOSPeerInfoRef SOSCircleCopyRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
721 SOSCircleAssertStable(circle);
722 return (SOSPeerInfoRef) CFArrayGetValueMatching(circle->rejected_applicants, ^bool(const void *value) {
723 return SOSPeerInfoCompareByID(value, peerInfo, NULL) == 0;
724 });
725}
726
727CFMutableArrayRef SOSCircleCopyRejectedApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
728 SOSCircleAssertStable(circle);
729
730 return CFArrayCreateMutableCopy(allocator, 0, circle->rejected_applicants);
731}
732
733
734bool SOSCircleHasPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
735 SOSCircleAssertStable(circle);
736 __block bool found = false;
737 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
738 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = true;
739 });
740 return found;
741}
742
743bool SOSCircleHasPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
744 return SOSCircleHasPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
745}
746
747bool SOSCircleHasActivePeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
748 SOSCircleAssertStable(circle);
749 __block bool found = false;
750 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
751 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = true;
752 });
753 return found;
754}
755
756bool SOSCircleHasActivePeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
757 if(!peerInfo) return false;
758 return SOSCircleHasActivePeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
759}
760
761
762
763bool SOSCircleResetToEmpty(SOSCircleRef circle, CFErrorRef *error) {
764 CFArrayRemoveAllValues(circle->applicants);
765 CFArrayRemoveAllValues(circle->peers);
766 CFDictionaryRemoveAllValues(circle->signatures);
767
768 return true;
769}
770
771bool SOSCircleResetToOffering(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error){
772
773 return SOSCircleResetToEmpty(circle, error)
774 && SOSCircleRequestAdmission(circle, user_privkey, requestor, error)
775 && SOSCircleAcceptRequest(circle, user_privkey, requestor, SOSFullPeerInfoGetPeerInfo(requestor), error);
776}
777
778CFIndex SOSCircleRemoveRetired(SOSCircleRef circle, CFErrorRef *error) {
779 CFIndex n = CFArrayRemoveAllPassing(circle->peers, ^ bool (const void *element) {
780 SOSPeerInfoRef peer = (SOSPeerInfoRef) element;
781
782 return SOSPeerInfoIsRetirementTicket(peer);
783 });
784
785 return n;
786}
787
788static bool SOSCircleRecordAdmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
789 SOSCircleAssertStable(circle);
790
791 bool isPeer = SOSCircleHasPeer(circle, SOSFullPeerInfoGetPeerInfo(requestor), error);
792
793 require_action_quiet(!isPeer, fail, SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Cannot request admission when already a peer"), NULL, error));
794
795 CFIndex total = CFArrayRemoveAllWithMatchingID(circle->applicants, SOSFullPeerInfoGetPeerInfo(requestor));
796
797 (void) total; // Suppress unused warning in release code.
798 assert(total <= 1); // We should at most be in the list once.
799
800 total = CFArrayRemoveAllWithMatchingID(circle->rejected_applicants, SOSFullPeerInfoGetPeerInfo(requestor));
801
802 (void) total; // Suppress unused warning in release code.
803 assert(total <= 1); // We should at most be in the list once.
804
805
806 // Refetch the current PeerInfo as the promtion above can change it.
807 CFArrayAppendValue(circle->applicants, SOSFullPeerInfoGetPeerInfo(requestor));
808
809 return true;
810
811fail:
812 return false;
813
814}
815
816bool SOSCircleRequestReadmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
817 bool success = false;
818
819 SOSPeerInfoRef peer = SOSFullPeerInfoGetPeerInfo(requestor);
820 require_quiet(SOSPeerInfoApplicationVerify(peer, user_pubkey, error), fail);
821 success = SOSCircleRecordAdmission(circle, user_pubkey, requestor, error);
822fail:
823 return success;
824}
825
826bool SOSCircleRequestAdmission(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
827 bool success = false;
828
829 SecKeyRef user_pubkey = SecKeyCreatePublicFromPrivate(user_privkey);
830 require_action_quiet(user_pubkey, fail, SOSCreateError(kSOSErrorBadKey, CFSTR("No public key for key"), NULL, error));
831
832 require(SOSFullPeerInfoPromoteToApplication(requestor, user_privkey, error), fail);
833
834 success = SOSCircleRecordAdmission(circle, user_pubkey, requestor, error);
835fail:
836 CFReleaseNull(user_pubkey);
837 return success;
838}
839
840
841bool SOSCircleUpdatePeerInfo(SOSCircleRef circle, SOSPeerInfoRef replacement_peer_info) {
842 __block bool replaced = false;
843 CFStringRef replacement_peer_id = SOSPeerInfoGetPeerID(replacement_peer_info);
844
845 CFMutableArrayModifyValues(circle->peers, ^const void *(const void *value) {
846 if (CFEqual(replacement_peer_id, SOSPeerInfoGetPeerID((SOSPeerInfoRef) value))
847 && !CFEqual(replacement_peer_info, value)) {
848 replaced = true;
849 return replacement_peer_info;
850 }
851
852 return value;
853 });
854 return replaced;
855}
856
857bool SOSCircleRemovePeer(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, SOSPeerInfoRef peer_to_remove, CFErrorRef *error) {
858 SOSPeerInfoRef requestor_peer_info = SOSFullPeerInfoGetPeerInfo(requestor);
859
860 if (SOSCircleHasApplicant(circle, peer_to_remove, error)) {
861 return SOSCircleRejectRequest(circle, requestor, peer_to_remove, error);
862 }
863
864 if (!SOSCircleHasPeer(circle, requestor_peer_info, error)) {
865 SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Must be peer to remove peer"), NULL, error);
866 return false;
867 }
868
869 CFArrayRemoveAllWithMatchingID(circle->peers, peer_to_remove);
870
871 SOSCircleGenerationSign(circle, user_privkey, requestor, error);
872
873 return true;
874}
875
876bool SOSCircleAcceptRequest(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
877 SOSCircleAssertStable(circle);
878
879 CFIndex total = CFArrayRemoveAllWithMatchingID(circle->applicants, peerInfo);
880 SecKeyRef publicKey = NULL;
881 bool result = false;
882
883 require_action_quiet(total != 0, fail,
884 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot accept non-applicant"), NULL, error));
885
886 publicKey = SecKeyCreatePublicFromPrivate(user_privkey);
887 require_quiet(SOSPeerInfoApplicationVerify(peerInfo, publicKey, error), fail);
888
889 assert(total == 1);
890
891 CFArrayAppendValue(circle->peers, peerInfo);
892 result = SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
893 secnotice("circle", "Accepted %@", peerInfo);
894
895fail:
896 CFReleaseNull(publicKey);
897 return result;
898}
899
900bool SOSCircleWithdrawRequest(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
901 SOSCircleAssertStable(circle);
902
903#ifndef NDEBUG
904 CFIndex total =
905#endif
906 CFArrayRemoveAllWithMatchingID(circle->applicants, peerInfo);
907
908 assert(total <= 1);
909
910 return true;
911}
912
913bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
914 SOSCircleAssertStable(circle);
915
916#ifndef NDEBUG
917 CFIndex total =
918#endif
919 CFArrayRemoveAllWithMatchingID(circle->rejected_applicants, peerInfo);
920
921 assert(total <= 1);
922
923 return true;
924}
925
926
927bool SOSCircleRejectRequest(SOSCircleRef circle, SOSFullPeerInfoRef device_rejector,
928 SOSPeerInfoRef peerInfo, CFErrorRef *error) {
929 SOSCircleAssertStable(circle);
930
931 if (CFEqual(SOSPeerInfoGetPeerID(peerInfo), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector))))
932 return SOSCircleWithdrawRequest(circle, peerInfo, error);
933
934 CFIndex total = CFArrayRemoveAllWithMatchingID(circle->applicants, peerInfo);
935
936 if (total == 0) {
937 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot reject non-applicant"), NULL, error);
938 return false;
939 }
940 assert(total == 1);
941
942 CFArrayAppendValue(circle->rejected_applicants, peerInfo);
943
944 // TODO: Maybe we sign the rejection with device_rejector.
945
946 return true;
947}
948
949bool SOSCircleAcceptRequests(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver,
950 CFErrorRef *error) {
951 // Returns true if we accepted someone and therefore have to post the circle back to KVS
952 __block bool result = false;
953
954 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
955 if (!SOSCircleAcceptRequest(circle, user_privkey, device_approver, peer, error))
956 printf("error in SOSCircleAcceptRequest\n");
957 else {
958 secnotice("circle", "Accepted peer: %@", peer);
959 result = true;
960 }
961 });
962
963 if (result) {
964 SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
965 secnotice("circle", "Countersigned accepted requests");
966 }
967
968 return result;
969}
970
971bool SOSCirclePeerSigUpdate(SOSCircleRef circle, SecKeyRef userPrivKey, SOSFullPeerInfoRef fpi,
972 CFErrorRef *error) {
973 // Returns true if we accepted someone and therefore have to post the circle back to KVS
974 __block bool result = false;
975 SecKeyRef userPubKey = SecKeyCreatePublicFromPrivate(userPrivKey);
976
977 // We're going to remove any applicants using a mismatched user key.
978 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
979 if(!SOSPeerInfoApplicationVerify(peer, userPubKey, NULL)) {
980 if(!SOSCircleRejectRequest(circle, fpi, peer, NULL)) {
981 // do we care?
982 }
983 }
984 });
985
986 result = SOSCircleUpdatePeerInfo(circle, SOSFullPeerInfoGetPeerInfo(fpi));
987
988 if (result) {
989 SOSCircleGenerationSign(circle, userPrivKey, fpi, error);
990 secnotice("circle", "Generation signed updated signatures on peerinfo");
991 }
992
993 return result;
994}
995
996SOSPeerInfoRef SOSCircleCopyPeerInfo(SOSCircleRef circle, CFStringRef peer_id, CFErrorRef *error) {
997 __block SOSPeerInfoRef result = NULL;
998
999 CFArrayForEach(circle->peers, ^(const void *value) {
1000 if (result == NULL) {
1001 SOSPeerInfoRef tpi = (SOSPeerInfoRef)value;
1002 if (CFEqual(SOSPeerInfoGetPeerID(tpi), peer_id))
1003 result = tpi;
1004 }
1005 });
1006
1007 CFRetainSafe(result);
1008 return result;
1009}
1010
1011
1012static inline void SOSCircleForEachPeerMatching(SOSCircleRef circle,
1013 void (^action)(SOSPeerInfoRef peer),
1014 bool (^condition)(SOSPeerInfoRef peer)) {
1015 CFArrayForEach(circle->peers, ^(const void *value) {
1016 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
1017 if (condition(peer))
1018 action(peer);
1019 });
1020}
1021
1022void SOSCircleForEachPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1023 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1024 return !SOSPeerInfoIsRetirementTicket(peer) && !SOSPeerInfoIsCloudIdentity(peer);
1025 });
1026}
1027
1028void SOSCircleForEachRetiredPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1029 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1030 return SOSPeerInfoIsRetirementTicket(peer);
1031 });
1032}
1033
1034void SOSCircleForEachActivePeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1035 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1036 return true;
1037 });
1038}
1039
1040void SOSCircleForEachActiveValidPeer(SOSCircleRef circle, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)) {
1041 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1042 return SOSPeerInfoApplicationVerify(peer, user_public_key, NULL);
1043 });
1044}
1045
1046void SOSCircleForEachApplicant(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1047 CFArrayForEach(circle->applicants, ^(const void*value) { action((SOSPeerInfoRef) value); } );
1048}
1049
1050
1051CFMutableArrayRef SOSCircleCopyPeers(SOSCircleRef circle, CFAllocatorRef allocator) {
1052 SOSCircleAssertStable(circle);
1053
1054 CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(allocator);
1055
1056 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
1057 CFArrayAppendValue(result, peer);
1058 });
1059
1060 return result;
1061}
1062
1063CFMutableArrayRef SOSCircleCopyConcurringPeers(SOSCircleRef circle, CFErrorRef* error) {
1064 SOSCircleAssertStable(circle);
1065
1066 CFMutableArrayRef concurringPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
1067
1068 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1069 CFErrorRef error = NULL;
1070 if (SOSCircleVerifyPeerSigned(circle, peer, &error)) {
1071 CFArrayAppendValue(concurringPeers, peer);
1072 } else if (error != NULL) {
1073 secerror("Error checking concurrence: %@", error);
1074 }
1075 CFReleaseNull(error);
1076 });
1077
1078 return concurringPeers;
1079}
1080
1081
1082//
1083// Stuff above this line is really SOSCircleInfo below the line is the active SOSCircle functionality
1084//
1085
1086static SOSPeerRef SOSCircleCopyPeer(SOSCircleRef circle, SOSFullPeerInfoRef myRef, SOSPeerSendBlock sendBlock,
1087 CFStringRef peer_id, CFErrorRef *error) {
1088 SOSPeerRef peer = NULL;
1089 SOSPeerInfoRef peer_info = SOSCircleCopyPeerInfo(circle, peer_id, error);
1090 //TODO: if (peer is legit member of us then good otherwise bail) {
1091 //}
1092 if (peer_info) {
1093 peer = SOSPeerCreate(myRef, peer_info, error, sendBlock);
1094 CFReleaseNull(peer_info);
1095 }
1096 return peer;
1097}
1098
1099
1100static bool SOSCircleDoWithPeer(SOSFullPeerInfoRef myRef, SOSCircleRef circle, SOSDataSourceFactoryRef factory,
1101 SOSPeerSendBlock sendBlock, CFStringRef peer_id, bool readOnly,
1102 CFErrorRef* error, bool (^do_action)(SOSEngineRef engine, SOSPeerRef peer, CFErrorRef *error))
1103{
1104 bool success = false;
1105 SOSEngineRef engine = NULL;
1106 SOSPeerRef peer = NULL;
1107 SOSDataSourceRef ds = NULL;
1108
1109 peer = SOSCircleCopyPeer(circle, myRef, sendBlock, peer_id, error);
1110 require(peer, exit);
1111
1112 ds = factory->create_datasource(factory, SOSCircleGetName(circle), readOnly, error);
1113 require(ds, exit);
1114
1115 engine = SOSEngineCreate(ds, error); // Hand off DS to engine.
1116 ds = NULL;
1117 require(engine, exit);
1118
1119 success = do_action(engine, peer, error);
1120
1121exit:
1122 if (ds)
1123 ds->release(ds);
1124 if (engine)
1125 SOSEngineDispose(engine);
1126 if (peer)
1127 SOSPeerDispose(peer);
1128
1129 return success;
1130}
1131
1132bool SOSCircleSyncWithPeer(SOSFullPeerInfoRef myRef, SOSCircleRef circle, SOSDataSourceFactoryRef factory,
1133 SOSPeerSendBlock sendBlock, CFStringRef peer_id,
1134 CFErrorRef *error)
1135{
1136 return SOSCircleDoWithPeer(myRef, circle, factory, sendBlock, peer_id, true, error, ^bool(SOSEngineRef engine, SOSPeerRef peer, CFErrorRef *error) {
1137 return SOSPeerStartSync(peer, engine, error) != kSOSPeerCoderFailure;
1138 });
1139}
1140
1141bool SOSCircleHandlePeerMessage(SOSCircleRef circle, SOSFullPeerInfoRef myRef, SOSDataSourceFactoryRef factory,
1142 SOSPeerSendBlock sendBlock, CFStringRef peer_id,
1143 CFDataRef message, CFErrorRef *error) {
1144 return SOSCircleDoWithPeer(myRef, circle, factory, sendBlock, peer_id, false, error, ^bool(SOSEngineRef engine, SOSPeerRef peer, CFErrorRef *error) {
1145 return SOSPeerHandleMessage(peer, engine, message, error) != kSOSPeerCoderFailure;
1146 });
1147}
1148
1149
1150SOSFullPeerInfoRef SOSCircleGetiCloudFullPeerInfoRef(SOSCircleRef circle) {
1151 __block SOSFullPeerInfoRef cloud_full_peer = NULL;
1152 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1153 if (SOSPeerInfoIsCloudIdentity(peer)) {
1154 if (cloud_full_peer == NULL) {
1155 CFErrorRef localError = NULL;
1156 cloud_full_peer = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, &localError);
1157
1158 if (localError) {
1159 secerror("Found cloud peer in circle but can't make full peer: %@", localError);
1160 CFReleaseNull(localError);
1161 }
1162
1163 } else {
1164 secerror("More than one cloud identity found in circle: %@", circle);
1165 }
1166 }
1167 });
1168 return cloud_full_peer;
1169}
1170
1171
1172