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