3 #import "utilities/debugging.h"
5 #import <CloudKit/CloudKit_Private.h>
7 #import "keychain/ot/OTResetCKKSZonesLackingTLKsOperation.h"
8 #import "keychain/ot/OTCuttlefishAccountStateHolder.h"
9 #import "keychain/ot/OTFetchCKKSKeysOperation.h"
11 #import "keychain/ckks/CloudKitCategories.h"
12 #import "keychain/ckks/CKKSCurrentKeyPointer.h"
13 #import "keychain/ckks/CKKSKeychainView.h"
15 #import "keychain/ot/ObjCImprovements.h"
17 @interface OTResetCKKSZonesLackingTLKsOperation ()
18 @property OTOperationDependencies* deps;
20 @property NSOperation* finishedOp;
23 @implementation OTResetCKKSZonesLackingTLKsOperation
24 @synthesize nextState = _nextState;
25 @synthesize intendedState = _intendedState;
27 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
28 intendedState:(OctagonState*)intendedState
29 errorState:(OctagonState*)errorState
31 if((self = [super init])) {
34 _intendedState = intendedState;
35 _nextState = errorState;
42 secnotice("octagon", "Checking if any CKKS zones need resetting");
46 self.finishedOp = [NSBlockOperation blockOperationWithBlock:^{
48 secnotice("octagon", "Finishing resetting CKKS missing TLKs operation with %@", self.error ?: @"no error");
50 [self dependOnBeforeGroupFinished:self.finishedOp];
52 OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps
54 [self runBeforeGroupFinished:fetchKeysOp];
56 CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"continue-ckks-resets"
59 [self proceedWithKeys:fetchKeysOp.viewKeySets
60 incompleteKeySets:fetchKeysOp.incompleteKeySets
61 pendingTLKShares:fetchKeysOp.tlkShares];
64 [proceedWithKeys addDependency:fetchKeysOp];
65 [self runBeforeGroupFinished:proceedWithKeys];
68 - (void)proceedWithKeys:(NSArray<CKKSKeychainBackedKeySet*>*)viewKeySets
69 incompleteKeySets:(NSArray<CKKSCurrentKeySet*>*)incompleteKeySets
70 pendingTLKShares:(NSArray<CKKSTLKShare*>*)pendingTLKShares
72 // Now that CKKS has returned, what are we even doing
73 NSMutableSet<CKKSKeychainView*>* viewsToReset = [NSMutableSet set];
75 for(CKKSCurrentKeySet* incompleteKeySet in incompleteKeySets) {
76 if(incompleteKeySet.error == nil) {
77 CKKSViewManager* viewManager = self.deps.viewManager;
78 CKKSKeychainView* viewMatchingSet = [viewManager findView:incompleteKeySet.viewName];
80 if(!viewMatchingSet) {
81 secnotice("octagon-ckks", "No view matching viewset %@?", incompleteKeySet);
85 if(incompleteKeySet.currentTLKPointer != nil &&
86 incompleteKeySet.tlk == nil) {
88 // We used to not reset the TLKs if there was a recent device claiming to have them, but
89 // in our Octagon-primary world, an Octagon reset should take precedence over existing Cloud-based data
90 secnotice("octagon-ckks", "Key set %@ has no TLK; scheduling for reset", incompleteKeySet);
91 [viewsToReset addObject:viewMatchingSet];
94 secnotice("octagon-ckks", "Error loading key set %@; not attempting reset", incompleteKeySet);
98 if(viewsToReset.count == 0) {
99 // Nothing to do; return to ready
100 secnotice("octagon-ckks", "No CKKS views need resetting");
101 self.nextState = self.intendedState;
102 [self runBeforeGroupFinished:self.finishedOp];
106 [self resetViews:viewsToReset];
109 - (void)resetViews:(NSSet<CKKSKeychainView*>*)viewsToReset {
110 CKOperationGroup* opGroup = [CKOperationGroup CKKSGroupWithName:@"octagon-reset-missing-tlks"];
111 for (CKKSKeychainView* view in viewsToReset) {
112 secnotice("octagon-ckks", "Resetting CKKS %@", view);
113 CKKSResultOperation* op = [view resetCloudKitZone:opGroup];
115 // Use an intermediary operation, just to ensure we have a timeout
116 CKKSResultOperation* waitOp = [CKKSResultOperation named:[NSString stringWithFormat:@"wait-for-%@", view.zoneName]
118 secnotice("octagon-ckks", "Successfully reset %@", view);
120 [waitOp timeout:120*NSEC_PER_SEC];
121 [waitOp addDependency:op];
122 [self.operationQueue addOperation:waitOp];
124 [self.finishedOp addDependency:waitOp];
127 self.nextState = self.intendedState;
128 [self.operationQueue addOperation:self.finishedOp];