X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/8a50f688fe9358387648fb83fbfecbefe8d32669..07691282a056c4efea71e1e505527601e8cc166b:/keychain/ckks/CKKSKeychainView.h?ds=inline diff --git a/keychain/ckks/CKKSKeychainView.h b/keychain/ckks/CKKSKeychainView.h index f10395e0..b5ab8e2d 100644 --- a/keychain/ckks/CKKSKeychainView.h +++ b/keychain/ckks/CKKSKeychainView.h @@ -21,47 +21,40 @@ * @APPLE_LICENSE_HEADER_END@ */ - -#ifndef CKKSKeychainView_h -#define CKKSKeychainView_h - +#if OCTAGON #import #include -#if OCTAGON -#import "keychain/ckks/CloudKitDependencies.h" #import "keychain/ckks/CKKSAPSReceiver.h" #import "keychain/ckks/CKKSLockStateTracker.h" -#endif +#import "keychain/ckks/CKKSReachabilityTracker.h" +#import "keychain/ckks/CloudKitDependencies.h" -#include #include +#include #import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h" +#import "keychain/ckks/CKKSGroupOperation.h" #import "keychain/ckks/CKKSIncomingQueueOperation.h" -#import "keychain/ckks/CKKSOutgoingQueueOperation.h" #import "keychain/ckks/CKKSNearFutureScheduler.h" #import "keychain/ckks/CKKSNewTLKOperation.h" +#import "keychain/ckks/CKKSNotifier.h" +#import "keychain/ckks/CKKSOutgoingQueueOperation.h" +#import "keychain/ckks/CKKSPeer.h" #import "keychain/ckks/CKKSProcessReceivedKeysOperation.h" #import "keychain/ckks/CKKSReencryptOutgoingItemsOperation.h" -#import "keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h" #import "keychain/ckks/CKKSScanLocalItemsOperation.h" +#import "keychain/ckks/CKKSTLKShare.h" #import "keychain/ckks/CKKSUpdateDeviceStateOperation.h" -#import "keychain/ckks/CKKSGroupOperation.h" #import "keychain/ckks/CKKSZone.h" #import "keychain/ckks/CKKSZoneChangeFetcher.h" -#import "keychain/ckks/CKKSNotifier.h" -#import "keychain/ckks/CKKSPeer.h" -#import "keychain/ckks/CKKSTLKShare.h" +#import "keychain/ckks/CKKSSynchronizeOperation.h" +#import "keychain/ckks/CKKSLocalSynchronizeOperation.h" #include "CKKS.h" -# if !OCTAGON -@interface CKKSKeychainView : NSObject { - NSString* _containerName; -} -@end -#else // OCTAGON +NS_ASSUME_NONNULL_BEGIN @class CKKSKey; @class CKKSAESSIVKey; @@ -72,27 +65,36 @@ @class CKKSOutgoingQueueEntry; @class CKKSZoneChangeFetcher; -@interface CKKSKeychainView : CKKSZone { +@interface CKKSKeychainView : CKKSZone +{ CKKSZoneKeyState* _keyHierarchyState; } +@property CKKSCondition* loggedIn; +@property CKKSCondition* loggedOut; +@property CKKSCondition* accountStateKnown; + @property CKKSLockStateTracker* lockStateTracker; @property CKKSZoneKeyState* keyHierarchyState; -@property NSError* keyHierarchyError; -@property CKOperationGroup* keyHierarchyOperationGroup; -@property NSOperation* keyStateMachineOperation; +@property (nullable) NSError* keyHierarchyError; +@property (nullable) CKOperationGroup* keyHierarchyOperationGroup; +@property (nullable) NSOperation* keyStateMachineOperation; // If the key hierarchy isn't coming together, it might be because we're out of sync with cloudkit. // Use this to track if we've completed a full refetch, so fix-up operations can be done. @property bool keyStateMachineRefetched; -@property CKKSEgoManifest* egoManifest; -@property CKKSManifest* latestManifest; -@property CKKSResultOperation* keyStateReadyDependency; +@property (nullable) CKKSEgoManifest* egoManifest; +@property (nullable) CKKSManifest* latestManifest; +@property (nullable) CKKSResultOperation* keyStateReadyDependency; -@property (readonly) NSString *lastActiveTLKUUID; +// Wait for the key state to become 'nontransient': no pending operation is expected to advance it (at least until user intervenes) +@property (nullable) CKKSResultOperation* keyStateNonTransientDependency; + +// True if we believe there's any items in the keychain which haven't been brought up in CKKS yet +@property bool droppedItems; + +@property (readonly) NSString* lastActiveTLKUUID; // Full of condition variables, if you'd like to try to wait until the key hierarchy is in some state @property NSMutableDictionary* keyHierarchyConditions; @@ -101,27 +103,29 @@ @property (weak) CKKSNearFutureScheduler* savedTLKNotifier; -// Differs from the zonesetupoperation: zoneSetup is only for CK modifications, viewSetup handles local db changes too -@property CKKSGroupOperation* viewSetupOperation; - /* Used for debugging: just what happened last time we ran this? */ -@property CKKSIncomingQueueOperation* lastIncomingQueueOperation; -@property CKKSNewTLKOperation* lastNewTLKOperation; -@property CKKSOutgoingQueueOperation* lastOutgoingQueueOperation; -@property CKKSProcessReceivedKeysOperation* lastProcessReceivedKeysOperation; -@property CKKSFetchAllRecordZoneChangesOperation* lastRecordZoneChangesOperation; -@property CKKSReencryptOutgoingItemsOperation* lastReencryptOutgoingItemsOperation; -@property CKKSScanLocalItemsOperation* lastScanLocalItemsOperation; -@property CKKSSynchronizeOperation* lastSynchronizeOperation; -@property CKKSResultOperation* lastFixupOperation; +@property CKKSIncomingQueueOperation* lastIncomingQueueOperation; +@property CKKSNewTLKOperation* lastNewTLKOperation; +@property CKKSOutgoingQueueOperation* lastOutgoingQueueOperation; +@property CKKSProcessReceivedKeysOperation* lastProcessReceivedKeysOperation; +@property CKKSReencryptOutgoingItemsOperation* lastReencryptOutgoingItemsOperation; +@property CKKSScanLocalItemsOperation* lastScanLocalItemsOperation; +@property CKKSSynchronizeOperation* lastSynchronizeOperation; +@property CKKSResultOperation* lastFixupOperation; /* Used for testing: pause operation types by adding operations here */ @property NSOperation* holdReencryptOutgoingItemsOperation; @property NSOperation* holdOutgoingQueueOperation; +@property NSOperation* holdIncomingQueueOperation; +@property NSOperation* holdLocalSynchronizeOperation; +@property CKKSResultOperation* holdFixupOperation; /* Trigger this to tell the whole machine that this view has changed */ @property CKKSNearFutureScheduler* notifyViewChangedScheduler; +/* trigger this to request key state machine poking */ +@property CKKSNearFutureScheduler* pokeKeyStateMachineScheduler; + // These are available when you're in a dispatchSyncWithAccountKeys call, but at no other time // These must be pre-fetched before you get on the CKKS queue, otherwise we end up with CKKS<->SQLite<->SOSAccountQueue deadlocks @property (nonatomic, readonly) CKKSSelves* currentSelfPeers; @@ -129,79 +133,83 @@ @property (nonatomic, readonly) NSSet>* currentTrustedPeers; @property (nonatomic, readonly) NSError* currentTrustedPeersError; -- (instancetype)initWithContainer: (CKContainer*) container - zoneName: (NSString*) zoneName - accountTracker:(CKKSCKAccountStateTracker*) accountTracker - lockStateTracker:(CKKSLockStateTracker*) lockStateTracker - savedTLKNotifier:(CKKSNearFutureScheduler*) savedTLKNotifier - peerProvider:(id)peerProvider - fetchRecordZoneChangesOperationClass: (Class) fetchRecordZoneChangesOperationClass - fetchRecordsOperationClass: (Class)fetchRecordsOperationClass - queryOperationClass:(Class)queryOperationClass - modifySubscriptionsOperationClass: (Class) modifySubscriptionsOperationClass - modifyRecordZonesOperationClass: (Class) modifyRecordZonesOperationClass - apsConnectionClass: (Class) apsConnectionClass - notifierClass: (Class) notifierClass; +- (instancetype)initWithContainer:(CKContainer*)container + zoneName:(NSString*)zoneName + accountTracker:(CKKSCKAccountStateTracker*)accountTracker + lockStateTracker:(CKKSLockStateTracker*)lockStateTracker + reachabilityTracker:(CKKSReachabilityTracker *)reachabilityTracker + changeFetcher:(CKKSZoneChangeFetcher*)fetcher + savedTLKNotifier:(CKKSNearFutureScheduler*)savedTLKNotifier + peerProvider:(id)peerProvider + fetchRecordZoneChangesOperationClass:(Class)fetchRecordZoneChangesOperationClass + fetchRecordsOperationClass:(Class)fetchRecordsOperationClass + queryOperationClass:(Class)queryOperationClass + modifySubscriptionsOperationClass:(Class)modifySubscriptionsOperationClass + modifyRecordZonesOperationClass:(Class)modifyRecordZonesOperationClass + apsConnectionClass:(Class)apsConnectionClass + notifierClass:(Class)notifierClass; /* Synchronous operations */ -- (void) handleKeychainEventDbConnection:(SecDbConnectionRef) dbconn - added:(SecDbItemRef) added - deleted:(SecDbItemRef) deleted - rateLimiter:(CKKSRateLimiter*) rateLimiter - syncCallback:(SecBoolNSErrorCallback) syncCallback; +- (void)handleKeychainEventDbConnection:(SecDbConnectionRef)dbconn + added:(SecDbItemRef _Nullable)added + deleted:(SecDbItemRef _Nullable)deleted + rateLimiter:(CKKSRateLimiter*)rateLimiter + syncCallback:(SecBoolNSErrorCallback)syncCallback; --(void)setCurrentItemForAccessGroup:(SecDbItemRef)newItem - hash:(NSData*)newItemSHA1 - accessGroup:(NSString*)accessGroup - identifier:(NSString*)identifier - replacing:(SecDbItemRef)oldItem - hash:(NSData*)oldItemSHA1 - complete:(void (^) (NSError* operror)) complete; +- (void)setCurrentItemForAccessGroup:(NSData*)newItemPersistentRef + hash:(NSData*)newItemSHA1 + accessGroup:(NSString*)accessGroup + identifier:(NSString*)identifier + replacing:(NSData* _Nullable)oldCurrentItemPersistentRef + hash:(NSData* _Nullable)oldItemSHA1 + complete:(void (^)(NSError* operror))complete; --(void)getCurrentItemForAccessGroup:(NSString*)accessGroup - identifier:(NSString*)identifier - fetchCloudValue:(bool)fetchCloudValue - complete:(void (^) (NSString* uuid, NSError* operror)) complete; +- (void)getCurrentItemForAccessGroup:(NSString*)accessGroup + identifier:(NSString*)identifier + fetchCloudValue:(bool)fetchCloudValue + complete:(void (^)(NSString* uuid, NSError* operror))complete; -- (bool) outgoingQueueEmpty: (NSError * __autoreleasing *) error; +- (bool)outgoingQueueEmpty:(NSError* __autoreleasing*)error; - (CKKSResultOperation*)waitForFetchAndIncomingQueueProcessing; -- (void) waitForKeyHierarchyReadiness; -- (void) cancelAllOperations; +- (void)waitForKeyHierarchyReadiness; +- (void)cancelAllOperations; -- (CKKSKey*) keyForItem: (SecDbItemRef) item error: (NSError * __autoreleasing *) error; +- (CKKSKey* _Nullable)keyForItem:(SecDbItemRef)item error:(NSError* __autoreleasing*)error; -- (bool)_onqueueWithAccountKeysCheckTLK: (CKKSKey*) proposedTLK error: (NSError * __autoreleasing *) error; +- (bool)_onqueueWithAccountKeysCheckTLK:(CKKSKey*)proposedTLK error:(NSError* __autoreleasing*)error; /* Asynchronous kickoffs */ -- (void) initializeZone; +- (CKKSOutgoingQueueOperation*)processOutgoingQueue:(CKOperationGroup* _Nullable)ckoperationGroup; +- (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation* _Nullable)after + ckoperationGroup:(CKOperationGroup* _Nullable)ckoperationGroup; -- (CKKSOutgoingQueueOperation*)processOutgoingQueue:(CKOperationGroup*)ckoperationGroup; -- (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation*)after ckoperationGroup:(CKOperationGroup*)ckoperationGroup; +- (CKKSIncomingQueueOperation*)processIncomingQueue:(bool)failOnClassA; +- (CKKSIncomingQueueOperation*)processIncomingQueue:(bool)failOnClassA after:(CKKSResultOperation* _Nullable)after; -- (CKKSIncomingQueueOperation*) processIncomingQueue:(bool)failOnClassA; -- (CKKSIncomingQueueOperation*) processIncomingQueue:(bool)failOnClassA after: (CKKSResultOperation*) after; +- (CKKSScanLocalItemsOperation*)scanLocalItems:(NSString*)name; // Schedules a process queueoperation to happen after the next device unlock. This may be Immediately, if the device is unlocked. - (void)processIncomingQueueAfterNextUnlock; +// This operation will complete directly after the next ProcessIncomingQueue, and should supply that IQO's result. Used mainly for testing; otherwise you'd just kick off a IQO directly. +- (CKKSResultOperation*)resultsOfNextProcessIncomingQueueOperation; + // Schedules an operation to update this device's state record in CloudKit // If rateLimit is true, the operation will abort if it's updated the record in the past 3 days - (CKKSUpdateDeviceStateOperation*)updateDeviceState:(bool)rateLimit waitForKeyHierarchyInitialization:(uint64_t)timeout - ckoperationGroup:(CKOperationGroup*)ckoperationGroup; + ckoperationGroup:(CKOperationGroup* _Nullable)ckoperationGroup; -- (CKKSSynchronizeOperation*) resyncWithCloud; +- (CKKSSynchronizeOperation*)resyncWithCloud; +- (CKKSLocalSynchronizeOperation*)resyncLocal; - (CKKSResultOperation*)fetchAndProcessCKChanges:(CKKSFetchBecause*)because; - (CKKSResultOperation*)resetLocalData; -- (CKKSResultOperation*)resetCloudKitZone; - -// Call this to pick and start the next key hierarchy operation for the zone -- (void)advanceKeyStateMachine; +- (CKKSResultOperation*)resetCloudKitZone:(CKOperationGroup*)operationGroup; // Call this to tell the key state machine that you think some new data has arrived that it is interested in - (void)keyStateMachineRequestProcess; @@ -209,68 +217,65 @@ // For our serial queue to work with how handleKeychainEventDbConnection is called from the main thread, // every block on our queue must have a SecDBConnectionRef available to it before it begins on the queue. // Use these helper methods to make sure those exist. -- (void) dispatchAsync: (bool (^)(void)) block; -- (void) dispatchSync: (bool (^)(void)) block; +- (void)dispatchSync:(bool (^)(void))block; - (void)dispatchSyncWithAccountKeys:(bool (^)(void))block; -/* Synchronous operations which must be called from inside a dispatchAsync or dispatchSync block */ +/* Synchronous operations which must be called from inside a dispatchAsyncWithAccountKeys or dispatchSync block */ // Call this to request the key hierarchy state machine to fetch new updates - (void)_onqueueKeyStateMachineRequestFetch; -// Call this to request the key hierarchy state machine to refetch everything in Cloudkit -- (void)_onqueueKeyStateMachineRequestFullRefetch; - // Call this to request the key hierarchy state machine to reprocess - (void)_onqueueKeyStateMachineRequestProcess; // Call this from a key hierarchy operation to move the state machine, and record the results of the last move. -- (void)_onqueueAdvanceKeyStateMachineToState: (CKKSZoneKeyState*) state withError: (NSError*) error; +- (void)_onqueueAdvanceKeyStateMachineToState:(CKKSZoneKeyState* _Nullable)state withError:(NSError* _Nullable)error; // Since we might have people interested in the state transitions of objects, please do those transitions via these methods -- (bool)_onqueueChangeOutgoingQueueEntry: (CKKSOutgoingQueueEntry*) oqe toState: (NSString*) state error: (NSError* __autoreleasing*) error; -- (bool)_onqueueErrorOutgoingQueueEntry: (CKKSOutgoingQueueEntry*) oqe itemError: (NSError*) itemError error: (NSError* __autoreleasing*) error; +- (bool)_onqueueChangeOutgoingQueueEntry:(CKKSOutgoingQueueEntry*)oqe + toState:(NSString*)state + error:(NSError* __autoreleasing*)error; +- (bool)_onqueueErrorOutgoingQueueEntry:(CKKSOutgoingQueueEntry*)oqe + itemError:(NSError*)itemError + error:(NSError* __autoreleasing*)error; // 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 // // Note that you need to tell this function the records you wanted to save, so it can determine which record failed from its CKRecordID. // I don't know why CKRecordIDs don't have record types, either. -- (bool)_onqueueCKWriteFailed:(NSError*)ckerror attemptedRecordsChanged:(NSDictionary*)savedRecords; +- (bool)_onqueueCKWriteFailed:(NSError*)ckerror attemptedRecordsChanged:(NSDictionary*)savedRecords; -- (bool) _onqueueCKRecordChanged:(CKRecord*)record resync:(bool)resync; -- (bool) _onqueueCKRecordDeleted:(CKRecordID*)recordID recordType:(NSString*)recordType resync:(bool)resync; +- (bool)_onqueueCKRecordChanged:(CKRecord*)record resync:(bool)resync; +- (bool)_onqueueCKRecordDeleted:(CKRecordID*)recordID recordType:(NSString*)recordType resync:(bool)resync; -// For this key, who doesn't yet have a CKKSTLKShare for it? +// For this key, who doesn't yet have a CKKSTLKShare for it, shared to their current Octagon keys? // Note that we really want a record sharing the TLK to ourselves, so this function might return // a non-empty set even if all peers have the TLK: it wants us to make a record for ourself. -- (NSSet>*)_onqueueFindPeersMissingShare:(CKKSKey*)key error:(NSError* __autoreleasing*)error; +- (NSSet>* _Nullable)_onqueueFindPeersMissingShare:(CKKSKey*)key error:(NSError* __autoreleasing*)error; // For this key, share it to all trusted peers who don't have it yet -- (NSSet*)_onqueueCreateMissingKeyShares:(CKKSKey*)key error:(NSError* __autoreleasing*)error; - -- (bool)_onQueueUpdateLatestManifestWithError:(NSError**)error; +- (NSSet* _Nullable)_onqueueCreateMissingKeyShares:(CKKSKey*)key error:(NSError* __autoreleasing*)error; -- (CKKSDeviceStateEntry*)_onqueueCurrentDeviceStateEntry: (NSError* __autoreleasing*)error; +- (bool)_onqueueUpdateLatestManifestWithError:(NSError**)error; -// Called by the CKKSZoneChangeFetcher -- (bool) isFatalCKFetchError: (NSError*) error; +- (CKKSDeviceStateEntry* _Nullable)_onqueueCurrentDeviceStateEntry:(NSError* __autoreleasing*)error; // Please don't use these unless you're an Operation in this package @property NSHashTable* incomingQueueOperations; @property NSHashTable* outgoingQueueOperations; @property CKKSScanLocalItemsOperation* initialScanOperation; -// Returns the current state of this view --(NSDictionary*)status; +// Returns the current state of this view, fastStatus is the same, but as name promise, no expensive calculations +- (NSDictionary*)status; +- (NSDictionary*)fastStatus; @end -#endif // OCTAGON - - -#define SecTranslateError(nserrorptr, cferror) \ - if(nserrorptr) { \ - *nserrorptr = (__bridge_transfer NSError*) cferror; \ - } else { \ - CFReleaseNull(cferror); \ - } -#endif /* CKKSKeychainView_h */ +NS_ASSUME_NONNULL_END +#else // !OCTAGON +#import +@interface CKKSKeychainView : NSObject +{ + NSString* _containerName; +} +@end +#endif // OCTAGON