10 Replies
      Latest reply on Apr 1, 2019 3:27 AM by eskimo
      LoileeBooz Level 1 Level 1 (0 points)

        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?

        • Re: KeyChain SecItemAdd return -25308 when app is launched from a "suspended" state
          eskimo Apple Staff Apple Staff (11,265 points)

          Error -25308 is errSecInteractionNotAllowed.  This usually means that you’re trying to access a keychain item that’s not accessible while the device is locked.

          I’m not sure how you go from this error to a crash.  The OS won’t automatically crash your process when this error occurs.  Rather, the relevant keychain API call will return this error and it’s up to your app to handle that case.  Is your code crashing as a result of this error?

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: KeyChain SecItemAdd return -25308 when app is launched
              LoileeBooz Level 1 Level 1 (0 points)

              You are right eskimo, sorry for the confusion. I rewrote the question.

                • Re: KeyChain SecItemAdd return -25308 when app is launched
                  eskimo Apple Staff Apple Staff (11,265 points)

                  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:

                  1. Your app is run by the user and everything is good.

                  2. The user presses the Home button and your app moves to the background.

                  3. Shortly thereafter the system suspends your app.

                  4. At some point in the future, the system needs memory and thus removes your suspended app from memory.

                  5. The user locks their device.

                  6. At some point in the future a location event causes the system to launch your app in the background.

                  7. Your ‘willFinishLaunchingWithOptions’ app delegate method runs.  If it attempts to access a keychain item with kSecAttrAccessible set to kSecAttrAccessibleWhenUnlocked, that access will fail because the device is locked.

                  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 kSecAttrAccessible 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 use kSecAttrAccessibleAfterFirstUnlock.  However, some background execution can happen before first unlock, in which case you’ll need kSecAttrAccessibleAlways.  This is measurably less secure.

                  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"

                    • Re: KeyChain SecItemAdd return -25308 when app is launched
                      LoileeBooz Level 1 Level 1 (0 points)

                      Thank you for the very quick reply.
                      We thought about those 2 approaches that you mention and it's good that it is confirmed.
                      We will also look into NSURLFileProtectionKey.

                      Cheers!

                      • Re: KeyChain SecItemAdd return -25308 when app is launched
                        Loilee Level 1 Level 1 (0 points)

                        We try moving the reading/writing of keychain to MainViewController in viewDidAppear() event but our customers still encounter the same -25308 error. Any idea why this is the case?

                          • Re: KeyChain SecItemAdd return -25308 when app is launched
                            eskimo Apple Staff Apple Staff (11,265 points)

                            It’s possible that the device is still locked at this point.  What does UIApplication.isProtectedDataAvailable return when you get this error?

                            Share and Enjoy

                            Quinn “The Eskimo!”
                            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                            let myEmail = "eskimo" + "1" + "@apple.com"

                              • Re: KeyChain SecItemAdd return -25308 when app is launched
                                Loilee Level 1 Level 1 (0 points)

                                I added logs to check isProtectedDataAvailable and deploy to customers.

                                Is it possible for a viewDidAppear event to execute even if device is locked?

                                  • Re: KeyChain SecItemAdd return -25308 when app is launched
                                    eskimo Apple Staff Apple Staff (11,265 points)

                                    Is it possible for a viewDidAppear event to execute even if device is locked?

                                    I don’t know for sure, but that’s what I suspect is going on.

                                    This is less nonsensical than it sounds: One of the key features of iOS multitasking is that the system takes snapshots of your app to show to the user in the multitasking UI.  To snapshot your app it must present your views, and that’ll involve a call to viewDidAppear(_:).

                                    Share and Enjoy

                                    Quinn “The Eskimo!”
                                    Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                    let myEmail = "eskimo" + "1" + "@apple.com"

                                      • Re: KeyChain SecItemAdd return -25308 when app is launched
                                        Loilee Level 1 Level 1 (0 points)

                                        Got new results from the logs we put in place.

                                        appState = background

                                        isProtectedDataAvailable = false

                                         

                                        We monitored it with some customers and find that it activates only when there is location update(geofencing).

                                        If the snapshot mechanism is really the culprit, then the solution is to guard against accessing the keychain when isProtectedDataAvailable is false. However when this happens, what should we do with the state of the app?

                                        Can we kill the process? or is there a more elegant way to implement this?

                                          • Re: KeyChain SecItemAdd return -25308 when app is launched
                                            eskimo Apple Staff Apple Staff (11,265 points)

                                            what should we do with the state of the app?

                                            There isn’t an easy answer to that.  You either have to restructure your app to support running when protected data is unavailable, or disable the code that causes you to run in the background.  If you don’t want to do the latter, then you need to do the engineering work to support the former.

                                            The first step there is deciding what your app should display when protected data is unavailable, and then working through the layers of your app to meet that goal.

                                            Share and Enjoy

                                            Quinn “The Eskimo!”
                                            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                            let myEmail = "eskimo" + "1" + "@apple.com"