2 // SOSAccountTrustClassic.m
6 #import <Foundation/Foundation.h>
7 #import "keychain/SecureObjectSync/SOSAccount.h"
8 #import "keychain/SecureObjectSync/SOSViews.h"
9 #import "keychain/SecureObjectSync/SOSAccountTrustClassic.h"
10 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h"
11 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Identity.h"
12 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
13 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Retirement.h"
15 #import "keychain/SecureObjectSync/SOSPeerInfoV2.h"
16 #import "keychain/SecureObjectSync/SOSPeerInfoCollections.h"
17 #import "keychain/SecureObjectSync/SOSTransportMessageKVS.h"
19 #import "keychain/SecureObjectSync/SOSAccountTransaction.h"
20 #include "keychain/SecureObjectSync/SOSTransportCircleKVS.h"
21 #include "keychain/SecureObjectSync/SOSTransportCircle.h"
22 #include "keychain/SecureObjectSync/SOSCircleDer.h"
23 #include "keychain/SecureObjectSync/SOSInternal.h"
25 #include <utilities/SecCFWrappers.h>
26 #include <utilities/SecCoreCrypto.h>
27 #include <utilities/SecBuffer.h>
29 @implementation SOSAccountTrustClassic
30 extern CFStringRef kSOSAccountDebugScope;
32 +(instancetype)trustClassic
34 return [[self alloc] init];
42 self.retirees = [NSMutableSet set];
43 self.fullPeerInfo = NULL;
44 self.trustedCircle = NULL;
45 self.departureCode = kSOSDepartureReasonError;
46 self.expansion = [NSMutableDictionary dictionary];
47 [self addRingDictionary];
52 -(id)initWithRetirees:(NSMutableSet*)r fpi:(SOSFullPeerInfoRef)fpi circle:(SOSCircleRef) trusted_circle
53 departureCode:(enum DepartureReason)code peerExpansion:(NSMutableDictionary*)e
58 self.retirees = [[NSMutableSet alloc] initWithSet:r] ;
59 self.fullPeerInfo = CFRetainSafe(fpi);
60 self.trustedCircle = CFRetainSafe(trusted_circle);
61 self.departureCode = code;
62 self.expansion = [[NSMutableDictionary alloc]initWithDictionary:e];
64 [self addRingDictionary];
71 -(bool) updateGestalt:(SOSAccount*)account newGestalt:(CFDictionaryRef)new_gestalt
73 if (CFEqualSafe(new_gestalt, (__bridge CFDictionaryRef)(account.gestalt)))
76 if (self.trustedCircle && self.fullPeerInfo
77 && SOSFullPeerInfoUpdateGestalt(self.fullPeerInfo, new_gestalt, NULL)) {
78 [self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) {
79 secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change");
80 return SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo);
84 account.gestalt = [[NSDictionary alloc] initWithDictionary:(__bridge NSDictionary * _Nonnull)(new_gestalt)];
88 #pragma clang diagnostic push
89 #pragma clang diagnostic ignored "-Wunused-value"
90 -(SOSViewResultCode) updateView:(SOSAccount*)account name:(CFStringRef) viewname code:(SOSViewActionCode) actionCode err:(CFErrorRef *)error
92 SOSViewResultCode retval = kSOSCCGeneralViewError;
93 SOSViewResultCode currentStatus = kSOSCCGeneralViewError;
94 bool alreadyInSync = SOSAccountHasCompletedInitialSync(account);
95 bool updateCircle = false;
96 CFSetRef alwaysOn = SOSViewCopyViewSet(kViewSetAlwaysOn);
98 require_action_quiet(self.trustedCircle, errOut, SOSCreateError(kSOSErrorNoCircle, CFSTR("No Trusted Circle"), NULL, error));
99 require_action_quiet(self.fullPeerInfo, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, error));
100 require_action_quiet((actionCode == kSOSCCViewEnable) || (actionCode == kSOSCCViewDisable), errOut, CFSTR("Invalid View Action"));
101 currentStatus = [account.trust viewStatus:account name:viewname err:error];
102 require_action_quiet((currentStatus == kSOSCCViewNotMember) || (currentStatus == kSOSCCViewMember), errOut, CFSTR("View Membership Not Actionable"));
104 if (CFEqualSafe(viewname, kSOSViewKeychainV0)) {
105 retval = SOSAccountVirtualV0Behavior(account, actionCode);
106 } else if ([account.trust isSyncingV0] && SOSViewsIsV0Subview(viewname)) {
107 // Subviews of V0 syncing can't be turned off if V0 is on.
108 require_action_quiet(actionCode = kSOSCCViewDisable, errOut, CFSTR("Have V0 peer can't disable"));
109 retval = kSOSCCViewMember;
111 CFMutableSetRef pendingSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
112 CFSetAddValue(pendingSet, viewname);
114 if(actionCode == kSOSCCViewEnable && currentStatus == kSOSCCViewNotMember) {
116 retval = SOSFullPeerInfoUpdateViews(self.fullPeerInfo, actionCode, viewname, error);
117 if(retval == kSOSCCViewMember) updateCircle = true;
119 [self pendEnableViewSet:pendingSet];
120 retval = kSOSCCViewMember;
121 updateCircle = false;
123 } else if(actionCode == kSOSCCViewDisable && currentStatus == kSOSCCViewMember) {
124 if(alwaysOn && CFSetContainsValue(alwaysOn, viewname)) {
125 retval = kSOSCCViewMember;
126 } else if(alreadyInSync) {
127 retval = SOSFullPeerInfoUpdateViews(self.fullPeerInfo, actionCode, viewname, error);
128 if(retval == kSOSCCViewNotMember) updateCircle = true;
130 SOSAccountPendDisableViewSet(account, pendingSet);
131 retval = kSOSCCViewNotMember;
132 updateCircle = false;
135 retval = currentStatus;
137 CFReleaseNull(pendingSet);
140 [self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) {
141 secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for views change");
142 return SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo);
148 CFReleaseNull(alwaysOn);
151 #pragma clang diagnostic pop
153 -(bool) activeValidInCircle:(SOSAccount*) account err:(CFErrorRef *)error {
154 return SOSCircleHasActiveValidPeer(self.trustedCircle, SOSFullPeerInfoGetPeerInfo(self.fullPeerInfo), SOSAccountGetTrustedPublicCredential(account, error), error);
157 -(SOSViewResultCode) viewStatus:(SOSAccount*)account name:(CFStringRef) viewname err:(CFErrorRef *)error
159 SOSViewResultCode retval = kSOSCCGeneralViewError;
161 require_action_quiet(SOSAccountGetTrustedPublicCredential(account, error), errOut, SOSCreateError(kSOSErrorNoKey, CFSTR("No Trusted UserKey"), NULL, error));
162 require_action_quiet(self.trustedCircle, errOut, SOSCreateError(kSOSErrorNoCircle, CFSTR("No Trusted Circle"), NULL, error));
163 require_action_quiet(self.fullPeerInfo, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, error));
164 require_action_quiet([self activeValidInCircle: account err: error ],
165 errOut, SOSCreateError(kSOSErrorNotInCircle, CFSTR("Not in Circle"), NULL, error));
167 if ([self valueSetContainsValue:kSOSPendingEnableViewsToBeSetKey value:viewname]) {
168 retval = kSOSCCViewMember;
169 } else if ([self valueSetContainsValue:kSOSPendingDisableViewsToBeSetKey value:viewname]) {
170 retval = kSOSCCViewNotMember;
172 retval = SOSFullPeerInfoViewStatus(self.fullPeerInfo, viewname, error);
175 // If that doesn't say we're a member and this view is a V0 subview, and we're syncing V0 views we are a member
176 if (retval != kSOSCCViewMember) {
177 if ((CFEqualSafe(viewname, kSOSViewKeychainV0) || SOSViewsIsV0Subview(viewname))
178 && [account.trust isSyncingV0]) {
179 retval = kSOSCCViewMember;
183 // If we're only an applicant we report pending if we would be a view member
184 if (retval == kSOSCCViewMember) {
185 bool isApplicant = SOSCircleHasApplicant(self.trustedCircle, self.peerInfo, error);
187 retval = kSOSCCViewPending;
195 static void dumpViewSet(CFStringRef label, CFSetRef views) {
197 CFStringSetPerformWithDescription(views, ^(CFStringRef description) {
198 secnotice("circleChange", "%@ list: %@", label, description);
201 secnotice("circleChange", "No %@ list provided.", label);
205 static bool SOSAccountScreenViewListForValidV0(SOSAccount* account, CFMutableSetRef viewSet, SOSViewActionCode actionCode) {
207 if(viewSet && CFSetContainsValue(viewSet, kSOSViewKeychainV0)) {
208 retval = SOSAccountVirtualV0Behavior(account, actionCode) != kSOSCCGeneralViewError;
209 CFSetRemoveValue(viewSet, kSOSViewKeychainV0);
214 -(bool) updateViewSetsWithAnalytics:(SOSAccount*)account enabled:(CFSetRef) origEnabledViews disabled:(CFSetRef) origDisabledViews parentEvent:(NSData*)parentEvent
217 bool updateCircle = false;
218 SOSPeerInfoRef pi = NULL;
219 NSError* localError = nil;
220 SFSignInAnalytics* parent = NULL;
221 bool doAnalytics = (parentEvent != NULL);
224 parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError];
227 SFSignInAnalytics *hasCompletedInitialSyncEvent = nil;
228 SFSignInAnalytics *updatePeerInCircleEvent = nil;
230 CFMutableSetRef enabledViews = NULL;
231 CFMutableSetRef disabledViews = NULL;
232 if(origEnabledViews) enabledViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, origEnabledViews);
233 if(origDisabledViews) disabledViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, origDisabledViews);
234 dumpViewSet(CFSTR("Enabled"), enabledViews);
235 dumpViewSet(CFSTR("Disabled"), disabledViews);
237 require_action_quiet(self.trustedCircle, errOut, secnotice("views", "Attempt to set viewsets with no trusted circle"));
239 // Make sure we have a peerInfo capable of supporting views.
240 SOSFullPeerInfoRef fpi = self.fullPeerInfo;
241 require_action_quiet(fpi, errOut, secnotice("views", "Attempt to set viewsets with no fullPeerInfo"));
242 require_action_quiet(enabledViews || disabledViews, errOut, secnotice("views", "No work to do"));
244 pi = SOSPeerInfoCreateCopy(kCFAllocatorDefault, SOSFullPeerInfoGetPeerInfo(fpi), NULL);
246 require_action_quiet(pi, errOut, secnotice("views", "Couldn't copy PeerInfoRef"));
248 if(!SOSPeerInfoVersionIsCurrent(pi)) {
249 CFErrorRef updateFailure = NULL;
250 require_action_quiet(SOSPeerInfoUpdateToV2(pi, &updateFailure), errOut,
251 (secnotice("views", "Unable to update peer to V2- can't update views: %@", updateFailure), (void) CFReleaseNull(updateFailure)));
252 secnotice("V2update", "Updating PeerInfo to V2 within SOSAccountUpdateViewSets");
256 CFStringSetPerformWithDescription(enabledViews, ^(CFStringRef description) {
257 secnotice("viewChange", "Enabling %@", description);
260 CFStringSetPerformWithDescription(disabledViews, ^(CFStringRef description) {
261 secnotice("viewChange", "Disabling %@", description);
264 require_action_quiet(SOSAccountScreenViewListForValidV0(account, enabledViews, kSOSCCViewEnable), errOut, secnotice("viewChange", "Bad view change (enable) with kSOSViewKeychainV0"));
265 require_action_quiet(SOSAccountScreenViewListForValidV0(account, disabledViews, kSOSCCViewDisable), errOut, secnotice("viewChange", "Bad view change (disable) with kSOSViewKeychainV0"));
267 hasCompletedInitialSyncEvent = [parent newSubTaskForEvent:@"hasCompletedInitialSyncEvent"];
269 if(SOSAccountHasCompletedInitialSync(account)) {
270 if(enabledViews) updateCircle |= SOSViewSetEnable(pi, enabledViews);
271 if(disabledViews) updateCircle |= SOSViewSetDisable(pi, disabledViews);
274 //hold on to the views and enable them later
275 if(enabledViews) [self pendEnableViewSet:enabledViews];
276 if(disabledViews) SOSAccountPendDisableViewSet(account, disabledViews);
280 [hasCompletedInitialSyncEvent stopWithAttributes:nil];
283 /* UPDATE FULLPEERINFO VIEWS */
284 require_quiet(SOSFullPeerInfoUpdateToThisPeer(fpi, pi, NULL), errOut);
286 updatePeerInCircleEvent = [parent newSubTaskForEvent:@"updatePeerInCircleEvent"];
288 require_quiet([self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) {
289 secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for views or peerInfo change");
290 bool updated= SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo);
294 [updatePeerInCircleEvent stopWithAttributes:nil];
296 // Make sure we update the engine
297 account.circle_rings_retirements_need_attention = true;
302 [updatePeerInCircleEvent stopWithAttributes:nil];
304 CFReleaseNull(enabledViews);
305 CFReleaseNull(disabledViews);
311 static inline void CFArrayAppendValueIfNot(CFMutableArrayRef array, CFTypeRef value, CFTypeRef excludedValue)
313 if (!CFEqualSafe(value, excludedValue))
314 CFArrayAppendValue(array, value);
317 -(void) addSyncablePeerBlock:(SOSAccountTransaction*)txn dsName:(CFStringRef) ds_name change:(SOSAccountSyncablePeersBlock) changeBlock
319 if (!changeBlock) return;
320 SOSAccount* account = txn.account;
321 CFRetainSafe(ds_name);
322 SOSAccountCircleMembershipChangeBlock block_to_register = ^void (SOSAccount *account, SOSCircleRef new_circle,
323 CFSetRef added_peers, CFSetRef removed_peers,
324 CFSetRef added_applicants, CFSetRef removed_applicants) {
326 if (!CFEqualSafe(SOSCircleGetName(new_circle), ds_name))
329 SOSPeerInfoRef myPi = self.peerInfo;
330 CFStringRef myPi_id = myPi ? SOSPeerInfoGetPeerID(myPi) : NULL;
332 CFMutableArrayRef peer_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
333 CFMutableArrayRef added_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
334 CFMutableArrayRef removed_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
336 if (SOSCircleHasPeer(new_circle, myPi, NULL)) {
337 SOSCircleForEachPeer(new_circle, ^(SOSPeerInfoRef peer) {
338 CFArrayAppendValueIfNot(peer_ids, SOSPeerInfoGetPeerID(peer), myPi_id);
341 CFSetForEach(added_peers, ^(const void *value) {
342 CFArrayAppendValueIfNot(added_ids, SOSPeerInfoGetPeerID((SOSPeerInfoRef) value), myPi_id);
345 CFSetForEach(removed_peers, ^(const void *value) {
346 CFArrayAppendValueIfNot(removed_ids, SOSPeerInfoGetPeerID((SOSPeerInfoRef) value), myPi_id);
350 if (CFArrayGetCount(peer_ids) || CFSetContainsValue(removed_peers, myPi))
351 changeBlock(peer_ids, added_ids, removed_ids);
353 CFReleaseSafe(peer_ids);
354 CFReleaseSafe(added_ids);
355 CFReleaseSafe(removed_ids);
358 SOSAccountAddChangeBlock(account, block_to_register);
360 CFSetRef empty = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
361 if (self.trustedCircle && CFEqualSafe(ds_name, SOSCircleGetName(self.trustedCircle))) {
362 block_to_register(account, self.trustedCircle, empty, empty, empty, empty);
364 CFReleaseSafe(empty);
368 -(CFSetRef) copyPeerSetForView:(CFStringRef) viewName
370 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
372 if (self.trustedCircle) {
373 SOSCircleForEachPeer(self.trustedCircle, ^(SOSPeerInfoRef peer) {
374 if (CFSetContainsValue(SOSPeerInfoGetPermittedViews(peer), viewName)) {
375 CFSetAddValue(result, peer);
383 -(SecKeyRef) copyPublicKeyForPeer:(CFStringRef) peer_id err:(CFErrorRef *)error
385 SecKeyRef publicKey = NULL;
386 SOSPeerInfoRef peer = NULL;
388 require_action_quiet(self.trustedCircle, fail, SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("No circle to get peer key from")));
390 peer = SOSCircleCopyPeerWithID(self.trustedCircle, peer_id, error);
391 require_quiet(peer, fail);
393 publicKey = SOSPeerInfoCopyPubKey(peer, error);
401 -(SOSPeerInfoRef) copyPeerWithID:(CFStringRef) peerid err:(CFErrorRef *)error
403 if(!self.trustedCircle) return NULL;
404 return SOSCircleCopyPeerWithID(self.trustedCircle, peerid, error);
406 -(bool) isAccountIdentity:(SOSPeerInfoRef)peerInfo err:(CFErrorRef *)error
408 return CFEqualSafe(peerInfo, self.peerInfo);
411 -(CFSetRef) copyPeerSetMatching:(SOSModifyPeerBlock)block
413 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
414 if (self.trustedCircle) {
415 SOSCircleForEachPeer(self.trustedCircle, ^(SOSPeerInfoRef peer) {
417 CFSetAddValue(result, peer);
424 -(CFArrayRef) copyPeersToListenTo:(SecKeyRef)userPublic err:(CFErrorRef *)error
426 SOSPeerInfoRef myPeerInfo = self.peerInfo;
427 CFStringRef myID = myPeerInfo ? SOSPeerInfoGetPeerID(myPeerInfo) : NULL;
428 return [self copySortedPeerArray:error action:^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) {
429 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
430 if(!CFEqualSafe(myID, SOSPeerInfoGetPeerID(peer)) &&
431 SOSPeerInfoApplicationVerify(peer, userPublic, NULL) &&
432 !SOSPeerInfoIsRetirementTicket(peer)) {
433 CFArrayAppendValue(appendPeersTo, peer);
438 -(bool) peerSignatureUpdate:(SecKeyRef)privKey err:(CFErrorRef *)error
440 return self.fullPeerInfo && SOSFullPeerInfoUpgradeSignatures(self.fullPeerInfo, privKey, error);
442 -(bool) updatePeerInfo:(SOSKVSCircleStorageTransport*)circleTransport description:(CFStringRef)updateDescription err:(CFErrorRef *)error update:(SOSModifyPeerInfoBlock)block
444 if (self.fullPeerInfo == NULL)
447 bool result = block(self.fullPeerInfo, error);
449 if (result && [self hasCircle:NULL]) {
450 return [self modifyCircle:circleTransport err:error action:^(SOSCircleRef circle_to_change) {
451 secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for %@", updateDescription);
452 return SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo);
460 -(void) removeInvalidApplications:(SOSCircleRef) circle userPublic:(SecKeyRef)userPublic
462 CFMutableSetRef peersToRemove = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
463 SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) {
464 if (!SOSPeerInfoApplicationVerify(peer, userPublic, NULL))
465 CFSetAddValue(peersToRemove, peer);
468 CFSetForEach(peersToRemove, ^(const void *value) {
469 SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
471 SOSCircleWithdrawRequest(circle, peer, NULL);
475 -(bool) upgradeiCloudIdentity:(SOSCircleRef) circle privKey:(SecKeyRef) privKey
478 SOSFullPeerInfoRef cloud_fpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, NULL);
479 require_quiet(cloud_fpi != NULL, errOut);
480 require_quiet(SOSFullPeerInfoUpgradeSignatures(cloud_fpi, privKey, NULL), errOut);
481 retval = SOSCircleUpdatePeerInfo(circle, SOSFullPeerInfoGetPeerInfo(cloud_fpi));
483 CFReleaseNull(cloud_fpi);
486 const CFStringRef kSOSHsaPreApprovedPeerKeyInfo = CFSTR("HSAPreApprovedPeer");
488 -(CFMutableSetRef) copyPreApprovedHSA2Info
490 CFMutableSetRef preApprovedPeers = (CFMutableSetRef) [self getValueFromExpansion:kSOSHsaPreApprovedPeerKeyInfo err:NULL];
492 if(preApprovedPeers) {
493 preApprovedPeers = CFSetCreateMutableCopy(NULL, 0, preApprovedPeers);
495 preApprovedPeers = CFSetCreateMutableForCFTypes(NULL);
497 return preApprovedPeers;
501 -(bool) addiCloudIdentity:(SOSCircleRef) circle key:(SecKeyRef) userKey err:(CFErrorRef*)error
504 SOSFullPeerInfoRef cloud_identity = NULL;
505 SOSPeerInfoRef cloud_peer = GenerateNewCloudIdentityPeerInfo(error);
508 cloud_identity = CopyCloudKeychainIdentity(cloud_peer, error);
509 CFReleaseNull(cloud_peer);
512 if(!SOSCircleRequestAdmission(circle, userKey, cloud_identity, error)) {
513 CFReleaseNull(cloud_identity);
517 require_quiet(SOSCircleAcceptRequest(circle, userKey, self.fullPeerInfo, SOSFullPeerInfoGetPeerInfo(cloud_identity), error), err_out);
520 CFReleaseNull(cloud_identity);
523 -(bool) addEscrowToPeerInfo:(SOSFullPeerInfoRef) myPeer err:(CFErrorRef *)error
525 bool success = false;
527 CFDictionaryRef escrowRecords = [self getValueFromExpansion:kSOSEscrowRecord err:error];
528 success = SOSFullPeerInfoReplaceEscrowRecords(myPeer, escrowRecords, error);
533 -(CFArrayRef) copySortedPeerArray:(CFErrorRef *)error
534 action:(SOSModifyPeersInCircleBlock)block
536 CFMutableArrayRef peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
538 block(self.trustedCircle, peers);
540 CFArrayOfSOSPeerInfosSortByID(peers);
546 #define CURRENT_ACCOUNT_PERSISTENT_VERSION 8
548 static size_t der_sizeof_data_optional(CFDataRef data)
550 return data ? der_sizeof_data(data, NULL) : 0;
553 -(size_t) getDEREncodedSize:(SOSAccount*)account err:(NSError**)error
555 size_t sequence_size = 0;
556 uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION;
557 CFErrorRef failure = NULL;
559 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(version)), fail);
560 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary((__bridge CFDictionaryRef)account.gestalt, &failure)), fail);
561 require_quiet(accumulate_size(&sequence_size, SOSCircleGetDEREncodedSize(self.trustedCircle, &failure)), fail);
562 require_quiet(accumulate_size(&sequence_size, der_sizeof_fullpeer_or_null(self.fullPeerInfo, &failure)), fail);
563 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(self.departureCode)), fail);
564 require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account.accountKeyIsTrusted, &failure)), fail);
565 require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account.accountKey, &failure)), fail);
566 require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account.previousAccountKey, &failure)), fail);
567 require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null((__bridge CFDataRef)account.accountKeyDerivationParamters, &failure)), fail);
568 require_quiet(accumulate_size(&sequence_size, SOSPeerInfoSetGetDEREncodedArraySize((__bridge CFSetRef)self.retirees, &failure)), fail);
569 (void)accumulate_size(&sequence_size, der_sizeof_data_optional((__bridge CFDataRef)(account.backup_key)));
570 require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary((__bridge CFDictionaryRef)(self.expansion), &failure)), fail);
572 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size);
575 // Ensure some error is made, maybe not this one, tho.
576 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, &failure);
578 if (failure != NULL) {
579 *error = (__bridge_transfer NSError*) failure;
583 CFReleaseNull(failure);
588 static uint8_t* der_encode_data_optional(CFDataRef data, CFErrorRef *error,
589 const uint8_t *der, uint8_t *der_end)
591 return data ? der_encode_data(data, error, der, der_end) : der_end;
595 -(uint8_t*) encodeToDER:(SOSAccount*)account err:(NSError**) error start:(const uint8_t*) der end:(uint8_t*)der_end
597 CFErrorRef failure = NULL;
598 uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION;
599 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
600 ccder_encode_uint64(version, der,
601 der_encode_dictionary((__bridge CFDictionaryRef)account.gestalt, &failure, der,
602 SOSCircleEncodeToDER(self.trustedCircle, &failure, der,
603 der_encode_fullpeer_or_null(self.fullPeerInfo, &failure, der,
604 ccder_encode_uint64(self.departureCode, der,
605 ccder_encode_bool(account.accountKeyIsTrusted, der,
606 der_encode_public_bytes(account.accountKey, &failure, der,
607 der_encode_public_bytes(account.previousAccountKey, &failure, der,
608 der_encode_data_or_null((__bridge CFDataRef)(account.accountKeyDerivationParamters), &failure, der,
609 SOSPeerInfoSetEncodeToArrayDER((__bridge CFSetRef)(self.retirees), &failure, der,
610 der_encode_data_optional((__bridge CFDataRef)account.backup_key, &failure, der,
611 der_encode_dictionary((__bridge CFDictionaryRef)(self.expansion), &failure, der,
612 der_end)))))))))))));
615 if (failure != NULL) {
616 *error = (__bridge_transfer NSError*) failure;
620 CFReleaseNull(failure);
625 -(CFMutableSetRef) CF_RETURNS_RETAINED syncWithPeers:(SOSAccountTransaction*) txn peerIDs:(CFSetRef) /* CFStringRef */ peerIDs err:(CFErrorRef *)error
627 CFMutableSetRef notMePeers = NULL;
628 CFMutableSetRef handledPeerIDs = NULL;
629 CFMutableSetRef peersForKVS = NULL;
631 SOSAccount* account = txn.account;
633 if(![account isInCircle:error])
635 handledPeerIDs = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs);
636 CFReleaseNull(notMePeers);
637 CFReleaseNull(peersForKVS);
638 return handledPeerIDs;
641 handledPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
642 peersForKVS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
644 SOSPeerInfoRef myPeerInfo = account.peerInfo;
647 CFReleaseNull(notMePeers);
648 CFReleaseNull(peersForKVS);
649 return handledPeerIDs;
652 CFStringRef myPeerID = SOSPeerInfoGetPeerID(myPeerInfo);
654 notMePeers = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs);
655 CFSetRemoveValue(notMePeers, myPeerID);
657 CFSetForEach(notMePeers, ^(const void *value) {
658 CFErrorRef localError = NULL;
659 CFStringRef peerID = asString(value, &localError);
660 SOSPeerInfoRef peerInfo = NULL;
661 require_quiet(peerID, skip);
663 peerInfo = SOSCircleCopyPeerWithID(self.trustedCircle, peerID, NULL);
664 if (peerInfo && SOSCircleHasValidSyncingPeer(self.trustedCircle, peerInfo, account.accountKey, NULL)) {
665 CFSetAddValue(peersForKVS, peerID);
667 CFSetAddValue(handledPeerIDs, peerID);
671 CFReleaseNull(peerInfo);
673 secnotice("sync-with-peers", "Skipped peer ID: %@ due to %@", peerID, localError);
675 CFReleaseNull(localError);
678 CFSetRef handledKVSPeerIDs = SOSAccountSyncWithPeersOverKVS(txn, peersForKVS);
679 CFSetUnion(handledPeerIDs, handledKVSPeerIDs);
680 CFReleaseNull(handledKVSPeerIDs);
682 SOSAccountConsiderLoggingEngineState(txn);
684 CFReleaseNull(notMePeers);
685 CFReleaseNull(peersForKVS);
686 return handledPeerIDs;
689 -(bool) requestSyncWithAllPeers:(SOSAccountTransaction*) txn key:(SecKeyRef)userPublic err:(CFErrorRef *)error
691 if (![txn.account isInCircle: error]) {
695 NSMutableSet<NSString*>* allSyncingPeerIDs = [NSMutableSet set];
697 SOSCircleForEachValidSyncingPeer(self.trustedCircle, userPublic, ^(SOSPeerInfoRef peer) {
698 [allSyncingPeerIDs addObject: (__bridge NSString*) SOSPeerInfoGetPeerID(peer)];
701 [txn requestSyncWithPeers: allSyncingPeerIDs];
707 __block bool syncingV0 = false;
709 [self forEachCirclePeerExceptMe:^(SOSPeerInfoRef peer){
710 if (SOSPeerInfoIsEnabledView(peer, kSOSViewKeychainV0)) {
718 -(SOSEngineRef) getDataSourceEngine:(SOSDataSourceFactoryRef)factory
720 return SOSDataSourceFactoryGetEngineForDataSourceName(factory, SOSCircleGetName(self.trustedCircle), NULL);
723 -(bool) postDebugScope:(SOSKVSCircleStorageTransport*) circle_transport scope:(CFTypeRef) scope err:(CFErrorRef*)error
726 if (circle_transport) {
727 result = [circle_transport kvssendDebugInfo:kSOSAccountDebugScope debug:scope err:error];
732 -(SecKeyRef) copyDeviceKey:(CFErrorRef *)error
734 SecKeyRef privateKey = NULL;
736 require_action_quiet(self.fullPeerInfo, fail, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No identity to get key from")));
738 privateKey = SOSFullPeerInfoCopyDeviceKey(self.fullPeerInfo, error);
744 -(bool) removeIncompleteiCloudIdentities:(SOSCircleRef) circle privKey:(SecKeyRef) privKey err:(CFErrorRef *)error
748 CFMutableSetRef iCloud2Remove = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
750 SOSCircleForEachActivePeer(self.trustedCircle, ^(SOSPeerInfoRef peer) {
751 if(SOSPeerInfoIsCloudIdentity(peer)) {
752 SOSFullPeerInfoRef icfpi = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, NULL);
754 CFSetAddValue(iCloud2Remove, peer);
756 CFReleaseNull(icfpi);
760 if(CFSetGetCount(iCloud2Remove) > 0) {
762 SOSCircleRemovePeers(self.trustedCircle, privKey, self.fullPeerInfo, iCloud2Remove, error);
764 CFReleaseNull(iCloud2Remove);
768 -(bool) clientPing:(SOSAccount*)account
770 if (self.trustedCircle && self.fullPeerInfo
771 && SOSFullPeerInfoPing(self.fullPeerInfo, NULL)) {
772 [self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) {
773 secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change");
774 return SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo);
780 static NSString* kSOSRingKey = @"trusted_rings";
782 -(void) addRingDictionary {
785 if(![self.expansion valueForKey:kSOSRingKey]) {
786 NSMutableDictionary *rings = [NSMutableDictionary dictionary];
787 [self.expansion setObject:rings forKey:kSOSRingKey];
792 -(void) resetRingDictionary {
794 NSMutableDictionary *rings = [NSMutableDictionary dictionary];
795 [self.expansion setObject:rings forKey:kSOSRingKey];