4 #import "utilities/debugging.h"
6 #import <CloudKit/CloudKit_Private.h>
8 #import "keychain/ot/OTUploadNewCKKSTLKsOperation.h"
9 #import "keychain/ot/OTCuttlefishAccountStateHolder.h"
10 #import "keychain/ot/OTFetchCKKSKeysOperation.h"
11 #import "keychain/ot/OTStates.h"
12 #import "keychain/ckks/CKKSCurrentKeyPointer.h"
13 #import "keychain/ckks/CKKSKeychainView.h"
14 #import "keychain/ckks/CKKSNearFutureScheduler.h"
15 #import "keychain/ckks/CloudKitCategories.h"
17 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
18 #import "keychain/ot/ObjCImprovements.h"
20 @interface OTUploadNewCKKSTLKsOperation ()
21 @property OTOperationDependencies* deps;
23 @property OctagonState* ckksConflictState;
24 @property OctagonState* peerMissingState;
26 @property NSOperation* finishedOp;
29 @implementation OTUploadNewCKKSTLKsOperation
30 @synthesize intendedState = _intendedState;
32 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
33 intendedState:(OctagonState*)intendedState
34 ckksConflictState:(OctagonState*)ckksConflictState
35 peerMissingState:(OctagonState*)peerMissingState
36 errorState:(OctagonState*)errorState
38 if((self = [super init])) {
41 _intendedState = intendedState;
42 _ckksConflictState = ckksConflictState;
43 _peerMissingState = peerMissingState;
44 _nextState = errorState;
51 secnotice("octagon", "Beginning an operation to upload any pending CKKS tlks");
55 NSMutableSet<CKKSKeychainView*>* viewsToUpload = [NSMutableSet set];
57 // One (or more) of our sub-CKKSes believes it needs to upload new TLKs.
58 CKKSViewManager* viewManager = self.deps.viewManager;
59 for(CKKSKeychainView* view in viewManager.currentViews) {
60 if([view requiresTLKUpload]) {
61 secnotice("octagon-ckks", "CKKS view %@ needs TLK uploads!", view);
62 [viewsToUpload addObject: view];
66 if(viewsToUpload.count == 0) {
67 // Nothing to do; return to ready
68 secnotice("octagon-ckks", "No CKKS views need uploads");
69 self.nextState = self.intendedState;
73 self.finishedOp = [NSBlockOperation blockOperationWithBlock:^{
75 secnotice("octagon", "Finishing an update TLKs operation with %@", self.error ?: @"no error");
77 [self dependOnBeforeGroupFinished:self.finishedOp];
79 OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithViews:viewsToUpload];
80 [self runBeforeGroupFinished:fetchKeysOp];
82 CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"upload-tlks-with-keys"
85 [self proceedWithKeys:fetchKeysOp.viewKeySets
86 pendingTLKShares:fetchKeysOp.tlkShares
87 viewsToUpload:viewsToUpload];
90 [proceedWithKeys addDependency:fetchKeysOp];
91 [self runBeforeGroupFinished:proceedWithKeys];
94 - (void)proceedWithKeys:(NSArray<CKKSKeychainBackedKeySet*>*)viewKeySets
95 pendingTLKShares:(NSArray<CKKSTLKShare*>*)pendingTLKShares
96 viewsToUpload:(NSSet<CKKSKeychainView*>*)viewsToUpload
100 secnotice("octagon-ckks", "Beginning tlk upload with keys: %@", viewKeySets);
101 [self.deps.cuttlefishXPCWrapper updateTLKsWithContainer:self.deps.containerName
102 context:self.deps.contextID
104 tlkShares:pendingTLKShares
105 reply:^(NSArray<CKRecord*>* _Nullable keyHierarchyRecords, NSError * _Nullable error) {
109 if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) {
110 secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; moving to '%@'", self.ckksConflictState);
111 self.nextState = self.ckksConflictState;
112 } else if ([error isCuttlefishError:CuttlefishErrorUpdateTrustPeerNotFound]) {
113 secnotice("octagon-ckks", "Cuttlefish reports we no longer exist.");
114 self.nextState = self.peerMissingState;
118 secerror("octagon: Error calling tlk upload: %@", error);
122 // Tell CKKS about our shiny new records!
123 for(CKKSKeychainView* view in viewsToUpload) {
124 secnotice("octagon-ckks", "Providing records to %@", view);
125 [view receiveTLKUploadRecords: keyHierarchyRecords];
128 self.nextState = self.intendedState;
130 [self runBeforeGroupFinished:self.finishedOp];