]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ProjectHeaders/Security/SecureObjectSync/SOSRingTypes.c
d5dd445e1656cc4f8a790a90600f646ed798de3f
[apple/security.git] / OSX / sec / ProjectHeaders / Security / SecureObjectSync / SOSRingTypes.c
1 //
2 // SOSRingTypes.c
3 // sec
4 //
5 // Created by Richard Murphy on 2/23/15.
6 //
7 //
8
9 #include "SOSRing.h"
10 #include "SOSRingTypes.h"
11 #include "SOSRingBasic.h"
12 #include "SOSRingBackup.h"
13 #include <Security/SecureObjectSync/SOSAccountPriv.h>
14 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
15
16 static ringFuncs ringTypes[] = {
17 &basic,
18 &backup,
19 };
20 static const size_t typecount = sizeof(ringTypes) / sizeof(ringFuncs);
21
22 static bool SOSRingValidType(SOSRingType type) {
23 return type < typecount;
24 }
25
26 // MARK: Exported Functions
27
28
29 SOSRingRef SOSRingCreate(CFStringRef name, CFStringRef myPeerID, SOSRingType type, CFErrorRef *error) {
30 require(SOSRingValidType(type), errOut);
31 require(ringTypes[type]->sosRingCreate, errOut);
32 return ringTypes[type]->sosRingCreate(name, myPeerID, error);
33 errOut:
34 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
35 return NULL;
36 }
37
38 bool SOSRingResetToEmpty(SOSRingRef ring, CFStringRef myPeerID, CFErrorRef *error) {
39 SOSRingAssertStable(ring);
40 SOSRingType type = SOSRingGetType(ring);
41 require(SOSRingValidType(type), errOut);
42 require(ringTypes[type]->sosRingResetToEmpty, errOut);
43 return ringTypes[type]->sosRingResetToEmpty(ring, myPeerID, error);
44 errOut:
45 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
46 return false;
47 }
48
49 bool SOSRingResetToOffering(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
50 SOSRingAssertStable(ring);
51 SOSRingType type = SOSRingGetType(ring);
52 require(SOSRingValidType(type), errOut);
53 require(ringTypes[type]->sosRingResetToOffering, errOut);
54 return ringTypes[type]->sosRingResetToOffering(ring, user_privkey, requestor, error);
55 errOut:
56 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
57 return false;
58 }
59
60 SOSRingStatus SOSRingDeviceIsInRing(SOSRingRef ring, CFStringRef peerID) {
61 SOSRingAssertStable(ring);
62 SOSRingType type = SOSRingGetType(ring);
63 require(SOSRingValidType(type), errOut);
64 require(ringTypes[type]->sosRingDeviceIsInRing, errOut);
65 return ringTypes[type]->sosRingDeviceIsInRing(ring, peerID);
66 errOut:
67 return kSOSRingError;
68 }
69
70 bool SOSRingApply(SOSRingRef ring, SecKeyRef user_pubkey, SOSFullPeerInfoRef fpi, CFErrorRef *error) {
71 SOSRingAssertStable(ring);
72 SOSRingType type = SOSRingGetType(ring);
73 require(SOSRingValidType(type), errOut);
74 require(ringTypes[type]->sosRingApply, shortCircuit);
75 require_quiet(SOSPeerInfoApplicationVerify(SOSFullPeerInfoGetPeerInfo(fpi), user_pubkey, error), errOut2);
76
77 return ringTypes[type]->sosRingApply(ring, user_pubkey, fpi, error);
78 errOut:
79 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
80 return false;
81 errOut2:
82 SOSCreateError(kSOSErrorBadSignature, CFSTR("FullPeerInfo fails userkey signature check"), NULL, error);
83 return false;
84 shortCircuit:
85 return true;
86 }
87
88 bool SOSRingWithdraw(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
89 SOSRingAssertStable(ring);
90 SOSRingType type = SOSRingGetType(ring);
91 require(SOSRingValidType(type), errOut);
92 require(ringTypes[type]->sosRingWithdraw, shortCircuit);
93 return ringTypes[type]->sosRingWithdraw(ring, user_privkey, requestor, error);
94 errOut:
95 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
96 return false;
97 shortCircuit:
98 return true;
99 }
100
101 bool SOSRingGenerationSign(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
102 SOSRingAssertStable(ring);
103 SOSRingType type = SOSRingGetType(ring);
104 require(SOSRingValidType(type), errOut);
105 require(ringTypes[type]->sosRingGenerationSign, shortCircuit);
106 return ringTypes[type]->sosRingGenerationSign(ring, user_privkey, requestor, error);
107 errOut:
108 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
109 return false;
110 shortCircuit:
111 return true;
112 }
113
114 bool SOSRingConcordanceSign(SOSRingRef ring, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
115 SOSRingAssertStable(ring);
116 SOSRingType type = SOSRingGetType(ring);
117 require(SOSRingValidType(type), errOut);
118 require(ringTypes[type]->sosRingConcordanceSign, shortCircuit);
119 return ringTypes[type]->sosRingConcordanceSign(ring, requestor, error);
120 errOut:
121 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
122 return false;
123 shortCircuit:
124 return true;
125 }
126
127 SOSConcordanceStatus SOSRingConcordanceTrust(SOSFullPeerInfoRef me, CFSetRef peers,
128 SOSRingRef knownRing, SOSRingRef proposedRing,
129 SecKeyRef knownPubkey, SecKeyRef userPubkey,
130 CFStringRef excludePeerID, CFErrorRef *error) {
131 SOSRingAssertStable(knownRing);
132 SOSRingAssertStable(proposedRing);
133 SOSRingType type1 = SOSRingGetType(knownRing);
134 SOSRingType type2 = SOSRingGetType(proposedRing);
135 require(SOSRingValidType(type1), errOut);
136 require(SOSRingValidType(type2), errOut);
137 require(type1 == type2, errOut);
138
139 secnotice("ring", "concordance trust (%s) knownRing: %@ proposedRing: %@ knownkey: %@ userkey: %@ excluded: %@",
140 ringTypes[type1]->typeName, knownRing, proposedRing, knownPubkey, userPubkey, excludePeerID);
141
142 require(ringTypes[type1]->sosRingConcordanceTrust, errOut);
143 return ringTypes[type1]->sosRingConcordanceTrust(me, peers, knownRing, proposedRing, knownPubkey, userPubkey, excludePeerID, error);
144 errOut:
145 return kSOSConcordanceError;
146 }
147
148 bool SOSRingAccept(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
149 SOSRingAssertStable(ring);
150 SOSRingType type = SOSRingGetType(ring);
151 require(SOSRingValidType(type), errOut);
152 require(ringTypes[type]->sosRingAccept, shortCircuit);
153 return ringTypes[type]->sosRingAccept(ring, user_privkey, requestor, error);
154 errOut:
155 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
156 return false;
157 shortCircuit:
158 return true;
159 }
160
161 bool SOSRingReject(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
162 SOSRingAssertStable(ring);
163 SOSRingType type = SOSRingGetType(ring);
164 require(SOSRingValidType(type), errOut);
165 require(ringTypes[type]->sosRingReject, shortCircuit);
166 return ringTypes[type]->sosRingReject(ring, user_privkey, requestor, error);
167 errOut:
168 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
169 return false;
170 shortCircuit:
171 return true;
172 }
173
174 bool SOSRingSetPayload(SOSRingRef ring, SecKeyRef user_privkey, CFDataRef payload, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
175 SOSRingAssertStable(ring);
176 SOSRingType type = SOSRingGetType(ring);
177 require(SOSRingValidType(type), errOut);
178 require(ringTypes[type]->sosRingSetPayload, errOut);
179 return ringTypes[type]->sosRingSetPayload(ring, user_privkey, payload, requestor, error);
180 errOut:
181 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
182 return false;
183 }
184
185 CFDataRef SOSRingGetPayload(SOSRingRef ring, CFErrorRef *error) {
186 SOSRingAssertStable(ring);
187 SOSRingType type = SOSRingGetType(ring);
188 require(SOSRingValidType(type), errOut);
189 require(ringTypes[type]->sosRingGetPayload, errOut);
190 return ringTypes[type]->sosRingGetPayload(ring, error);
191 errOut:
192 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
193 return false;
194 }
195
196 CFSetRef SOSRingGetBackupViewset(SOSRingRef ring, CFErrorRef *error) {
197 SOSRingAssertStable(ring);
198 SOSRingType type = SOSRingGetType(ring);
199 require(kSOSRingBackup == type, errOut);
200 return SOSRingGetBackupViewset_Internal(ring);
201 errOut:
202 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not backup ring type"), NULL, error);
203 return false;
204 }
205
206 static bool isBackupRing(SOSRingRef ring, CFErrorRef *error) {
207 SOSRingType type = SOSRingGetType(ring);
208 require_quiet(kSOSRingBackup == type, errOut);
209 return true;
210 errOut:
211 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not backup ring type"), NULL, error);
212 return false;
213 }
214
215 bool SOSRingSetBackupKeyBag(SOSRingRef ring, SOSFullPeerInfoRef fpi, CFSetRef viewSet, SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
216 SOSRingAssertStable(ring);
217 CFDataRef bskb_as_data = NULL;
218 bool result = false;
219 require_quiet(isBackupRing(ring, error), errOut);
220
221 bskb_as_data = SOSBSKBCopyEncoded(bskb, error);
222 result = bskb_as_data &&
223 SOSRingSetBackupViewset_Internal(ring, viewSet) &&
224 SOSRingSetPayload(ring, NULL, bskb_as_data, fpi, error);
225 errOut:
226 CFReleaseNull(bskb_as_data);
227 return result;
228 }
229
230 SOSBackupSliceKeyBagRef SOSRingCopyBackupSliceKeyBag(SOSRingRef ring, CFErrorRef *error) {
231 SOSRingAssertStable(ring);
232
233 CFDataRef bskb_as_data = NULL;
234 SOSBackupSliceKeyBagRef result = NULL;
235 require_quiet(isBackupRing(ring, error), errOut);
236
237 bskb_as_data = SOSRingGetPayload(ring, error);
238 require_quiet(bskb_as_data, errOut);
239
240 result = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, bskb_as_data, error);
241
242 errOut:
243 return result;
244 }
245
246
247 bool SOSRingPKTrusted(SOSRingRef ring, SecKeyRef pubkey, CFErrorRef *error) {
248 SOSRingAssertStable(ring);
249 SOSRingType type = SOSRingGetType(ring);
250 require(SOSRingValidType(type), errOut);
251 return SOSRingVerify(ring, pubkey, error);
252 errOut:
253 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error);
254 return false;
255 }
256
257 bool SOSRingPeerTrusted(SOSRingRef ring, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
258 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(requestor);
259 SecKeyRef pubkey = SOSPeerInfoCopyPubKey(pi);
260 bool retval = SOSRingPKTrusted(ring, pubkey, error);
261 CFReleaseNull(pubkey);
262 return retval;
263 }
264
265
266 #if 0
267 static inline
268 bool SOSAccountKnowsRings(SOSAccountRef account, CFErrorRef *error) {
269 if(account->rings) return true;
270 SOSCreateError(kSOSErrorUnsupported, CFSTR("This account doesn't support rings"), NULL, error);
271 return false;
272 }
273
274
275 // ViewRequirements
276 bool SOSRingRequirementKnown(SOSAccountRef account, CFStringRef name, CFErrorRef *error) {
277 bool retval = false;
278 require_quiet(SOSAccountKnowsRings(account, error), errOut);
279 retval = CFDictionaryContainsValue(account->rings, name);
280 errOut:
281 return retval;
282 }
283
284 bool SOSRingRequirementCreate(SOSAccountRef account, CFStringRef name, SOSRingType type, CFErrorRef *error) {
285 if(account->rings) return false;
286 if(CFDictionaryContainsValue(account->rings, name)) return true;
287 if(!SOSRingValidType(type)) return false;
288 SOSRingRef ring = SOSRingCreate(NULL, name, type, error);
289 if(!ring) return false;
290 CFDictionaryAddValue(account->rings, name, ring);
291 return false;
292 }
293
294 static SOSRingRef getRingFromAccount(SOSAccountRef account, CFStringRef name, CFErrorRef* error) {
295 SOSRingRef retval = NULL;
296 require_quiet(SOSAccountKnowsRings(account, error), errOut);
297 retval = (SOSRingRef) CFDictionaryGetValue(account->rings, name);
298
299 errOut:
300 return retval;
301
302 }
303
304 // Admins
305 bool SOSRingRequirementResetToOffering(SOSAccountRef account, CFStringRef name, CFErrorRef* error) {
306 SOSRingRef ring = getRingFromAccount(account, name, error);
307 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account);
308 require_action_quiet(ring, errOut,
309 SOSCreateError(kSOSErrorNoCircle, CFSTR("No ring by name specified"), NULL, error));
310 switch(SOSRingGetType(ring)) {
311
312 }
313 SOSRingResetToOffering(ring, account->__user_private, fpi, error);
314
315 errOut:
316 return false;
317 }
318
319
320 bool SOSRingRequirementResetToEmpty(SOSAccountRef account, CFStringRef name, CFErrorRef* error) {
321 return false;
322 }
323
324
325
326 // Clients
327 bool SOSRingRequirementRequestToJoin(SOSAccountRef account, CFStringRef name, CFErrorRef* error) {
328 return false;
329 }
330
331 bool SOSRingRequirementRemoveThisDevice(SOSAccountRef account, CFStringRef name, CFErrorRef* error) {
332 return false;
333 }
334
335 // Approvers
336 CFArrayRef SOSRingRequirementGetApplicants(SOSAccountRef account, CFStringRef name, CFErrorRef* error) {
337 return false;
338 }
339
340
341 bool SOSRingRequirementAcceptApplicants(SOSAccountRef account, CFStringRef name, CFArrayRef applicants, CFErrorRef* error) {
342 return false;
343 }
344
345
346 bool SOSRingRequirementRejectApplicants(SOSAccountRef account, CFStringRef name, CFArrayRef applicants, CFErrorRef *error) {
347 return false;
348 }
349
350
351 bool SOSRingResetToOffering(SOSCircleRef circle, SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error){
352
353 return SOSRingResetToEmpty(ring, error)
354 && SOSRingRequestAdmission(ring, user_privkey, requestor, error)
355 && SOSRingAcceptRequest(ring, user_privkey, requestor, SOSFullPeerInfoGetPeerInfo(requestor), error);
356 }
357
358
359 static bool SOSRingRecordAdmissionRequest(SOSRingRef ring, SecKeyRef user_pubkey, CFStringRef peerID, CFErrorRef *error) {
360 SOSRingAssertStable(ring);
361
362 bool isPeer = SOSRingHasPeerWithID(ring, peerID, error);
363 require_action_quiet(!isPeer, fail, SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Cannot request admission when already a peer"), NULL, error));
364 CFSetRemoveValue(ring->rejections, requestorPeerInfo); // We remove from rejected list, in case?
365 CFSetSetValue(ring->applicants, requestorPeerInfo);
366
367 return true;
368
369 fail:
370 return false;
371
372 }
373
374 bool SOSRingRequestReadmission(SOSRingRef ring, SecKeyRef user_pubkey, SOSPeerInfoRef peer, CFErrorRef *error) {
375 bool success = false;
376
377 require_quiet(SOSPeerInfoApplicationVerify(peer, user_pubkey, error), fail);
378 success = SOSRingRecordAdmissionRequest(ring, user_pubkey, peer, error);
379 fail:
380 return success;
381 }
382
383 bool SOSRingRequestAdmission(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
384 bool success = false;
385
386 SecKeyRef user_pubkey = SecKeyCreatePublicFromPrivate(user_privkey);
387 require_action_quiet(user_pubkey, fail, SOSCreateError(kSOSErrorBadKey, CFSTR("No public key for key"), NULL, error));
388
389 require(SOSFullPeerInfoPromoteToApplication(requestor, user_privkey, error), fail);
390
391 success = SOSRingRecordAdmissionRequest(ring, user_pubkey, SOSFullPeerInfoGetPeerInfo(requestor), error);
392 fail:
393 CFReleaseNull(user_pubkey);
394 return success;
395 }
396
397
398 bool SOSRingRemovePeer(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, SOSPeerInfoRef peer_to_remove, CFErrorRef *error) {
399 SOSPeerInfoRef requestor_peer_info = SOSFullPeerInfoGetPeerInfo(requestor);
400
401 if (SOSRingHasApplicant(ring, peer_to_remove, error)) {
402 return SOSRingRejectRequest(ring, requestor, peer_to_remove, error);
403 }
404
405 if (!SOSRingHasPeer(ring, requestor_peer_info, error)) {
406 SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Must be peer to remove peer"), NULL, error);
407 return false;
408 }
409
410 CFSetRemoveValue(ring->peers, peer_to_remove);
411
412 SOSRingGenerationSign(ring, user_privkey, requestor, error);
413
414 return true;
415 }
416
417 bool SOSRingAcceptRequest(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
418 SOSRingAssertStable(ring);
419
420 SecKeyRef publicKey = NULL;
421 bool result = false;
422
423 require_action_quiet(CFSetContainsValue(ring->applicants, peerInfo), fail,
424 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot accept non-applicant"), NULL, error));
425
426 publicKey = SecKeyCreatePublicFromPrivate(user_privkey);
427 require_quiet(SOSPeerInfoApplicationVerify(peerInfo, publicKey, error), fail);
428
429 CFSetRemoveValue(ring->applicants, peerInfo);
430 CFSetSetValue(ring->peers, peerInfo);
431
432 result = SOSRingGenerationSign(ring, user_privkey, device_approver, error);
433 secnotice("ring", "Accepted %@", peerInfo);
434
435 fail:
436 CFReleaseNull(publicKey);
437 return result;
438 }
439
440 bool SOSRingWithdrawRequest(SOSRingRef ring, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
441 SOSRingAssertStable(ring);
442
443 CFSetRemoveValue(ring->applicants, peerInfo);
444
445 return true;
446 }
447
448 bool SOSRingRemoveRejectedPeer(SOSRingRef ring, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
449 SOSRingAssertStable(ring);
450
451 CFSetRemoveValue(ring->rejected_applicants, peerInfo);
452
453 return true;
454 }
455
456
457 bool SOSRingRejectRequest(SOSRingRef ring, SOSFullPeerInfoRef device_rejector,
458 SOSPeerInfoRef peerInfo, CFErrorRef *error) {
459 SOSRingAssertStable(ring);
460
461 if (CFEqual(SOSPeerInfoGetPeerID(peerInfo), SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(device_rejector))))
462 return SOSRingWithdrawRequest(ring, peerInfo, error);
463
464 if (!CFSetContainsValue(ring->applicants, peerInfo)) {
465 SOSCreateError(kSOSErrorNotApplicant, CFSTR("Cannot reject non-applicant"), NULL, error);
466 return false;
467 }
468
469 CFSetRemoveValue(ring->applicants, peerInfo);
470 CFSetSetValue(ring->rejected_applicants, peerInfo);
471
472 // TODO: Maybe we sign the rejection with device_rejector.
473
474 return true;
475 }
476
477 bool SOSRingAcceptRequests(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver,
478 CFErrorRef *error) {
479 // Returns true if we accepted someone and therefore have to post the ring back to KVS
480 __block bool result = false;
481
482 SOSRingForEachApplicant(ring, ^(SOSPeerInfoRef peer) {
483 if (!SOSRingAcceptRequest(ring, user_privkey, device_approver, peer, error))
484 printf("error in SOSRingAcceptRequest\n");
485 else {
486 secnotice("ring", "Accepted peer: %@", peer);
487 result = true;
488 }
489 });
490
491 if (result) {
492 SOSRingGenerationSign(ring, user_privkey, device_approver, error);
493 secnotice("ring", "Countersigned accepted requests");
494 }
495
496 return result;
497 }
498
499 bool SOSRingPeerSigUpdate(SOSRingRef ring, SecKeyRef userPrivKey, SOSFullPeerInfoRef fpi,
500 CFErrorRef *error) {
501 // Returns true if we accepted someone and therefore have to post the ring back to KVS
502 __block bool result = false;
503 SecKeyRef userPubKey = SecKeyCreatePublicFromPrivate(userPrivKey);
504
505 // We're going to remove any applicants using a mismatched user key.
506 SOSRingForEachApplicant(ring, ^(SOSPeerInfoRef peer) {
507 if(!SOSPeerInfoApplicationVerify(peer, userPubKey, NULL)) {
508 if(!SOSRingRejectRequest(ring, fpi, peer, NULL)) {
509 // do we care?
510 }
511 }
512 });
513
514 result = SOSRingUpdatePeerInfo(ring, SOSFullPeerInfoGetPeerInfo(fpi));
515
516 if (result) {
517 SOSRingGenerationSign(ring, userPrivKey, fpi, error);
518 secnotice("ring", "Generation signed updated signatures on peerinfo");
519 }
520
521 return result;
522 }
523
524
525 SOSFullPeerInfoRef SOSRingGetiCloudFullPeerInfoRef(SOSCircleRef circle, SOSRingRef ring) {
526 __block SOSFullPeerInfoRef cloud_full_peer = NULL;
527 SOSRingForEachActivePeer(circle, ring, ^(SOSPeerInfoRef peer) {
528 if (SOSPeerInfoIsCloudIdentity(peer)) {
529 if (cloud_full_peer == NULL) {
530 CFErrorRef localError = NULL;
531 cloud_full_peer = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, &localError);
532
533 if (localError) {
534 secerror("Found cloud peer in ring but can't make full peer: %@", localError);
535 CFReleaseNull(localError);
536 }
537
538 } else {
539 secerror("More than one cloud identity found in ring: %@", ring);
540 }
541 }
542 });
543 return cloud_full_peer;
544 }
545
546
547 CFMutableArrayRef SOSRingCopyConcurringPeers(SOSRingRef ring, CFErrorRef* error) {
548 SOSRingAssertStable(ring);
549
550 CFMutableArrayRef concurringPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
551
552 if (!SOSRingAppendConcurringPeers(ring, concurringPeers, error))
553 CFReleaseNull(concurringPeers);
554
555 return concurringPeers;
556 }
557
558
559 bool SOSRingAppendConcurringPeers(SOSCircleRef circle, SOSRingRef ring, CFMutableArrayRef appendHere, CFErrorRef *error) {
560 SOSRingForEachActivePeer(circle, ring, ^(SOSPeerInfoRef peer) {
561 CFErrorRef localError = NULL;
562 if (SOSRingVerifyPeerSigned(ring, peer, &localError)) {
563 CFArrayAppendValue(appendHere, peer);
564 } else if (error != NULL) {
565 secerror("Error checking concurrence: %@", localError);
566 }
567 CFReleaseNull(localError);
568 });
569
570 return true;
571 }
572 #endif