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 <SecureObjectSync/SOSCircle.h>
33 #include <SecureObjectSync/SOSCloudCircleInternal.h>
34 #include <SecureObjectSync/SOSInternal.h>
35 #include <SecureObjectSync/SOSEngine.h>
36 #include <SecureObjectSync/SOSPeer.h>
37 #include <SecureObjectSync/SOSPeerInfoCollections.h>
38 #include <CoreFoundation/CoreFoundation.h>
39 #include <Security/SecFramework.h>
41 #include <Security/SecKey.h>
42 #include <Security/SecKeyPriv.h>
44 #include <utilities/SecCFWrappers.h>
45 //#include "ckdUtilities.h"
47 #include <utilities/der_plist.h>
48 #include <utilities/der_plist_internal.h>
50 #include <corecrypto/ccder.h>
51 #include <corecrypto/ccdigest.h>
52 #include <corecrypto/ccsha2.h>
58 kOnlyCompatibleVersion
= 1, // Sometime in the future this name will be improved to reflect history.
60 kAlwaysIncompatibleVersion
= UINT64_MAX
,
63 struct __OpaqueSOSCircle
{
67 CFNumberRef generation
;
68 CFMutableSetRef peers
;
69 CFMutableSetRef applicants
;
70 CFMutableSetRef rejected_applicants
;
72 CFMutableDictionaryRef signatures
;
75 CFGiblisWithCompareFor(SOSCircle
);
77 SOSCircleRef
SOSCircleCreate(CFAllocatorRef allocator
, CFStringRef name
, CFErrorRef
*error
) {
78 SOSCircleRef c
= CFTypeAllocate(SOSCircle
, struct __OpaqueSOSCircle
, allocator
);
83 c
->name
= CFStringCreateCopy(allocator
, name
);
84 c
->generation
= CFNumberCreate(allocator
, kCFNumberSInt64Type
, &gen
);
85 c
->peers
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
86 c
->applicants
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
87 c
->rejected_applicants
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
88 c
->signatures
= CFDictionaryCreateMutableForCFTypes(allocator
);
93 static CFNumberRef
SOSCircleGenerationCopy(CFNumberRef generation
) {
95 CFAllocatorRef allocator
= CFGetAllocator(generation
);
96 CFNumberGetValue(generation
, kCFNumberSInt64Type
, &value
);
97 return CFNumberCreate(allocator
, kCFNumberSInt64Type
, &value
);
100 static CFMutableSetRef
CFSetOfPeerInfoDeepCopy(CFAllocatorRef allocator
, CFSetRef peerInfoSet
)
102 __block CFMutableSetRef result
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
103 CFSetForEach(peerInfoSet
, ^(const void *value
) {
104 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
105 CFErrorRef localError
= NULL
;
106 SOSPeerInfoRef copiedPeer
= SOSPeerInfoCreateCopy(allocator
, pi
, &localError
);
108 CFSetAddValue(result
, copiedPeer
);
110 secerror("Failed to copy peer: %@ (%@)", pi
, localError
);
112 CFReleaseSafe(copiedPeer
);
113 CFReleaseSafe(localError
);
118 SOSCircleRef
SOSCircleCopyCircle(CFAllocatorRef allocator
, SOSCircleRef otherCircle
, CFErrorRef
*error
)
120 SOSCircleRef c
= CFTypeAllocate(SOSCircle
, struct __OpaqueSOSCircle
, allocator
);
123 c
->name
= CFStringCreateCopy(allocator
, otherCircle
->name
);
124 c
->generation
= SOSCircleGenerationCopy(otherCircle
->generation
);
126 c
->peers
= CFSetOfPeerInfoDeepCopy(allocator
, otherCircle
->peers
);
127 c
->applicants
= CFSetOfPeerInfoDeepCopy(allocator
, otherCircle
->applicants
);
128 c
->rejected_applicants
= CFSetOfPeerInfoDeepCopy(allocator
, otherCircle
->rejected_applicants
);
130 c
->signatures
= CFDictionaryCreateMutableCopy(allocator
, 0, otherCircle
->signatures
);
136 void SOSCircleAssertStable(SOSCircleRef circle
)
139 assert(circle
->name
);
140 assert(circle
->generation
);
141 assert(circle
->peers
);
142 assert(circle
->applicants
);
143 assert(circle
->rejected_applicants
);
144 assert(circle
->signatures
);
148 SOSCircleRef
SOSCircleConvertAndAssertStable(CFTypeRef circleAsType
)
150 if (CFGetTypeID(circleAsType
) != SOSCircleGetTypeID())
153 SOSCircleRef circle
= (SOSCircleRef
) circleAsType
;
155 SOSCircleAssertStable(circle
);
160 static Boolean
SOSCircleCompare(CFTypeRef lhs
, CFTypeRef rhs
) {
161 if (CFGetTypeID(lhs
) != SOSCircleGetTypeID()
162 || CFGetTypeID(rhs
) != SOSCircleGetTypeID())
165 SOSCircleRef left
= SOSCircleConvertAndAssertStable(lhs
);
166 SOSCircleRef right
= SOSCircleConvertAndAssertStable(rhs
);
168 // TODO: we should be doing set equality for peers and applicants.
169 return NULL
!= left
&& NULL
!= right
170 && CFEqualSafe(left
->generation
, right
->generation
)
171 && SOSPeerInfoSetContainsIdenticalPeers(left
->peers
, right
->peers
)
172 && SOSPeerInfoSetContainsIdenticalPeers(left
->applicants
, right
->applicants
)
173 && SOSPeerInfoSetContainsIdenticalPeers(left
->rejected_applicants
, right
->rejected_applicants
)
174 && CFEqualSafe(left
->signatures
, right
->signatures
);
177 static CFMutableArrayRef
CFSetCopyValuesCFArray(CFSetRef set
)
179 CFIndex count
= CFSetGetCount(set
);
181 CFMutableArrayRef result
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
183 const void * values
[count
];
184 CFSetGetValues(set
, values
);
185 for (int current
= 0; current
< count
; ++current
) {
186 CFArrayAppendValue(result
, values
[current
]);
193 static bool SOSCircleDigestArray(const struct ccdigest_info
*di
, CFMutableArrayRef array
, void *hash_result
, CFErrorRef
*error
)
195 __block
bool success
= true;
196 ccdigest_di_decl(di
, array_digest
);
197 const void * a_digest
= array_digest
;
199 ccdigest_init(di
, array_digest
);
200 CFArraySortValues(array
, CFRangeMake(0, CFArrayGetCount(array
)), SOSPeerInfoCompareByID
, SOSPeerCmpPubKeyHash
);
201 CFArrayForEach(array
, ^(const void *peer
) {
202 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes((SOSPeerInfoRef
)peer
, di
, a_digest
, error
))
205 ccdigest_final(di
, array_digest
, hash_result
);
210 static bool SOSCircleDigestSet(const struct ccdigest_info
*di
, CFMutableSetRef set
, void *hash_result
, CFErrorRef
*error
)
212 CFMutableArrayRef values
= CFSetCopyValuesCFArray(set
);
214 bool result
= SOSCircleDigestArray(di
, values
, hash_result
, error
);
216 CFReleaseSafe(values
);
222 static bool SOSCircleHash(const struct ccdigest_info
*di
, SOSCircleRef circle
, void *hash_result
, CFErrorRef
*error
) {
223 ccdigest_di_decl(di
, circle_digest
);
224 ccdigest_init(di
, circle_digest
);
225 int64_t gen
= SOSCircleGetGenerationSint(circle
);
226 ccdigest_update(di
, circle_digest
, sizeof(gen
), &gen
);
228 SOSCircleDigestSet(di
, circle
->peers
, hash_result
, error
);
229 ccdigest_update(di
, circle_digest
, di
->output_size
, hash_result
);
230 ccdigest_final(di
, circle_digest
, hash_result
);
234 static bool SOSCircleSetSignature(SOSCircleRef circle
, SecKeyRef pubkey
, CFDataRef signature
, CFErrorRef
*error
) {
237 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubkey
, error
);
238 require_quiet(pubKeyID
, fail
);
239 CFDictionarySetValue(circle
->signatures
, pubKeyID
, signature
);
243 CFReleaseSafe(pubKeyID
);
247 static bool SOSCircleRemoveSignatures(SOSCircleRef circle
, CFErrorRef
*error
) {
248 CFDictionaryRemoveAllValues(circle
->signatures
);
252 static CFDataRef
SOSCircleGetSignature(SOSCircleRef circle
, SecKeyRef pubkey
, CFErrorRef
*error
) {
253 CFStringRef pubKeyID
= SOSCopyIDOfKey(pubkey
, error
);
254 CFDataRef result
= NULL
;
255 require_quiet(pubKeyID
, fail
);
257 CFTypeRef value
= (CFDataRef
)CFDictionaryGetValue(circle
->signatures
, pubKeyID
);
259 if (isData(value
)) result
= (CFDataRef
) value
;
262 CFReleaseSafe(pubKeyID
);
266 bool SOSCircleSign(SOSCircleRef circle
, SecKeyRef privKey
, CFErrorRef
*error
) {
267 if (!privKey
) return false; // Really assertion but not always true for now.
268 CFAllocatorRef allocator
= CFGetAllocator(circle
);
270 size_t tmplen
= 4096;
271 const struct ccdigest_info
*di
= ccsha256_di();
272 uint8_t hash_result
[di
->output_size
];
274 SOSCircleHash(di
, circle
, hash_result
, error
);
275 OSStatus stat
= SecKeyRawSign(privKey
, kSecPaddingNone
, hash_result
, di
->output_size
, tmp
, &tmplen
);
277 // TODO - Create a CFErrorRef;
278 secerror("Bad Circle SecKeyRawSign, stat: %ld", (long)stat
);
279 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Circle SecKeyRawSign"), (error
!= NULL
) ? *error
: NULL
, error
);
282 CFDataRef signature
= CFDataCreate(allocator
, tmp
, tmplen
);
283 SecKeyRef publicKey
= SecKeyCreatePublicFromPrivate(privKey
);
284 SOSCircleSetSignature(circle
, publicKey
, signature
, error
);
285 CFReleaseNull(publicKey
);
286 CFRelease(signature
);
290 bool SOSCircleVerifySignatureExists(SOSCircleRef circle
, SecKeyRef pubKey
, CFErrorRef
*error
) {
293 secerror("SOSCircleVerifySignatureExists no pubKey");
294 SOSCreateError(kSOSErrorBadFormat
, CFSTR("SOSCircleVerifySignatureExists no pubKey"), (error
!= NULL
) ? *error
: NULL
, error
);
297 CFDataRef signature
= SOSCircleGetSignature(circle
, pubKey
, error
);
298 return NULL
!= signature
;
301 bool SOSCircleVerify(SOSCircleRef circle
, SecKeyRef pubKey
, CFErrorRef
*error
) {
302 const struct ccdigest_info
*di
= ccsha256_di();
303 uint8_t hash_result
[di
->output_size
];
305 SOSCircleHash(di
, circle
, hash_result
, error
);
307 CFDataRef signature
= SOSCircleGetSignature(circle
, pubKey
, error
);
308 if(!signature
) return false;
310 return SecKeyRawVerify(pubKey
, kSecPaddingNone
, hash_result
, di
->output_size
,
311 CFDataGetBytePtr(signature
), CFDataGetLength(signature
)) == errSecSuccess
;
314 bool SOSCircleVerifyPeerSigned(SOSCircleRef circle
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
315 SecKeyRef pub_key
= SOSPeerInfoCopyPubKey(peer
);
316 bool result
= SOSCircleVerify(circle
, pub_key
, error
);
317 CFReleaseSafe(pub_key
);
321 static void CFSetRemoveAllPassing(CFMutableSetRef set
, bool (^test
)(const void *) ){
322 CFMutableArrayRef toBeRemoved
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
324 CFSetForEach(set
, ^(const void *value
) {
326 CFArrayAppendValue(toBeRemoved
, value
);
329 CFArrayForEach(toBeRemoved
, ^(const void *value
) {
330 CFSetRemoveValue(set
, value
);
332 CFReleaseNull(toBeRemoved
);
335 static void SOSCircleRejectNonValidApplicants(SOSCircleRef circle
, SecKeyRef pubkey
) {
336 CFMutableSetRef applicants
= SOSCircleCopyApplicants(circle
, NULL
);
337 CFSetForEach(applicants
, ^(const void *value
) {
338 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
339 if(!SOSPeerInfoApplicationVerify(pi
, pubkey
, NULL
)) {
340 CFSetRemoveValue(circle
->applicants
, pi
);
341 CFSetSetValue(circle
->rejected_applicants
, pi
);
344 CFReleaseNull(applicants
);
347 static SOSPeerInfoRef
SOSCircleCopyPeerInfo(SOSCircleRef circle
, CFStringRef peer_id
, CFErrorRef
*error
) {
348 __block SOSPeerInfoRef result
= NULL
;
350 CFSetForEach(circle
->peers
, ^(const void *value
) {
351 if (result
== NULL
) {
352 SOSPeerInfoRef tpi
= (SOSPeerInfoRef
)value
;
353 if (CFEqual(SOSPeerInfoGetPeerID(tpi
), peer_id
))
358 CFRetainSafe(result
);
362 static bool SOSCircleUpgradePeerInfo(SOSCircleRef circle
, SecKeyRef user_approver
, SOSFullPeerInfoRef peerinfo
) {
364 SecKeyRef userPubKey
= SecKeyCreatePublicFromPrivate(user_approver
);
365 SOSPeerInfoRef fpi_pi
= SOSFullPeerInfoGetPeerInfo(peerinfo
);
366 SOSPeerInfoRef pi
= SOSCircleCopyPeerInfo(circle
, SOSPeerInfoGetPeerID(fpi_pi
), NULL
);
367 require_quiet(pi
, out
);
368 require_quiet(SOSPeerInfoApplicationVerify(pi
, userPubKey
, NULL
), re_sign
);
369 CFReleaseNull(userPubKey
);
374 secerror("SOSCircleGenerationSign: Upgraded peer's Application Signature");
375 SecKeyRef device_key
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, NULL
);
376 require_quiet(device_key
, out
);
377 SOSPeerInfoRef new_pi
= SOSPeerInfoCopyAsApplication(pi
, user_approver
, device_key
, NULL
);
378 if(SOSCircleUpdatePeerInfo(circle
, new_pi
))
380 CFReleaseNull(new_pi
);
381 CFReleaseNull(device_key
);
383 CFReleaseNull(userPubKey
);
388 bool SOSCircleGenerationSign(SOSCircleRef circle
, SecKeyRef user_approver
, SOSFullPeerInfoRef peerinfo
, CFErrorRef
*error
) {
389 SecKeyRef ourKey
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, error
);
390 SecKeyRef publicKey
= NULL
;
391 require_quiet(ourKey
, fail
);
393 // Check if we're using an invalid peerinfo for this op. There are cases where we might not be "upgraded".
394 require_quiet(SOSCircleUpgradePeerInfo(circle
, user_approver
, peerinfo
), fail
);
395 SOSCircleRemoveRetired(circle
, error
); // Prune off retirees since we're signing this one
396 CFSetRemoveAllValues(circle
->rejected_applicants
); // Dump rejects so we clean them up sometime.
397 publicKey
= SecKeyCreatePublicFromPrivate(user_approver
);
398 SOSCircleRejectNonValidApplicants(circle
, publicKey
);
399 SOSCircleGenerationIncrement(circle
);
400 require_quiet(SOSCircleRemoveSignatures(circle
, error
), fail
);
401 require_quiet(SOSCircleSign(circle
, user_approver
, error
), fail
);
402 require_quiet(SOSCircleSign(circle
, ourKey
, error
), fail
);
404 CFReleaseNull(ourKey
);
405 CFReleaseNull(publicKey
);
409 CFReleaseNull(ourKey
);
410 CFReleaseNull(publicKey
);
414 bool SOSCircleGenerationUpdate(SOSCircleRef circle
, SecKeyRef user_approver
, SOSFullPeerInfoRef peerinfo
, CFErrorRef
*error
) {
416 return SOSCircleGenerationSign(circle
, user_approver
, peerinfo
, error
);
419 bool success
= false;
421 SecKeyRef ourKey
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, error
);
422 require_quiet(ourKey
, fail
);
424 require_quiet(SOSCircleSign(circle
, user_approver
, error
), fail
);
425 require_quiet(SOSCircleSign(circle
, ourKey
, error
), fail
);
430 CFReleaseNull(ourKey
);
435 bool SOSCircleConcordanceSign(SOSCircleRef circle
, SOSFullPeerInfoRef peerinfo
, CFErrorRef
*error
) {
436 bool success
= false;
437 SecKeyRef ourKey
= SOSFullPeerInfoCopyDeviceKey(peerinfo
, error
);
438 require_quiet(ourKey
, exit
);
440 success
= SOSCircleSign(circle
, ourKey
, error
);
443 CFReleaseNull(ourKey
);
447 static inline SOSConcordanceStatus
CheckPeerStatus(SOSCircleRef circle
, SOSPeerInfoRef peer
, SecKeyRef user_public_key
, CFErrorRef
*error
) {
448 SOSConcordanceStatus result
= kSOSConcordanceNoPeer
;
449 SecKeyRef pubKey
= SOSPeerInfoCopyPubKey(peer
);
451 require_action_quiet(SOSCircleHasActiveValidPeer(circle
, peer
, user_public_key
, error
), exit
, result
= kSOSConcordanceNoPeer
);
452 require_action_quiet(SOSCircleVerifySignatureExists(circle
, pubKey
, error
), exit
, result
= kSOSConcordanceNoPeerSig
);
453 require_action_quiet(SOSCircleVerify(circle
, pubKey
, error
), exit
, result
= kSOSConcordanceBadPeerSig
);
455 result
= kSOSConcordanceTrusted
;
458 CFReleaseNull(pubKey
);
462 static inline SOSConcordanceStatus
CombineStatus(SOSConcordanceStatus status1
, SOSConcordanceStatus status2
)
464 if (status1
== kSOSConcordanceTrusted
|| status2
== kSOSConcordanceTrusted
)
465 return kSOSConcordanceTrusted
;
467 if (status1
== kSOSConcordanceBadPeerSig
|| status2
== kSOSConcordanceBadPeerSig
)
468 return kSOSConcordanceBadPeerSig
;
470 if (status1
== kSOSConcordanceNoPeerSig
|| status2
== kSOSConcordanceNoPeerSig
)
471 return kSOSConcordanceNoPeerSig
;
476 static inline bool SOSCircleIsEmpty(SOSCircleRef circle
) {
477 return SOSCircleCountPeers(circle
) == 0;
480 static inline bool SOSCircleIsOffering(SOSCircleRef circle
) {
481 return SOSCircleCountPeers(circle
) == 1;
484 __unused
static inline bool SOSCircleIsResignOffering(SOSCircleRef circle
, SecKeyRef pubkey
) {
485 return SOSCircleCountActiveValidPeers(circle
, pubkey
) == 1;
488 static inline SOSConcordanceStatus
GetSignersStatus(SOSCircleRef signers_circle
, SOSCircleRef status_circle
,
489 SecKeyRef user_pubKey
, SOSPeerInfoRef exclude
, CFErrorRef
*error
) {
490 CFStringRef excluded_id
= exclude
? SOSPeerInfoGetPeerID(exclude
) : NULL
;
492 __block SOSConcordanceStatus status
= kSOSConcordanceNoPeer
;
493 SOSCircleForEachActivePeer(signers_circle
, ^(SOSPeerInfoRef peer
) {
494 SOSConcordanceStatus peerStatus
= CheckPeerStatus(status_circle
, peer
, user_pubKey
, error
);
496 if (peerStatus
== kSOSConcordanceNoPeerSig
&&
497 (CFEqualSafe(SOSPeerInfoGetPeerID(peer
), excluded_id
) || SOSPeerInfoIsCloudIdentity(peer
)))
498 peerStatus
= kSOSConcordanceNoPeer
;
500 status
= CombineStatus(status
, peerStatus
); // TODO: Use multiple error gathering.
506 static inline bool isOlderGeneration(SOSCircleRef current
, SOSCircleRef proposed
) {
507 return CFNumberCompare(current
->generation
, proposed
->generation
, NULL
) == kCFCompareGreaterThan
;
510 bool SOSCircleSharedTrustedPeers(SOSCircleRef current
, SOSCircleRef proposed
, SOSPeerInfoRef me
) {
511 __block
bool retval
= false;
512 SOSCircleForEachPeer(current
, ^(SOSPeerInfoRef peer
) {
513 if(!CFEqual(me
, peer
) && SOSCircleHasPeer(proposed
, peer
, NULL
)) retval
= true;
518 static void SOSCircleUpgradePeersByCircle(SOSCircleRef known_circle
, SOSCircleRef proposed_circle
) {
519 SOSCircleForEachPeer(known_circle
, ^(SOSPeerInfoRef known_peer
) {
520 SOSPeerInfoRef proposed_peer
= SOSCircleCopyPeerInfo(proposed_circle
, SOSPeerInfoGetPeerID(known_peer
), NULL
);
521 if(proposed_peer
&& CFEqualSafe(proposed_peer
, known_peer
) != 0) {
522 SOSCircleUpdatePeerInfo(known_circle
, proposed_peer
);
527 SOSConcordanceStatus
SOSCircleConcordanceTrust(SOSCircleRef known_circle
, SOSCircleRef proposed_circle
,
528 SecKeyRef known_pubkey
, SecKeyRef user_pubkey
,
529 SOSPeerInfoRef exclude
, CFErrorRef
*error
) {
530 if(user_pubkey
== NULL
) {
531 SOSCreateError(kSOSErrorPublicKeyAbsent
, CFSTR("Concordance with no public key"), NULL
, error
);
532 return kSOSConcordanceNoUserKey
; //TODO: - needs to return an error
535 if (SOSCircleIsEmpty(proposed_circle
)) {
536 return kSOSConcordanceTrusted
;
539 if(!SOSCircleVerifySignatureExists(proposed_circle
, user_pubkey
, error
)) {
540 SOSCreateError(kSOSErrorBadSignature
, CFSTR("No public signature"), (error
!= NULL
) ? *error
: NULL
, error
);
541 return kSOSConcordanceNoUserSig
;
544 if(!SOSCircleVerify(proposed_circle
, user_pubkey
, error
)) {
545 SOSCreateError(kSOSErrorBadSignature
, CFSTR("Bad public signature"), (error
!= NULL
) ? *error
: NULL
, error
);
546 return kSOSConcordanceBadUserSig
;
549 if (SOSCircleIsEmpty(known_circle
) || SOSCircleIsOffering(proposed_circle
)) {
550 return GetSignersStatus(proposed_circle
, proposed_circle
, user_pubkey
, NULL
, error
);
553 if(isOlderGeneration(known_circle
, proposed_circle
)) {
554 SOSCreateError(kSOSErrorReplay
, CFSTR("Bad generation"), NULL
, error
);
555 return kSOSConcordanceGenOld
;
559 if(!SOSCircleVerify(known_circle
, user_pubkey
, error
)) {
560 SOSCircleUpgradePeersByCircle(known_circle
, proposed_circle
);
563 if(known_pubkey
== NULL
) known_pubkey
= user_pubkey
;
564 if(!SOSCircleVerify(known_circle
, known_pubkey
, error
)) known_pubkey
= user_pubkey
;
565 return GetSignersStatus(known_circle
, proposed_circle
, known_pubkey
, exclude
, error
);
569 static const uint8_t* der_decode_mutable_dictionary(CFAllocatorRef allocator
, CFOptionFlags mutability
,
570 CFMutableDictionaryRef
* dictionary
, CFErrorRef
*error
,
571 const uint8_t* der
, const uint8_t *der_end
)
573 CFDictionaryRef theDict
;
574 const uint8_t* result
= der_decode_dictionary(allocator
, mutability
, &theDict
, error
, der
, der_end
);
577 *dictionary
= (CFMutableDictionaryRef
)theDict
;
583 SOSCircleRef
SOSCircleCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
584 const uint8_t** der_p
, const uint8_t *der_end
) {
585 SOSCircleRef cir
= CFTypeAllocate(SOSCircle
, struct __OpaqueSOSCircle
, allocator
);
587 const uint8_t *sequence_end
;
590 cir
->generation
= NULL
;
592 cir
->applicants
= NULL
;
593 cir
->rejected_applicants
= NULL
;
594 cir
->signatures
= NULL
;
596 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
597 require_action_quiet(sequence_end
!= NULL
, fail
,
598 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Circle DER"), (error
!= NULL
) ? *error
: NULL
, error
));
601 uint64_t version
= 0;
602 *der_p
= ccder_decode_uint64(&version
, *der_p
, der_end
);
604 require_action_quiet(version
== kOnlyCompatibleVersion
, fail
,
605 SOSCreateError(kSOSErrorIncompatibleCircle
, CFSTR("Bad Circle Version"), NULL
, error
));
607 *der_p
= der_decode_string(allocator
, 0, &cir
->name
, error
, *der_p
, sequence_end
);
608 *der_p
= der_decode_number(allocator
, 0, &cir
->generation
, error
, *der_p
, sequence_end
);
610 cir
->peers
= SOSPeerInfoSetCreateFromArrayDER(allocator
, &kSOSPeerSetCallbacks
, error
, der_p
, sequence_end
);
611 cir
->applicants
= SOSPeerInfoSetCreateFromArrayDER(allocator
, &kSOSPeerSetCallbacks
, error
, der_p
, sequence_end
);
612 cir
->rejected_applicants
= SOSPeerInfoSetCreateFromArrayDER(allocator
, &kSOSPeerSetCallbacks
, error
, der_p
, sequence_end
);
614 *der_p
= der_decode_mutable_dictionary(allocator
, kCFPropertyListMutableContainersAndLeaves
,
615 &cir
->signatures
, error
, *der_p
, sequence_end
);
617 require_action_quiet(*der_p
== sequence_end
, fail
,
618 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Circle DER"), (error
!= NULL
) ? *error
: NULL
, error
));
627 SOSCircleRef
SOSCircleCreateFromData(CFAllocatorRef allocator
, CFDataRef circleData
, CFErrorRef
*error
)
629 size_t size
= CFDataGetLength(circleData
);
630 const uint8_t *der
= CFDataGetBytePtr(circleData
);
631 SOSCircleRef inflated
= SOSCircleCreateFromDER(allocator
, error
, &der
, der
+ size
);
635 size_t SOSCircleGetDEREncodedSize(SOSCircleRef cir
, CFErrorRef
*error
) {
636 SOSCircleAssertStable(cir
);
637 size_t total_payload
= 0;
639 require_quiet(accumulate_size(&total_payload
, ccder_sizeof_uint64(kOnlyCompatibleVersion
)), fail
);
640 require_quiet(accumulate_size(&total_payload
, der_sizeof_string(cir
->name
, error
)), fail
);
641 require_quiet(accumulate_size(&total_payload
, der_sizeof_number(cir
->generation
, error
)), fail
);
642 require_quiet(accumulate_size(&total_payload
, SOSPeerInfoSetGetDEREncodedArraySize(cir
->peers
, error
)), fail
);
643 require_quiet(accumulate_size(&total_payload
, SOSPeerInfoSetGetDEREncodedArraySize(cir
->applicants
, error
)), fail
);
644 require_quiet(accumulate_size(&total_payload
, SOSPeerInfoSetGetDEREncodedArraySize(cir
->rejected_applicants
, error
)), fail
);
645 require_quiet(accumulate_size(&total_payload
, der_sizeof_dictionary((CFDictionaryRef
) cir
->signatures
, error
)), fail
);
647 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, total_payload
);
650 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("don't know how to encode"), NULL
, error
);
654 uint8_t* SOSCircleEncodeToDER(SOSCircleRef cir
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
) {
655 SOSCircleAssertStable(cir
);
657 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
658 ccder_encode_uint64(kOnlyCompatibleVersion
, der
,
659 der_encode_string(cir
->name
, error
, der
,
660 der_encode_number(cir
->generation
, error
, der
,
661 SOSPeerInfoSetEncodeToArrayDER(cir
->peers
, error
, der
,
662 SOSPeerInfoSetEncodeToArrayDER(cir
->applicants
, error
, der
,
663 SOSPeerInfoSetEncodeToArrayDER(cir
->rejected_applicants
, error
, der
,
664 der_encode_dictionary((CFDictionaryRef
) cir
->signatures
, error
, der
, der_end
))))))));
667 CFDataRef
SOSCircleCreateIncompatibleCircleDER(CFErrorRef
* error
)
669 size_t total_payload
= 0;
670 size_t encoded_size
= 0;
672 uint8_t* der_end
= 0;
673 CFMutableDataRef result
= NULL
;
675 require_quiet(accumulate_size(&total_payload
, ccder_sizeof_uint64(kAlwaysIncompatibleVersion
)), fail
);
677 encoded_size
= ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, total_payload
);
679 result
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, encoded_size
);
681 der
= CFDataGetMutableBytePtr(result
);
682 der_end
= der
+ CFDataGetLength(result
);
684 der_end
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
685 ccder_encode_uint64(kAlwaysIncompatibleVersion
, der
, der_end
));
688 if (der
== NULL
|| der
!= der_end
)
689 CFReleaseNull(result
);
695 CFDataRef
SOSCircleCopyEncodedData(SOSCircleRef circle
, CFAllocatorRef allocator
, CFErrorRef
*error
)
697 size_t size
= SOSCircleGetDEREncodedSize(circle
, error
);
700 uint8_t buffer
[size
];
701 uint8_t* start
= SOSCircleEncodeToDER(circle
, error
, buffer
, buffer
+ sizeof(buffer
));
702 CFDataRef result
= CFDataCreate(kCFAllocatorDefault
, start
, size
);
706 static void SOSCircleDestroy(CFTypeRef aObj
) {
707 SOSCircleRef c
= (SOSCircleRef
) aObj
;
709 CFReleaseNull(c
->name
);
710 CFReleaseNull(c
->generation
);
711 CFReleaseNull(c
->peers
);
712 CFReleaseNull(c
->applicants
);
713 CFReleaseNull(c
->rejected_applicants
);
714 CFReleaseNull(c
->signatures
);
717 static CFStringRef
SOSCircleCopyDescription(CFTypeRef aObj
) {
718 SOSCircleRef c
= (SOSCircleRef
) aObj
;
720 SOSCircleAssertStable(c
);
723 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
724 CFStringAppendFormat(description
, NULL
, CFSTR("<SOSCircle@%p: '%@' P:["), c
, c
->name
);
726 __block CFStringRef separator
= CFSTR("");
727 SOSCircleForEachPeer(c
, ^(SOSPeerInfoRef peer
) {
728 CFStringRef sig
= NULL
;
729 if (SOSCircleVerifyPeerSigned(c
, peer
, NULL
)) {
732 SecKeyRef pub_key
= SOSPeerInfoCopyPubKey(peer
);
733 CFDataRef signature
= SOSCircleGetSignature(c
, pub_key
, NULL
);
734 sig
= (signature
== NULL
) ? CFSTR("-") : CFSTR("?");
735 CFReleaseNull(pub_key
);
738 CFStringAppendFormat(description
, NULL
, CFSTR("%@%@ %@"), separator
, peer
, sig
);
739 separator
= CFSTR(",");
742 CFStringAppend(description
, CFSTR("], A:["));
743 separator
= CFSTR("");
744 SOSCircleForEachApplicant(c
, ^(SOSPeerInfoRef peer
) {
745 CFStringAppendFormat(description
, NULL
, CFSTR("%@%@"), separator
, peer
);
746 separator
= CFSTR(",");
749 CFStringAppend(description
, CFSTR("], R:["));
750 separator
= CFSTR("");
751 CFSetForEach(c
->rejected_applicants
, ^(const void *value
) {
752 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) value
;
753 CFStringAppendFormat(description
, NULL
, CFSTR("%@%@"), separator
, peer
);
754 separator
= CFSTR(",");
756 CFStringAppend(description
, CFSTR("]>"));
761 CFStringRef
SOSCircleGetName(SOSCircleRef circle
) {
763 assert(circle
->name
);
767 const char *SOSCircleGetNameC(SOSCircleRef circle
) {
768 CFStringRef name
= SOSCircleGetName(circle
);
771 return CFStringToCString(name
);
774 CFNumberRef
SOSCircleGetGeneration(SOSCircleRef circle
) {
776 assert(circle
->generation
);
777 return circle
->generation
;
780 int64_t SOSCircleGetGenerationSint(SOSCircleRef circle
) {
781 CFNumberRef gen
= SOSCircleGetGeneration(circle
);
784 CFNumberGetValue(gen
, kCFNumberSInt64Type
, &value
);
788 void SOSCircleGenerationSetValue(SOSCircleRef circle
, int64_t value
)
790 CFAllocatorRef allocator
= CFGetAllocator(circle
->generation
);
791 CFAssignRetained(circle
->generation
, CFNumberCreate(allocator
, kCFNumberSInt64Type
, &value
));
795 static int64_t GenerationSetHighBits(int64_t value
, int32_t high_31
)
797 value
&= 0xFFFFFFFF; // Keep the low 32 bits.
798 value
|= ((int64_t) high_31
) << 32;
804 void SOSCircleGenerationIncrement(SOSCircleRef circle
) {
805 int64_t value
= SOSCircleGetGenerationSint(circle
);
807 if ((value
>> 32) == 0) {
808 uint32_t seconds
= CFAbsoluteTimeGetCurrent(); // seconds
809 value
= GenerationSetHighBits(value
, (seconds
>> 1));
814 SOSCircleGenerationSetValue(circle
, value
);
817 int SOSCircleCountPeers(SOSCircleRef circle
) {
818 SOSCircleAssertStable(circle
);
819 __block
int count
= 0;
820 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
826 int SOSCircleCountActivePeers(SOSCircleRef circle
) {
827 SOSCircleAssertStable(circle
);
828 __block
int count
= 0;
829 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
835 int SOSCircleCountActiveValidPeers(SOSCircleRef circle
, SecKeyRef pubkey
) {
836 SOSCircleAssertStable(circle
);
837 __block
int count
= 0;
838 SOSCircleForEachActiveValidPeer(circle
, pubkey
, ^(SOSPeerInfoRef peer
) {
844 int SOSCircleCountRetiredPeers(SOSCircleRef circle
) {
845 SOSCircleAssertStable(circle
);
846 __block
int count
= 0;
847 SOSCircleForEachRetiredPeer(circle
, ^(SOSPeerInfoRef peer
) {
853 int SOSCircleCountApplicants(SOSCircleRef circle
) {
854 SOSCircleAssertStable(circle
);
856 return (int)CFSetGetCount(circle
->applicants
);
859 bool SOSCircleHasApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
860 SOSCircleAssertStable(circle
);
862 return CFSetContainsValue(circle
->applicants
, peerInfo
);
865 CFMutableSetRef
SOSCircleCopyApplicants(SOSCircleRef circle
, CFAllocatorRef allocator
) {
866 SOSCircleAssertStable(circle
);
868 return CFSetCreateMutableCopy(allocator
, 0, circle
->applicants
);
871 int SOSCircleCountRejectedApplicants(SOSCircleRef circle
) {
872 SOSCircleAssertStable(circle
);
874 return (int)CFSetGetCount(circle
->rejected_applicants
);
877 bool SOSCircleHasRejectedApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
878 SOSCircleAssertStable(circle
);
879 return CFSetContainsValue(circle
->rejected_applicants
, peerInfo
);
882 SOSPeerInfoRef
SOSCircleCopyRejectedApplicant(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
883 SOSCircleAssertStable(circle
);
884 return CFRetainSafe((SOSPeerInfoRef
)CFSetGetValue(circle
->rejected_applicants
, peerInfo
));
887 CFMutableArrayRef
SOSCircleCopyRejectedApplicants(SOSCircleRef circle
, CFAllocatorRef allocator
) {
888 SOSCircleAssertStable(circle
);
890 return CFSetCopyValuesCFArray(circle
->rejected_applicants
);
894 bool SOSCircleHasPeerWithID(SOSCircleRef circle
, CFStringRef peerid
, CFErrorRef
*error
) {
895 SOSCircleAssertStable(circle
);
896 __block
bool found
= false;
897 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
898 if(peerid
&& peer
&& CFEqualSafe(peerid
, SOSPeerInfoGetPeerID(peer
))) found
= true;
903 SOSPeerInfoRef
SOSCircleCopyPeerWithID(SOSCircleRef circle
, CFStringRef peerid
, CFErrorRef
*error
) {
904 SOSCircleAssertStable(circle
);
905 __block SOSPeerInfoRef found
= false;
906 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
907 if(peerid
&& peer
&& CFEqualSafe(peerid
, SOSPeerInfoGetPeerID(peer
))) found
= peer
;
912 bool SOSCircleHasPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
913 if(!peerInfo
) return false;
914 return SOSCircleHasPeerWithID(circle
, SOSPeerInfoGetPeerID(peerInfo
), error
);
917 bool SOSCircleHasActivePeerWithID(SOSCircleRef circle
, CFStringRef peerid
, CFErrorRef
*error
) {
918 SOSCircleAssertStable(circle
);
919 __block
bool found
= false;
920 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
921 if(peerid
&& peer
&& CFEqualSafe(peerid
, SOSPeerInfoGetPeerID(peer
))) found
= true;
926 bool SOSCircleHasActivePeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
927 if(!peerInfo
) return false;
928 return SOSCircleHasActivePeerWithID(circle
, SOSPeerInfoGetPeerID(peerInfo
), error
);
931 bool SOSCircleHasActiveValidPeerWithID(SOSCircleRef circle
, CFStringRef peerid
, SecKeyRef user_public_key
, CFErrorRef
*error
) {
932 SOSCircleAssertStable(circle
);
933 __block
bool found
= false;
934 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
935 if(peerid
&& peer
&& CFEqualSafe(peerid
, SOSPeerInfoGetPeerID(peer
)) && SOSPeerInfoApplicationVerify(peer
, user_public_key
, NULL
)) found
= true;
940 bool SOSCircleHasActiveValidPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, SecKeyRef user_public_key
, CFErrorRef
*error
) {
941 if(!peerInfo
) return false;
942 return SOSCircleHasActiveValidPeerWithID(circle
, SOSPeerInfoGetPeerID(peerInfo
), user_public_key
, error
);
946 bool SOSCircleResetToEmpty(SOSCircleRef circle
, CFErrorRef
*error
) {
947 CFSetRemoveAllValues(circle
->applicants
);
948 CFSetRemoveAllValues(circle
->rejected_applicants
);
949 CFSetRemoveAllValues(circle
->peers
);
950 CFDictionaryRemoveAllValues(circle
->signatures
);
952 int64_t old_value
= SOSCircleGetGenerationSint(circle
);
954 SOSCircleGenerationSetValue(circle
, 0);
955 SOSCircleGenerationIncrement(circle
); // Increment to get high bits set.
957 int64_t new_value
= SOSCircleGetGenerationSint(circle
);
959 if (new_value
<= old_value
) {
960 int64_t new_new_value
= GenerationSetHighBits(new_value
, (old_value
>> 32) + 1);
961 SOSCircleGenerationSetValue(circle
, new_new_value
);
967 bool SOSCircleResetToOffering(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
){
969 return SOSCircleResetToEmpty(circle
, error
)
970 && SOSCircleRequestAdmission(circle
, user_privkey
, requestor
, error
)
971 && SOSCircleAcceptRequest(circle
, user_privkey
, requestor
, SOSFullPeerInfoGetPeerInfo(requestor
), error
);
974 bool SOSCircleRemoveRetired(SOSCircleRef circle
, CFErrorRef
*error
) {
975 CFSetRemoveAllPassing(circle
->peers
, ^ bool (const void *element
) {
976 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) element
;
978 return SOSPeerInfoIsRetirementTicket(peer
);
984 static bool SOSCircleRecordAdmissionRequest(SOSCircleRef circle
, SecKeyRef user_pubkey
, SOSPeerInfoRef requestorPeerInfo
, CFErrorRef
*error
) {
985 SOSCircleAssertStable(circle
);
987 bool isPeer
= SOSCircleHasPeer(circle
, requestorPeerInfo
, error
);
989 require_action_quiet(!isPeer
, fail
, SOSCreateError(kSOSErrorAlreadyPeer
, CFSTR("Cannot request admission when already a peer"), NULL
, error
));
991 CFSetRemoveValue(circle
->rejected_applicants
, requestorPeerInfo
); // We remove from rejected list, in case?
992 CFSetSetValue(circle
->applicants
, requestorPeerInfo
);
1001 bool SOSCircleRequestReadmission(SOSCircleRef circle
, SecKeyRef user_pubkey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
1002 bool success
= false;
1004 require_quiet(SOSPeerInfoApplicationVerify(peer
, user_pubkey
, error
), fail
);
1005 success
= SOSCircleRecordAdmissionRequest(circle
, user_pubkey
, peer
, error
);
1010 bool SOSCircleRequestAdmission(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, CFErrorRef
*error
) {
1011 bool success
= false;
1013 SecKeyRef user_pubkey
= SecKeyCreatePublicFromPrivate(user_privkey
);
1014 require_action_quiet(user_pubkey
, fail
, SOSCreateError(kSOSErrorBadKey
, CFSTR("No public key for key"), NULL
, error
));
1016 require(SOSFullPeerInfoPromoteToApplication(requestor
, user_privkey
, error
), fail
);
1018 success
= SOSCircleRecordAdmissionRequest(circle
, user_pubkey
, SOSFullPeerInfoGetPeerInfo(requestor
), error
);
1020 CFReleaseNull(user_pubkey
);
1025 bool SOSCircleUpdatePeerInfo(SOSCircleRef circle
, SOSPeerInfoRef replacement_peer_info
) {
1026 if(!replacement_peer_info
) return false;
1027 CFTypeRef old
= CFSetGetValue(circle
->peers
, replacement_peer_info
);
1028 bool replace
= old
&& !CFEqualSafe(old
, replacement_peer_info
);
1030 CFSetReplaceValue(circle
->peers
, replacement_peer_info
);
1035 bool SOSCircleRemovePeer(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef requestor
, SOSPeerInfoRef peer_to_remove
, CFErrorRef
*error
) {
1036 SOSPeerInfoRef requestor_peer_info
= SOSFullPeerInfoGetPeerInfo(requestor
);
1038 if (SOSCircleHasApplicant(circle
, peer_to_remove
, error
)) {
1039 return SOSCircleRejectRequest(circle
, requestor
, peer_to_remove
, error
);
1042 if (!SOSCircleHasPeer(circle
, requestor_peer_info
, error
)) {
1043 SOSCreateError(kSOSErrorAlreadyPeer
, CFSTR("Must be peer to remove peer"), NULL
, error
);
1047 CFSetRemoveValue(circle
->peers
, peer_to_remove
);
1049 SOSCircleGenerationSign(circle
, user_privkey
, requestor
, error
);
1054 bool SOSCircleAcceptRequest(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef device_approver
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
1055 SOSCircleAssertStable(circle
);
1057 SecKeyRef publicKey
= NULL
;
1058 bool result
= false;
1060 require_action_quiet(CFSetContainsValue(circle
->applicants
, peerInfo
), fail
,
1061 SOSCreateError(kSOSErrorNotApplicant
, CFSTR("Cannot accept non-applicant"), NULL
, error
));
1063 publicKey
= SecKeyCreatePublicFromPrivate(user_privkey
);
1064 require_quiet(SOSPeerInfoApplicationVerify(peerInfo
, publicKey
, error
), fail
);
1066 CFSetRemoveValue(circle
->applicants
, peerInfo
);
1067 CFSetSetValue(circle
->peers
, peerInfo
);
1069 result
= SOSCircleGenerationSign(circle
, user_privkey
, device_approver
, error
);
1070 secnotice("circle", "Accepted %@", peerInfo
);
1073 CFReleaseNull(publicKey
);
1077 bool SOSCircleWithdrawRequest(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
1078 SOSCircleAssertStable(circle
);
1080 CFSetRemoveValue(circle
->applicants
, peerInfo
);
1085 bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
1086 SOSCircleAssertStable(circle
);
1088 CFSetRemoveValue(circle
->rejected_applicants
, peerInfo
);
1094 bool SOSCircleRejectRequest(SOSCircleRef circle
, SOSFullPeerInfoRef device_rejector
,
1095 SOSPeerInfoRef peerInfo
, CFErrorRef
*error
) {
1096 SOSCircleAssertStable(circle
);
1098 if (CFEqual(SOSPeerInfoGetPeerID(peerInfo
), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector
))))
1099 return SOSCircleWithdrawRequest(circle
, peerInfo
, error
);
1101 if (!CFSetContainsValue(circle
->applicants
, peerInfo
)) {
1102 SOSCreateError(kSOSErrorNotApplicant
, CFSTR("Cannot reject non-applicant"), NULL
, error
);
1106 CFSetRemoveValue(circle
->applicants
, peerInfo
);
1107 CFSetSetValue(circle
->rejected_applicants
, peerInfo
);
1109 // TODO: Maybe we sign the rejection with device_rejector.
1114 bool SOSCircleAcceptRequests(SOSCircleRef circle
, SecKeyRef user_privkey
, SOSFullPeerInfoRef device_approver
,
1115 CFErrorRef
*error
) {
1116 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1117 __block
bool result
= false;
1119 SOSCircleForEachApplicant(circle
, ^(SOSPeerInfoRef peer
) {
1120 if (!SOSCircleAcceptRequest(circle
, user_privkey
, device_approver
, peer
, error
))
1121 printf("error in SOSCircleAcceptRequest\n");
1123 secnotice("circle", "Accepted peer: %@", peer
);
1129 SOSCircleGenerationSign(circle
, user_privkey
, device_approver
, error
);
1130 secnotice("circle", "Countersigned accepted requests");
1136 bool SOSCirclePeerSigUpdate(SOSCircleRef circle
, SecKeyRef userPrivKey
, SOSFullPeerInfoRef fpi
,
1137 CFErrorRef
*error
) {
1138 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1139 __block
bool result
= false;
1140 SecKeyRef userPubKey
= SecKeyCreatePublicFromPrivate(userPrivKey
);
1142 // We're going to remove any applicants using a mismatched user key.
1143 SOSCircleForEachApplicant(circle
, ^(SOSPeerInfoRef peer
) {
1144 if(!SOSPeerInfoApplicationVerify(peer
, userPubKey
, NULL
)) {
1145 if(!SOSCircleRejectRequest(circle
, fpi
, peer
, NULL
)) {
1151 result
= SOSCircleUpdatePeerInfo(circle
, SOSFullPeerInfoGetPeerInfo(fpi
));
1154 SOSCircleGenerationSign(circle
, userPrivKey
, fpi
, error
);
1155 secnotice("circle", "Generation signed updated signatures on peerinfo");
1161 static inline void SOSCircleForEachPeerMatching(SOSCircleRef circle
,
1162 void (^action
)(SOSPeerInfoRef peer
),
1163 bool (^condition
)(SOSPeerInfoRef peer
)) {
1164 CFSetForEach(circle
->peers
, ^(const void *value
) {
1165 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) value
;
1166 if (condition(peer
))
1171 static inline bool isHiddenPeer(SOSPeerInfoRef peer
) {
1172 return SOSPeerInfoIsRetirementTicket(peer
) || SOSPeerInfoIsCloudIdentity(peer
);
1175 void SOSCircleForEachPeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1176 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1177 return !isHiddenPeer(peer
);
1181 void SOSCircleForEachRetiredPeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1182 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1183 return SOSPeerInfoIsRetirementTicket(peer
);
1187 void SOSCircleForEachActivePeer(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1188 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1193 void SOSCircleForEachActiveValidPeer(SOSCircleRef circle
, SecKeyRef user_public_key
, void (^action
)(SOSPeerInfoRef peer
)) {
1194 SOSCircleForEachPeerMatching(circle
, action
, ^bool(SOSPeerInfoRef peer
) {
1195 return SOSPeerInfoApplicationVerify(peer
, user_public_key
, NULL
);
1199 void SOSCircleForEachApplicant(SOSCircleRef circle
, void (^action
)(SOSPeerInfoRef peer
)) {
1200 CFSetForEach(circle
->applicants
, ^(const void*value
) { action((SOSPeerInfoRef
) value
); } );
1204 CFMutableSetRef
SOSCircleCopyPeers(SOSCircleRef circle
, CFAllocatorRef allocator
) {
1205 SOSCircleAssertStable(circle
);
1207 CFMutableSetRef result
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
1209 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
1210 CFSetAddValue(result
, peer
);
1216 bool SOSCircleAppendConcurringPeers(SOSCircleRef circle
, CFMutableArrayRef appendHere
, CFErrorRef
*error
) {
1217 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
1218 CFErrorRef localError
= NULL
;
1219 if (SOSCircleVerifyPeerSigned(circle
, peer
, &localError
)) {
1220 CFArrayAppendValue(appendHere
, peer
);
1221 } else if (error
!= NULL
) {
1222 secerror("Error checking concurrence: %@", localError
);
1224 CFReleaseNull(localError
);
1230 CFMutableArrayRef
SOSCircleCopyConcurringPeers(SOSCircleRef circle
, CFErrorRef
* error
) {
1231 SOSCircleAssertStable(circle
);
1233 CFMutableArrayRef concurringPeers
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
1235 if (!SOSCircleAppendConcurringPeers(circle
, concurringPeers
, error
))
1236 CFReleaseNull(concurringPeers
);
1238 return concurringPeers
;
1241 SOSFullPeerInfoRef
SOSCircleGetiCloudFullPeerInfoRef(SOSCircleRef circle
) {
1242 __block SOSFullPeerInfoRef cloud_full_peer
= NULL
;
1243 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
1244 if (SOSPeerInfoIsCloudIdentity(peer
)) {
1245 if (cloud_full_peer
== NULL
) {
1246 CFErrorRef localError
= NULL
;
1247 cloud_full_peer
= SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault
, peer
, &localError
);
1250 secerror("Found cloud peer in circle but can't make full peer: %@", localError
);
1251 CFReleaseNull(localError
);
1255 secerror("More than one cloud identity found in circle: %@", circle
);
1259 return cloud_full_peer
;