Estoy usando este código para enumerar todas las claves privadas y obtener información sobre ellas, usando la API del marco de seguridad de Apple:
int main(int argc, const char * argv[]) { const void *keys[] = { kSecClass, kSecReturnRef, kSecMatchLimit, kSecAttrKeyClass}; const void *values[] = { kSecClassKey, kCFBooleanTrue, kSecMatchLimitAll, kSecAttrKeyClassPrivate}; CFDictionaryRef searchDict = CFDictionaryCreate( NULL, keys, values, sizeof(keys) / sizeof(keys[0]), NULL, NULL ); checkAlloc(searchDict); CFArrayRef items; check(SecItemCopyMatching(searchDict, (CFTypeRef *)&items)); for(int i=0; i<CFArrayGetCount(items); i++) { SecKeychainItemRef item = (SecKeychainItemRef) CFArrayGetValueAtIndex(items, i); CFShow((CFTypeRef)item); SecItemClass cls; SecKeychainAttributeList attrs; UInt32 dataLen; void* data; check(SecKeychainItemCopyContent(item, &cls, &attrs, &dataLen, &data)); printf("Key: %d\n", (int)dataLen); check(SecKeychainItemFreeContent(&attrs, data)); } CFRelease(items); CFRelease(searchDict); return 0; } La llamada a SecKeychainItemCopyContent falla en el segmento, aunque ninguno de los punteros que he estado pasando no son válidos.
El CFShow imprime líneas similares a <SecKey 0x7fb4d9d01420 [0x7fff74790ed0]> , por lo que item debe ser un SecKeyRef , pero la documentación dice que está bien usar un SecKeyRef como SecKeychainItemRef si la clave está en un llavero. Sin embargo, no veo ninguna función para encontrar si la clave está en un llavero, por lo que no puedo validar que las claves devueltas se puedan usar como tales.
¿Qué estoy haciendo mal aquí?
Para copiar los datos y/o atributos almacenados en el elemento del llavero dado, el tercer parámetro de la función SecKeychainItemCopyContent() es SecKeychainAttributeList *attrList con tipo como,
struct SecKeychainAttributeList { UInt32 count; SecKeychainAttribute *attr; }; Para este parámetro IN/OUT attrList : en la entrada, es la lista de atributos que solicita recuperar. En la salida, los atributos se completan. Pase NULL si no hay necesidad de recuperar ningún atributo, o pase una lista de atributos que necesita obtener. Debería ser cualquiera de estos dos argumentos mencionados. Dejarlo sin inicializar podría causar problemas, como fallas de segmento.
Por lo tanto, intente así, debería funcionar bien.
SecKeychainAttributeList attrs = {0, NULL}; //... check(SecKeychainItemCopyContent(item, &cls, &attrs, &dataLen, &data));o
//SecKeychainAttributeList attrs ; //... check(SecKeychainItemCopyContent(item, &cls, NULL, &dataLen, &data)); printf("Key: %d\n", (int)dataLen); check(SecKeychainItemFreeContent(NULL, data));En caso de que fuera necesario obtener una lista de atributos, el código de muestra podría ser el siguiente:
SecKeychainAttributeList xlist; SecKeychainAttribute outList[] = { {kSecAddressItemAttr,}, {kSecAccountItemAttr,}, {kSecVolumeItemAttr,}, {kSecProtocolItemAttr} }; xlist.count = sizeof(outList)/sizeof(outList[0]); xlist.attr = outList; //... err = SecKeychainItemCopyContent (itemRef, nil, &xlist, &len, &outData); //...Aparentemente, el parámetro SecKeychainAttributeList no es solo una salida. También es una entrada que contiene los atributos a obtener.
SecKeychainAttributeList la referencia al puntero attrs->attr no inicializado y se bloqueó. Inicializar el puntero a NULL soluciona el problema.