¿Qué hace que un elemento de llavero sea único (en iOS)?

Mi pregunta se refiere a llaveros en iOS (iPhone, iPad, …). Creo (pero no estoy seguro) de que la implementación de llaveros en Mac OS X plantea la misma pregunta con la misma respuesta.


iOS proporciona cinco types (classs) de artículos de llavero. Debe elegir uno de esos cinco valores para la key kSecClass para determinar el tipo:

 kSecClassGenericPassword used to store a generic password kSecClassInternetPassword used to store an internet password kSecClassCertificate used to store a certificate kSecClassKey used to store a kryptographic key kSecClassIdentity used to store an identity (certificate + private key) 

Después de mucho time de leer la documentation de manzanas, blogs y inputs de foro, descubrí que un elemento llavero del tipo kSecClassGenericPassword obtiene su singularidad de los attributes kSecAttrAccessGroup , kSecAttrAccount y kSecAttrService .

Si esos tres attributes en la request 1 son los mismos que en la request 2, recibirá el mismo elemento de la key de la key genérica, independientemente de cualquier otro atributo. Si uno (o dos o todos) de estos attributes cambia su valor, obtienes diferentes elementos.

Pero kSecAttrService solo está disponible para elementos del tipo kSecClassGenericPassword , por lo que no puede ser parte de la "key única" de un artículo de ningún otro tipo, y parece que no hay documentation que indique claramente qué attributes determinan de manera única un elemento llavero .

El código de muestra en la class "KeychainItemWrapper" de "GenericKeychain" utiliza el atributo kSecAttrGeneric para hacer que un elemento sea único, pero este es un error. Las dos inputs en este ejemplo solo se almacenan como dos inputs distintas, ya que su kSecAttrAccessGroup es diferente (uno tiene el set de grupos de acceso y el otro lo deja libre). Si intenta agregar una segunda contraseña sin un grupo de acceso, utilizando KeychainItemWrapper de Apple, fallará.

Entonces, por favor, responda mis preguntas:

  • ¿Es cierto que la combinación de kSecAttrAccessGroup , kSecAttrAccount y kSecAttrService es la "key única" de un elemento llavero cuyo kSecClass es kSecClassGenericPassword ?
  • ¿Qué attributes hacen que un elemento de llavero sea único si su kSecClass no es kSecClassGenericPassword ?

Las keys principales son las siguientes (derivadas de files de código abierto de Apple, consulte Schema.m4 , KeySchema.m4 y SecItem.cpp ):

  • Para un elemento llavero de la class kSecClassGenericPassword , la key principal es la combinación de kSecAttrAccount y kSecAttrService .
  • Para un artículo llavero de la class kSecClassInternetPassword , la key principal es la combinación de kSecAttrAccount , kSecAttrSecurityDomain , kSecAttrServer , kSecAttrProtocol , kSecAttrAuthenticationType , kSecAttrPort y kSecAttrPath .
  • Para un artículo llavero de la class kSecClassCertificate , la key principal es la combinación de kSecAttrCertificateType , kSecAttrIssuer y kSecAttrSerialNumber .
  • Para un elemento llavero de la class kSecClassKey , la key principal es la combinación de kSecAttrApplicationLabel , kSecAttrApplicationTag , kSecAttrKeyType , kSecAttrKeySizeInBits , kSecAttrEffectiveKeySize y el creador, date de inicio y date de finalización, que aún no están expuestos por SecItem.
  • Para un elemento llavero de la class kSecClassIdentity , no encontré información en los campos de key primaria en los files de código abierto, pero como identidad es la combinación de una key privada y un certificate, supongo que la key primaria es la combinación de la key primaria campos key para kSecClassKey y kSecClassCertificate .

Como cada elemento de llavero pertenece a un grupo de acceso de llavero, se siente como que el grupo de acceso de llavero (campo kSecAttrAccessGroup ) es un campo agregado a todas estas teclas principales.

Estuve chocando con un error el otro día (en iOS 7.1) que está relacionado con esta pregunta. Estaba utilizando SecItemCopyMatching para leer un elemento kSecClassGenericPassword y seguía devolviendo errSecItemNotFound (-25300) aunque kSecAttrAccessGroup , kSecAttrAccount y kSecAttrService coincidían con el elemento en el llavero.

Eventualmente me di count de que kSecAttrAccessible no coincidía. El valor en el llavero contenía pdmn = dk ( kSecAttrAccessibleAlways ), pero estaba usando kSecAttrAccessibleWhenUnlocked .

Por supuesto, este valor no es necesario en primer lugar para SecItemCopyMatching , pero el OSStatus del sistema OSStatus no era errSecParam ni errSecBadReq sino simplemente errSecItemNotFound (-25300) lo que lo hacía un poco difícil de encontrar.

Para SecItemUpdate he experimentado el mismo problema pero en este método, incluso el uso del mismo kSecAttrAccessible en el parámetro de query no funcionó. Solo eliminando completamente este atributo lo solucionó.

Espero que este comentario guarde algunos preciosos momentos de debugging para algunos de ustedes.