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