]> git.saurik.com Git - apple/security.git/blob - sec/SOSCircle/SecureObjectSync/SOSCircle.c
9475fc64fe71d40f34eb5a6467f7d4566c9520a1
[apple/security.git] / sec / SOSCircle / SecureObjectSync / SOSCircle.c
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
37 enum {
38 kOnlyCompatibleVersion = 1, // Sometime in the future this name will be improved to reflect history.
39
40 kAlwaysIncompatibleVersion = UINT64_MAX,
41 };
42
43 struct __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
55 CFGiblisWithCompareFor(SOSCircle);
56
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);
60 }
61
62 static const CFDictionaryValueCallBacks dispose_peer_callbacks = { .release = SOSPeerRelease };
63
64 SOSCircleRef 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
80 static 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
87 SOSCircleRef 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
102 static inline
103 void 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
114 static inline
115 SOSCircleRef 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
128 static 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
146 static 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
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);
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
175 static 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
183 fail:
184 CFReleaseSafe(pubKeyID);
185 return result;
186 }
187
188 static bool SOSCircleRemoveSignatures(SOSCircleRef circle, CFErrorRef *error) {
189 CFDictionaryRemoveAllValues(circle->signatures);
190 return true;
191 }
192
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);
197
198 CFTypeRef value = (CFDataRef)CFDictionaryGetValue(circle->signatures, pubKeyID);
199
200 if (isData(value)) result = (CFDataRef) value;
201
202 fail:
203 CFReleaseSafe(pubKeyID);
204 return result;
205 }
206
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);
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
231 bool 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
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];
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
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);
259 return result;
260 }
261
262
263 static 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
280 static CFIndex CFArrayRemoveAllWithMatchingID(CFMutableArrayRef array, SOSPeerInfoRef peerInfo) {
281 CFStringRef peer_id = SOSPeerInfoGetPeerID(peerInfo);
282
283 return CFArrayRemoveAllPassing(array, ^ bool (const void *element) {
284 SOSPeerInfoRef peer = (SOSPeerInfoRef) element;
285
286 return CFEqual(peer_id, SOSPeerInfoGetPeerID(peer));
287 });
288 }
289
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);
297 }
298 });
299 }
300
301 bool SOSCircleGenerationSign(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
302
303 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
304 require_quiet(ourKey, fail);
305
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);
313
314 CFReleaseNull(ourKey);
315 return true;
316
317 fail:
318 CFReleaseNull(ourKey);
319 return false;
320 }
321
322
323 bool SOSCircleConcordanceSign(SOSCircleRef circle, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
324 bool success = false;
325 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
326 require_quiet(ourKey, exit);
327
328 success = SOSCircleSign(circle, ourKey, error);
329
330 exit:
331 CFReleaseNull(ourKey);
332 return success;
333 }
334
335 static inline SOSConcordanceStatus CheckPeerStatus(SOSCircleRef circle, SOSPeerInfoRef peer, CFErrorRef *error) {
336 SOSConcordanceStatus result = kSOSConcordanceNoPeer;
337 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(peer);
338
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);
342
343 result = kSOSConcordanceTrusted;
344
345 exit:
346 CFReleaseNull(pubKey);
347 return result;
348 }
349
350 static inline SOSConcordanceStatus CombineStatus(SOSConcordanceStatus status1, SOSConcordanceStatus status2)
351 {
352 if (status1 == kSOSConcordanceTrusted || status2 == kSOSConcordanceTrusted)
353 return kSOSConcordanceTrusted;
354
355 if (status1 == kSOSConcordanceBadPeerSig || status2 == kSOSConcordanceBadPeerSig)
356 return kSOSConcordanceBadPeerSig;
357
358 if (status1 == kSOSConcordanceNoPeerSig || status2 == kSOSConcordanceNoPeerSig)
359 return kSOSConcordanceNoPeerSig;
360
361 return status1;
362 }
363
364 static inline bool SOSCircleIsEmpty(SOSCircleRef circle) {
365 return SOSCircleCountPeers(circle) == 0;
366 }
367
368 static inline bool SOSCircleIsOffering(SOSCircleRef circle) {
369 return SOSCircleCountPeers(circle) == 1;
370 }
371
372 static inline bool SOSCircleIsResignOffering(SOSCircleRef circle, SecKeyRef pubkey) {
373 return SOSCircleCountActiveValidPeers(circle, pubkey) == 1;
374 }
375
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;
379
380 __block SOSConcordanceStatus status = kSOSConcordanceNoPeer;
381 SOSCircleForEachActiveValidPeer(signers_circle, user_pubKey, ^(SOSPeerInfoRef peer) {
382 SOSConcordanceStatus peerStatus = CheckPeerStatus(status_circle, peer, error);
383
384 if (peerStatus == kSOSConcordanceNoPeerSig &&
385 (CFEqualSafe(SOSPeerInfoGetPeerID(peer), excluded_id) || SOSPeerInfoIsCloudIdentity(peer)))
386 peerStatus = kSOSConcordanceNoPeer;
387
388 status = CombineStatus(status, peerStatus); // TODO: Use multiple error gathering.
389 });
390
391 return status;
392 }
393
394 static inline bool isOlderGeneration(SOSCircleRef current, SOSCircleRef proposed) {
395 return CFNumberCompare(current->generation, proposed->generation, NULL) == kCFCompareGreaterThan;
396 }
397
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;
402 });
403 return retval;
404 }
405
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);
411 }
412 });
413 }
414
415 SOSConcordanceStatus SOSCircleConcordanceTrust(SOSCircleRef known_circle, SOSCircleRef proposed_circle,
416 SecKeyRef known_pubkey, SecKeyRef user_pubkey,
417 SOSPeerInfoRef exclude, CFErrorRef *error) {
418
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
422 }
423
424 if (SOSCircleIsEmpty(proposed_circle)) {
425 return kSOSConcordanceTrusted;
426 }
427
428 if(!SOSCircleVerifySignatureExists(proposed_circle, user_pubkey, error)) {
429 SOSCreateError(kSOSErrorBadSignature, CFSTR("No public signature"), (error != NULL) ? *error : NULL, error);
430 return kSOSConcordanceNoUserSig;
431 }
432
433 if(!SOSCircleVerify(proposed_circle, user_pubkey, error)) {
434 SOSCreateError(kSOSErrorBadSignature, CFSTR("Bad public signature"), (error != NULL) ? *error : NULL, error);
435 return kSOSConcordanceBadUserSig;
436 }
437
438 if (SOSCircleIsEmpty(known_circle) || SOSCircleIsOffering(proposed_circle)) {
439 return GetSignersStatus(proposed_circle, proposed_circle, user_pubkey, NULL, error);
440 }
441
442 if(isOlderGeneration(known_circle, proposed_circle)) {
443 SOSCreateError(kSOSErrorReplay, CFSTR("Bad generation"), NULL, error);
444 return kSOSConcordanceGenOld;
445 }
446
447
448 if(!SOSCircleVerify(known_circle, user_pubkey, error)) {
449 SOSCircleUpgradePeersByCircle(known_circle, proposed_circle);
450 }
451
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);
455 }
456
457
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)
461 {
462 CFDictionaryRef theDict;
463 const uint8_t* result = der_decode_dictionary(allocator, mutability, &theDict, error, der, der_end);
464
465 if (result != NULL)
466 *dictionary = (CFMutableDictionaryRef)theDict;
467
468 return result;
469 }
470
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);
474
475 const uint8_t *sequence_end;
476
477 cir->name = NULL;
478 cir->generation = NULL;
479 cir->peers = NULL;
480 cir->applicants = NULL;
481 cir->rejected_applicants = NULL;
482 cir->signatures = NULL;
483
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));
487
488 // Version first.
489 uint64_t version = 0;
490 *der_p = ccder_decode_uint64(&version, *der_p, der_end);
491
492 require_action_quiet(version == kOnlyCompatibleVersion, fail,
493 SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("Bad Circle Version"), NULL, error));
494
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);
497
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);
501
502 *der_p = der_decode_mutable_dictionary(allocator, kCFPropertyListMutableContainersAndLeaves,
503 &cir->signatures, error, *der_p, sequence_end);
504
505 require_action_quiet(*der_p == sequence_end, fail,
506 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Circle DER"), (error != NULL) ? *error : NULL, error));
507
508 return cir;
509
510 fail:
511 CFReleaseNull(cir);
512 return NULL;
513 }
514
515 SOSCircleRef SOSCircleCreateFromData(CFAllocatorRef allocator, CFDataRef circleData, CFErrorRef *error)
516 {
517 size_t size = CFDataGetLength(circleData);
518 const uint8_t *der = CFDataGetBytePtr(circleData);
519 SOSCircleRef inflated = SOSCircleCreateFromDER(allocator, error, &der, der + size);
520 return inflated;
521 }
522
523 size_t SOSCircleGetDEREncodedSize(SOSCircleRef cir, CFErrorRef *error) {
524 SOSCircleAssertStable(cir);
525 size_t total_payload = 0;
526
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);
534
535 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, total_payload);
536
537 fail:
538 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
539 return 0;
540 }
541
542 uint8_t* SOSCircleEncodeToDER(SOSCircleRef cir, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) {
543 SOSCircleAssertStable(cir);
544
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))))))));
553 }
554
555 CFDataRef SOSCircleCreateIncompatibleCircleDER(CFErrorRef* error)
556 {
557 size_t total_payload = 0;
558 size_t encoded_size = 0;
559 uint8_t* der = 0;
560 uint8_t* der_end = 0;
561 CFMutableDataRef result = NULL;
562
563 require_quiet(accumulate_size(&total_payload, ccder_sizeof_uint64(kAlwaysIncompatibleVersion)), fail);
564
565 encoded_size = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, total_payload);
566
567 result = CFDataCreateMutableWithScratch(kCFAllocatorDefault, encoded_size);
568
569 der = CFDataGetMutableBytePtr(result);
570 der_end = der + CFDataGetLength(result);
571
572 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
573 ccder_encode_uint64(kAlwaysIncompatibleVersion, der, der_end));
574
575 fail:
576 if (der == NULL || der != der_end)
577 CFReleaseNull(result);
578
579 return result;
580 }
581
582
583 CFDataRef SOSCircleCopyEncodedData(SOSCircleRef circle, CFAllocatorRef allocator, CFErrorRef *error)
584 {
585 size_t size = SOSCircleGetDEREncodedSize(circle, error);
586 if (size == 0)
587 return NULL;
588 uint8_t buffer[size];
589 uint8_t* start = SOSCircleEncodeToDER(circle, error, buffer, buffer + sizeof(buffer));
590 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
591 return result;
592 }
593
594 static void SOSCircleDestroy(CFTypeRef aObj) {
595 SOSCircleRef c = (SOSCircleRef) aObj;
596
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);
603 }
604
605 static CFStringRef SOSCircleCopyDescription(CFTypeRef aObj) {
606 SOSCircleRef c = (SOSCircleRef) aObj;
607
608 SOSCircleAssertStable(c);
609
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);
613 }
614
615 CFStringRef SOSCircleGetName(SOSCircleRef circle) {
616 assert(circle);
617 assert(circle->name);
618 return circle->name;
619 }
620
621 const char *SOSCircleGetNameC(SOSCircleRef circle) {
622 CFStringRef name = SOSCircleGetName(circle);
623 if (!name)
624 return strdup("");
625 return CFStringToCString(name);
626 }
627
628 CFNumberRef SOSCircleGetGeneration(SOSCircleRef circle) {
629 assert(circle);
630 assert(circle->generation);
631 return circle->generation;
632 }
633
634 int64_t SOSCircleGetGenerationSint(SOSCircleRef circle) {
635 CFNumberRef gen = SOSCircleGetGeneration(circle);
636 int64_t value;
637 if(!gen) return 0;
638 CFNumberGetValue(gen, kCFNumberSInt64Type, &value);
639 return value;
640 }
641
642 void SOSCircleGenerationIncrement(SOSCircleRef circle) {
643 CFAllocatorRef allocator = CFGetAllocator(circle->generation);
644 int64_t value = SOSCircleGetGenerationSint(circle);
645 value++;
646 circle->generation = CFNumberCreate(allocator, kCFNumberSInt64Type, &value);
647 }
648
649 int SOSCircleCountPeers(SOSCircleRef circle) {
650 SOSCircleAssertStable(circle);
651 __block int count = 0;
652 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
653 ++count;
654 });
655 return count;
656 }
657
658 int SOSCircleCountActivePeers(SOSCircleRef circle) {
659 SOSCircleAssertStable(circle);
660 __block int count = 0;
661 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
662 ++count;
663 });
664 return count;
665 }
666
667 int SOSCircleCountActiveValidPeers(SOSCircleRef circle, SecKeyRef pubkey) {
668 SOSCircleAssertStable(circle);
669 __block int count = 0;
670 SOSCircleForEachActiveValidPeer(circle, pubkey, ^(SOSPeerInfoRef peer) {
671 ++count;
672 });
673 return count;
674 }
675
676 int SOSCircleCountRetiredPeers(SOSCircleRef circle) {
677 SOSCircleAssertStable(circle);
678 __block int count = 0;
679 SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) {
680 ++count;
681 });
682 return count;
683 }
684
685 int SOSCircleCountApplicants(SOSCircleRef circle) {
686 SOSCircleAssertStable(circle);
687
688 return (int)CFArrayGetCount(circle->applicants);
689 }
690
691 bool SOSCircleHasApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
692 SOSCircleAssertStable(circle);
693
694 return CFArrayHasValueMatching(circle->applicants, ^bool(const void *value) {
695 return SOSPeerInfoCompareByID(value, peerInfo, NULL) == 0;
696 });
697 }
698
699 CFMutableArrayRef SOSCircleCopyApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
700 SOSCircleAssertStable(circle);
701
702 return CFArrayCreateMutableCopy(allocator, 0, circle->applicants);
703 }
704
705 int SOSCircleCountRejectedApplicants(SOSCircleRef circle) {
706 SOSCircleAssertStable(circle);
707
708 return (int)CFArrayGetCount(circle->rejected_applicants);
709 }
710
711 bool SOSCircleHasRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
712 SOSCircleAssertStable(circle);
713
714 return CFArrayHasValueMatching(circle->rejected_applicants, ^bool(const void *value) {
715 return SOSPeerInfoCompareByID(value, peerInfo, NULL) == 0;
716 });
717 }
718
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;
723 });
724 }
725
726 CFMutableArrayRef SOSCircleCopyRejectedApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
727 SOSCircleAssertStable(circle);
728
729 return CFArrayCreateMutableCopy(allocator, 0, circle->rejected_applicants);
730 }
731
732
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;
738 });
739 return found;
740 }
741
742 bool SOSCircleHasPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
743 return SOSCircleHasPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
744 }
745
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;
751 });
752 return found;
753 }
754
755 bool SOSCircleHasActivePeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
756 if(!peerInfo) return false;
757 return SOSCircleHasActivePeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
758 }
759
760
761
762 bool SOSCircleResetToEmpty(SOSCircleRef circle, CFErrorRef *error) {
763 CFArrayRemoveAllValues(circle->applicants);
764 CFArrayRemoveAllValues(circle->peers);
765 CFDictionaryRemoveAllValues(circle->signatures);
766
767 return true;
768 }
769
770 bool SOSCircleResetToOffering(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error){
771
772 return SOSCircleResetToEmpty(circle, error)
773 && SOSCircleRequestAdmission(circle, user_privkey, requestor, error)
774 && SOSCircleAcceptRequest(circle, user_privkey, requestor, SOSFullPeerInfoGetPeerInfo(requestor), error);
775 }
776
777 CFIndex SOSCircleRemoveRetired(SOSCircleRef circle, CFErrorRef *error) {
778 CFIndex n = CFArrayRemoveAllPassing(circle->peers, ^ bool (const void *element) {
779 SOSPeerInfoRef peer = (SOSPeerInfoRef) element;
780
781 return SOSPeerInfoIsRetirementTicket(peer);
782 });
783
784 return n;
785 }
786
787 static bool SOSCircleRecordAdmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
788 SOSCircleAssertStable(circle);
789
790 bool isPeer = SOSCircleHasPeer(circle, SOSFullPeerInfoGetPeerInfo(requestor), error);
791
792 require_action_quiet(!isPeer, fail, SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Cannot request admission when already a peer"), NULL, error));
793
794 CFIndex total = CFArrayRemoveAllWithMatchingID(circle->applicants, SOSFullPeerInfoGetPeerInfo(requestor));
795
796 (void) total; // Suppress unused warning in release code.
797 assert(total <= 1); // We should at most be in the list once.
798
799 total = CFArrayRemoveAllWithMatchingID(circle->rejected_applicants, SOSFullPeerInfoGetPeerInfo(requestor));
800
801 (void) total; // Suppress unused warning in release code.
802 assert(total <= 1); // We should at most be in the list once.
803
804
805 // Refetch the current PeerInfo as the promtion above can change it.
806 CFArrayAppendValue(circle->applicants, SOSFullPeerInfoGetPeerInfo(requestor));
807
808 return true;
809
810 fail:
811 return false;
812
813 }
814
815 bool SOSCircleRequestReadmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
816 bool success = false;
817
818 SOSPeerInfoRef peer = SOSFullPeerInfoGetPeerInfo(requestor);
819 require_quiet(SOSPeerInfoApplicationVerify(peer, user_pubkey, error), fail);
820 success = SOSCircleRecordAdmission(circle, user_pubkey, requestor, error);
821 fail:
822 return success;
823 }
824
825 bool SOSCircleRequestAdmission(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
826 bool success = false;
827
828 SecKeyRef user_pubkey = SecKeyCreatePublicFromPrivate(user_privkey);
829 require_action_quiet(user_pubkey, fail, SOSCreateError(kSOSErrorBadKey, CFSTR("No public key for key"), NULL, error));
830
831 require(SOSFullPeerInfoPromoteToApplication(requestor, user_privkey, error), fail);
832
833 success = SOSCircleRecordAdmission(circle, user_pubkey, requestor, error);
834 fail:
835 CFReleaseNull(user_pubkey);
836 return success;
837 }
838
839
840 bool SOSCircleUpdatePeerInfo(SOSCircleRef circle, SOSPeerInfoRef replacement_peer_info) {
841 __block bool replaced = false;
842 CFStringRef replacement_peer_id = SOSPeerInfoGetPeerID(replacement_peer_info);
843
844 CFMutableArrayModifyValues(circle->peers, ^const void *(const void *value) {
845 if (CFEqual(replacement_peer_id, SOSPeerInfoGetPeerID((SOSPeerInfoRef) value))
846 && !CFEqual(replacement_peer_info, value)) {
847 replaced = true;
848 return replacement_peer_info;
849 }
850
851 return value;
852 });
853 return replaced;
854 }
855
856 bool SOSCircleRemovePeer(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, SOSPeerInfoRef peer_to_remove, CFErrorRef *error) {
857 SOSPeerInfoRef requestor_peer_info = SOSFullPeerInfoGetPeerInfo(requestor);
858
859 if (SOSCircleHasApplicant(circle, peer_to_remove, error)) {
860 return SOSCircleRejectRequest(circle, requestor, peer_to_remove, error);
861 }
862
863 if (!SOSCircleHasPeer(circle, requestor_peer_info, error)) {
864 SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Must be peer to remove peer"), NULL, error);
865 return false;
866 }
867
868 CFArrayRemoveAllWithMatchingID(circle->peers, peer_to_remove);
869
870 SOSCircleGenerationSign(circle, user_privkey, requestor, error);
871
872 return true;
873 }
874
875 bool SOSCircleAcceptRequest(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
876 SOSCircleAssertStable(circle);
877
878 CFIndex total = CFArrayRemoveAllWithMatchingID(circle->applicants, peerInfo);
879 SecKeyRef publicKey = NULL;
880 bool result = false;
881
882 require_action_quiet(total != 0, fail,
883 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot accept non-applicant"), NULL, error));
884
885 publicKey = SecKeyCreatePublicFromPrivate(user_privkey);
886 require_quiet(SOSPeerInfoApplicationVerify(peerInfo, publicKey, error), fail);
887
888 assert(total == 1);
889
890 CFArrayAppendValue(circle->peers, peerInfo);
891 result = SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
892 secnotice("circle", "Accepted %@", peerInfo);
893
894 fail:
895 CFReleaseNull(publicKey);
896 return result;
897 }
898
899 bool SOSCircleWithdrawRequest(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
900 SOSCircleAssertStable(circle);
901
902 #ifndef NDEBUG
903 CFIndex total =
904 #endif
905 CFArrayRemoveAllWithMatchingID(circle->applicants, peerInfo);
906
907 assert(total <= 1);
908
909 return true;
910 }
911
912 bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
913 SOSCircleAssertStable(circle);
914
915 #ifndef NDEBUG
916 CFIndex total =
917 #endif
918 CFArrayRemoveAllWithMatchingID(circle->rejected_applicants, peerInfo);
919
920 assert(total <= 1);
921
922 return true;
923 }
924
925
926 bool SOSCircleRejectRequest(SOSCircleRef circle, SOSFullPeerInfoRef device_rejector,
927 SOSPeerInfoRef peerInfo, CFErrorRef *error) {
928 SOSCircleAssertStable(circle);
929
930 if (CFEqual(SOSPeerInfoGetPeerID(peerInfo), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector))))
931 return SOSCircleWithdrawRequest(circle, peerInfo, error);
932
933 CFIndex total = CFArrayRemoveAllWithMatchingID(circle->applicants, peerInfo);
934
935 if (total == 0) {
936 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot reject non-applicant"), NULL, error);
937 return false;
938 }
939 assert(total == 1);
940
941 CFArrayAppendValue(circle->rejected_applicants, peerInfo);
942
943 // TODO: Maybe we sign the rejection with device_rejector.
944
945 return true;
946 }
947
948 bool SOSCircleAcceptRequests(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver,
949 CFErrorRef *error) {
950 // Returns true if we accepted someone and therefore have to post the circle back to KVS
951 __block bool result = false;
952
953 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
954 if (!SOSCircleAcceptRequest(circle, user_privkey, device_approver, peer, error))
955 printf("error in SOSCircleAcceptRequest\n");
956 else {
957 secnotice("circle", "Accepted peer: %@", peer);
958 result = true;
959 }
960 });
961
962 if (result) {
963 SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
964 secnotice("circle", "Countersigned accepted requests");
965 }
966
967 return result;
968 }
969
970 bool SOSCirclePeerSigUpdate(SOSCircleRef circle, SecKeyRef userPrivKey, SOSFullPeerInfoRef fpi,
971 CFErrorRef *error) {
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);
975
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)) {
980 // do we care?
981 }
982 }
983 });
984
985 result = SOSCircleUpdatePeerInfo(circle, SOSFullPeerInfoGetPeerInfo(fpi));
986
987 if (result) {
988 SOSCircleGenerationSign(circle, userPrivKey, fpi, error);
989 secnotice("circle", "Generation signed updated signatures on peerinfo");
990 }
991
992 return result;
993 }
994
995 SOSPeerInfoRef SOSCircleCopyPeerInfo(SOSCircleRef circle, CFStringRef peer_id, CFErrorRef *error) {
996 __block SOSPeerInfoRef result = NULL;
997
998 CFArrayForEach(circle->peers, ^(const void *value) {
999 if (result == NULL) {
1000 SOSPeerInfoRef tpi = (SOSPeerInfoRef)value;
1001 if (CFEqual(SOSPeerInfoGetPeerID(tpi), peer_id))
1002 result = tpi;
1003 }
1004 });
1005
1006 CFRetainSafe(result);
1007 return result;
1008 }
1009
1010
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))
1017 action(peer);
1018 });
1019 }
1020
1021 void SOSCircleForEachPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1022 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1023 return !SOSPeerInfoIsRetirementTicket(peer) && !SOSPeerInfoIsCloudIdentity(peer);
1024 });
1025 }
1026
1027 void SOSCircleForEachRetiredPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1028 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1029 return SOSPeerInfoIsRetirementTicket(peer);
1030 });
1031 }
1032
1033 void SOSCircleForEachActivePeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1034 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1035 return true;
1036 });
1037 }
1038
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);
1042 });
1043 }
1044
1045 void SOSCircleForEachApplicant(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1046 CFArrayForEach(circle->applicants, ^(const void*value) { action((SOSPeerInfoRef) value); } );
1047 }
1048
1049
1050 CFMutableArrayRef SOSCircleCopyPeers(SOSCircleRef circle, CFAllocatorRef allocator) {
1051 SOSCircleAssertStable(circle);
1052
1053 CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(allocator);
1054
1055 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
1056 CFArrayAppendValue(result, peer);
1057 });
1058
1059 return result;
1060 }
1061
1062 CFMutableArrayRef SOSCircleCopyConcurringPeers(SOSCircleRef circle, CFErrorRef* error) {
1063 SOSCircleAssertStable(circle);
1064
1065 CFMutableArrayRef concurringPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
1066
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);
1073 }
1074 CFReleaseNull(error);
1075 });
1076
1077 return concurringPeers;
1078 }
1079
1080
1081 //
1082 // Stuff above this line is really SOSCircleInfo below the line is the active SOSCircle functionality
1083 //
1084
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) {
1090 //}
1091 if (peer_info) {
1092 peer = SOSPeerCreate(myRef, peer_info, error, sendBlock);
1093 CFReleaseNull(peer_info);
1094 }
1095 return peer;
1096 }
1097
1098
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))
1102 {
1103 bool success = false;
1104 SOSEngineRef engine = NULL;
1105 SOSPeerRef peer = NULL;
1106 SOSDataSourceRef ds = NULL;
1107
1108 peer = SOSCircleCopyPeer(circle, myRef, sendBlock, peer_id, error);
1109 require(peer, exit);
1110
1111 ds = factory->create_datasource(factory, SOSCircleGetName(circle), readOnly, error);
1112 require(ds, exit);
1113
1114 engine = SOSEngineCreate(ds, error); // Hand off DS to engine.
1115 ds = NULL;
1116 require(engine, exit);
1117
1118 success = do_action(engine, peer, error);
1119
1120 exit:
1121 if (ds)
1122 ds->release(ds);
1123 if (engine)
1124 SOSEngineDispose(engine);
1125 if (peer)
1126 SOSPeerDispose(peer);
1127
1128 return success;
1129 }
1130
1131 bool SOSCircleSyncWithPeer(SOSFullPeerInfoRef myRef, SOSCircleRef circle, SOSDataSourceFactoryRef factory,
1132 SOSPeerSendBlock sendBlock, CFStringRef peer_id,
1133 CFErrorRef *error)
1134 {
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;
1137 });
1138 }
1139
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;
1145 });
1146 }
1147
1148
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);
1156
1157 if (localError) {
1158 secerror("Found cloud peer in circle but can't make full peer: %@", localError);
1159 CFReleaseNull(localError);
1160 }
1161
1162 } else {
1163 secerror("More than one cloud identity found in circle: %@", circle);
1164 }
1165 }
1166 });
1167 return cloud_full_peer;
1168 }
1169
1170
1171