2010-05-12 7 views
2

J'ai essayé d'utiliser des références de keychain persistantes dans une application iPhone. J'ai trouvé que si je créais deux éléments de trousseau différents, j'obtiendrais une référence persistante différente à chaque fois (ils ressemblent à 'genp ....... 1', 'genp ....... 2', ...) . Cependant, les tentatives de recherche des éléments par référence persistante ont toujours renvoyé le contenu du premier élément. Pourquoi cela devrait-il être? J'ai confirmé que mon code d'économie de trousseaux créait définitivement de nouveaux éléments dans chaque cas (plutôt que de mettre à jour des éléments existants), et qu'il n'y avait aucune erreur. Et comme je le dis, Keychain Services donne une référence persistante différente pour chaque élément. J'ai réussi à résoudre mon problème immédiat en recherchant des éléments de keychain par attribut plutôt que des références persistantes, mais il serait plus facile d'utiliser des références persistantes, donc j'apprécierais de résoudre ce problème.Pourquoi Keychain Services renvoie-t-il le mauvais contenu de trousseau?

Voici mon code:

- (NSString *)keychainItemWithName: (NSString *)name { 
    NSString *path = [GLApplicationSupportFolder() 
         stringByAppendingPathComponent: name]; 
    NSData *persistentRef = [NSData dataWithContentsOfFile: path]; 
    if (!persistentRef) { 
     NSLog(@"no persistent reference for name: %@", name); 
     return nil; 
    } 
    NSArray *refs = [NSArray arrayWithObject: persistentRef]; 
    //get the data 
    CFMutableDictionaryRef params = CFDictionaryCreateMutable(NULL, 
                   0, 
                   &kCFTypeDictionaryKeyCallBacks, 
                   &kCFTypeDictionaryValueCallBacks); 
    CFDictionaryAddValue(params, kSecMatchItemList, refs); 
    CFDictionaryAddValue(params, kSecClass, kSecClassGenericPassword); 
    CFDictionaryAddValue(params, kSecReturnData, kCFBooleanTrue); 
    CFDataRef item = NULL; 
    OSStatus result = SecItemCopyMatching(params, (CFTypeRef *)&item); 
    CFRelease(params); 
    if (result != errSecSuccess) { 
     NSLog(@"error %d retrieving keychain reference for name: %@", result, name); 
     return nil; 
    } 
    NSString *token = [[NSString alloc] initWithData: (NSData *)item 
              encoding: NSUTF8StringEncoding]; 
    CFRelease(item); 
    return [token autorelease]; 
} 

- (void)setKeychainItem: (NSString *)newToken forName: (NSString *)name { 
    NSData *tokenData = [newToken dataUsingEncoding: NSUTF8StringEncoding]; 
    //firstly, find out whether the item already exists 
    NSDictionary *searchAttributes = [NSDictionary dictionaryWithObjectsAndKeys: 
             name, kSecAttrAccount, 
             kCFBooleanTrue, kSecReturnAttributes, 
             nil]; 
    NSDictionary *foundAttrs = nil; 
    OSStatus searchResult = SecItemCopyMatching((CFDictionaryRef)searchAttributes, 
               (CFTypeRef *)&foundAttrs); 
    if (noErr == searchResult) { 
     NSMutableDictionary *toStore = [foundAttrs mutableCopy]; 
     [toStore setObject: tokenData forKey: (id)kSecValueData]; 
     OSStatus result = SecItemUpdate((CFDictionaryRef)foundAttrs, 
             (CFDictionaryRef)toStore); 
     if (result != errSecSuccess) { 
      NSLog(@"error %d updating keychain", result); 
     } 
     [toStore release]; 
     return; 
    } 
    //need to create the item. 
    CFMutableDictionaryRef params = CFDictionaryCreateMutable(NULL, 
                   0, 
                   &kCFTypeDictionaryKeyCallBacks, 
                   &kCFTypeDictionaryValueCallBacks); 
    CFDictionaryAddValue(params, kSecClass, kSecClassGenericPassword); 
    CFDictionaryAddValue(params, kSecAttrAccount, name); 
    CFDictionaryAddValue(params, kSecReturnPersistentRef, kCFBooleanTrue); 
    CFDictionaryAddValue(params, kSecValueData, tokenData); 
    NSData *persistentRef = nil; 
    OSStatus result = SecItemAdd(params, (CFTypeRef *)&persistentRef); 
    CFRelease(params); 
    if (result != errSecSuccess) { 
     NSLog(@"error %d from keychain services", result); 
     return; 
    } 
    NSString *path = [GLApplicationSupportFolder() 
         stringByAppendingPathComponent: name]; 
    [persistentRef writeToFile: path atomically: NO]; 
    [persistentRef release]; 
} 

Répondre

1

Transforme que l'utilisation de l'kSecMatchItemList ne semble pas fonctionner du tout.

J'ai fait le mien comme ceci:

NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys: 
        (id)kSecClassGenericPassword, kSecClass, 
        persistentRef, (id)kSecValuePersistentRef, 
        (id)kCFBooleanTrue, kSecReturnAttributes, 
        (id)kCFBooleanTrue, kSecReturnData, 
        nil]; 
NSDictionary *result = nil; 
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, 
            (CFTypeRef*)&result); 

qui retourne les attributs et les données pour la référence persistante. La documentation dans l'en-tête sur la conversion d'une "référence persistante" en une "référence standard" n'a aucun sens. J'espère que cela t'aides.