2012-07-26 6 views
19

Sto tentando di aggiungere una chiave privata nel portachiavi iOS. Il certificato (chiave pubblica) funziona bene ma la chiave privata si rifiuta ... Sono totalmente confuso perché il seguente codice non funziona.Aggiunta di una chiave privata nel portachiavi iOS

Prima di tutto sto verificando se la chiave corrente (= il tasto nel caso in cui il portachiavi sia un archivio di chiavi/valori) sia "libero" nel portachiavi. Quindi aggiungerò la chiave privata.

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

uscita Il debug è la seguente:

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) 

Il primo codice di errore -25300 rappresenta errSecItemNotFound. Quindi non esiste alcun valore memorizzato per questa chiave. Quindi, quando provo ad aggiungere la chiave privata nel Portachiavi, ricevo -25299 che significa errSecDuplicateItem. Questo non lo capisco. Perché sta succedendo?

Qualcuno ha un indizio o un suggerimento su questo?

codici di errore di 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. */ 

Grazie in anticipo!

Aggiornamento n. 1: ho capito che funziona solo per la prima volta. Anche quando i dati e la chiave sono diversi, dopo la prima volta memorizzato nel portachiavi non posso memorizzare ulteriori chiavi.

+0

sto affrontando lo stesso problema esatto. Prima chiave aggiunta usando SecItemAdd senza problemi, quindi qualsiasi chiamata consecutiva a SecItemAdd fallisce con errSecDuplicateItem sebbene nonostante SecItemCopyMatching restituisca errSecItemNotFound. Hai già trovato una soluzione? – 100grams

risposta

8

Il seguente codice ha funzionato per me:

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

È una cattiva pratica eliminare un oggetto portachiavi solo per aggiungere un oggetto con le stesse informazioni indietro. Non ricordo il motivo specifico per cui, ma io credere che possa causare conflitti quando si tenta di farlo. – Joey

+0

Ho parlato con un dipendente della Apple che lavora al Keychain negli ultimi anni del WWDC e mi ha detto che in realtà non offrono un altro modo per raggiungere questo obiettivo, ma hanno un'API privata per quello che rilasceranno _soon_. .. – Chris

+1

Non so cosa intendi, Chris. Ho avuto lo stesso problema ed è stato in grado di correggere il mio codice per trovare correttamente l'elemento esistente. Il mio problema era che stavo definendo la sincronizzazione su iCloud durante l'aggiunta, ma non l'ho incluso nella query durante la ricerca, quindi non è stato possibile trovare una corrispondenza. Non ho dovuto eliminare e aggiungerlo di nuovo. – Joey

1

Scusa ma non riuscirò mai a eseguire il debug del codice. Apple fornisce un codice di esempio (KeychainItemWrapper) che consente di salvare una stringa (ricordo). È un grande aiuto per la catena di chiavi. C'è una nota sul web che è una versione modificata di quella classe, ma salva e ripristina un dizionario (archiviato come un oggetto dati, che è ciò che il codice Apple fa alla stringa). Ciò consente di salvare più elementi in un'unica interfaccia sul portachiavi. Il succo è qui Keychain for NSDictionary/data

+1

Grazie, ma deve essere memorizzato come 'kSecClassKey' (e il certificato corrispondente come' kSecClassCertificate'). So che Apple fornisce questo codice di esempio per l'archiviazione delle credenziali dell'utente (ma solo delle stringhe) nel portachiavi. Considerando che uno vuole verificare un certificato o utilizzare la protezione aggiuntiva di 'kSecClassKey', non può essere memorizzato utilizzando l'approccio dal codice di esempio di Apple o dal tuo link. Tuttavia, penso di aver trovato una soluzione, ma devo verificarla prima di postarla qui. – Chris

+1

In base alla mia esperienza, il wrapper portachiavi non consente di salvare più oggetti nello stesso gruppo portachiavi. Ciò ha causato una certa frustrazione ma una soluzione può essere trovata qui: http://stackoverflow.com/questions/11055731/ios-save-multiple-passwords-in-keychain?lq=1 – rob

+0

Questo è divertente - dato che lo sto facendo con un dizionario nella mia app e il salvataggio di e-mail, password e un altro bit di contesto relativo all'utente. Ma ho modificato il codice di Apple un po 'non molto - potete vederlo nel link nella mia risposta. Questo è un codice funzionante che è in migliaia di telefoni ora (non in milioni :-() –