]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSCircle.c
Security-59306.120.7.tar.gz
[apple/security.git] / keychain / 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 "keychain/SecureObjectSync/SOSTypes.h"
33 #include "keychain/SecureObjectSync/SOSPeerInfo.h"
34 #include "keychain/SecureObjectSync/SOSPeer.h"
35 #include "keychain/SecureObjectSync/SOSCircle.h"
36 #include "keychain/SecureObjectSync/SOSCloudCircle.h"
37 #include "keychain/SecureObjectSync/SOSCloudCircleInternal.h"
38 #include "keychain/SecureObjectSync/SOSInternal.h"
39 #include "keychain/SecureObjectSync/SOSEnginePriv.h"
40 #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
41 #include "keychain/SecureObjectSync/SOSGenCount.h"
42 #include "keychain/SecureObjectSync/SOSPeerInfoCollections.h"
43 #include <CoreFoundation/CoreFoundation.h>
44 #include <Security/SecFramework.h>
45
46 #include <Security/SecKey.h>
47 #include <Security/SecKeyPriv.h>
48 #include <utilities/SecBuffer.h>
49
50 #include <utilities/SecCFWrappers.h>
51 #include <utilities/SecCFError.h>
52
53 #include "keychain/SecureObjectSync/SOSCirclePriv.h"
54
55 //#include "ckdUtilities.h"
56
57 #include <corecrypto/ccder.h>
58 #include <corecrypto/ccdigest.h>
59 #include <corecrypto/ccsha2.h>
60
61 #include <stdlib.h>
62 #include <assert.h>
63
64 CFGiblisWithCompareFor(SOSCircle);
65
66 SOSCircleRef SOSCircleCreate(CFAllocatorRef allocator, CFStringRef name, CFErrorRef *error) {
67 SOSCircleRef c = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
68 assert(name);
69
70 c->name = CFStringCreateCopy(allocator, name);
71 c->generation = SOSGenerationCreate();
72 c->peers = CFSetCreateMutableForSOSPeerInfosByID(allocator);
73 c->applicants = CFSetCreateMutableForSOSPeerInfosByID(allocator);
74 c->rejected_applicants = CFSetCreateMutableForSOSPeerInfosByID(allocator);
75 c->signatures = CFDictionaryCreateMutableForCFTypes(allocator);
76 return c;
77 }
78
79 static CFMutableSetRef CFSetOfPeerInfoDeepCopy(CFAllocatorRef allocator, CFSetRef peerInfoSet)
80 {
81 __block CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
82 CFSetForEach(peerInfoSet, ^(const void *value) {
83 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
84 CFErrorRef localError = NULL;
85 SOSPeerInfoRef copiedPeer = SOSPeerInfoCreateCopy(allocator, pi, &localError);
86 if (copiedPeer) {
87 CFSetAddValue(result, copiedPeer);
88 } else {
89 secerror("Failed to copy peer: %@ (%@)", pi, localError);
90 }
91 CFReleaseSafe(copiedPeer);
92 CFReleaseSafe(localError);
93 });
94 return result;
95 }
96
97 SOSCircleRef SOSCircleCopyCircle(CFAllocatorRef allocator, SOSCircleRef otherCircle, CFErrorRef *error)
98 {
99 SOSCircleRef c = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
100
101 assert(otherCircle);
102 c->name = CFStringCreateCopy(allocator, otherCircle->name);
103 c->generation = SOSGenerationCopy(otherCircle->generation);
104
105 c->peers = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->peers);
106 c->applicants = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->applicants);
107 c->rejected_applicants = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->rejected_applicants);
108
109 c->signatures = CFDictionaryCreateMutableCopy(allocator, 0, otherCircle->signatures);
110
111 return c;
112 }
113
114 static Boolean SOSCircleCompare(CFTypeRef lhs, CFTypeRef rhs) {
115 if (CFGetTypeID(lhs) != SOSCircleGetTypeID()
116 || CFGetTypeID(rhs) != SOSCircleGetTypeID())
117 return false;
118
119 SOSCircleRef left = SOSCircleConvertAndAssertStable(lhs);
120 SOSCircleRef right = SOSCircleConvertAndAssertStable(rhs);
121
122 // TODO: we should be doing set equality for peers and applicants.
123 return NULL != left && NULL != right
124 && CFEqualSafe(left->generation, right->generation)
125 && SOSPeerInfoSetContainsIdenticalPeers(left->peers, right->peers)
126 && SOSPeerInfoSetContainsIdenticalPeers(left->applicants, right->applicants)
127 && SOSPeerInfoSetContainsIdenticalPeers(left->rejected_applicants, right->rejected_applicants)
128 && CFEqualSafe(left->signatures, right->signatures);
129 }
130
131 static CFMutableArrayRef CFSetCopyValuesCFArray(CFSetRef set)
132 {
133 CFIndex count = CFSetGetCount(set);
134
135 CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
136 if (count > 0) {
137 const void * values[count];
138 CFSetGetValues(set, values);
139 for (int current = 0; current < count; ++current) {
140 CFArrayAppendValue(result, values[current]);
141 }
142 }
143
144 return result;
145 }
146
147 static bool SOSCircleDigestArray(const struct ccdigest_info *di, CFMutableArrayRef array, void *hash_result, CFErrorRef *error)
148 {
149 __block bool success = true;
150 ccdigest_di_decl(di, array_digest);
151 void * a_digest = (void * )array_digest;
152
153 ccdigest_init(di, array_digest);
154 CFArraySortValues(array, CFRangeMake(0, CFArrayGetCount(array)), SOSPeerInfoCompareByID, (void *)SOSPeerCmpPubKeyHash);
155 CFArrayForEach(array, ^(const void *peer) {
156 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes((SOSPeerInfoRef)peer, di, a_digest, error))
157 success = false;
158 });
159 ccdigest_final(di, array_digest, hash_result);
160
161 return success;
162 }
163
164 static bool SOSCircleDigestSet(const struct ccdigest_info *di, CFMutableSetRef set, void *hash_result, CFErrorRef *error)
165 {
166 CFMutableArrayRef values = CFSetCopyValuesCFArray(set);
167
168 bool result = SOSCircleDigestArray(di, values, hash_result, error);
169
170 CFReleaseSafe(values);
171
172 return result;
173 }
174
175 static bool SOSCircleHashGenAndPeers(const struct ccdigest_info *di, SOSGenCountRef gen, CFMutableSetRef peers, void*hash_result, CFErrorRef *error) {
176 ccdigest_di_decl(di, circle_digest);
177 ccdigest_init(di, circle_digest);
178 int64_t generation = SOSGetGenerationSint(gen);
179 ccdigest_update(di, circle_digest, sizeof(generation), &generation);
180
181 SOSCircleDigestSet(di, peers, hash_result, error);
182 ccdigest_update(di, circle_digest, di->output_size, hash_result);
183 ccdigest_final(di, circle_digest, hash_result);
184 return true;
185 }
186
187 static bool SOSCircleHash(const struct ccdigest_info *di, SOSCircleRef circle, void *hash_result, CFErrorRef *error) {
188 return SOSCircleHashGenAndPeers(di, SOSCircleGetGeneration(circle), circle->peers, hash_result, error);
189 }
190
191 static bool SOSCircleHashNextGenWithAdditionalPeer(const struct ccdigest_info *di, SOSCircleRef circle, SOSPeerInfoRef additionalPeer, void *hash_result, CFErrorRef *error) {
192 bool result = false;
193 CFMutableSetRef peers = CFSetCreateMutableCopy(NULL, 0, circle->peers);
194 CFSetAddValue(peers, additionalPeer);
195
196 SOSGenCountRef nextGen = SOSGenerationIncrementAndCreate(circle->generation);
197
198 result = SOSCircleHashGenAndPeers(di, nextGen, peers, hash_result, error);
199
200 CFReleaseNull(nextGen);
201 CFReleaseNull(peers);
202
203 return result;
204 }
205
206 bool SOSCircleSetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFDataRef signature, CFErrorRef *error) {
207 bool result = false;
208
209 CFStringRef pubKeyID = SOSCopyIDOfKey(pubkey, error);
210 require_quiet(pubKeyID, fail);
211 CFDictionarySetValue(circle->signatures, pubKeyID, signature);
212 result = true;
213
214 fail:
215 CFReleaseSafe(pubKeyID);
216 return result;
217 }
218
219 static bool SOSCircleRemoveSignatures(SOSCircleRef circle, CFErrorRef *error) {
220 CFDictionaryRemoveAllValues(circle->signatures);
221 return true;
222 }
223
224 CFDataRef SOSCircleGetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFErrorRef *error) {
225 CFStringRef pubKeyID = SOSCopyIDOfKey(pubkey, error);
226 CFDataRef result = NULL;
227 require_quiet(pubKeyID, fail);
228
229 CFTypeRef value = (CFDataRef)CFDictionaryGetValue(circle->signatures, pubKeyID);
230
231 if (isData(value)) result = (CFDataRef) value;
232
233 fail:
234 CFReleaseSafe(pubKeyID);
235 return result;
236 }
237
238 CFDictionaryRef SOSCircleCopyAllSignatures(SOSCircleRef circle) {
239 return CFDictionaryCreateCopy(kCFAllocatorDefault, circle->signatures);
240 }
241
242 #define circle_signature_di() ccsha256_di()
243
244 static CFDataRef SecKeyCopyRawHashSignature(const struct ccdigest_info *di, const uint8_t* hashToSign, SecKeyRef privKey, CFErrorRef *error) {
245 CFDataRef result = NULL;
246
247 CFMutableDataRef signature = CFDataCreateMutableWithScratch(kCFAllocatorDefault, SecKeyGetSize(privKey, kSecKeySignatureSize));
248 size_t signatureSpace = CFDataGetLength(signature);
249
250 OSStatus status = SecKeyRawSign(privKey, kSecPaddingNone, hashToSign, di->output_size, CFDataGetMutableBytePtr(signature), &signatureSpace);
251 require_quiet(SecError(status, error, CFSTR("Signing failed: %d"), (int)status), fail);
252
253 if (signatureSpace < (size_t)CFDataGetLength(signature)) {
254 CFDataSetLength(signature, signatureSpace);
255 }
256
257 CFTransferRetained(result, signature);
258 fail:
259 CFReleaseNull(signature);
260 return result;
261 }
262
263 bool SOSCircleSign(SOSCircleRef circle, SecKeyRef privKey, CFErrorRef *error) {
264 const struct ccdigest_info *di = circle_signature_di();
265
266 __block CFDataRef signature = NULL;
267 bool didSign = false;
268 require_quiet(privKey, fail);
269
270 PerformWithBuffer(di->output_size, ^(size_t size, uint8_t *hash_result) {
271 if (SOSCircleHash(di, circle, hash_result, error)) {
272 signature = SecKeyCopyRawHashSignature(di, hash_result, privKey, error);
273 }
274 });
275 require_quiet(signature, fail);
276 require_quiet(SOSCircleSetSignature(circle, privKey, signature, error), fail);
277
278 didSign = true;
279
280 fail:
281 CFReleaseNull(signature);
282 return didSign;
283 }
284
285 CFDataRef SOSCircleCopyNextGenSignatureWithPeerAdded(SOSCircleRef circle, SOSPeerInfoRef peer, SecKeyRef privKey, CFErrorRef *error) {
286 const struct ccdigest_info *di = circle_signature_di();
287
288 __block CFDataRef signature = NULL;
289 require_quiet(privKey, fail);
290
291 PerformWithBuffer(di->output_size, ^(size_t size, uint8_t *hash_result) {
292 if (SOSCircleHashNextGenWithAdditionalPeer(di, circle, peer, hash_result, error)) {
293 signature = SecKeyCopyRawHashSignature(di, hash_result, privKey, error);
294 }
295 });
296
297 fail:
298 return signature;
299 }
300
301
302 static bool SOSCircleConcordanceRingSign(SOSCircleRef circle, SecKeyRef privKey, CFErrorRef *error) {
303 secnotice("Development", "SOSCircleEnsureRingConsistency requires ring signing op", NULL);
304 return true;
305 }
306
307
308 bool SOSCircleVerifySignatureExists(SOSCircleRef circle, SecKeyRef pubKey, CFErrorRef *error) {
309 if(!pubKey) {
310 secerror("SOSCircleVerifySignatureExists no pubKey");
311 SOSCreateError(kSOSErrorBadFormat, CFSTR("SOSCircleVerifySignatureExists no pubKey"), (error != NULL) ? *error : NULL, error);
312 return false;
313 }
314 CFDataRef signature = SOSCircleGetSignature(circle, pubKey, error);
315 return NULL != signature;
316 }
317
318 CFStringRef SOSCircleCopyHashString(SOSCircleRef circle) {
319 const struct ccdigest_info *di = ccsha256_di();
320 uint8_t hash_result[di->output_size];
321 SOSCircleHash(di, circle, hash_result, NULL);
322 return SOSCopyHashBufAsString(hash_result, sizeof(hash_result));
323 }
324
325 bool SOSCircleVerify(SOSCircleRef circle, SecKeyRef pubKey, CFErrorRef *error) {
326 const struct ccdigest_info *di = ccsha256_di();
327 uint8_t hash_result[di->output_size];
328
329 SOSCircleHash(di, circle, hash_result, error);
330
331 CFDataRef signature = SOSCircleGetSignature(circle, pubKey, error);
332 if(!signature) return false;
333
334 return SecError(SecKeyRawVerify(pubKey, kSecPaddingNone, hash_result, di->output_size,
335 CFDataGetBytePtr(signature), CFDataGetLength(signature)), error, CFSTR("Signature verification failed."));;
336 }
337
338 bool SOSCircleVerifyPeerSignatureExists(SOSCircleRef circle, SOSPeerInfoRef peer) {
339 bool result = false;
340 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer, NULL);
341 require_quiet(pub_key, fail);
342 result = SOSCircleVerifySignatureExists(circle, pub_key, NULL);
343 fail:
344 CFReleaseSafe(pub_key);
345 return result;
346 }
347
348 bool SOSCircleVerifyPeerSigned(SOSCircleRef circle, SOSPeerInfoRef peer, CFErrorRef *error) {
349 bool result = false;
350 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer, error);
351 require_quiet(pub_key, fail);
352
353 result = SOSCircleVerify(circle, pub_key, error);
354 fail:
355 CFReleaseSafe(pub_key);
356 return result;
357 }
358
359 static void CFSetRemoveAllPassing(CFMutableSetRef set, bool (^test)(const void *) ){
360 CFMutableArrayRef toBeRemoved = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
361
362 CFSetForEach(set, ^(const void *value) {
363 if (test(value))
364 CFArrayAppendValue(toBeRemoved, value);
365 });
366
367 CFArrayForEach(toBeRemoved, ^(const void *value) {
368 CFSetRemoveValue(set, value);
369 });
370 CFReleaseNull(toBeRemoved);
371 }
372
373 static void SOSCircleRejectNonValidApplicants(SOSCircleRef circle, SecKeyRef pubkey) {
374 CFMutableSetRef applicants = SOSCircleCopyApplicants(circle, NULL);
375 CFSetForEach(applicants, ^(const void *value) {
376 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
377 if(!SOSPeerInfoApplicationVerify(pi, pubkey, NULL)) {
378 CFSetTransferObject(pi, circle->applicants, circle->rejected_applicants);
379 }
380 });
381 CFReleaseNull(applicants);
382 }
383
384 static SOSPeerInfoRef SOSCircleCopyPeerInfo(SOSCircleRef circle, CFStringRef peer_id, CFErrorRef *error) {
385 __block SOSPeerInfoRef result = NULL;
386
387 CFSetForEach(circle->peers, ^(const void *value) {
388 if (result == NULL) {
389 SOSPeerInfoRef tpi = (SOSPeerInfoRef)value;
390 if (CFEqual(SOSPeerInfoGetPeerID(tpi), peer_id))
391 result = tpi;
392 }
393 });
394
395 CFRetainSafe(result);
396 return result;
397 }
398
399 static bool SOSCircleUpgradePeerInfo(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo) {
400 bool retval = false;
401 SecKeyRef userPubKey = SecKeyCreatePublicFromPrivate(user_approver);
402 SOSPeerInfoRef fpi_pi = SOSFullPeerInfoGetPeerInfo(peerinfo);
403 SOSPeerInfoRef pi = SOSCircleCopyPeerInfo(circle, SOSPeerInfoGetPeerID(fpi_pi), NULL);
404 require_quiet(pi, out);
405 require_quiet(SOSPeerInfoApplicationVerify(pi, userPubKey, NULL), re_sign);
406 CFReleaseNull(userPubKey);
407 CFReleaseNull(pi);
408 return true;
409
410 re_sign:
411 secnotice("circle", "SOSCircleGenerationSign: Upgraded peer's Application Signature");
412 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peerinfo, NULL);
413 require_quiet(device_key, out);
414 SOSPeerInfoRef new_pi = SOSPeerInfoCopyAsApplication(pi, user_approver, device_key, NULL);
415 if(SOSCircleUpdatePeerInfo(circle, new_pi))
416 retval = true;
417 CFReleaseNull(new_pi);
418 CFReleaseNull(device_key);
419 out:
420 CFReleaseNull(userPubKey);
421 CFReleaseNull(pi);
422 return retval;
423 }
424
425 static bool SOSCircleEnsureRingConsistency(SOSCircleRef circle, CFErrorRef *error) {
426 secnotice("Development", "SOSCircleEnsureRingConsistency requires ring membership and generation count consistency check", NULL);
427 return true;
428 }
429
430 bool SOSCircleSignOldStyleResetToOfferingCircle(SOSCircleRef circle, SOSFullPeerInfoRef peerinfo, SecKeyRef user_approver, CFErrorRef *error){
431
432 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
433 SecKeyRef publicKey = NULL;
434 require_quiet(ourKey, fail);
435
436 // Check if we're using an invalid peerinfo for this op. There are cases where we might not be "upgraded".
437 require_quiet(SOSCircleUpgradePeerInfo(circle, user_approver, peerinfo), fail);
438 SOSCircleRemoveRetired(circle, error); // Prune off retirees since we're signing this one
439 CFSetRemoveAllValues(circle->rejected_applicants); // Dump rejects so we clean them up sometime.
440 publicKey = SecKeyCreatePublicFromPrivate(user_approver);
441 SOSCircleRejectNonValidApplicants(circle, publicKey);
442 require_quiet(SOSCircleEnsureRingConsistency(circle, error), fail);
443 require_quiet(SOSCircleRemoveSignatures(circle, error), fail);
444 require_quiet(SOSCircleSign(circle, user_approver, error), fail);
445 require_quiet(SOSCircleSign(circle, ourKey, error), fail);
446
447 CFReleaseNull(ourKey);
448 CFReleaseNull(publicKey);
449 return true;
450
451 fail:
452 CFReleaseNull(ourKey);
453 CFReleaseNull(publicKey);
454 return false;
455 }
456
457 bool SOSCirclePreGenerationSign(SOSCircleRef circle, SecKeyRef userPubKey, CFErrorRef *error) {
458 bool retval = false;
459
460 SOSCircleRemoveRetired(circle, error); // Prune off retirees since we're signing this one
461 CFSetRemoveAllValues(circle->rejected_applicants); // Dump rejects so we clean them up sometime.
462 SOSCircleRejectNonValidApplicants(circle, userPubKey);
463
464 require_quiet(SOSCircleRemoveSignatures(circle, error), errOut);
465
466 retval = true;
467
468 errOut:
469 return retval;
470
471 }
472
473 static bool SOSCircleGenerationSign_Internal(SOSCircleRef circle, SecKeyRef userKey, SOSFullPeerInfoRef fpi, CFErrorRef *error) {
474 // require_quiet(SOSCircleEnsureRingConsistency(circle, error), fail); Placeholder - this was never implemented
475 bool retval = false;
476 SecKeyRef ourKey = NULL;
477 if (SOSCircleCountPeers(circle) != 0) {
478 ourKey = SOSFullPeerInfoCopyDeviceKey(fpi, error);
479 require_quiet(ourKey, errOut);
480
481 // Check if we're using an invalid peerinfo for this op. There are cases where we might not be "upgraded".
482 require_quiet(SOSCircleUpgradePeerInfo(circle, userKey, fpi), errOut);
483
484 require_quiet(SOSCircleSign(circle, userKey, error), errOut);
485 require_quiet(SOSCircleSign(circle, ourKey, error), errOut);
486 CFReleaseNull(ourKey);
487 }
488 retval = true;
489
490 errOut:
491 CFReleaseNull(ourKey);
492 return retval;
493 }
494
495 bool SOSCircleGenerationSign(SOSCircleRef circle, SecKeyRef userKey, SOSFullPeerInfoRef fpi, CFErrorRef *error) {
496 bool retval = false;
497 SecKeyRef publicKey = NULL;
498 publicKey = SecKeyCreatePublicFromPrivate(userKey);
499
500 require_quiet(SOSCirclePreGenerationSign(circle, publicKey, error), errOut);
501 SOSCircleGenerationIncrement(circle);
502 require_quiet(SOSCircleGenerationSign_Internal(circle, userKey, fpi, error), errOut);
503 retval = true;
504
505 errOut:
506 CFReleaseNull(publicKey);
507 return retval;
508 }
509
510
511 static bool SOSCircleGenerationSignWithGenCount(SOSCircleRef circle, SecKeyRef userKey, SOSFullPeerInfoRef fpi, SOSGenCountRef gencount, CFErrorRef *error) {
512 bool retval = false;
513 SOSGenCountRef currentGen = SOSCircleGetGeneration(circle);
514 require_action_quiet(SOSGenerationIsOlder(currentGen, gencount), errOut, SOSCreateError(kSOSErrorReplay, CFSTR("Generation Count for new circle is too old"), NULL, error));
515 require_quiet(SOSCirclePreGenerationSign(circle, userKey, error), errOut);
516 SOSCircleSetGeneration(circle, gencount);
517 require_quiet(SOSCircleGenerationSign_Internal(circle, userKey, fpi, error), errOut);
518 retval = true;
519
520 errOut:
521 return retval;
522 }
523
524
525 bool SOSCircleConcordanceSign(SOSCircleRef circle, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
526 bool success = false;
527 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
528 require_quiet(ourKey, exit);
529
530 success = SOSCircleSign(circle, ourKey, error);
531 SOSCircleConcordanceRingSign(circle, ourKey, error);
532
533 exit:
534 CFReleaseNull(ourKey);
535 return success;
536 }
537
538 static inline SOSConcordanceStatus CheckPeerStatus(SOSCircleRef circle, SOSPeerInfoRef peer, SecKeyRef user_public_key, CFErrorRef *error) {
539 SOSConcordanceStatus result = kSOSConcordanceNoPeer;
540 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(peer, error);
541 require_quiet(pubKey, exit);
542
543 require_action_quiet(SOSCircleHasActiveValidPeer(circle, peer, user_public_key, error), exit, result = kSOSConcordanceNoPeer);
544 require_action_quiet(SOSCircleVerifySignatureExists(circle, pubKey, error), exit, result = kSOSConcordanceNoPeerSig);
545 require_action_quiet(SOSCircleVerify(circle, pubKey, error), exit, result = kSOSConcordanceBadPeerSig);
546
547 result = kSOSConcordanceTrusted;
548
549 exit:
550 CFReleaseNull(pubKey);
551 return result;
552 }
553
554 static inline SOSConcordanceStatus CombineStatus(SOSConcordanceStatus status1, SOSConcordanceStatus status2)
555 {
556 if (status1 == kSOSConcordanceTrusted || status2 == kSOSConcordanceTrusted)
557 return kSOSConcordanceTrusted;
558
559 if (status1 == kSOSConcordanceBadPeerSig || status2 == kSOSConcordanceBadPeerSig)
560 return kSOSConcordanceBadPeerSig;
561
562 if (status1 == kSOSConcordanceNoPeerSig || status2 == kSOSConcordanceNoPeerSig)
563 return kSOSConcordanceNoPeerSig;
564
565 return status1;
566 }
567
568 static inline bool SOSCircleIsEmpty(SOSCircleRef circle) {
569 return SOSCircleCountPeers(circle) == 0;
570 }
571
572 static inline bool SOSCircleHasDegenerateGeneration(SOSCircleRef deGenCircle){
573 CFIndex testPtr;
574 CFNumberRef genCountTest = SOSCircleGetGeneration(deGenCircle);
575 CFNumberGetValue(genCountTest, kCFNumberCFIndexType, &testPtr);
576 return (testPtr== 0);
577 }
578
579
580 static inline bool SOSCircleIsDegenerateReset(SOSCircleRef deGenCircle){
581 return SOSCircleHasDegenerateGeneration(deGenCircle) && SOSCircleIsEmpty(deGenCircle);
582 }
583
584 static inline SOSConcordanceStatus GetSignersStatus(SOSCircleRef signers_circle, SOSCircleRef status_circle,
585 SecKeyRef user_pubKey, SOSPeerInfoRef exclude, CFErrorRef *error) {
586 CFStringRef excluded_id = exclude ? SOSPeerInfoGetPeerID(exclude) : NULL;
587
588 __block SOSConcordanceStatus status = kSOSConcordanceNoPeer;
589 SOSCircleForEachActivePeer(signers_circle, ^(SOSPeerInfoRef peer) {
590 SOSConcordanceStatus peerStatus = CheckPeerStatus(status_circle, peer, user_pubKey, error);
591
592 if (peerStatus == kSOSConcordanceNoPeerSig &&
593 (CFEqualSafe(SOSPeerInfoGetPeerID(peer), excluded_id) || SOSPeerInfoIsCloudIdentity(peer)))
594 peerStatus = kSOSConcordanceNoPeer;
595
596 status = CombineStatus(status, peerStatus); // TODO: Use multiple error gathering.
597 });
598
599 return status;
600 }
601
602 // Is current older than proposed?
603 bool SOSCircleIsOlderGeneration(SOSCircleRef older, SOSCircleRef newer) {
604 return SOSGenerationIsOlder(older->generation, newer->generation);
605 }
606
607 static inline bool SOSCircleIsValidReset(SOSCircleRef current, SOSCircleRef proposed) {
608 bool retval = false;
609 retval = SOSCircleIsEmpty(proposed);
610 require_quiet(retval, errOut);
611 retval = SOSCircleIsOlderGeneration(current, proposed);
612 errOut:
613 return retval;
614 }
615
616
617 bool SOSCircleSharedTrustedPeers(SOSCircleRef current, SOSCircleRef proposed, SOSPeerInfoRef me) {
618 __block bool retval = false;
619 SOSCircleForEachPeer(current, ^(SOSPeerInfoRef peer) {
620 if(!CFEqual(me, peer) && SOSCircleHasPeer(proposed, peer, NULL)) retval = true;
621 });
622 return retval;
623 }
624
625 static SOSConcordanceStatus GetOfferingStatus(SOSCircleRef circle, SecKeyRef user_pubKey, CFErrorRef *error) {
626 __block SOSConcordanceStatus status = kSOSConcordanceNoPeer;
627 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
628 status = CheckPeerStatus(circle, peer, user_pubKey, error);
629 if(status != kSOSConcordanceTrusted) status = kSOSConcordanceNoPeer;
630 });
631 return status;
632 }
633
634
635 SOSConcordanceStatus SOSCircleConcordanceTrust(SOSCircleRef known_circle, SOSCircleRef proposed_circle,
636 SecKeyRef known_pubkey, SecKeyRef user_pubkey,
637 SOSPeerInfoRef me, CFErrorRef *error) {
638 if(user_pubkey == NULL) {
639 SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Concordance with no user public key"), NULL, error);
640 return kSOSConcordanceNoUserKey;
641 }
642
643 if(SOSCircleIsDegenerateReset(proposed_circle)) {
644 return kSOSConcordanceTrusted;
645 }
646
647 if (SOSCircleIsValidReset(known_circle, proposed_circle)) {
648 return kSOSConcordanceTrusted;
649 }
650
651 if(!SOSCircleVerifySignatureExists(proposed_circle, user_pubkey, error)) {
652 SOSCreateError(kSOSErrorBadSignature, CFSTR("No public signature to match current user key"), (error != NULL) ? *error : NULL, error);
653 return kSOSConcordanceNoUserSig;
654 }
655
656 if(!SOSCircleVerify(proposed_circle, user_pubkey, error)) {
657 SOSCreateError(kSOSErrorBadSignature, CFSTR("Bad user public signature"), (error != NULL) ? *error : NULL, error);
658 debugDumpCircle(CFSTR("proposed_circle"), proposed_circle);
659 return kSOSConcordanceBadUserSig;
660 }
661
662 if (SOSCircleIsEmpty(known_circle)) {
663 return GetSignersStatus(proposed_circle, proposed_circle, user_pubkey, NULL, error);
664 }
665
666 if(SOSCircleHasDegenerateGeneration(proposed_circle) && SOSCircleIsOffering(proposed_circle)){
667 return GetSignersStatus(proposed_circle, proposed_circle, user_pubkey, NULL, error);
668 }
669
670 if(SOSCircleIsOlderGeneration(proposed_circle, known_circle)) {
671 SOSCreateError(kSOSErrorReplay, CFSTR("Bad generation - proposed circle gencount is older than known circle gencount"), NULL, error);
672 debugDumpCircle(CFSTR("isOlderGeneration known_circle"), known_circle);
673 debugDumpCircle(CFSTR("isOlderGeneration proposed_circle"), proposed_circle);
674 return kSOSConcordanceGenOld;
675 }
676
677 if(SOSCircleIsOffering(proposed_circle)){
678 return GetOfferingStatus(proposed_circle, user_pubkey, error);
679 }
680
681 return GetSignersStatus(known_circle, proposed_circle, user_pubkey, me, error);
682 }
683
684
685 static void SOSCircleDestroy(CFTypeRef aObj) {
686 SOSCircleRef c = (SOSCircleRef) aObj;
687
688 CFReleaseNull(c->name);
689 CFReleaseNull(c->generation);
690 CFReleaseNull(c->peers);
691 CFReleaseNull(c->applicants);
692 CFReleaseNull(c->rejected_applicants);
693 CFReleaseNull(c->signatures);
694 }
695
696 static CFMutableStringRef defaultDescriptionCreate(CFTypeRef aObj){
697 SOSCircleRef c = (SOSCircleRef) aObj;
698 CFStringRef initPeerSep = CFSTR("\n");
699 CFStringRef peerSep = CFSTR("\n");
700
701 CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
702
703 SOSGenerationCountWithDescription(c->generation, ^(CFStringRef genDescription) {
704 CFStringAppendFormat(description, NULL, CFSTR("<SOSCircle@%p: '%@' %@ P:["), c, c->name, genDescription);
705 });
706
707 __block CFStringRef separator = initPeerSep;
708 SOSCircleForEachActivePeer(c, ^(SOSPeerInfoRef peer) {
709 CFStringRef sig = NULL;
710 if (SOSCircleVerifyPeerSigned(c, peer, NULL)) {
711 sig = CFSTR("√");
712 } else {
713 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer, NULL);
714 CFDataRef signature = pub_key ? SOSCircleGetSignature(c, pub_key, NULL) : NULL;
715 sig = (signature == NULL) ? CFSTR("-") : CFSTR("?");
716 CFReleaseNull(pub_key);
717 }
718
719 CFStringAppendFormat(description, NULL, CFSTR("%@%@ %@"), separator, peer, sig);
720 separator = peerSep;
721 });
722
723 //applicants
724 CFStringAppend(description, CFSTR("], A:["));
725 separator = initPeerSep;
726 if(CFSetGetCount(c->applicants) == 0 )
727 CFStringAppendFormat(description, NULL, CFSTR("-"));
728 else{
729
730 SOSCircleForEachApplicant(c, ^(SOSPeerInfoRef peer) {
731 CFStringAppendFormat(description, NULL, CFSTR("%@%@"), separator, peer);
732 separator = peerSep;
733 });
734 }
735
736 //rejected
737 CFStringAppend(description, CFSTR("], R:["));
738 separator = initPeerSep;
739 if(CFSetGetCount(c->rejected_applicants) == 0)
740 CFStringAppendFormat(description, NULL, CFSTR("-"));
741 else{
742 CFSetForEach(c->rejected_applicants, ^(const void *value) {
743 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
744 CFStringAppendFormat(description, NULL, CFSTR("%@%@"), separator, peer);
745 separator = peerSep;
746 });
747 }
748 CFStringAppend(description, CFSTR("]>"));
749 return description;
750
751 }
752 static CFMutableStringRef descriptionCreateWithFormatOptions(CFTypeRef aObj, CFDictionaryRef formatOptions){
753 SOSCircleRef c = (SOSCircleRef) aObj;
754
755 CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
756
757 if(CFDictionaryContainsKey(formatOptions, CFSTR("SyncD"))) {
758 CFStringRef generationDescription = SOSGenerationCountCopyDescription(c->generation);
759 CFStringAppendFormat(description, NULL, CFSTR("<C: gen:'%@' %@>\n"), generationDescription, c->name);
760 CFReleaseNull(generationDescription);
761 __block CFStringRef separator = CFSTR("\t\t");
762 SOSCircleForEachActivePeer(c, ^(SOSPeerInfoRef peer) {
763 CFStringRef sig = NULL;
764 if (SOSCircleVerifyPeerSigned(c, peer, NULL)) {
765 sig = CFSTR("√");
766 } else {
767 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer, NULL);
768 CFDataRef signature = pub_key ? SOSCircleGetSignature(c, pub_key, NULL) : NULL;
769 sig = (signature == NULL) ? CFSTR("-") : CFSTR("?");
770 CFReleaseNull(pub_key);
771 }
772
773 CFStringAppendFormat(description, formatOptions, CFSTR("%@%@ %@"), separator, peer, sig);
774 separator = CFSTR("\n\t\t");
775 });
776 CFStringAppend(description, CFSTR("\n\t\t<A:["));
777 separator = CFSTR("");
778
779 //applicants list
780 if(CFSetGetCount(c->applicants) == 0 )
781 CFStringAppendFormat(description, NULL, CFSTR("-"));
782 else{
783
784 SOSCircleForEachApplicant(c, ^(SOSPeerInfoRef peer) {
785 CFStringAppendFormat(description, formatOptions, CFSTR("%@A: %@"), separator, peer);
786 separator = CFSTR("\n\t\t\t");
787 });
788 }
789 //rejected list
790 CFStringAppend(description, CFSTR("]> \n\t\t<R:["));
791 separator = CFSTR("");
792 if(CFSetGetCount(c->rejected_applicants) == 0)
793 CFStringAppendFormat(description, NULL, CFSTR("-"));
794 else{
795 CFSetForEach(c->rejected_applicants, ^(const void *value) {
796 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
797 CFStringAppendFormat(description, formatOptions, CFSTR("%@R: %@"), separator, peer);
798 separator = CFSTR("\n\t\t");
799 });
800 }
801 CFStringAppend(description, CFSTR("]>"));
802 }
803
804 else{
805 CFReleaseNull(description);
806 description = defaultDescriptionCreate(aObj);
807 }
808
809 return description;
810
811 }
812
813
814 static CFStringRef SOSCircleCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
815 SOSCircleRef c = (SOSCircleRef) aObj;
816 SOSCircleAssertStable(c);
817 CFMutableStringRef description = NULL;
818
819 if(formatOptions != NULL){
820 description = descriptionCreateWithFormatOptions(aObj, formatOptions);
821 }
822 else{
823 description = defaultDescriptionCreate(aObj);
824 }
825 return description;
826 }
827
828 CFStringRef SOSCircleGetName(SOSCircleRef circle) {
829 if(!circle || !circle->name) {
830 return NULL;
831 }
832 return circle->name;
833 }
834
835 const char *SOSCircleGetNameC(SOSCircleRef circle) {
836 CFStringRef name = SOSCircleGetName(circle);
837 if (!name)
838 return strdup("");
839 return CFStringToCString(name);
840 }
841
842 SOSGenCountRef SOSCircleGetGeneration(SOSCircleRef circle) {
843 assert(circle);
844 assert(circle->generation);
845 return circle->generation;
846 }
847
848 void SOSCircleSetGeneration(SOSCircleRef circle, SOSGenCountRef gencount) {
849 assert(circle);
850 CFReleaseNull(circle->generation);
851 circle->generation = CFRetainSafe(gencount);
852 }
853
854 int64_t SOSCircleGetGenerationSint(SOSCircleRef circle) {
855 SOSGenCountRef gen = SOSCircleGetGeneration(circle);
856 return SOSGetGenerationSint(gen);
857 }
858
859 void SOSCircleGenerationSetValue(SOSCircleRef circle, int64_t value) {
860 CFAssignRetained(circle->generation, SOSGenerationCreateWithValue(value));
861 }
862
863 void SOSCircleGenerationIncrement(SOSCircleRef circle) {
864 SOSGenCountRef old = circle->generation;
865 circle->generation = SOSGenerationIncrementAndCreate(old);
866 CFReleaseNull(old);
867 }
868
869 int SOSCircleCountPeers(SOSCircleRef circle) {
870 SOSCircleAssertStable(circle);
871 __block int count = 0;
872 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
873 ++count;
874 });
875 return count;
876 }
877
878 int SOSCircleCountActivePeers(SOSCircleRef circle) {
879 SOSCircleAssertStable(circle);
880 __block int count = 0;
881 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
882 ++count;
883 });
884 return count;
885 }
886
887 int SOSCircleCountActiveValidPeers(SOSCircleRef circle, SecKeyRef pubkey) {
888 SOSCircleAssertStable(circle);
889 __block int count = 0;
890 SOSCircleForEachActiveValidPeer(circle, pubkey, ^(SOSPeerInfoRef peer) {
891 ++count;
892 });
893 return count;
894 }
895
896 int SOSCircleCountValidSyncingPeers(SOSCircleRef circle, SecKeyRef pubkey) {
897 SOSCircleAssertStable(circle);
898 __block int count = 0;
899 SOSCircleForEachValidSyncingPeer(circle, pubkey, ^(SOSPeerInfoRef peer) {
900 ++count;
901 });
902 return count;
903
904 }
905
906 int SOSCircleCountRetiredPeers(SOSCircleRef circle) {
907 SOSCircleAssertStable(circle);
908 __block int count = 0;
909 SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) {
910 ++count;
911 });
912 return count;
913 }
914
915 int SOSCircleCountApplicants(SOSCircleRef circle) {
916 SOSCircleAssertStable(circle);
917
918 return (int)CFSetGetCount(circle->applicants);
919 }
920
921 bool SOSCircleHasApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
922 SOSCircleAssertStable(circle);
923
924 return CFSetContainsValue(circle->applicants, peerInfo);
925 }
926
927 CFMutableSetRef SOSCircleCopyApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
928 SOSCircleAssertStable(circle);
929
930 return CFSetCreateMutableCopy(allocator, 0, circle->applicants);
931 }
932
933 int SOSCircleCountRejectedApplicants(SOSCircleRef circle) {
934 SOSCircleAssertStable(circle);
935
936 return (int)CFSetGetCount(circle->rejected_applicants);
937 }
938
939 bool SOSCircleHasRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
940 SOSCircleAssertStable(circle);
941 return CFSetContainsValue(circle->rejected_applicants, peerInfo);
942 }
943
944 SOSPeerInfoRef SOSCircleCopyRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
945 SOSCircleAssertStable(circle);
946 return CFRetainSafe((SOSPeerInfoRef)CFSetGetValue(circle->rejected_applicants, peerInfo));
947 }
948
949 CFMutableArrayRef SOSCircleCopyRejectedApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
950 SOSCircleAssertStable(circle);
951
952 return CFSetCopyValuesCFArray(circle->rejected_applicants);
953 }
954
955 bool SOSCircleResetToEmpty(SOSCircleRef circle, CFErrorRef *error) {
956 CFSetRemoveAllValues(circle->applicants);
957 CFSetRemoveAllValues(circle->rejected_applicants);
958 CFSetRemoveAllValues(circle->peers);
959 CFDictionaryRemoveAllValues(circle->signatures);
960 SOSGenCountRef oldGen = SOSCircleGetGeneration(circle);
961 SOSGenCountRef newGen = SOSGenerationCreateWithBaseline(oldGen);
962 SOSCircleSetGeneration(circle, newGen);
963 CFReleaseSafe(newGen);
964 return true;
965 }
966
967 bool SOSCircleResetToEmptyWithSameGeneration(SOSCircleRef circle, CFErrorRef *error) {
968 SOSGenCountRef gen = SOSGenerationCopy(SOSCircleGetGeneration(circle));
969 SOSCircleResetToEmpty(circle, error);
970 SOSCircleSetGeneration(circle, gen);
971 CFReleaseNull(gen);
972 return true;
973 }
974
975 bool SOSCircleResetToOffering(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error){
976
977 return SOSCircleResetToEmpty(circle, error)
978 && SOSCircleRequestAdmission(circle, user_privkey, requestor, error)
979 && SOSCircleAcceptRequest(circle, user_privkey, requestor, SOSFullPeerInfoGetPeerInfo(requestor), error);
980 }
981
982 bool SOSCircleRemoveRetired(SOSCircleRef circle, CFErrorRef *error) {
983 CFSetRemoveAllPassing(circle->peers, ^ bool (const void *element) {
984 SOSPeerInfoRef peer = (SOSPeerInfoRef) element;
985
986 return SOSPeerInfoIsRetirementTicket(peer);
987 });
988
989 return true;
990 }
991
992 static bool SOSCircleRecordAdmissionRequest(SOSCircleRef circle, SecKeyRef user_pubkey, SOSPeerInfoRef requestorPeerInfo, CFErrorRef *error) {
993 SOSCircleAssertStable(circle);
994
995 bool isPeer = SOSCircleHasPeer(circle, requestorPeerInfo, error);
996
997 require_action_quiet(!isPeer, fail, SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Cannot request admission when already a peer"), NULL, error));
998
999 // This adds to applicants and will take off rejected if it's there.
1000 CFSetTransferObject(requestorPeerInfo, circle->rejected_applicants, circle->applicants);
1001
1002 return true;
1003
1004 fail:
1005 return false;
1006
1007 }
1008
1009 bool SOSCircleRequestReadmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSPeerInfoRef peer, CFErrorRef *error) {
1010 bool success = false;
1011
1012 require_quiet(SOSPeerInfoApplicationVerify(peer, user_pubkey, error), fail);
1013 success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, peer, error);
1014 fail:
1015 return success;
1016 }
1017
1018 bool SOSCircleRequestAdmission(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
1019 bool success = false;
1020
1021 SecKeyRef user_pubkey = SecKeyCreatePublicFromPrivate(user_privkey);
1022 require_action_quiet(user_pubkey, fail, SOSCreateError(kSOSErrorBadKey, CFSTR("No public key for key"), NULL, error));
1023
1024 require(SOSFullPeerInfoPromoteToApplication(requestor, user_privkey, error), fail);
1025
1026 success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, SOSFullPeerInfoGetPeerInfo(requestor), error);
1027 fail:
1028 CFReleaseNull(user_pubkey);
1029 return success;
1030 }
1031
1032 static bool sosCircleUpdatePeerInfoSet(CFMutableSetRef theSet, SOSPeerInfoRef replacement_peer_info) {
1033 CFTypeRef old = NULL;
1034 if(!replacement_peer_info) return false;
1035 if(!(old = CFSetGetValue(theSet, replacement_peer_info))) return false;
1036 if(CFEqualSafe(old, replacement_peer_info)) return false;
1037 CFSetReplaceValue(theSet, replacement_peer_info);
1038 return true;
1039 }
1040
1041 bool SOSCircleUpdatePeerInfo(SOSCircleRef circle, SOSPeerInfoRef replacement_peer_info) {
1042 if(sosCircleUpdatePeerInfoSet(circle->peers, replacement_peer_info)) return true;
1043 if(sosCircleUpdatePeerInfoSet(circle->applicants, replacement_peer_info)) return true;
1044 if(sosCircleUpdatePeerInfoSet(circle->rejected_applicants, replacement_peer_info)) return true;
1045 return false;
1046 }
1047
1048 static bool SOSCircleRemovePeerInternal(SOSCircleRef circle, SOSFullPeerInfoRef requestor, SOSPeerInfoRef peer_to_remove, CFErrorRef *error) {
1049 SOSPeerInfoRef requestor_peer_info = SOSFullPeerInfoGetPeerInfo(requestor);
1050
1051 if (SOSCircleHasPeer(circle, peer_to_remove, NULL)) {
1052 if (!SOSCircleHasPeer(circle, requestor_peer_info, error)) {
1053 SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Must be peer to remove peer"), NULL, error);
1054 return false;
1055 }
1056 CFSetRemoveValue(circle->peers, peer_to_remove);
1057 }
1058
1059 if (SOSCircleHasApplicant(circle, peer_to_remove, error)) {
1060 return SOSCircleRejectRequest(circle, requestor, peer_to_remove, error);
1061 }
1062
1063 return true;
1064 }
1065
1066 bool SOSCircleRemovePeers(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFSetRef peersToRemove, CFErrorRef *error) {
1067
1068 bool success = false;
1069
1070 __block bool removed_all = true;
1071 CFSetForEach(peersToRemove, ^(const void *value) {
1072 SOSPeerInfoRef peerInfo = asSOSPeerInfo(value);
1073 if (peerInfo) {
1074 removed_all &= SOSCircleRemovePeerInternal(circle, requestor, peerInfo, error);
1075 }
1076 });
1077
1078 require_quiet(removed_all, exit);
1079
1080 require_quiet(SOSCircleGenerationSign(circle, user_privkey, requestor, error), exit);
1081
1082 success = true;
1083
1084 exit:
1085 return success;
1086 }
1087
1088
1089 bool SOSCircleRemovePeersByID(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFSetRef peersToRemove, CFErrorRef *error) {
1090
1091 bool success = false;
1092
1093 __block bool removed_all = true;
1094 CFSetForEach(peersToRemove, ^(const void *value) {
1095 CFStringRef peerID = asString(value, NULL);
1096 if(peerID) {
1097 SOSPeerInfoRef peerInfo = SOSCircleCopyPeerInfo(circle, peerID, NULL);
1098 if (peerInfo) {
1099 removed_all &= SOSCircleRemovePeerInternal(circle, requestor, peerInfo, error);
1100 CFReleaseNull(peerInfo);
1101 }
1102 }
1103 });
1104
1105 require_quiet(removed_all, exit);
1106
1107 require_quiet(SOSCircleGenerationSign(circle, user_privkey, requestor, error), exit);
1108
1109 success = true;
1110
1111 exit:
1112 return success;
1113 }
1114
1115 static bool SOSCircleRemovePeerUnsigned(SOSCircleRef circle, SOSPeerInfoRef peer_to_remove) {
1116 bool retval = false;
1117 if (SOSCircleHasPeer(circle, peer_to_remove, NULL)) {
1118 CFSetRemoveValue(circle->peers, peer_to_remove);
1119 retval = true;
1120 }
1121 return retval;
1122 }
1123
1124 bool SOSCircleRemovePeersByIDUnsigned(SOSCircleRef circle, CFSetRef peersToRemove) {
1125 __block bool removed_all = true;
1126 CFSetForEach(peersToRemove, ^(const void *value) {
1127 CFStringRef peerID = asString(value, NULL);
1128 SOSPeerInfoRef peerInfo = SOSCircleCopyPeerInfo(circle, peerID, NULL);
1129 removed_all &= SOSCircleRemovePeerUnsigned(circle, peerInfo);
1130 CFReleaseNull(peerInfo);
1131 });
1132 return removed_all;
1133 }
1134
1135 bool SOSCircleRemovePeer(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, SOSPeerInfoRef peer_to_remove, CFErrorRef *error) {
1136 bool success = false;
1137
1138 require_quiet(SOSCircleRemovePeerInternal(circle, requestor, peer_to_remove, error), exit);
1139
1140 require_quiet(SOSCircleGenerationSign(circle, user_privkey, requestor, error), exit);
1141
1142 success = true;
1143 exit:
1144 return success;
1145 }
1146
1147 bool SOSCircleAcceptRequest(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1148 SOSCircleAssertStable(circle);
1149
1150 SecKeyRef publicKey = NULL;
1151 bool result = false;
1152
1153 require_action_quiet(CFSetContainsValue(circle->applicants, peerInfo), fail,
1154 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot accept non-applicant"), NULL, error));
1155
1156 publicKey = SecKeyCreatePublicFromPrivate(user_privkey);
1157 require_quiet(SOSPeerInfoApplicationVerify(peerInfo, publicKey, error), fail);
1158
1159 CFSetTransferObject(peerInfo, circle->applicants, circle->peers);
1160
1161 result = SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
1162
1163 fail:
1164 CFReleaseNull(publicKey);
1165 return result;
1166 }
1167
1168 bool SOSCircleWithdrawRequest(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1169 SOSCircleAssertStable(circle);
1170
1171 CFSetRemoveValue(circle->applicants, peerInfo);
1172
1173 return true;
1174 }
1175
1176 bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1177 SOSCircleAssertStable(circle);
1178
1179 CFSetRemoveValue(circle->rejected_applicants, peerInfo);
1180
1181 return true;
1182 }
1183
1184
1185 bool SOSCircleRejectRequest(SOSCircleRef circle, SOSFullPeerInfoRef device_rejector,
1186 SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1187 SOSCircleAssertStable(circle);
1188
1189 if (CFEqual(SOSPeerInfoGetPeerID(peerInfo), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector))))
1190 return SOSCircleWithdrawRequest(circle, peerInfo, error);
1191
1192 if (!CFSetContainsValue(circle->applicants, peerInfo)) {
1193 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot reject non-applicant"), NULL, error);
1194 return false;
1195 }
1196
1197 CFSetTransferObject(peerInfo, circle->applicants, circle->rejected_applicants);
1198
1199 // TODO: Maybe we sign the rejection with device_rejector.
1200
1201 return true;
1202 }
1203
1204 bool SOSCircleAcceptRequests(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver,
1205 CFErrorRef *error) {
1206 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1207 __block bool result = false;
1208
1209 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
1210 if (!SOSCircleAcceptRequest(circle, user_privkey, device_approver, peer, error)) {
1211 secnotice("circle", "error in SOSCircleAcceptRequest\n");
1212 } else {
1213 secnotice("circle", "Accepted peer: %@", peer);
1214 result = true;
1215 }
1216 });
1217
1218 if (result) {
1219 SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
1220 secnotice("circle", "Countersigned accepted requests");
1221 }
1222
1223 return result;
1224 }
1225
1226 bool SOSCirclePeerSigUpdate(SOSCircleRef circle, SecKeyRef userPrivKey, SOSFullPeerInfoRef fpi,
1227 CFErrorRef *error) {
1228 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1229 __block bool result = false;
1230 SecKeyRef userPubKey = SecKeyCreatePublicFromPrivate(userPrivKey);
1231
1232 // We're going to remove any applicants using a mismatched user key.
1233 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
1234 if(!SOSPeerInfoApplicationVerify(peer, userPubKey, NULL)) {
1235 if(!SOSCircleRejectRequest(circle, fpi, peer, NULL)) {
1236 // do we care?
1237 }
1238 }
1239 });
1240
1241 result = SOSCircleUpdatePeerInfo(circle, SOSFullPeerInfoGetPeerInfo(fpi));
1242
1243 if (result) {
1244 SOSCircleGenerationSign(circle, userPrivKey, fpi, error);
1245 secnotice("circle", "Generation signed updated signatures on peerinfo");
1246 }
1247
1248 return result;
1249 }
1250
1251 //
1252 // Peer iteration and membership
1253 //
1254
1255 static inline void SOSCircleForEachPeerMatching(SOSCircleRef circle,
1256 void (^action)(SOSPeerInfoRef peer),
1257 bool (^condition)(SOSPeerInfoRef peer)) {
1258 CFSetForEach(circle->peers, ^(const void *value) {
1259 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
1260 if (condition(peer))
1261 action(peer);
1262 });
1263 }
1264
1265 static inline bool isHiddenPeer(SOSPeerInfoRef peer) {
1266 return SOSPeerInfoIsRetirementTicket(peer) || SOSPeerInfoIsCloudIdentity(peer);
1267 }
1268
1269 void SOSCircleForEachPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1270 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1271 return !isHiddenPeer(peer);
1272 });
1273 }
1274
1275 void SOSCircleForEachRetiredPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1276 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1277 return SOSPeerInfoIsRetirementTicket(peer);
1278 });
1279 }
1280
1281 void SOSCircleForEachiCloudIdentityPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1282 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1283 return SOSPeerInfoIsCloudIdentity(peer);
1284 });
1285 }
1286
1287
1288 void SOSCircleForEachActivePeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1289 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1290 return true;
1291 });
1292 }
1293
1294 void SOSCircleForEachActiveValidPeer(SOSCircleRef circle, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)) {
1295 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1296 return SOSPeerInfoApplicationVerify(peer, user_public_key, NULL);
1297 });
1298 }
1299
1300 void SOSCircleForEachValidPeer(SOSCircleRef circle, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)) {
1301 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1302 return !isHiddenPeer(peer) && SOSPeerInfoApplicationVerify(peer, user_public_key, NULL);
1303 });
1304 }
1305
1306 void SOSCircleForEachValidSyncingPeer(SOSCircleRef circle, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)) {
1307 SOSCircleForEachValidPeer(circle, user_public_key, action);
1308 }
1309
1310 void SOSCircleForEachBackupCapablePeerForView(SOSCircleRef circle, SecKeyRef user_public_key, CFStringRef viewName, void (^action)(SOSPeerInfoRef peer)) {
1311 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1312 return (!isHiddenPeer(peer) && SOSPeerInfoIsEnabledView(peer, viewName) /* let the wookie win --- && SOSPeerInfoHasBackupKey(peer)*/ && SOSPeerInfoApplicationVerify(peer, user_public_key, NULL));
1313 });
1314 }
1315
1316 void SOSCircleForEachApplicant(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1317 CFSetForEach(circle->applicants, ^(const void*value) { action((SOSPeerInfoRef) value); } );
1318 }
1319
1320
1321 bool SOSCircleHasPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
1322 SOSCircleAssertStable(circle);
1323 if(!peerid) {
1324 return false;
1325 }
1326 SOSPeerInfoRef found = asSOSPeerInfo(CFSetGetValue(circle->peers, peerid));
1327 return found && !isHiddenPeer(found);
1328 }
1329
1330 SOSPeerInfoRef SOSCircleCopyPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
1331 SOSCircleAssertStable(circle);
1332
1333 SOSPeerInfoRef found = asSOSPeerInfo(CFSetGetValue(circle->peers, peerid));
1334 return found ? SOSPeerInfoCreateCopy(kCFAllocatorDefault, found, NULL) : NULL;
1335 }
1336
1337 bool SOSCircleHasPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1338 if(!peerInfo) return false;
1339 return SOSCircleHasPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
1340 }
1341
1342 bool SOSCircleHasActivePeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
1343 SOSCircleAssertStable(circle);
1344 SOSPeerInfoRef found = asSOSPeerInfo(CFSetGetValue(circle->peers, peerid));
1345 return found;
1346 }
1347
1348 bool SOSCircleHasActivePeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1349 if(!peerInfo) return false;
1350 return SOSCircleHasActivePeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
1351 }
1352
1353 bool SOSCircleHasActiveValidPeerWithID(SOSCircleRef circle, CFStringRef peerid, SecKeyRef user_public_key, CFErrorRef *error) {
1354 SOSCircleAssertStable(circle);
1355 SOSPeerInfoRef found = asSOSPeerInfo(CFSetGetValue(circle->peers, peerid));
1356 return found && SOSPeerInfoApplicationVerify(found, user_public_key, NULL);
1357 }
1358
1359 bool SOSCircleHasValidSyncingPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, SecKeyRef user_public_key, CFErrorRef *error) {
1360 SOSCircleAssertStable(circle);
1361 SOSPeerInfoRef found = asSOSPeerInfo(CFSetGetValue(circle->peers, peerInfo));
1362 return found && !isHiddenPeer(found) && SOSPeerInfoApplicationVerify(found, user_public_key, NULL);
1363 }
1364
1365 bool SOSCircleHasActiveValidPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, SecKeyRef user_public_key, CFErrorRef *error) {
1366 if(!peerInfo) return false;
1367 return SOSCircleHasActiveValidPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), user_public_key, error);
1368 }
1369
1370
1371 CFMutableSetRef SOSCircleCopyPeers(SOSCircleRef circle, CFAllocatorRef allocator) {
1372 SOSCircleAssertStable(circle);
1373
1374 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
1375
1376 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
1377 CFSetAddValue(result, peer);
1378 });
1379
1380 return result;
1381 }
1382
1383
1384 CFMutableSetRef SOSCircleCopyBackupCapablePeersForView(SOSCircleRef circle, CFAllocatorRef allocator, SecKeyRef userPubKey, CFStringRef viewName) {
1385 SOSCircleAssertStable(circle);
1386
1387 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
1388
1389 SOSCircleForEachBackupCapablePeerForView(circle, userPubKey, viewName, ^(SOSPeerInfoRef peer) {
1390 CFSetAddValue(result, peer);
1391 });
1392
1393 return result;
1394 }
1395
1396 bool SOSCircleAppendConcurringPeers(SOSCircleRef circle, CFMutableArrayRef appendHere, CFErrorRef *error) {
1397 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1398 CFErrorRef localError = NULL;
1399 if (SOSCircleVerifyPeerSigned(circle, peer, &localError)) {
1400 SOSPeerInfoRef peerInfo = SOSPeerInfoCreateCopy(kCFAllocatorDefault, peer, error);
1401 CFArrayAppendValue(appendHere, peerInfo);
1402 CFRelease(peerInfo);
1403 } else if (error != NULL) {
1404 secerror("Error checking concurrence: %@", localError);
1405 }
1406 CFReleaseNull(localError);
1407 });
1408
1409 return true;
1410 }
1411
1412 CFMutableArrayRef SOSCircleCopyConcurringPeers(SOSCircleRef circle, CFErrorRef* error) {
1413 SOSCircleAssertStable(circle);
1414
1415 CFMutableArrayRef concurringPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
1416
1417 if (!SOSCircleAppendConcurringPeers(circle, concurringPeers, error))
1418 CFReleaseNull(concurringPeers);
1419
1420 return concurringPeers;
1421 }
1422
1423 SOSFullPeerInfoRef SOSCircleCopyiCloudFullPeerInfoRef(SOSCircleRef circle, CFErrorRef *error) {
1424 __block SOSFullPeerInfoRef cloud_full_peer = NULL;
1425 __block CFErrorRef searchError = NULL;
1426 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1427 if (SOSPeerInfoIsCloudIdentity(peer)) {
1428 if (cloud_full_peer == NULL) {
1429 if (searchError) {
1430 secerror("More than one cloud identity found, first had error, trying new one.");
1431 }
1432 CFReleaseNull(searchError);
1433 cloud_full_peer = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, &searchError);
1434 if (!cloud_full_peer) {
1435 secnotice("icloud-identity", "Failed to make FullPeer for iCloud Identity: %@ (%@)", cloud_full_peer, searchError);
1436 }
1437 } else {
1438 secerror("Additional cloud identity found in circle after successful creation: %@", circle);
1439 }
1440 }
1441 });
1442 // If we didn't find one at all, report the error.
1443 if (cloud_full_peer == NULL && searchError == NULL) {
1444 SOSErrorCreate(kSOSErrorNoiCloudPeer, &searchError, NULL, CFSTR("No iCloud identity PeerInfo found in circle"));
1445 secnotice("icloud-identity", "No iCloud identity PeerInfo found in circle");
1446 }
1447 if (error) {
1448 CFTransferRetained(*error, searchError);
1449 }
1450 CFReleaseNull(searchError);
1451 return cloud_full_peer;
1452 }
1453
1454 SOSFullPeerInfoRef SOSCircleCopyiCloudFullPeerInfoVerifier(SOSCircleRef circle, CFErrorRef *error) {
1455 __block CFErrorRef searchError = NULL;
1456 __block SOSFullPeerInfoRef cloud_full_peer = NULL;
1457 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1458 // There should only ever be one signing iCloud identity. If there are more we'll take the first one.
1459 if (!cloud_full_peer && SOSPeerInfoIsCloudIdentity(peer) && SOSCircleVerifyPeerSignatureExists(circle, peer)) {
1460 cloud_full_peer = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, &searchError);
1461 }
1462 });
1463 // If we didn't find one at all, report the error.
1464 if (cloud_full_peer == NULL && searchError == NULL) {
1465 SOSErrorCreate(kSOSErrorNoiCloudPeer, &searchError, NULL, CFSTR("No iCloud identity PeerInfo found in circle"));
1466 secnotice("icloud-identity", "No iCloud identity PeerInfo found in circle");
1467 }
1468 if (error) {
1469 CFTransferRetained(*error, searchError);
1470 }
1471 CFReleaseNull(searchError);
1472 return cloud_full_peer;
1473 }
1474
1475 void debugDumpCircle(CFStringRef message, SOSCircleRef circle) {
1476 CFErrorRef error;
1477
1478 secinfo("circledebug", "%@: %@", message, circle);
1479 if (!circle)
1480 return;
1481
1482 CFDataRef derdata = SOSCircleCopyEncodedData(circle, kCFAllocatorDefault, &error);
1483 if (derdata) {
1484 CFStringRef hex = CFDataCopyHexString(derdata);
1485 secinfo("circledebug", "Full contents: %@", hex);
1486 if (hex) CFRelease(hex);
1487 CFRelease(derdata);
1488 }
1489 }
1490
1491 bool SOSCircleAcceptPeerFromHSA2(SOSCircleRef circle, SecKeyRef userKey, SOSGenCountRef gencount, SecKeyRef pPubKey, CFDataRef signature, SOSFullPeerInfoRef fpi, CFErrorRef *error) {
1492 SOSPeerInfoRef peerInfo = SOSFullPeerInfoGetPeerInfo(fpi);
1493 bool res;
1494
1495 CFSetAddValue(circle->peers, peerInfo);
1496
1497 // Gen sign first, then add signature from our approver - remember gensign removes all existing sigs.
1498 res = SOSCircleGenerationSignWithGenCount(circle, userKey, fpi, gencount, error);
1499 if (!res) {
1500 secnotice("circleOps", "Failed to regenerate circle with new gen count: %@", error ? *error : NULL);
1501 return res;
1502 }
1503 res = SOSCircleSetSignature(circle, pPubKey, signature, error);
1504 if (!res) {
1505 secnotice("circleOps", "Failed to set signature: %@", error ? *error : NULL);
1506 return res;
1507 }
1508 res = SOSCircleVerify(circle, pPubKey, error);
1509 if (!res) {
1510 secnotice("circleOps", "Circle failed to validate after peer signature: %@", error ? *error : NULL);
1511 return res;
1512 }
1513 secnotice("circleOps", "Circle accepted successfully");
1514
1515 return true;
1516 }
1517
1518
1519 /*
1520 ccstatus: Not in Circle (1)
1521 Account user public is trusted
1522 Generation Count: [2016-05-19 15:53 4]
1523
1524 */
1525
1526 static inline void logPeerInfo(char *category, SOSCircleRef circle, SecKeyRef pubKey, CFStringRef myPID, SOSPeerInfoRef peer) {
1527 char sigchr = 'v';
1528 if (SOSCircleVerifyPeerSignatureExists(circle, peer)) {
1529 sigchr = 'V';
1530 }
1531 SOSPeerInfoLogState(category, peer, pubKey, myPID, sigchr);
1532 }
1533
1534 void SOSCircleLogState(char *category, SOSCircleRef circle, SecKeyRef pubKey, CFStringRef myPID) {
1535 if(!circle) return;
1536 CFStringRef genString = SOSGenerationCountCopyDescription(SOSCircleGetGeneration(circle));
1537 char sigchr = 'v';
1538 if(pubKey && SOSCircleVerifySignatureExists(circle, pubKey, NULL)) {
1539 sigchr = 'V';
1540 }
1541 secnotice(category, "CIRCLE: [%20@] UserSigned: %c", genString, sigchr);
1542 if(CFSetGetCount(circle->peers) == 0 )
1543 secnotice(category, "Peers In Circle: None");
1544 else{
1545 secnotice(category, "Peers In Circle:");
1546 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
1547 logPeerInfo(category, circle, pubKey, myPID, peer);
1548 });
1549 SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) {
1550 logPeerInfo(category, circle, pubKey, myPID, peer);
1551 });
1552 SOSCircleForEachiCloudIdentityPeer(circle, ^(SOSPeerInfoRef peer) {
1553 logPeerInfo(category, circle, pubKey, myPID, peer);
1554 });
1555 }
1556
1557 //applicants
1558 if(CFSetGetCount(circle->applicants) == 0 )
1559 secnotice(category, "Applicants To Circle: None");
1560 else{
1561 secnotice(category, "Applicants To Circle:");
1562
1563 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
1564 SOSPeerInfoLogState(category, peer, pubKey, myPID, 'v');
1565 });
1566 }
1567
1568 //rejected
1569 if(CFSetGetCount(circle->rejected_applicants) == 0)
1570 secnotice(category, "Rejected Applicants To Circle: None");
1571 else{
1572 secnotice(category, "Rejected Applicants To Circle:");
1573 CFSetForEach(circle->rejected_applicants, ^(const void *value) {
1574 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
1575 SOSPeerInfoLogState(category, peer, pubKey, myPID, 'v');
1576 });
1577 }
1578 CFReleaseNull(genString);
1579 }
1580