]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTUpdateTPHOperation.m
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / ot / OTUpdateTPHOperation.m
1
2 #if OCTAGON
3
4 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
5 #import "keychain/ot/categories/OTAccountMetadataClassC+KeychainSupport.h"
6
7 #import <CloudKit/CloudKit_Private.h>
8
9 #import "keychain/ckks/CloudKitCategories.h"
10
11 #import "keychain/ot/ObjCImprovements.h"
12
13 #import "keychain/ot/OTCuttlefishAccountStateHolder.h"
14 #import "keychain/ot/OTOperationDependencies.h"
15 #import "keychain/ot/OTStates.h"
16 #import "keychain/ot/OTUpdateTPHOperation.h"
17
18 @interface OTUpdateTPHOperation ()
19 @property OTOperationDependencies* deps;
20
21 @property OctagonState* peerUnknownState;
22
23 @property NSOperation* finishedOp;
24
25 @property (nullable) OctagonFlag* retryFlag;
26 @end
27
28 @implementation OTUpdateTPHOperation
29 @synthesize nextState = _nextState;
30 @synthesize intendedState = _intendedState;
31
32 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
33 intendedState:(OctagonState*)intendedState
34 peerUnknownState:(OctagonState*)peerUnknownState
35 errorState:(OctagonState*)errorState
36 retryFlag:(OctagonFlag* _Nullable)retryFlag
37 {
38 if((self = [super init])) {
39 _deps = dependencies;
40
41 _intendedState = intendedState;
42 _nextState = errorState;
43 _peerUnknownState = peerUnknownState;
44
45 _retryFlag = retryFlag;
46 }
47 return self;
48 }
49
50 - (void)groupStart
51 {
52 WEAKIFY(self);
53 self.finishedOp = [NSBlockOperation blockOperationWithBlock:^{
54 // If we errored in some unknown way, ask to try again!
55 STRONGIFY(self);
56
57 if(self.error) {
58 if(self.retryFlag == nil) {
59 secerror("octagon: Received an error updating TPH, but no retry flag present.");
60 return;
61 }
62
63 // Is this a very scary error?
64 bool fatal = true;
65
66 OctagonPendingFlag* pendingFlag = nil;
67
68 if([self.deps.lockStateTracker isLockedError:self.error]) {
69 secnotice("octagon", "Updating trust state failed because locked, retry once unlocked: %@", self.error);
70 self.nextState = OctagonStateWaitForUnlock;
71 pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag
72 conditions:OctagonPendingConditionsDeviceUnlocked];
73 fatal = false;
74 } else {
75 // more CloudKit errors should trigger a retry here
76 secnotice("octagon", "Error is currently unknown, aborting: %@", self.error);
77 }
78
79 if(!fatal) {
80 if(!pendingFlag) {
81 NSTimeInterval baseDelay = SecCKKSTestsEnabled() ? 2 : 30;
82 NSTimeInterval ckDelay = CKRetryAfterSecondsForError(self.error);
83 NSTimeInterval cuttlefishDelay = [self.error cuttlefishRetryAfter];
84 NSTimeInterval delay = MAX(ckDelay, cuttlefishDelay);
85 if (delay == 0) {
86 delay = baseDelay;
87 }
88
89 pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag
90 delayInSeconds:delay];
91 }
92 secnotice("octagon", "Updating trust state no fatal: requesting retry: %@",
93 pendingFlag);
94 [self.deps.flagHandler handlePendingFlag:pendingFlag];
95 }
96 }
97 }];
98 [self dependOnBeforeGroupFinished:self.finishedOp];
99
100
101 [self.deps.cuttlefishXPCWrapper updateWithContainer:self.deps.containerName
102 context:self.deps.contextID
103 deviceName:self.deps.deviceInformationAdapter.deviceName
104 serialNumber:self.deps.deviceInformationAdapter.serialNumber
105 osVersion:self.deps.deviceInformationAdapter.osVersion
106 policyVersion:nil
107 policySecrets:nil
108 syncUserControllableViews:nil
109 reply:^(TrustedPeersHelperPeerState* peerState, TPSyncingPolicy* syncingPolicy, NSError* error) {
110 STRONGIFY(self);
111 if(error || !peerState) {
112 secerror("octagon: update errored: %@", error);
113 self.error = error;
114
115 if ([error isCuttlefishError:CuttlefishErrorUpdateTrustPeerNotFound]) {
116 secnotice("octagon-ckks", "Cuttlefish reports we no longer exist.");
117 self.nextState = self.peerUnknownState;
118 } else {
119 // On an error, for now, go back to the intended state
120 // <rdar://problem/50190005> Octagon: handle lock state errors in update()
121 self.nextState = self.intendedState;
122 }
123 [self runBeforeGroupFinished:self.finishedOp];
124 return;
125 }
126
127 secnotice("octagon", "update complete: %@, %@", peerState, syncingPolicy);
128
129 NSError* localError = nil;
130 BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) {
131 [metadata setTPSyncingPolicy:syncingPolicy];
132 return metadata;
133 } error:&localError];
134 if(!persisted || localError) {
135 secerror("octagon: Unable to save new syncing state: %@", localError);
136
137 } else {
138 // After an update(), we're sure that we have a fresh policy
139 BOOL viewSetChanged = [self.deps.viewManager setCurrentSyncingPolicy:syncingPolicy policyIsFresh:YES];
140 if(viewSetChanged) {
141 [self.deps.flagHandler handleFlag:OctagonFlagCKKSViewSetChanged];
142 }
143 }
144
145 if(peerState.identityIsPreapproved) {
146 secnotice("octagon-sos", "Self peer is now preapproved!");
147 [self.deps.flagHandler handleFlag:OctagonFlagEgoPeerPreapproved];
148 }
149 if (peerState.memberChanges) {
150 secnotice("octagon", "Member list changed");
151 [self.deps.octagonAdapter sendTrustedPeerSetChangedUpdate];
152 }
153
154 if (peerState.unknownMachineIDsPresent) {
155 secnotice("octagon-authkit", "Unknown machine IDs are present; requesting fetch");
156 [self.deps.flagHandler handleFlag:OctagonFlagFetchAuthKitMachineIDList];
157 }
158
159 if (peerState.peerStatus & TPPeerStatusExcluded) {
160 secnotice("octagon", "Self peer (%@) is excluded; moving to untrusted", peerState.peerID);
161 self.nextState = OctagonStateBecomeUntrusted;
162 } else if(peerState.peerStatus & TPPeerStatusUnknown) {
163 if (peerState.identityIsPreapproved) {
164 secnotice("octagon", "Self peer (%@) is excluded but is preapproved, moving to sosuprade", peerState.peerID);
165 self.nextState = OctagonStateAttemptSOSUpgrade;
166 } else {
167 secnotice("octagon", "Self peer (%@) is unknown; moving to '%@''", peerState.peerID, self.peerUnknownState);
168 self.nextState = self.peerUnknownState;
169 }
170 } else {
171 self.nextState = self.intendedState;
172 }
173
174 [self runBeforeGroupFinished:self.finishedOp];
175 }];
176 }
177
178 @end
179
180 #endif // OCTAGON