2012-07-26 7 views
19

Ich versuche, einen privaten Schlüssel in den iOS-Schlüsselbund hinzuzufügen. Das Zertifikat (öffentlicher Schlüssel) funktioniert gut, aber der private Schlüssel verweigert ... Ich bin total verwirrt, warum der folgende Code nicht funktioniert.Hinzufügen eines privaten Schlüssels zu iOS Keychain

Zuerst überprüfe ich, ob der aktuelle Schlüssel (= Schlüssel im Falle dass der Schlüsselbund ein Schlüssel/Wertspeicher ist) 'frei' im Schlüsselbund ist. Dann werde ich den privaten Schlüssel hinzufügen.

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

Die Debug-Ausgabe ist die folgende:

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) 

Der erste Fehlercode -25300errSecItemNotFound darstellt. Daher ist für diesen Schlüssel kein Wert gespeichert. Dann, wenn ich versuche, den privaten Schlüssel in den Schlüsselbund hinzuzufügen, bekomme ich -25299, was errSecDuplicateItem bedeutet. Ich verstehe das nicht. Warum passiert dies?

Hat jemand eine Ahnung oder einen Hinweis darauf?

Fehlercodes von 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. */ 

Vielen Dank im Voraus!

Update # 1: Ich habe herausgefunden, dass es nur zum ersten Mal funktioniert. Auch wenn Daten und Schlüssel anders sind, kann ich nach dem ersten Mal, das im Schlüsselbund gespeichert ist, keine weiteren Schlüssel speichern.

+0

ich genau das gleiche Problem konfrontiert bin. Der erste Schlüssel wurde mit SecItemAdd ohne Probleme hinzugefügt, dann schlägt jeder nachfolgende Aufruf von SecItemAdd mit errSecDuplicateItem fehl, obwohl SecItemCopyMatching errSecItemNotFound zurückgibt. Haben Sie schon eine Lösung gefunden? – 100grams

Antwort

8

Der folgende Code für mich gearbeitet:

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

Es ist eine schlechte Praxis, ein Schlüsselbund-Element nur zu löschen, um ein Element mit der gleichen Information zurück hinzuzufügen.Ich erinnere mich nicht an den bestimmten Grund, aber ich glaube, dass es Konflikte verursachen kann, wenn man versucht, dies zu tun. – Joey

+0

Ich habe mit einem Angestellten von Apple gesprochen, der auf der letzten WWDC an dem Schlüsselbund arbeitet und er sagte mir, dass sie in Wirklichkeit keine andere Möglichkeit bieten, dies zu erreichen, aber sie haben eine private API für das, was sie _soon_ veröffentlichen werden. .. – Chris

+1

Ich weiß nicht, was du meinst Chris. Ich hatte das gleiche Problem und konnte meinen Code korrigieren, um den vorhandenen Artikel korrekt zu finden. Mein Problem war, dass ich es so definierte, dass es über iCloud synchronisiert werden konnte, wenn ich es hinzufügte, aber das bei der Suche nicht in die Abfrage einfügte, sodass es keine Übereinstimmung finden konnte. Ich musste es nicht löschen und neu hinzufügen. – Joey

1

Entschuldigung, aber ich werde nie in der Lage sein, Ihren Code zu debuggen. Apple bietet einen Beispielcode (KeychainItemWrapper), mit dem Sie eine Zeichenfolge speichern können (ich erinnere mich). Es ist eine große Hilfe im Umgang mit der Schlüsselkette. Es gibt einen Kern im Web, der eine modifizierte Version dieser Klasse ist, aber ein Wörterbuch speichert und wiederherstellt (archiviert als Datenobjekt, was der Apple-Code für die Zeichenkette tut). Auf diese Weise können Sie mehrere Objekte in einer Oberfläche am Schlüsselbund speichern. Der Kern ist hier Keychain for NSDictionary/data

+1

Danke, aber es muss als 'kSecClassKey' (und das entsprechende Zertifikat als' kSecClassCertificate') gespeichert werden. Ich weiß, Apple bietet diesen Beispielcode zum Speichern von Benutzeranmeldeinformationen (aber nur Zeichenfolgen) in den Schlüsselbund. Wenn man bedenkt, dass man ein Zertifikat verifizieren oder den zusätzlichen Schutz des 'kSecClassKey' verwenden möchte, kann es nicht mit dem Ansatz von Apples Beispielcode oder Ihrem Link gespeichert werden. Ich denke jedoch, dass ich eine Lösung gefunden habe, aber das muss ich verifizieren, bevor ich es hier poste. – Chris

+1

Meiner Erfahrung nach kann der Schlüsselbund-Wrapper nicht mehrere Objekte in derselben Schlüsselbundgruppe speichern. Dies verursachte einige große Frustration, aber eine Lösung kann hier gefunden werden: http://stackoverflow.com/questions/11055731/ios-save-multiple-passwords-in-keychain?lq=1 – rob

+0

Das ist lustig - seit ich es mache mit einem Wörterbuch in meiner App und Speichern von E-Mail, Passwort und einem anderen Kontext mit dem Benutzer. Aber ich habe Apples Code ein bisschen geändert, aber nicht viel - Sie können es in dem Link in meiner Antwort sehen. Dies ist Arbeitscode, der jetzt in Tausenden von Telefonen ist (nicht Millionen :-() –