2013-06-27 3 views
1

По какой-то причине я получил пустой словарь при вызове SecItemCopyMatching на OSX 10.8.4. Соответствующий элемент находится в цепочке ключей и содержит имя пользователя и пароль. SecItemCopyMatching находит его (errSecSuccess), но словарь результатов всего содержит 0 записей. Я бы ожидал, что у него будут хотя бы данные о имени пользователя и пароле, поэтому что случилось с моим запросом?SecItemCopyMatching возвращает пустой словарь

OSStatus status; 
NSMutableDictionary *query = [NSMutableDictionary dictionary]; 
[query setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; 
[query setObject:(id)kSecReturnAttributes forKey:(id)kCFBooleanTrue]; 
[query setObject:@"MyService" forKey:(id)kSecAttrService]; 

CFDictionaryRef dictRef = NULL; 
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&dictRef); 
if (status != errSecSuccess) { 
    CFStringRef errorRef = SecCopyErrorMessageString(status, NULL); 
    NSLog(@"%s: %@", __FUNCTION__, (__bridge NSString *)errorRef); 
    CFRelease(errorRef); 
    return nil; 
} 

// --> dictRef empty 

if (dictRef != NULL) CFRelease(dictRef); 

enter image description here

+0

Я не могу сразу увидеть, почему вы получаете пустой словарь назад, но неудивительно, что пароль не возвращается. Документация заголовка для kSecReturnAttributes говорит: _Specify ключ словаря, значение которого имеет тип CFBooleanRef. Значение kCFBooleanTrue указывает, что должны быть возвращены (нешифрованные) атрибуты элемента (в CFDictionaryRef). – bdash

+0

Вы правы, он не просил разрешить доступ к цепочке ключей. И есть глупая ошибка в запросе: [query setObject: (id) kCFBooleanTrue forKey: (id) kSecReturnAttributes]; – Gamadril

ответ

1

Существует ошибка в запросе. Я перепутал ключ и объект.

[query setObject:(id)kSecReturnAttributes forKey:(id)kCFBooleanTrue]; 

должен быть

[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes]; 

однако, как bdash указал, он будет возвращать только незашифрованные атрибуты, как имя пользователя. Чтобы получить пароль, есть еще один запрос необходимо с прохождением

[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; 

Так вот, что у меня сейчас:

OSStatus status; 
NSMutableDictionary *query = [NSMutableDictionary dictionary]; 
[query setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; 
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes]; 
[query setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; 
[query setObject:@"MyService" forKey:(id)kSecAttrService]; 

// get username 
CFDictionaryRef dictRef = NULL; 
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&dictRef); 
if (status != errSecSuccess) { 
    CFStringRef errorRef = SecCopyErrorMessageString(status, NULL); 
    NSLog(@"%s: %@", __FUNCTION__, (__bridge NSString *)errorRef); 
    CFRelease(errorRef); 
    return nil; 
} 

NSString *username = (__bridge NSString *)CFDictionaryGetValue(dictRef, kSecAttrAccount); 
CFRelease(dictRef); 

// get password 
[query removeObjectForKey:(id)kSecReturnAttributes]; 
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; 
CFDataRef dataRef = NULL; 
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&dataRef); 
if (status != errSecSuccess) { 
    CFStringRef errorRef = SecCopyErrorMessageString(status, NULL); 
    NSLog(@"%s: %@", __FUNCTION__, (__bridge NSString *)errorRef); 
    CFRelease(errorRef); 
    return nil; 
} 

NSString *password = [[NSString alloc] initWithData:(__bridge NSData *)(dataRef) encoding:NSUTF8StringEncoding]; 
CFRelease(dataRef);