]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSCircle.c
Security-57337.50.23.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 SOSCircleHasDegenerateGeneration(SOSCircleRef deGenCircle){
474 int testPtr;
475 CFNumberRef genCountTest = SOSCircleGetGeneration(deGenCircle);
476 CFNumberGetValue(genCountTest, kCFNumberCFIndexType, &testPtr);
477 return (testPtr== 0);
478 }
479
480
481 static inline bool SOSCircleIsDegenerateReset(SOSCircleRef deGenCircle){
482 return SOSCircleHasDegenerateGeneration(deGenCircle) && SOSCircleIsEmpty(deGenCircle);
483 }
484
485
486 __unused static inline bool SOSCircleIsResignOffering(SOSCircleRef circle, SecKeyRef pubkey) {
487 return SOSCircleCountActiveValidPeers(circle, pubkey) == 1;
488 }
489
490 static inline SOSConcordanceStatus GetSignersStatus(SOSCircleRef signers_circle, SOSCircleRef status_circle,
491 SecKeyRef user_pubKey, SOSPeerInfoRef exclude, CFErrorRef *error) {
492 CFStringRef excluded_id = exclude ? SOSPeerInfoGetPeerID(exclude) : NULL;
493
494 __block SOSConcordanceStatus status = kSOSConcordanceNoPeer;
495 SOSCircleForEachActivePeer(signers_circle, ^(SOSPeerInfoRef peer) {
496 SOSConcordanceStatus peerStatus = CheckPeerStatus(status_circle, peer, user_pubKey, error);
497
498 if (peerStatus == kSOSConcordanceNoPeerSig &&
499 (CFEqualSafe(SOSPeerInfoGetPeerID(peer), excluded_id) || SOSPeerInfoIsCloudIdentity(peer)))
500 peerStatus = kSOSConcordanceNoPeer;
501
502 status = CombineStatus(status, peerStatus); // TODO: Use multiple error gathering.
503 });
504
505 return status;
506 }
507
508 // Is proposed older than current?
509 static inline bool isOlderGeneration(SOSCircleRef current, SOSCircleRef proposed) {
510 return CFNumberCompare(current->generation, proposed->generation, NULL) == kCFCompareGreaterThan;
511 }
512
513 static inline bool SOSCircleIsValidReset(SOSCircleRef current, SOSCircleRef proposed) {
514 return (!isOlderGeneration(current, proposed)) && SOSCircleIsEmpty(proposed); // is current older or equal to proposed and is proposed empty
515 }
516
517
518 bool SOSCircleSharedTrustedPeers(SOSCircleRef current, SOSCircleRef proposed, SOSPeerInfoRef me) {
519 __block bool retval = false;
520 SOSCircleForEachPeer(current, ^(SOSPeerInfoRef peer) {
521 if(!CFEqual(me, peer) && SOSCircleHasPeer(proposed, peer, NULL)) retval = true;
522 });
523 return retval;
524 }
525
526 static SOSConcordanceStatus GetOfferingStatus(SOSCircleRef circle, SecKeyRef user_pubKey, CFErrorRef *error) {
527 __block SOSConcordanceStatus status = kSOSConcordanceNoPeer;
528 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
529 status = CheckPeerStatus(circle, peer, user_pubKey, error);
530 if(status != kSOSConcordanceTrusted) status = kSOSConcordanceNoPeer;
531 });
532 return status;
533 }
534
535
536 SOSConcordanceStatus SOSCircleConcordanceTrust(SOSCircleRef known_circle, SOSCircleRef proposed_circle,
537 SecKeyRef known_pubkey, SecKeyRef user_pubkey,
538 SOSPeerInfoRef me, CFErrorRef *error) {
539 if(user_pubkey == NULL) {
540 SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Concordance with no public key"), NULL, error);
541 return kSOSConcordanceNoUserKey; //TODO: - needs to return an error
542 }
543
544 if(SOSCircleIsDegenerateReset(proposed_circle)) {
545 return kSOSConcordanceTrusted;
546 }
547
548 if (SOSCircleIsValidReset(known_circle, proposed_circle)) {
549 return kSOSConcordanceTrusted;
550 }
551
552 if(!SOSCircleVerifySignatureExists(proposed_circle, user_pubkey, error)) {
553 SOSCreateError(kSOSErrorBadSignature, CFSTR("No public signature"), (error != NULL) ? *error : NULL, error);
554 return kSOSConcordanceNoUserSig;
555 }
556
557 if(!SOSCircleVerify(proposed_circle, user_pubkey, error)) {
558 SOSCreateError(kSOSErrorBadSignature, CFSTR("Bad public signature"), (error != NULL) ? *error : NULL, error);
559 debugDumpCircle(CFSTR("proposed_circle"), proposed_circle);
560 return kSOSConcordanceBadUserSig;
561 }
562
563 if (SOSCircleIsEmpty(known_circle)) {
564 return GetSignersStatus(proposed_circle, proposed_circle, user_pubkey, NULL, error);
565 }
566
567 if(SOSCircleHasDegenerateGeneration(proposed_circle) && SOSCircleIsOffering(proposed_circle)){
568 return GetSignersStatus(proposed_circle, proposed_circle, user_pubkey, NULL, error);
569 }
570
571 if(isOlderGeneration(known_circle, proposed_circle)) {
572 SOSCreateError(kSOSErrorReplay, CFSTR("Bad generation"), NULL, error);
573 debugDumpCircle(CFSTR("isOlderGeneration known_circle"), known_circle);
574 debugDumpCircle(CFSTR("isOlderGeneration proposed_circle"), proposed_circle);
575 return kSOSConcordanceGenOld;
576 }
577
578 if(SOSCircleIsOffering(proposed_circle)){
579 return GetOfferingStatus(proposed_circle, user_pubkey, error);
580 }
581
582 return GetSignersStatus(known_circle, proposed_circle, user_pubkey, me, error);
583 }
584
585
586 static void SOSCircleDestroy(CFTypeRef aObj) {
587 SOSCircleRef c = (SOSCircleRef) aObj;
588
589 CFReleaseNull(c->name);
590 CFReleaseNull(c->generation);
591 CFReleaseNull(c->peers);
592 CFReleaseNull(c->applicants);
593 CFReleaseNull(c->rejected_applicants);
594 CFReleaseNull(c->signatures);
595 }
596
597 static CFMutableStringRef defaultDescription(CFTypeRef aObj){
598 SOSCircleRef c = (SOSCircleRef) aObj;
599
600 CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
601
602 SOSGenerationCountWithDescription(c->generation, ^(CFStringRef genDescription) {
603 CFStringAppendFormat(description, NULL, CFSTR("<SOSCircle@%p: '%@' %@ P:["), c, c->name, genDescription);
604 });
605
606 __block CFStringRef separator = CFSTR("");
607 SOSCircleForEachActivePeer(c, ^(SOSPeerInfoRef peer) {
608 CFStringRef sig = NULL;
609 if (SOSCircleVerifyPeerSigned(c, peer, NULL)) {
610 sig = CFSTR("√");
611 } else {
612 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer);
613 CFDataRef signature = SOSCircleGetSignature(c, pub_key, NULL);
614 sig = (signature == NULL) ? CFSTR("-") : CFSTR("?");
615 CFReleaseNull(pub_key);
616 }
617
618 CFStringAppendFormat(description, NULL, CFSTR("%@%@ %@"), separator, peer, sig);
619 separator = CFSTR(",");
620 });
621
622 //applicants
623 CFStringAppend(description, CFSTR("], A:["));
624 separator = CFSTR("");
625 if(CFSetGetCount(c->applicants) == 0 )
626 CFStringAppendFormat(description, NULL, CFSTR("-"));
627 else{
628
629 SOSCircleForEachApplicant(c, ^(SOSPeerInfoRef peer) {
630 CFStringAppendFormat(description, NULL, CFSTR("%@%@"), separator, peer);
631 separator = CFSTR(",");
632 });
633 }
634
635 //rejected
636 CFStringAppend(description, CFSTR("], R:["));
637 separator = CFSTR("");
638 if(CFSetGetCount(c->rejected_applicants) == 0)
639 CFStringAppendFormat(description, NULL, CFSTR("-"));
640 else{
641 CFSetForEach(c->rejected_applicants, ^(const void *value) {
642 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
643 CFStringAppendFormat(description, NULL, CFSTR("%@%@"), separator, peer);
644 separator = CFSTR(",");
645 });
646 }
647 CFStringAppend(description, CFSTR("]>"));
648 return description;
649
650 }
651 static CFMutableStringRef descriptionWithFormatOptions(CFTypeRef aObj, CFDictionaryRef formatOptions){
652 SOSCircleRef c = (SOSCircleRef) aObj;
653
654 CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
655
656 if(CFDictionaryContainsKey(formatOptions, CFSTR("SyncD"))) {
657 CFStringRef generationDescription = SOSGenerationCountCopyDescription(c->generation);
658 CFStringAppendFormat(description, NULL, CFSTR("<C: gen:'%@' %@>\n"), generationDescription, c->name);
659 CFReleaseNull(generationDescription);
660 __block CFStringRef separator = CFSTR("\t\t");
661 SOSCircleForEachActivePeer(c, ^(SOSPeerInfoRef peer) {
662 CFStringRef sig = NULL;
663 if (SOSCircleVerifyPeerSigned(c, peer, NULL)) {
664 sig = CFSTR("√");
665 } else {
666 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer);
667 CFDataRef signature = SOSCircleGetSignature(c, pub_key, NULL);
668 sig = (signature == NULL) ? CFSTR("-") : CFSTR("?");
669 CFReleaseNull(pub_key);
670 }
671
672 CFStringAppendFormat(description, formatOptions, CFSTR("%@%@ %@"), separator, peer, sig);
673 separator = CFSTR("\n\t\t");
674 });
675 CFStringAppend(description, CFSTR("\n\t\t<A:["));
676 separator = CFSTR("");
677
678 //applicants list
679 if(CFSetGetCount(c->applicants) == 0 )
680 CFStringAppendFormat(description, NULL, CFSTR("-"));
681 else{
682
683 SOSCircleForEachApplicant(c, ^(SOSPeerInfoRef peer) {
684 CFStringAppendFormat(description, formatOptions, CFSTR("%@A: %@"), separator, peer);
685 separator = CFSTR("\n\t\t\t");
686 });
687 }
688 //rejected list
689 CFStringAppend(description, CFSTR("]> \n\t\t<R:["));
690 separator = CFSTR("");
691 if(CFSetGetCount(c->rejected_applicants) == 0)
692 CFStringAppendFormat(description, NULL, CFSTR("-"));
693 else{
694 CFSetForEach(c->rejected_applicants, ^(const void *value) {
695 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
696 CFStringAppendFormat(description, formatOptions, CFSTR("%@R: %@"), separator, peer);
697 separator = CFSTR("\n\t\t");
698 });
699 }
700 CFStringAppend(description, CFSTR("]>"));
701 }
702
703 else{
704 CFReleaseNull(description);
705 description = defaultDescription(aObj);
706 }
707
708 return description;
709
710 }
711
712
713 static CFStringRef SOSCircleCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
714 SOSCircleRef c = (SOSCircleRef) aObj;
715 SOSCircleAssertStable(c);
716 CFMutableStringRef description = NULL;
717
718 if(formatOptions != NULL){
719 description = descriptionWithFormatOptions(aObj, formatOptions);
720 }
721 else{
722 description = defaultDescription(aObj);
723 }
724 return description;
725 }
726
727 CFStringRef SOSCircleGetName(SOSCircleRef circle) {
728 assert(circle);
729 assert(circle->name);
730 return circle->name;
731 }
732
733 const char *SOSCircleGetNameC(SOSCircleRef circle) {
734 CFStringRef name = SOSCircleGetName(circle);
735 if (!name)
736 return strdup("");
737 return CFStringToCString(name);
738 }
739
740 SOSGenCountRef SOSCircleGetGeneration(SOSCircleRef circle) {
741 assert(circle);
742 assert(circle->generation);
743 return circle->generation;
744 }
745
746 void SOSCircleSetGeneration(SOSCircleRef circle, SOSGenCountRef gencount) {
747 assert(circle);
748 CFReleaseNull(circle->generation);
749 circle->generation = CFRetainSafe(gencount);
750 }
751
752 int64_t SOSCircleGetGenerationSint(SOSCircleRef circle) {
753 SOSGenCountRef gen = SOSCircleGetGeneration(circle);
754 return SOSGetGenerationSint(gen);
755 }
756
757 void SOSCircleGenerationSetValue(SOSCircleRef circle, int64_t value) {
758 CFAssignRetained(circle->generation, SOSGenerationCreateWithValue(value));
759 }
760
761 void SOSCircleGenerationIncrement(SOSCircleRef circle) {
762 SOSGenCountRef old = circle->generation;
763 circle->generation = SOSGenerationIncrementAndCreate(old);
764 CFReleaseNull(old);
765 }
766
767 int SOSCircleCountPeers(SOSCircleRef circle) {
768 SOSCircleAssertStable(circle);
769 __block int count = 0;
770 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
771 ++count;
772 });
773 return count;
774 }
775
776 int SOSCircleCountActivePeers(SOSCircleRef circle) {
777 SOSCircleAssertStable(circle);
778 __block int count = 0;
779 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
780 ++count;
781 });
782 return count;
783 }
784
785 int SOSCircleCountActiveValidPeers(SOSCircleRef circle, SecKeyRef pubkey) {
786 SOSCircleAssertStable(circle);
787 __block int count = 0;
788 SOSCircleForEachActiveValidPeer(circle, pubkey, ^(SOSPeerInfoRef peer) {
789 ++count;
790 });
791 return count;
792 }
793
794 int SOSCircleCountRetiredPeers(SOSCircleRef circle) {
795 SOSCircleAssertStable(circle);
796 __block int count = 0;
797 SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) {
798 ++count;
799 });
800 return count;
801 }
802
803 int SOSCircleCountApplicants(SOSCircleRef circle) {
804 SOSCircleAssertStable(circle);
805
806 return (int)CFSetGetCount(circle->applicants);
807 }
808
809 bool SOSCircleHasApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
810 SOSCircleAssertStable(circle);
811
812 return CFSetContainsValue(circle->applicants, peerInfo);
813 }
814
815 CFMutableSetRef SOSCircleCopyApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
816 SOSCircleAssertStable(circle);
817
818 return CFSetCreateMutableCopy(allocator, 0, circle->applicants);
819 }
820
821 int SOSCircleCountRejectedApplicants(SOSCircleRef circle) {
822 SOSCircleAssertStable(circle);
823
824 return (int)CFSetGetCount(circle->rejected_applicants);
825 }
826
827 bool SOSCircleHasRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
828 SOSCircleAssertStable(circle);
829 return CFSetContainsValue(circle->rejected_applicants, peerInfo);
830 }
831
832 SOSPeerInfoRef SOSCircleCopyRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
833 SOSCircleAssertStable(circle);
834 return CFRetainSafe((SOSPeerInfoRef)CFSetGetValue(circle->rejected_applicants, peerInfo));
835 }
836
837 CFMutableArrayRef SOSCircleCopyRejectedApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
838 SOSCircleAssertStable(circle);
839
840 return CFSetCopyValuesCFArray(circle->rejected_applicants);
841 }
842
843 bool SOSCircleHasPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
844 SOSCircleAssertStable(circle);
845 __block bool found = false;
846 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
847 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = true;
848 });
849 return found;
850 }
851
852 SOSPeerInfoRef SOSCircleCopyPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
853 SOSCircleAssertStable(circle);
854 __block SOSPeerInfoRef found = NULL;
855 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
856 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = peer;
857 });
858 return found ? SOSPeerInfoCreateCopy(kCFAllocatorDefault, found, NULL) : NULL;
859 }
860
861 bool SOSCircleHasPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
862 if(!peerInfo) return false;
863 return SOSCircleHasPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
864 }
865
866 bool SOSCircleHasActivePeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
867 SOSCircleAssertStable(circle);
868 __block bool found = false;
869 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
870 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = true;
871 });
872 return found;
873 }
874
875 bool SOSCircleHasActivePeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
876 if(!peerInfo) return false;
877 return SOSCircleHasActivePeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
878 }
879
880 bool SOSCircleHasActiveValidPeerWithID(SOSCircleRef circle, CFStringRef peerid, SecKeyRef user_public_key, CFErrorRef *error) {
881 SOSCircleAssertStable(circle);
882 __block bool found = false;
883 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
884 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer)) && SOSPeerInfoApplicationVerify(peer, user_public_key, NULL)) found = true;
885 });
886 return found;
887 }
888
889 bool SOSCircleHasActiveValidPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, SecKeyRef user_public_key, CFErrorRef *error) {
890 if(!peerInfo) return false;
891 return SOSCircleHasActiveValidPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), user_public_key, error);
892 }
893
894
895 bool SOSCircleResetToEmpty(SOSCircleRef circle, CFErrorRef *error) {
896 CFSetRemoveAllValues(circle->applicants);
897 CFSetRemoveAllValues(circle->rejected_applicants);
898 CFSetRemoveAllValues(circle->peers);
899 CFDictionaryRemoveAllValues(circle->signatures);
900 SOSGenCountRef oldGen = SOSCircleGetGeneration(circle);
901 SOSGenCountRef newGen = SOSGenerationCreateWithBaseline(oldGen);
902 SOSCircleSetGeneration(circle, newGen);
903 return true;
904 }
905
906 bool SOSCircleResetToOffering(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error){
907
908 return SOSCircleResetToEmpty(circle, error)
909 && SOSCircleRequestAdmission(circle, user_privkey, requestor, error)
910 && SOSCircleAcceptRequest(circle, user_privkey, requestor, SOSFullPeerInfoGetPeerInfo(requestor), error);
911 }
912
913 bool SOSCircleRemoveRetired(SOSCircleRef circle, CFErrorRef *error) {
914 CFSetRemoveAllPassing(circle->peers, ^ bool (const void *element) {
915 SOSPeerInfoRef peer = (SOSPeerInfoRef) element;
916
917 return SOSPeerInfoIsRetirementTicket(peer);
918 });
919
920 return true;
921 }
922
923 static bool SOSCircleRecordAdmissionRequest(SOSCircleRef circle, SecKeyRef user_pubkey, SOSPeerInfoRef requestorPeerInfo, CFErrorRef *error) {
924 SOSCircleAssertStable(circle);
925
926 bool isPeer = SOSCircleHasPeer(circle, requestorPeerInfo, error);
927
928 require_action_quiet(!isPeer, fail, SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Cannot request admission when already a peer"), NULL, error));
929
930 CFSetTransferObject(requestorPeerInfo, circle->rejected_applicants, circle->applicants);
931
932 return true;
933
934 fail:
935 return false;
936
937 }
938
939 bool SOSCircleRequestReadmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSPeerInfoRef peer, CFErrorRef *error) {
940 bool success = false;
941
942 require_quiet(SOSPeerInfoApplicationVerify(peer, user_pubkey, error), fail);
943 success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, peer, error);
944 fail:
945 return success;
946 }
947
948 bool SOSCircleRequestAdmission(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
949 bool success = false;
950
951 SecKeyRef user_pubkey = SecKeyCreatePublicFromPrivate(user_privkey);
952 require_action_quiet(user_pubkey, fail, SOSCreateError(kSOSErrorBadKey, CFSTR("No public key for key"), NULL, error));
953
954 require(SOSFullPeerInfoPromoteToApplication(requestor, user_privkey, error), fail);
955
956 success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, SOSFullPeerInfoGetPeerInfo(requestor), error);
957 fail:
958 CFReleaseNull(user_pubkey);
959 return success;
960 }
961
962 static bool sosCircleUpdatePeerInfoSet(CFMutableSetRef theSet, SOSPeerInfoRef replacement_peer_info) {
963 CFTypeRef old = NULL;
964 if(!replacement_peer_info) return false;
965 if(!(old = CFSetGetValue(theSet, replacement_peer_info))) return false;
966 if(CFEqualSafe(old, replacement_peer_info)) return false;
967 CFSetReplaceValue(theSet, replacement_peer_info);
968 return true;
969 }
970
971 bool SOSCircleUpdatePeerInfo(SOSCircleRef circle, SOSPeerInfoRef replacement_peer_info) {
972 if(sosCircleUpdatePeerInfoSet(circle->peers, replacement_peer_info)) return true;
973 if(sosCircleUpdatePeerInfoSet(circle->applicants, replacement_peer_info)) return true;
974 if(sosCircleUpdatePeerInfoSet(circle->rejected_applicants, replacement_peer_info)) return true;
975 return false;
976 }
977
978 static bool SOSCircleRemovePeerInternal(SOSCircleRef circle, SOSFullPeerInfoRef requestor, SOSPeerInfoRef peer_to_remove, CFErrorRef *error) {
979 SOSPeerInfoRef requestor_peer_info = SOSFullPeerInfoGetPeerInfo(requestor);
980
981 if (SOSCircleHasPeer(circle, peer_to_remove, NULL)) {
982 if (!SOSCircleHasPeer(circle, requestor_peer_info, error)) {
983 SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Must be peer to remove peer"), NULL, error);
984 return false;
985 }
986 CFSetRemoveValue(circle->peers, peer_to_remove);
987 }
988
989 if (SOSCircleHasApplicant(circle, peer_to_remove, error)) {
990 return SOSCircleRejectRequest(circle, requestor, peer_to_remove, error);
991 }
992
993 return true;
994 }
995
996 bool SOSCircleRemovePeers(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFSetRef peersToRemove, CFErrorRef *error) {
997
998 bool success = false;
999
1000 __block bool removed_all = true;
1001 CFSetForEach(peersToRemove, ^(const void *value) {
1002 SOSPeerInfoRef peerInfo = asSOSPeerInfo(value);
1003 if (peerInfo) {
1004 removed_all &= SOSCircleRemovePeerInternal(circle, requestor, peerInfo, error);
1005 }
1006 });
1007
1008 require_quiet(removed_all, exit);
1009
1010 require_quiet(SOSCircleGenerationSign(circle, user_privkey, requestor, error), exit);
1011
1012 success = true;
1013
1014 exit:
1015 return success;
1016 }
1017
1018 bool SOSCircleRemovePeer(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, SOSPeerInfoRef peer_to_remove, CFErrorRef *error) {
1019 bool success = false;
1020
1021 require_quiet(SOSCircleRemovePeerInternal(circle, requestor, peer_to_remove, error), exit);
1022
1023 require_quiet(SOSCircleGenerationSign(circle, user_privkey, requestor, error), exit);
1024
1025 success = true;
1026 exit:
1027 return success;
1028 }
1029
1030 bool SOSCircleAcceptRequest(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1031 SOSCircleAssertStable(circle);
1032
1033 SecKeyRef publicKey = NULL;
1034 bool result = false;
1035
1036 require_action_quiet(CFSetContainsValue(circle->applicants, peerInfo), fail,
1037 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot accept non-applicant"), NULL, error));
1038
1039 publicKey = SecKeyCreatePublicFromPrivate(user_privkey);
1040 require_quiet(SOSPeerInfoApplicationVerify(peerInfo, publicKey, error), fail);
1041
1042 CFSetTransferObject(peerInfo, circle->applicants, circle->peers);
1043
1044 result = SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
1045
1046 fail:
1047 CFReleaseNull(publicKey);
1048 return result;
1049 }
1050
1051 bool SOSCircleWithdrawRequest(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1052 SOSCircleAssertStable(circle);
1053
1054 CFSetRemoveValue(circle->applicants, peerInfo);
1055
1056 return true;
1057 }
1058
1059 bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1060 SOSCircleAssertStable(circle);
1061
1062 CFSetRemoveValue(circle->rejected_applicants, peerInfo);
1063
1064 return true;
1065 }
1066
1067
1068 bool SOSCircleRejectRequest(SOSCircleRef circle, SOSFullPeerInfoRef device_rejector,
1069 SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1070 SOSCircleAssertStable(circle);
1071
1072 if (CFEqual(SOSPeerInfoGetPeerID(peerInfo), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector))))
1073 return SOSCircleWithdrawRequest(circle, peerInfo, error);
1074
1075 if (!CFSetContainsValue(circle->applicants, peerInfo)) {
1076 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot reject non-applicant"), NULL, error);
1077 return false;
1078 }
1079
1080 CFSetTransferObject(peerInfo, circle->applicants, circle->rejected_applicants);
1081
1082 // TODO: Maybe we sign the rejection with device_rejector.
1083
1084 return true;
1085 }
1086
1087 bool SOSCircleAcceptRequests(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver,
1088 CFErrorRef *error) {
1089 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1090 __block bool result = false;
1091
1092 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
1093 if (!SOSCircleAcceptRequest(circle, user_privkey, device_approver, peer, error)) {
1094 secnotice("circle", "error in SOSCircleAcceptRequest\n");
1095 } else {
1096 secnotice("circle", "Accepted peer: %@", peer);
1097 result = true;
1098 }
1099 });
1100
1101 if (result) {
1102 SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
1103 secnotice("circle", "Countersigned accepted requests");
1104 }
1105
1106 return result;
1107 }
1108
1109 bool SOSCirclePeerSigUpdate(SOSCircleRef circle, SecKeyRef userPrivKey, SOSFullPeerInfoRef fpi,
1110 CFErrorRef *error) {
1111 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1112 __block bool result = false;
1113 SecKeyRef userPubKey = SecKeyCreatePublicFromPrivate(userPrivKey);
1114
1115 // We're going to remove any applicants using a mismatched user key.
1116 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
1117 if(!SOSPeerInfoApplicationVerify(peer, userPubKey, NULL)) {
1118 if(!SOSCircleRejectRequest(circle, fpi, peer, NULL)) {
1119 // do we care?
1120 }
1121 }
1122 });
1123
1124 result = SOSCircleUpdatePeerInfo(circle, SOSFullPeerInfoGetPeerInfo(fpi));
1125
1126 if (result) {
1127 SOSCircleGenerationSign(circle, userPrivKey, fpi, error);
1128 secnotice("circle", "Generation signed updated signatures on peerinfo");
1129 }
1130
1131 return result;
1132 }
1133
1134 static inline void SOSCircleForEachPeerMatching(SOSCircleRef circle,
1135 void (^action)(SOSPeerInfoRef peer),
1136 bool (^condition)(SOSPeerInfoRef peer)) {
1137 CFSetForEach(circle->peers, ^(const void *value) {
1138 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
1139 if (condition(peer))
1140 action(peer);
1141 });
1142 }
1143
1144 static inline bool isHiddenPeer(SOSPeerInfoRef peer) {
1145 return SOSPeerInfoIsRetirementTicket(peer) || SOSPeerInfoIsCloudIdentity(peer);
1146 }
1147
1148 void SOSCircleForEachPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1149 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1150 return !isHiddenPeer(peer);
1151 });
1152 }
1153
1154 void SOSCircleForEachRetiredPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1155 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1156 return SOSPeerInfoIsRetirementTicket(peer);
1157 });
1158 }
1159
1160 void SOSCircleForEachActivePeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1161 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1162 return true;
1163 });
1164 }
1165
1166 void SOSCircleForEachActiveValidPeer(SOSCircleRef circle, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)) {
1167 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1168 return SOSPeerInfoApplicationVerify(peer, user_public_key, NULL);
1169 });
1170 }
1171
1172 void SOSCircleForEachValidPeer(SOSCircleRef circle, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)) {
1173 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1174 return !isHiddenPeer(peer) && SOSPeerInfoApplicationVerify(peer, user_public_key, NULL);
1175 });
1176 }
1177
1178 void SOSCircleForEachApplicant(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1179 CFSetForEach(circle->applicants, ^(const void*value) { action((SOSPeerInfoRef) value); } );
1180 }
1181
1182
1183 CFMutableSetRef SOSCircleCopyPeers(SOSCircleRef circle, CFAllocatorRef allocator) {
1184 SOSCircleAssertStable(circle);
1185
1186 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
1187
1188 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
1189 CFSetAddValue(result, peer);
1190 });
1191
1192 return result;
1193 }
1194
1195 bool SOSCircleAppendConcurringPeers(SOSCircleRef circle, CFMutableArrayRef appendHere, CFErrorRef *error) {
1196 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1197 CFErrorRef localError = NULL;
1198 if (SOSCircleVerifyPeerSigned(circle, peer, &localError)) {
1199 SOSPeerInfoRef peerInfo = SOSPeerInfoCreateCopy(kCFAllocatorDefault, peer, error);
1200 CFArrayAppendValue(appendHere, peerInfo);
1201 CFRelease(peerInfo);
1202 } else if (error != NULL) {
1203 secerror("Error checking concurrence: %@", localError);
1204 }
1205 CFReleaseNull(localError);
1206 });
1207
1208 return true;
1209 }
1210
1211 CFMutableArrayRef SOSCircleCopyConcurringPeers(SOSCircleRef circle, CFErrorRef* error) {
1212 SOSCircleAssertStable(circle);
1213
1214 CFMutableArrayRef concurringPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
1215
1216 if (!SOSCircleAppendConcurringPeers(circle, concurringPeers, error))
1217 CFReleaseNull(concurringPeers);
1218
1219 return concurringPeers;
1220 }
1221
1222 SOSFullPeerInfoRef SOSCircleCopyiCloudFullPeerInfoRef(SOSCircleRef circle, CFErrorRef *error) {
1223 __block SOSFullPeerInfoRef cloud_full_peer = NULL;
1224 __block CFErrorRef searchError = NULL;
1225 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1226 if (SOSPeerInfoIsCloudIdentity(peer)) {
1227 if (cloud_full_peer == NULL) {
1228 if (searchError) {
1229 secerror("More than one cloud identity found, first had error, trying new one.");
1230 }
1231 CFReleaseNull(searchError);
1232 cloud_full_peer = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, &searchError);
1233 if (!cloud_full_peer) {
1234 secnotice("icloud-identity", "Failed to make FullPeer for iCloud Identity: %@ (%@)", cloud_full_peer, searchError);
1235 }
1236 } else {
1237 secerror("Additional cloud identity found in circle after successful creation: %@", circle);
1238 }
1239 }
1240 });
1241 // If we didn't find one at all, report the error.
1242 if (cloud_full_peer == NULL && searchError == NULL) {
1243 SOSErrorCreate(kSOSErrorNoiCloudPeer, &searchError, NULL, CFSTR("No iCloud identity PeerInfo found in circle"));
1244 secnotice("icloud-identity", "No iCloud identity PeerInfo found in circle");
1245 }
1246 if (error) {
1247 CFTransferRetained(*error, searchError);
1248 }
1249 CFReleaseNull(searchError);
1250 return cloud_full_peer;
1251 }
1252
1253 void debugDumpCircle(CFStringRef message, SOSCircleRef circle) {
1254 CFErrorRef error;
1255
1256 secinfo("circledebug", "%@: %@", message, circle);
1257 if (!circle)
1258 return;
1259
1260 CFDataRef derdata = SOSCircleCopyEncodedData(circle, kCFAllocatorDefault, &error);
1261 if (derdata) {
1262 CFStringRef hex = CFDataCopyHexString(derdata);
1263 secinfo("circledebug", "Full contents: %@", hex);
1264 if (hex) CFRelease(hex);
1265 CFRelease(derdata);
1266 }
1267 }