Perché i servizi di portachiavi restituiscono il contenuto del portachiavi sbagliato?

StackOverflow https://stackoverflow.com/questions/2817980

  •  26-09-2019
  •  | 
  •  

Domanda

Ho cercato di utilizzare i riferimenti di portachiavi persistenti in un'applicazione per iPhone. Ho scoperto che se avessi creato due diversi elementi del portachiavi, avrei un altro riferimento persistente ogni volta (sembrano "Genp ....... 1", "Genp ....... 2", ...) . Tuttavia, i tentativi di cercare gli elementi per persistente riferimento hanno sempre restituito il contenuto del primo elemento. Perché dovrebbe essere? Ho confermato che il mio codice di risparmio di portachiavi stava sicuramente creando nuovi elementi in ogni caso (piuttosto che aggiornare gli elementi esistenti) e non stava ottenendo errori. E come ho detto, i servizi di portachiavi stanno dando un riferimento persistente diverso per ogni articolo.

Sono riuscito a risolvere il mio problema immediato cercando elementi chiave per attributo piuttosto che riferimenti persistenti, ma sarebbe più facile usare riferimenti persistenti, quindi apprezzerei risolvere questo problema.

Ecco il mio codice:

- (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];
}
È stato utile?

Soluzione

Si scopre che l'uso della ksecmatchitemlist non sembra funzionare affatto.

Ho fatto il mio in questo modo:

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);

che hanno restituito gli attributi e i dati per il riferimento persistente. La documentazione nell'intestazione sulla conversione di un "riferimento persistente" in un "riferimento standard" non ha alcun senso. Spero che sia di aiuto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top