2012-07-26 19 views
19

Estoy tratando de agregar una clave privada en el llavero de iOS. El certificado (clave pública) funciona bien pero la clave privada se niega ... Estoy totalmente confundido por qué el siguiente código no funciona.Agregar clave privada en iOS Keychain

Primero estoy comprobando si la clave actual (= clave en caso de que el Llavero sea un almacén de claves/valores) está 'libre' en el Llavero. Luego voy a agregar la clave privada.

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

salida La depuración es la siguiente:

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) 

El primero código de error -25300 representa errSecItemNotFound. Entonces no hay ningún valor almacenado para esta clave. Luego, cuando trato de agregar la clave privada en el llavero, obtengo -25299, que significa errSecDuplicateItem. No entiendo esto. ¿Por qué está pasando esto?

¿Alguien tiene una pista o pista sobre esto?

códigos de error de 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. */ 

Gracias de antemano!

Actualización n. ° 1: He descubierto que funciona solo por primera vez. Incluso cuando los datos y la clave son diferentes, después de la primera vez que guardé el llavero no puedo almacenar más llaves.

+0

que estoy enfrentando el mismo problema exacto. La primera clave añadida usando SecItemAdd sin problema, luego cualquier llamada consecutiva a SecItemAdd falla con errSecDuplicateItem aunque a pesar de SecItemCopyMatching devolver errSecItemNotFound. ¿Has encontrado una solución para esto todavía? – 100grams

Respuesta

8

el siguiente código que funcionó para mí:

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 una mala práctica eliminar un elemento de Llavero solo para agregar un artículo con la misma información. No recuerdo el motivo específico por el cual, pero yo cree que puede causar conflictos al intentar hacerlo. – Joey

+0

Hablé con un empleado de Apple que trabaja en el llavero en la WWDC del año pasado y me dijo que, de hecho, no ofrecen otra forma de lograrlo, pero tienen una API privada para lo que lanzarán _soon_. .. – Chris

+1

No sé a qué te refieres, Chris. Tuve el mismo problema y pude arreglar mi código para encontrar correctamente el elemento existente. Mi problema era que estaba definiéndolo como sincronizable con iCloud al agregarlo, pero no lo incluí en la consulta cuando buscaba, por lo que no pude encontrar una coincidencia. No tuve que eliminar y agregarlo de nuevo. – Joey

1

Lo siento, pero nunca podré depurar el código. Apple proporciona un código de ejemplo (KeychainItemWrapper) que le permite guardar una cadena (recuerdo). Es una gran ayuda lidiar con el llavero. Hay una esencia en la web que es una versión modificada de esa clase, pero guarda y restaura un diccionario (archivado como un objeto de datos, que es lo que el código de Apple hace a la cadena). Esto le permite guardar varios elementos en una interfaz para el llavero. Lo esencial es aquí Keychain for NSDictionary/data

+1

Gracias, pero debe almacenarse como 'kSecClassKey' (y el certificado correspondiente como' kSecClassCertificate'). Sé que Apple proporciona este código de muestra para almacenar credenciales de usuario (pero solo cadenas) en el llavero. Teniendo en cuenta que uno desea verificar un certificado o utilizar la protección adicional de 'kSecClassKey' no puede almacenarse utilizando el enfoque del código de muestra de Apple o su enlace. Sin embargo, creo que he encontrado una solución, pero tengo que verificar esto antes de publicarlo aquí. – Chris

+1

En mi experiencia, el envoltorio de llavero no permite que varios elementos se guarden en el mismo grupo de llavero. Esto causó una gran frustación, pero se puede encontrar una solución aquí: http://stackoverflow.com/questions/11055731/ios-save-multiple-passwords-in-keychain?lq=1 – rob

+0

Eso es gracioso, ya que lo estoy haciendo con un diccionario en mi aplicación y guardando el correo electrónico, la contraseña y otro poco de contexto relacionado con el usuario. Pero modifiqué un poco el código de Apple: puede verlo en el enlace en mi respuesta. Este es el código de trabajo que está en miles de teléfonos ahora (no en millones :-() –

Cuestiones relacionadas