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/SOSEnginePriv.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>
46 #include <utilities/SecBuffer.h>
48 #include <utilities/SecCFWrappers.h>
49 #include <utilities/SecCFError.h>
51 #include <Security/SecureObjectSync/SOSCirclePriv.h>
53 //#include "ckdUtilities.h"
55 #include <corecrypto/ccder.h>
56 #include <corecrypto/ccdigest.h>
57 #include <corecrypto/ccsha2.h>
62 CFGiblisWithCompareFor(SOSCircle
);
64 SOSCircleRef
SOSCircleCreate(CFAllocatorRef allocator
, CFStringRef name
, CFErrorRef
*error
) {
65 SOSCircleRef c
= CFTypeAllocate(SOSCircle
, struct __OpaqueSOSCircle
, allocator
);
68 c
->name
= CFStringCreateCopy(allocator
, name
);
69 c
->generation
= SOSGenerationCreate();
70 c
->peers
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
71 c
->applicants
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
72 c
->rejected_applicants
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
73 c
->signatures
= CFDictionaryCreateMutableForCFTypes(allocator
);
77 static CFMutableSetRef
CFSetOfPeerInfoDeepCopy(CFAllocatorRef allocator
, CFSetRef peerInfoSet
)
79 __block CFMutableSetRef result
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
80 CFSetForEach(peerInfoSet
, ^(const void *value
) {
81 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
82 CFErrorRef localError
= NULL
;
83 SOSPeerInfoRef copiedPeer
= SOSPeerInfoCreateCopy(allocator
, pi
, &localError
);
85 CFSetAddValue(result
, copiedPeer
);
87 secerror("Failed to copy peer: %@ (%@)", pi
, localError
);
89 CFReleaseSafe(copiedPeer
);
90 CFReleaseSafe(localError
);
95 SOSCircleRef
SOSCircleCopyCircle(CFAllocatorRef allocator
, SOSCircleRef otherCircle
, CFErrorRef
*error
)
97 SOSCircleRef c
= CFTypeAllocate(SOSCircle
, struct __OpaqueSOSCircle
, allocator
);
100 c
->name
= CFStringCreateCopy(allocator
, otherCircle
->name
);
101 c
->generation
= SOSGenerationCopy(otherCircle
->generation
);
103 c
->peers
= CFSetOfPeerInfoDeepCopy(allocator
, otherCircle
->peers
);
104 c
->applicants
= CFSetOfPeerInfoDeepCopy(allocator
, otherCircle
->applicants
);
105 c
->rejected_applicants
= CFSetOfPeerInfoDeepCopy(allocator
, otherCircle
->rejected_applicants
);
107 c
->signatures
= CFDictionaryCreateMutableCopy(allocator
, 0, otherCircle
->signatures
);
112 static Boolean
SOSCircleCompare(CFTypeRef lhs
, CFTypeRef rhs
) {
113 if (CFGetTypeID(lhs
) != SOSCircleGetTypeID()
114 || CFGetTypeID(rhs
) != SOSCircleGetTypeID())
117 SOSCircleRef left
= SOSCircleConvertAndAssertStable(lhs
);
118 SOSCircleRef right
= SOSCircleConvertAndAssertStable(rhs
);
120 // TODO: we should be doing set equality for peers and applicants.
121 return NULL
!= left
&& NULL
!= right
122 && CFEqualSafe(left
->generation
, right
->generation
)
123 && SOSPeerInfoSetContainsIdenticalPeers(left
->peers
, right
->peers
)
124 && SOSPeerInfoSetContainsIdenticalPeers(left
->applicants
, right
->applicants
)
125 && SOSPeerInfoSetContainsIdenticalPeers(left
->rejected_applicants
, right
->rejected_applicants
)
126 && CFEqualSafe(left
->signatures
, right
->signatures
);
129 static CFMutableArrayRef
CFSetCopyValuesCFArray(CFSetRef set
)
131 CFIndex count
= CFSetGetCount(set
);
133 CFMutableArrayRef result
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
135 const void * values
[count
];
136 CFSetGetValues(set
, values
);
137 for (int current
= 0; current
< count
; ++current
) {
138 CFArrayAppendValue(result
, values
[current
]);
145 static bool SOSCircleDigestArray(const struct ccdigest_info
*di
, CFMutableArrayRef array
, void *hash_result
, CFErrorRef
*error
)
147 __block
bool success
= true;
148 ccdigest_di_decl(di
, array_digest
);
149 void * a_digest
= (void * )array_digest
;
151 ccdigest_init(di
, array_digest
);
152 CFArraySortValues(array
, CFRangeMake(0, CFArrayGetCount(array
)), SOSPeerInfoCompareByID
, SOSPeerCmpPubKeyHash
);
153 CFArrayForEach(array
, ^(const void *peer
) {
154 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes((SOSPeerInfoRef
)peer
, di
, a_digest
, error
))
157 ccdigest_final(di
, array_digest
, hash_result
);
162 static bool SOSCircleDigestSet(const struct ccdigest_info
*di
, CFMutableSetRef set
, void *hash_result
, CFErrorRef
*error
)
164 CFMutableArrayRef values
= CFSetCopyValuesCFArray(set
);
166 bool result
= SOSCircleDigestArray(di
, values
, hash_result
, error
);
168 CFReleaseSafe(values
);
173 static bool SOSCircleHashGenAndPeers(const struct ccdigest_info
*di
, SOSGenCountRef gen
, CFMutableSetRef peers
, void*hash_result
, CFErrorRef
*error
) {
174 ccdigest_di_decl(di
, circle_digest
);
175 ccdigest_init(di
, circle_digest
);
176 int64_t generation
= SOSGetGenerationSint(gen
);
177 ccdigest_update(di
, circle_digest
, sizeof(generation
), &generation
);
179 SOSCircleDigestSet(di
, peers
, hash_result
, error
);
180 ccdigest_update(di
, circle_digest
, di
->output_size
, hash_result
);
181 ccdigest_final(di
, circle_digest
, hash_result
);
185 static bool SOSCircleHash(const struct ccdigest_info
*di
, SOSCircleRef circle
, void *hash_result
, CFErrorRef
*error
) {
186 return SOSCircleHashGenAndPeers(di
, SOSCircleGetGeneration(circle
), circle
->peers
, hash_result
, error
);
189 static bool SOSCircleHashNextGenWithAdditionalPeer(const struct ccdigest_info
*di
, SOSCircleRef circle
, SOSPeerInfoRef additionalPeer
, void *hash_result
, CFErrorRef
*error
) {
190 CFMutableSetRef peers
= CFSetCreateMutableCopy(NULL
, 0, circle
->peers
);
191 CFSetAddValue(peers
, additionalPeer
);
193 SOSGenCountRef nextGen
= SOSGenerationIncrementAndCreate(circle
->generation
);
195 return SOSCircleHashGenAndPeers(di
, nextGen
, peers
, hash_result
, error
);
198 bool SOSCircleSetSignature(SOSCircleRef circle
, SecKeyRef pubkey
, CFDataRef signature
, CFErrorRef
*error
) {
201 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubkey
, error
);
202 require_quiet(pubKeyID
, fail
);
203 CFDictionarySetValue(circle
->signatures
, pubKeyID
, signature
);
207 CFReleaseSafe(pubKeyID
);
211 static bool SOSCircleRemoveSignatures(SOSCircleRef circle
, CFErrorRef
*error
) {
212 CFDictionaryRemoveAllValues(circle
->signatures
);
216 CFDataRef
SOSCircleGetSignature(SOSCircleRef circle
, SecKeyRef pubkey
, CFErrorRef
*error
) {
217 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubkey
, error
);
218 CFDataRef result
= NULL
;
219 require_quiet(pubKeyID
, fail
);
221 CFTypeRef value
= (CFDataRef
)CFDictionaryGetValue(circle
->signatures
, pubKeyID
);
223 if (isData(value
)) result
= (CFDataRef
) value
;
226 CFReleaseSafe(pubKeyID
);
230 CFDictionaryRef
SOSCircleCopyAllSignatures(SOSCircleRef circle
) {
231 return CFDictionaryCreateCopy(kCFAllocatorDefault
, circle
->signatures
);
234 #define circle_signature_di() ccsha256_di()
236 static CFDataRef
SecKeyCopyRawHashSignature(const struct ccdigest_info
*di
, const uint8_t* hashToSign
, SecKeyRef privKey
, CFErrorRef
*error
) {
237 CFDataRef result
= NULL
;
239 CFMutableDataRef signature
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, SecKeyGetSize(privKey
, kSecKeySignatureSize
));
240 size_t signatureSpace
= CFDataGetLength(signature
);
242 OSStatus status
= SecKeyRawSign(privKey
, kSecPaddingNone
, hashToSign
, di
->output_size
, CFDataGetMutableBytePtr(signature
), &signatureSpace
);
243 require_quiet(SecError(status
, error
, CFSTR("Signing failed: %d"), (int)status
), fail
);
245 if (signatureSpace
< (size_t)CFDataGetLength(signature
)) {
246 CFDataSetLength(signature
, signatureSpace
);
249 CFTransferRetained(result
, signature
);
251 CFReleaseNull(signature
);
255 bool SOSCircleSign(SOSCircleRef circle
, SecKeyRef privKey
, CFErrorRef
*error
) {
256 const struct ccdigest_info
*di
= circle_signature_di();
258 __block CFDataRef signature
= NULL
;
259 bool didSign
= false;
260 require_quiet(privKey
, fail
);
262 PerformWithBuffer(di
->output_size
, ^(size_t size
, uint8_t *hash_result
) {
263 if (SOSCircleHash(di
, circle
, hash_result
, error
)) {
264 signature
= SecKeyCopyRawHashSignature(di
, hash_result
, privKey
, error
);
267 require_quiet(signature
, fail
);
268 require_quiet(SOSCircleSetSignature(circle
, privKey
, signature
, error
), fail
);
273 CFReleaseNull(signature
);
277 CFDataRef
SOSCircleCopyNextGenSignatureWithPeerAdded(SOSCircleRef circle
, SOSPeerInfoRef peer
, SecKeyRef privKey
, CFErrorRef
*error
) {
278 const struct ccdigest_info
*di
= circle_signature_di();
280 __block CFDataRef signature
= NULL
;
281 require_quiet(privKey
, fail
);
283 PerformWithBuffer(di
->output_size
, ^(size_t size
, uint8_t *hash_result
) {
284 if (SOSCircleHashNextGenWithAdditionalPeer(di
, circle
, peer
, hash_result
, error
)) {
285 signature
= SecKeyCopyRawHashSignature(di
, hash_result
, privKey
, error
);
294 static bool SOSCircleConcordanceRingSign(SOSCircleRef circle
, SecKeyRef privKey
, CFErrorRef
*error
) {
295 secnotice("Development", "SOSCircleEnsureRingConsistency requires ring signing op", NULL
);
300 bool SOSCircleVerifySignatureExists(SOSCircleRef circle
, SecKeyRef pubKey
, CFErrorRef
*error
) {
303 secerror("SOSCircleVerifySignatureExists no pubKey");
304 SOSCreateError(kSOSErrorBadFormat
, CFSTR("SOSCircleVerifySignatureExists no pubKey"), (error
!= NULL
) ? *error
: NULL
, error
);
307 CFDataRef signature
= SOSCircleGetSignature(circle
, pubKey
, error
);
308 return NULL
!= signature
;
311 bool SOSCircleVerify(SOSCircleRef circle
, SecKeyRef pubKey
, CFErrorRef
*error
) {
312 const struct ccdigest_info
*di
= ccsha256_di();
313 uint8_t hash_result
[di
->output_size
];
315 SOSCircleHash(di
, circle
, hash_result
, error
);
317 CFDataRef signature
= SOSCircleGetSignature(circle
, pubKey
, error
);
318 if(!signature
) return false;
320 return SecError(SecKeyRawVerify(pubKey
, kSecPaddingNone
, hash_result
, di
->output_size
,
321 CFDataGetBytePtr(signature
), CFDataGetLength(signature
)), error
, CFSTR("Signature verification failed."));;
324 bool SOSCircleVerifyPeerSigned(SOSCircleRef circle
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
326 SecKeyRef pub_key
= SOSPeerInfoCopyPubKey(peer
, error
);
327 require_quiet(pub_key
, fail
);
329 result
= SOSCircleVerify(circle
, pub_key
, error
);
331 CFReleaseSafe(pub_key
);
335 static void CFSetRemoveAllPassing(CFMutableSetRef set
, bool (^test
)(const void *) ){
336 CFMutableArrayRef toBeRemoved
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
338 CFSetForEach(set
, ^(const void *value
) {
340 CFArrayAppendValue(toBeRemoved
, value
);
343 CFArrayForEach(toBeRemoved
, ^(const void *value
) {
344 CFSetRemoveValue(set
, value
);
346 CFReleaseNull(toBeRemoved
);
349 static void SOSCircleRejectNonValidApplicants(SOSCircleRef circle
, SecKeyRef pubkey
) {
350 CFMutableSetRef applicants
= SOSCircleCopyApplicants(circle
, NULL
);
351 CFSetForEach(applicants
, ^(const void *value
) {
352 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
353 if(!SOSPeerInfoApplicationVerify(pi
, pubkey
, NULL
)) {
354 CFSetTransferObject(pi
, circle
->applicants
, circle
->rejected_applicants
);
357 CFReleaseNull(applicants
);
360 static SOSPeerInfoRef
SOSCircleCopyPeerInfo(SOSCircleRef circle
, CFStringRef peer_id
, CFErrorRef
*error
) {
361 __block SOSPeerInfoRef result
= NULL
;
363 CFSetForEach(circle
->peers
, ^(const void *value
) {
364 if (result
== NULL
) {
365 SOSPeerInfoRef tpi
= (SOSPeerInfoRef
)value
;
366 if (CFEqual(SOSPeerInfoGetPeerID(tpi
), peer_id
))
371 CFRetainSafe(result
);
375 static bool SOSCircleUpgradePeerInfo(SOSCircleRef circle
, SecKeyRef user_approver
, SOSFullPeerInfoRef peerinfo
) {
377 SecKeyRef userPubKey
= SecKeyCreatePublicFromPrivate(user_approver
);
378 SOSPeerInfoRef fpi_pi
= SOSFullPeerInfoGetPeerInfo(peerinfo
);
379 SOSPeerInfoRef pi
= SOSCircleCopyPeerInfo(circle
, SOSPeerInfoGetPeerID(fpi_pi
), NULL
);
380 require_quiet(pi
, out
);
381 require_quiet(SOSPeerInfoApplicationVerify(pi
, userPubKey
, NULL
), re_sign
);
382 CFReleaseNull(userPubKey
);
387 secnotice("circle", "SOSCircleGenerationSign: Upgraded peer's Application Signature");
388 SecKeyRef device_key
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, NULL
);
389 require_quiet(device_key
, out
);
390 SOSPeerInfoRef new_pi
= SOSPeerInfoCopyAsApplication(pi
, user_approver
, device_key
, NULL
);
391 if(SOSCircleUpdatePeerInfo(circle
, new_pi
))
393 CFReleaseNull(new_pi
);
394 CFReleaseNull(device_key
);
396 CFReleaseNull(userPubKey
);
401 static bool SOSCircleEnsureRingConsistency(SOSCircleRef circle
, CFErrorRef
*error
) {
402 secnotice("Development", "SOSCircleEnsureRingConsistency requires ring membership and generation count consistency check", NULL
);
406 bool SOSCircleSignOldStyleResetToOfferingCircle(SOSCircleRef circle
, SOSFullPeerInfoRef peerinfo
, SecKeyRef user_approver
, CFErrorRef
*error
){
408 SecKeyRef ourKey
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, error
);
409 SecKeyRef publicKey
= NULL
;
410 require_quiet(ourKey
, fail
);
412 // Check if we're using an invalid peerinfo for this op. There are cases where we might not be "upgraded".
413 require_quiet(SOSCircleUpgradePeerInfo(circle
, user_approver
, peerinfo
), fail
);
414 SOSCircleRemoveRetired(circle
, error
); // Prune off retirees since we're signing this one
415 CFSetRemoveAllValues(circle
->rejected_applicants
); // Dump rejects so we clean them up sometime.
416 publicKey
= SecKeyCreatePublicFromPrivate(user_approver
);
417 SOSCircleRejectNonValidApplicants(circle
, publicKey
);
418 require_quiet(SOSCircleEnsureRingConsistency(circle
, error
), fail
);
419 require_quiet(SOSCircleRemoveSignatures(circle
, error
), fail
);
420 require_quiet(SOSCircleSign(circle
, user_approver
, error
), fail
);
421 require_quiet(SOSCircleSign(circle
, ourKey
, error
), fail
);
423 CFReleaseNull(ourKey
);
424 CFReleaseNull(publicKey
);
428 CFReleaseNull(ourKey
);
429 CFReleaseNull(publicKey
);
433 bool SOSCirclePreGenerationSign(SOSCircleRef circle
, SecKeyRef userPubKey
, CFErrorRef
*error
) {
436 SOSCircleRemoveRetired(circle
, error
); // Prune off retirees since we're signing this one
437 CFSetRemoveAllValues(circle
->rejected_applicants
); // Dump rejects so we clean them up sometime.
438 SOSCircleRejectNonValidApplicants(circle
, userPubKey
);
440 require_quiet(SOSCircleRemoveSignatures(circle
, error
), errOut
);
449 static bool SOSCircleGenerationSign_Internal(SOSCircleRef circle
, SecKeyRef userKey
, SOSFullPeerInfoRef fpi
, CFErrorRef
*error
) {
450 // require_quiet(SOSCircleEnsureRingConsistency(circle, error), fail); Placeholder - this was never implemented
452 if (SOSCircleCountPeers(circle
) != 0) {
453 SecKeyRef ourKey
= SOSFullPeerInfoCopyDeviceKey(fpi
, error
);
454 require_quiet(ourKey
, errOut
);
456 // Check if we're using an invalid peerinfo for this op. There are cases where we might not be "upgraded".
457 require_quiet(SOSCircleUpgradePeerInfo(circle
, userKey
, fpi
), errOut
);
459 require_quiet(SOSCircleSign(circle
, userKey
, error
), errOut
);
460 require_quiet(SOSCircleSign(circle
, ourKey
, error
), errOut
);
461 CFReleaseNull(ourKey
);
469 bool SOSCircleGenerationSign(SOSCircleRef circle
, SecKeyRef userKey
, SOSFullPeerInfoRef fpi
, CFErrorRef
*error
) {
471 SecKeyRef publicKey
= NULL
;
472 publicKey
= SecKeyCreatePublicFromPrivate(userKey
);
474 require_quiet(SOSCirclePreGenerationSign(circle
, publicKey
, error
), errOut
);
475 SOSCircleGenerationIncrement(circle
);
476 require_quiet(SOSCircleGenerationSign_Internal(circle
, userKey
, fpi
, error
), errOut
);
480 CFReleaseNull(publicKey
);
485 static bool SOSCircleGenerationSignWithGenCount(SOSCircleRef circle
, SecKeyRef userKey
, SOSFullPeerInfoRef fpi
, SOSGenCountRef gencount
, CFErrorRef
*error
) {
487 SOSGenCountRef currentGen
= SOSCircleGetGeneration(circle
);
488 require_action_quiet(SOSGenerationIsOlder(currentGen
, gencount
), errOut
, SOSCreateError(kSOSErrorReplay
, CFSTR("Generation Count for new circle is too old"), NULL
, error
));
489 require_quiet(SOSCirclePreGenerationSign(circle
, userKey
, error
), errOut
);
490 SOSCircleSetGeneration(circle
, gencount
);
491 require_quiet(SOSCircleGenerationSign_Internal(circle
, userKey
, fpi
, error
), errOut
);
499 bool SOSCircleConcordanceSign(SOSCircleRef circle
, SOSFullPeerInfoRef peerinfo
, CFErrorRef
*error
) {
500 bool success
= false;
501 SecKeyRef ourKey
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, error
);
502 require_quiet(ourKey
, exit
);
504 success
= SOSCircleSign(circle
, ourKey
, error
);
505 SOSCircleConcordanceRingSign(circle
, ourKey
, error
);
508 CFReleaseNull(ourKey
);
512 static inline SOSConcordanceStatus
CheckPeerStatus(SOSCircleRef circle
, SOSPeerInfoRef peer
, SecKeyRef user_public_key
, CFErrorRef
*error
) {
513 SOSConcordanceStatus result
= kSOSConcordanceNoPeer
;
514 SecKeyRef pubKey
= SOSPeerInfoCopyPubKey(peer
, error
);
515 require_quiet(pubKey
, exit
);
517 require_action_quiet(SOSCircleHasActiveValidPeer(circle
, peer
, user_public_key
, error
), exit
, result
= kSOSConcordanceNoPeer
);
518 require_action_quiet(SOSCircleVerifySignatureExists(circle
, pubKey
, error
), exit
, result
= kSOSConcordanceNoPeerSig
);
519 require_action_quiet(SOSCircleVerify(circle
, pubKey
, error
), exit
, result
= kSOSConcordanceBadPeerSig
);
521 result
= kSOSConcordanceTrusted
;
524 CFReleaseNull(pubKey
);
528 static inline SOSConcordanceStatus
CombineStatus(SOSConcordanceStatus status1
, SOSConcordanceStatus status2
)
530 if (status1
== kSOSConcordanceTrusted
|| status2
== kSOSConcordanceTrusted
)
531 return kSOSConcordanceTrusted
;
533 if (status1
== kSOSConcordanceBadPeerSig
|| status2
== kSOSConcordanceBadPeerSig
)
534 return kSOSConcordanceBadPeerSig
;
536 if (status1
== kSOSConcordanceNoPeerSig
|| status2
== kSOSConcordanceNoPeerSig
)
537 return kSOSConcordanceNoPeerSig
;
542 static inline bool SOSCircleIsEmpty(SOSCircleRef circle
) {
543 return SOSCircleCountPeers(circle
) == 0;
546 static inline bool SOSCircleHasDegenerateGeneration(SOSCircleRef deGenCircle
){
548 CFNumberRef genCountTest
= SOSCircleGetGeneration(deGenCircle
);
549 CFNumberGetValue(genCountTest
, kCFNumberCFIndexType
, &testPtr
);
550 return (testPtr
== 0);
554 static inline bool SOSCircleIsDegenerateReset(SOSCircleRef deGenCircle
){
555 return SOSCircleHasDegenerateGeneration(deGenCircle
) && SOSCircleIsEmpty(deGenCircle
);
559 __unused
static inline bool SOSCircleIsResignOffering(SOSCircleRef circle
, SecKeyRef pubkey
) {
560 return SOSCircleCountActiveValidPeers(circle
, pubkey
) == 1;
563 static inline SOSConcordanceStatus
GetSignersStatus(SOSCircleRef signers_circle
, SOSCircleRef status_circle
,
564 SecKeyRef user_pubKey
, SOSPeerInfoRef exclude
, CFErrorRef
*error
) {
565 CFStringRef excluded_id
= exclude
? SOSPeerInfoGetPeerID(exclude
) : NULL
;
567 __block SOSConcordanceStatus status
= kSOSConcordanceNoPeer
;
568 SOSCircleForEachActivePeer(signers_circle
, ^(SOSPeerInfoRef peer
) {
569 SOSConcordanceStatus peerStatus
= CheckPeerStatus(status_circle
, peer
, user_pubKey
, error
);
571 if (peerStatus
== kSOSConcordanceNoPeerSig
&&
572 (CFEqualSafe(SOSPeerInfoGetPeerID(peer
), excluded_id
) || SOSPeerInfoIsCloudIdentity(peer
)))
573 peerStatus
= kSOSConcordanceNoPeer
;
575 status
= CombineStatus(status
, peerStatus
); // TODO: Use multiple error gathering.
581 // Is current older than proposed?
582 bool SOSCircleIsOlderGeneration(SOSCircleRef older
, SOSCircleRef newer
) {
583 return SOSGenerationIsOlder(older
->generation
, newer
->generation
);
586 static inline bool SOSCircleIsValidReset(SOSCircleRef current
, SOSCircleRef proposed
) {
588 retval
= SOSCircleIsEmpty(proposed
);
589 require_quiet(retval
, errOut
);
590 retval
= SOSCircleIsOlderGeneration(current
, proposed
);
596 bool SOSCircleSharedTrustedPeers(SOSCircleRef current
, SOSCircleRef proposed
, SOSPeerInfoRef me
) {
597 __block
bool retval
= false;
598 SOSCircleForEachPeer(current
, ^(SOSPeerInfoRef peer
) {
599 if(!CFEqual(me
, peer
) && SOSCircleHasPeer(proposed
, peer
, NULL
)) retval
= true;
604 static SOSConcordanceStatus
GetOfferingStatus(SOSCircleRef circle
, SecKeyRef user_pubKey
, CFErrorRef
*error
) {
605 __block SOSConcordanceStatus status
= kSOSConcordanceNoPeer
;
606 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
607 status
= CheckPeerStatus(circle
, peer
, user_pubKey
, error
);
608 if(status
!= kSOSConcordanceTrusted
) status
= kSOSConcordanceNoPeer
;
614 SOSConcordanceStatus
SOSCircleConcordanceTrust(SOSCircleRef known_circle
, SOSCircleRef proposed_circle
,
615 SecKeyRef known_pubkey
, SecKeyRef user_pubkey
,
616 SOSPeerInfoRef me
, CFErrorRef
*error
) {
617 if(user_pubkey
== NULL
) {
618 SOSCreateError(kSOSErrorPublicKeyAbsent
, CFSTR("Concordance with no user public key"), NULL
, error
);
619 return kSOSConcordanceNoUserKey
;
622 if(SOSCircleIsDegenerateReset(proposed_circle
)) {
623 return kSOSConcordanceTrusted
;
626 if (SOSCircleIsValidReset(known_circle
, proposed_circle
)) {
627 return kSOSConcordanceTrusted
;
630 if(!SOSCircleVerifySignatureExists(proposed_circle
, user_pubkey
, error
)) {
631 SOSCreateError(kSOSErrorBadSignature
, CFSTR("No public signature to match current user key"), (error
!= NULL
) ? *error
: NULL
, error
);
632 return kSOSConcordanceNoUserSig
;
635 if(!SOSCircleVerify(proposed_circle
, user_pubkey
, error
)) {
636 SOSCreateError(kSOSErrorBadSignature
, CFSTR("Bad user public signature"), (error
!= NULL
) ? *error
: NULL
, error
);
637 debugDumpCircle(CFSTR("proposed_circle"), proposed_circle
);
638 return kSOSConcordanceBadUserSig
;
641 if (SOSCircleIsEmpty(known_circle
)) {
642 return GetSignersStatus(proposed_circle
, proposed_circle
, user_pubkey
, NULL
, error
);
645 if(SOSCircleHasDegenerateGeneration(proposed_circle
) && SOSCircleIsOffering(proposed_circle
)){
646 return GetSignersStatus(proposed_circle
, proposed_circle
, user_pubkey
, NULL
, error
);
649 if(SOSCircleIsOlderGeneration(proposed_circle
, known_circle
)) {
650 SOSCreateError(kSOSErrorReplay
, CFSTR("Bad generation - proposed circle gencount is older than known circle gencount"), NULL
, error
);
651 debugDumpCircle(CFSTR("isOlderGeneration known_circle"), known_circle
);
652 debugDumpCircle(CFSTR("isOlderGeneration proposed_circle"), proposed_circle
);
653 return kSOSConcordanceGenOld
;
656 if(SOSCircleIsOffering(proposed_circle
)){
657 return GetOfferingStatus(proposed_circle
, user_pubkey
, error
);
660 return GetSignersStatus(known_circle
, proposed_circle
, user_pubkey
, me
, error
);
664 static void SOSCircleDestroy(CFTypeRef aObj
) {
665 SOSCircleRef c
= (SOSCircleRef
) aObj
;
667 CFReleaseNull(c
->name
);
668 CFReleaseNull(c
->generation
);
669 CFReleaseNull(c
->peers
);
670 CFReleaseNull(c
->applicants
);
671 CFReleaseNull(c
->rejected_applicants
);
672 CFReleaseNull(c
->signatures
);
675 static CFMutableStringRef
defaultDescriptionCreate(CFTypeRef aObj
){
676 SOSCircleRef c
= (SOSCircleRef
) aObj
;
677 CFStringRef initPeerSep
= CFSTR("\n");
678 CFStringRef peerSep
= CFSTR("\n");
680 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
682 SOSGenerationCountWithDescription(c
->generation
, ^(CFStringRef genDescription
) {
683 CFStringAppendFormat(description
, NULL
, CFSTR("<SOSCircle@%p: '%@' %@ P:["), c
, c
->name
, genDescription
);
686 __block CFStringRef separator
= initPeerSep
;
687 SOSCircleForEachActivePeer(c
, ^(SOSPeerInfoRef peer
) {
688 CFStringRef sig
= NULL
;
689 if (SOSCircleVerifyPeerSigned(c
, peer
, NULL
)) {
692 SecKeyRef pub_key
= SOSPeerInfoCopyPubKey(peer
, NULL
);
693 CFDataRef signature
= pub_key
? SOSCircleGetSignature(c
, pub_key
, NULL
) : NULL
;
694 sig
= (signature
== NULL
) ? CFSTR("-") : CFSTR("?");
695 CFReleaseNull(pub_key
);
698 CFStringAppendFormat(description
, NULL
, CFSTR("%@%@ %@"), separator
, peer
, sig
);
703 CFStringAppend(description
, CFSTR("], A:["));
704 separator
= initPeerSep
;
705 if(CFSetGetCount(c
->applicants
) == 0 )
706 CFStringAppendFormat(description
, NULL
, CFSTR("-"));
709 SOSCircleForEachApplicant(c
, ^(SOSPeerInfoRef peer
) {
710 CFStringAppendFormat(description
, NULL
, CFSTR("%@%@"), separator
, peer
);
716 CFStringAppend(description
, CFSTR("], R:["));
717 separator
= initPeerSep
;
718 if(CFSetGetCount(c
->rejected_applicants
) == 0)
719 CFStringAppendFormat(description
, NULL
, CFSTR("-"));
721 CFSetForEach(c
->rejected_applicants
, ^(const void *value
) {
722 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) value
;
723 CFStringAppendFormat(description
, NULL
, CFSTR("%@%@"), separator
, peer
);
727 CFStringAppend(description
, CFSTR("]>"));
731 static CFMutableStringRef
descriptionCreateWithFormatOptions(CFTypeRef aObj
, CFDictionaryRef formatOptions
){
732 SOSCircleRef c
= (SOSCircleRef
) aObj
;
734 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
736 if(CFDictionaryContainsKey(formatOptions
, CFSTR("SyncD"))) {
737 CFStringRef generationDescription
= SOSGenerationCountCopyDescription(c
->generation
);
738 CFStringAppendFormat(description
, NULL
, CFSTR("<C: gen:'%@' %@>\n"), generationDescription
, c
->name
);
739 CFReleaseNull(generationDescription
);
740 __block CFStringRef separator
= CFSTR("\t\t");
741 SOSCircleForEachActivePeer(c
, ^(SOSPeerInfoRef peer
) {
742 CFStringRef sig
= NULL
;
743 if (SOSCircleVerifyPeerSigned(c
, peer
, NULL
)) {
746 SecKeyRef pub_key
= SOSPeerInfoCopyPubKey(peer
, NULL
);
747 CFDataRef signature
= pub_key
? SOSCircleGetSignature(c
, pub_key
, NULL
) : NULL
;
748 sig
= (signature
== NULL
) ? CFSTR("-") : CFSTR("?");
749 CFReleaseNull(pub_key
);
752 CFStringAppendFormat(description
, formatOptions
, CFSTR("%@%@ %@"), separator
, peer
, sig
);
753 separator
= CFSTR("\n\t\t");
755 CFStringAppend(description
, CFSTR("\n\t\t<A:["));
756 separator
= CFSTR("");
759 if(CFSetGetCount(c
->applicants
) == 0 )
760 CFStringAppendFormat(description
, NULL
, CFSTR("-"));
763 SOSCircleForEachApplicant(c
, ^(SOSPeerInfoRef peer
) {
764 CFStringAppendFormat(description
, formatOptions
, CFSTR("%@A: %@"), separator
, peer
);
765 separator
= CFSTR("\n\t\t\t");
769 CFStringAppend(description
, CFSTR("]> \n\t\t<R:["));
770 separator
= CFSTR("");
771 if(CFSetGetCount(c
->rejected_applicants
) == 0)
772 CFStringAppendFormat(description
, NULL
, CFSTR("-"));
774 CFSetForEach(c
->rejected_applicants
, ^(const void *value
) {
775 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) value
;
776 CFStringAppendFormat(description
, formatOptions
, CFSTR("%@R: %@"), separator
, peer
);
777 separator
= CFSTR("\n\t\t");
780 CFStringAppend(description
, CFSTR("]>"));
784 CFReleaseNull(description
);
785 description
= defaultDescriptionCreate(aObj
);
793 static CFStringRef
SOSCircleCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOptions
) {
794 SOSCircleRef c
= (SOSCircleRef
) aObj
;
795 SOSCircleAssertStable(c
);
796 CFMutableStringRef description
= NULL
;
798 if(formatOptions
!= NULL
){
799 description
= descriptionCreateWithFormatOptions(aObj
, formatOptions
);
802 description
= defaultDescriptionCreate(aObj
);
807 CFStringRef
SOSCircleGetName(SOSCircleRef circle
) {
809 assert(circle
->name
);
813 const char *SOSCircleGetNameC(SOSCircleRef circle
) {
814 CFStringRef name
= SOSCircleGetName(circle
);
817 return CFStringToCString(name
);
820 SOSGenCountRef
SOSCircleGetGeneration(SOSCircleRef circle
) {
822 assert(circle
->generation
);
823 return circle
->generation
;
826 void SOSCircleSetGeneration(SOSCircleRef circle
, SOSGenCountRef gencount
) {
828 CFReleaseNull(circle
->generation
);
829 circle
->generation
= CFRetainSafe(gencount
);
832 int64_t SOSCircleGetGenerationSint(SOSCircleRef circle
) {
833 SOSGenCountRef gen
= SOSCircleGetGeneration(circle
);
834 return SOSGetGenerationSint(gen
);
837 void SOSCircleGenerationSetValue(SOSCircleRef circle
, int64_t value
) {
838 CFAssignRetained(circle
->generation
, SOSGenerationCreateWithValue(value
));
841 void SOSCircleGenerationIncrement(SOSCircleRef circle
) {
842 SOSGenCountRef old
= circle
->generation
;
843 circle
->generation
= SOSGenerationIncrementAndCreate(old
);
847 int SOSCircleCountPeers(SOSCircleRef circle
) {
848 SOSCircleAssertStable(circle
);
849 __block
int count
= 0;
850 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
856 int SOSCircleCountActivePeers(SOSCircleRef circle
) {
857 SOSCircleAssertStable(circle
);
858 __block
int count
= 0;
859 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
865 int SOSCircleCountActiveValidPeers(SOSCircleRef circle
, SecKeyRef pubkey
) {
866 SOSCircleAssertStable(circle
);
867 __block
int count
= 0;
868 SOSCircleForEachActiveValidPeer(circle
, pubkey
, ^(SOSPeerInfoRef peer
) {
874 int SOSCircleCountValidSyncingPeers(SOSCircleRef circle
, SecKeyRef pubkey
) {
875 SOSCircleAssertStable(circle
);
876 __block
int count
= 0;
877 SOSCircleForEachValidSyncingPeer(circle
, pubkey
, ^(SOSPeerInfoRef peer
) {
884 int SOSCircleCountRetiredPeers(SOSCircleRef circle
) {
885 SOSCircleAssertStable(circle
);
886 __block
int count
= 0;
887 SOSCircleForEachRetiredPeer(circle
, ^(SOSPeerInfoRef peer
) {
893 int SOSCircleCountApplicants(SOSCircleRef circle
) {
894 SOSCircleAssertStable(circle
);
896 return (int)CFSetGetCount(circle
->applicants
);
899 bool SOSCircleHasApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
900 SOSCircleAssertStable(circle
);
902 return CFSetContainsValue(circle
->applicants
, peerInfo
);
905 CFMutableSetRef
SOSCircleCopyApplicants(SOSCircleRef circle
, CFAllocatorRef allocator
) {
906 SOSCircleAssertStable(circle
);
908 return CFSetCreateMutableCopy(allocator
, 0, circle
->applicants
);
911 int SOSCircleCountRejectedApplicants(SOSCircleRef circle
) {
912 SOSCircleAssertStable(circle
);
914 return (int)CFSetGetCount(circle
->rejected_applicants
);
917 bool SOSCircleHasRejectedApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
918 SOSCircleAssertStable(circle
);
919 return CFSetContainsValue(circle
->rejected_applicants
, peerInfo
);
922 SOSPeerInfoRef
SOSCircleCopyRejectedApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
923 SOSCircleAssertStable(circle
);
924 return CFRetainSafe((SOSPeerInfoRef
)CFSetGetValue(circle
->rejected_applicants
, peerInfo
));
927 CFMutableArrayRef
SOSCircleCopyRejectedApplicants(SOSCircleRef circle
, CFAllocatorRef allocator
) {
928 SOSCircleAssertStable(circle
);
930 return CFSetCopyValuesCFArray(circle
->rejected_applicants
);
933 bool SOSCircleResetToEmpty(SOSCircleRef circle
, CFErrorRef
*error
) {
934 CFSetRemoveAllValues(circle
->applicants
);
935 CFSetRemoveAllValues(circle
->rejected_applicants
);
936 CFSetRemoveAllValues(circle
->peers
);
937 CFDictionaryRemoveAllValues(circle
->signatures
);
938 SOSGenCountRef oldGen
= SOSCircleGetGeneration(circle
);
939 SOSGenCountRef newGen
= SOSGenerationCreateWithBaseline(oldGen
);
940 SOSCircleSetGeneration(circle
, newGen
);
941 CFReleaseSafe(newGen
);
945 bool SOSCircleResetToEmptyWithSameGeneration(SOSCircleRef circle
, CFErrorRef
*error
) {
946 SOSGenCountRef gen
= SOSGenerationCopy(SOSCircleGetGeneration(circle
));
947 SOSCircleResetToEmpty(circle
, error
);
948 SOSCircleSetGeneration(circle
, gen
);
953 bool SOSCircleResetToOffering(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
){
955 return SOSCircleResetToEmpty(circle
, error
)
956 && SOSCircleRequestAdmission(circle
, user_privkey
, requestor
, error
)
957 && SOSCircleAcceptRequest(circle
, user_privkey
, requestor
, SOSFullPeerInfoGetPeerInfo(requestor
), error
);
960 bool SOSCircleRemoveRetired(SOSCircleRef circle
, CFErrorRef
*error
) {
961 CFSetRemoveAllPassing(circle
->peers
, ^ bool (const void *element
) {
962 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) element
;
964 return SOSPeerInfoIsRetirementTicket(peer
);
970 static bool SOSCircleRecordAdmissionRequest(SOSCircleRef circle
, SecKeyRef user_pubkey
, SOSPeerInfoRef requestorPeerInfo
, CFErrorRef
*error
) {
971 SOSCircleAssertStable(circle
);
973 bool isPeer
= SOSCircleHasPeer(circle
, requestorPeerInfo
, error
);
975 require_action_quiet(!isPeer
, fail
, SOSCreateError(kSOSErrorAlreadyPeer
, CFSTR("Cannot request admission when already a peer"), NULL
, error
));
977 // This adds to applicants and will take off rejected if it's there.
978 CFSetTransferObject(requestorPeerInfo
, circle
->rejected_applicants
, circle
->applicants
);
987 bool SOSCircleRequestReadmission(SOSCircleRef circle
, SecKeyRef user_pubkey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
988 bool success
= false;
990 require_quiet(SOSPeerInfoApplicationVerify(peer
, user_pubkey
, error
), fail
);
991 success
= SOSCircleRecordAdmissionRequest(circle
, user_pubkey
, peer
, error
);
996 bool SOSCircleRequestAdmission(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
) {
997 bool success
= false;
999 SecKeyRef user_pubkey
= SecKeyCreatePublicFromPrivate(user_privkey
);
1000 require_action_quiet(user_pubkey
, fail
, SOSCreateError(kSOSErrorBadKey
, CFSTR("No public key for key"), NULL
, error
));
1002 require(SOSFullPeerInfoPromoteToApplication(requestor
, user_privkey
, error
), fail
);
1004 success
= SOSCircleRecordAdmissionRequest(circle
, user_pubkey
, SOSFullPeerInfoGetPeerInfo(requestor
), error
);
1006 CFReleaseNull(user_pubkey
);
1010 static bool sosCircleUpdatePeerInfoSet(CFMutableSetRef theSet
, SOSPeerInfoRef replacement_peer_info
) {
1011 CFTypeRef old
= NULL
;
1012 if(!replacement_peer_info
) return false;
1013 if(!(old
= CFSetGetValue(theSet
, replacement_peer_info
))) return false;
1014 if(CFEqualSafe(old
, replacement_peer_info
)) return false;
1015 CFSetReplaceValue(theSet
, replacement_peer_info
);
1019 bool SOSCircleUpdatePeerInfo(SOSCircleRef circle
, SOSPeerInfoRef replacement_peer_info
) {
1020 if(sosCircleUpdatePeerInfoSet(circle
->peers
, replacement_peer_info
)) return true;
1021 if(sosCircleUpdatePeerInfoSet(circle
->applicants
, replacement_peer_info
)) return true;
1022 if(sosCircleUpdatePeerInfoSet(circle
->rejected_applicants
, replacement_peer_info
)) return true;
1026 static bool SOSCircleRemovePeerInternal(SOSCircleRef circle
, SOSFullPeerInfoRef requestor
, SOSPeerInfoRef peer_to_remove
, CFErrorRef
*error
) {
1027 SOSPeerInfoRef requestor_peer_info
= SOSFullPeerInfoGetPeerInfo(requestor
);
1029 if (SOSCircleHasPeer(circle
, peer_to_remove
, NULL
)) {
1030 if (!SOSCircleHasPeer(circle
, requestor_peer_info
, error
)) {
1031 SOSCreateError(kSOSErrorAlreadyPeer
, CFSTR("Must be peer to remove peer"), NULL
, error
);
1034 CFSetRemoveValue(circle
->peers
, peer_to_remove
);
1037 if (SOSCircleHasApplicant(circle
, peer_to_remove
, error
)) {
1038 return SOSCircleRejectRequest(circle
, requestor
, peer_to_remove
, error
);
1044 bool SOSCircleRemovePeers(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFSetRef peersToRemove
, CFErrorRef
*error
) {
1046 bool success
= false;
1048 __block
bool removed_all
= true;
1049 CFSetForEach(peersToRemove
, ^(const void *value
) {
1050 SOSPeerInfoRef peerInfo
= asSOSPeerInfo(value
);
1052 removed_all
&= SOSCircleRemovePeerInternal(circle
, requestor
, peerInfo
, error
);
1056 require_quiet(removed_all
, exit
);
1058 require_quiet(SOSCircleGenerationSign(circle
, user_privkey
, requestor
, error
), exit
);
1067 bool SOSCircleRemovePeersByID(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFSetRef peersToRemove
, CFErrorRef
*error
) {
1069 bool success
= false;
1071 __block
bool removed_all
= true;
1072 CFSetForEach(peersToRemove
, ^(const void *value
) {
1073 CFStringRef peerID
= asString(value
, NULL
);
1075 SOSPeerInfoRef peerInfo
= SOSCircleCopyPeerInfo(circle
, peerID
, NULL
);
1077 removed_all
&= SOSCircleRemovePeerInternal(circle
, requestor
, peerInfo
, error
);
1078 CFReleaseNull(peerInfo
);
1083 require_quiet(removed_all
, exit
);
1085 require_quiet(SOSCircleGenerationSign(circle
, user_privkey
, requestor
, error
), exit
);
1093 static bool SOSCircleRemovePeerUnsigned(SOSCircleRef circle
, SOSPeerInfoRef peer_to_remove
) {
1094 bool retval
= false;
1095 if (SOSCircleHasPeer(circle
, peer_to_remove
, NULL
)) {
1096 CFSetRemoveValue(circle
->peers
, peer_to_remove
);
1102 bool SOSCircleRemovePeersByIDUnsigned(SOSCircleRef circle
, CFSetRef peersToRemove
) {
1103 __block
bool removed_all
= true;
1104 CFSetForEach(peersToRemove
, ^(const void *value
) {
1105 CFStringRef peerID
= asString(value
, NULL
);
1106 SOSPeerInfoRef peerInfo
= SOSCircleCopyPeerInfo(circle
, peerID
, NULL
);
1107 removed_all
&= SOSCircleRemovePeerUnsigned(circle
, peerInfo
);
1108 CFReleaseNull(peerInfo
);
1113 bool SOSCircleRemovePeer(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, SOSPeerInfoRef peer_to_remove
, CFErrorRef
*error
) {
1114 bool success
= false;
1116 require_quiet(SOSCircleRemovePeerInternal(circle
, requestor
, peer_to_remove
, error
), exit
);
1118 require_quiet(SOSCircleGenerationSign(circle
, user_privkey
, requestor
, error
), exit
);
1125 bool SOSCircleAcceptRequest(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef device_approver
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
1126 SOSCircleAssertStable(circle
);
1128 SecKeyRef publicKey
= NULL
;
1129 bool result
= false;
1131 require_action_quiet(CFSetContainsValue(circle
->applicants
, peerInfo
), fail
,
1132 SOSCreateError(kSOSErrorNotApplicant
, CFSTR("Cannot accept non-applicant"), NULL
, error
));
1134 publicKey
= SecKeyCreatePublicFromPrivate(user_privkey
);
1135 require_quiet(SOSPeerInfoApplicationVerify(peerInfo
, publicKey
, error
), fail
);
1137 CFSetTransferObject(peerInfo
, circle
->applicants
, circle
->peers
);
1139 result
= SOSCircleGenerationSign(circle
, user_privkey
, device_approver
, error
);
1142 CFReleaseNull(publicKey
);
1146 bool SOSCircleWithdrawRequest(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
1147 SOSCircleAssertStable(circle
);
1149 CFSetRemoveValue(circle
->applicants
, peerInfo
);
1154 bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
1155 SOSCircleAssertStable(circle
);
1157 CFSetRemoveValue(circle
->rejected_applicants
, peerInfo
);
1163 bool SOSCircleRejectRequest(SOSCircleRef circle
, SOSFullPeerInfoRef device_rejector
,
1164 SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
1165 SOSCircleAssertStable(circle
);
1167 if (CFEqual(SOSPeerInfoGetPeerID(peerInfo
), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector
))))
1168 return SOSCircleWithdrawRequest(circle
, peerInfo
, error
);
1170 if (!CFSetContainsValue(circle
->applicants
, peerInfo
)) {
1171 SOSCreateError(kSOSErrorNotApplicant
, CFSTR("Cannot reject non-applicant"), NULL
, error
);
1175 CFSetTransferObject(peerInfo
, circle
->applicants
, circle
->rejected_applicants
);
1177 // TODO: Maybe we sign the rejection with device_rejector.
1182 bool SOSCircleAcceptRequests(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef device_approver
,
1183 CFErrorRef
*error
) {
1184 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1185 __block
bool result
= false;
1187 SOSCircleForEachApplicant(circle
, ^(SOSPeerInfoRef peer
) {
1188 if (!SOSCircleAcceptRequest(circle
, user_privkey
, device_approver
, peer
, error
)) {
1189 secnotice("circle", "error in SOSCircleAcceptRequest\n");
1191 secnotice("circle", "Accepted peer: %@", peer
);
1197 SOSCircleGenerationSign(circle
, user_privkey
, device_approver
, error
);
1198 secnotice("circle", "Countersigned accepted requests");
1204 bool SOSCirclePeerSigUpdate(SOSCircleRef circle
, SecKeyRef userPrivKey
, SOSFullPeerInfoRef fpi
,
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 SecKeyRef userPubKey
= SecKeyCreatePublicFromPrivate(userPrivKey
);
1210 // We're going to remove any applicants using a mismatched user key.
1211 SOSCircleForEachApplicant(circle
, ^(SOSPeerInfoRef peer
) {
1212 if(!SOSPeerInfoApplicationVerify(peer
, userPubKey
, NULL
)) {
1213 if(!SOSCircleRejectRequest(circle
, fpi
, peer
, NULL
)) {
1219 result
= SOSCircleUpdatePeerInfo(circle
, SOSFullPeerInfoGetPeerInfo(fpi
));
1222 SOSCircleGenerationSign(circle
, userPrivKey
, fpi
, error
);
1223 secnotice("circle", "Generation signed updated signatures on peerinfo");
1230 // Peer iteration and membership
1233 static inline void SOSCircleForEachPeerMatching(SOSCircleRef circle
,
1234 void (^action
)(SOSPeerInfoRef peer
),
1235 bool (^condition
)(SOSPeerInfoRef peer
)) {
1236 CFSetForEach(circle
->peers
, ^(const void *value
) {
1237 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) value
;
1238 if (condition(peer
))
1243 static inline bool isHiddenPeer(SOSPeerInfoRef peer
) {
1244 return SOSPeerInfoIsRetirementTicket(peer
) || SOSPeerInfoIsCloudIdentity(peer
);
1247 void SOSCircleForEachPeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1248 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1249 return !isHiddenPeer(peer
);
1253 void SOSCircleForEachRetiredPeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1254 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1255 return SOSPeerInfoIsRetirementTicket(peer
);
1259 void SOSCircleForEachiCloudIdentityPeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1260 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1261 return SOSPeerInfoIsCloudIdentity(peer
);
1266 void SOSCircleForEachActivePeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1267 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1272 void SOSCircleForEachActiveValidPeer(SOSCircleRef circle
, SecKeyRef user_public_key
, void (^action
)(SOSPeerInfoRef peer
)) {
1273 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1274 return SOSPeerInfoApplicationVerify(peer
, user_public_key
, NULL
);
1278 void SOSCircleForEachValidPeer(SOSCircleRef circle
, SecKeyRef user_public_key
, void (^action
)(SOSPeerInfoRef peer
)) {
1279 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1280 return !isHiddenPeer(peer
) && SOSPeerInfoApplicationVerify(peer
, user_public_key
, NULL
);
1284 void SOSCircleForEachValidSyncingPeer(SOSCircleRef circle
, SecKeyRef user_public_key
, void (^action
)(SOSPeerInfoRef peer
)) {
1285 SOSCircleForEachValidPeer(circle
, user_public_key
, action
);
1288 void SOSCircleForEachApplicant(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1289 CFSetForEach(circle
->applicants
, ^(const void*value
) { action((SOSPeerInfoRef
) value
); } );
1293 bool SOSCircleHasPeerWithID(SOSCircleRef circle
, CFStringRef peerid
, CFErrorRef
*error
) {
1294 SOSCircleAssertStable(circle
);
1296 SOSPeerInfoRef found
= asSOSPeerInfo(CFSetGetValue(circle
->peers
, peerid
));
1297 return found
&& !isHiddenPeer(found
);
1300 SOSPeerInfoRef
SOSCircleCopyPeerWithID(SOSCircleRef circle
, CFStringRef peerid
, CFErrorRef
*error
) {
1301 SOSCircleAssertStable(circle
);
1303 SOSPeerInfoRef found
= asSOSPeerInfo(CFSetGetValue(circle
->peers
, peerid
));
1304 return found
? SOSPeerInfoCreateCopy(kCFAllocatorDefault
, found
, NULL
) : NULL
;
1307 bool SOSCircleHasPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
1308 if(!peerInfo
) return false;
1309 return SOSCircleHasPeerWithID(circle
, SOSPeerInfoGetPeerID(peerInfo
), error
);
1312 bool SOSCircleHasActivePeerWithID(SOSCircleRef circle
, CFStringRef peerid
, CFErrorRef
*error
) {
1313 SOSCircleAssertStable(circle
);
1314 SOSPeerInfoRef found
= asSOSPeerInfo(CFSetGetValue(circle
->peers
, peerid
));
1318 bool SOSCircleHasActivePeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
1319 if(!peerInfo
) return false;
1320 return SOSCircleHasActivePeerWithID(circle
, SOSPeerInfoGetPeerID(peerInfo
), error
);
1323 bool SOSCircleHasActiveValidPeerWithID(SOSCircleRef circle
, CFStringRef peerid
, SecKeyRef user_public_key
, CFErrorRef
*error
) {
1324 SOSCircleAssertStable(circle
);
1325 SOSPeerInfoRef found
= asSOSPeerInfo(CFSetGetValue(circle
->peers
, peerid
));
1326 return found
&& SOSPeerInfoApplicationVerify(found
, user_public_key
, NULL
);
1329 bool SOSCircleHasValidSyncingPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, SecKeyRef user_public_key
, CFErrorRef
*error
) {
1330 SOSCircleAssertStable(circle
);
1331 SOSPeerInfoRef found
= asSOSPeerInfo(CFSetGetValue(circle
->peers
, peerInfo
));
1332 return found
&& !isHiddenPeer(found
) && SOSPeerInfoApplicationVerify(found
, user_public_key
, NULL
);
1335 bool SOSCircleHasActiveValidPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, SecKeyRef user_public_key
, CFErrorRef
*error
) {
1336 if(!peerInfo
) return false;
1337 return SOSCircleHasActiveValidPeerWithID(circle
, SOSPeerInfoGetPeerID(peerInfo
), user_public_key
, error
);
1341 CFMutableSetRef
SOSCircleCopyPeers(SOSCircleRef circle
, CFAllocatorRef allocator
) {
1342 SOSCircleAssertStable(circle
);
1344 CFMutableSetRef result
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
1346 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
1347 CFSetAddValue(result
, peer
);
1353 bool SOSCircleAppendConcurringPeers(SOSCircleRef circle
, CFMutableArrayRef appendHere
, CFErrorRef
*error
) {
1354 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
1355 CFErrorRef localError
= NULL
;
1356 if (SOSCircleVerifyPeerSigned(circle
, peer
, &localError
)) {
1357 SOSPeerInfoRef peerInfo
= SOSPeerInfoCreateCopy(kCFAllocatorDefault
, peer
, error
);
1358 CFArrayAppendValue(appendHere
, peerInfo
);
1359 CFRelease(peerInfo
);
1360 } else if (error
!= NULL
) {
1361 secerror("Error checking concurrence: %@", localError
);
1363 CFReleaseNull(localError
);
1369 CFMutableArrayRef
SOSCircleCopyConcurringPeers(SOSCircleRef circle
, CFErrorRef
* error
) {
1370 SOSCircleAssertStable(circle
);
1372 CFMutableArrayRef concurringPeers
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
1374 if (!SOSCircleAppendConcurringPeers(circle
, concurringPeers
, error
))
1375 CFReleaseNull(concurringPeers
);
1377 return concurringPeers
;
1380 SOSFullPeerInfoRef
SOSCircleCopyiCloudFullPeerInfoRef(SOSCircleRef circle
, CFErrorRef
*error
) {
1381 __block SOSFullPeerInfoRef cloud_full_peer
= NULL
;
1382 __block CFErrorRef searchError
= NULL
;
1383 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
1384 if (SOSPeerInfoIsCloudIdentity(peer
)) {
1385 if (cloud_full_peer
== NULL
) {
1387 secerror("More than one cloud identity found, first had error, trying new one.");
1389 CFReleaseNull(searchError
);
1390 cloud_full_peer
= SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault
, peer
, &searchError
);
1391 if (!cloud_full_peer
) {
1392 secnotice("icloud-identity", "Failed to make FullPeer for iCloud Identity: %@ (%@)", cloud_full_peer
, searchError
);
1395 secerror("Additional cloud identity found in circle after successful creation: %@", circle
);
1399 // If we didn't find one at all, report the error.
1400 if (cloud_full_peer
== NULL
&& searchError
== NULL
) {
1401 SOSErrorCreate(kSOSErrorNoiCloudPeer
, &searchError
, NULL
, CFSTR("No iCloud identity PeerInfo found in circle"));
1402 secnotice("icloud-identity", "No iCloud identity PeerInfo found in circle");
1405 CFTransferRetained(*error
, searchError
);
1407 CFReleaseNull(searchError
);
1408 return cloud_full_peer
;
1411 void debugDumpCircle(CFStringRef message
, SOSCircleRef circle
) {
1414 secinfo("circledebug", "%@: %@", message
, circle
);
1418 CFDataRef derdata
= SOSCircleCopyEncodedData(circle
, kCFAllocatorDefault
, &error
);
1420 CFStringRef hex
= CFDataCopyHexString(derdata
);
1421 secinfo("circledebug", "Full contents: %@", hex
);
1422 if (hex
) CFRelease(hex
);
1427 bool SOSCircleAcceptPeerFromHSA2(SOSCircleRef circle
, SecKeyRef userKey
, SOSGenCountRef gencount
, SecKeyRef pPubKey
, CFDataRef signature
, SOSFullPeerInfoRef fpi
, CFErrorRef
*error
) {
1428 SOSPeerInfoRef peerInfo
= SOSFullPeerInfoGetPeerInfo(fpi
);
1431 CFSetAddValue(circle
->peers
, peerInfo
);
1433 // Gen sign first, then add signature from our approver - remember gensign removes all existing sigs.
1434 res
= SOSCircleGenerationSignWithGenCount(circle
, userKey
, fpi
, gencount
, error
);
1436 secnotice("circleJoin", "Failed to regenerate circle with new gen count: %@", error
? *error
: NULL
);
1439 res
= SOSCircleSetSignature(circle
, pPubKey
, signature
, error
);
1441 secnotice("circleJoin", "Failed to set signature: %@", error
? *error
: NULL
);
1444 res
= SOSCircleVerify(circle
, pPubKey
, error
);
1446 secnotice("circleJoin", "Circle failed to validate after peer signature: %@", error
? *error
: NULL
);
1449 secnotice("circleJoin", "Circle accepted successfullyed");
1456 ccstatus: Not in Circle (1)
1457 Account user public is trusted
1458 Generation Count: [2016-05-19 15:53 4]
1462 static inline void logPeerInfo(char *category
, SOSCircleRef circle
, SecKeyRef pubKey
, CFStringRef myPID
, SOSPeerInfoRef peer
) {
1464 if (SOSCircleVerifyPeerSigned(circle
, peer
, NULL
)) {
1467 SOSPeerInfoLogState(category
, peer
, pubKey
, myPID
, sigchr
);
1470 void SOSCircleLogState(char *category
, SOSCircleRef circle
, SecKeyRef pubKey
, CFStringRef myPID
) {
1472 CFStringRef genString
= SOSGenerationCountCopyDescription(SOSCircleGetGeneration(circle
));
1474 if(pubKey
&& SOSCircleVerify(circle
, pubKey
, NULL
)) {
1477 secnotice(category
, "CIRCLE: [%20@] UserSigned: %c", genString
, sigchr
);
1478 if(CFSetGetCount(circle
->peers
) == 0 )
1479 secnotice(category
, "Peers In Circle: None");
1481 secnotice(category
, "Peers In Circle:");
1482 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
1483 logPeerInfo(category
, circle
, pubKey
, myPID
, peer
);
1485 SOSCircleForEachRetiredPeer(circle
, ^(SOSPeerInfoRef peer
) {
1486 logPeerInfo(category
, circle
, pubKey
, myPID
, peer
);
1488 SOSCircleForEachiCloudIdentityPeer(circle
, ^(SOSPeerInfoRef peer
) {
1489 logPeerInfo(category
, circle
, pubKey
, myPID
, peer
);
1494 if(CFSetGetCount(circle
->applicants
) == 0 )
1495 secnotice(category
, "Applicants To Circle: None");
1497 secnotice(category
, "Applicants To Circle:");
1499 SOSCircleForEachApplicant(circle
, ^(SOSPeerInfoRef peer
) {
1500 SOSPeerInfoLogState(category
, peer
, pubKey
, myPID
, 'v');
1505 if(CFSetGetCount(circle
->rejected_applicants
) == 0)
1506 secnotice(category
, "Rejected Applicants To Circle: None");
1508 secnotice(category
, "Rejected Applicants To Circle:");
1509 CFSetForEach(circle
->rejected_applicants
, ^(const void *value
) {
1510 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) value
;
1511 SOSPeerInfoLogState(category
, peer
, pubKey
, myPID
, 'v');
1514 CFReleaseNull(genString
);