Va bene, ho trovato la soluzione in questo post del blog Keychain duplicate item when adding password
Per riassumere, il problema è che il campione app GenericKeychain utilizza il valore memorizzato nella chiave kSecAttrGeneric come l'identificatore per la voce di portachiavi quando in realtà che non è ciò che l'API usa per determinare un oggetto portachiavi unico. Le chiavi che è necessario impostare con valori univoci sono la chiave kSecAttrAccount e/o la chiave kSecAttrService.
È possibile riscrivere l'initilizer di KeychainItemWrapper quindi non c'è bisogno di cambiare qualsiasi altro codice, modificando queste righe:
Cambio:
[genericPasswordQuery setObject:identifier forKey:(id)kSecAttrGeneric];
a:
[genericPasswordQuery setObject:identifier forKey:(id)kSecAttrAccount];
e cambio:
[keychainItemData setObject:identifier forKey:(id)kSecAttrGeneric];
a:
[keychainItemData setObject:identifier forKey:(id)kSecAttrAccount];
Oppure, si potrebbe fare quello che ho fatto e scrivere un nuovo initilizer che prende entrambe le chiavi che identificano:
Edit: Per le persone che utilizzano ARC (si dovrebbe essere al giorno d'oggi) controllare nycynik's answer per tutte le annotazioni di collegamento corrette
- (id)initWithAccount:(NSString *)account service:(NSString *)service accessGroup:(NSString *) accessGroup;
{
if (self = [super init])
{
NSAssert(account != nil || service != nil, @"Both account and service are nil. Must specifiy at least one.");
// Begin Keychain search setup. The genericPasswordQuery the attributes kSecAttrAccount and
// kSecAttrService are used as unique identifiers differentiating keychain items from one another
genericPasswordQuery = [[NSMutableDictionary alloc] init];
[genericPasswordQuery setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
[genericPasswordQuery setObject:account forKey:(id)kSecAttrAccount];
[genericPasswordQuery setObject:service forKey:(id)kSecAttrService];
// The keychain access group attribute determines if this item can be shared
// amongst multiple apps whose code signing entitlements contain the same keychain access group.
if (accessGroup != nil)
{
#if TARGET_IPHONE_SIMULATOR
// Ignore the access group if running on the iPhone simulator.
//
// Apps that are built for the simulator aren't signed, so there's no keychain access group
// for the simulator to check. This means that all apps can see all keychain items when run
// on the simulator.
//
// If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
// simulator will return -25243 (errSecNoAccessForItem).
#else
[genericPasswordQuery setObject:accessGroup forKey:(id)kSecAttrAccessGroup];
#endif
}
// Use the proper search constants, return only the attributes of the first match.
[genericPasswordQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
[genericPasswordQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
NSDictionary *tempQuery = [NSDictionary dictionaryWithDictionary:genericPasswordQuery];
NSMutableDictionary *outDictionary = nil;
if (! SecItemCopyMatching((CFDictionaryRef)tempQuery, (CFTypeRef *)&outDictionary) == noErr)
{
// Stick these default values into keychain item if nothing found.
[self resetKeychainItem];
//Adding the account and service identifiers to the keychain
[keychainItemData setObject:account forKey:(id)kSecAttrAccount];
[keychainItemData setObject:service forKey:(id)kSecAttrService];
if (accessGroup != nil)
{
#if TARGET_IPHONE_SIMULATOR
// Ignore the access group if running on the iPhone simulator.
//
// Apps that are built for the simulator aren't signed, so there's no keychain access group
// for the simulator to check. This means that all apps can see all keychain items when run
// on the simulator.
//
// If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
// simulator will return -25243 (errSecNoAccessForItem).
#else
[keychainItemData setObject:accessGroup forKey:(id)kSecAttrAccessGroup];
#endif
}
}
else
{
// load the saved data from Keychain.
self.keychainItemData = [self secItemFormatToDictionary:outDictionary];
}
[outDictionary release];
}
return self;
}
Spero che questo aiuti qualcun altro!
fonte
2011-02-15 19:15:54
domanda relativa: http: // stackoverflow.it/questions/11614047/what-makes-a-keychain-item-unique-in-ios –
FWIW, ho archiviato un radar con Apple su questo problema con il loro codice di esempio. Vedi http://www.openradar.me/13472204 se lo vuoi ingannare. –