]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKSKeychainView.h
f10395e0c033b0c14a00e234bf2079c955449b37
[apple/security.git] / keychain / ckks / CKKSKeychainView.h
1 /*
2 * Copyright (c) 2016 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #ifndef CKKSKeychainView_h
26 #define CKKSKeychainView_h
27
28 #import <Foundation/Foundation.h>
29 #include <dispatch/dispatch.h>
30
31 #if OCTAGON
32 #import "keychain/ckks/CloudKitDependencies.h"
33 #import "keychain/ckks/CKKSAPSReceiver.h"
34 #import "keychain/ckks/CKKSLockStateTracker.h"
35 #endif
36
37 #include <utilities/SecDb.h>
38 #include <securityd/SecDbItem.h>
39
40 #import "keychain/ckks/CKKS.h"
41 #import "keychain/ckks/CKKSIncomingQueueOperation.h"
42 #import "keychain/ckks/CKKSOutgoingQueueOperation.h"
43 #import "keychain/ckks/CKKSNearFutureScheduler.h"
44 #import "keychain/ckks/CKKSNewTLKOperation.h"
45 #import "keychain/ckks/CKKSProcessReceivedKeysOperation.h"
46 #import "keychain/ckks/CKKSReencryptOutgoingItemsOperation.h"
47 #import "keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h"
48 #import "keychain/ckks/CKKSScanLocalItemsOperation.h"
49 #import "keychain/ckks/CKKSUpdateDeviceStateOperation.h"
50 #import "keychain/ckks/CKKSGroupOperation.h"
51 #import "keychain/ckks/CKKSZone.h"
52 #import "keychain/ckks/CKKSZoneChangeFetcher.h"
53 #import "keychain/ckks/CKKSNotifier.h"
54 #import "keychain/ckks/CKKSPeer.h"
55 #import "keychain/ckks/CKKSTLKShare.h"
56
57 #include "CKKS.h"
58
59 # if !OCTAGON
60 @interface CKKSKeychainView : NSObject {
61 NSString* _containerName;
62 }
63 @end
64 #else // OCTAGON
65
66 @class CKKSKey;
67 @class CKKSAESSIVKey;
68 @class CKKSSynchronizeOperation;
69 @class CKKSRateLimiter;
70 @class CKKSManifest;
71 @class CKKSEgoManifest;
72 @class CKKSOutgoingQueueEntry;
73 @class CKKSZoneChangeFetcher;
74
75 @interface CKKSKeychainView : CKKSZone <CKKSZoneUpdateReceiver,
76 CKKSChangeFetcherErrorOracle,
77 CKKSPeerUpdateListener> {
78 CKKSZoneKeyState* _keyHierarchyState;
79 }
80
81 @property CKKSLockStateTracker* lockStateTracker;
82
83 @property CKKSZoneKeyState* keyHierarchyState;
84 @property NSError* keyHierarchyError;
85 @property CKOperationGroup* keyHierarchyOperationGroup;
86 @property NSOperation* keyStateMachineOperation;
87
88 // If the key hierarchy isn't coming together, it might be because we're out of sync with cloudkit.
89 // Use this to track if we've completed a full refetch, so fix-up operations can be done.
90 @property bool keyStateMachineRefetched;
91 @property CKKSEgoManifest* egoManifest;
92 @property CKKSManifest* latestManifest;
93 @property CKKSResultOperation* keyStateReadyDependency;
94
95 @property (readonly) NSString *lastActiveTLKUUID;
96
97 // Full of condition variables, if you'd like to try to wait until the key hierarchy is in some state
98 @property NSMutableDictionary<CKKSZoneKeyState*, CKKSCondition*>* keyHierarchyConditions;
99
100 @property CKKSZoneChangeFetcher* zoneChangeFetcher;
101
102 @property (weak) CKKSNearFutureScheduler* savedTLKNotifier;
103
104 // Differs from the zonesetupoperation: zoneSetup is only for CK modifications, viewSetup handles local db changes too
105 @property CKKSGroupOperation* viewSetupOperation;
106
107 /* Used for debugging: just what happened last time we ran this? */
108 @property CKKSIncomingQueueOperation* lastIncomingQueueOperation;
109 @property CKKSNewTLKOperation* lastNewTLKOperation;
110 @property CKKSOutgoingQueueOperation* lastOutgoingQueueOperation;
111 @property CKKSProcessReceivedKeysOperation* lastProcessReceivedKeysOperation;
112 @property CKKSFetchAllRecordZoneChangesOperation* lastRecordZoneChangesOperation;
113 @property CKKSReencryptOutgoingItemsOperation* lastReencryptOutgoingItemsOperation;
114 @property CKKSScanLocalItemsOperation* lastScanLocalItemsOperation;
115 @property CKKSSynchronizeOperation* lastSynchronizeOperation;
116 @property CKKSResultOperation* lastFixupOperation;
117
118 /* Used for testing: pause operation types by adding operations here */
119 @property NSOperation* holdReencryptOutgoingItemsOperation;
120 @property NSOperation* holdOutgoingQueueOperation;
121
122 /* Trigger this to tell the whole machine that this view has changed */
123 @property CKKSNearFutureScheduler* notifyViewChangedScheduler;
124
125 // These are available when you're in a dispatchSyncWithAccountKeys call, but at no other time
126 // These must be pre-fetched before you get on the CKKS queue, otherwise we end up with CKKS<->SQLite<->SOSAccountQueue deadlocks
127 @property (nonatomic, readonly) CKKSSelves* currentSelfPeers;
128 @property (nonatomic, readonly) NSError* currentSelfPeersError;
129 @property (nonatomic, readonly) NSSet<id<CKKSPeer>>* currentTrustedPeers;
130 @property (nonatomic, readonly) NSError* currentTrustedPeersError;
131
132 - (instancetype)initWithContainer: (CKContainer*) container
133 zoneName: (NSString*) zoneName
134 accountTracker:(CKKSCKAccountStateTracker*) accountTracker
135 lockStateTracker:(CKKSLockStateTracker*) lockStateTracker
136 savedTLKNotifier:(CKKSNearFutureScheduler*) savedTLKNotifier
137 peerProvider:(id<CKKSPeerProvider>)peerProvider
138 fetchRecordZoneChangesOperationClass: (Class<CKKSFetchRecordZoneChangesOperation>) fetchRecordZoneChangesOperationClass
139 fetchRecordsOperationClass: (Class<CKKSFetchRecordsOperation>)fetchRecordsOperationClass
140 queryOperationClass:(Class<CKKSQueryOperation>)queryOperationClass
141 modifySubscriptionsOperationClass: (Class<CKKSModifySubscriptionsOperation>) modifySubscriptionsOperationClass
142 modifyRecordZonesOperationClass: (Class<CKKSModifyRecordZonesOperation>) modifyRecordZonesOperationClass
143 apsConnectionClass: (Class<CKKSAPSConnection>) apsConnectionClass
144 notifierClass: (Class<CKKSNotifier>) notifierClass;
145
146 /* Synchronous operations */
147
148 - (void) handleKeychainEventDbConnection:(SecDbConnectionRef) dbconn
149 added:(SecDbItemRef) added
150 deleted:(SecDbItemRef) deleted
151 rateLimiter:(CKKSRateLimiter*) rateLimiter
152 syncCallback:(SecBoolNSErrorCallback) syncCallback;
153
154 -(void)setCurrentItemForAccessGroup:(SecDbItemRef)newItem
155 hash:(NSData*)newItemSHA1
156 accessGroup:(NSString*)accessGroup
157 identifier:(NSString*)identifier
158 replacing:(SecDbItemRef)oldItem
159 hash:(NSData*)oldItemSHA1
160 complete:(void (^) (NSError* operror)) complete;
161
162 -(void)getCurrentItemForAccessGroup:(NSString*)accessGroup
163 identifier:(NSString*)identifier
164 fetchCloudValue:(bool)fetchCloudValue
165 complete:(void (^) (NSString* uuid, NSError* operror)) complete;
166
167 - (bool) outgoingQueueEmpty: (NSError * __autoreleasing *) error;
168
169 - (CKKSResultOperation*)waitForFetchAndIncomingQueueProcessing;
170 - (void) waitForKeyHierarchyReadiness;
171 - (void) cancelAllOperations;
172
173 - (CKKSKey*) keyForItem: (SecDbItemRef) item error: (NSError * __autoreleasing *) error;
174
175 - (bool)_onqueueWithAccountKeysCheckTLK: (CKKSKey*) proposedTLK error: (NSError * __autoreleasing *) error;
176
177 /* Asynchronous kickoffs */
178
179 - (void) initializeZone;
180
181 - (CKKSOutgoingQueueOperation*)processOutgoingQueue:(CKOperationGroup*)ckoperationGroup;
182 - (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation*)after ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
183
184 - (CKKSIncomingQueueOperation*) processIncomingQueue:(bool)failOnClassA;
185 - (CKKSIncomingQueueOperation*) processIncomingQueue:(bool)failOnClassA after: (CKKSResultOperation*) after;
186
187 // Schedules a process queueoperation to happen after the next device unlock. This may be Immediately, if the device is unlocked.
188 - (void)processIncomingQueueAfterNextUnlock;
189
190 // Schedules an operation to update this device's state record in CloudKit
191 // If rateLimit is true, the operation will abort if it's updated the record in the past 3 days
192 - (CKKSUpdateDeviceStateOperation*)updateDeviceState:(bool)rateLimit
193 waitForKeyHierarchyInitialization:(uint64_t)timeout
194 ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
195
196 - (CKKSSynchronizeOperation*) resyncWithCloud;
197
198 - (CKKSResultOperation*)fetchAndProcessCKChanges:(CKKSFetchBecause*)because;
199
200 - (CKKSResultOperation*)resetLocalData;
201 - (CKKSResultOperation*)resetCloudKitZone;
202
203 // Call this to pick and start the next key hierarchy operation for the zone
204 - (void)advanceKeyStateMachine;
205
206 // Call this to tell the key state machine that you think some new data has arrived that it is interested in
207 - (void)keyStateMachineRequestProcess;
208
209 // For our serial queue to work with how handleKeychainEventDbConnection is called from the main thread,
210 // every block on our queue must have a SecDBConnectionRef available to it before it begins on the queue.
211 // Use these helper methods to make sure those exist.
212 - (void) dispatchAsync: (bool (^)(void)) block;
213 - (void) dispatchSync: (bool (^)(void)) block;
214 - (void)dispatchSyncWithAccountKeys:(bool (^)(void))block;
215
216 /* Synchronous operations which must be called from inside a dispatchAsync or dispatchSync block */
217
218 // Call this to request the key hierarchy state machine to fetch new updates
219 - (void)_onqueueKeyStateMachineRequestFetch;
220
221 // Call this to request the key hierarchy state machine to refetch everything in Cloudkit
222 - (void)_onqueueKeyStateMachineRequestFullRefetch;
223
224 // Call this to request the key hierarchy state machine to reprocess
225 - (void)_onqueueKeyStateMachineRequestProcess;
226
227 // Call this from a key hierarchy operation to move the state machine, and record the results of the last move.
228 - (void)_onqueueAdvanceKeyStateMachineToState: (CKKSZoneKeyState*) state withError: (NSError*) error;
229
230 // Since we might have people interested in the state transitions of objects, please do those transitions via these methods
231 - (bool)_onqueueChangeOutgoingQueueEntry: (CKKSOutgoingQueueEntry*) oqe toState: (NSString*) state error: (NSError* __autoreleasing*) error;
232 - (bool)_onqueueErrorOutgoingQueueEntry: (CKKSOutgoingQueueEntry*) oqe itemError: (NSError*) itemError error: (NSError* __autoreleasing*) error;
233
234 // Call this if you've done a write and received an error. It'll pull out any new records returned as CKErrorServerRecordChanged and pretend we received them in a fetch
235 //
236 // Note that you need to tell this function the records you wanted to save, so it can determine which record failed from its CKRecordID.
237 // I don't know why CKRecordIDs don't have record types, either.
238 - (bool)_onqueueCKWriteFailed:(NSError*)ckerror attemptedRecordsChanged:(NSDictionary<CKRecordID*,CKRecord*>*)savedRecords;
239
240 - (bool) _onqueueCKRecordChanged:(CKRecord*)record resync:(bool)resync;
241 - (bool) _onqueueCKRecordDeleted:(CKRecordID*)recordID recordType:(NSString*)recordType resync:(bool)resync;
242
243 // For this key, who doesn't yet have a CKKSTLKShare for it?
244 // Note that we really want a record sharing the TLK to ourselves, so this function might return
245 // a non-empty set even if all peers have the TLK: it wants us to make a record for ourself.
246 - (NSSet<id<CKKSPeer>>*)_onqueueFindPeersMissingShare:(CKKSKey*)key error:(NSError* __autoreleasing*)error;
247
248 // For this key, share it to all trusted peers who don't have it yet
249 - (NSSet<CKKSTLKShare*>*)_onqueueCreateMissingKeyShares:(CKKSKey*)key error:(NSError* __autoreleasing*)error;
250
251 - (bool)_onQueueUpdateLatestManifestWithError:(NSError**)error;
252
253 - (CKKSDeviceStateEntry*)_onqueueCurrentDeviceStateEntry: (NSError* __autoreleasing*)error;
254
255 // Called by the CKKSZoneChangeFetcher
256 - (bool) isFatalCKFetchError: (NSError*) error;
257
258 // Please don't use these unless you're an Operation in this package
259 @property NSHashTable<CKKSIncomingQueueOperation*>* incomingQueueOperations;
260 @property NSHashTable<CKKSOutgoingQueueOperation*>* outgoingQueueOperations;
261 @property CKKSScanLocalItemsOperation* initialScanOperation;
262
263 // Returns the current state of this view
264 -(NSDictionary<NSString*, NSString*>*)status;
265 @end
266 #endif // OCTAGON
267
268
269 #define SecTranslateError(nserrorptr, cferror) \
270 if(nserrorptr) { \
271 *nserrorptr = (__bridge_transfer NSError*) cferror; \
272 } else { \
273 CFReleaseNull(cferror); \
274 }
275
276 #endif /* CKKSKeychainView_h */