]> git.saurik.com Git - apple/security.git/blob - Security/sec/SOSCircle/SecureObjectSync/SOSCircle.c
Security-57031.1.35.tar.gz
[apple/security.git] / Security / 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 <SecureObjectSync/SOSCircle.h>
33 #include <SecureObjectSync/SOSCloudCircleInternal.h>
34 #include <SecureObjectSync/SOSInternal.h>
35 #include <SecureObjectSync/SOSEngine.h>
36 #include <SecureObjectSync/SOSPeer.h>
37 #include <SecureObjectSync/SOSPeerInfoCollections.h>
38 #include <CoreFoundation/CoreFoundation.h>
39 #include <Security/SecFramework.h>
40
41 #include <Security/SecKey.h>
42 #include <Security/SecKeyPriv.h>
43
44 #include <utilities/SecCFWrappers.h>
45 //#include "ckdUtilities.h"
46
47 #include <utilities/der_plist.h>
48 #include <utilities/der_plist_internal.h>
49
50 #include <corecrypto/ccder.h>
51 #include <corecrypto/ccdigest.h>
52 #include <corecrypto/ccsha2.h>
53
54 #include <stdlib.h>
55 #include <assert.h>
56
57 enum {
58 kOnlyCompatibleVersion = 1, // Sometime in the future this name will be improved to reflect history.
59
60 kAlwaysIncompatibleVersion = UINT64_MAX,
61 };
62
63 struct __OpaqueSOSCircle {
64 CFRuntimeBase _base;
65
66 CFStringRef name;
67 CFNumberRef generation;
68 CFMutableSetRef peers;
69 CFMutableSetRef applicants;
70 CFMutableSetRef rejected_applicants;
71
72 CFMutableDictionaryRef signatures;
73 };
74
75 CFGiblisWithCompareFor(SOSCircle);
76
77 SOSCircleRef SOSCircleCreate(CFAllocatorRef allocator, CFStringRef name, CFErrorRef *error) {
78 SOSCircleRef c = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
79 int64_t gen = 1;
80
81 assert(name);
82
83 c->name = CFStringCreateCopy(allocator, name);
84 c->generation = CFNumberCreate(allocator, kCFNumberSInt64Type, &gen);
85 c->peers = CFSetCreateMutableForSOSPeerInfosByID(allocator);
86 c->applicants = CFSetCreateMutableForSOSPeerInfosByID(allocator);
87 c->rejected_applicants = CFSetCreateMutableForSOSPeerInfosByID(allocator);
88 c->signatures = CFDictionaryCreateMutableForCFTypes(allocator);
89
90 return c;
91 }
92
93 static CFNumberRef SOSCircleGenerationCopy(CFNumberRef generation) {
94 int64_t value;
95 CFAllocatorRef allocator = CFGetAllocator(generation);
96 CFNumberGetValue(generation, kCFNumberSInt64Type, &value);
97 return CFNumberCreate(allocator, kCFNumberSInt64Type, &value);
98 }
99
100 static CFMutableSetRef CFSetOfPeerInfoDeepCopy(CFAllocatorRef allocator, CFSetRef peerInfoSet)
101 {
102 __block CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
103 CFSetForEach(peerInfoSet, ^(const void *value) {
104 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
105 CFErrorRef localError = NULL;
106 SOSPeerInfoRef copiedPeer = SOSPeerInfoCreateCopy(allocator, pi, &localError);
107 if (copiedPeer) {
108 CFSetAddValue(result, copiedPeer);
109 } else {
110 secerror("Failed to copy peer: %@ (%@)", pi, localError);
111 }
112 CFReleaseSafe(copiedPeer);
113 CFReleaseSafe(localError);
114 });
115 return result;
116 }
117
118 SOSCircleRef SOSCircleCopyCircle(CFAllocatorRef allocator, SOSCircleRef otherCircle, CFErrorRef *error)
119 {
120 SOSCircleRef c = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
121
122 assert(otherCircle);
123 c->name = CFStringCreateCopy(allocator, otherCircle->name);
124 c->generation = SOSCircleGenerationCopy(otherCircle->generation);
125
126 c->peers = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->peers);
127 c->applicants = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->applicants);
128 c->rejected_applicants = CFSetOfPeerInfoDeepCopy(allocator, otherCircle->rejected_applicants);
129
130 c->signatures = CFDictionaryCreateMutableCopy(allocator, 0, otherCircle->signatures);
131
132 return c;
133 }
134
135 static inline
136 void SOSCircleAssertStable(SOSCircleRef circle)
137 {
138 assert(circle);
139 assert(circle->name);
140 assert(circle->generation);
141 assert(circle->peers);
142 assert(circle->applicants);
143 assert(circle->rejected_applicants);
144 assert(circle->signatures);
145 }
146
147 static inline
148 SOSCircleRef SOSCircleConvertAndAssertStable(CFTypeRef circleAsType)
149 {
150 if (CFGetTypeID(circleAsType) != SOSCircleGetTypeID())
151 return NULL;
152
153 SOSCircleRef circle = (SOSCircleRef) circleAsType;
154
155 SOSCircleAssertStable(circle);
156
157 return circle;
158 }
159
160 static Boolean SOSCircleCompare(CFTypeRef lhs, CFTypeRef rhs) {
161 if (CFGetTypeID(lhs) != SOSCircleGetTypeID()
162 || CFGetTypeID(rhs) != SOSCircleGetTypeID())
163 return false;
164
165 SOSCircleRef left = SOSCircleConvertAndAssertStable(lhs);
166 SOSCircleRef right = SOSCircleConvertAndAssertStable(rhs);
167
168 // TODO: we should be doing set equality for peers and applicants.
169 return NULL != left && NULL != right
170 && CFEqualSafe(left->generation, right->generation)
171 && SOSPeerInfoSetContainsIdenticalPeers(left->peers, right->peers)
172 && SOSPeerInfoSetContainsIdenticalPeers(left->applicants, right->applicants)
173 && SOSPeerInfoSetContainsIdenticalPeers(left->rejected_applicants, right->rejected_applicants)
174 && CFEqualSafe(left->signatures, right->signatures);
175 }
176
177 static CFMutableArrayRef CFSetCopyValuesCFArray(CFSetRef set)
178 {
179 CFIndex count = CFSetGetCount(set);
180
181 CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
182 if (count > 0) {
183 const void * values[count];
184 CFSetGetValues(set, values);
185 for (int current = 0; current < count; ++current) {
186 CFArrayAppendValue(result, values[current]);
187 }
188 }
189
190 return result;
191 }
192
193 static bool SOSCircleDigestArray(const struct ccdigest_info *di, CFMutableArrayRef array, void *hash_result, CFErrorRef *error)
194 {
195 __block bool success = true;
196 ccdigest_di_decl(di, array_digest);
197 const void * a_digest = array_digest;
198
199 ccdigest_init(di, array_digest);
200 CFArraySortValues(array, CFRangeMake(0, CFArrayGetCount(array)), SOSPeerInfoCompareByID, SOSPeerCmpPubKeyHash);
201 CFArrayForEach(array, ^(const void *peer) {
202 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes((SOSPeerInfoRef)peer, di, a_digest, error))
203 success = false;
204 });
205 ccdigest_final(di, array_digest, hash_result);
206
207 return success;
208 }
209
210 static bool SOSCircleDigestSet(const struct ccdigest_info *di, CFMutableSetRef set, void *hash_result, CFErrorRef *error)
211 {
212 CFMutableArrayRef values = CFSetCopyValuesCFArray(set);
213
214 bool result = SOSCircleDigestArray(di, values, hash_result, error);
215
216 CFReleaseSafe(values);
217
218 return result;
219 }
220
221
222 static bool SOSCircleHash(const struct ccdigest_info *di, SOSCircleRef circle, void *hash_result, CFErrorRef *error) {
223 ccdigest_di_decl(di, circle_digest);
224 ccdigest_init(di, circle_digest);
225 int64_t gen = SOSCircleGetGenerationSint(circle);
226 ccdigest_update(di, circle_digest, sizeof(gen), &gen);
227
228 SOSCircleDigestSet(di, circle->peers, hash_result, error);
229 ccdigest_update(di, circle_digest, di->output_size, hash_result);
230 ccdigest_final(di, circle_digest, hash_result);
231 return true;
232 }
233
234 static bool SOSCircleSetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFDataRef signature, CFErrorRef *error) {
235 bool result = false;
236
237 CFStringRef pubKeyID = SOSCopyIDOfKey(pubkey, error);
238 require_quiet(pubKeyID, fail);
239 CFDictionarySetValue(circle->signatures, pubKeyID, signature);
240 result = true;
241
242 fail:
243 CFReleaseSafe(pubKeyID);
244 return result;
245 }
246
247 static bool SOSCircleRemoveSignatures(SOSCircleRef circle, CFErrorRef *error) {
248 CFDictionaryRemoveAllValues(circle->signatures);
249 return true;
250 }
251
252 static CFDataRef SOSCircleGetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFErrorRef *error) {
253 CFStringRef pubKeyID = SOSCopyIDOfKey(pubkey, error);
254 CFDataRef result = NULL;
255 require_quiet(pubKeyID, fail);
256
257 CFTypeRef value = (CFDataRef)CFDictionaryGetValue(circle->signatures, pubKeyID);
258
259 if (isData(value)) result = (CFDataRef) value;
260
261 fail:
262 CFReleaseSafe(pubKeyID);
263 return result;
264 }
265
266 bool SOSCircleSign(SOSCircleRef circle, SecKeyRef privKey, CFErrorRef *error) {
267 if (!privKey) return false; // Really assertion but not always true for now.
268 CFAllocatorRef allocator = CFGetAllocator(circle);
269 uint8_t tmp[4096];
270 size_t tmplen = 4096;
271 const struct ccdigest_info *di = ccsha256_di();
272 uint8_t hash_result[di->output_size];
273
274 SOSCircleHash(di, circle, hash_result, error);
275 OSStatus stat = SecKeyRawSign(privKey, kSecPaddingNone, hash_result, di->output_size, tmp, &tmplen);
276 if(stat) {
277 // TODO - Create a CFErrorRef;
278 secerror("Bad Circle SecKeyRawSign, stat: %ld", (long)stat);
279 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Circle SecKeyRawSign"), (error != NULL) ? *error : NULL, error);
280 return false;
281 };
282 CFDataRef signature = CFDataCreate(allocator, tmp, tmplen);
283 SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(privKey);
284 SOSCircleSetSignature(circle, publicKey, signature, error);
285 CFReleaseNull(publicKey);
286 CFRelease(signature);
287 return true;
288 }
289
290 bool SOSCircleVerifySignatureExists(SOSCircleRef circle, SecKeyRef pubKey, CFErrorRef *error) {
291 if(!pubKey) {
292 // TODO ErrorRef
293 secerror("SOSCircleVerifySignatureExists no pubKey");
294 SOSCreateError(kSOSErrorBadFormat, CFSTR("SOSCircleVerifySignatureExists no pubKey"), (error != NULL) ? *error : NULL, error);
295 return false;
296 }
297 CFDataRef signature = SOSCircleGetSignature(circle, pubKey, error);
298 return NULL != signature;
299 }
300
301 bool SOSCircleVerify(SOSCircleRef circle, SecKeyRef pubKey, CFErrorRef *error) {
302 const struct ccdigest_info *di = ccsha256_di();
303 uint8_t hash_result[di->output_size];
304
305 SOSCircleHash(di, circle, hash_result, error);
306
307 CFDataRef signature = SOSCircleGetSignature(circle, pubKey, error);
308 if(!signature) return false;
309
310 return SecKeyRawVerify(pubKey, kSecPaddingNone, hash_result, di->output_size,
311 CFDataGetBytePtr(signature), CFDataGetLength(signature)) == errSecSuccess;
312 }
313
314 bool SOSCircleVerifyPeerSigned(SOSCircleRef circle, SOSPeerInfoRef peer, CFErrorRef *error) {
315 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer);
316 bool result = SOSCircleVerify(circle, pub_key, error);
317 CFReleaseSafe(pub_key);
318 return result;
319 }
320
321 static void CFSetRemoveAllPassing(CFMutableSetRef set, bool (^test)(const void *) ){
322 CFMutableArrayRef toBeRemoved = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
323
324 CFSetForEach(set, ^(const void *value) {
325 if (test(value))
326 CFArrayAppendValue(toBeRemoved, value);
327 });
328
329 CFArrayForEach(toBeRemoved, ^(const void *value) {
330 CFSetRemoveValue(set, value);
331 });
332 CFReleaseNull(toBeRemoved);
333 }
334
335 static void SOSCircleRejectNonValidApplicants(SOSCircleRef circle, SecKeyRef pubkey) {
336 CFMutableSetRef applicants = SOSCircleCopyApplicants(circle, NULL);
337 CFSetForEach(applicants, ^(const void *value) {
338 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
339 if(!SOSPeerInfoApplicationVerify(pi, pubkey, NULL)) {
340 CFSetRemoveValue(circle->applicants, pi);
341 CFSetSetValue(circle->rejected_applicants, pi);
342 }
343 });
344 CFReleaseNull(applicants);
345 }
346
347 static SOSPeerInfoRef SOSCircleCopyPeerInfo(SOSCircleRef circle, CFStringRef peer_id, CFErrorRef *error) {
348 __block SOSPeerInfoRef result = NULL;
349
350 CFSetForEach(circle->peers, ^(const void *value) {
351 if (result == NULL) {
352 SOSPeerInfoRef tpi = (SOSPeerInfoRef)value;
353 if (CFEqual(SOSPeerInfoGetPeerID(tpi), peer_id))
354 result = tpi;
355 }
356 });
357
358 CFRetainSafe(result);
359 return result;
360 }
361
362 static bool SOSCircleUpgradePeerInfo(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo) {
363 bool retval = false;
364 SecKeyRef userPubKey = SecKeyCreatePublicFromPrivate(user_approver);
365 SOSPeerInfoRef fpi_pi = SOSFullPeerInfoGetPeerInfo(peerinfo);
366 SOSPeerInfoRef pi = SOSCircleCopyPeerInfo(circle, SOSPeerInfoGetPeerID(fpi_pi), NULL);
367 require_quiet(pi, out);
368 require_quiet(SOSPeerInfoApplicationVerify(pi, userPubKey, NULL), re_sign);
369 CFReleaseNull(userPubKey);
370 CFReleaseNull(pi);
371 return true;
372
373 re_sign:
374 secerror("SOSCircleGenerationSign: Upgraded peer's Application Signature");
375 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peerinfo, NULL);
376 require_quiet(device_key, out);
377 SOSPeerInfoRef new_pi = SOSPeerInfoCopyAsApplication(pi, user_approver, device_key, NULL);
378 if(SOSCircleUpdatePeerInfo(circle, new_pi))
379 retval = true;
380 CFReleaseNull(new_pi);
381 CFReleaseNull(device_key);
382 out:
383 CFReleaseNull(userPubKey);
384 CFReleaseNull(pi);
385 return retval;
386 }
387
388 bool SOSCircleGenerationSign(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
389 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
390 SecKeyRef publicKey = NULL;
391 require_quiet(ourKey, fail);
392
393 // Check if we're using an invalid peerinfo for this op. There are cases where we might not be "upgraded".
394 require_quiet(SOSCircleUpgradePeerInfo(circle, user_approver, peerinfo), fail);
395 SOSCircleRemoveRetired(circle, error); // Prune off retirees since we're signing this one
396 CFSetRemoveAllValues(circle->rejected_applicants); // Dump rejects so we clean them up sometime.
397 publicKey = SecKeyCreatePublicFromPrivate(user_approver);
398 SOSCircleRejectNonValidApplicants(circle, publicKey);
399 SOSCircleGenerationIncrement(circle);
400 require_quiet(SOSCircleRemoveSignatures(circle, error), fail);
401 require_quiet(SOSCircleSign(circle, user_approver, error), fail);
402 require_quiet(SOSCircleSign(circle, ourKey, error), fail);
403
404 CFReleaseNull(ourKey);
405 CFReleaseNull(publicKey);
406 return true;
407
408 fail:
409 CFReleaseNull(ourKey);
410 CFReleaseNull(publicKey);
411 return false;
412 }
413
414 bool SOSCircleGenerationUpdate(SOSCircleRef circle, SecKeyRef user_approver, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
415
416 return SOSCircleGenerationSign(circle, user_approver, peerinfo, error);
417
418 #if 0
419 bool success = false;
420
421 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
422 require_quiet(ourKey, fail);
423
424 require_quiet(SOSCircleSign(circle, user_approver, error), fail);
425 require_quiet(SOSCircleSign(circle, ourKey, error), fail);
426
427 success = true;
428
429 fail:
430 CFReleaseNull(ourKey);
431 return success;
432 #endif
433 }
434
435 bool SOSCircleConcordanceSign(SOSCircleRef circle, SOSFullPeerInfoRef peerinfo, CFErrorRef *error) {
436 bool success = false;
437 SecKeyRef ourKey = SOSFullPeerInfoCopyDeviceKey(peerinfo, error);
438 require_quiet(ourKey, exit);
439
440 success = SOSCircleSign(circle, ourKey, error);
441
442 exit:
443 CFReleaseNull(ourKey);
444 return success;
445 }
446
447 static inline SOSConcordanceStatus CheckPeerStatus(SOSCircleRef circle, SOSPeerInfoRef peer, SecKeyRef user_public_key, CFErrorRef *error) {
448 SOSConcordanceStatus result = kSOSConcordanceNoPeer;
449 SecKeyRef pubKey = SOSPeerInfoCopyPubKey(peer);
450
451 require_action_quiet(SOSCircleHasActiveValidPeer(circle, peer, user_public_key, error), exit, result = kSOSConcordanceNoPeer);
452 require_action_quiet(SOSCircleVerifySignatureExists(circle, pubKey, error), exit, result = kSOSConcordanceNoPeerSig);
453 require_action_quiet(SOSCircleVerify(circle, pubKey, error), exit, result = kSOSConcordanceBadPeerSig);
454
455 result = kSOSConcordanceTrusted;
456
457 exit:
458 CFReleaseNull(pubKey);
459 return result;
460 }
461
462 static inline SOSConcordanceStatus CombineStatus(SOSConcordanceStatus status1, SOSConcordanceStatus status2)
463 {
464 if (status1 == kSOSConcordanceTrusted || status2 == kSOSConcordanceTrusted)
465 return kSOSConcordanceTrusted;
466
467 if (status1 == kSOSConcordanceBadPeerSig || status2 == kSOSConcordanceBadPeerSig)
468 return kSOSConcordanceBadPeerSig;
469
470 if (status1 == kSOSConcordanceNoPeerSig || status2 == kSOSConcordanceNoPeerSig)
471 return kSOSConcordanceNoPeerSig;
472
473 return status1;
474 }
475
476 static inline bool SOSCircleIsEmpty(SOSCircleRef circle) {
477 return SOSCircleCountPeers(circle) == 0;
478 }
479
480 static inline bool SOSCircleIsOffering(SOSCircleRef circle) {
481 return SOSCircleCountPeers(circle) == 1;
482 }
483
484 __unused static inline bool SOSCircleIsResignOffering(SOSCircleRef circle, SecKeyRef pubkey) {
485 return SOSCircleCountActiveValidPeers(circle, pubkey) == 1;
486 }
487
488 static inline SOSConcordanceStatus GetSignersStatus(SOSCircleRef signers_circle, SOSCircleRef status_circle,
489 SecKeyRef user_pubKey, SOSPeerInfoRef exclude, CFErrorRef *error) {
490 CFStringRef excluded_id = exclude ? SOSPeerInfoGetPeerID(exclude) : NULL;
491
492 __block SOSConcordanceStatus status = kSOSConcordanceNoPeer;
493 SOSCircleForEachActivePeer(signers_circle, ^(SOSPeerInfoRef peer) {
494 SOSConcordanceStatus peerStatus = CheckPeerStatus(status_circle, peer, user_pubKey, error);
495
496 if (peerStatus == kSOSConcordanceNoPeerSig &&
497 (CFEqualSafe(SOSPeerInfoGetPeerID(peer), excluded_id) || SOSPeerInfoIsCloudIdentity(peer)))
498 peerStatus = kSOSConcordanceNoPeer;
499
500 status = CombineStatus(status, peerStatus); // TODO: Use multiple error gathering.
501 });
502
503 return status;
504 }
505
506 static inline bool isOlderGeneration(SOSCircleRef current, SOSCircleRef proposed) {
507 return CFNumberCompare(current->generation, proposed->generation, NULL) == kCFCompareGreaterThan;
508 }
509
510 bool SOSCircleSharedTrustedPeers(SOSCircleRef current, SOSCircleRef proposed, SOSPeerInfoRef me) {
511 __block bool retval = false;
512 SOSCircleForEachPeer(current, ^(SOSPeerInfoRef peer) {
513 if(!CFEqual(me, peer) && SOSCircleHasPeer(proposed, peer, NULL)) retval = true;
514 });
515 return retval;
516 }
517
518 static void SOSCircleUpgradePeersByCircle(SOSCircleRef known_circle, SOSCircleRef proposed_circle) {
519 SOSCircleForEachPeer(known_circle, ^(SOSPeerInfoRef known_peer) {
520 SOSPeerInfoRef proposed_peer = SOSCircleCopyPeerInfo(proposed_circle, SOSPeerInfoGetPeerID(known_peer), NULL);
521 if(proposed_peer && CFEqualSafe(proposed_peer, known_peer) != 0) {
522 SOSCircleUpdatePeerInfo(known_circle, proposed_peer);
523 }
524 });
525 }
526
527 SOSConcordanceStatus SOSCircleConcordanceTrust(SOSCircleRef known_circle, SOSCircleRef proposed_circle,
528 SecKeyRef known_pubkey, SecKeyRef user_pubkey,
529 SOSPeerInfoRef exclude, CFErrorRef *error) {
530 if(user_pubkey == NULL) {
531 SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Concordance with no public key"), NULL, error);
532 return kSOSConcordanceNoUserKey; //TODO: - needs to return an error
533 }
534
535 if (SOSCircleIsEmpty(proposed_circle)) {
536 return kSOSConcordanceTrusted;
537 }
538
539 if(!SOSCircleVerifySignatureExists(proposed_circle, user_pubkey, error)) {
540 SOSCreateError(kSOSErrorBadSignature, CFSTR("No public signature"), (error != NULL) ? *error : NULL, error);
541 return kSOSConcordanceNoUserSig;
542 }
543
544 if(!SOSCircleVerify(proposed_circle, user_pubkey, error)) {
545 SOSCreateError(kSOSErrorBadSignature, CFSTR("Bad public signature"), (error != NULL) ? *error : NULL, error);
546 return kSOSConcordanceBadUserSig;
547 }
548
549 if (SOSCircleIsEmpty(known_circle) || SOSCircleIsOffering(proposed_circle)) {
550 return GetSignersStatus(proposed_circle, proposed_circle, user_pubkey, NULL, error);
551 }
552
553 if(isOlderGeneration(known_circle, proposed_circle)) {
554 SOSCreateError(kSOSErrorReplay, CFSTR("Bad generation"), NULL, error);
555 return kSOSConcordanceGenOld;
556 }
557
558
559 if(!SOSCircleVerify(known_circle, user_pubkey, error)) {
560 SOSCircleUpgradePeersByCircle(known_circle, proposed_circle);
561 }
562
563 if(known_pubkey == NULL) known_pubkey = user_pubkey;
564 if(!SOSCircleVerify(known_circle, known_pubkey, error)) known_pubkey = user_pubkey;
565 return GetSignersStatus(known_circle, proposed_circle, known_pubkey, exclude, error);
566 }
567
568
569 static const uint8_t* der_decode_mutable_dictionary(CFAllocatorRef allocator, CFOptionFlags mutability,
570 CFMutableDictionaryRef* dictionary, CFErrorRef *error,
571 const uint8_t* der, const uint8_t *der_end)
572 {
573 CFDictionaryRef theDict;
574 const uint8_t* result = der_decode_dictionary(allocator, mutability, &theDict, error, der, der_end);
575
576 if (result != NULL)
577 *dictionary = (CFMutableDictionaryRef)theDict;
578
579 return result;
580 }
581
582
583 SOSCircleRef SOSCircleCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
584 const uint8_t** der_p, const uint8_t *der_end) {
585 SOSCircleRef cir = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
586
587 const uint8_t *sequence_end;
588
589 cir->name = NULL;
590 cir->generation = NULL;
591 cir->peers = NULL;
592 cir->applicants = NULL;
593 cir->rejected_applicants = NULL;
594 cir->signatures = NULL;
595
596 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
597 require_action_quiet(sequence_end != NULL, fail,
598 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Circle DER"), (error != NULL) ? *error : NULL, error));
599
600 // Version first.
601 uint64_t version = 0;
602 *der_p = ccder_decode_uint64(&version, *der_p, der_end);
603
604 require_action_quiet(version == kOnlyCompatibleVersion, fail,
605 SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("Bad Circle Version"), NULL, error));
606
607 *der_p = der_decode_string(allocator, 0, &cir->name, error, *der_p, sequence_end);
608 *der_p = der_decode_number(allocator, 0, &cir->generation, error, *der_p, sequence_end);
609
610 cir->peers = SOSPeerInfoSetCreateFromArrayDER(allocator, &kSOSPeerSetCallbacks, error, der_p, sequence_end);
611 cir->applicants = SOSPeerInfoSetCreateFromArrayDER(allocator, &kSOSPeerSetCallbacks, error, der_p, sequence_end);
612 cir->rejected_applicants = SOSPeerInfoSetCreateFromArrayDER(allocator, &kSOSPeerSetCallbacks, error, der_p, sequence_end);
613
614 *der_p = der_decode_mutable_dictionary(allocator, kCFPropertyListMutableContainersAndLeaves,
615 &cir->signatures, error, *der_p, sequence_end);
616
617 require_action_quiet(*der_p == sequence_end, fail,
618 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Circle DER"), (error != NULL) ? *error : NULL, error));
619
620 return cir;
621
622 fail:
623 CFReleaseNull(cir);
624 return NULL;
625 }
626
627 SOSCircleRef SOSCircleCreateFromData(CFAllocatorRef allocator, CFDataRef circleData, CFErrorRef *error)
628 {
629 size_t size = CFDataGetLength(circleData);
630 const uint8_t *der = CFDataGetBytePtr(circleData);
631 SOSCircleRef inflated = SOSCircleCreateFromDER(allocator, error, &der, der + size);
632 return inflated;
633 }
634
635 size_t SOSCircleGetDEREncodedSize(SOSCircleRef cir, CFErrorRef *error) {
636 SOSCircleAssertStable(cir);
637 size_t total_payload = 0;
638
639 require_quiet(accumulate_size(&total_payload, ccder_sizeof_uint64(kOnlyCompatibleVersion)), fail);
640 require_quiet(accumulate_size(&total_payload, der_sizeof_string(cir->name, error)), fail);
641 require_quiet(accumulate_size(&total_payload, der_sizeof_number(cir->generation, error)), fail);
642 require_quiet(accumulate_size(&total_payload, SOSPeerInfoSetGetDEREncodedArraySize(cir->peers, error)), fail);
643 require_quiet(accumulate_size(&total_payload, SOSPeerInfoSetGetDEREncodedArraySize(cir->applicants, error)), fail);
644 require_quiet(accumulate_size(&total_payload, SOSPeerInfoSetGetDEREncodedArraySize(cir->rejected_applicants, error)), fail);
645 require_quiet(accumulate_size(&total_payload, der_sizeof_dictionary((CFDictionaryRef) cir->signatures, error)), fail);
646
647 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, total_payload);
648
649 fail:
650 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error);
651 return 0;
652 }
653
654 uint8_t* SOSCircleEncodeToDER(SOSCircleRef cir, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) {
655 SOSCircleAssertStable(cir);
656
657 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
658 ccder_encode_uint64(kOnlyCompatibleVersion, der,
659 der_encode_string(cir->name, error, der,
660 der_encode_number(cir->generation, error, der,
661 SOSPeerInfoSetEncodeToArrayDER(cir->peers, error, der,
662 SOSPeerInfoSetEncodeToArrayDER(cir->applicants, error, der,
663 SOSPeerInfoSetEncodeToArrayDER(cir->rejected_applicants, error, der,
664 der_encode_dictionary((CFDictionaryRef) cir->signatures, error, der, der_end))))))));
665 }
666
667 CFDataRef SOSCircleCreateIncompatibleCircleDER(CFErrorRef* error)
668 {
669 size_t total_payload = 0;
670 size_t encoded_size = 0;
671 uint8_t* der = 0;
672 uint8_t* der_end = 0;
673 CFMutableDataRef result = NULL;
674
675 require_quiet(accumulate_size(&total_payload, ccder_sizeof_uint64(kAlwaysIncompatibleVersion)), fail);
676
677 encoded_size = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, total_payload);
678
679 result = CFDataCreateMutableWithScratch(kCFAllocatorDefault, encoded_size);
680
681 der = CFDataGetMutableBytePtr(result);
682 der_end = der + CFDataGetLength(result);
683
684 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
685 ccder_encode_uint64(kAlwaysIncompatibleVersion, der, der_end));
686
687 fail:
688 if (der == NULL || der != der_end)
689 CFReleaseNull(result);
690
691 return result;
692 }
693
694
695 CFDataRef SOSCircleCopyEncodedData(SOSCircleRef circle, CFAllocatorRef allocator, CFErrorRef *error)
696 {
697 size_t size = SOSCircleGetDEREncodedSize(circle, error);
698 if (size == 0)
699 return NULL;
700 uint8_t buffer[size];
701 uint8_t* start = SOSCircleEncodeToDER(circle, error, buffer, buffer + sizeof(buffer));
702 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
703 return result;
704 }
705
706 static void SOSCircleDestroy(CFTypeRef aObj) {
707 SOSCircleRef c = (SOSCircleRef) aObj;
708
709 CFReleaseNull(c->name);
710 CFReleaseNull(c->generation);
711 CFReleaseNull(c->peers);
712 CFReleaseNull(c->applicants);
713 CFReleaseNull(c->rejected_applicants);
714 CFReleaseNull(c->signatures);
715 }
716
717 static CFStringRef SOSCircleCopyDescription(CFTypeRef aObj) {
718 SOSCircleRef c = (SOSCircleRef) aObj;
719
720 SOSCircleAssertStable(c);
721
722
723 CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
724 CFStringAppendFormat(description, NULL, CFSTR("<SOSCircle@%p: '%@' P:["), c, c->name);
725
726 __block CFStringRef separator = CFSTR("");
727 SOSCircleForEachPeer(c, ^(SOSPeerInfoRef peer) {
728 CFStringRef sig = NULL;
729 if (SOSCircleVerifyPeerSigned(c, peer, NULL)) {
730 sig = CFSTR("√");
731 } else {
732 SecKeyRef pub_key = SOSPeerInfoCopyPubKey(peer);
733 CFDataRef signature = SOSCircleGetSignature(c, pub_key, NULL);
734 sig = (signature == NULL) ? CFSTR("-") : CFSTR("?");
735 CFReleaseNull(pub_key);
736 }
737
738 CFStringAppendFormat(description, NULL, CFSTR("%@%@ %@"), separator, peer, sig);
739 separator = CFSTR(",");
740 });
741
742 CFStringAppend(description, CFSTR("], A:["));
743 separator = CFSTR("");
744 SOSCircleForEachApplicant(c, ^(SOSPeerInfoRef peer) {
745 CFStringAppendFormat(description, NULL, CFSTR("%@%@"), separator, peer);
746 separator = CFSTR(",");
747 });
748
749 CFStringAppend(description, CFSTR("], R:["));
750 separator = CFSTR("");
751 CFSetForEach(c->rejected_applicants, ^(const void *value) {
752 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
753 CFStringAppendFormat(description, NULL, CFSTR("%@%@"), separator, peer);
754 separator = CFSTR(",");
755 });
756 CFStringAppend(description, CFSTR("]>"));
757
758 return description;
759 }
760
761 CFStringRef SOSCircleGetName(SOSCircleRef circle) {
762 assert(circle);
763 assert(circle->name);
764 return circle->name;
765 }
766
767 const char *SOSCircleGetNameC(SOSCircleRef circle) {
768 CFStringRef name = SOSCircleGetName(circle);
769 if (!name)
770 return strdup("");
771 return CFStringToCString(name);
772 }
773
774 CFNumberRef SOSCircleGetGeneration(SOSCircleRef circle) {
775 assert(circle);
776 assert(circle->generation);
777 return circle->generation;
778 }
779
780 int64_t SOSCircleGetGenerationSint(SOSCircleRef circle) {
781 CFNumberRef gen = SOSCircleGetGeneration(circle);
782 int64_t value;
783 if(!gen) return 0;
784 CFNumberGetValue(gen, kCFNumberSInt64Type, &value);
785 return value;
786 }
787
788 void SOSCircleGenerationSetValue(SOSCircleRef circle, int64_t value)
789 {
790 CFAllocatorRef allocator = CFGetAllocator(circle->generation);
791 CFAssignRetained(circle->generation, CFNumberCreate(allocator, kCFNumberSInt64Type, &value));
792 }
793
794
795 static int64_t GenerationSetHighBits(int64_t value, int32_t high_31)
796 {
797 value &= 0xFFFFFFFF; // Keep the low 32 bits.
798 value |= ((int64_t) high_31) << 32;
799
800 return value;
801 }
802
803
804 void SOSCircleGenerationIncrement(SOSCircleRef circle) {
805 int64_t value = SOSCircleGetGenerationSint(circle);
806
807 if ((value >> 32) == 0) {
808 uint32_t seconds = CFAbsoluteTimeGetCurrent(); // seconds
809 value = GenerationSetHighBits(value, (seconds >> 1));
810 }
811
812 value++;
813
814 SOSCircleGenerationSetValue(circle, value);
815 }
816
817 int SOSCircleCountPeers(SOSCircleRef circle) {
818 SOSCircleAssertStable(circle);
819 __block int count = 0;
820 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
821 ++count;
822 });
823 return count;
824 }
825
826 int SOSCircleCountActivePeers(SOSCircleRef circle) {
827 SOSCircleAssertStable(circle);
828 __block int count = 0;
829 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
830 ++count;
831 });
832 return count;
833 }
834
835 int SOSCircleCountActiveValidPeers(SOSCircleRef circle, SecKeyRef pubkey) {
836 SOSCircleAssertStable(circle);
837 __block int count = 0;
838 SOSCircleForEachActiveValidPeer(circle, pubkey, ^(SOSPeerInfoRef peer) {
839 ++count;
840 });
841 return count;
842 }
843
844 int SOSCircleCountRetiredPeers(SOSCircleRef circle) {
845 SOSCircleAssertStable(circle);
846 __block int count = 0;
847 SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) {
848 ++count;
849 });
850 return count;
851 }
852
853 int SOSCircleCountApplicants(SOSCircleRef circle) {
854 SOSCircleAssertStable(circle);
855
856 return (int)CFSetGetCount(circle->applicants);
857 }
858
859 bool SOSCircleHasApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
860 SOSCircleAssertStable(circle);
861
862 return CFSetContainsValue(circle->applicants, peerInfo);
863 }
864
865 CFMutableSetRef SOSCircleCopyApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
866 SOSCircleAssertStable(circle);
867
868 return CFSetCreateMutableCopy(allocator, 0, circle->applicants);
869 }
870
871 int SOSCircleCountRejectedApplicants(SOSCircleRef circle) {
872 SOSCircleAssertStable(circle);
873
874 return (int)CFSetGetCount(circle->rejected_applicants);
875 }
876
877 bool SOSCircleHasRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
878 SOSCircleAssertStable(circle);
879 return CFSetContainsValue(circle->rejected_applicants, peerInfo);
880 }
881
882 SOSPeerInfoRef SOSCircleCopyRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
883 SOSCircleAssertStable(circle);
884 return CFRetainSafe((SOSPeerInfoRef)CFSetGetValue(circle->rejected_applicants, peerInfo));
885 }
886
887 CFMutableArrayRef SOSCircleCopyRejectedApplicants(SOSCircleRef circle, CFAllocatorRef allocator) {
888 SOSCircleAssertStable(circle);
889
890 return CFSetCopyValuesCFArray(circle->rejected_applicants);
891 }
892
893
894 bool SOSCircleHasPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
895 SOSCircleAssertStable(circle);
896 __block bool found = false;
897 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
898 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = true;
899 });
900 return found;
901 }
902
903 SOSPeerInfoRef SOSCircleCopyPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
904 SOSCircleAssertStable(circle);
905 __block SOSPeerInfoRef found = false;
906 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
907 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = peer;
908 });
909 return found;
910 }
911
912 bool SOSCircleHasPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
913 return SOSCircleHasPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
914 }
915
916 bool SOSCircleHasActivePeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) {
917 SOSCircleAssertStable(circle);
918 __block bool found = false;
919 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
920 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer))) found = true;
921 });
922 return found;
923 }
924
925 bool SOSCircleHasActivePeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
926 if(!peerInfo) return false;
927 return SOSCircleHasActivePeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
928 }
929
930 bool SOSCircleHasActiveValidPeerWithID(SOSCircleRef circle, CFStringRef peerid, SecKeyRef user_public_key, CFErrorRef *error) {
931 SOSCircleAssertStable(circle);
932 __block bool found = false;
933 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
934 if(peerid && peer && CFEqualSafe(peerid, SOSPeerInfoGetPeerID(peer)) && SOSPeerInfoApplicationVerify(peer, user_public_key, NULL)) found = true;
935 });
936 return found;
937 }
938
939 bool SOSCircleHasActiveValidPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, SecKeyRef user_public_key, CFErrorRef *error) {
940 if(!peerInfo) return false;
941 return SOSCircleHasActiveValidPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), user_public_key, error);
942 }
943
944
945 bool SOSCircleResetToEmpty(SOSCircleRef circle, CFErrorRef *error) {
946 CFSetRemoveAllValues(circle->applicants);
947 CFSetRemoveAllValues(circle->rejected_applicants);
948 CFSetRemoveAllValues(circle->peers);
949 CFDictionaryRemoveAllValues(circle->signatures);
950
951 int64_t old_value = SOSCircleGetGenerationSint(circle);
952
953 SOSCircleGenerationSetValue(circle, 0);
954 SOSCircleGenerationIncrement(circle); // Increment to get high bits set.
955
956 int64_t new_value = SOSCircleGetGenerationSint(circle);
957
958 if (new_value <= old_value) {
959 int64_t new_new_value = GenerationSetHighBits(new_value, (old_value >> 32) + 1);
960 SOSCircleGenerationSetValue(circle, new_new_value);
961 }
962
963 return true;
964 }
965
966 bool SOSCircleResetToOffering(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error){
967
968 return SOSCircleResetToEmpty(circle, error)
969 && SOSCircleRequestAdmission(circle, user_privkey, requestor, error)
970 && SOSCircleAcceptRequest(circle, user_privkey, requestor, SOSFullPeerInfoGetPeerInfo(requestor), error);
971 }
972
973 bool SOSCircleRemoveRetired(SOSCircleRef circle, CFErrorRef *error) {
974 CFSetRemoveAllPassing(circle->peers, ^ bool (const void *element) {
975 SOSPeerInfoRef peer = (SOSPeerInfoRef) element;
976
977 return SOSPeerInfoIsRetirementTicket(peer);
978 });
979
980 return true;
981 }
982
983 static bool SOSCircleRecordAdmissionRequest(SOSCircleRef circle, SecKeyRef user_pubkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
984 SOSCircleAssertStable(circle);
985
986 SOSPeerInfoRef requestorPeerInfo = SOSFullPeerInfoGetPeerInfo(requestor);
987 bool isPeer = SOSCircleHasPeer(circle, SOSFullPeerInfoGetPeerInfo(requestor), error);
988
989 require_action_quiet(!isPeer, fail, SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Cannot request admission when already a peer"), NULL, error));
990
991 CFSetRemoveValue(circle->rejected_applicants, requestorPeerInfo); // We remove from rejected list, in case?
992 CFSetSetValue(circle->applicants, requestorPeerInfo);
993
994 return true;
995
996 fail:
997 return false;
998
999 }
1000
1001 bool SOSCircleRequestReadmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
1002 bool success = false;
1003
1004 SOSPeerInfoRef peer = SOSFullPeerInfoGetPeerInfo(requestor);
1005 require_quiet(SOSPeerInfoApplicationVerify(peer, user_pubkey, error), fail);
1006 success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, requestor, error);
1007 fail:
1008 return success;
1009 }
1010
1011 bool SOSCircleRequestAdmission(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
1012 bool success = false;
1013
1014 SecKeyRef user_pubkey = SecKeyCreatePublicFromPrivate(user_privkey);
1015 require_action_quiet(user_pubkey, fail, SOSCreateError(kSOSErrorBadKey, CFSTR("No public key for key"), NULL, error));
1016
1017 require(SOSFullPeerInfoPromoteToApplication(requestor, user_privkey, error), fail);
1018
1019 success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, requestor, error);
1020 fail:
1021 CFReleaseNull(user_pubkey);
1022 return success;
1023 }
1024
1025
1026 bool SOSCircleUpdatePeerInfo(SOSCircleRef circle, SOSPeerInfoRef replacement_peer_info) {
1027 if(!replacement_peer_info) return false;
1028 CFTypeRef old = CFSetGetValue(circle->peers, replacement_peer_info);
1029 bool replace = old && !CFEqualSafe(old, replacement_peer_info);
1030 if (replace)
1031 CFSetReplaceValue(circle->peers, replacement_peer_info);
1032
1033 return replace;
1034 }
1035
1036 bool SOSCircleRemovePeer(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, SOSPeerInfoRef peer_to_remove, CFErrorRef *error) {
1037 SOSPeerInfoRef requestor_peer_info = SOSFullPeerInfoGetPeerInfo(requestor);
1038
1039 if (SOSCircleHasApplicant(circle, peer_to_remove, error)) {
1040 return SOSCircleRejectRequest(circle, requestor, peer_to_remove, error);
1041 }
1042
1043 if (!SOSCircleHasPeer(circle, requestor_peer_info, error)) {
1044 SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Must be peer to remove peer"), NULL, error);
1045 return false;
1046 }
1047
1048 CFSetRemoveValue(circle->peers, peer_to_remove);
1049
1050 SOSCircleGenerationSign(circle, user_privkey, requestor, error);
1051
1052 return true;
1053 }
1054
1055 bool SOSCircleAcceptRequest(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1056 SOSCircleAssertStable(circle);
1057
1058 SecKeyRef publicKey = NULL;
1059 bool result = false;
1060
1061 require_action_quiet(CFSetContainsValue(circle->applicants, peerInfo), fail,
1062 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot accept non-applicant"), NULL, error));
1063
1064 publicKey = SecKeyCreatePublicFromPrivate(user_privkey);
1065 require_quiet(SOSPeerInfoApplicationVerify(peerInfo, publicKey, error), fail);
1066
1067 CFSetRemoveValue(circle->applicants, peerInfo);
1068 CFSetSetValue(circle->peers, peerInfo);
1069
1070 result = SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
1071 secnotice("circle", "Accepted %@", peerInfo);
1072
1073 fail:
1074 CFReleaseNull(publicKey);
1075 return result;
1076 }
1077
1078 bool SOSCircleWithdrawRequest(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1079 SOSCircleAssertStable(circle);
1080
1081 CFSetRemoveValue(circle->applicants, peerInfo);
1082
1083 return true;
1084 }
1085
1086 bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1087 SOSCircleAssertStable(circle);
1088
1089 CFSetRemoveValue(circle->rejected_applicants, peerInfo);
1090
1091 return true;
1092 }
1093
1094
1095 bool SOSCircleRejectRequest(SOSCircleRef circle, SOSFullPeerInfoRef device_rejector,
1096 SOSPeerInfoRef peerInfo, CFErrorRef *error) {
1097 SOSCircleAssertStable(circle);
1098
1099 if (CFEqual(SOSPeerInfoGetPeerID(peerInfo), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector))))
1100 return SOSCircleWithdrawRequest(circle, peerInfo, error);
1101
1102 if (!CFSetContainsValue(circle->applicants, peerInfo)) {
1103 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot reject non-applicant"), NULL, error);
1104 return false;
1105 }
1106
1107 CFSetRemoveValue(circle->applicants, peerInfo);
1108 CFSetSetValue(circle->rejected_applicants, peerInfo);
1109
1110 // TODO: Maybe we sign the rejection with device_rejector.
1111
1112 return true;
1113 }
1114
1115 bool SOSCircleAcceptRequests(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver,
1116 CFErrorRef *error) {
1117 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1118 __block bool result = false;
1119
1120 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
1121 if (!SOSCircleAcceptRequest(circle, user_privkey, device_approver, peer, error))
1122 printf("error in SOSCircleAcceptRequest\n");
1123 else {
1124 secnotice("circle", "Accepted peer: %@", peer);
1125 result = true;
1126 }
1127 });
1128
1129 if (result) {
1130 SOSCircleGenerationSign(circle, user_privkey, device_approver, error);
1131 secnotice("circle", "Countersigned accepted requests");
1132 }
1133
1134 return result;
1135 }
1136
1137 bool SOSCirclePeerSigUpdate(SOSCircleRef circle, SecKeyRef userPrivKey, SOSFullPeerInfoRef fpi,
1138 CFErrorRef *error) {
1139 // Returns true if we accepted someone and therefore have to post the circle back to KVS
1140 __block bool result = false;
1141 SecKeyRef userPubKey = SecKeyCreatePublicFromPrivate(userPrivKey);
1142
1143 // We're going to remove any applicants using a mismatched user key.
1144 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
1145 if(!SOSPeerInfoApplicationVerify(peer, userPubKey, NULL)) {
1146 if(!SOSCircleRejectRequest(circle, fpi, peer, NULL)) {
1147 // do we care?
1148 }
1149 }
1150 });
1151
1152 result = SOSCircleUpdatePeerInfo(circle, SOSFullPeerInfoGetPeerInfo(fpi));
1153
1154 if (result) {
1155 SOSCircleGenerationSign(circle, userPrivKey, fpi, error);
1156 secnotice("circle", "Generation signed updated signatures on peerinfo");
1157 }
1158
1159 return result;
1160 }
1161
1162 static inline void SOSCircleForEachPeerMatching(SOSCircleRef circle,
1163 void (^action)(SOSPeerInfoRef peer),
1164 bool (^condition)(SOSPeerInfoRef peer)) {
1165 CFSetForEach(circle->peers, ^(const void *value) {
1166 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
1167 if (condition(peer))
1168 action(peer);
1169 });
1170 }
1171
1172 static inline bool isHiddenPeer(SOSPeerInfoRef peer) {
1173 return SOSPeerInfoIsRetirementTicket(peer) || SOSPeerInfoIsCloudIdentity(peer);
1174 }
1175
1176 void SOSCircleForEachPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1177 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1178 return !isHiddenPeer(peer);
1179 });
1180 }
1181
1182 void SOSCircleForEachRetiredPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1183 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1184 return SOSPeerInfoIsRetirementTicket(peer);
1185 });
1186 }
1187
1188 void SOSCircleForEachActivePeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1189 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1190 return true;
1191 });
1192 }
1193
1194 void SOSCircleForEachActiveValidPeer(SOSCircleRef circle, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)) {
1195 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) {
1196 return SOSPeerInfoApplicationVerify(peer, user_public_key, NULL);
1197 });
1198 }
1199
1200 void SOSCircleForEachApplicant(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) {
1201 CFSetForEach(circle->applicants, ^(const void*value) { action((SOSPeerInfoRef) value); } );
1202 }
1203
1204
1205 CFMutableSetRef SOSCircleCopyPeers(SOSCircleRef circle, CFAllocatorRef allocator) {
1206 SOSCircleAssertStable(circle);
1207
1208 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator);
1209
1210 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
1211 CFSetAddValue(result, peer);
1212 });
1213
1214 return result;
1215 }
1216
1217 bool SOSCircleAppendConcurringPeers(SOSCircleRef circle, CFMutableArrayRef appendHere, CFErrorRef *error) {
1218 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1219 CFErrorRef localError = NULL;
1220 if (SOSCircleVerifyPeerSigned(circle, peer, &localError)) {
1221 CFArrayAppendValue(appendHere, peer);
1222 } else if (error != NULL) {
1223 secerror("Error checking concurrence: %@", localError);
1224 }
1225 CFReleaseNull(localError);
1226 });
1227
1228 return true;
1229 }
1230
1231 CFMutableArrayRef SOSCircleCopyConcurringPeers(SOSCircleRef circle, CFErrorRef* error) {
1232 SOSCircleAssertStable(circle);
1233
1234 CFMutableArrayRef concurringPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
1235
1236 if (!SOSCircleAppendConcurringPeers(circle, concurringPeers, error))
1237 CFReleaseNull(concurringPeers);
1238
1239 return concurringPeers;
1240 }
1241
1242 SOSFullPeerInfoRef SOSCircleGetiCloudFullPeerInfoRef(SOSCircleRef circle) {
1243 __block SOSFullPeerInfoRef cloud_full_peer = NULL;
1244 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
1245 if (SOSPeerInfoIsCloudIdentity(peer)) {
1246 if (cloud_full_peer == NULL) {
1247 CFErrorRef localError = NULL;
1248 cloud_full_peer = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, &localError);
1249
1250 if (localError) {
1251 secerror("Found cloud peer in circle but can't make full peer: %@", localError);
1252 CFReleaseNull(localError);
1253 }
1254
1255 } else {
1256 secerror("More than one cloud identity found in circle: %@", circle);
1257 }
1258 }
1259 });
1260 return cloud_full_peer;
1261 }