I've been digging around Apple forums and SO for this issue to no avail. Using Apple's KeychainItemWrapper (ARCified), trying to set the kSecAttrAccessible
attribute to anything except the default (kSecAttrAccessibleWhenUnlocked
) results in an assertion failure from SecItemUpdate returning an error.
KeychainItemWrapper *wrapper = [[KeyChainItemWrapper alloc] initWithIdentifier:kMyIdentifier accessGroup:nil];
[wrapper setObject:kMyServiceName forKey:(__bridge NSString*)kSecAttrService];
[wrapper setObject:kMyAccountToken forKey:(__bridge NSString*)kSecAttrAccount];
[wrapper setObject:(__bridge NSString*)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly forKey:(__bridge NSString*)kSecAttrAccessible];
The rest of our keychain updates seem to be going through fine, but the last line results in:
*** Assertion failure in -[KeychainItemWrapper writeToKeychain], /Users/john.hammerlund/.../KeychainItemWrapper.m:299
The assertion failure is due to SecItemUpdate() returning a status of -50, which appears to be a generic "invalid parameters" error.
Immediately setting the kSecAttrAccessible
key has no impact, but setting it to the default kSecAttrAccessibleWhenUnlocked
mitigates the issue (but eliminates the point). This other question is the only additional info I've found relating to iOS 8 causing the KeychainItemWrapper to crash. Building to a device with iOS 7 or a simulator on iOS 7/8 eliminates the issue; it's only flaring up on a real device using iOS 8.
Update
Here's a broad overview of the query dictionary:
{
accc = "<SecAccessControlRef: 0x1687cc70>";
acct = ...;
agrp = ...;
cdat = "2014-10-13 22:22:47 +0000";
desc = "";
gena = ...;
labl = "";
mdat = "2014-10-13 22:34:16 +0000";
pdmn = cku; <-- kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
svce = ...;
sync = 0;
tomb = 0;
"v_Data" = <>;
}
and the attributesToUpdate parameter:
{
accc = "<SecAccessControlRef: 0x1687cc70>";
acct = ...;
agrp = ...;
cdat = "2014-10-13 22:22:47 +0000";
desc = "";
gena = ...;
labl = "";
mdat = "2014-10-13 22:34:16 +0000";
pdmn = ak; <-- kSecAttrAccessibleWhenUnlocked
svce = ...;
sync = 0;
tomb = 0;
"v_Data" = <>;
}
I've confirmed that changing other fields (i.e. kSecAttrService, kSecAttrAccount) have the same effect on the corresponding fields in the dictionaries, but with an expected status of 0.