Our app runs a background task while it's locked that calls a web service, and presents a URLCredential with a SecIdentity. It works fine if you simulate the background task using,
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.ourapp.extendedtask"]
but when it actually runs in the background with the device locked, and I try to fetch the SecIdentity
from the Keychain using SecItemCopyMatching,
it fails with
-25308 (errSecInteractionNotAllowed)
I tried adding kSecAttrAccessibleAfterFirstUnlock
when writing to the Keychain like this,
let keychainAddQuery: [String: Any] = [
kSecValueRef as String: identity,
kSecAttrLabel as String: "certKey",
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock
]
let addResult = SecItemAdd(keychainAddQuery as CFDictionary, nil)
But it still fails when the background task tries to fetch it from the Keychain using SecItemCopyMatching.
I could try using
kSecAttrAccessibleAlways
when I write to the Keychain, but the documentation says that is deprecated.
Is there a way to write the SecIdentity
to a file and storing that within the Application Support folder rather than in the Keychain? So it's accessible when the BackgroundTask runs while the device is locked?
Our original approach was to put the PFX file in the Application Support folder, and store the password in the Keychain, then use SecPKCS12Import
to generate the SecIdentity
. However, it never gets that far, because fetching the password with SecItemCopyMatching
didn't work due to the errSecInteractionNotAllowed
issue. I then tried writing the SecIdentity
itself to the Keychain using SecItemAdd
as shown above, but encountered the same problem when the Background Task tried to fetch it using SecItemCopyMatching.
I realize now it's not an issue with the specifics of the data being fetched from the Keychain, but rather a security issue reading from the Keychain while in the background.
If the item has already been added to the Keychain, it won't update unless you explicitly delete it with SecItemDelete,
or update it with SecItemUpdate
. Once I deleted it and re-added it, it does work using kSecAttrAccessibleAfterFirstUnlock.
Still curious if this could be done without the Keychain, but I'm guessing that's you only choice, or I would've come across more code examples showing alternate methods.