2012-07-26 33 views
19

Próbuję dodać klucz prywatny do pęku kluczy systemu iOS. Certyfikat (klucz publiczny) działa dobrze, ale klucz prywatny odmawia ... Jestem całkowicie zdezorientowany, dlaczego poniższy kod nie działa.Dodawanie klucza prywatnego do pęku kluczy systemu iOS

Najpierw sprawdzam, czy bieżący klucz (= klucz, w przypadku którego Keychain jest magazynem kluczy/wartości) jest "wolny" w pęku kluczy. Następnie dodam klucz prywatny.

CFStringRef labelstring = CFStringCreateWithCString(NULL, [key cStringUsingEncoding:NSUTF8StringEncoding], kCFStringEncodingUTF8); 

NSArray* keys = [NSArray arrayWithObjects:(__bridge id)kSecClass,kSecAttrLabel,kSecReturnData,kSecAttrAccessible,nil]; 
NSArray* values = [NSArray arrayWithObjects:(__bridge id)kSecClassKey,labelstring,kCFBooleanTrue,kSecAttrAccessibleWhenUnlocked,nil]; 
NSMutableDictionary* searchdict = [NSMutableDictionary dictionaryWithObjects:values forKeys:keys]; 

CFRelease(labelstring); 

NSMutableDictionary *query = searchdict; 


CFTypeRef item = NULL; 
OSStatus error = SecItemCopyMatching((__bridge_retained CFDictionaryRef) query, &item); 

if (error) 
{ 
    NSLog(@"Error: %ld (statuscode)", error); 
} 

if(error != errSecItemNotFound) 
{ 
    SecItemDelete((__bridge_retained CFDictionaryRef) query); 
} 

[query setObject:(id)data forKey:(__bridge id)kSecValueData]; 

OSStatus status = SecItemAdd((__bridge_retained CFDictionaryRef) query, &item); 

if(status) 
{ 
    NSLog(@"Keychain error occured: %ld (statuscode)", status); 
    return NO; 
} 

Wyjście debugowania jest następująca:

2012-07-26 15:33:03.772 App[15529:1b03] Error: -25300 (statuscode) 
2012-07-26 15:33:11.195 App[15529:1b03] Keychain error occured: -25299 (statuscode) 

Pierwszy kod błędu -25300 reprezentuje errSecItemNotFound. Tak więc nie ma wartości zapisanej dla tego klucza. Następnie, gdy próbuję dodać klucz prywatny do pęku kluczy, otrzymuję -25299, co oznacza errSecDuplicateItem. Nie rozumiem tego. Dlaczego to się dzieje?

Czy ktoś ma wskazówkę lub podpowiedź na ten temat?

kody błędów Apple:

errSecSuccess    = 0,  /* No error. */ 
errSecUnimplemented   = -4,  /* Function or operation not implemented. */ 
errSecParam     = -50,  /* One or more parameters passed to a function where not valid. */ 
errSecAllocate    = -108, /* Failed to allocate memory. */ 
errSecNotAvailable   = -25291, /* No keychain is available. You may need to restart your computer. */ 
errSecDuplicateItem   = -25299, /* The specified item already exists in the keychain. */ 
errSecItemNotFound   = -25300, /* The specified item could not be found in the keychain. */ 
errSecInteractionNotAllowed = -25308, /* User interaction is not allowed. */ 
errSecDecode     = -26275, /* Unable to decode the provided data. */ 
errSecAuthFailed    = -25293, /* The user name or passphrase you entered is not correct. */ 

Z góry dzięki!

Aktualizacja # 1: Stwierdziłem, że działa tylko po raz pierwszy. Nawet jeśli dane i klucz są różne, po pierwszym zapisaniu w pęku kluczy nie mogę przechowywać kolejnych kluczy.

+0

Jestem stoi dokładnie ten sam problem. Pierwszy klucz dodany za pomocą SecItemAdd bez problemu, a następnie każde kolejne wywołanie SecItemAdd kończy się niepowodzeniem z errSecDuplicateItem, mimo że SecItemCopyMatching zwraca errSecItemNotFound. Czy znalazłeś już rozwiązanie? – 100grams

Odpowiedz

8

Poniższy kod pracował dla mnie:

NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; 
[query setObject:(id)kSecClassKey forKey:(id)kSecClass]; 
[query setObject:(id)kSecAttrAccessibleWhenUnlocked forKey:(id)kSecAttrAccessible]; 
[query setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnData]; 

//adding access key 
[query setObject:(id)key forKey:(id)kSecAttrApplicationTag]; 


//removing item if it exists 
SecItemDelete((CFDictionaryRef)query); 

//setting data (private key) 
[query setObject:(id)data forKey:(id)kSecValueData]; 

CFTypeRef persistKey; OSStatus status = SecItemAdd((CFDictionaryRef)query, &persistKey); 

if(status) { 
    NSLog(@"Keychain error occured: %ld (statuscode)", status); 
    return NO; 
} 
+0

Złą praktyką jest usuwanie elementu z pęku kluczy tylko w celu dodania elementu z tymi samymi informacjami z powrotem.Nie pamiętam konkretnego powodu, ale sądzić, że może to powodować konflikty podczas próby wykonania tego. – Joey

+0

Rozmawiałem z pracownikiem Apple, który pracuje nad Keychainem w ubiegłym roku WWDC i powiedział mi, że w rzeczywistości nie oferują innego sposobu, aby osiągnąć to już teraz, ale mają prywatny interfejs API do tego, który wypuszczą _soon_. .. – Chris

+1

Nie wiem, co masz na myśli Chris. Miałem ten sam problem i udało mi się naprawić mój kod, aby poprawnie znaleźć istniejący przedmiot. Mój problem polegał na tym, że definiowałem go jako możliwy do zsynchronizowania z usługą iCloud podczas dodawania go, ale nie uwzględnił tego w zapytaniu podczas wyszukiwania, więc nie mógł znaleźć dopasowania. Nie musiałem usuwać i dodawać go ponownie. – Joey

1

Przepraszam, ale nigdy nie będę w stanie debugować kodu. Apple udostępnia przykładowy kod (KeychainItemWrapper), który pozwala zapisać jeden ciąg znaków (przypominam sobie). Jest to wielka pomoc w walce z kluczowym łańcuchem. W sieci jest istota zmodyfikowanej wersji tej klasy, ale zapisuje i odtwarza słownik (zarchiwizowany jako obiekt danych, który jest tym, co kod Apple robi z łańcuchem). Pozwala to zapisać wiele elementów w jednym interfejsie do pęku kluczy. Istotą jest tutaj Keychain for NSDictionary/data

+1

Dzięki, ale musi być przechowywany jako 'kSecClassKey' (i odpowiedni certyfikat jako' kSecClassCertificate'). Wiem, że Apple dostarcza ten przykładowy kod do przechowywania poświadczeń użytkownika (ale tylko łańcuchów) w pęku kluczy. Biorąc pod uwagę, że ktoś chce zweryfikować certyfikat lub użyć dodatkowej ochrony 'kSecClassKey' nie może zostać zapisany przy użyciu podejścia z przykładowego kodu Apple lub twojego linku. Jednak sądzę, że znalazłem rozwiązanie, ale muszę to zweryfikować, zanim opublikuję to tutaj. – Chris

+1

Z mojego doświadczenia wynika, że ​​opakowanie pęku kluczy nie pozwala na zapisanie wielu elementów w tej samej grupie pęków kluczy. Spowodowało to duże rozdrobnienie, ale rozwiązanie można znaleźć tutaj: http://stackoverflow.com/questions/11055731/ios-save-multiple-passwords-in-keychain?lq=1 – rob

+0

To zabawne - od kiedy to robię ze słownikiem w mojej aplikacji i zapisaniem adresu e-mail, hasła i innego kontekstu związanego z użytkownikiem. Ale trochę zmodyfikowałem kod Apple'a - widać to w linku w mojej odpowiedzi. To działa kod, który jest teraz w tysiącach telefonów (nie milionami :-() –

Powiązane problemy