2  * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  26  * SOSCircle.c -  Implementation of the secure object syncing transport 
  29 #include <AssertMacros.h> 
  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> 
  44 #include <Security/SecKey.h> 
  45 #include <Security/SecKeyPriv.h> 
  47 #include <utilities/SecCFWrappers.h> 
  48 #include <Security/SecureObjectSync/SOSCirclePriv.h> 
  50 //#include "ckdUtilities.h" 
  52 #include <corecrypto/ccder.h> 
  53 #include <corecrypto/ccdigest.h> 
  54 #include <corecrypto/ccsha2.h> 
  59 CFGiblisWithCompareFor(SOSCircle
); 
  61 SOSCircleRef 
SOSCircleCreate(CFAllocatorRef allocator
, CFStringRef name
, CFErrorRef 
*error
) { 
  62     SOSCircleRef c 
= CFTypeAllocate(SOSCircle
, struct __OpaqueSOSCircle
, allocator
); 
  65     c
->name 
= CFStringCreateCopy(allocator
, name
); 
  66     c
->generation 
= SOSGenerationCreate(); 
  67     c
->peers 
= CFSetCreateMutableForSOSPeerInfosByID(allocator
); 
  68     c
->applicants 
= CFSetCreateMutableForSOSPeerInfosByID(allocator
); 
  69     c
->rejected_applicants 
= CFSetCreateMutableForSOSPeerInfosByID(allocator
); 
  70     c
->signatures 
= CFDictionaryCreateMutableForCFTypes(allocator
); 
  74 static CFMutableSetRef 
CFSetOfPeerInfoDeepCopy(CFAllocatorRef allocator
, CFSetRef peerInfoSet
) 
  76    __block CFMutableSetRef result 
= CFSetCreateMutableForSOSPeerInfosByID(allocator
); 
  77     CFSetForEach(peerInfoSet
, ^(const void *value
) { 
  78         SOSPeerInfoRef pi 
= (SOSPeerInfoRef
) value
; 
  79         CFErrorRef localError 
= NULL
; 
  80         SOSPeerInfoRef copiedPeer 
= SOSPeerInfoCreateCopy(allocator
, pi
, &localError
); 
  82             CFSetAddValue(result
, copiedPeer
); 
  84             secerror("Failed to copy peer: %@ (%@)", pi
, localError
); 
  86         CFReleaseSafe(copiedPeer
); 
  87         CFReleaseSafe(localError
); 
  92 SOSCircleRef 
SOSCircleCopyCircle(CFAllocatorRef allocator
, SOSCircleRef otherCircle
, CFErrorRef 
*error
) 
  94     SOSCircleRef c 
= CFTypeAllocate(SOSCircle
, struct __OpaqueSOSCircle
, allocator
); 
  97     c
->name 
= CFStringCreateCopy(allocator
, otherCircle
->name
); 
  98     c
->generation 
= SOSGenerationCopy(otherCircle
->generation
); 
 100     c
->peers 
= CFSetOfPeerInfoDeepCopy(allocator
, otherCircle
->peers
); 
 101     c
->applicants 
= CFSetOfPeerInfoDeepCopy(allocator
, otherCircle
->applicants
); 
 102     c
->rejected_applicants 
= CFSetOfPeerInfoDeepCopy(allocator
, otherCircle
->rejected_applicants
); 
 104     c
->signatures 
= CFDictionaryCreateMutableCopy(allocator
, 0, otherCircle
->signatures
); 
 109 static Boolean 
SOSCircleCompare(CFTypeRef lhs
, CFTypeRef rhs
) { 
 110     if (CFGetTypeID(lhs
) != SOSCircleGetTypeID() 
 111      || CFGetTypeID(rhs
) != SOSCircleGetTypeID()) 
 114     SOSCircleRef left 
= SOSCircleConvertAndAssertStable(lhs
); 
 115     SOSCircleRef right 
= SOSCircleConvertAndAssertStable(rhs
); 
 117     // TODO: we should be doing set equality for peers and applicants. 
 118     return NULL 
!= left 
&& NULL 
!= right
 
 119         && CFEqualSafe(left
->generation
, right
->generation
) 
 120         && SOSPeerInfoSetContainsIdenticalPeers(left
->peers
, right
->peers
) 
 121         && SOSPeerInfoSetContainsIdenticalPeers(left
->applicants
, right
->applicants
) 
 122         && SOSPeerInfoSetContainsIdenticalPeers(left
->rejected_applicants
, right
->rejected_applicants
) 
 123         && CFEqualSafe(left
->signatures
, right
->signatures
); 
 126 static CFMutableArrayRef 
CFSetCopyValuesCFArray(CFSetRef set
) 
 128     CFIndex count 
= CFSetGetCount(set
); 
 130     CFMutableArrayRef result 
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
); 
 132         const void * values
[count
]; 
 133         CFSetGetValues(set
, values
); 
 134         for (int current 
= 0; current 
< count
; ++current
) { 
 135             CFArrayAppendValue(result
, values
[current
]); 
 142 static bool SOSCircleDigestArray(const struct ccdigest_info 
*di
, CFMutableArrayRef array
, void *hash_result
, CFErrorRef 
*error
) 
 144     __block 
bool success 
= true; 
 145     ccdigest_di_decl(di
, array_digest
); 
 146     const void * a_digest 
= array_digest
; 
 148     ccdigest_init(di
, array_digest
); 
 149     CFArraySortValues(array
, CFRangeMake(0, CFArrayGetCount(array
)), SOSPeerInfoCompareByID
, SOSPeerCmpPubKeyHash
); 
 150     CFArrayForEach(array
, ^(const void *peer
) { 
 151         if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes((SOSPeerInfoRef
)peer
, di
, a_digest
, error
)) 
 154     ccdigest_final(di
, array_digest
, hash_result
); 
 159 static bool SOSCircleDigestSet(const struct ccdigest_info 
*di
, CFMutableSetRef set
, void *hash_result
, CFErrorRef 
*error
) 
 161     CFMutableArrayRef values 
= CFSetCopyValuesCFArray(set
); 
 163     bool result 
= SOSCircleDigestArray(di
, values
, hash_result
, error
); 
 165     CFReleaseSafe(values
); 
 171 static bool SOSCircleHash(const struct ccdigest_info 
*di
, SOSCircleRef circle
, void *hash_result
, CFErrorRef 
*error
) { 
 172     ccdigest_di_decl(di
, circle_digest
); 
 173     ccdigest_init(di
, circle_digest
); 
 174     int64_t gen 
= SOSCircleGetGenerationSint(circle
); 
 175     ccdigest_update(di
, circle_digest
, sizeof(gen
), &gen
); 
 177     SOSCircleDigestSet(di
, circle
->peers
, hash_result
, error
); 
 178     ccdigest_update(di
, circle_digest
, di
->output_size
, hash_result
); 
 179     ccdigest_final(di
, circle_digest
, hash_result
); 
 183 static bool SOSCircleSetSignature(SOSCircleRef circle
, SecKeyRef pubkey
, CFDataRef signature
, CFErrorRef 
*error
) { 
 186     CFStringRef pubKeyID 
= SOSCopyIDOfKey(pubkey
, error
); 
 187     require_quiet(pubKeyID
, fail
); 
 188     CFDictionarySetValue(circle
->signatures
, pubKeyID
, signature
); 
 192     CFReleaseSafe(pubKeyID
); 
 196 static bool SOSCircleRemoveSignatures(SOSCircleRef circle
, CFErrorRef 
*error
) { 
 197     CFDictionaryRemoveAllValues(circle
->signatures
); 
 201 static CFDataRef 
SOSCircleGetSignature(SOSCircleRef circle
, SecKeyRef pubkey
, CFErrorRef 
*error
) {     
 202     CFStringRef pubKeyID 
= SOSCopyIDOfKey(pubkey
, error
); 
 203     CFDataRef result 
= NULL
; 
 204     require_quiet(pubKeyID
, fail
); 
 206     CFTypeRef value 
= (CFDataRef
)CFDictionaryGetValue(circle
->signatures
, pubKeyID
); 
 208     if (isData(value
)) result 
= (CFDataRef
) value
; 
 211     CFReleaseSafe(pubKeyID
); 
 215 bool SOSCircleSign(SOSCircleRef circle
, SecKeyRef privKey
, CFErrorRef 
*error
) { 
 216     if (!privKey
) return false; // Really assertion but not always true for now. 
 217     CFAllocatorRef allocator 
= CFGetAllocator(circle
); 
 219     size_t tmplen 
= 4096; 
 220     const struct ccdigest_info 
*di 
= ccsha256_di(); 
 221     uint8_t hash_result
[di
->output_size
]; 
 223     SOSCircleHash(di
, circle
, hash_result
, error
); 
 224     OSStatus stat 
=  SecKeyRawSign(privKey
, kSecPaddingNone
, hash_result
, di
->output_size
, tmp
, &tmplen
); 
 226         // TODO - Create a CFErrorRef; 
 227         secerror("Bad Circle SecKeyRawSign, stat: %ld", (long)stat
); 
 228         SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Circle SecKeyRawSign"), (error 
!= NULL
) ? *error 
: NULL
, error
); 
 231     CFDataRef signature 
= CFDataCreate(allocator
, tmp
, tmplen
); 
 232     SecKeyRef publicKey 
= SecKeyCreatePublicFromPrivate(privKey
); 
 233     SOSCircleSetSignature(circle
, publicKey
, signature
, error
); 
 234     CFReleaseNull(publicKey
); 
 235     CFRelease(signature
); 
 239 static bool SOSCircleConcordanceRingSign(SOSCircleRef circle
, SecKeyRef privKey
, CFErrorRef 
*error
) { 
 240     secnotice("Development", "SOSCircleEnsureRingConsistency requires ring signing op", NULL
); 
 245 bool SOSCircleVerifySignatureExists(SOSCircleRef circle
, SecKeyRef pubKey
, CFErrorRef 
*error
) { 
 248         secerror("SOSCircleVerifySignatureExists no pubKey"); 
 249         SOSCreateError(kSOSErrorBadFormat
, CFSTR("SOSCircleVerifySignatureExists no pubKey"), (error 
!= NULL
) ? *error 
: NULL
, error
); 
 252     CFDataRef signature 
= SOSCircleGetSignature(circle
, pubKey
, error
); 
 253     return NULL 
!= signature
; 
 256 bool SOSCircleVerify(SOSCircleRef circle
, SecKeyRef pubKey
, CFErrorRef 
*error
) { 
 257     const struct ccdigest_info 
*di 
= ccsha256_di(); 
 258     uint8_t hash_result
[di
->output_size
]; 
 260     SOSCircleHash(di
, circle
, hash_result
, error
); 
 262     CFDataRef signature 
= SOSCircleGetSignature(circle
, pubKey
, error
); 
 263     if(!signature
) return false; 
 265     return SecKeyRawVerify(pubKey
, kSecPaddingNone
, hash_result
, di
->output_size
, 
 266                            CFDataGetBytePtr(signature
), CFDataGetLength(signature
)) == errSecSuccess
; 
 269 bool SOSCircleVerifyPeerSigned(SOSCircleRef circle
, SOSPeerInfoRef peer
, CFErrorRef 
*error
) { 
 270     SecKeyRef pub_key 
= SOSPeerInfoCopyPubKey(peer
); 
 271     bool result 
= SOSCircleVerify(circle
, pub_key
, error
); 
 272     CFReleaseSafe(pub_key
); 
 276 static void CFSetRemoveAllPassing(CFMutableSetRef set
, bool (^test
)(const void *) ){ 
 277     CFMutableArrayRef toBeRemoved 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
); 
 279     CFSetForEach(set
, ^(const void *value
) { 
 281             CFArrayAppendValue(toBeRemoved
, value
); 
 284     CFArrayForEach(toBeRemoved
, ^(const void *value
) { 
 285         CFSetRemoveValue(set
, value
); 
 287     CFReleaseNull(toBeRemoved
); 
 290 static void SOSCircleRejectNonValidApplicants(SOSCircleRef circle
, SecKeyRef pubkey
) { 
 291     CFMutableSetRef applicants 
= SOSCircleCopyApplicants(circle
, NULL
); 
 292     CFSetForEach(applicants
, ^(const void *value
) { 
 293         SOSPeerInfoRef pi 
= (SOSPeerInfoRef
) value
; 
 294         if(!SOSPeerInfoApplicationVerify(pi
, pubkey
, NULL
)) { 
 295             CFSetTransferObject(pi
, circle
->applicants
, circle
->rejected_applicants
); 
 298     CFReleaseNull(applicants
); 
 301 static SOSPeerInfoRef 
SOSCircleCopyPeerInfo(SOSCircleRef circle
, CFStringRef peer_id
, CFErrorRef 
*error
) { 
 302     __block SOSPeerInfoRef result 
= NULL
; 
 304     CFSetForEach(circle
->peers
, ^(const void *value
) { 
 305         if (result 
== NULL
) { 
 306             SOSPeerInfoRef tpi 
= (SOSPeerInfoRef
)value
; 
 307             if (CFEqual(SOSPeerInfoGetPeerID(tpi
), peer_id
)) 
 312     CFRetainSafe(result
); 
 316 static bool SOSCircleUpgradePeerInfo(SOSCircleRef circle
, SecKeyRef user_approver
, SOSFullPeerInfoRef peerinfo
) { 
 318     SecKeyRef userPubKey 
= SecKeyCreatePublicFromPrivate(user_approver
); 
 319     SOSPeerInfoRef fpi_pi 
= SOSFullPeerInfoGetPeerInfo(peerinfo
); 
 320     SOSPeerInfoRef pi 
= SOSCircleCopyPeerInfo(circle
, SOSPeerInfoGetPeerID(fpi_pi
), NULL
); 
 321     require_quiet(pi
, out
); 
 322     require_quiet(SOSPeerInfoApplicationVerify(pi
, userPubKey
, NULL
), re_sign
); 
 323     CFReleaseNull(userPubKey
); 
 328     secnotice("circle", "SOSCircleGenerationSign: Upgraded peer's Application Signature"); 
 329     SecKeyRef device_key 
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, NULL
); 
 330     require_quiet(device_key
, out
); 
 331     SOSPeerInfoRef new_pi 
= SOSPeerInfoCopyAsApplication(pi
, user_approver
, device_key
, NULL
); 
 332     if(SOSCircleUpdatePeerInfo(circle
, new_pi
)) 
 334     CFReleaseNull(new_pi
); 
 335     CFReleaseNull(device_key
); 
 337     CFReleaseNull(userPubKey
); 
 342 static bool SOSCircleEnsureRingConsistency(SOSCircleRef circle
, CFErrorRef 
*error
) { 
 343     secnotice("Development", "SOSCircleEnsureRingConsistency requires ring membership and generation count consistency check", NULL
); 
 347 bool SOSCircleSignOldStyleResetToOfferingCircle(SOSCircleRef circle
, SOSFullPeerInfoRef peerinfo
, SecKeyRef user_approver
, CFErrorRef 
*error
){ 
 349     SecKeyRef ourKey 
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, error
); 
 350     SecKeyRef publicKey 
= NULL
; 
 351     require_quiet(ourKey
, fail
); 
 353     // Check if we're using an invalid peerinfo for this op.  There are cases where we might not be "upgraded". 
 354     require_quiet(SOSCircleUpgradePeerInfo(circle
, user_approver
, peerinfo
), fail
); 
 355     SOSCircleRemoveRetired(circle
, error
); // Prune off retirees since we're signing this one 
 356     CFSetRemoveAllValues(circle
->rejected_applicants
); // Dump rejects so we clean them up sometime. 
 357     publicKey 
= SecKeyCreatePublicFromPrivate(user_approver
); 
 358     SOSCircleRejectNonValidApplicants(circle
, publicKey
); 
 359     require_quiet(SOSCircleEnsureRingConsistency(circle
, error
), fail
); 
 360     require_quiet(SOSCircleRemoveSignatures(circle
, error
), fail
); 
 361     require_quiet(SOSCircleSign(circle
, user_approver
, error
), fail
); 
 362     require_quiet(SOSCircleSign(circle
, ourKey
, error
), fail
); 
 364     CFReleaseNull(ourKey
); 
 365     CFReleaseNull(publicKey
); 
 369     CFReleaseNull(ourKey
); 
 370     CFReleaseNull(publicKey
); 
 375 bool SOSCircleGenerationSign(SOSCircleRef circle
, SecKeyRef user_approver
, SOSFullPeerInfoRef peerinfo
, CFErrorRef 
*error
) { 
 376     SecKeyRef publicKey 
= NULL
; 
 378     SOSCircleRemoveRetired(circle
, error
); // Prune off retirees since we're signing this one 
 379     CFSetRemoveAllValues(circle
->rejected_applicants
); // Dump rejects so we clean them up sometime. 
 380     publicKey 
= SecKeyCreatePublicFromPrivate(user_approver
); 
 381     SOSCircleRejectNonValidApplicants(circle
, publicKey
); 
 382     SOSCircleGenerationIncrement(circle
); 
 383     require_quiet(SOSCircleEnsureRingConsistency(circle
, error
), fail
); 
 384     require_quiet(SOSCircleRemoveSignatures(circle
, error
), fail
); 
 386     if (SOSCircleCountPeers(circle
) != 0) { 
 387         SecKeyRef ourKey 
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, error
); 
 388         require_quiet(ourKey
, fail
); 
 390         // Check if we're using an invalid peerinfo for this op.  There are cases where we might not be "upgraded". 
 391         require_quiet(SOSCircleUpgradePeerInfo(circle
, user_approver
, peerinfo
), fail
); 
 393         require_quiet(SOSCircleSign(circle
, user_approver
, error
), fail
); 
 394         require_quiet(SOSCircleSign(circle
, ourKey
, error
), fail
); 
 395         CFReleaseNull(ourKey
); 
 398     CFReleaseNull(publicKey
); 
 402     CFReleaseNull(publicKey
); 
 406 bool SOSCircleGenerationUpdate(SOSCircleRef circle
, SecKeyRef user_approver
, SOSFullPeerInfoRef peerinfo
, CFErrorRef 
*error
) { 
 408     return SOSCircleGenerationSign(circle
, user_approver
, peerinfo
, error
); 
 411     bool success 
= false; 
 413     SecKeyRef ourKey 
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, error
); 
 414     require_quiet(ourKey
, fail
); 
 416     require_quiet(SOSCircleSign(circle
, user_approver
, error
), fail
); 
 417     require_quiet(SOSCircleSign(circle
, ourKey
, error
), fail
); 
 422     CFReleaseNull(ourKey
); 
 427 bool SOSCircleConcordanceSign(SOSCircleRef circle
, SOSFullPeerInfoRef peerinfo
, CFErrorRef 
*error
) { 
 428     bool success 
= false; 
 429     SecKeyRef ourKey 
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, error
); 
 430     require_quiet(ourKey
, exit
); 
 432     success 
= SOSCircleSign(circle
, ourKey
, error
); 
 433     SOSCircleConcordanceRingSign(circle
, ourKey
, error
); 
 436     CFReleaseNull(ourKey
); 
 440 static inline SOSConcordanceStatus 
CheckPeerStatus(SOSCircleRef circle
, SOSPeerInfoRef peer
, SecKeyRef user_public_key
, CFErrorRef 
*error
) { 
 441     SOSConcordanceStatus result 
= kSOSConcordanceNoPeer
; 
 442     SecKeyRef pubKey 
= SOSPeerInfoCopyPubKey(peer
); 
 444     require_action_quiet(SOSCircleHasActiveValidPeer(circle
, peer
, user_public_key
, error
), exit
, result 
= kSOSConcordanceNoPeer
); 
 445     require_action_quiet(SOSCircleVerifySignatureExists(circle
, pubKey
, error
), exit
, result 
= kSOSConcordanceNoPeerSig
); 
 446     require_action_quiet(SOSCircleVerify(circle
, pubKey
, error
), exit
, result 
= kSOSConcordanceBadPeerSig
); 
 448     result 
= kSOSConcordanceTrusted
; 
 451     CFReleaseNull(pubKey
); 
 455 static inline SOSConcordanceStatus 
CombineStatus(SOSConcordanceStatus status1
, SOSConcordanceStatus status2
) 
 457     if (status1 
== kSOSConcordanceTrusted 
|| status2 
== kSOSConcordanceTrusted
) 
 458         return kSOSConcordanceTrusted
; 
 460     if (status1 
== kSOSConcordanceBadPeerSig 
|| status2 
== kSOSConcordanceBadPeerSig
) 
 461         return kSOSConcordanceBadPeerSig
; 
 463     if (status1 
== kSOSConcordanceNoPeerSig 
|| status2 
== kSOSConcordanceNoPeerSig
) 
 464         return kSOSConcordanceNoPeerSig
; 
 469 static inline bool SOSCircleIsEmpty(SOSCircleRef circle
) { 
 470     return SOSCircleCountPeers(circle
) == 0; 
 473 static inline bool SOSCircleHasDegenerateGeneration(SOSCircleRef deGenCircle
){ 
 475     CFNumberRef genCountTest 
= SOSCircleGetGeneration(deGenCircle
); 
 476     CFNumberGetValue(genCountTest
, kCFNumberCFIndexType
, &testPtr
); 
 477     return (testPtr
== 0); 
 481 static inline bool SOSCircleIsDegenerateReset(SOSCircleRef deGenCircle
){ 
 482     return SOSCircleHasDegenerateGeneration(deGenCircle
) && SOSCircleIsEmpty(deGenCircle
); 
 486 __unused 
static inline bool SOSCircleIsResignOffering(SOSCircleRef circle
, SecKeyRef pubkey
) { 
 487     return SOSCircleCountActiveValidPeers(circle
, pubkey
) == 1; 
 490 static inline SOSConcordanceStatus 
GetSignersStatus(SOSCircleRef signers_circle
, SOSCircleRef status_circle
, 
 491                                                     SecKeyRef user_pubKey
, SOSPeerInfoRef exclude
, CFErrorRef 
*error
) { 
 492     CFStringRef excluded_id 
= exclude 
? SOSPeerInfoGetPeerID(exclude
) : NULL
; 
 494     __block SOSConcordanceStatus status 
= kSOSConcordanceNoPeer
; 
 495     SOSCircleForEachActivePeer(signers_circle
, ^(SOSPeerInfoRef peer
) { 
 496         SOSConcordanceStatus peerStatus 
= CheckPeerStatus(status_circle
, peer
, user_pubKey
, error
); 
 498         if (peerStatus 
== kSOSConcordanceNoPeerSig 
&& 
 499             (CFEqualSafe(SOSPeerInfoGetPeerID(peer
), excluded_id
) || SOSPeerInfoIsCloudIdentity(peer
))) 
 500             peerStatus 
= kSOSConcordanceNoPeer
; 
 502         status 
= CombineStatus(status
, peerStatus
); // TODO: Use multiple error gathering. 
 508 // Is proposed older than current? 
 509 static inline bool isOlderGeneration(SOSCircleRef current
, SOSCircleRef proposed
) { 
 510     return CFNumberCompare(current
->generation
, proposed
->generation
, NULL
) == kCFCompareGreaterThan
; 
 513 static inline bool SOSCircleIsValidReset(SOSCircleRef current
, SOSCircleRef proposed
) { 
 514     return (!isOlderGeneration(current
, proposed
)) && SOSCircleIsEmpty(proposed
); // is current older or equal to  proposed and is proposed empty 
 518 bool SOSCircleSharedTrustedPeers(SOSCircleRef current
, SOSCircleRef proposed
, SOSPeerInfoRef me
) { 
 519     __block 
bool retval 
= false; 
 520     SOSCircleForEachPeer(current
, ^(SOSPeerInfoRef peer
) { 
 521         if(!CFEqual(me
, peer
) && SOSCircleHasPeer(proposed
, peer
, NULL
)) retval 
= true; 
 526 static SOSConcordanceStatus 
GetOfferingStatus(SOSCircleRef circle
, SecKeyRef user_pubKey
, CFErrorRef 
*error
) { 
 527     __block SOSConcordanceStatus status 
= kSOSConcordanceNoPeer
; 
 528     SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) { 
 529         status 
= CheckPeerStatus(circle
, peer
, user_pubKey
, error
); 
 530         if(status 
!= kSOSConcordanceTrusted
) status 
= kSOSConcordanceNoPeer
; 
 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 
 544     if(SOSCircleIsDegenerateReset(proposed_circle
)) { 
 545         return kSOSConcordanceTrusted
; 
 548     if (SOSCircleIsValidReset(known_circle
, proposed_circle
)) { 
 549         return kSOSConcordanceTrusted
; 
 552     if(!SOSCircleVerifySignatureExists(proposed_circle
, user_pubkey
, error
)) { 
 553         SOSCreateError(kSOSErrorBadSignature
, CFSTR("No public signature"), (error 
!= NULL
) ? *error 
: NULL
, error
); 
 554         return kSOSConcordanceNoUserSig
; 
 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
; 
 563     if (SOSCircleIsEmpty(known_circle
)) { 
 564         return GetSignersStatus(proposed_circle
, proposed_circle
, user_pubkey
, NULL
, error
); 
 567     if(SOSCircleHasDegenerateGeneration(proposed_circle
) && SOSCircleIsOffering(proposed_circle
)){ 
 568         return GetSignersStatus(proposed_circle
, proposed_circle
, user_pubkey
, NULL
, error
); 
 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
; 
 578     if(SOSCircleIsOffering(proposed_circle
)){ 
 579         return GetOfferingStatus(proposed_circle
, user_pubkey
, error
); 
 582     return GetSignersStatus(known_circle
, proposed_circle
, user_pubkey
, me
, error
); 
 586 static void SOSCircleDestroy(CFTypeRef aObj
) { 
 587     SOSCircleRef c 
= (SOSCircleRef
) aObj
; 
 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
); 
 597 static CFMutableStringRef 
defaultDescription(CFTypeRef aObj
){ 
 598     SOSCircleRef c 
= (SOSCircleRef
) aObj
; 
 600     CFMutableStringRef description 
= CFStringCreateMutable(kCFAllocatorDefault
, 0); 
 602     SOSGenerationCountWithDescription(c
->generation
, ^(CFStringRef genDescription
) { 
 603         CFStringAppendFormat(description
, NULL
, CFSTR("<SOSCircle@%p: '%@' %@ P:["), c
, c
->name
, genDescription
); 
 606     __block CFStringRef separator 
= CFSTR(""); 
 607     SOSCircleForEachActivePeer(c
, ^(SOSPeerInfoRef peer
) { 
 608         CFStringRef sig 
= NULL
; 
 609         if (SOSCircleVerifyPeerSigned(c
, peer
, NULL
)) { 
 612             SecKeyRef pub_key 
= SOSPeerInfoCopyPubKey(peer
); 
 613             CFDataRef signature 
= SOSCircleGetSignature(c
, pub_key
, NULL
); 
 614             sig 
= (signature 
== NULL
) ? CFSTR("-") : CFSTR("?"); 
 615             CFReleaseNull(pub_key
); 
 618         CFStringAppendFormat(description
, NULL
, CFSTR("%@%@ %@"), separator
, peer
, sig
); 
 619         separator 
= CFSTR(","); 
 623     CFStringAppend(description
, CFSTR("], A:[")); 
 624     separator 
= CFSTR(""); 
 625     if(CFSetGetCount(c
->applicants
) == 0 ) 
 626         CFStringAppendFormat(description
, NULL
, CFSTR("-")); 
 629         SOSCircleForEachApplicant(c
, ^(SOSPeerInfoRef peer
) { 
 630             CFStringAppendFormat(description
, NULL
, CFSTR("%@%@"), separator
, peer
); 
 631             separator 
= CFSTR(","); 
 636     CFStringAppend(description
, CFSTR("], R:[")); 
 637     separator 
= CFSTR(""); 
 638     if(CFSetGetCount(c
->rejected_applicants
) == 0) 
 639         CFStringAppendFormat(description
, NULL
, CFSTR("-")); 
 641         CFSetForEach(c
->rejected_applicants
, ^(const void *value
) { 
 642             SOSPeerInfoRef peer 
= (SOSPeerInfoRef
) value
; 
 643             CFStringAppendFormat(description
, NULL
, CFSTR("%@%@"), separator
, peer
); 
 644             separator 
= CFSTR(","); 
 647     CFStringAppend(description
, CFSTR("]>")); 
 651 static CFMutableStringRef 
descriptionWithFormatOptions(CFTypeRef aObj
, CFDictionaryRef formatOptions
){ 
 652     SOSCircleRef c 
= (SOSCircleRef
) aObj
; 
 654     CFMutableStringRef description 
= CFStringCreateMutable(kCFAllocatorDefault
, 0); 
 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
)) { 
 666                 SecKeyRef pub_key 
= SOSPeerInfoCopyPubKey(peer
); 
 667                 CFDataRef signature 
= SOSCircleGetSignature(c
, pub_key
, NULL
); 
 668                 sig 
= (signature 
== NULL
) ? CFSTR("-") : CFSTR("?"); 
 669                 CFReleaseNull(pub_key
); 
 672             CFStringAppendFormat(description
, formatOptions
, CFSTR("%@%@ %@"), separator
, peer
, sig
); 
 673             separator 
= CFSTR("\n\t\t"); 
 675         CFStringAppend(description
, CFSTR("\n\t\t<A:[")); 
 676         separator 
= CFSTR(""); 
 679         if(CFSetGetCount(c
->applicants
) == 0 ) 
 680             CFStringAppendFormat(description
, NULL
, CFSTR("-")); 
 683             SOSCircleForEachApplicant(c
, ^(SOSPeerInfoRef peer
) { 
 684                 CFStringAppendFormat(description
, formatOptions
, CFSTR("%@A: %@"), separator
, peer
); 
 685                 separator 
= CFSTR("\n\t\t\t"); 
 689         CFStringAppend(description
, CFSTR("]> \n\t\t<R:[")); 
 690         separator 
= CFSTR(""); 
 691         if(CFSetGetCount(c
->rejected_applicants
) == 0) 
 692             CFStringAppendFormat(description
, NULL
, CFSTR("-")); 
 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"); 
 700         CFStringAppend(description
, CFSTR("]>")); 
 704         CFReleaseNull(description
); 
 705         description 
= defaultDescription(aObj
); 
 713 static CFStringRef 
SOSCircleCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOptions
) { 
 714     SOSCircleRef c 
= (SOSCircleRef
) aObj
; 
 715     SOSCircleAssertStable(c
); 
 716     CFMutableStringRef description 
= NULL
; 
 718     if(formatOptions 
!= NULL
){ 
 719         description 
= descriptionWithFormatOptions(aObj
, formatOptions
); 
 722         description 
= defaultDescription(aObj
); 
 727 CFStringRef 
SOSCircleGetName(SOSCircleRef circle
) { 
 729     assert(circle
->name
); 
 733 const char *SOSCircleGetNameC(SOSCircleRef circle
) { 
 734     CFStringRef name 
= SOSCircleGetName(circle
); 
 737     return CFStringToCString(name
); 
 740 SOSGenCountRef 
SOSCircleGetGeneration(SOSCircleRef circle
) { 
 742     assert(circle
->generation
); 
 743     return circle
->generation
; 
 746 void SOSCircleSetGeneration(SOSCircleRef circle
, SOSGenCountRef gencount
) { 
 748     CFReleaseNull(circle
->generation
); 
 749     circle
->generation 
= CFRetainSafe(gencount
); 
 752 int64_t SOSCircleGetGenerationSint(SOSCircleRef circle
) { 
 753     SOSGenCountRef gen 
= SOSCircleGetGeneration(circle
); 
 754     return SOSGetGenerationSint(gen
); 
 757 void SOSCircleGenerationSetValue(SOSCircleRef circle
, int64_t value
) { 
 758     CFAssignRetained(circle
->generation
, SOSGenerationCreateWithValue(value
)); 
 761 void SOSCircleGenerationIncrement(SOSCircleRef circle
) { 
 762     SOSGenCountRef old 
= circle
->generation
; 
 763     circle
->generation 
= SOSGenerationIncrementAndCreate(old
); 
 767 int SOSCircleCountPeers(SOSCircleRef circle
) { 
 768     SOSCircleAssertStable(circle
); 
 769     __block 
int count 
= 0; 
 770     SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) { 
 776 int SOSCircleCountActivePeers(SOSCircleRef circle
) { 
 777     SOSCircleAssertStable(circle
); 
 778     __block 
int count 
= 0; 
 779     SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) { 
 785 int SOSCircleCountActiveValidPeers(SOSCircleRef circle
, SecKeyRef pubkey
) { 
 786     SOSCircleAssertStable(circle
); 
 787     __block 
int count 
= 0; 
 788     SOSCircleForEachActiveValidPeer(circle
, pubkey
, ^(SOSPeerInfoRef peer
) { 
 794 int SOSCircleCountRetiredPeers(SOSCircleRef circle
) { 
 795     SOSCircleAssertStable(circle
); 
 796     __block 
int count 
= 0; 
 797     SOSCircleForEachRetiredPeer(circle
, ^(SOSPeerInfoRef peer
) { 
 803 int SOSCircleCountApplicants(SOSCircleRef circle
) { 
 804     SOSCircleAssertStable(circle
); 
 806     return (int)CFSetGetCount(circle
->applicants
); 
 809 bool SOSCircleHasApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef 
*error
) { 
 810     SOSCircleAssertStable(circle
); 
 812     return CFSetContainsValue(circle
->applicants
, peerInfo
); 
 815 CFMutableSetRef 
SOSCircleCopyApplicants(SOSCircleRef circle
, CFAllocatorRef allocator
) { 
 816     SOSCircleAssertStable(circle
); 
 818     return CFSetCreateMutableCopy(allocator
, 0, circle
->applicants
); 
 821 int SOSCircleCountRejectedApplicants(SOSCircleRef circle
) { 
 822     SOSCircleAssertStable(circle
); 
 824     return (int)CFSetGetCount(circle
->rejected_applicants
); 
 827 bool SOSCircleHasRejectedApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef 
*error
) { 
 828     SOSCircleAssertStable(circle
); 
 829     return CFSetContainsValue(circle
->rejected_applicants
, peerInfo
); 
 832 SOSPeerInfoRef 
SOSCircleCopyRejectedApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef 
*error
) { 
 833     SOSCircleAssertStable(circle
); 
 834     return CFRetainSafe((SOSPeerInfoRef
)CFSetGetValue(circle
->rejected_applicants
, peerInfo
)); 
 837 CFMutableArrayRef 
SOSCircleCopyRejectedApplicants(SOSCircleRef circle
, CFAllocatorRef allocator
) { 
 838     SOSCircleAssertStable(circle
); 
 840     return CFSetCopyValuesCFArray(circle
->rejected_applicants
); 
 843 bool SOSCircleHasPeerWithID(SOSCircleRef circle
, CFStringRef peerid
, CFErrorRef 
*error
) { 
 844     SOSCircleAssertStable(circle
); 
 845     __block 
bool found 
= false; 
 846     SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) { 
 847         if(peerid 
&& peer 
&& CFEqualSafe(peerid
, SOSPeerInfoGetPeerID(peer
))) found 
= true; 
 852 SOSPeerInfoRef 
SOSCircleCopyPeerWithID(SOSCircleRef circle
, CFStringRef peerid
, CFErrorRef 
*error
) { 
 853     SOSCircleAssertStable(circle
); 
 854     __block SOSPeerInfoRef found 
= NULL
; 
 855     SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) { 
 856         if(peerid 
&& peer 
&& CFEqualSafe(peerid
, SOSPeerInfoGetPeerID(peer
))) found 
= peer
; 
 858     return found 
? SOSPeerInfoCreateCopy(kCFAllocatorDefault
, found
, NULL
) : NULL
; 
 861 bool SOSCircleHasPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef 
*error
) { 
 862     if(!peerInfo
) return false; 
 863     return SOSCircleHasPeerWithID(circle
, SOSPeerInfoGetPeerID(peerInfo
), error
); 
 866 bool SOSCircleHasActivePeerWithID(SOSCircleRef circle
, CFStringRef peerid
, CFErrorRef 
*error
) { 
 867     SOSCircleAssertStable(circle
); 
 868     __block 
bool found 
= false; 
 869     SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) { 
 870         if(peerid 
&& peer 
&& CFEqualSafe(peerid
, SOSPeerInfoGetPeerID(peer
))) found 
= true; 
 875 bool SOSCircleHasActivePeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef 
*error
) { 
 876     if(!peerInfo
) return false; 
 877     return SOSCircleHasActivePeerWithID(circle
, SOSPeerInfoGetPeerID(peerInfo
), error
); 
 880 bool SOSCircleHasActiveValidPeerWithID(SOSCircleRef circle
, CFStringRef peerid
, SecKeyRef user_public_key
, CFErrorRef 
*error
) { 
 881     SOSCircleAssertStable(circle
); 
 882     __block 
bool found 
= false; 
 883     SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) { 
 884         if(peerid 
&& peer 
&& CFEqualSafe(peerid
, SOSPeerInfoGetPeerID(peer
)) && SOSPeerInfoApplicationVerify(peer
, user_public_key
, NULL
)) found 
= true; 
 889 bool SOSCircleHasActiveValidPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, SecKeyRef user_public_key
, CFErrorRef 
*error
) { 
 890     if(!peerInfo
) return false; 
 891     return SOSCircleHasActiveValidPeerWithID(circle
, SOSPeerInfoGetPeerID(peerInfo
), user_public_key
, error
); 
 895 bool SOSCircleResetToEmpty(SOSCircleRef circle
, CFErrorRef 
*error
) { 
 896     CFSetRemoveAllValues(circle
->applicants
); 
 897     CFSetRemoveAllValues(circle
->rejected_applicants
); 
 898     CFSetRemoveAllValues(circle
->peers
); 
 899     CFDictionaryRemoveAllValues(circle
->signatures
); 
 900     SOSGenCountRef oldGen 
= SOSCircleGetGeneration(circle
); 
 901     SOSGenCountRef newGen 
= SOSGenerationCreateWithBaseline(oldGen
); 
 902     SOSCircleSetGeneration(circle
, newGen
); 
 906 bool SOSCircleResetToOffering(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFErrorRef 
*error
){ 
 908     return SOSCircleResetToEmpty(circle
, error
) 
 909         && SOSCircleRequestAdmission(circle
, user_privkey
, requestor
, error
) 
 910         && SOSCircleAcceptRequest(circle
, user_privkey
, requestor
, SOSFullPeerInfoGetPeerInfo(requestor
), error
); 
 913 bool SOSCircleRemoveRetired(SOSCircleRef circle
, CFErrorRef 
*error
) { 
 914     CFSetRemoveAllPassing(circle
->peers
,  ^ bool (const void *element
) { 
 915         SOSPeerInfoRef peer 
= (SOSPeerInfoRef
) element
; 
 917         return SOSPeerInfoIsRetirementTicket(peer
); 
 923 static bool SOSCircleRecordAdmissionRequest(SOSCircleRef circle
, SecKeyRef user_pubkey
, SOSPeerInfoRef requestorPeerInfo
, CFErrorRef 
*error
) { 
 924     SOSCircleAssertStable(circle
); 
 926     bool isPeer 
= SOSCircleHasPeer(circle
, requestorPeerInfo
, error
); 
 928     require_action_quiet(!isPeer
, fail
, SOSCreateError(kSOSErrorAlreadyPeer
, CFSTR("Cannot request admission when already a peer"), NULL
, error
)); 
 930     CFSetTransferObject(requestorPeerInfo
, circle
->rejected_applicants
, circle
->applicants
); 
 939 bool SOSCircleRequestReadmission(SOSCircleRef circle
, SecKeyRef user_pubkey
, SOSPeerInfoRef peer
, CFErrorRef 
*error
) { 
 940     bool success 
= false; 
 942     require_quiet(SOSPeerInfoApplicationVerify(peer
, user_pubkey
, error
), fail
); 
 943     success 
= SOSCircleRecordAdmissionRequest(circle
, user_pubkey
, peer
, error
); 
 948 bool SOSCircleRequestAdmission(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFErrorRef 
*error
) { 
 949     bool success 
= false; 
 951     SecKeyRef user_pubkey 
= SecKeyCreatePublicFromPrivate(user_privkey
); 
 952     require_action_quiet(user_pubkey
, fail
, SOSCreateError(kSOSErrorBadKey
, CFSTR("No public key for key"), NULL
, error
)); 
 954     require(SOSFullPeerInfoPromoteToApplication(requestor
, user_privkey
, error
), fail
); 
 956     success 
= SOSCircleRecordAdmissionRequest(circle
, user_pubkey
, SOSFullPeerInfoGetPeerInfo(requestor
), error
); 
 958     CFReleaseNull(user_pubkey
); 
 962 static bool sosCircleUpdatePeerInfoSet(CFMutableSetRef theSet
, SOSPeerInfoRef replacement_peer_info
) { 
 963     CFTypeRef old 
= NULL
; 
 964     if(!replacement_peer_info
) return false; 
 965     if(!(old 
= CFSetGetValue(theSet
, replacement_peer_info
))) return false; 
 966     if(CFEqualSafe(old
, replacement_peer_info
)) return false; 
 967     CFSetReplaceValue(theSet
, replacement_peer_info
); 
 971 bool SOSCircleUpdatePeerInfo(SOSCircleRef circle
, SOSPeerInfoRef replacement_peer_info
) { 
 972     if(sosCircleUpdatePeerInfoSet(circle
->peers
, replacement_peer_info
)) return true; 
 973     if(sosCircleUpdatePeerInfoSet(circle
->applicants
, replacement_peer_info
)) return true; 
 974     if(sosCircleUpdatePeerInfoSet(circle
->rejected_applicants
, replacement_peer_info
)) return true; 
 978 static bool SOSCircleRemovePeerInternal(SOSCircleRef circle
, SOSFullPeerInfoRef requestor
, SOSPeerInfoRef peer_to_remove
, CFErrorRef 
*error
) { 
 979     SOSPeerInfoRef requestor_peer_info 
= SOSFullPeerInfoGetPeerInfo(requestor
); 
 981     if (SOSCircleHasPeer(circle
, peer_to_remove
, NULL
)) { 
 982         if (!SOSCircleHasPeer(circle
, requestor_peer_info
, error
)) { 
 983             SOSCreateError(kSOSErrorAlreadyPeer
, CFSTR("Must be peer to remove peer"), NULL
, error
); 
 986         CFSetRemoveValue(circle
->peers
, peer_to_remove
); 
 989     if (SOSCircleHasApplicant(circle
, peer_to_remove
, error
)) { 
 990         return SOSCircleRejectRequest(circle
, requestor
, peer_to_remove
, error
); 
 996 bool SOSCircleRemovePeers(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFSetRef peersToRemove
, CFErrorRef 
*error
) { 
 998     bool success 
= false; 
1000     __block 
bool removed_all 
= true; 
1001     CFSetForEach(peersToRemove
, ^(const void *value
) { 
1002         SOSPeerInfoRef peerInfo 
= asSOSPeerInfo(value
); 
1004             removed_all 
&= SOSCircleRemovePeerInternal(circle
, requestor
, peerInfo
, error
); 
1008     require_quiet(removed_all
, exit
); 
1010     require_quiet(SOSCircleGenerationSign(circle
, user_privkey
, requestor
, error
), exit
); 
1018 bool SOSCircleRemovePeer(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, SOSPeerInfoRef peer_to_remove
, CFErrorRef 
*error
) { 
1019     bool success 
= false; 
1021     require_quiet(SOSCircleRemovePeerInternal(circle
, requestor
, peer_to_remove
, error
), exit
); 
1023     require_quiet(SOSCircleGenerationSign(circle
, user_privkey
, requestor
, error
), exit
); 
1030 bool SOSCircleAcceptRequest(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef device_approver
, SOSPeerInfoRef peerInfo
, CFErrorRef 
*error
) { 
1031     SOSCircleAssertStable(circle
); 
1033     SecKeyRef publicKey 
= NULL
; 
1034     bool result 
= false; 
1036     require_action_quiet(CFSetContainsValue(circle
->applicants
, peerInfo
), fail
, 
1037                          SOSCreateError(kSOSErrorNotApplicant
, CFSTR("Cannot accept non-applicant"), NULL
, error
)); 
1039     publicKey 
= SecKeyCreatePublicFromPrivate(user_privkey
); 
1040     require_quiet(SOSPeerInfoApplicationVerify(peerInfo
, publicKey
, error
), fail
); 
1042     CFSetTransferObject(peerInfo
, circle
->applicants
, circle
->peers
); 
1044     result 
= SOSCircleGenerationSign(circle
, user_privkey
, device_approver
, error
); 
1047     CFReleaseNull(publicKey
); 
1051 bool SOSCircleWithdrawRequest(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef 
*error
) { 
1052     SOSCircleAssertStable(circle
); 
1054     CFSetRemoveValue(circle
->applicants
, peerInfo
); 
1059 bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef 
*error
) { 
1060     SOSCircleAssertStable(circle
); 
1062     CFSetRemoveValue(circle
->rejected_applicants
, peerInfo
); 
1068 bool SOSCircleRejectRequest(SOSCircleRef circle
, SOSFullPeerInfoRef device_rejector
, 
1069                             SOSPeerInfoRef peerInfo
, CFErrorRef 
*error
) { 
1070     SOSCircleAssertStable(circle
); 
1072     if (CFEqual(SOSPeerInfoGetPeerID(peerInfo
), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector
)))) 
1073         return SOSCircleWithdrawRequest(circle
, peerInfo
, error
); 
1075     if (!CFSetContainsValue(circle
->applicants
, peerInfo
)) { 
1076         SOSCreateError(kSOSErrorNotApplicant
, CFSTR("Cannot reject non-applicant"), NULL
, error
); 
1080     CFSetTransferObject(peerInfo
, circle
->applicants
, circle
->rejected_applicants
); 
1082     // TODO: Maybe we sign the rejection with device_rejector. 
1087 bool SOSCircleAcceptRequests(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef device_approver
, 
1088                              CFErrorRef 
*error
) { 
1089     // Returns true if we accepted someone and therefore have to post the circle back to KVS 
1090     __block 
bool result 
= false; 
1092     SOSCircleForEachApplicant(circle
, ^(SOSPeerInfoRef peer
) { 
1093         if (!SOSCircleAcceptRequest(circle
, user_privkey
, device_approver
, peer
, error
)) { 
1094             secnotice("circle", "error in SOSCircleAcceptRequest\n"); 
1096             secnotice("circle", "Accepted peer: %@", peer
); 
1102         SOSCircleGenerationSign(circle
, user_privkey
, device_approver
, error
); 
1103         secnotice("circle", "Countersigned accepted requests"); 
1109 bool SOSCirclePeerSigUpdate(SOSCircleRef circle
, SecKeyRef userPrivKey
, SOSFullPeerInfoRef fpi
, 
1110                              CFErrorRef 
*error
) { 
1111     // Returns true if we accepted someone and therefore have to post the circle back to KVS 
1112     __block 
bool result 
= false; 
1113     SecKeyRef userPubKey 
= SecKeyCreatePublicFromPrivate(userPrivKey
); 
1115     // We're going to remove any applicants using a mismatched user key. 
1116     SOSCircleForEachApplicant(circle
, ^(SOSPeerInfoRef peer
) { 
1117         if(!SOSPeerInfoApplicationVerify(peer
, userPubKey
, NULL
)) { 
1118             if(!SOSCircleRejectRequest(circle
, fpi
, peer
, NULL
)) { 
1124     result 
= SOSCircleUpdatePeerInfo(circle
, SOSFullPeerInfoGetPeerInfo(fpi
)); 
1127         SOSCircleGenerationSign(circle
, userPrivKey
, fpi
, error
); 
1128         secnotice("circle", "Generation signed updated signatures on peerinfo"); 
1134 static inline void SOSCircleForEachPeerMatching(SOSCircleRef circle
, 
1135                                                 void (^action
)(SOSPeerInfoRef peer
), 
1136                                                 bool (^condition
)(SOSPeerInfoRef peer
)) { 
1137     CFSetForEach(circle
->peers
, ^(const void *value
) { 
1138         SOSPeerInfoRef peer 
= (SOSPeerInfoRef
) value
; 
1139         if (condition(peer
)) 
1144 static inline bool isHiddenPeer(SOSPeerInfoRef peer
) { 
1145     return SOSPeerInfoIsRetirementTicket(peer
) || SOSPeerInfoIsCloudIdentity(peer
); 
1148 void SOSCircleForEachPeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) { 
1149     SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) { 
1150         return !isHiddenPeer(peer
); 
1154 void SOSCircleForEachRetiredPeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) { 
1155     SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) { 
1156         return SOSPeerInfoIsRetirementTicket(peer
); 
1160 void SOSCircleForEachActivePeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) { 
1161     SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) { 
1166 void SOSCircleForEachActiveValidPeer(SOSCircleRef circle
, SecKeyRef user_public_key
, void (^action
)(SOSPeerInfoRef peer
)) { 
1167     SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) { 
1168         return SOSPeerInfoApplicationVerify(peer
, user_public_key
, NULL
); 
1172 void SOSCircleForEachValidPeer(SOSCircleRef circle
, SecKeyRef user_public_key
, void (^action
)(SOSPeerInfoRef peer
)) { 
1173     SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) { 
1174         return !isHiddenPeer(peer
) && SOSPeerInfoApplicationVerify(peer
, user_public_key
, NULL
); 
1178 void SOSCircleForEachApplicant(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) { 
1179     CFSetForEach(circle
->applicants
, ^(const void*value
) { action((SOSPeerInfoRef
) value
); } ); 
1183 CFMutableSetRef 
SOSCircleCopyPeers(SOSCircleRef circle
, CFAllocatorRef allocator
) { 
1184     SOSCircleAssertStable(circle
); 
1186     CFMutableSetRef result 
= CFSetCreateMutableForSOSPeerInfosByID(allocator
); 
1188     SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) { 
1189         CFSetAddValue(result
, peer
); 
1195 bool SOSCircleAppendConcurringPeers(SOSCircleRef circle
, CFMutableArrayRef appendHere
, CFErrorRef 
*error
) { 
1196     SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) { 
1197         CFErrorRef localError 
= NULL
; 
1198         if (SOSCircleVerifyPeerSigned(circle
, peer
, &localError
)) { 
1199             SOSPeerInfoRef peerInfo 
= SOSPeerInfoCreateCopy(kCFAllocatorDefault
, peer
, error
); 
1200             CFArrayAppendValue(appendHere
, peerInfo
); 
1201             CFRelease(peerInfo
); 
1202         } else if (error 
!= NULL
) { 
1203             secerror("Error checking concurrence: %@", localError
); 
1205         CFReleaseNull(localError
); 
1211 CFMutableArrayRef 
SOSCircleCopyConcurringPeers(SOSCircleRef circle
, CFErrorRef
* error
) { 
1212     SOSCircleAssertStable(circle
); 
1214     CFMutableArrayRef concurringPeers 
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
); 
1216     if (!SOSCircleAppendConcurringPeers(circle
, concurringPeers
, error
)) 
1217         CFReleaseNull(concurringPeers
); 
1219     return concurringPeers
; 
1222 SOSFullPeerInfoRef 
SOSCircleCopyiCloudFullPeerInfoRef(SOSCircleRef circle
, CFErrorRef 
*error
) { 
1223     __block SOSFullPeerInfoRef cloud_full_peer 
= NULL
; 
1224     __block CFErrorRef searchError 
= NULL
; 
1225     SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) { 
1226         if (SOSPeerInfoIsCloudIdentity(peer
)) { 
1227             if (cloud_full_peer 
== NULL
) { 
1229                     secerror("More than one cloud identity found, first had error, trying new one."); 
1231                 CFReleaseNull(searchError
); 
1232                 cloud_full_peer 
= SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault
, peer
, &searchError
); 
1233                 if (!cloud_full_peer
) { 
1234                     secnotice("icloud-identity", "Failed to make FullPeer for iCloud Identity: %@ (%@)", cloud_full_peer
, searchError
); 
1237                 secerror("Additional cloud identity found in circle after successful creation: %@", circle
); 
1241     // If we didn't find one at all, report the error. 
1242     if (cloud_full_peer 
== NULL 
&& searchError 
== NULL
) { 
1243         SOSErrorCreate(kSOSErrorNoiCloudPeer
, &searchError
, NULL
, CFSTR("No iCloud identity PeerInfo found in circle")); 
1244         secnotice("icloud-identity", "No iCloud identity PeerInfo found in circle"); 
1247         CFTransferRetained(*error
, searchError
); 
1249     CFReleaseNull(searchError
); 
1250     return cloud_full_peer
; 
1253 void debugDumpCircle(CFStringRef message
, SOSCircleRef circle
) { 
1256     secinfo("circledebug", "%@: %@", message
, circle
); 
1260     CFDataRef derdata 
= SOSCircleCopyEncodedData(circle
, kCFAllocatorDefault
, &error
); 
1262         CFStringRef hex 
= CFDataCopyHexString(derdata
); 
1263         secinfo("circledebug", "Full contents: %@", hex
); 
1264         if (hex
) CFRelease(hex
);