Error saving in the keychain with iphone sdk



7
down vote favorite
9

I use the Apple wraper for the keychain, and try to save a item on it (running in simulator, ios 4.1).

I have not experience with the keychain before.

I get this error:

Couldn't add the Keychain Item. Error - 25299

In KeychainItemWrapper.m line 304:

// No previous item found; add the new one. result = SecItemAdd((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL); NSAssert( result == noErr, @"Couldn't add the Keychain Item." );

This is how I do the save:

- (void) saveKey:(NSString *)key value:(NSString *)value { KeychainItemWrapper *keyItem = [[KeychainItemWrapper alloc] initWithIdentifier:key accessGroup:nil]; [keyItem setObject:value forKey:(id)kSecValueData]; [keyItem release]; }

And this are the values that the api try to save:

<CFBasicHash 0x7231f60 [0x320d380]>{type = mutable dict, count = 5, entries => 2 : <CFString 0x2e6eb98 [0x320d380]>{contents = "labl"} = <CFString 0x2fb018 [0x320d380]>{contents = ""} 3 : <CFString 0x2e6efb8 [0x320d380]>{contents = "v_Data"} = <CFString 0x727de60 [0x320d380]>{contents = "dit8"} 4 : <CFString 0x2e6ebc8 [0x320d380]>{contents = "acct"} = <CFString 0x2fb018 [0x320d380]>{contents = ""} 5 : <CFString 0x2e6eb58 [0x320d380]>{contents = "desc"} = <CFString 0x2fb018 [0x320d380]>{contents = ""} 6 : <CFString 0x2e6ebe8 [0x320d380]>{contents = "gena"} = <CFString 0x2ffd08 [0x320d380]>{contents = "userCode"} }
share | improve this question
 
have you solved the problem?  –  Matthias Bauch   Apr 7 '11 at 20:28
 
I'm stuck with this, so I think a bounty is a good idea. Same errorCode but iOS4.3 But I guess this is a PEBKAC problem, and no problem with the sdk.  –  Matthias Bauch   Apr 7 '11 at 20:37
 
This problem occurred to me when I added [keychainItemData setObject:@"" forKey:(__bridge id)kSecAttrService]; in - (void)resetKeychainItem. Then when I was reading user379075's answer below, it rang a bell that if you 'reset' it, you also have to set it and v.v.  –  mrd3650   Apr 13 '12 at 15:52

5 Answers

active oldest votes
up vote 15 down vote accepted

I know this is from several months ago, but I just had the same problem and it was painful so I thought I'd share. I solved it by adding this line:

[self.keychainItemWrapper setObject:@"MY_APP_CREDENTIALS" forKey:(id)kSecAttrService]; //@"MY_APP_CREDENTIALS" can be any string.

I found this blog entry very helpful: "In database terms you could think of their being a unique index on the two attributes kSecAttrAccount, kSecAttrService requiring the combination of those two attributes to be unique for each entry in the keychain." (from http://useyourloaf.com/blog/2010/4/28/keychain-duplicate-item-when-adding-password.html).

Also, in Apple's example project using this code, they instantiate KeychainItemWrapper in the app delegate. I don't know if it's necessary, but I like to follow their examples as closely as possible:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ //there will be some standard code here. KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MY_APP_CREDENTIALS" accessGroup:nil]; self.keychainWrapper = wrapper; [self.keychainWrapper setObject:@"MYOBJECT" forKey:(id)kSecAttrService]; [wrapper release]; }

I think this is a bug in the wrapper code. The logic basically says "Does this entry exist already? No, it doesn't. OK, I'll add it. Oops, you can't add it because it's already there."

You may also need to set kSecAttrAccount; I've never tried it without also setting this value since it's intended to save the username that goes with the password:

[self.wrapper setObject:txtUserName.text forKey:(id)kSecAttrAccount]; 
share | improve this answer
 
Worked fine after adding the MY_APP_CREDENTIALS statement. Thanks a lot :)  –  ilight   Sep 3 '12 at 6:32
 
Awesome! Thanks! :-)  –  orange80   Dec 30 '12 at 1:27
up vote 6 down vote

According to the documentation, the error -25299 you are getting is "errSecDuplicateItem", meaning that the item you are trying to add already exists. Looking at the linked code for KeychainItemWrapper, I would guess that the SecItemCopyMatching call is failing with an error other than errSecItemNotFound (–25300).

share | improve this answer
   
up vote 5 down vote

You can easily store and get back values with keychain using SFHFKeychainUtils by Buzz Andersen.

  1. Download and copy in your project SFHFKeychainUtils.h and .m
  2. Add Security.framework to your Framework folder
  3. Make sure these files are added to your target
  4. Import SFHFKeychainUtils.h where you want to use it

This is a little example on how to use this library.

// To store data NSError *error = nil; [SFHFKeychainUtils storeUsername:username andPassword:password forServiceName:kStoredData updateExisting:YES error:&error]; // To retrieve data NSString *password = [SFHFKeychainUtils getPasswordForUsername:username andServiceName:kStoredData error:&error]; // To delete data from keychain [SFHFKeychainUtils deleteItemForUsername:username andServiceName:kStoredData error:&error];
share | improve this answer
 
What is kStoredData in this context? I'm getting a build error when trying to do this.  –  Philip Walton   Apr 21 '11 at 23:34
 
In this case kStoredData is a defined key... You can use any key... In this example, kStoreData is a key for a service name like @"com.company.app.serviceName". You can define a key like this in you .h file and then use it to store and retrieve your data  –  matteodv   Apr 22 '11 at 9:51
up vote 3 down vote

The keychain is a total pain. You should use Buzz Andersen's STUtils library instead as a wrapper. It will make your life substantially easier. I've never had a problem with it.

share | improve this answer
 
2  
This github project has now been deprecated; the author suggestsgithub.com/ldandersen/STUtils/blob/master/Security as a replacement.  –  Graham Miln   Oct 11 '12 at 10:25
up vote 0 down vote

I had this problem also and solved it thanks to the accepter answer and the additional link to useyourloaf.

The problem I had was interesting, I needed to save only one value and decided to store it in the fieldkSecValueData. That is because I saw other posts about using the keychain and started my own implementation before turning to KeychainItemWrapper. This caused the following issue: On the first device I was testing (iPad 1st gen) I was getting an error in writeToKeychain. I changed device (also ipad 1st gen) and it worked! Back to the first device it still didn't work.

So I that point I knew that I had previously done something wrong in the device's keychain and couldn't revert it easily. The error codes I was getting were: -25300 on the writeToKeychain's SecItemCopyMatching (item not found) and right after -25299 on the SecItemAdd. (item duplicate)

With this question, this all made sense: the device has a key that matches any new key but the KeychainItemWrapper cannot delete it but the key cannot be retrieved. As soon as I added the same value to the field kSecAttrAccount, it started working.

Long story short, for other users having this problem, your problem might look different but pay attention to the details. If you have -25300 (item not found) followed by -25299 (item duplicate); make sure that you are setting a field that defines the uniqueness of your keychain item. If it doesn't work on one device, try another if you can you might be able to isolate the problem to one device. Apple keychain Error codes:http://developer.apple.com/library/ios/#documentation/Security/Reference/keychainservices/Reference/reference.html#//apple_ref/doc/uid/TP30000898-CH5g-CJBEABHG (search for Result Codes)

你可能感兴趣的:(Error saving in the keychain with iphone sdk)