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
);