December 27, 2017 update:
According to this post on the Apple Developer forums regarding the issue discussed in this topic,
This is a bug in the beta that should already be fixed by the time you read this.
kSecAttrAccessGroupToken is writable only by CryptoTokenKit smart card drivers. Apps can query the keychain using that attribute in order to find items stored on a particular smart card. This attribute is not for any other use.
It appears as though the kSecAttrAccessGroupToken access group was never meant to be writable by any app outside of CryptoTokenKit. This means that normal apps like yours and mine cannot make use of this access group for the purpose of writing our own custom data to it.
It’s also worth noting that the keychain autodelete behaviour which was observed in the iOS 10.3 beta did not end up making it into the public releases. So, for the time being, our beloved keychain continues to persist data beyond app deletion.
Original post below:
On February 7th, 2017, Apple released iOS 10.3 Beta2 to the public, and with that came some changes to the keychain.
The keychain was introduced to iOS devices with the release of iOS 7. The intention of the keychain is to allow a user to securely store login credentials to any number of services so as to not have to type them in every time. Safari uses the iOS keychain and prompts users to save their credentials whenever they login to any websites. However, the keychain is also available to developers. This means that it is possible to store passwords, certificates, and keys without any user interaction.
One of the (potentially unintended) side-effects of the keychain is that anything stored inside of it would persist even after uninstalling the app. This means that anything an app stores in the keychain would potentially live beyond the app itself, and the next time the app is installed and launched, it could read from the keychain and continue as if nothing ever happened.
This property of the keychain is quite useful and heavily relied upon by developers, however, it seems as though this might change with iOS 10.3. As outlined in this post on the Apple developer forums, keychain items are now automatically deleted when the app is deleted. For the purpose of keychain access groups, the keychain items are deleted when the last app in that access group is deleted.
This can be problematic for many apps which rely on the persistence of the keychain in order for their features to work. This was certainly true for me, so I decided to go looking for a workaround.
That is when I stumbled upon the constant kSecAttrAccessGroupToken, of which there does not seem to be much information about on the Internet. Here is the documentation found with this constant:
@enum kSecAttrAccessGroup Value Constants
@constant kSecAttrAccessGroupToken Represents well-known access group
which contains items provided by external token (typically smart card).
This may be used as a value for kSecAttrAccessGroup attribute. Every
application has access to this access group so it is not needed to
explicitly list it in keychain-access-groups entitlement, but application
must explicitly state this access group in keychain queries in order to
be able to access items from external tokens.
extern const CFStringRef kSecAttrAccessGroupToken
So, it would seem as though there is an access group, introduced with iOS 10, which all apps on the phone have read/write access to. If this is the case, then anything stored within that access group should persist forever, since any app currently installed may want to read from it in the future.
After testing my hypothesis, this indeed seems to be the case. Saving keychain items with the kSecAttrAccessGroupToken access group persists beyond app deletion. I wrote some sample code demonstrating this here.
So, in order to preserve existing keychain functionality and have entries persist beyond app deletion, a simple work around could be to use this access group. However, there is a caveat:
Since any app on the system can freely read and write to this access group, it is important to consider any security side effects this might have for your app. If you are storing sensitive information in the keychain, it could be worth encrypting keychain entries yourself before saving it off to the keychain.