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