Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS KeychainItemWrapper not updating

Tags:

ios

keychain

ios5

I just found an interesting problem with my app. In the app I am saving the user's user name and password to the keychain.

keychainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyLoginPassword" accessGroup:nil];

[keychainWrapper setObject:usernameField.text forKey:(id)kSecAttrAccount];
[keychainWrapper setObject:passwordField.text forKey:(id)kSecValueData];

When this code is run in Debug it seems to work just fine. It updates each time and I can later retrieve the items from the keychain. When it is run in Distribution however the keychain never gets updated. I have verified that yes these lines of code are hit in both builds. I am using Xcode 4.2 with the iOS5 SDK and running the app on an iPad 2 with iOS5 installed.

like image 499
iHorse Avatar asked Nov 08 '11 17:11

iHorse


2 Answers

When you include

keychainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyLoginPassword" accessGroup:nil];

[keychainWrapper setObject:usernameField.text forKey:(id)kSecAttrAccount];
[keychainWrapper setObject:passwordField.text forKey:(id)kSecValueData];

you also had to include

[keychainWrapper setObject:@"Myappstring" forKey: (id)kSecAttrService];

Or I get a "SIGABRT" error. (Myappstring) is a string defining your application.

Maybe I'm missing something, this should be done at least once.

like image 69
Andres Bucci Avatar answered Nov 01 '22 00:11

Andres Bucci


I also had this problem, and it took me forever to figure out

There is a version of "KeychainWrapper" floating around that has it's SecItemUpdate within an NSAssert (among other things).

Whoever did this is a moron!, when building for release/distribution every NSAssert is nullified, meaning that code doesn't even get run.

For example:

NSAssert(SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck), @"Couldn't update the Keychain Item." );

Needs to become

OSStatus status = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck);
NSAssert(status == noErr, @"Couldn't update the Keychain Item." );

Notice how the actual SecItemUpdate is moved outside the NSAssert, and instead the result is checked

Important note: Attempting to update a value for kSecValueData, without also specifying a value for kSecAttrAccount, will cause the assertion to fail as well. So, if your intent is to store a single string of sensitive data (such as a list of credit card numbers), be sure to store some "account name" text in the kSecAttrAccount attribute, like so:

static NSString* kCardListXML = @"cardListXML";
static NSString* cardListAccountName = @"cardListAccount";

-(void)setCardListXML:(NSString*)xml {
  KeychainItemWrapper* wrapper =
    [[KeychainItemWrapper alloc] initWithIdentifier:kCardListXML accessGroup:nil];
  [wrapper setObject:cardListAccountName forKey:(id)CFBridgingRelease(kSecAttrAccount)];
  [wrapper setObject:xml forKey:(id)CFBridgingRelease(kSecValueData)];
}    

-(NSString*)getCardListXML {
  KeychainItemWrapper* wrapper =
    [[KeychainItemWrapper alloc] initWithIdentifier:kCardListXML accessGroup:nil];
  [wrapper setObject:cardListAccountName forKey:(id)CFBridgingRelease(kSecAttrAccount)];
  return [wrapper objectForKey:CFBridgingRelease(kSecValueData)];
}
like image 44
SomeGuy Avatar answered Nov 01 '22 00:11

SomeGuy