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 for(CKKSKeychainView* view in [self.deps.viewManager currentViews]) {
55 if([view.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateWaitForTLKUpload] ||
56 [view.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateWaitForTLKCreation]) {
57 secnotice("octagon-ckks", "CKKS view %@ needs TLK uploads!", view);
58 [viewsToUpload addObject: view];
62 if(viewsToUpload.count == 0) {
63 // Nothing to do; return to ready
64 secnotice("octagon-ckks", "No CKKS views need uploads");
65 self.nextState = self.intendedState;
69 self.finishedOp = [NSBlockOperation blockOperationWithBlock:^{
71 secnotice("octagon", "Finishing an update TLKs operation with %@", self.error ?: @"no error");
73 [self dependOnBeforeGroupFinished:self.finishedOp];
75 OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithViews:viewsToUpload];
76 [self runBeforeGroupFinished:fetchKeysOp];
78 CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"upload-tlks-with-keys"
81 [self proceedWithKeys:fetchKeysOp.viewKeySets
82 pendingTLKShares:fetchKeysOp.tlkShares
83 viewsToUpload:viewsToUpload];
86 [proceedWithKeys addDependency:fetchKeysOp];
87 [self runBeforeGroupFinished:proceedWithKeys];
90 - (void)proceedWithKeys:(NSArray<CKKSKeychainBackedKeySet*>*)viewKeySets
91 pendingTLKShares:(NSArray<CKKSTLKShare*>*)pendingTLKShares
92 viewsToUpload:(NSSet<CKKSKeychainView*>*)viewsToUpload
96 secnotice("octagon-ckks", "Beginning tlk upload with keys: %@", viewKeySets);
97 [self.deps.cuttlefishXPCWrapper updateTLKsWithContainer:self.deps.containerName
98 context:self.deps.contextID
100 tlkShares:pendingTLKShares
101 reply:^(NSArray<CKRecord*>* _Nullable keyHierarchyRecords, NSError * _Nullable error) {
105 if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) {
106 secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; moving to '%@'", self.ckksConflictState);
107 self.nextState = self.ckksConflictState;
109 secerror("octagon: Error calling tlk upload: %@", error);
113 // Tell CKKS about our shiny new records!
114 for(CKKSKeychainView* view in viewsToUpload) {
115 secnotice("octagon-ckks", "Providing records to %@", view);
116 [view receiveTLKUploadRecords: keyHierarchyRecords];
119 self.nextState = self.intendedState;
121 [self runBeforeGroupFinished:self.finishedOp];