]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKSKeychainView.h
f9d7de0013f0ace4879fa4740a2403de92606e15
[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
55 #include "CKKS.h"
56
57 # if !OCTAGON
58 @interface CKKSKeychainView : NSObject {
59 NSString* _containerName;
60 }
61 @end
62 #else // OCTAGON
63
64 @class CKKSKey;
65 @class CKKSAESSIVKey;
66 @class CKKSSynchronizeOperation;
67 @class CKKSRateLimiter;
68 @class CKKSManifest;
69 @class CKKSEgoManifest;
70 @class CKKSOutgoingQueueEntry;
71 @class CKKSZoneChangeFetcher;
72
73 @interface CKKSKeychainView : CKKSZone <CKKSZoneUpdateReceiver, CKKSChangeFetcherErrorOracle> {
74 CKKSZoneKeyState* _keyHierarchyState;
75 }
76
77 @property CKKSLockStateTracker* lockStateTracker;
78
79 @property CKKSZoneKeyState* keyHierarchyState;
80 @property NSError* keyHierarchyError;
81 @property CKOperationGroup* keyHierarchyOperationGroup;
82 @property NSOperation* keyStateMachineOperation;
83
84 // If the key hierarchy isn't coming together, it might be because we're out of sync with cloudkit.
85 // Use this to track if we've completed a full refetch, so fix-up operations can be done.
86 @property bool keyStateMachineRefetched;
87 @property CKKSEgoManifest* egoManifest;
88 @property CKKSManifest* latestManifest;
89 @property CKKSResultOperation* keyStateReadyDependency;
90
91 @property (readonly) NSString *lastActiveTLKUUID;
92
93 // Full of condition variables, if you'd like to try to wait until the key hierarchy is in some state
94 @property NSMutableDictionary<CKKSZoneKeyState*, CKKSCondition*>* keyHierarchyConditions;
95
96 @property CKKSZoneChangeFetcher* zoneChangeFetcher;
97
98 @property (weak) CKKSNearFutureScheduler* savedTLKNotifier;
99
100 // Differs from the zonesetupoperation: zoneSetup is only for CK modifications, viewSetup handles local db changes too
101 @property CKKSGroupOperation* viewSetupOperation;
102
103 /* Used for debugging: just what happened last time we ran this? */
104 @property CKKSIncomingQueueOperation* lastIncomingQueueOperation;
105 @property CKKSNewTLKOperation* lastNewTLKOperation;
106 @property CKKSOutgoingQueueOperation* lastOutgoingQueueOperation;
107 @property CKKSProcessReceivedKeysOperation* lastProcessReceivedKeysOperation;
108 @property CKKSFetchAllRecordZoneChangesOperation* lastRecordZoneChangesOperation;
109 @property CKKSReencryptOutgoingItemsOperation* lastReencryptOutgoingItemsOperation;
110 @property CKKSScanLocalItemsOperation* lastScanLocalItemsOperation;
111 @property CKKSSynchronizeOperation* lastSynchronizeOperation;
112
113 /* Used for testing: pause operation types by adding operations here */
114 @property NSOperation* holdReencryptOutgoingItemsOperation;
115 @property NSOperation* holdOutgoingQueueOperation;
116
117 /* Trigger this to tell the whole machine that this view has changed */
118 @property CKKSNearFutureScheduler* notifyViewChangedScheduler;
119
120 - (instancetype)initWithContainer: (CKContainer*) container
121 zoneName: (NSString*) zoneName
122 accountTracker:(CKKSCKAccountStateTracker*) accountTracker
123 lockStateTracker:(CKKSLockStateTracker*) lockStateTracker
124 savedTLKNotifier:(CKKSNearFutureScheduler*) savedTLKNotifier
125 fetchRecordZoneChangesOperationClass: (Class<CKKSFetchRecordZoneChangesOperation>) fetchRecordZoneChangesOperationClass
126 modifySubscriptionsOperationClass: (Class<CKKSModifySubscriptionsOperation>) modifySubscriptionsOperationClass
127 modifyRecordZonesOperationClass: (Class<CKKSModifyRecordZonesOperation>) modifyRecordZonesOperationClass
128 apsConnectionClass: (Class<CKKSAPSConnection>) apsConnectionClass
129 notifierClass: (Class<CKKSNotifier>) notifierClass;
130
131 /* Synchronous operations */
132
133 - (void) handleKeychainEventDbConnection:(SecDbConnectionRef) dbconn
134 added:(SecDbItemRef) added
135 deleted:(SecDbItemRef) deleted
136 rateLimiter:(CKKSRateLimiter*) rateLimiter
137 syncCallback:(SecBoolNSErrorCallback) syncCallback;
138
139 -(void)setCurrentItemForAccessGroup:(SecDbItemRef)newItem
140 hash:(NSData*)newItemSHA1
141 accessGroup:(NSString*)accessGroup
142 identifier:(NSString*)identifier
143 replacing:(SecDbItemRef)oldItem
144 hash:(NSData*)oldItemSHA1
145 complete:(void (^) (NSError* operror)) complete;
146
147 -(void)getCurrentItemForAccessGroup:(NSString*)accessGroup
148 identifier:(NSString*)identifier
149 fetchCloudValue:(bool)fetchCloudValue
150 complete:(void (^) (NSString* uuid, NSError* operror)) complete;
151
152 - (bool) outgoingQueueEmpty: (NSError * __autoreleasing *) error;
153
154 - (CKKSResultOperation*)waitForFetchAndIncomingQueueProcessing;
155 - (void) waitForKeyHierarchyReadiness;
156 - (void) cancelAllOperations;
157
158 - (CKKSKey*) keyForItem: (SecDbItemRef) item error: (NSError * __autoreleasing *) error;
159
160 - (bool)checkTLK: (CKKSKey*) proposedTLK error: (NSError * __autoreleasing *) error;
161
162 /* Asynchronous kickoffs */
163
164 - (void) initializeZone;
165
166 - (CKKSOutgoingQueueOperation*)processOutgoingQueue:(CKOperationGroup*)ckoperationGroup;
167 - (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation*)after ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
168
169 - (CKKSIncomingQueueOperation*) processIncomingQueue:(bool)failOnClassA;
170 - (CKKSIncomingQueueOperation*) processIncomingQueue:(bool)failOnClassA after: (CKKSResultOperation*) after;
171
172 // Schedules a process queueoperation to happen after the next device unlock. This may be Immediately, if the device is unlocked.
173 - (void)processIncomingQueueAfterNextUnlock;
174
175 // Schedules an operation to update this device's state record in CloudKit
176 // If rateLimit is true, the operation will abort if it's updated the record in the past 3 days
177 - (CKKSUpdateDeviceStateOperation*)updateDeviceState:(bool)rateLimit ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
178
179 - (CKKSSynchronizeOperation*) resyncWithCloud;
180
181 - (CKKSResultOperation*)fetchAndProcessCKChanges:(CKKSFetchBecause*)because;
182
183 - (CKKSResultOperation*)resetLocalData;
184 - (CKKSResultOperation*)resetCloudKitZone;
185
186 // Call this to pick and start the next key hierarchy operation for the zone
187 - (void)advanceKeyStateMachine;
188
189 // Call this to tell the key state machine that you think some new data has arrived that it is interested in
190 - (void)keyStateMachineRequestProcess;
191
192 // For our serial queue to work with how handleKeychainEventDbConnection is called from the main thread,
193 // every block on our queue must have a SecDBConnectionRef available to it before it begins on the queue.
194 // Use these helper methods to make sure those exist.
195 - (void) dispatchAsync: (bool (^)(void)) block;
196 - (void) dispatchSync: (bool (^)(void)) block;
197 - (void)dispatchSyncWithAccountQueue:(bool (^)(void))block;
198
199 /* Synchronous operations which must be called from inside a dispatchAsync or dispatchSync block */
200
201 // Call this to request the key hierarchy state machine to fetch new updates
202 - (void)_onqueueKeyStateMachineRequestFetch;
203
204 // Call this to request the key hierarchy state machine to refetch everything in Cloudkit
205 - (void)_onqueueKeyStateMachineRequestFullRefetch;
206
207 // Call this to request the key hierarchy state machine to reprocess
208 - (void)_onqueueKeyStateMachineRequestProcess;
209
210 // Call this from a key hierarchy operation to move the state machine, and record the results of the last move.
211 - (void)_onqueueAdvanceKeyStateMachineToState: (CKKSZoneKeyState*) state withError: (NSError*) error;
212
213 // Since we might have people interested in the state transitions of objects, please do those transitions via these methods
214 - (bool)_onqueueChangeOutgoingQueueEntry: (CKKSOutgoingQueueEntry*) oqe toState: (NSString*) state error: (NSError* __autoreleasing*) error;
215 - (bool)_onqueueErrorOutgoingQueueEntry: (CKKSOutgoingQueueEntry*) oqe itemError: (NSError*) itemError error: (NSError* __autoreleasing*) error;
216
217 // 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
218 //
219 // Note that you need to tell this function the records you wanted to save, so it can determine which record failed from its CKRecordID.
220 // I don't know why CKRecordIDs don't have record types, either.
221 - (bool)_onqueueCKWriteFailed:(NSError*)ckerror attemptedRecordsChanged:(NSDictionary<CKRecordID*,CKRecord*>*)savedRecords;
222
223 - (bool) _onqueueCKRecordChanged:(CKRecord*)record resync:(bool)resync;
224 - (bool) _onqueueCKRecordDeleted:(CKRecordID*)recordID recordType:(NSString*)recordType resync:(bool)resync;
225
226 - (bool)_onQueueUpdateLatestManifestWithError:(NSError**)error;
227
228 - (CKKSDeviceStateEntry*)_onqueueCurrentDeviceStateEntry: (NSError* __autoreleasing*)error;
229
230 // Called by the CKKSZoneChangeFetcher
231 - (bool) isFatalCKFetchError: (NSError*) error;
232
233 // Please don't use these unless you're an Operation in this package
234 @property NSHashTable<CKKSIncomingQueueOperation*>* incomingQueueOperations;
235 @property NSHashTable<CKKSOutgoingQueueOperation*>* outgoingQueueOperations;
236 @property CKKSScanLocalItemsOperation* initialScanOperation;
237
238 // Returns the current state of this view
239 -(NSDictionary<NSString*, NSString*>*)status;
240 @end
241 #endif // OCTAGON
242
243
244 #define SecTranslateError(nserrorptr, cferror) \
245 if(nserrorptr) { \
246 *nserrorptr = (__bridge_transfer NSError*) cferror; \
247 } else { \
248 CFReleaseNull(cferror); \
249 }
250
251 #endif /* CKKSKeychainView_h */