127 votes

Qu'est-ce qui rend un porte-clés unique (dans iOS) ?

Ma question concerne les trousseaux de clés dans iOS (iPhone, iPad, ...). Je pense (mais je n'en suis pas sûr) que l'implémentation des trousseaux sous Mac OS X pose la même question avec la même réponse.


iOS propose cinq types (classes) de porte-clés. Vous devez choisir l'une de ces cinq valeurs pour la clé kSecClass pour déterminer le type :

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)

Après avoir longuement lu la documentation sur les pommes, les blogs et les articles de forum, j'ai découvert qu'un élément de trousseau de clés du type kSecClassGenericPassword tire son unicité des attributs kSecAttrAccessGroup , kSecAttrAccount y kSecAttrService .

Si les trois attributs de la demande 1 sont les mêmes que ceux de la demande 2, vous recevrez le même porte-clés générique pour mot de passe, quels que soient les autres attributs. Si l'un (ou deux ou tous) de ces attributs change de valeur, alors vous recevez des articles différents.

Mais kSecAttrService est uniquement disponible pour les éléments de type kSecClassGenericPassword Il ne peut donc pas faire partie de la "clé unique" d'un article d'un autre type, et aucune documentation ne semble indiquer clairement quels attributs déterminent de manière unique un article de trousseau.

L'exemple de code dans la classe "KeychainItemWrapper" de "GenericKeychain" utilise l'attribut kSecAttrGeneric pour rendre un objet unique, mais c'est un bug. Les deux entrées de cet exemple ne sont stockées que comme deux entrées distinctes, parce que leur kSecAttrAccessGroup est différent (l'un a le groupe d'accès défini, l'autre le laisse libre). Si vous essayez d'ajouter un deuxième mot de passe sans groupe d'accès, en utilisant la méthode d'Apple, vous devez vous assurer que le mot de passe est libre. KeychainItemWrapper vous échouerez.

Alors, s'il vous plaît, répondez à mes questions :

  • Est-il vrai, que la combinaison de kSecAttrAccessGroup , kSecAttrAccount y kSecAttrService est la "clé unique" d'un élément du trousseau dont le kSecClass est kSecClassGenericPassword ?
  • Quels sont les attributs qui rendent un porte-clés unique si son kSecClass n'est pas kSecClassGenericPassword ?

2 votes

Il existe un article de blog ici à ce sujet.

220voto

Tammo Freese Points 5648

Les clés primaires sont les suivantes (dérivées de fichiers open source d'Apple, voir Schema.m4 , KeySchema.m4 y SecItem.cpp ) :

  • Pour un objet porte-clés de classe kSecClassGenericPassword la clé primaire est la combinaison de kSecAttrAccount y kSecAttrService .
  • Pour un objet porte-clés de classe kSecClassInternetPassword la clé primaire est la combinaison de kSecAttrAccount , kSecAttrSecurityDomain , kSecAttrServer , kSecAttrProtocol , kSecAttrAuthenticationType , kSecAttrPort y kSecAttrPath .
  • Pour un objet porte-clés de classe kSecClassCertificate la clé primaire est la combinaison de kSecAttrCertificateType , kSecAttrIssuer y kSecAttrSerialNumber .
  • Pour un objet porte-clés de classe kSecClassKey la clé primaire est la combinaison de kSecAttrApplicationLabel , kSecAttrApplicationTag , kSecAttrKeyType , kSecAttrKeySizeInBits , kSecAttrEffectiveKeySize et le créateur, la date de début et la date de fin qui ne sont pas encore exposés par SecItem.
  • Pour un objet porte-clés de classe kSecClassIdentity Je n'ai pas trouvé d'informations sur les champs de clé primaire dans les fichiers open source, mais comme une identité est la combinaison d'une clé privée et d'un certificat, je suppose que la clé primaire est la combinaison des champs de clé primaire de kSecClassKey y kSecClassCertificate .

Comme chaque élément du trousseau appartient à un groupe d'accès au trousseau, on a l'impression que le groupe d'accès au trousseau (champ kSecAttrAccessGroup ) est un champ ajouté à toutes ces clés primaires.

0 votes

Cela semble être une très bonne réponse ! Je vous remercie ! Je vais vérifier et je veux attendre un ou deux jours pour des commentaires supplémentaires d'autres utilisateurs, mais vous êtes un candidat chaud pour les +50 points du bounty.

3 votes

Excellente réponse ! Je travaille depuis quelques jours sur l'implémentation d'un wrapper Keychain générique pour les certificats et les clés privées. C'est très différent de l'exemple de code d'Apple qui ne stocke que des informations d'identification de type chaîne (nom d'utilisateur/mot de passe). Cependant, j'ai découvert que lorsque vous définissez l'attribut kSecClass a kSecClassCertificate o kSecClassKey le Trousseau vérifie également si l'entrée (l'élément value ) est déjà stocké. Cela évite d'ajouter deux fois le même certificat ou la même clé. De même, si vous spécifiez un autre kSecAttrApplicationTag pour une clé (qui doit être unique, selon le post ci-dessus), il échouera.

0 votes

@Chris C'est bon de savoir qu'il y a une vérification supplémentaire, merci !

10voto

user3426913 Points 1

J'ai rencontré un bug l'autre jour (sur iOS 7.1) qui est lié à cette question. J'utilisais SecItemCopyMatching pour lire un kSecClassGenericPassword et il revenait sans cesse errSecItemNotFound (-25300) même si kSecAttrAccessGroup , kSecAttrAccount y kSecAttrService correspondaient tous à l'objet du porte-clés.

Finalement, j'ai compris que kSecAttrAccessible ne correspondait pas. La valeur dans le trousseau contenait pdmn = dk ( kSecAttrAccessibleAlways ), mais j'utilisais kSecAttrAccessibleWhenUnlocked .

Bien sûr, cette valeur n'est pas nécessaire en premier lieu pour SecItemCopyMatching mais le OSStatus n'était pas errSecParam ni errSecBadReq mais juste errSecItemNotFound (-25300), ce qui l'a rendu un peu difficile à trouver.

Pour SecItemUpdate J'ai rencontré le même problème, mais avec cette méthode, même en utilisant la même méthode. kSecAttrAccessible dans le query n'a pas fonctionné. Seule la suppression complète de cet attribut a permis de résoudre le problème.

J'espère que ce commentaire permettra à certains d'entre vous d'économiser quelques précieux moments de débogage.

8voto

Julian Król Points 1596

La réponse donnée par @Tammo Freese semble être correcte (mais ne mentionne pas toutes les clés primaires). J'ai cherché une preuve dans la documentation. J'ai finalement trouvé :

La documentation d'Apple mentionne des clés primaires pour chaque classe de secret (citation ci-dessous) :

Le système considère qu'un élément est un doublon pour un trousseau donné lorsque ce trousseau possède déjà un élément de la même classe avec le même ensemble de clés primaires composites. Chaque classe d'élément du trousseau a un ensemble différent de clés primaires, bien que les clés primaires composées soient les mêmes. quelques attributs sont utilisés en commun dans toutes les classes. En particulier, le cas échéant, kSecAttrSynchronizable et kSecAttrAccessGroup font partie de l'ensemble des clés primaires. . Les clés primaires supplémentaires par classe sont listées ci-dessous :

  • Pour les mots de passe génériques, les clés primaires inclure kSecAttrAccount et kSecAttrService.
  • Pour les mots de passe internet, les clés primaires inclure kSecAttrAccount, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrProtocol, kSecAttrAuthenticationType, kSecAttrPort, et kSecAttrPath.
  • Pour les certificats, les clés primaires inclure kSecAttrCertificateType, kSecAttrIssuer, et kSecAttrSerialNumber.
  • Pour les éléments clés, les clés primaires inclure kSecAttrKeyClass, kSecAttrKeyType, kSecAttrApplicationLabel, kSecAttrApplicationTag, kSecAttrKeySizeInBits, et kSecAttrEffectiveKeySize.
  • Pour les éléments d'identité, qui sont un certificat et une clé privée groupés ensemble, les clés primaires sont de la même manière que pour un certificat. Parce que une clé privée peut être certifiée plus d'une fois, l'unicité du certificat détermine celle de l'identifiant. certificat détermine celle de l'identité.

0voto

Casper Points 28

Voici un autre élément d'information utile sur le caractère unique d'un porte-clés, que l'on trouve dans la section "Assurer la facilité de recherche" du site Web de la Commission européenne. cette page Apple docs .

Pour pouvoir retrouver l'objet plus tard, vous allez utiliser votre connaissance de ses attributs. Dans cet exemple, le serveur et le compte sont les caractéristiques distinctives de l'élément. Pour les attributs constants (ici, le serveur), utilisez la même valeur lors de la recherche. En revanche, l'attribut compte est dynamique, car il contient une valeur fournie par l'utilisateur au moment de l'exécution. Tant que votre application n'ajoute jamais d'éléments similaires avec des attributs différents (comme les mots de passe de différents comptes sur le même serveur), vous pouvez omettre ces attributs dynamiques comme paramètres de recherche et les récupérer avec l'élément. Par conséquent, lorsque vous recherchez le mot de passe, vous obtenez également le nom d'utilisateur correspondant.

Si votre application ajoute des éléments dont les attributs dynamiques varient, vous devrez trouver un moyen de les choisir lors de la récupération. Une option consiste à enregistrer les informations sur les éléments d'une autre manière. Par exemple, si vous enregistrez les utilisateurs dans un modèle Core Data, vous y stockez le nom d'utilisateur après avoir utilisé les services du trousseau pour stocker le champ du mot de passe. Plus tard, vous utilisez le nom d'utilisateur extrait de votre modèle de données pour conditionner la recherche du mot de passe.

Dans d'autres cas, il peut être utile de caractériser davantage l'élément en ajoutant d'autres attributs. Par exemple, vous pouvez inclure l'attribut kSecAttrLabel dans la requête d'ajout originale, en fournissant une chaîne de caractères qui marque l'élément pour le but particulier. Vous pourrez ensuite utiliser cet attribut pour affiner votre recherche.

Elément de la classe kSecClassInternetPassword a été utilisé dans l'exemple, mais il y a une note qui dit :

Les services du trousseau offrent également la classe d'éléments kSecClassGenericPassword correspondante. Les mots de passe génériques sont similaires dans la plupart des cas aux mots de passe Internet, mais il leur manque certains attributs spécifiques à l'accès à distance (par exemple, ils n'ont pas d'attribut kSecAttrServer). Lorsque vous n'avez pas besoin de ces attributs supplémentaires, utilisez plutôt un mot de passe générique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X