2 * Copyright (c) 2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #ifndef CKKSKeychainView_h
26 #define CKKSKeychainView_h
28 #import <Foundation/Foundation.h>
29 #include <dispatch/dispatch.h>
32 #import "keychain/ckks/CloudKitDependencies.h"
33 #import "keychain/ckks/CKKSAPSReceiver.h"
34 #import "keychain/ckks/CKKSLockStateTracker.h"
37 #include <utilities/SecDb.h>
38 #include <securityd/SecDbItem.h>
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"
58 @interface CKKSKeychainView
: NSObject
{
59 NSString
* _containerName
;
66 @
class CKKSSynchronizeOperation
;
67 @
class CKKSRateLimiter
;
69 @
class CKKSEgoManifest
;
70 @
class CKKSOutgoingQueueEntry
;
71 @
class CKKSZoneChangeFetcher
;
73 @interface CKKSKeychainView
: CKKSZone
<CKKSZoneUpdateReceiver
, CKKSChangeFetcherErrorOracle
> {
74 CKKSZoneKeyState
* _keyHierarchyState
;
77 @property CKKSLockStateTracker
* lockStateTracker
;
79 @property CKKSZoneKeyState
* keyHierarchyState
;
80 @property NSError
* keyHierarchyError
;
81 @property CKOperationGroup
* keyHierarchyOperationGroup
;
82 @property NSOperation
* keyStateMachineOperation
;
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
;
91 @
property (readonly
) NSString
*lastActiveTLKUUID
;
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
;
96 @property CKKSZoneChangeFetcher
* zoneChangeFetcher
;
98 @
property (weak
) CKKSNearFutureScheduler
* savedTLKNotifier
;
100 // Differs from the zonesetupoperation: zoneSetup is only for CK modifications, viewSetup handles local db changes too
101 @property CKKSGroupOperation
* viewSetupOperation
;
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
;
113 /* Used for testing: pause operation types by adding operations here */
114 @property NSOperation
* holdReencryptOutgoingItemsOperation
;
115 @property NSOperation
* holdOutgoingQueueOperation
;
117 /* Trigger this to tell the whole machine that this view has changed */
118 @property CKKSNearFutureScheduler
* notifyViewChangedScheduler
;
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
;
131 /* Synchronous operations */
133 - (void) handleKeychainEventDbConnection
:(SecDbConnectionRef
) dbconn
134 added
:(SecDbItemRef
) added
135 deleted
:(SecDbItemRef
) deleted
136 rateLimiter
:(CKKSRateLimiter
*) rateLimiter
137 syncCallback
:(SecBoolNSErrorCallback
) syncCallback
;
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
;
147 -(void)getCurrentItemForAccessGroup
:(NSString
*)accessGroup
148 identifier
:(NSString
*)identifier
149 fetchCloudValue
:(bool)fetchCloudValue
150 complete
:(void (^) (NSString
* uuid
, NSError
* operror
)) complete
;
152 - (bool) outgoingQueueEmpty
: (NSError
* __autoreleasing
*) error
;
154 - (CKKSResultOperation
*)waitForFetchAndIncomingQueueProcessing
;
155 - (void) waitForKeyHierarchyReadiness
;
156 - (void) cancelAllOperations
;
158 - (CKKSKey
*) keyForItem
: (SecDbItemRef
) item error
: (NSError
* __autoreleasing
*) error
;
160 - (bool)checkTLK
: (CKKSKey
*) proposedTLK error
: (NSError
* __autoreleasing
*) error
;
162 /* Asynchronous kickoffs */
164 - (void) initializeZone
;
166 - (CKKSOutgoingQueueOperation
*)processOutgoingQueue
:(CKOperationGroup
*)ckoperationGroup
;
167 - (CKKSOutgoingQueueOperation
*)processOutgoingQueueAfter
:(CKKSResultOperation
*)after ckoperationGroup
:(CKOperationGroup
*)ckoperationGroup
;
169 - (CKKSIncomingQueueOperation
*) processIncomingQueue
:(bool)failOnClassA
;
170 - (CKKSIncomingQueueOperation
*) processIncomingQueue
:(bool)failOnClassA after
: (CKKSResultOperation
*) after
;
172 // Schedules a process queueoperation to happen after the next device unlock. This may be Immediately, if the device is unlocked.
173 - (void)processIncomingQueueAfterNextUnlock
;
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
;
179 - (CKKSSynchronizeOperation
*) resyncWithCloud
;
181 - (CKKSResultOperation
*)fetchAndProcessCKChanges
:(CKKSFetchBecause
*)because
;
183 - (CKKSResultOperation
*)resetLocalData
;
184 - (CKKSResultOperation
*)resetCloudKitZone
;
186 // Call this to pick and start the next key hierarchy operation for the zone
187 - (void)advanceKeyStateMachine
;
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
;
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
;
199 /* Synchronous operations which must be called from inside a dispatchAsync or dispatchSync block */
201 // Call this to request the key hierarchy state machine to fetch new updates
202 - (void)_onqueueKeyStateMachineRequestFetch
;
204 // Call this to request the key hierarchy state machine to refetch everything in Cloudkit
205 - (void)_onqueueKeyStateMachineRequestFullRefetch
;
207 // Call this to request the key hierarchy state machine to reprocess
208 - (void)_onqueueKeyStateMachineRequestProcess
;
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
;
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
;
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
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
;
223 - (bool) _onqueueCKRecordChanged
:(CKRecord
*)record resync
:(bool)resync
;
224 - (bool) _onqueueCKRecordDeleted
:(CKRecordID
*)recordID recordType
:(NSString
*)recordType resync
:(bool)resync
;
226 - (bool)_onQueueUpdateLatestManifestWithError
:(NSError
**)error
;
228 - (CKKSDeviceStateEntry
*)_onqueueCurrentDeviceStateEntry
: (NSError
* __autoreleasing
*)error
;
230 // Called by the CKKSZoneChangeFetcher
231 - (bool) isFatalCKFetchError
: (NSError
*) error
;
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
;
238 // Returns the current state of this view
239 -(NSDictionary
<NSString
*, NSString
*>*)status
;
244 #define SecTranslateError(nserrorptr, cferror) \
246 *nserrorptr = (__bridge_transfer NSError*) cferror; \
248 CFReleaseNull(cferror); \
251 #endif /* CKKSKeychainView_h */