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/ckks/CKKSCurrentKeyPointer.h"
12 #import "keychain/ckks/CKKSKeychainView.h"
13 #import "keychain/ckks/CKKSNearFutureScheduler.h"
14 #import "keychain/ckks/CloudKitCategories.h"
16 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
17 #import "keychain/ot/ObjCImprovements.h"
19 @interface OTUploadNewCKKSTLKsOperation ()
20 @property OTOperationDependencies* deps;
22 @property OctagonState* ckksConflictState;
24 @property NSOperation* finishedOp;
27 @implementation OTUploadNewCKKSTLKsOperation
28 @synthesize intendedState = _intendedState;
30 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
31 intendedState:(OctagonState*)intendedState
32 ckksConflictState:(OctagonState*)ckksConflictState
33 errorState:(OctagonState*)errorState
35 if((self = [super init])) {
38 _intendedState = intendedState;
39 _ckksConflictState = ckksConflictState;
40 _nextState = errorState;
47 secnotice("octagon", "Beginning to upload any pending CKKS tlks operation");
51 NSMutableSet<CKKSKeychainView*>* viewsToUpload = [NSMutableSet set];
53 // One (or more) of our sub-CKKSes believes it needs to upload new TLKs.
54 CKKSViewManager* viewManager = self.deps.viewManager;
55 for(CKKSKeychainView* view in viewManager.currentViews) {
56 if([view.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateWaitForTLKUpload] ||
57 [view.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateWaitForTLKCreation]) {
58 secnotice("octagon-ckks", "CKKS view %@ needs TLK uploads!", view);
59 [viewsToUpload addObject: view];
63 if(viewsToUpload.count == 0) {
64 // Nothing to do; return to ready
65 secnotice("octagon-ckks", "No CKKS views need uploads");
66 self.nextState = self.intendedState;
70 self.finishedOp = [NSBlockOperation blockOperationWithBlock:^{
72 secnotice("octagon", "Finishing an update TLKs operation with %@", self.error ?: @"no error");
74 [self dependOnBeforeGroupFinished:self.finishedOp];
76 OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithViews:viewsToUpload];
77 [self runBeforeGroupFinished:fetchKeysOp];
79 CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"upload-tlks-with-keys"
82 [self proceedWithKeys:fetchKeysOp.viewKeySets
83 pendingTLKShares:fetchKeysOp.tlkShares
84 viewsToUpload:viewsToUpload];
87 [proceedWithKeys addDependency:fetchKeysOp];
88 [self runBeforeGroupFinished:proceedWithKeys];
91 - (void)proceedWithKeys:(NSArray<CKKSKeychainBackedKeySet*>*)viewKeySets
92 pendingTLKShares:(NSArray<CKKSTLKShare*>*)pendingTLKShares
93 viewsToUpload:(NSSet<CKKSKeychainView*>*)viewsToUpload
97 secnotice("octagon-ckks", "Beginning tlk upload with keys: %@", viewKeySets);
98 [self.deps.cuttlefishXPCWrapper updateTLKsWithContainer:self.deps.containerName
99 context:self.deps.contextID
101 tlkShares:pendingTLKShares
102 reply:^(NSArray<CKRecord*>* _Nullable keyHierarchyRecords, NSError * _Nullable error) {
106 if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) {
107 secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; moving to '%@'", self.ckksConflictState);
108 self.nextState = self.ckksConflictState;
110 secerror("octagon: Error calling tlk upload: %@", error);
114 // Tell CKKS about our shiny new records!
115 for(CKKSKeychainView* view in viewsToUpload) {
116 secnotice("octagon-ckks", "Providing records to %@", view);
117 [view receiveTLKUploadRecords: keyHierarchyRecords];
120 self.nextState = self.intendedState;
122 [self runBeforeGroupFinished:self.finishedOp];