My code works 70% of the time, but sometimes it throws a errSecDuplicateItem
error on a SecItemUpdate
and I just don't understand why.
The code below accesses two class objects, self.storedActiveDirectoryKeychainItem
which is the unchanged dictionary representing the keychain item and self.activeDirectoryKeychainItem
which holds the modified values.
I'm making modifications to the username and/or password field and sometimes it works as expected and other times the SecItemUpdate
returns a result code of –25299 which is the errSecDuplicateItem
. The insert(SecItemAdd
) doesn't ever error.
- (void)persistStandardADKeychainItem {
NSMutableDictionary *keychainItemContents = [self.activeDirectoryKeychainItem mutableCopy];
// encode password
NSData *encodedPassword = [self.password dataUsingEncoding:NSUTF8StringEncoding];
keychainItemContents[(__bridge id)kSecValueData] = encodedPassword;
// encode the meta data
NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:keychainItemContents[(__bridge id)kSecAttrGeneric]];
keychainItemContents[(__bridge id)kSecAttrGeneric] = encodedData;
OSStatus resultCode;
if (self.storedActiveDirectoryKeychainItem[(__bridge id)kSecAttrCreationDate]) {
// Update Existing Item
NSMutableDictionary *query = [self.storedActiveDirectoryKeychainItem mutableCopy];
// add in keychain item type to search query
query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
// remove the Generic Data (meta data), we don't want to search on it.
[query removeObjectForKey:(__bridge id)kSecAttrGeneric];
resultCode = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)keychainItemContents);
if (resultCode != 0)
NSLog(@"Updated standard keychain credentials result code: %d", (int)resultCode);
} else {
// Insert New Item
keychainItemContents[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
keychainItemContents[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleWhenUnlockedThisDeviceOnly;
keychainItemContents[(__bridge id)kSecAttrCreator] = self.configurationManager.keychainItemCreatorName;
keychainItemContents[(__bridge id)kSecAttrService] = self.configurationManager.keychainItemServiceName;
resultCode = SecItemAdd((__bridge CFDictionaryRef)keychainItemContents, NULL);
if (resultCode != 0)
NSLog(@"Insert standard keychain credentials result code: %d", (int)resultCode);
}
}
Below is debug output of a fail where I did a dump of both the query
and keychainItemContents
dictionaries.
2014-12-03 11:46:55.776 TestKeychainServices[314:34883] query
{
accc = "<SecAccessControlRef: 0x165d01f0>";
acct = fubar;
agrp = "C35BXHSRSA.com.bobco.Security";
cdat = "2014-12-02 17:05:44 +0000";
class = genp;
crtr = MyCompany;
icmt = "12/3/14, 11:46 AM";
mdat = "2014-12-03 16:46:52 +0000";
pdmn = aku;
svce = "Active Directory";
sync = 0;
tomb = 0;
"v_Data" = <54155341 34452965 6374>;
}
2014-12-03 11:46:55.778 TestKeychainServices[314:34883] new contents
{
accc = "<SecAccessControlRef: 0x165d01f0>";
acct = user123;
agrp = "C35BXHSRSA.com.bobco.Security";
cdat = "2014-12-02 17:05:44 +0000";
crtr = MyCompany;
gena = <62706c69 73743030 d4010203 04050827 28542474 6f705824 6f626a65 63747358 24766572 0a012001 25000000 00000002 01000000 00000000 29000000 00000000 00000000 00000001 37>;
icmt = "12/3/14, 11:46 AM";
mdat = "2014-12-03 16:46:52 +0000";
pdmn = aku;
svce = "Active Directory";
sync = 0;
tomb = 0;
"v_Data" = <54155341 34452965 6374>;
}
2014-12-03 11:46:55.801 TestKeychainServices[314:34883] Updated standard keychain credentials result code: -25299