]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSCircle.c
Security-57337.20.44.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSCircle.c
1 /*
2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 /*
26 * SOSCircle.c - Implementation of the secure object syncing transport
27 */
28
29 #include <AssertMacros.h>
30
31 #include <CoreFoundation/CFArray.h>
32 #include <Security/SecureObjectSync/SOSCircle.h>
33 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
34 #include <Security/SecureObjectSync/SOSInternal.h>
35 #include <Security/SecureObjectSync/SOSEngine.h>
36 #include <Security/SecureObjectSync/SOSPeer.h>
37 #include <Security/SecureObjectSync/SOSPeerInfoInternal.h>
38 #include <Security/SecureObjectSync/SOSGenCount.h>
39 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
40 #include <Security/SecureObjectSync/SOSGenCount.h>
41 #include <CoreFoundation/CoreFoundation.h>
42 #include <Security/SecFramework.h>
43
44 #include <Security/SecKey.h>
45 #include <Security/SecKeyPriv.h>
46
47 #include <utilities/SecCFWrappers.h>
48 #include <Security/SecureObjectSync/SOSCirclePriv.h>
49
50 //#include "ckdUtilities.h"
51
52 #include <corecrypto/ccder.h>
53 #include <corecrypto/ccdigest.h>
54 #include <corecrypto/ccsha2.h>
55
56 #include <stdlib.h>
57 #include <assert.h>
58
59 CFGiblisWithCompareFor(SOSCircle);
60
61 SOSCircleRef SOSCircleCreate(CFAllocatorRef allocator, CFStringRef name, CFErrorRef *error) {
62 SOSCircleRef c = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
63 assert(name);
64
65 c->name = CFStringCreateCopy(allocator, name);
66 c->generation = SOSGenerationCreate();
67 c->peers = CFSetCreateMutableForSOSPeerInfosByID(allocator);
68 c->applicants = CFSetCreateMutableForSOSPeerInfosByID(allocator);
69 c->rejected_applicants = CFSetCreateMutableForSOSPeerInfosByID(allocator);
70 c->signatures = CFDictionaryCreateMutableForCFTypes(allocator);
71 return c;
72 }
73
74 static CFMutableSetRef CFSetOfPeerInfoDeepCopy(CFAllocatorRef allocator, CFSetRef peerInfoSet)
75 {
76 __block CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
77 CFSetForEach(peerInfoSet, ^(const void *value) {
78 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
79 CFErrorRef localError = NULL;
80 SOSPeerInfoRef copiedPeer = SOSPeerInfoCreateCopy(allocator, pi, &localError);
81 if (copiedPeer) {
82 CFSetAddValue(result, copiedPeer);
83 } else {
84 secerror("Failed to copy peer: %@ (%@)", pi, localError);
85 }
86 CFReleaseSafe(copiedPeer);
87 CFReleaseSafe(localError);
88 });
89 return result;
90 }
91
92 SOSCircleRef SOSCircleCopyCircle(CFAllocatorRef allocator, SOSCircleRef otherCircle, CFErrorRef *error)
93 {
94 SOSCircleRef c = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
95
96 assert(otherCircle);
97 c->name = CFStringCreateCopy(allocator, otherCircle->name);
98 c->generation = SOSGenerationCopy(otherCircle->generation);
99
100 c->peers = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->peers);
101 c->applicants = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->applicants);
102 c->rejected_applicants = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->rejected_applicants);
103
104 c->signatures = CFDictionaryCreateMutableCopy(allocator, 0, otherCircle->signatures);
105
106 return c;
107 }
108
109 static Boolean SOSCircleCompare(CFTypeRef lhs, CFTypeRef rhs) {
110 if (CFGetTypeID(lhs) != SOSCircleGetTypeID()
111 || CFGetTypeID(rhs) != SOSCircleGetTypeID())
112 return false;
113
114 SOSCircleRef left = SOSCircleConvertAndAssertStable(lhs);
115 SOSCircleRef right = SOSCircleConvertAndAssertStable(rhs);
116
117 // TODO: we should be doing set equality for peers and applicants.
118 return NULL != left && NULL != right
119 && CFEqualSafe(left->generation, right->generation)
120 && SOSPeerInfoSetContainsIdenticalPeers(left->peers, right->peers)
121 && SOSPeerInfoSetContainsIdenticalPeers(left->applicants, right->applicants)
122 && SOSPeerInfoSetContainsIdenticalPeers(left->rejected_applicants, right->rejected_applicants)
123 && CFEqualSafe(left->signatures, right->signatures);
124 }
125
126 static CFMutableArrayRef CFSetCopyValuesCFArray(CFSetRef set)
127 {
128 CFIndex count = CFSetGetCount(set);
129
130 CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
131 if (count > 0) {
132 const void * values[count];
133 CFSetGetValues(set, values);
134 for (int current = 0; current < count; ++current) {
135 CFArrayAppendValue(result, values[current]);
136 }
137 }
138
139 return result;
140 }
141
142 static bool SOSCircleDigestArray(const struct ccdigest_info *di, CFMutableArrayRef array, void *hash_result, CFErrorRef *error)
143 {
144 __block bool success = true;
145 ccdigest_di_decl(di, array_digest);
146 const void * a_digest = array_digest;
147
148 ccdigest_init(di, array_digest);
149 CFArraySortValues(array, CFRangeMake(0, CFArrayGetCount(array)), SOSPeerInfoCompareByID, SOSPeerCmpPubKeyHash);
150 CFArrayForEach(array, ^(const void *peer) {
151 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes((SOSPeerInfoRef)peer, di, a_digest, error))
152 success = false;
153 });
154 ccdigest_final(di, array_digest, hash_result);
155
156 return success;
157 }
158
159 static bool SOSCircleDigestSet(const struct ccdigest_info *di, CFMutableSetRef set, void *hash_result, CFErrorRef *error)
160 {
161 CFMutableArrayRef values = CFSetCopyValuesCFArray(set);
162
163 bool result = SOSCircleDigestArray(di, values, hash_result, error);
164
165 CFReleaseSafe(values);
166
167 return result;
168 }
169
170
171 static bool SOSCircleHash(const struct ccdigest_info *di, SOSCircleRef circle, void *hash_result, CFErrorRef *error) {
172 ccdigest_di_decl(di, circle_digest);
173 ccdigest_init(di, circle_digest);
174 int64_t gen = SOSCircleGetGenerationSint(circle);
175 ccdigest_update(di, circle_digest, sizeof(gen), &gen);
176
177 SOSCircleDigestSet(di, circle->peers, hash_result, error);
178 ccdigest_update(di, circle_digest, di->output_size, hash_result);
179 ccdigest_final(di, circle_digest, hash_result);
180 return true;
181 }
182
183 static bool SOSCircleSetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFDataRef signature, CFErrorRef *error) {
184 bool result = false;
185
186 CFStringRef pubKeyID = SOSCopyIDOfKey(pubkey, error);
187 require_quiet(pubKeyID, fail);
188 CFDictionarySetValue(circle->signatures, pubKeyID, signature);
189 result = true;
190
191 fail:
192 CFReleaseSafe(pubKeyID);
193 return result;
194 }
195
196 static bool SOSCircleRemoveSignatures(SOSCircleRef circle, CFErrorRef *error) {
197 CFDictionaryRemoveAllValues(circle->signatures);
198 return true;
199 }
200
201 static CFDataRef SOSCircleGetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFErrorRef *error) {
202 CFStringRef pubKeyID = SOSCopyIDOfKey(pubkey, error);
203 CFDataRef result = NULL;
204 require_quiet(pubKeyID, fail);
205
206 CFTypeRef value = (CFDataRef)CFDictionaryGetValue(circle->signatures, pubKeyID);
207
208 if (isData(value)) result = (CFDataRef) value;
209
210 fail:
211 CFReleaseSafe(pubKeyID);
212 return result;
213 }
214
215 bool SOSCircleSign(SOSCircleRef circle, SecKeyRef privKey, CFErrorRef *error) {
216 if (!privKey) return false; // Really assertion but not always true for now.
217 CFAllocatorRef allocator = CFGetAllocator(circle);
218 uint8_t tmp[4096];
219 size_t tmplen = 4096;
220 const struct ccdigest_info *di = ccsha256_di();
221 uint8_t hash_result[di->output_size];
222
223 SOSCircleHash(di, circle, hash_result, error);
224 OSStatus stat = SecKeyRawSign(privKey, kSecPaddingNone, hash_result, di->output_size, tmp, &tmplen);
225 if(stat) {
226 // TODO - Create a CFErrorRef;
227 secerror("Bad Circle SecKeyRawSign, stat: %ld", (long)stat);
228 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Circle SecKeyRawSign"), (error != NULL) ? *error : NULL, error);
229 return false;
230 };
231 CFDataRef signature = CFDataCreate(allocator, tmp, tmplen);
232 SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(privKey);
233 SOSCircleSetSignature(circle, publicKey, signature, error);
234 CFReleaseNull(publicKey);
235 CFRelease(signature);
236 return true;
237 }
238
239 static bool SOSCircleConcordanceRingSign(SOSCircleRef circle, SecKeyRef privKey, CFErrorRef *error) {
240 secnotice("Development", "SOSCircleEnsureRingConsistency requires ring signing op", NULL);
241 return true;
242 }
243
244
245 bool SOSCircleVerifySignatureExists(SOSCircleRef circle, SecKeyRef pubKey, CFErrorRef *error) {
246 if(!pubKey) {
247 // TODO ErrorRef
248 secerror("SOSCircleVerifySignatureExists no pubKey");
249 SOSCreateError(kSOSErrorBadFormat, CFSTR("SOSCircleVerifySignatureExists no pubKey"), (error != NULL) ? *error : NULL, error);
250 return false;
251 }
252 CFDataRef signature = SOSCircleGetSignature(circle, pubKey, error);
253 return NULL != signature;
254 }
255
256 bool SOSCircleVerify(SOSCircleRef circle, SecKeyRef pubKey, CFErrorRef *error) {
257 const struct ccdigest_info *di = ccsha256_di();
258 uint8_t hash_result[di->output_size];
259
260 SOSCircleHash(di, circle, hash_result, error);
261
262 CFDataRef signature = SOSCircleGetSignature(circle, pubKey, error);
263 if(!signature) return false;
264
265 return SecKeyRawVerify(pubKey, kSecPaddingNone, hash_result, di->output_size,
266 CFDataGetBytePtr(signature), CFDataGetLength(signature)) == errSecSuccess;
267 }
268
269 bool SOSCircleVerifyPeerSigned(SOSCircleRef circle, SOSPeerInfoRef peer, CFErrorRef *error) {
270 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer);
271 bool result = SOSCircleVerify(circle, pub_key, error);
272 CFReleaseSafe(pub_key);
273 return result;
274 }
275
276 static void CFSetRemoveAllPassing(CFMutableSetRef set, bool (^test)(const void *) ){
277 CFMutableArrayRef toBeRemoved = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
278
279 CFSetForEach(set, ^(const void *value) {
280 if (test(value))
281 CFArrayAppendValue(toBeRemoved, value);
282 });
283
284 CFArrayForEach(toBeRemoved, ^(const void *value) {
285 CFSetRemoveValue(set, value);
286 });
287 CFReleaseNull(toBeRemoved);
288 }
289
290 static void SOSCircleRejectNonValidApplicants(SOSCircleRef circle, SecKeyRef pubkey) {
291 CFMutableSetRef applicants = SOSCircleCopyApplicants(circle, NULL);
292 CFSetForEach(applicants, ^(const void *value) {
293 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
294 if(!SOSPeerInfoApplicationVerify(pi, pubkey, NULL)) {
295 CFSetTransferObject(pi, circle->applicants, circle->rejected_applicants);
296 }
297 });
298 CFReleaseNull(applicants);
299 }
300
301 static SOSPeerInfoRef SOSCircleCopyPeerInfo(SOSCircleRef circle, CFStringRef peer_id, CFErrorRef *error) {
302 __block SOSPeerInfoRef result = NULL;
303
304 CFSetForEach(circle->peers, ^(const void *value) {
305 if (result == NULL) {
306 SOSPeerInfoRef tpi = (SOSPeerInfoRef)value;
307 if (CFEqual(SOSPeerInfoGetPeerID(tpi), peer_id))
308 result = tpi;
309 }
310 });
311
312 CFRetainSafe(result);
313 return result;
314 }
315
316 static bool SOSCircleUpgradePeerInfo(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo) {
317 bool retval = false;
318 SecKeyRef userPubKey = SecKeyCreatePublicFromPrivate(user_approver);
319 SOSPeerInfoRef fpi_pi = SOSFullPeerInfoGetPeerInfo(peerinfo);
320 SOSPeerInfoRef pi = SOSCircleCopyPeerInfo(circle, SOSPeerInfoGetPeerID(fpi_pi), NULL);
321 require_quiet(pi, out);
322 require_quiet(SOSPeerInfoApplicationVerify(pi, userPubKey, NULL), re_sign);
323 CFReleaseNull(userPubKey);
324 CFReleaseNull(pi);
325 return true;
326
327 re_sign:
328 secnotice("circle", "SOSCircleGenerationSign: Upgraded peer's Application Signature");
329 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peerinfo, NULL);
330 require_quiet(device_key, out);
331 SOSPeerInfoRef new_pi = SOSPeerInfoCopyAsApplication(pi, user_approver, device_key, NULL);
332 if(SOSCircleUpdatePeerInfo(circle, new_pi))
333 retval = true;
334 CFReleaseNull(new_pi);
335 CFReleaseNull(device_key);
336 out:
337 CFReleaseNull(userPubKey);
338 CFReleaseNull(pi);
339 return retval;
340 }
341
342 static bool SOSCircleEnsureRingConsistency(SOSCircleRef circle, CFErrorRef *error) {
343 secnotice("Development", "SOSCircleEnsureRingConsistency requires ring membership and generation count consistency check", NULL);
344 return true;
345 }
346
347 bool SOSCircleSignOldStyleResetToOfferingCircle(SOSCircleRef circle, SOSFullPeerInfoRef peerinfo, SecKeyRef user_approver, CFErrorRef *error){
348
349 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
350 SecKeyRef publicKey = NULL;
351 require_quiet(ourKey, fail);
352
353 // Check if we're using an invalid peerinfo for this op. There are cases where we might not be "upgraded".
354 require_quiet(SOSCircleUpgradePeerInfo(circle, user_approver, peerinfo), fail);
355 SOSCircleRemoveRetired(circle, error); // Prune off retirees since we're signing this one
356 CFSetRemoveAllValues(circle->rejected_applicants); // Dump rejects so we clean them up sometime.
357 publicKey = SecKeyCreatePublicFromPrivate(user_approver);
358 SOSCircleRejectNonValidApplicants(circle, publicKey);
359 require_quiet(SOSCircleEnsureRingConsistency(circle, error), fail);
360 require_quiet(SOSCircleRemoveSignatures(circle, error), fail);
361 require_quiet(SOSCircleSign(circle, user_approver, error), fail);
362 require_quiet(SOSCircleSign(circle, ourKey, error), fail);
363
364 CFReleaseNull(ourKey);
365 CFReleaseNull(publicKey);
366 return true;
367
368 fail:
369 CFReleaseNull(ourKey);
370 CFReleaseNull(publicKey);
371 return false;
372 }
373
374
375 bool SOSCircleGenerationSign(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
376 SecKeyRef publicKey = NULL;
377
378 SOSCircleRemoveRetired(circle, error); // Prune off retirees since we're signing this one
379 CFSetRemoveAllValues(circle->rejected_applicants); // Dump rejects so we clean them up sometime.
380 publicKey = SecKeyCreatePublicFromPrivate(user_approver);
381 SOSCircleRejectNonValidApplicants(circle, publicKey);
382 SOSCircleGenerationIncrement(circle);
383 require_quiet(SOSCircleEnsureRingConsistency(circle, error), fail);
384 require_quiet(SOSCircleRemoveSignatures(circle, error), fail);
385
386 if (SOSCircleCountPeers(circle) != 0) {
387 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
388 require_quiet(ourKey, fail);
389
390 // Check if we're using an invalid peerinfo for this op. There are cases where we might not be "upgraded".
391 require_quiet(SOSCircleUpgradePeerInfo(circle, user_approver, peerinfo), fail);
392
393 require_quiet(SOSCircleSign(circle, user_approver, error), fail);
394 require_quiet(SOSCircleSign(circle, ourKey, error), fail);
395 CFReleaseNull(ourKey);
396 }
397
398 CFReleaseNull(publicKey);
399 return true;
400
401 fail:
402 CFReleaseNull(publicKey);
403 return false;
404 }
405
406 bool SOSCircleGenerationUpdate(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
407
408 return SOSCircleGenerationSign(circle, user_approver, peerinfo, error);
409
410 #if 0
411 bool success = false;
412
413 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
414 require_quiet(ourKey, fail);
415
416 require_quiet(SOSCircleSign(circle, user_approver, error), fail);
417 require_quiet(SOSCircleSign(circle, ourKey, error), fail);
418
419 success = true;
420
421 fail:
422 CFReleaseNull(ourKey);
423 return success;
424 #endif
425 }
426
427 bool SOSCircleConcordanceSign(SOSCircleRef circle, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
428 bool success = false;
429 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
430 require_quiet(ourKey, exit);
431
432 success = SOSCircleSign(circle, ourKey, error);
433 SOSCircleConcordanceRingSign(circle, ourKey, error);
434
435 exit:
436 CFReleaseNull(ourKey);
437 return success;
438 }
439
440 static inline SOSConcordanceStatus CheckPeerStatus(SOSCircleRef circle, SOSPeerInfoRef peer, SecKeyRef user_public_key, CFErrorRef *error) {
441 SOSConcordanceStatus result = kSOSConcordanceNoPeer;
442 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(peer);
443
444 require_action_quiet(SOSCircleHasActiveValidPeer(circle, peer, user_public_key, error), exit, result = kSOSConcordanceNoPeer);
445 require_action_quiet(SOSCircleVerifySignatureExists(circle, pubKey, error), exit, result = kSOSConcordanceNoPeerSig);
446 require_action_quiet(SOSCircleVerify(circle, pubKey, error), exit, result = kSOSConcordanceBadPeerSig);
447
448 result = kSOSConcordanceTrusted;
449
450 exit:
451 CFReleaseNull(pubKey);
452 return result;
453 }
454
455 static inline SOSConcordanceStatus CombineStatus(SOSConcordanceStatus status1, SOSConcordanceStatus status2)
456 {
457 if (status1 == kSOSConcordanceTrusted || status2 == kSOSConcordanceTrusted)
458 return kSOSConcordanceTrusted;
459
460 if (status1 == kSOSConcordanceBadPeerSig || status2 == kSOSConcordanceBadPeerSig)
461 return kSOSConcordanceBadPeerSig;
462
463 if (status1 == kSOSConcordanceNoPeerSig || status2 == kSOSConcordanceNoPeerSig)
464 return kSOSConcordanceNoPeerSig;
465
466 return status1;
467 }
468
469 static inline bool SOSCircleIsEmpty(SOSCircleRef circle) {
470 return SOSCircleCountPeers(circle) == 0;
471 }
472
473 static inline bool SOSCircleIsOffering(SOSCircleRef circle) {
474 return SOSCircleCountPeers(circle) == 1;
475 }
476
477 static inline bool SOSCircleHasDegenerateGeneration(SOSCircleRef deGenCircle){
478 int testPtr;
479 CFNumberRef genCountTest = SOSCircleGetGeneration(deGenCircle);
480 CFNumberGetValue(genCountTest, kCFNumberCFIndexType, &testPtr);
481 return (testPtr== 0);
482 }
483
484
485 static inline bool SOSCircleIsDegenerateReset(SOSCircleRef deGenCircle){
486 return SOSCircleHasDegenerateGeneration(deGenCircle) && SOSCircleIsEmpty(deGenCircle);
487 }
488
489
490 __unused static inline bool SOSCircleIsResignOffering(SOSCircleRef circle, SecKeyRef pubkey) {
491 return SOSCircleCountActiveValidPeers(circle, pubkey) == 1;
492 }
493
494 static inline SOSConcordanceStatus GetSignersStatus(SOSCircleRef signers_circle, SOSCircleRef status_circle,
495 SecKeyRef user_pubKey, SOSPeerInfoRef exclude, CFErrorRef *error) {
496 CFStringRef excluded_id = exclude ? SOSPeerInfoGetPeerID(exclude) : NULL;
497
498 __block SOSConcordanceStatus status = kSOSConcordanceNoPeer;
499 SOSCircleForEachActivePeer(signers_circle, ^(SOSPeerInfoRef peer) {
500 SOSConcordanceStatus peerStatus = CheckPeerStatus(status_circle, peer, user_pubKey, error);
501
502 if (peerStatus == kSOSConcordanceNoPeerSig &&
503 (CFEqualSafe(SOSPeerInfoGetPeerID(peer), excluded_id) || SOSPeerInfoIsCloudIdentity(peer)))
504 peerStatus = kSOSConcordanceNoPeer;
505
506 status = CombineStatus(status, peerStatus); // TODO: Use multiple error gathering.
507 });
508
509 return status;
510 }
511
512 // Is proposed older than current?
513 static inline bool isOlderGeneration(SOSCircleRef current, SOSCircleRef proposed) {
514 return CFNumberCompare(current->generation, proposed->generation, NULL) == kCFCompareGreaterThan;
515 }
516
517 static inline bool SOSCircleIsValidReset(SOSCircleRef current, SOSCircleRef proposed) {
518 return (!isOlderGeneration(current, proposed)) && SOSCircleIsEmpty(proposed); // is current older or equal to proposed and is proposed empty
519 }
520
521
522 bool SOSCircleSharedTrustedPeers(SOSCircleRef current, SOSCircleRef proposed, SOSPeerInfoRef me) {
523 __block bool retval = false;
524 SOSCircleForEachPeer(current, ^(SOSPeerInfoRef peer) {
525 if(!CFEqual(me, peer) && SOSCircleHasPeer(proposed, peer, NULL)) retval = true;
526 });
527 return retval;
528 }
529
530
531 SOSConcordanceStatus SOSCircleConcordanceTrust(SOSCircleRef known_circle, SOSCircleRef proposed_circle,
532 SecKeyRef known_pubkey, SecKeyRef user_pubkey,
533 SOSPeerInfoRef me, CFErrorRef *error) {
534 if(user_pubkey == NULL) {
535 SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Concordance with no public key"), NULL, error);
536 return kSOSConcordanceNoUserKey; //TODO: - needs to return an error
537 }
538
539 if(SOSCircleIsDegenerateReset(proposed_circle)) {
540 return kSOSConcordanceTrusted;
541 }
542
543 if (SOSCircleIsValidReset(known_circle, proposed_circle)) {
544 return kSOSConcordanceTrusted;
545 }
546
547 if(!SOSCircleVerifySignatureExists(proposed_circle, user_pubkey, error)) {
548 SOSCreateError(kSOSErrorBadSignature, CFSTR("No public signature"), (error != NULL) ? *error : NULL, error);
549 return kSOSConcordanceNoUserSig;
550 }
551
552 if(!SOSCircleVerify(proposed_circle, user_pubkey, error)) {
553 SOSCreateError(kSOSErrorBadSignature, CFSTR("Bad public signature"), (error != NULL) ? *error : NULL, error);
554 debugDumpCircle(CFSTR("proposed_circle"), proposed_circle);
555 return kSOSConcordanceBadUserSig;
556 }
557
558 if (SOSCircleIsEmpty(known_circle)) {
559 return GetSignersStatus(proposed_circle, proposed_circle, user_pubkey, NULL, error);
560 }
561
562 if(SOSCircleHasDegenerateGeneration(proposed_circle) && SOSCircleIsOffering(proposed_circle)){
563 return GetSignersStatus(proposed_circle, proposed_circle, user_pubkey, NULL, error);
564 }
565
566 if(isOlderGeneration(known_circle, proposed_circle)) {
567 SOSCreateError(kSOSErrorReplay, CFSTR("Bad generation"), NULL, error);
568 debugDumpCircle(CFSTR("isOlderGeneration known_circle"), known_circle);
569 debugDumpCircle(CFSTR("isOlderGeneration proposed_circle"), proposed_circle);
570 return kSOSConcordanceGenOld;
571 }
572
573 if(SOSCircleIsOffering(proposed_circle)){
574 return GetSignersStatus(proposed_circle, proposed_circle, user_pubkey, NULL, error);
575 }
576
577 return GetSignersStatus(known_circle, proposed_circle, user_pubkey, me, error);
578 }
579
580
581 static void SOSCircleDestroy(CFTypeRef aObj) {
582 SOSCircleRef c = (SOSCircleRef) aObj;
583
584 CFReleaseNull(c->name);
585 CFReleaseNull(c->generation);
586 CFReleaseNull(c->peers);
587 CFReleaseNull(c->applicants);
588 CFReleaseNull(c->rejected_applicants);
589 CFReleaseNull(c->signatures);
590 }
591
592 static CFMutableStringRef defaultDescription(CFTypeRef aObj){
593 SOSCircleRef c = (SOSCircleRef) aObj;
594
595 CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
596
597 SOSGenerationCountWithDescription(c->generation, ^(CFStringRef genDescription) {
598 CFStringAppendFormat(description, NULL, CFSTR("<SOSCircle@%p: '%@' %@ P:["), c, c->name, genDescription);
599 });
600
601 __block CFStringRef separator = CFSTR("");
602 SOSCircleForEachActivePeer(c, ^(SOSPeerInfoRef peer) {
603 CFStringRef sig = NULL;
604 if (SOSCircleVerifyPeerSigned(c, peer, NULL)) {
605 sig = CFSTR("√");
606 } else {
607 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer);
608 CFDataRef signature = SOSCircleGetSignature(c, pub_key, NULL);
609 sig = (signature == NULL) ? CFSTR("-") : CFSTR("?");
610 CFReleaseNull(pub_key);
611 }
612
613 CFStringAppendFormat(description, NULL, CFSTR("%@%@ %@"), separator, peer, sig);
614 separator = CFSTR(",");
615 });
616
617 //applicants
618 CFStringAppend(description, CFSTR("], A:["));
619 separator = CFSTR("");
620 if(CFSetGetCount(c->applicants) == 0 )
621 CFStringAppendFormat(description, NULL, CFSTR("-"));
622 else{
623
624 SOSCircleForEachApplicant(c, ^(SOSPeerInfoRef peer) {
625 CFStringAppendFormat(description, NULL, CFSTR("%@%@"), separator, peer);
626 separator = CFSTR(",");
627 });
628 }
629
630 //rejected
631 CFStringAppend(description, CFSTR("], R:["));
632 separator = CFSTR("");
633 if(CFSetGetCount(c->rejected_applicants) == 0)
634 CFStringAppendFormat(description, NULL, CFSTR("-"));
635 else{
636 CFSetForEach(c->rejected_applicants, ^(const void *value) {
637 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
638 CFStringAppendFormat(description, NULL, CFSTR("%@%@"), separator, peer);
639 separator = CFSTR(",");
640 });
641 }
642 CFStringAppend(description, CFSTR("]>"));
643 return description;
644
645 }
646 static CFMutableStringRef descriptionWithFormatOptions(CFTypeRef aObj, CFDictionaryRef formatOptions){
647 SOSCircleRef c = (SOSCircleRef) aObj;
648
649 CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
650
651 if(CFDictionaryContainsKey(formatOptions, CFSTR("SyncD"))) {
652 CFStringRef generationDescription = SOSGenerationCountCopyDescription(c->generation);
653 CFStringAppendFormat(description, NULL, CFSTR("<C: gen:'%@' %@>\n"), generationDescription, c->name);
654 CFReleaseNull(generationDescription);
655 __block CFStringRef separator = CFSTR("\t\t");
656 SOSCircleForEachActivePeer(c, ^(SOSPeerInfoRef peer) {
657 CFStringRef sig = NULL;
658 if (SOSCircleVerifyPeerSigned(c, peer, NULL)) {
659 sig = CFSTR("√");
660 } else {
661 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer);
662 CFDataRef signature = SOSCircleGetSignature(c, pub_key, NULL);
663 sig = (signature == NULL) ? CFSTR("-") : CFSTR("?");
664 CFReleaseNull(pub_key);
665 }
666
667 CFStringAppendFormat(description, formatOptions, CFSTR("%@%@ %@"), separator, peer, sig);
668 separator = CFSTR("\n\t\t");
669 });
670 CFStringAppend(description, CFSTR("\n\t\t<A:["));
671 separator = CFSTR("");
672
673 //applicants list
674 if(CFSetGetCount(c->applicants) == 0 )
675 CFStringAppendFormat(description, NULL, CFSTR("-"));
676 else{
677
678 SOSCircleForEachApplicant(c, ^(SOSPeerInfoRef peer) {
679 CFStringAppendFormat(description, formatOptions, CFSTR("%@A: %@"), separator, peer);
680 separator = CFSTR("\n\t\t\t");
681 });
682 }
683 //rejected list
684 CFStringAppend(description, CFSTR("]> \n\t\t<R:["));
685 separator = CFSTR("");
686 if(CFSetGetCount(c->rejected_applicants) == 0)
687 CFStringAppendFormat(description, NULL, CFSTR("-"));
688 else{
689 CFSetForEach(c->rejected_applicants, ^(const void *value) {
690 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
691 CFStringAppendFormat(description, formatOptions, CFSTR("%@R: %@"), separator, peer);
692 separator = CFSTR("\n\t\t");
693 });
694 }
695 CFStringAppend(description, CFSTR("]>"));
696 }
697
698 else{
699 CFReleaseNull(description);
700 description = defaultDescription(aObj);
701 }
702
703 return description;
704
705 }
706
707
708 static CFStringRef SOSCircleCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
709 SOSCircleRef c = (SOSCircleRef) aObj;
710 SOSCircleAssertStable(c);
711 CFMutableStringRef description = NULL;
712
713 if(formatOptions != NULL){
714 description = descriptionWithFormatOptions(aObj, formatOptions);
715 }
716 else{
717 description = defaultDescription(aObj);
718 }
719 return description;
720 }
721
722 CFStringRef SOSCircleGetName(SOSCircleRef circle) {
723 assert(circle);
724 assert(circle->name);
725 return circle->name;
726 }
727
728 const char *SOSCircleGetNameC(SOSCircleRef circle) {
729 CFStringRef name = SOSCircleGetName(circle);
730 if (!name)
731 return strdup("");
732 return CFStringToCString(name);
733 }
734
735 SOSGenCountRef SOSCircleGetGeneration(SOSCircleRef circle) {
736 assert(circle);
737 assert(circle->generation);
738 return circle->generation;
739 }
740
741 void SOSCircleSetGeneration(SOSCircleRef circle, SOSGenCountRef gencount) {
742 assert(circle);
743 CFReleaseNull(circle->generation);
744 circle->generation = CFRetainSafe(gencount);
745 }
746
747 int64_t SOSCircleGetGenerationSint(SOSCircleRef circle) {
748 SOSGenCountRef gen = SOSCircleGetGeneration(circle);
749 return SOSGetGenerationSint(gen);
750 }
751
752 void SOSCircleGenerationSetValue(SOSCircleRef circle, int64_t value) {
753 CFAssignRetained(circle->generation, SOSGenerationCreateWithValue(value));
754 }
755
756 void SOSCircleGenerationIncrement(SOSCircleRef circle) {
757 SOSGenCountRef old = circle->generation;
758 circle->generation = SOSGenerationIncrementAndCreate(old);
759 CFReleaseNull(old);
760 }
761
762 int SOSCircleCountPeers(SOSCircleRef circle) {
763 SOSCircleAssertStable(circle);
764 __block int count = 0;
765 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
766 ++count;
767 });
768 return count;
769 }
770
771 int SOSCircleCountActivePeers(SOSCircleRef circle) {
772 SOSCircleAssertStable(circle);
773 __block int count = 0;
774 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
775 ++count;
776 });
777 return count;
778 }
779
780 int SOSCircleCountActiveValidPeers(SOSCircleRef circle, SecKeyRef pubkey) {
781 SOSCircleAssertStable(circle);
782 __block int count = 0;
783 SOSCircleForEachActiveValidPeer(circle, pubkey, ^(SOSPeerInfoRef peer) {
784 ++count;
785 });
786 return count;
787 }
788
789 int SOSCircleCountRetiredPeers(SOSCircleRef circle) {
790 SOSCircleAssertStable(circle);
791 __block int count = 0;
792 SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) {
793 ++count;
794 });
795 return count;
796 }
797
798 int SOSCircleCountApplicants(SOSCircleRef circle) {
799 SOSCircleAssertStable(circle);
800
801 return (int)CFSetGetCount(circle->applicants);
802 }
803
804 bool SOSCircleHasApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
805 SOSCircleAssertStable(circle);
806
807 return CFSetContainsValue(circle->applicants, peerInfo);
808 }
809
810 CFMutableSetRef SOSCircleCopyApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
811 SOSCircleAssertStable(circle);
812
813 return CFSetCreateMutableCopy(allocator, 0, circle->applicants);
814 }
815
816 int SOSCircleCountRejectedApplicants(SOSCircleRef circle) {
817 SOSCircleAssertStable(circle);
818
819 return (int)CFSetGetCount(circle->rejected_applicants);
820 }
821
822 bool SOSCircleHasRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
823 SOSCircleAssertStable(circle);
824 return CFSetContainsValue(circle->rejected_applicants, peerInfo);
825 }
826
827 SOSPeerInfoRef SOSCircleCopyRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
828 SOSCircleAssertStable(circle);
829 return CFRetainSafe((SOSPeerInfoRef)CFSetGetValue(circle->rejected_applicants, peerInfo));
830 }
831
832 CFMutableArrayRef SOSCircleCopyRejectedApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
833 SOSCircleAssertStable(circle);
834
835 return CFSetCopyValuesCFArray(circle->rejected_applicants);
836 }
837
838 bool SOSCircleHasPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
839 SOSCircleAssertStable(circle);
840 __block bool found = false;
841 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
842 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = true;
843 });
844 return found;
845 }
846
847 SOSPeerInfoRef SOSCircleCopyPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
848 SOSCircleAssertStable(circle);
849 __block SOSPeerInfoRef found = NULL;
850 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
851 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = peer;
852 });
853 return found ? SOSPeerInfoCreateCopy(kCFAllocatorDefault, found, NULL) : NULL;
854 }
855
856 bool SOSCircleHasPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
857 if(!peerInfo) return false;
858 return SOSCircleHasPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
859 }
860
861 bool SOSCircleHasActivePeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
862 SOSCircleAssertStable(circle);
863 __block bool found = false;
864 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
865 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = true;
866 });
867 return found;
868 }
869
870 bool SOSCircleHasActivePeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
871 if(!peerInfo) return false;
872 return SOSCircleHasActivePeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
873 }
874
875 bool SOSCircleHasActiveValidPeerWithID(SOSCircleRef circle, CFStringRef peerid, SecKeyRef user_public_key, CFErrorRef *error) {
876 SOSCircleAssertStable(circle);
877 __block bool found = false;
878 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
879 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer)) && SOSPeerInfoApplicationVerify(peer, user_public_key, NULL)) found = true;
880 });
881 return found;
882 }
883
884 bool SOSCircleHasActiveValidPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, SecKeyRef user_public_key, CFErrorRef *error) {
885 if(!peerInfo) return false;
886 return SOSCircleHasActiveValidPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), user_public_key, error);
887 }
888
889
890 bool SOSCircleResetToEmpty(SOSCircleRef circle, CFErrorRef *error) {
891 CFSetRemoveAllValues(circle->applicants);
892 CFSetRemoveAllValues(circle->rejected_applicants);
893 CFSetRemoveAllValues(circle->peers);
894 CFDictionaryRemoveAllValues(circle->signatures);
895 SOSGenCountRef oldGen = SOSCircleGetGeneration(circle);
896 SOSGenCountRef newGen = SOSGenerationCreateWithBaseline(oldGen);
897 SOSCircleSetGeneration(circle, newGen);
898 return true;
899 }
900
901 bool SOSCircleResetToOffering(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error){
902
903 return SOSCircleResetToEmpty(circle, error)
904 && SOSCircleRequestAdmission(circle, user_privkey, requestor, error)
905 && SOSCircleAcceptRequest(circle, user_privkey, requestor, SOSFullPeerInfoGetPeerInfo(requestor), error);
906 }
907
908 bool SOSCircleRemoveRetired(SOSCircleRef circle, CFErrorRef *error) {
909 CFSetRemoveAllPassing(circle->peers, ^ bool (const void *element) {
910 SOSPeerInfoRef peer = (SOSPeerInfoRef) element;
911
912 return SOSPeerInfoIsRetirementTicket(peer);
913 });
914
915 return true;
916 }
917
918 static bool SOSCircleRecordAdmissionRequest(SOSCircleRef circle, SecKeyRef user_pubkey, SOSPeerInfoRef requestorPeerInfo, CFErrorRef *error) {
919 SOSCircleAssertStable(circle);
920
921 bool isPeer = SOSCircleHasPeer(circle, requestorPeerInfo, error);
922
923 require_action_quiet(!isPeer, fail, SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Cannot request admission when already a peer"), NULL, error));
924
925 CFSetTransferObject(requestorPeerInfo, circle->rejected_applicants, circle->applicants);
926
927 return true;
928
929 fail:
930 return false;
931
932 }
933
934 bool SOSCircleRequestReadmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSPeerInfoRef peer, CFErrorRef *error) {
935 bool success = false;
936
937 require_quiet(SOSPeerInfoApplicationVerify(peer, user_pubkey, error), fail);
938 success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, peer, error);
939 fail:
940 return success;
941 }
942
943 bool SOSCircleRequestAdmission(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
944 bool success = false;
945
946 SecKeyRef user_pubkey = SecKeyCreatePublicFromPrivate(user_privkey);
947 require_action_quiet(user_pubkey, fail, SOSCreateError(kSOSErrorBadKey, CFSTR("No public key for key"), NULL, error));
948
949 require(SOSFullPeerInfoPromoteToApplication(requestor, user_privkey, error), fail);
950
951 success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, SOSFullPeerInfoGetPeerInfo(requestor), error);
952 fail:
953 CFReleaseNull(user_pubkey);
954 return success;
955 }
956
957 static bool sosCircleUpdatePeerInfoSet(CFMutableSetRef theSet, SOSPeerInfoRef replacement_peer_info) {
958 CFTypeRef old = NULL;
959 if(!replacement_peer_info) return false;
960 if(!(old = CFSetGetValue(theSet, replacement_peer_info))) return false;
961 if(CFEqualSafe(old, replacement_peer_info)) return false;
962 CFSetReplaceValue(theSet, replacement_peer_info);
963 return true;
964 }
965
966 bool SOSCircleUpdatePeerInfo(SOSCircleRef circle, SOSPeerInfoRef replacement_peer_info) {
967 if(sosCircleUpdatePeerInfoSet(circle->peers, replacement_peer_info)) return true;
968 if(sosCircleUpdatePeerInfoSet(circle->applicants, replacement_peer_info)) return true;
969 if(sosCircleUpdatePeerInfoSet(circle->rejected_applicants, replacement_peer_info)) return true;
970 return false;
971 }
972
973 static bool SOSCircleRemovePeerInternal(SOSCircleRef circle, SOSFullPeerInfoRef requestor, SOSPeerInfoRef peer_to_remove, CFErrorRef *error) {
974 SOSPeerInfoRef requestor_peer_info = SOSFullPeerInfoGetPeerInfo(requestor);
975
976 if (SOSCircleHasPeer(circle, peer_to_remove, NULL)) {
977 if (!SOSCircleHasPeer(circle, requestor_peer_info, error)) {
978 SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Must be peer to remove peer"), NULL, error);
979 return false;
980 }
981 CFSetRemoveValue(circle->peers, peer_to_remove);
982 }
983
984 if (SOSCircleHasApplicant(circle, peer_to_remove, error)) {
985 return SOSCircleRejectRequest(circle, requestor, peer_to_remove, error);
986 }
987
988 return true;
989 }
990
991 bool SOSCircleRemovePeers(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFSetRef peersToRemove, CFErrorRef *error) {
992
993 bool success = false;
994
995 __block bool removed_all = true;
996 CFSetForEach(peersToRemove, ^(const void *value) {
997 SOSPeerInfoRef peerInfo = asSOSPeerInfo(value);
998 if (peerInfo) {
999 removed_all &= SOSCircleRemovePeerInternal(circle, requestor, peerInfo, error);
1000 }
1001 });
1002
1003 require_quiet(removed_all, exit);
1004
1005 require_quiet(SOSCircleGenerationSign(circle, user_privkey, requestor, error), exit);
1006
1007 success = true;
1008
1009 exit:
1010 return success;
1011 }
1012
1013 bool SOSCircleRemovePeer(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, SOSPeerInfoRef peer_to_remove, CFErrorRef *error) {
1014 bool success = false;
1015
1016 require_quiet(SOSCircleRemovePeerInternal(circle, requestor, peer_to_remove, error), exit);
1017
1018 require_quiet(SOSCircleGenerationSign(circle, user_privkey, requestor, error), exit);
1019
1020 success = true;
1021 exit:
1022 return success;
1023 }
1024
1025 bool SOSCircleAcceptRequest(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1026 SOSCircleAssertStable(circle);
1027
1028 SecKeyRef publicKey = NULL;
1029 bool result = false;
1030
1031 require_action_quiet(CFSetContainsValue(circle->applicants, peerInfo), fail,
1032 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot accept non-applicant"), NULL, error));
1033
1034 publicKey = SecKeyCreatePublicFromPrivate(user_privkey);
1035 require_quiet(SOSPeerInfoApplicationVerify(peerInfo, publicKey, error), fail);
1036
1037 CFSetTransferObject(peerInfo, circle->applicants, circle->peers);
1038
1039 result = SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
1040
1041 fail:
1042 CFReleaseNull(publicKey);
1043 return result;
1044 }
1045
1046 bool SOSCircleWithdrawRequest(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1047 SOSCircleAssertStable(circle);
1048
1049 CFSetRemoveValue(circle->applicants, peerInfo);
1050
1051 return true;
1052 }
1053
1054 bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1055 SOSCircleAssertStable(circle);
1056
1057 CFSetRemoveValue(circle->rejected_applicants, peerInfo);
1058
1059 return true;
1060 }
1061
1062
1063 bool SOSCircleRejectRequest(SOSCircleRef circle, SOSFullPeerInfoRef device_rejector,
1064 SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1065 SOSCircleAssertStable(circle);
1066
1067 if (CFEqual(SOSPeerInfoGetPeerID(peerInfo), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector))))
1068 return SOSCircleWithdrawRequest(circle, peerInfo, error);
1069
1070 if (!CFSetContainsValue(circle->applicants, peerInfo)) {
1071 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot reject non-applicant"), NULL, error);
1072 return false;
1073 }
1074
1075 CFSetTransferObject(peerInfo, circle->applicants, circle->rejected_applicants);
1076
1077 // TODO: Maybe we sign the rejection with device_rejector.
1078
1079 return true;
1080 }
1081
1082 bool SOSCircleAcceptRequests(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver,
1083 CFErrorRef *error) {
1084 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1085 __block bool result = false;
1086
1087 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
1088 if (!SOSCircleAcceptRequest(circle, user_privkey, device_approver, peer, error)) {
1089 secnotice("circle", "error in SOSCircleAcceptRequest\n");
1090 } else {
1091 secnotice("circle", "Accepted peer: %@", peer);
1092 result = true;
1093 }
1094 });
1095
1096 if (result) {
1097 SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
1098 secnotice("circle", "Countersigned accepted requests");
1099 }
1100
1101 return result;
1102 }
1103
1104 bool SOSCirclePeerSigUpdate(SOSCircleRef circle, SecKeyRef userPrivKey, SOSFullPeerInfoRef fpi,
1105 CFErrorRef *error) {
1106 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1107 __block bool result = false;
1108 SecKeyRef userPubKey = SecKeyCreatePublicFromPrivate(userPrivKey);
1109
1110 // We're going to remove any applicants using a mismatched user key.
1111 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
1112 if(!SOSPeerInfoApplicationVerify(peer, userPubKey, NULL)) {
1113 if(!SOSCircleRejectRequest(circle, fpi, peer, NULL)) {
1114 // do we care?
1115 }
1116 }
1117 });
1118
1119 result = SOSCircleUpdatePeerInfo(circle, SOSFullPeerInfoGetPeerInfo(fpi));
1120
1121 if (result) {
1122 SOSCircleGenerationSign(circle, userPrivKey, fpi, error);
1123 secnotice("circle", "Generation signed updated signatures on peerinfo");
1124 }
1125
1126 return result;
1127 }
1128
1129 static inline void SOSCircleForEachPeerMatching(SOSCircleRef circle,
1130 void (^action)(SOSPeerInfoRef peer),
1131 bool (^condition)(SOSPeerInfoRef peer)) {
1132 CFSetForEach(circle->peers, ^(const void *value) {
1133 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
1134 if (condition(peer))
1135 action(peer);
1136 });
1137 }
1138
1139 static inline bool isHiddenPeer(SOSPeerInfoRef peer) {
1140 return SOSPeerInfoIsRetirementTicket(peer) || SOSPeerInfoIsCloudIdentity(peer);
1141 }
1142
1143 void SOSCircleForEachPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1144 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1145 return !isHiddenPeer(peer);
1146 });
1147 }
1148
1149 void SOSCircleForEachRetiredPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1150 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1151 return SOSPeerInfoIsRetirementTicket(peer);
1152 });
1153 }
1154
1155 void SOSCircleForEachActivePeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1156 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1157 return true;
1158 });
1159 }
1160
1161 void SOSCircleForEachActiveValidPeer(SOSCircleRef circle, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)) {
1162 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1163 return SOSPeerInfoApplicationVerify(peer, user_public_key, NULL);
1164 });
1165 }
1166
1167 void SOSCircleForEachValidPeer(SOSCircleRef circle, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)) {
1168 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1169 return !isHiddenPeer(peer) && SOSPeerInfoApplicationVerify(peer, user_public_key, NULL);
1170 });
1171 }
1172
1173 void SOSCircleForEachApplicant(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1174 CFSetForEach(circle->applicants, ^(const void*value) { action((SOSPeerInfoRef) value); } );
1175 }
1176
1177
1178 CFMutableSetRef SOSCircleCopyPeers(SOSCircleRef circle, CFAllocatorRef allocator) {
1179 SOSCircleAssertStable(circle);
1180
1181 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
1182
1183 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
1184 CFSetAddValue(result, peer);
1185 });
1186
1187 return result;
1188 }
1189
1190 bool SOSCircleAppendConcurringPeers(SOSCircleRef circle, CFMutableArrayRef appendHere, CFErrorRef *error) {
1191 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1192 CFErrorRef localError = NULL;
1193 if (SOSCircleVerifyPeerSigned(circle, peer, &localError)) {
1194 SOSPeerInfoRef peerInfo = SOSPeerInfoCreateCopy(kCFAllocatorDefault, peer, error);
1195 CFArrayAppendValue(appendHere, peerInfo);
1196 CFRelease(peerInfo);
1197 } else if (error != NULL) {
1198 secerror("Error checking concurrence: %@", localError);
1199 }
1200 CFReleaseNull(localError);
1201 });
1202
1203 return true;
1204 }
1205
1206 CFMutableArrayRef SOSCircleCopyConcurringPeers(SOSCircleRef circle, CFErrorRef* error) {
1207 SOSCircleAssertStable(circle);
1208
1209 CFMutableArrayRef concurringPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
1210
1211 if (!SOSCircleAppendConcurringPeers(circle, concurringPeers, error))
1212 CFReleaseNull(concurringPeers);
1213
1214 return concurringPeers;
1215 }
1216
1217 SOSFullPeerInfoRef SOSCircleCopyiCloudFullPeerInfoRef(SOSCircleRef circle, CFErrorRef *error) {
1218 __block SOSFullPeerInfoRef cloud_full_peer = NULL;
1219 __block CFErrorRef searchError = NULL;
1220 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1221 if (SOSPeerInfoIsCloudIdentity(peer)) {
1222 if (cloud_full_peer == NULL) {
1223 if (searchError) {
1224 secerror("More than one cloud identity found, first had error, trying new one.");
1225 }
1226 CFReleaseNull(searchError);
1227 cloud_full_peer = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, &searchError);
1228 if (!cloud_full_peer) {
1229 secnotice("icloud-identity", "Failed to make FullPeer for iCloud Identity: %@ (%@)", cloud_full_peer, searchError);
1230 }
1231 } else {
1232 secerror("Additional cloud identity found in circle after successful creation: %@", circle);
1233 }
1234 }
1235 });
1236 // If we didn't find one at all, report the error.
1237 if (cloud_full_peer == NULL && searchError == NULL) {
1238 SOSErrorCreate(kSOSErrorNoiCloudPeer, &searchError, NULL, CFSTR("No iCloud identity PeerInfo found in circle"));
1239 secnotice("icloud-identity", "No iCloud identity PeerInfo found in circle");
1240 }
1241 if (error) {
1242 CFTransferRetained(*error, searchError);
1243 }
1244 CFReleaseNull(searchError);
1245 return cloud_full_peer;
1246 }
1247
1248 void debugDumpCircle(CFStringRef message, SOSCircleRef circle) {
1249 CFErrorRef error;
1250
1251 secinfo("circledebug", "%@: %@", message, circle);
1252 if (!circle)
1253 return;
1254
1255 CFDataRef derdata = SOSCircleCopyEncodedData(circle, kCFAllocatorDefault, &error);
1256 if (derdata) {
1257 CFStringRef hex = CFDataCopyHexString(derdata);
1258 secinfo("circledebug", "Full contents: %@", hex);
1259 if (hex) CFRelease(hex);
1260 CFRelease(derdata);
1261 }
1262 }