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 57enum { 58 kOnlyCompatibleVersion = 1, // Sometime in the future this name will be improved to reflect history. 59 60 kAlwaysIncompatibleVersion = UINT64_MAX, 61}; 62 63struct __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 75CFGiblisWithCompareFor(SOSCircle); 76 77SOSCircleRef 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 93static 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 100static 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 118SOSCircleRef 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 135static inline 136void 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 147static inline 148SOSCircleRef 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 160static 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 177static 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 193static 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 210static 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 222static 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 234static 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 242fail: 243 CFReleaseSafe(pubKeyID); 244 return result; 245} 246 247static bool SOSCircleRemoveSignatures(SOSCircleRef circle, CFErrorRef *error) { 248 CFDictionaryRemoveAllValues(circle->signatures); 249 return true; 250} 251 252static 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 261fail: 262 CFReleaseSafe(pubKeyID); 263 return result; 264} 265 266bool 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 290bool 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 301bool 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 314bool 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 321static 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 335static 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 347static 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 362static 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 373re_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); 382out: 383 CFReleaseNull(userPubKey); 384 CFReleaseNull(pi); 385 return retval; 386} 387 388bool 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 408fail: 409 CFReleaseNull(ourKey); 410 CFReleaseNull(publicKey); 411 return false; 412} 413 414bool 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 429fail: 430 CFReleaseNull(ourKey); 431 return success; 432#endif 433} 434 435bool 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 442exit: 443 CFReleaseNull(ourKey); 444 return success; 445} 446 447static 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 457exit: 458 CFReleaseNull(pubKey); 459 return result; 460} 461 462static 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 476static inline bool SOSCircleIsEmpty(SOSCircleRef circle) { 477 return SOSCircleCountPeers(circle) == 0; 478} 479 480static 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 488static 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 506static inline bool isOlderGeneration(SOSCircleRef current, SOSCircleRef proposed) { 507 return CFNumberCompare(current->generation, proposed->generation, NULL) == kCFCompareGreaterThan; 508} 509 510bool 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 518static 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 527SOSConcordanceStatus 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 569static 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 583SOSCircleRef 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 622fail: 623 CFReleaseNull(cir); 624 return NULL; 625} 626 627SOSCircleRef 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 635size_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 649fail: 650 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error); 651 return 0; 652} 653 654uint8_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 667CFDataRef 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 687fail: 688 if (der == NULL || der != der_end) 689 CFReleaseNull(result); 690 691 return result; 692} 693 694 695CFDataRef 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 706static 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 717static 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 761CFStringRef SOSCircleGetName(SOSCircleRef circle) { 762 assert(circle); 763 assert(circle->name); 764 return circle->name; 765} 766 767const char *SOSCircleGetNameC(SOSCircleRef circle) { 768 CFStringRef name = SOSCircleGetName(circle); 769 if (!name) 770 return strdup(""); 771 return CFStringToCString(name); 772} 773 774CFNumberRef SOSCircleGetGeneration(SOSCircleRef circle) { 775 assert(circle); 776 assert(circle->generation); 777 return circle->generation; 778} 779 780int64_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 788void SOSCircleGenerationSetValue(SOSCircleRef circle, int64_t value) 789{ 790 CFAllocatorRef allocator = CFGetAllocator(circle->generation); 791 CFAssignRetained(circle->generation, CFNumberCreate(allocator, kCFNumberSInt64Type, &value)); 792} 793 794 795static 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 804void 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 817int SOSCircleCountPeers(SOSCircleRef circle) { 818 SOSCircleAssertStable(circle); 819 __block int count = 0; 820 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) { 821 ++count; 822 }); 823 return count; 824} 825 826int SOSCircleCountActivePeers(SOSCircleRef circle) { 827 SOSCircleAssertStable(circle); 828 __block int count = 0; 829 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { 830 ++count; 831 }); 832 return count; 833} 834 835int 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 844int SOSCircleCountRetiredPeers(SOSCircleRef circle) { 845 SOSCircleAssertStable(circle); 846 __block int count = 0; 847 SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) { 848 ++count; 849 }); 850 return count; 851} 852 853int SOSCircleCountApplicants(SOSCircleRef circle) { 854 SOSCircleAssertStable(circle); 855 856 return (int)CFSetGetCount(circle->applicants); 857} 858 859bool SOSCircleHasApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) { 860 SOSCircleAssertStable(circle); 861 862 return CFSetContainsValue(circle->applicants, peerInfo); 863} 864 865CFMutableSetRef SOSCircleCopyApplicants(SOSCircleRef circle, CFAllocatorRef allocator) { 866 SOSCircleAssertStable(circle); 867 868 return CFSetCreateMutableCopy(allocator, 0, circle->applicants); 869} 870 871int SOSCircleCountRejectedApplicants(SOSCircleRef circle) { 872 SOSCircleAssertStable(circle); 873 874 return (int)CFSetGetCount(circle->rejected_applicants); 875} 876 877bool SOSCircleHasRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) { 878 SOSCircleAssertStable(circle); 879 return CFSetContainsValue(circle->rejected_applicants, peerInfo); 880} 881 882SOSPeerInfoRef SOSCircleCopyRejectedApplicant(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) { 883 SOSCircleAssertStable(circle); 884 return CFRetainSafe((SOSPeerInfoRef)CFSetGetValue(circle->rejected_applicants, peerInfo)); 885} 886 887CFMutableArrayRef SOSCircleCopyRejectedApplicants(SOSCircleRef circle, CFAllocatorRef allocator) { 888 SOSCircleAssertStable(circle); 889 890 return CFSetCopyValuesCFArray(circle->rejected_applicants); 891} 892 893 894bool 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 903SOSPeerInfoRef 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 912bool SOSCircleHasPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) { 913 return SOSCircleHasPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error); 914} 915 916bool 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 925bool SOSCircleHasActivePeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) { 926 if(!peerInfo) return false; 927 return SOSCircleHasActivePeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error); 928} 929 930bool 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 939bool 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 945bool 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 966bool 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 973bool 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 983static 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 996fail: 997 return false; 998 999} 1000 1001bool 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); 1007fail: 1008 return success; 1009} 1010 1011bool 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); 1020fail: 1021 CFReleaseNull(user_pubkey); 1022 return success; 1023} 1024 1025 1026bool 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 1036bool 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 1055bool 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 1073fail: 1074 CFReleaseNull(publicKey); 1075 return result; 1076} 1077 1078bool SOSCircleWithdrawRequest(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) { 1079 SOSCircleAssertStable(circle); 1080 1081 CFSetRemoveValue(circle->applicants, peerInfo); 1082 1083 return true; 1084} 1085 1086bool SOSCircleRemoveRejectedPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) { 1087 SOSCircleAssertStable(circle); 1088 1089 CFSetRemoveValue(circle->rejected_applicants, peerInfo); 1090 1091 return true; 1092} 1093 1094 1095bool 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 1115bool 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 1137bool 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 1162static 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 1172static inline bool isHiddenPeer(SOSPeerInfoRef peer) { 1173 return SOSPeerInfoIsRetirementTicket(peer) || SOSPeerInfoIsCloudIdentity(peer); 1174} 1175 1176void SOSCircleForEachPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) { 1177 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) { 1178 return !isHiddenPeer(peer); 1179 }); 1180} 1181 1182void SOSCircleForEachRetiredPeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) { 1183 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) { 1184 return SOSPeerInfoIsRetirementTicket(peer); 1185 }); 1186} 1187 1188void SOSCircleForEachActivePeer(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) { 1189 SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) { 1190 return true; 1191 }); 1192} 1193 1194void 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 1200void SOSCircleForEachApplicant(SOSCircleRef circle, void (^action)(SOSPeerInfoRef peer)) { 1201 CFSetForEach(circle->applicants, ^(const void*value) { action((SOSPeerInfoRef) value); } ); 1202} 1203 1204 1205CFMutableSetRef 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 1217bool 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 1231CFMutableArrayRef 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 1242SOSFullPeerInfoRef 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} 1262