]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTUpdateTrustedDeviceListOperation.m
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / ot / OTUpdateTrustedDeviceListOperation.m
1
2 #if OCTAGON
3
4 #import "keychain/ot/OTUpdateTrustedDeviceListOperation.h"
5
6 #import <CloudKit/CloudKit_Private.h>
7
8 #import <Security/SecKey.h>
9 #import <Security/SecKeyPriv.h>
10 #import <SecurityFoundation/SFKey_Private.h>
11
12 #import "keychain/ckks/CKKSNearFutureScheduler.h"
13 #import "keychain/ckks/CloudKitCategories.h"
14 #import "keychain/ot/ObjCImprovements.h"
15 #import "keychain/ot/OTSOSUpgradeOperation.h"
16 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
17 #import "keychain/ot/categories/OTAccountMetadataClassC+KeychainSupport.h"
18 #import "keychain/ot/OTOperationDependencies.h"
19
20 @interface OTUpdateTrustedDeviceListOperation ()
21 @property OTOperationDependencies* deps;
22
23 @property OctagonState* stateIfListUpdates;
24
25 @property (nullable) OctagonFlag* retryFlag;
26
27 // Since we're making callback based async calls, use this operation trick to hold off the ending of this operation
28 @property NSOperation* finishedOp;
29 @end
30
31 @implementation OTUpdateTrustedDeviceListOperation
32 @synthesize nextState = _nextState;
33 @synthesize intendedState = _intendedState;
34
35 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
36 intendedState:(OctagonState*)intendedState
37 listUpdatesState:(OctagonState*)stateIfListUpdates
38 errorState:(OctagonState*)errorState
39 retryFlag:(OctagonFlag*)retryFlag
40
41 {
42 if((self = [super init])) {
43 _deps = dependencies;
44
45 _intendedState = intendedState;
46 _nextState = errorState;
47 _stateIfListUpdates = stateIfListUpdates;
48
49 _retryFlag = retryFlag;
50 }
51 return self;
52 }
53
54 - (void)groupStart
55 {
56 WEAKIFY(self);
57 secnotice("octagon-authkit", "Attempting to update trusted device list");
58
59 self.finishedOp = [NSBlockOperation blockOperationWithBlock:^{
60 // If we errored in some unknown way, ask to try again!
61 STRONGIFY(self);
62
63 if(self.error) {
64 if(self.retryFlag == nil) {
65 secerror("octagon-authkit: Received an error updating the trusted device list operation, but no retry flag present.");
66 return;
67 }
68
69 OctagonPendingFlag* pendingFlag = nil;
70
71 if([self.deps.lockStateTracker isLockedError:self.error]) {
72 secnotice("octagon-authkit", "Setting the allowed device list failed due to lock state: %@", self.error);
73 self.nextState = OctagonStateWaitForUnlock;
74 pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag
75 conditions:OctagonPendingConditionsDeviceUnlocked];
76
77 } else {
78 secnotice("octagon-authkit", "Error is currently unknown, will not retry: %@", self.error);
79 }
80
81 if(pendingFlag) {
82 secnotice("octagon-authkit", "Machine ID list error is not fatal: requesting retry: %@",
83 pendingFlag);
84 [self.deps.flagHandler handlePendingFlag:pendingFlag];
85 }
86 }
87 }];
88 [self dependOnBeforeGroupFinished:self.finishedOp];
89
90 NSError* localError = nil;
91 BOOL isAccountDemo = [self.deps.authKitAdapter accountIsDemoAccount:&localError];
92 if(localError) {
93 secerror("octagon-authkit: failed to fetch demo account flag: %@", localError);
94 }
95
96 [self.deps.authKitAdapter fetchCurrentDeviceList:^(NSSet<NSString *> * _Nullable machineIDs, NSError * _Nullable error) {
97 STRONGIFY(self);
98
99 if (error) {
100 secerror("octagon-authkit: Unable to fetch machine ID list: %@", error);
101 [self fetchCurrentDeviceListAfterCuttlefishUpdate:isAccountDemo];
102 } else if (!machineIDs) {
103 secerror("octagon-authkit: empty machine id list");
104 if (self.logForUpgrade) {
105 [[CKKSAnalytics logger] logRecoverableError:error
106 forEvent:OctagonEventUpgradeFetchDeviceIDs
107 withAttributes:NULL];
108 }
109 self.error = error;
110 [self runBeforeGroupFinished:self.finishedOp];
111
112 } else {
113 if (self.logForUpgrade) {
114 [[CKKSAnalytics logger] logSuccessForEventNamed:OctagonEventUpgradeFetchDeviceIDs];
115 }
116 [self afterAuthKitFetch:machineIDs accountIsDemo:isAccountDemo];
117 }
118 }];
119 }
120
121 - (void)fetchCurrentDeviceListAfterCuttlefishUpdate:(BOOL)isAccountDemo
122 {
123 secnotice("octagon-authkit", "beginning update trust fetch");
124
125 WEAKIFY(self);
126 [self.deps.cuttlefishXPCWrapper updateWithContainer:self.deps.containerName
127 context:self.deps.contextID
128 deviceName:nil
129 serialNumber:nil
130 osVersion:nil
131 policyVersion:nil
132 policySecrets:nil
133 syncUserControllableViews:nil
134 reply:^(TrustedPeersHelperPeerState* peerState, TPSyncingPolicy* syncingPolicy, NSError* error) {
135 STRONGIFY(self);
136 if(error) {
137 secerror("octagon-authkit: fetching updates from cuttlefish failed: %@", error);
138 self.error = error;
139
140 if([self.deps.lockStateTracker isLockedError:self.error]) {
141 secnotice("octagon-authkit", "Feching changes from Cuttlefish failed because of lock state, will retry once unlocked: %@", self.error);
142 OctagonPendingFlag* pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagFetchAuthKitMachineIDList
143 conditions:OctagonPendingConditionsDeviceUnlocked];
144
145 [self.deps.flagHandler handlePendingFlag:pendingFlag];
146 }
147
148 [self runBeforeGroupFinished:self.finishedOp];
149 return;
150 }
151 secnotice("octagon-authkit", "re-attempting fetching current device list");
152
153 [self.deps.authKitAdapter fetchCurrentDeviceList:^(NSSet<NSString *> * _Nullable machineIDs, NSError * _Nullable error) {
154 STRONGIFY(self);
155 if(!machineIDs || error) {
156 secerror("octagon-authkit: STILL unable to fetch machine ID list: %@", error);
157 if (self.logForUpgrade) {
158 [[CKKSAnalytics logger] logRecoverableError:error
159 forEvent:OctagonEventUpgradeFetchDeviceIDs
160 withAttributes:NULL];
161 }
162 self.error = error;
163 [self runBeforeGroupFinished:self.finishedOp];
164
165 } else {
166 if (self.logForUpgrade) {
167 [[CKKSAnalytics logger] logSuccessForEventNamed:OctagonEventUpgradeFetchDeviceIDs];
168 }
169 [self afterAuthKitFetch:machineIDs accountIsDemo:isAccountDemo];
170 }
171 }];
172 }];
173 }
174
175 - (void)afterAuthKitFetch:(NSSet<NSString *>*)allowedMachineIDs accountIsDemo:(BOOL)accountIsDemo
176 {
177 WEAKIFY(self);
178 BOOL honorIDMSListChanges = accountIsDemo ? NO : YES;
179
180 [self.deps.cuttlefishXPCWrapper setAllowedMachineIDsWithContainer:self.deps.containerName
181 context:self.deps.contextID
182 allowedMachineIDs:allowedMachineIDs
183 honorIDMSListChanges:honorIDMSListChanges
184 reply:^(BOOL listDifferences, NSError * _Nullable error) {
185 STRONGIFY(self);
186
187 if (self.logForUpgrade) {
188 [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradeSetAllowList hardFailure:true result:error];
189 }
190 if(error) {
191 secnotice("octagon-authkit", "Unable to save machineID allow-list: %@", error);
192 self.error = error;
193 } else {
194 secnotice("octagon-authkit", "Successfully saved machineID allow-list (%@ change)", listDifferences ? @"some" : @"no");
195 if(listDifferences) {
196 self.nextState = self.stateIfListUpdates;
197 } else {
198 self.nextState = self.intendedState;
199 }
200 }
201
202 [self runBeforeGroupFinished:self.finishedOp];
203 }];
204 }
205
206 @end
207
208 #endif // OCTAGON