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