New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Error: cannotAccessKeychain despite canAccessKeychain()
returning true immediately before calling, caused by saving largeish data
#246
Comments
Go figure! Thank you for the detailed report with sample code. I agree that the README language needs updating (or we need to surface better errors). I've tried saving a couple hundred kb to the keychain before, but admittedly I never tried saving something so large. Excited to play with this and see what I find 🙂 |
You sound like you have more reasonable expectations of the Keychain than me. 😄 Happy to help, thank you again for the library! |
So I pulled this up in the debugger. Looks like we're getting We've managed to break the keychain! Looking into my console logs, I see the following:
Seems like we're literally crashing |
I was able to get crashes inserting a My sample code:
Since we don't know the upper size limit of a keychain item, I think we should likely update our in-code documentation here. Throwing Open to other approaches as well. How does the above sound to you? |
That sounds phenomenal to me! I would have been happy with even a "Hey doofus, don't try to store a ton of info in the Keychain, it's probably not going to work out" in the README, so this is even better. :) I think just communicating in the README to any library consumers that I'd lower than 5MB recommendation to even 1MB, I was able to make it crash on an iPhone 6 (not as often, but still sometimes) with a single megabyte. Might just be wise to mention the 1MB as a guideline and to inspect the size of data you're storing (as well as the device) if you're running into weird behavior. |
The other option I see here is to set some lower bound where we know there are issues (maybe 1 MB or so) and call That said, I think it's reasonable to update the documentation and say that large data blobs are not supported. |
While we could add an error case, given how little we know about this error I worry about creating an explicit contract. I think it's best to add some "here be dragons" warnings and call it a day. |
Dug a little bit around this and here are some findings: As of iOS 13.7, there is no hard limit defined by Keychain Services around the size of individual item being saved in the Keychain. The experiment in #246 (comment) was caused by Things get a little more interest when apps try to put data > 16MB into keychain. In that case, you'll get error -50, for invalid query.
It's pretty nice that Apple open sourced most of Keychain's implementation. After looking around for this error, it turned out that the Keychain APIs encodes client queries into DER format before sending it to the daemon, and on the daemon side, the decoding logic from Apple's corecrypto refuses to decode (in function For the soft limit, the implementation considered a reasonable size for data to be around 4KB. |
Great digging! Sounds like we should update our recommendation to 4K, and get less explicit about what'll happen if you exceed 🙂 |
I've ran into a bug where saving to the Keychain with Valet will fail with a "cannotAccessKeychain" error if you're saving larger amounts of data (say, several megabytes) despite everything else seeming proper and
canAccessKeychain()
being called immediately before returningtrue
.I ran into this because I foolishly was testing encrypting more of the user's data (performance was fine on modern devices) than necessary, and for some users with a large amount of data combined with older iOS devices they were running into issues with data saving. Sure enough I was able to replicate this within a few tries with an iPhone 6 running iOS 12.4.3.
I was admittedly lulled to a false sense of security a little (totally my fault, should have done my due diligence) by this phrase in the README that maybe should be updated to reflect issues around larger data saving:
In this can
canAccessKeychain
indeed returns true, but the call immediately following it will fail. Here's an exaggerated test case showing it with a 10MB data set (excuse the forced unwrapping, just for illustrative purposes):(It may take a few tries to reproduce, but I see the same error that users are reporting. On main thread in this example if relevant, but occurs on background threads as well. Also my logs show the error occurring on the most up to date version of iOS 13 (13.7) as well as the most recent iOS 14 beta, so it doesn't seem to be limited to iOS 12. Also worth mentioning it happens in other libraries like Lockbox so it appears to be an internal Keychain issue, not specific to Valet, but still might be worth mentioning in that exceptions section.)
Again, 100% my dumb fault for saving things larger than I likely should be and not testing thoroughly enough on older devices, but thought it might be helpful to mention in case anyone else runs into it.
And thank you for the library!
The text was updated successfully, but these errors were encountered: