]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ProjectHeaders/Security/SecureObjectSync/SOSCircle.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / ProjectHeaders / Security / 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 int64_t gen = 1;
64
65 assert(name);
66
67 c->name = CFStringCreateCopy(allocator, name);
68 c->generation = CFNumberCreate(allocator, kCFNumberSInt64Type, &gen);
69 c->peers = CFSetCreateMutableForSOSPeerInfosByID(allocator);
70 c->applicants = CFSetCreateMutableForSOSPeerInfosByID(allocator);
71 c->rejected_applicants = CFSetCreateMutableForSOSPeerInfosByID(allocator);
72 c->signatures = CFDictionaryCreateMutableForCFTypes(allocator);
73 return c;
74 }
75
76 static CFNumberRef SOSCircleGenerationCopy(CFNumberRef generation) {
77 int64_t value;
78 CFAllocatorRef allocator = CFGetAllocator(generation);
79 CFNumberGetValue(generation, kCFNumberSInt64Type, &value);
80 return CFNumberCreate(allocator, kCFNumberSInt64Type, &value);
81 }
82
83 static CFMutableSetRef CFSetOfPeerInfoDeepCopy(CFAllocatorRef allocator, CFSetRef peerInfoSet)
84 {
85 __block CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
86 CFSetForEach(peerInfoSet, ^(const void *value) {
87 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
88 CFErrorRef localError = NULL;
89 SOSPeerInfoRef copiedPeer = SOSPeerInfoCreateCopy(allocator, pi, &localError);
90 if (copiedPeer) {
91 CFSetAddValue(result, copiedPeer);
92 } else {
93 secerror("Failed to copy peer: %@ (%@)", pi, localError);
94 }
95 CFReleaseSafe(copiedPeer);
96 CFReleaseSafe(localError);
97 });
98 return result;
99 }
100
101 SOSCircleRef SOSCircleCopyCircle(CFAllocatorRef allocator, SOSCircleRef otherCircle, CFErrorRef *error)
102 {
103 SOSCircleRef c = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
104
105 assert(otherCircle);
106 c->name = CFStringCreateCopy(allocator, otherCircle->name);
107 c->generation = SOSCircleGenerationCopy(otherCircle->generation);
108
109 c->peers = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->peers);
110 c->applicants = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->applicants);
111 c->rejected_applicants = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->rejected_applicants);
112
113 c->signatures = CFDictionaryCreateMutableCopy(allocator, 0, otherCircle->signatures);
114
115 return c;
116 }
117
118 static Boolean SOSCircleCompare(CFTypeRef lhs, CFTypeRef rhs) {
119 if (CFGetTypeID(lhs) != SOSCircleGetTypeID()
120 || CFGetTypeID(rhs) != SOSCircleGetTypeID())
121 return false;
122
123 SOSCircleRef left = SOSCircleConvertAndAssertStable(lhs);
124 SOSCircleRef right = SOSCircleConvertAndAssertStable(rhs);
125
126 // TODO: we should be doing set equality for peers and applicants.
127 return NULL != left && NULL != right
128 && CFEqualSafe(left->generation, right->generation)
129 && SOSPeerInfoSetContainsIdenticalPeers(left->peers, right->peers)
130 && SOSPeerInfoSetContainsIdenticalPeers(left->applicants, right->applicants)
131 && SOSPeerInfoSetContainsIdenticalPeers(left->rejected_applicants, right->rejected_applicants)
132 && CFEqualSafe(left->signatures, right->signatures);
133 }
134
135 static CFMutableArrayRef CFSetCopyValuesCFArray(CFSetRef set)
136 {
137 CFIndex count = CFSetGetCount(set);
138
139 CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
140 if (count > 0) {
141 const void * values[count];
142 CFSetGetValues(set, values);
143 for (int current = 0; current < count; ++current) {
144 CFArrayAppendValue(result, values[current]);
145 }
146 }
147
148 return result;
149 }
150
151 static bool SOSCircleDigestArray(const struct ccdigest_info *di, CFMutableArrayRef array, void *hash_result, CFErrorRef *error)
152 {
153 __block bool success = true;
154 ccdigest_di_decl(di, array_digest);
155 const void * a_digest = array_digest;
156
157 ccdigest_init(di, array_digest);
158 CFArraySortValues(array, CFRangeMake(0, CFArrayGetCount(array)), SOSPeerInfoCompareByID, SOSPeerCmpPubKeyHash);
159 CFArrayForEach(array, ^(const void *peer) {
160 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes((SOSPeerInfoRef)peer, di, a_digest, error))
161 success = false;
162 });
163 ccdigest_final(di, array_digest, hash_result);
164
165 return success;
166 }
167
168 static bool SOSCircleDigestSet(const struct ccdigest_info *di, CFMutableSetRef set, void *hash_result, CFErrorRef *error)
169 {
170 CFMutableArrayRef values = CFSetCopyValuesCFArray(set);
171
172 bool result = SOSCircleDigestArray(di, values, hash_result, error);
173
174 CFReleaseSafe(values);
175
176 return result;
177 }
178
179
180 static bool SOSCircleHash(const struct ccdigest_info *di, SOSCircleRef circle, void *hash_result, CFErrorRef *error) {
181 ccdigest_di_decl(di, circle_digest);
182 ccdigest_init(di, circle_digest);
183 int64_t gen = SOSCircleGetGenerationSint(circle);
184 ccdigest_update(di, circle_digest, sizeof(gen), &gen);
185
186 SOSCircleDigestSet(di, circle->peers, hash_result, error);
187 ccdigest_update(di, circle_digest, di->output_size, hash_result);
188 ccdigest_final(di, circle_digest, hash_result);
189 return true;
190 }
191
192 static bool SOSCircleSetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFDataRef signature, CFErrorRef *error) {
193 bool result = false;
194
195 CFStringRef pubKeyID = SOSCopyIDOfKey(pubkey, error);
196 require_quiet(pubKeyID, fail);
197 CFDictionarySetValue(circle->signatures, pubKeyID, signature);
198 result = true;
199
200 fail:
201 CFReleaseSafe(pubKeyID);
202 return result;
203 }
204
205 static bool SOSCircleRemoveSignatures(SOSCircleRef circle, CFErrorRef *error) {
206 CFDictionaryRemoveAllValues(circle->signatures);
207 return true;
208 }
209
210 static CFDataRef SOSCircleGetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFErrorRef *error) {
211 CFStringRef pubKeyID = SOSCopyIDOfKey(pubkey, error);
212 CFDataRef result = NULL;
213 require_quiet(pubKeyID, fail);
214
215 CFTypeRef value = (CFDataRef)CFDictionaryGetValue(circle->signatures, pubKeyID);
216
217 if (isData(value)) result = (CFDataRef) value;
218
219 fail:
220 CFReleaseSafe(pubKeyID);
221 return result;
222 }
223
224 bool SOSCircleSign(SOSCircleRef circle, SecKeyRef privKey, CFErrorRef *error) {
225 if (!privKey) return false; // Really assertion but not always true for now.
226 CFAllocatorRef allocator = CFGetAllocator(circle);
227 uint8_t tmp[4096];
228 size_t tmplen = 4096;
229 const struct ccdigest_info *di = ccsha256_di();
230 uint8_t hash_result[di->output_size];
231
232 SOSCircleHash(di, circle, hash_result, error);
233 OSStatus stat = SecKeyRawSign(privKey, kSecPaddingNone, hash_result, di->output_size, tmp, &tmplen);
234 if(stat) {
235 // TODO - Create a CFErrorRef;
236 secerror("Bad Circle SecKeyRawSign, stat: %ld", (long)stat);
237 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Circle SecKeyRawSign"), (error != NULL) ? *error : NULL, error);
238 return false;
239 };
240 CFDataRef signature = CFDataCreate(allocator, tmp, tmplen);
241 SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(privKey);
242 SOSCircleSetSignature(circle, publicKey, signature, error);
243 CFReleaseNull(publicKey);
244 CFRelease(signature);
245 return true;
246 }
247
248 static bool SOSCircleConcordanceRingSign(SOSCircleRef circle, SecKeyRef privKey, CFErrorRef *error) {
249 secnotice("Development", "SOSCircleEnsureRingConsistency requires ring signing op", NULL);
250 return true;
251 }
252
253
254 bool SOSCircleVerifySignatureExists(SOSCircleRef circle, SecKeyRef pubKey, CFErrorRef *error) {
255 if(!pubKey) {
256 // TODO ErrorRef
257 secerror("SOSCircleVerifySignatureExists no pubKey");
258 SOSCreateError(kSOSErrorBadFormat, CFSTR("SOSCircleVerifySignatureExists no pubKey"), (error != NULL) ? *error : NULL, error);
259 return false;
260 }
261 CFDataRef signature = SOSCircleGetSignature(circle, pubKey, error);
262 return NULL != signature;
263 }
264
265 bool SOSCircleVerify(SOSCircleRef circle, SecKeyRef pubKey, CFErrorRef *error) {
266 const struct ccdigest_info *di = ccsha256_di();
267 uint8_t hash_result[di->output_size];
268
269 SOSCircleHash(di, circle, hash_result, error);
270
271 CFDataRef signature = SOSCircleGetSignature(circle, pubKey, error);
272 if(!signature) return false;
273
274 return SecKeyRawVerify(pubKey, kSecPaddingNone, hash_result, di->output_size,
275 CFDataGetBytePtr(signature), CFDataGetLength(signature)) == errSecSuccess;
276 }
277
278 bool SOSCircleVerifyPeerSigned(SOSCircleRef circle, SOSPeerInfoRef peer, CFErrorRef *error) {
279 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer);
280 bool result = SOSCircleVerify(circle, pub_key, error);
281 CFReleaseSafe(pub_key);
282 return result;
283 }
284
285 static void CFSetRemoveAllPassing(CFMutableSetRef set, bool (^test)(const void *) ){
286 CFMutableArrayRef toBeRemoved = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
287
288 CFSetForEach(set, ^(const void *value) {
289 if (test(value))
290 CFArrayAppendValue(toBeRemoved, value);
291 });
292
293 CFArrayForEach(toBeRemoved, ^(const void *value) {
294 CFSetRemoveValue(set, value);
295 });
296 CFReleaseNull(toBeRemoved);
297 }
298
299 static void SOSCircleRejectNonValidApplicants(SOSCircleRef circle, SecKeyRef pubkey) {
300 CFMutableSetRef applicants = SOSCircleCopyApplicants(circle, NULL);
301 CFSetForEach(applicants, ^(const void *value) {
302 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
303 if(!SOSPeerInfoApplicationVerify(pi, pubkey, NULL)) {
304 CFSetTransferObject(pi, circle->applicants, circle->rejected_applicants);
305 }
306 });
307 CFReleaseNull(applicants);
308 }
309
310 static SOSPeerInfoRef SOSCircleCopyPeerInfo(SOSCircleRef circle, CFStringRef peer_id, CFErrorRef *error) {
311 __block SOSPeerInfoRef result = NULL;
312
313 CFSetForEach(circle->peers, ^(const void *value) {
314 if (result == NULL) {
315 SOSPeerInfoRef tpi = (SOSPeerInfoRef)value;
316 if (CFEqual(SOSPeerInfoGetPeerID(tpi), peer_id))
317 result = tpi;
318 }
319 });
320
321 CFRetainSafe(result);
322 return result;
323 }
324
325 static bool SOSCircleUpgradePeerInfo(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo) {
326 bool retval = false;
327 SecKeyRef userPubKey = SecKeyCreatePublicFromPrivate(user_approver);
328 SOSPeerInfoRef fpi_pi = SOSFullPeerInfoGetPeerInfo(peerinfo);
329 SOSPeerInfoRef pi = SOSCircleCopyPeerInfo(circle, SOSPeerInfoGetPeerID(fpi_pi), NULL);
330 require_quiet(pi, out);
331 require_quiet(SOSPeerInfoApplicationVerify(pi, userPubKey, NULL), re_sign);
332 CFReleaseNull(userPubKey);
333 CFReleaseNull(pi);
334 return true;
335
336 re_sign:
337 secnotice("circle", "SOSCircleGenerationSign: Upgraded peer's Application Signature");
338 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peerinfo, NULL);
339 require_quiet(device_key, out);
340 SOSPeerInfoRef new_pi = SOSPeerInfoCopyAsApplication(pi, user_approver, device_key, NULL);
341 if(SOSCircleUpdatePeerInfo(circle, new_pi))
342 retval = true;
343 CFReleaseNull(new_pi);
344 CFReleaseNull(device_key);
345 out:
346 CFReleaseNull(userPubKey);
347 CFReleaseNull(pi);
348 return retval;
349 }
350
351 static bool SOSCircleEnsureRingConsistency(SOSCircleRef circle, CFErrorRef *error) {
352 secnotice("Development", "SOSCircleEnsureRingConsistency requires ring membership and generation count consistency check", NULL);
353 return true;
354 }
355
356 bool SOSCircleSignOldStyleResetToOfferingCircle(SOSCircleRef circle, SOSFullPeerInfoRef peerinfo, SecKeyRef user_approver, CFErrorRef *error){
357
358 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
359 SecKeyRef publicKey = NULL;
360 require_quiet(ourKey, fail);
361
362 // Check if we're using an invalid peerinfo for this op. There are cases where we might not be "upgraded".
363 require_quiet(SOSCircleUpgradePeerInfo(circle, user_approver, peerinfo), fail);
364 SOSCircleRemoveRetired(circle, error); // Prune off retirees since we're signing this one
365 CFSetRemoveAllValues(circle->rejected_applicants); // Dump rejects so we clean them up sometime.
366 publicKey = SecKeyCreatePublicFromPrivate(user_approver);
367 SOSCircleRejectNonValidApplicants(circle, publicKey);
368 require_quiet(SOSCircleEnsureRingConsistency(circle, error), fail);
369 require_quiet(SOSCircleRemoveSignatures(circle, error), fail);
370 require_quiet(SOSCircleSign(circle, user_approver, error), fail);
371 require_quiet(SOSCircleSign(circle, ourKey, error), fail);
372
373 CFReleaseNull(ourKey);
374 CFReleaseNull(publicKey);
375 return true;
376
377 fail:
378 CFReleaseNull(ourKey);
379 CFReleaseNull(publicKey);
380 return false;
381 }
382
383
384 bool SOSCircleGenerationSign(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
385 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
386 SecKeyRef publicKey = NULL;
387 require_quiet(ourKey, fail);
388
389 // Check if we're using an invalid peerinfo for this op. There are cases where we might not be "upgraded".
390 require_quiet(SOSCircleUpgradePeerInfo(circle, user_approver, peerinfo), fail);
391 SOSCircleRemoveRetired(circle, error); // Prune off retirees since we're signing this one
392 CFSetRemoveAllValues(circle->rejected_applicants); // Dump rejects so we clean them up sometime.
393 publicKey = SecKeyCreatePublicFromPrivate(user_approver);
394 SOSCircleRejectNonValidApplicants(circle, publicKey);
395 SOSCircleGenerationIncrement(circle);
396 require_quiet(SOSCircleEnsureRingConsistency(circle, error), fail);
397 require_quiet(SOSCircleRemoveSignatures(circle, error), fail);
398 require_quiet(SOSCircleSign(circle, user_approver, error), fail);
399 require_quiet(SOSCircleSign(circle, ourKey, error), fail);
400
401 CFReleaseNull(ourKey);
402 CFReleaseNull(publicKey);
403 return true;
404
405 fail:
406 CFReleaseNull(ourKey);
407 CFReleaseNull(publicKey);
408 return false;
409 }
410
411 bool SOSCircleGenerationUpdate(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
412
413 return SOSCircleGenerationSign(circle, user_approver, peerinfo, error);
414
415 #if 0
416 bool success = false;
417
418 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
419 require_quiet(ourKey, fail);
420
421 require_quiet(SOSCircleSign(circle, user_approver, error), fail);
422 require_quiet(SOSCircleSign(circle, ourKey, error), fail);
423
424 success = true;
425
426 fail:
427 CFReleaseNull(ourKey);
428 return success;
429 #endif
430 }
431
432 bool SOSCircleConcordanceSign(SOSCircleRef circle, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
433 bool success = false;
434 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
435 require_quiet(ourKey, exit);
436
437 success = SOSCircleSign(circle, ourKey, error);
438 SOSCircleConcordanceRingSign(circle, ourKey, error);
439
440 exit:
441 CFReleaseNull(ourKey);
442 return success;
443 }
444
445 static inline SOSConcordanceStatus CheckPeerStatus(SOSCircleRef circle, SOSPeerInfoRef peer, SecKeyRef user_public_key, CFErrorRef *error) {
446 SOSConcordanceStatus result = kSOSConcordanceNoPeer;
447 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(peer);
448
449 require_action_quiet(SOSCircleHasActiveValidPeer(circle, peer, user_public_key, error), exit, result = kSOSConcordanceNoPeer);
450 require_action_quiet(SOSCircleVerifySignatureExists(circle, pubKey, error), exit, result = kSOSConcordanceNoPeerSig);
451 require_action_quiet(SOSCircleVerify(circle, pubKey, error), exit, result = kSOSConcordanceBadPeerSig);
452
453 result = kSOSConcordanceTrusted;
454
455 exit:
456 CFReleaseNull(pubKey);
457 return result;
458 }
459
460 static inline SOSConcordanceStatus CombineStatus(SOSConcordanceStatus status1, SOSConcordanceStatus status2)
461 {
462 if (status1 == kSOSConcordanceTrusted || status2 == kSOSConcordanceTrusted)
463 return kSOSConcordanceTrusted;
464
465 if (status1 == kSOSConcordanceBadPeerSig || status2 == kSOSConcordanceBadPeerSig)
466 return kSOSConcordanceBadPeerSig;
467
468 if (status1 == kSOSConcordanceNoPeerSig || status2 == kSOSConcordanceNoPeerSig)
469 return kSOSConcordanceNoPeerSig;
470
471 return status1;
472 }
473
474 static inline bool SOSCircleIsEmpty(SOSCircleRef circle) {
475 return SOSCircleCountPeers(circle) == 0;
476 }
477
478 static inline bool SOSCircleIsOffering(SOSCircleRef circle) {
479 return SOSCircleCountPeers(circle) == 1;
480 }
481
482 static inline bool SOSCircleHasDegenerateGeneration(SOSCircleRef deGenCircle){
483 int testPtr;
484 CFNumberRef genCountTest = SOSCircleGetGeneration(deGenCircle);
485 CFNumberGetValue(genCountTest, kCFNumberCFIndexType, &testPtr);
486 return (testPtr== 0);
487 }
488
489
490 static inline bool SOSCircleIsDegenerateReset(SOSCircleRef deGenCircle){
491 return SOSCircleHasDegenerateGeneration(deGenCircle) && SOSCircleIsEmpty(deGenCircle);
492 }
493
494
495 __unused static inline bool SOSCircleIsResignOffering(SOSCircleRef circle, SecKeyRef pubkey) {
496 return SOSCircleCountActiveValidPeers(circle, pubkey) == 1;
497 }
498
499 static inline SOSConcordanceStatus GetSignersStatus(SOSCircleRef signers_circle, SOSCircleRef status_circle,
500 SecKeyRef user_pubKey, SOSPeerInfoRef exclude, CFErrorRef *error) {
501 CFStringRef excluded_id = exclude ? SOSPeerInfoGetPeerID(exclude) : NULL;
502
503 __block SOSConcordanceStatus status = kSOSConcordanceNoPeer;
504 SOSCircleForEachActivePeer(signers_circle, ^(SOSPeerInfoRef peer) {
505 SOSConcordanceStatus peerStatus = CheckPeerStatus(status_circle, peer, user_pubKey, error);
506
507 if (peerStatus == kSOSConcordanceNoPeerSig &&
508 (CFEqualSafe(SOSPeerInfoGetPeerID(peer), excluded_id) || SOSPeerInfoIsCloudIdentity(peer)))
509 peerStatus = kSOSConcordanceNoPeer;
510
511 status = CombineStatus(status, peerStatus); // TODO: Use multiple error gathering.
512 });
513
514 return status;
515 }
516
517 // Is proposed older than current?
518 static inline bool isOlderGeneration(SOSCircleRef current, SOSCircleRef proposed) {
519 return CFNumberCompare(current->generation, proposed->generation, NULL) == kCFCompareGreaterThan;
520 }
521
522 static inline bool SOSCircleIsValidReset(SOSCircleRef current, SOSCircleRef proposed) {
523 return (!isOlderGeneration(current, proposed)) && SOSCircleIsEmpty(proposed); // is current older or equal to proposed and is proposed empty
524 }
525
526
527 bool SOSCircleSharedTrustedPeers(SOSCircleRef current, SOSCircleRef proposed, SOSPeerInfoRef me) {
528 __block bool retval = false;
529 SOSCircleForEachPeer(current, ^(SOSPeerInfoRef peer) {
530 if(!CFEqual(me, peer) && SOSCircleHasPeer(proposed, peer, NULL)) retval = true;
531 });
532 return retval;
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 GetSignersStatus(proposed_circle, proposed_circle, user_pubkey, NULL, 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 CFNumberRef SOSCircleGetGeneration(SOSCircleRef circle) {
741 assert(circle);
742 assert(circle->generation);
743 return circle->generation;
744 }
745
746 void SOSCircleSetGeneration(SOSCircleRef circle, CFNumberRef gencount) {
747 assert(circle);
748 CFReleaseNull(circle->generation);
749 circle->generation = CFRetainSafe(gencount);
750 }
751
752 int64_t SOSCircleGetGenerationSint(SOSCircleRef circle) {
753 CFNumberRef gen = SOSCircleGetGeneration(circle);
754 int64_t value;
755 if(!gen) return 0;
756 CFNumberGetValue(gen, kCFNumberSInt64Type, &value);
757 return value;
758 }
759
760 void SOSCircleGenerationSetValue(SOSCircleRef circle, int64_t value)
761 {
762 CFAllocatorRef allocator = CFGetAllocator(circle->generation);
763 CFAssignRetained(circle->generation, CFNumberCreate(allocator, kCFNumberSInt64Type, &value));
764 }
765
766
767 static int64_t GenerationSetHighBits(int64_t value, int32_t high_31)
768 {
769 value &= 0xFFFFFFFF; // Keep the low 32 bits.
770 value |= ((int64_t) high_31) << 32;
771
772 return value;
773 }
774
775
776 void SOSCircleGenerationIncrement(SOSCircleRef circle) {
777 int64_t value = SOSCircleGetGenerationSint(circle);
778
779 if ((value >> 32) == 0) {
780 uint32_t seconds = CFAbsoluteTimeGetCurrent(); // seconds
781 value = GenerationSetHighBits(value, (seconds >> 1));
782 }
783
784 value++;
785
786 SOSCircleGenerationSetValue(circle, value);
787 }
788
789 int SOSCircleCountPeers(SOSCircleRef circle) {
790 SOSCircleAssertStable(circle);
791 __block int count = 0;
792 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
793 ++count;
794 });
795 return count;
796 }
797
798 int SOSCircleCountActivePeers(SOSCircleRef circle) {
799 SOSCircleAssertStable(circle);
800 __block int count = 0;
801 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
802 ++count;
803 });
804 return count;
805 }
806
807 int SOSCircleCountActiveValidPeers(SOSCircleRef circle, SecKeyRef pubkey) {
808 SOSCircleAssertStable(circle);
809 __block int count = 0;
810 SOSCircleForEachActiveValidPeer(circle, pubkey, ^(SOSPeerInfoRef peer) {
811 ++count;
812 });
813 return count;
814 }
815
816 int SOSCircleCountRetiredPeers(SOSCircleRef circle) {
817 SOSCircleAssertStable(circle);
818 __block int count = 0;
819 SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) {
820 ++count;
821 });
822 return count;
823 }
824
825 int SOSCircleCountApplicants(SOSCircleRef circle) {
826 SOSCircleAssertStable(circle);
827
828 return (int)CFSetGetCount(circle->applicants);
829 }
830
831 bool SOSCircleHasApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
832 SOSCircleAssertStable(circle);
833
834 return CFSetContainsValue(circle->applicants, peerInfo);
835 }
836
837 CFMutableSetRef SOSCircleCopyApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
838 SOSCircleAssertStable(circle);
839
840 return CFSetCreateMutableCopy(allocator, 0, circle->applicants);
841 }
842
843 int SOSCircleCountRejectedApplicants(SOSCircleRef circle) {
844 SOSCircleAssertStable(circle);
845
846 return (int)CFSetGetCount(circle->rejected_applicants);
847 }
848
849 bool SOSCircleHasRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
850 SOSCircleAssertStable(circle);
851 return CFSetContainsValue(circle->rejected_applicants, peerInfo);
852 }
853
854 SOSPeerInfoRef SOSCircleCopyRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
855 SOSCircleAssertStable(circle);
856 return CFRetainSafe((SOSPeerInfoRef)CFSetGetValue(circle->rejected_applicants, peerInfo));
857 }
858
859 CFMutableArrayRef SOSCircleCopyRejectedApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
860 SOSCircleAssertStable(circle);
861
862 return CFSetCopyValuesCFArray(circle->rejected_applicants);
863 }
864
865 bool SOSCircleHasPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
866 SOSCircleAssertStable(circle);
867 __block bool found = false;
868 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
869 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = true;
870 });
871 return found;
872 }
873
874 SOSPeerInfoRef SOSCircleCopyPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
875 SOSCircleAssertStable(circle);
876 __block SOSPeerInfoRef found = NULL;
877 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
878 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = peer;
879 });
880 return found ? SOSPeerInfoCreateCopy(kCFAllocatorDefault, found, NULL) : NULL;
881 }
882
883 bool SOSCircleHasPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
884 if(!peerInfo) return false;
885 return SOSCircleHasPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
886 }
887
888 bool SOSCircleHasActivePeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
889 SOSCircleAssertStable(circle);
890 __block bool found = false;
891 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
892 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = true;
893 });
894 return found;
895 }
896
897 bool SOSCircleHasActivePeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
898 if(!peerInfo) return false;
899 return SOSCircleHasActivePeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
900 }
901
902 bool SOSCircleHasActiveValidPeerWithID(SOSCircleRef circle, CFStringRef peerid, SecKeyRef user_public_key, CFErrorRef *error) {
903 SOSCircleAssertStable(circle);
904 __block bool found = false;
905 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
906 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer)) && SOSPeerInfoApplicationVerify(peer, user_public_key, NULL)) found = true;
907 });
908 return found;
909 }
910
911 bool SOSCircleHasActiveValidPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, SecKeyRef user_public_key, CFErrorRef *error) {
912 if(!peerInfo) return false;
913 return SOSCircleHasActiveValidPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), user_public_key, error);
914 }
915
916
917 bool SOSCircleResetToEmpty(SOSCircleRef circle, CFErrorRef *error) {
918 CFSetRemoveAllValues(circle->applicants);
919 CFSetRemoveAllValues(circle->rejected_applicants);
920 CFSetRemoveAllValues(circle->peers);
921 CFDictionaryRemoveAllValues(circle->signatures);
922
923 int64_t old_value = SOSCircleGetGenerationSint(circle);
924
925 SOSCircleGenerationSetValue(circle, 0);
926 SOSCircleGenerationIncrement(circle); // Increment to get high bits set.
927
928 int64_t new_value = SOSCircleGetGenerationSint(circle);
929
930 if (new_value <= old_value) {
931 int64_t new_new_value = GenerationSetHighBits(new_value, (old_value >> 32) + 1);
932 SOSCircleGenerationSetValue(circle, new_new_value);
933 }
934
935 return true;
936 }
937
938 bool SOSCircleResetToOffering(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error){
939
940 return SOSCircleResetToEmpty(circle, error)
941 && SOSCircleRequestAdmission(circle, user_privkey, requestor, error)
942 && SOSCircleAcceptRequest(circle, user_privkey, requestor, SOSFullPeerInfoGetPeerInfo(requestor), error);
943 }
944
945 bool SOSCircleRemoveRetired(SOSCircleRef circle, CFErrorRef *error) {
946 CFSetRemoveAllPassing(circle->peers, ^ bool (const void *element) {
947 SOSPeerInfoRef peer = (SOSPeerInfoRef) element;
948
949 return SOSPeerInfoIsRetirementTicket(peer);
950 });
951
952 return true;
953 }
954
955 static bool SOSCircleRecordAdmissionRequest(SOSCircleRef circle, SecKeyRef user_pubkey, SOSPeerInfoRef requestorPeerInfo, CFErrorRef *error) {
956 SOSCircleAssertStable(circle);
957
958 bool isPeer = SOSCircleHasPeer(circle, requestorPeerInfo, error);
959
960 require_action_quiet(!isPeer, fail, SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Cannot request admission when already a peer"), NULL, error));
961
962 CFSetTransferObject(requestorPeerInfo, circle->rejected_applicants, circle->applicants);
963
964 return true;
965
966 fail:
967 return false;
968
969 }
970
971 bool SOSCircleRequestReadmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSPeerInfoRef peer, CFErrorRef *error) {
972 bool success = false;
973
974 require_quiet(SOSPeerInfoApplicationVerify(peer, user_pubkey, error), fail);
975 success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, peer, error);
976 fail:
977 return success;
978 }
979
980 bool SOSCircleRequestAdmission(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
981 bool success = false;
982
983 SecKeyRef user_pubkey = SecKeyCreatePublicFromPrivate(user_privkey);
984 require_action_quiet(user_pubkey, fail, SOSCreateError(kSOSErrorBadKey, CFSTR("No public key for key"), NULL, error));
985
986 require(SOSFullPeerInfoPromoteToApplication(requestor, user_privkey, error), fail);
987
988 success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, SOSFullPeerInfoGetPeerInfo(requestor), error);
989 fail:
990 CFReleaseNull(user_pubkey);
991 return success;
992 }
993
994 static bool sosCircleUpdatePeerInfoSet(CFMutableSetRef theSet, SOSPeerInfoRef replacement_peer_info) {
995 CFTypeRef old = NULL;
996 if(!replacement_peer_info) return false;
997 if(!(old = CFSetGetValue(theSet, replacement_peer_info))) return false;
998 if(CFEqualSafe(old, replacement_peer_info)) return false;
999 CFSetReplaceValue(theSet, replacement_peer_info);
1000 return true;
1001 }
1002
1003 bool SOSCircleUpdatePeerInfo(SOSCircleRef circle, SOSPeerInfoRef replacement_peer_info) {
1004 if(sosCircleUpdatePeerInfoSet(circle->peers, replacement_peer_info)) return true;
1005 if(sosCircleUpdatePeerInfoSet(circle->applicants, replacement_peer_info)) return true;
1006 if(sosCircleUpdatePeerInfoSet(circle->rejected_applicants, replacement_peer_info)) return true;
1007 return false;
1008 }
1009
1010 bool SOSCircleRemovePeer(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, SOSPeerInfoRef peer_to_remove, CFErrorRef *error) {
1011 SOSPeerInfoRef requestor_peer_info = SOSFullPeerInfoGetPeerInfo(requestor);
1012
1013 if (SOSCircleHasApplicant(circle, peer_to_remove, error)) {
1014 return SOSCircleRejectRequest(circle, requestor, peer_to_remove, error);
1015 }
1016
1017 if (!SOSCircleHasPeer(circle, requestor_peer_info, error)) {
1018 SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Must be peer to remove peer"), NULL, error);
1019 return false;
1020 }
1021
1022 CFSetRemoveValue(circle->peers, peer_to_remove);
1023
1024 SOSCircleGenerationSign(circle, user_privkey, requestor, error);
1025
1026 return true;
1027 }
1028
1029 bool SOSCircleAcceptRequest(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1030 SOSCircleAssertStable(circle);
1031
1032 SecKeyRef publicKey = NULL;
1033 bool result = false;
1034
1035 require_action_quiet(CFSetContainsValue(circle->applicants, peerInfo), fail,
1036 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot accept non-applicant"), NULL, error));
1037
1038 publicKey = SecKeyCreatePublicFromPrivate(user_privkey);
1039 require_quiet(SOSPeerInfoApplicationVerify(peerInfo, publicKey, error), fail);
1040
1041 CFSetTransferObject(peerInfo, circle->applicants, circle->peers);
1042
1043 result = SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
1044
1045 fail:
1046 CFReleaseNull(publicKey);
1047 return result;
1048 }
1049
1050 bool SOSCircleWithdrawRequest(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1051 SOSCircleAssertStable(circle);
1052
1053 CFSetRemoveValue(circle->applicants, peerInfo);
1054
1055 return true;
1056 }
1057
1058 bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1059 SOSCircleAssertStable(circle);
1060
1061 CFSetRemoveValue(circle->rejected_applicants, peerInfo);
1062
1063 return true;
1064 }
1065
1066
1067 bool SOSCircleRejectRequest(SOSCircleRef circle, SOSFullPeerInfoRef device_rejector,
1068 SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1069 SOSCircleAssertStable(circle);
1070
1071 if (CFEqual(SOSPeerInfoGetPeerID(peerInfo), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector))))
1072 return SOSCircleWithdrawRequest(circle, peerInfo, error);
1073
1074 if (!CFSetContainsValue(circle->applicants, peerInfo)) {
1075 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot reject non-applicant"), NULL, error);
1076 return false;
1077 }
1078
1079 CFSetTransferObject(peerInfo, circle->applicants, circle->rejected_applicants);
1080
1081 // TODO: Maybe we sign the rejection with device_rejector.
1082
1083 return true;
1084 }
1085
1086 bool SOSCircleAcceptRequests(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver,
1087 CFErrorRef *error) {
1088 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1089 __block bool result = false;
1090
1091 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
1092 if (!SOSCircleAcceptRequest(circle, user_privkey, device_approver, peer, error)) {
1093 secnotice("circle", "error in SOSCircleAcceptRequest\n");
1094 } else {
1095 secnotice("circle", "Accepted peer: %@", peer);
1096 result = true;
1097 }
1098 });
1099
1100 if (result) {
1101 SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
1102 secnotice("circle", "Countersigned accepted requests");
1103 }
1104
1105 return result;
1106 }
1107
1108 bool SOSCirclePeerSigUpdate(SOSCircleRef circle, SecKeyRef userPrivKey, SOSFullPeerInfoRef fpi,
1109 CFErrorRef *error) {
1110 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1111 __block bool result = false;
1112 SecKeyRef userPubKey = SecKeyCreatePublicFromPrivate(userPrivKey);
1113
1114 // We're going to remove any applicants using a mismatched user key.
1115 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
1116 if(!SOSPeerInfoApplicationVerify(peer, userPubKey, NULL)) {
1117 if(!SOSCircleRejectRequest(circle, fpi, peer, NULL)) {
1118 // do we care?
1119 }
1120 }
1121 });
1122
1123 result = SOSCircleUpdatePeerInfo(circle, SOSFullPeerInfoGetPeerInfo(fpi));
1124
1125 if (result) {
1126 SOSCircleGenerationSign(circle, userPrivKey, fpi, error);
1127 secnotice("circle", "Generation signed updated signatures on peerinfo");
1128 }
1129
1130 return result;
1131 }
1132
1133 static inline void SOSCircleForEachPeerMatching(SOSCircleRef circle,
1134 void (^action)(SOSPeerInfoRef peer),
1135 bool (^condition)(SOSPeerInfoRef peer)) {
1136 CFSetForEach(circle->peers, ^(const void *value) {
1137 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
1138 if (condition(peer))
1139 action(peer);
1140 });
1141 }
1142
1143 static inline bool isHiddenPeer(SOSPeerInfoRef peer) {
1144 return SOSPeerInfoIsRetirementTicket(peer) || SOSPeerInfoIsCloudIdentity(peer);
1145 }
1146
1147 void SOSCircleForEachPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1148 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1149 return !isHiddenPeer(peer);
1150 });
1151 }
1152
1153 void SOSCircleForEachRetiredPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1154 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1155 return SOSPeerInfoIsRetirementTicket(peer);
1156 });
1157 }
1158
1159 void SOSCircleForEachActivePeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1160 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1161 return true;
1162 });
1163 }
1164
1165 void SOSCircleForEachActiveValidPeer(SOSCircleRef circle, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)) {
1166 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1167 return SOSPeerInfoApplicationVerify(peer, user_public_key, NULL);
1168 });
1169 }
1170
1171 void SOSCircleForEachValidPeer(SOSCircleRef circle, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)) {
1172 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1173 return !isHiddenPeer(peer) && SOSPeerInfoApplicationVerify(peer, user_public_key, NULL);
1174 });
1175 }
1176
1177 void SOSCircleForEachApplicant(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1178 CFSetForEach(circle->applicants, ^(const void*value) { action((SOSPeerInfoRef) value); } );
1179 }
1180
1181
1182 CFMutableSetRef SOSCircleCopyPeers(SOSCircleRef circle, CFAllocatorRef allocator) {
1183 SOSCircleAssertStable(circle);
1184
1185 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
1186
1187 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
1188 CFSetAddValue(result, peer);
1189 });
1190
1191 return result;
1192 }
1193
1194 bool SOSCircleAppendConcurringPeers(SOSCircleRef circle, CFMutableArrayRef appendHere, CFErrorRef *error) {
1195 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1196 CFErrorRef localError = NULL;
1197 if (SOSCircleVerifyPeerSigned(circle, peer, &localError)) {
1198 SOSPeerInfoRef peerInfo = SOSPeerInfoCreateCopy(kCFAllocatorDefault, peer, error);
1199 CFArrayAppendValue(appendHere, peerInfo);
1200 CFRelease(peerInfo);
1201 } else if (error != NULL) {
1202 secerror("Error checking concurrence: %@", localError);
1203 }
1204 CFReleaseNull(localError);
1205 });
1206
1207 return true;
1208 }
1209
1210 CFMutableArrayRef SOSCircleCopyConcurringPeers(SOSCircleRef circle, CFErrorRef* error) {
1211 SOSCircleAssertStable(circle);
1212
1213 CFMutableArrayRef concurringPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
1214
1215 if (!SOSCircleAppendConcurringPeers(circle, concurringPeers, error))
1216 CFReleaseNull(concurringPeers);
1217
1218 return concurringPeers;
1219 }
1220
1221 SOSFullPeerInfoRef SOSCircleCopyiCloudFullPeerInfoRef(SOSCircleRef circle, CFErrorRef *error) {
1222 __block SOSFullPeerInfoRef cloud_full_peer = NULL;
1223 __block CFErrorRef searchError = NULL;
1224 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1225 if (SOSPeerInfoIsCloudIdentity(peer)) {
1226 if (cloud_full_peer == NULL) {
1227 if (searchError) {
1228 secerror("More than one cloud identity found, first had error, trying new one.");
1229 }
1230 CFReleaseNull(searchError);
1231 cloud_full_peer = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, &searchError);
1232 if (!cloud_full_peer) {
1233 secnotice("icloud-identity", "Failed to make FullPeer for iCloud Identity: %@ (%@)", cloud_full_peer, searchError);
1234 }
1235 } else {
1236 secerror("Additional cloud identity found in circle after successful creation: %@", circle);
1237 }
1238 }
1239 });
1240 // If we didn't find one at all, report the error.
1241 if (cloud_full_peer == NULL && searchError == NULL) {
1242 SOSErrorCreate(kSOSErrorNoiCloudPeer, &searchError, NULL, CFSTR("No iCloud identity PeerInfo found in circle"));
1243 secnotice("icloud-identity", "No iCloud identity PeerInfo found in circle");
1244 }
1245 if (error) {
1246 CFTransferRetained(*error, searchError);
1247 }
1248 CFReleaseNull(searchError);
1249 return cloud_full_peer;
1250 }
1251
1252 void debugDumpCircle(CFStringRef message, SOSCircleRef circle) {
1253 CFErrorRef error;
1254
1255 secinfo("circledebug", "%@: %@", message, circle);
1256 if (!circle)
1257 return;
1258
1259 CFDataRef derdata = SOSCircleCopyEncodedData(circle, kCFAllocatorDefault, &error);
1260 if (derdata) {
1261 CFStringRef hex = CFDataCopyHexString(derdata);
1262 secinfo("circledebug", "Full contents: %@", hex);
1263 if (hex) CFRelease(hex);
1264 CFRelease(derdata);
1265 }
1266 }