The app I am working on cannot access the KeyChain on more than 50% of the user base ever
since I enable Background Modes for Location Update for MarketingCloud SDK which I integrated.
The app has Keychain Sharing enabled.
The code is:
KeyChain is read to get an encryption key, if it is not found, we create a new encryption key which is used for open a database needed to launch the app. This code is executed in AppDelegate willFinishLaunchingWithOptions.
We intentionally kill the app when KeyChain returns an error since the app logic is dependent on the database.
We cannot reproduce the same issue.
Our question is, when is the keychain available for access? Should we delay(don't use it in AppDelegate) access to the keychain during app launch?
Once you enable your app to run into the background you have to start caring about data protection, and specifically the keychain access attribute. Consider a scenario like this:
Your app is run by the user and everything is good.
The user presses the Home button and your app moves to the background.
Shortly thereafter the system suspends your app.
At some point in the future, the system needs memory and thus removes your suspended app from memory.
The user locks their device.
At some point in the future a location event causes the system to launch your app in the background.
Your ‘willFinishLaunchingWithOptions’ app delegate method runs. If it attempts to access a keychain item with
set tokSecAttrAccessible
, that access will fail because the device is locked.kSecAttrAccessibleWhenUnlocked
How you resolve this depends on the nature of your app:
If you only need your database when the app is showing UI, you can defer this access until the app is on screen. The app can only come on screen if the device is unlocked.
If you need your database while in the background, you can set
to something less secure. The exact value depends on how your app gets run in the background. Most background execution is deferred until first unlock, and thus you can usekSecAttrAccessible
. However, some background execution can happen before first unlock, in which case you’ll needkSecAttrAccessibleAfterFirstUnlock
. This is measurably less secure.kSecAttrAccessibleAlways
Obviously it’s best to keep your data as secure as possible, so you should only use the second approach if your database is absolutely critical to the background operation of your app. You may be able to come up with a hybrid approach, where you split your database in two, using better protection in general but less protection for the critical-to-background-execution stuff. Or if you only need to write to your database, you could temporarily write new data to a less secure database and then consolidate things when the device is unlocked.
Keep in mind that the keychain is not the only place where data protection applies. Ideally you should protect your files on disk as well, using the various file protection modes. The preferred API for this is
NSURLFileProtectionKey
in
NSURL
, but most of the documentation you’ll find for the older
NSFileProtectionKey
in in
NSFileManager
.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"