Was macht einen Schlüsselbund einzigartig (in iOS)?

104

Meine Frage betrifft Schlüsselanhänger in iOS (iPhone, iPad, ...). Ich denke (bin mir aber nicht sicher), dass die Implementierung von Schlüsselanhängern unter Mac OS X dieselbe Frage mit derselben Antwort aufwirft.


iOS bietet fünf Arten (Klassen) von Schlüsselbundelementen. Sie müssen einen dieser fünf Werte für den Schlüssel auswählen kSecClass, um den Typ zu bestimmen:

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)

Nach langer Zeit des Lesens Äpfel Dokumentation, Blogs und Forum-Einträge, fand ich heraus , dass ein Schlüsselbund Artikel vom Typ kSecClassGenericPasswordseine Einzigartigkeit aus den Attributen wird kSecAttrAccessGroup, kSecAttrAccountund kSecAttrService.

Wenn diese drei Attribute in Anforderung 1 mit denen in Anforderung 2 identisch sind, erhalten Sie unabhängig von anderen Attributen dasselbe generische Kennwort-Schlüsselbundelement. Wenn eines (oder zwei oder alle) dieser Attribute seinen Wert ändert, erhalten Sie verschiedene Elemente.

Ist kSecAttrServicejedoch nur für Artikel vom Typ verfügbar kSecClassGenericPassword, kann es also nicht Teil des "eindeutigen Schlüssels" eines Artikels eines anderen Typs sein, und es scheint keine Dokumentation zu geben, die klar darauf hinweist, welche Attribute einen Schlüsselbundartikel eindeutig bestimmen.

Der Beispielcode in der Klasse "KeychainItemWrapper" von "GenericKeychain" verwendet das Attribut kSecAttrGeneric, um ein Element eindeutig zu machen. Dies ist jedoch ein Fehler. Die beiden Einträge in diesem Beispiel werden nur als zwei unterschiedliche Einträge gespeichert, da sie kSecAttrAccessGroupunterschiedlich sind (bei einem ist die Zugriffsgruppe festgelegt, bei dem anderen ist sie frei). Wenn Sie versuchen, mit Apple ein zweites Kennwort ohne Zugriffsgruppe hinzuzufügen, schlagen KeychainItemWrapperSie fehl.

Beantworten Sie also bitte meine Fragen:

  • Ist es wahr, dass die Kombination aus kSecAttrAccessGroup, kSecAttrAccountund kSecAttrServicesind die „eindeutigen Schlüssel“ ein Schlüsselanhänger - Elements , dessen kSecClass ist kSecClassGenericPassword?
  • Welche Attribute machen ein Schlüsselbundelement einzigartig, wenn dies kSecClassnicht der Fall ist kSecClassGenericPassword?
Hubert Schölnast
quelle
1
Hierüber gibt es einen Blogeintrag .
Bobobobo

Antworten:

179

Die Primärschlüssel lauten wie folgt (abgeleitet von Open Source-Dateien von Apple, siehe Schema.m4 , KeySchema.m4 und SecItem.cpp ):

  • Bei einem Schlüsselbund der Klasse kSecClassGenericPasswordist der Primärschlüssel die Kombination von kSecAttrAccountund kSecAttrService.
  • Für einen Schlüsselbund Artikel der Klasse kSecClassInternetPassword, ist der Primärschlüssel die Kombination von kSecAttrAccount, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrProtocol, kSecAttrAuthenticationType, kSecAttrPortund kSecAttrPath.
  • Für einen Schlüsselbund Artikel der Klasse kSecClassCertificate, ist der Primärschlüssel die Kombination aus kSecAttrCertificateType, kSecAttrIssuerund kSecAttrSerialNumber.
  • Für einen Schlüsselbund Artikel der Klasse kSecClassKey, ist der Primärschlüssel die Kombination von kSecAttrApplicationLabel, kSecAttrApplicationTag, kSecAttrKeyType, kSecAttrKeySizeInBits, kSecAttrEffectiveKeySize, und der Schöpfer, und Enddatum beginnen , die von SecItem noch nicht ausgesetzt sind.
  • Für ein Schlüsselbundelement der Klasse habe kSecClassIdentityich keine Informationen zu den Primärschlüsselfeldern in den Open Source-Dateien gefunden, aber da eine Identität die Kombination eines privaten Schlüssels und eines Zertifikats ist, gehe ich davon aus, dass der Primärschlüssel die Kombination des Primärschlüssels ist Felder für kSecClassKeyund kSecClassCertificate.

Da jedes Schlüsselbundelement zu einer Schlüsselbundzugriffsgruppe gehört, scheint die Schlüsselbundzugriffsgruppe (Feld kSecAttrAccessGroup) ein zusätzliches Feld zu all diesen Primärschlüsseln zu sein.

Tammo Freese
quelle
Klingt nach einer wirklich guten Antwort! Danke dir! Ich werde es überprüfen und ich möchte ein oder zwei Tage auf zusätzliche Kommentare von anderen Benutzern warten, aber Sie sind ein heißer Kandidat für die +50 Punkte aus dem Kopfgeld.
Hubert Schölnast
3
Gute Antwort! Ich arbeite seit einigen Tagen an der Implementierung eines generischen Schlüsselbund-Wrappers für Zertifikate und private Schlüssel. Dies unterscheidet sich stark von Apples Beispielcode, in dem nur Anmeldeinformationen für Zeichenfolgen (Benutzername / Kennwort) gespeichert werden. Ich habe jedoch herausgefunden, dass beim Festlegen kSecClassvon kSecClassCertificateoder kSecClassKeySchlüsselbund auch überprüft wird, ob der Eintrag (der value) bereits gespeichert ist. Dies verhindert, dass dasselbe Zertifikat oder Schlüssel zweimal hinzugefügt wird. Auch wenn Sie kSecAttrApplicationTagfür einen Schlüssel einen anderen angeben (der in Bezug auf den obigen Beitrag eindeutig sein muss), schlägt dies fehl.
Chris
1
Es kann hilfreich sein, sich das kSecClassAttribut als Tabellennamen und die oben angegebenen Werte nur als die primary keyder jeweiligen Tabelle vorzustellen.
Bobobobo
2
Was ist die Semantik von kSecAttrAccountund kSecAttrService? - oder kann der Programmierer eine Semantik wählen, die er entscheidet?
Wcochran
1
kSecAttrServicedient zum Speichern des Dienstes, kSecAttrAccountdient zum Speichern des Kontonamens. Sie könnten verschiedene Dinge darin speichern, aber das kann verwirrend werden.
Tammo Freese
9

Ich habe neulich (unter iOS 7.1) einen Fehler gefunden, der mit dieser Frage zusammenhängt. Ich SecItemCopyMatchinghabe einen kSecClassGenericPasswordArtikel gelesen und er kehrte immer wieder zurück errSecItemNotFound(-25300) kSecAttrAccessGroup, kSecAttrAccountund kSecAttrServicealle stimmten mit dem Artikel im Schlüsselbund überein.

Schließlich fand ich heraus, dass kSecAttrAccessibledas nicht passte. Der Wert im Schlüsselbund enthielt pdmn = dk ( kSecAttrAccessibleAlways), aber ich habe ihn verwendet kSecAttrAccessibleWhenUnlocked.

Natürlich wird dieser Wert überhaupt nicht benötigt SecItemCopyMatching, aber das OSStatuswar nicht errSecParamnoch, errSecBadReqsondern nur errSecItemNotFound(-25300), was es etwas schwierig machte, ihn zu finden.

Denn SecItemUpdateich habe das gleiche Problem erlebt, aber bei dieser Methode hat es nicht funktioniert, dasselbe kSecAttrAccessibleim queryParameter zu verwenden. Nur das vollständige Entfernen dieses Attributs hat es behoben.

Ich hoffe, dieser Kommentar erspart einigen von Ihnen einige wertvolle Debugging-Momente.

izik lissabon
quelle
4

Die Antwort von @Tammo Freese scheint richtig zu sein (ohne jedoch alle Primärschlüssel zu erwähnen). Ich habe nach Beweisen in der Dokumentation gesucht. Endlich gefunden:

Apple-Dokumentation mit Erwähnung der Primärschlüssel für jede Klasse von Geheimnissen (Zitat unten):

Das System betrachtet ein Element als Duplikat für einen bestimmten Schlüsselbund, wenn dieser Schlüsselbund bereits ein Element derselben Klasse mit demselben Satz zusammengesetzter Primärschlüssel enthält. Jede Klasse von Schlüsselbundelementen verfügt über einen anderen Satz von Primärschlüsseln, obwohl einige Attribute für alle Klassen gemeinsam verwendet werden. Insbesondere sind kSecAttrSynchronizable und kSecAttrAccessGroup gegebenenfalls Teil des Satzes von Primärschlüsseln . Die zusätzlichen Primärschlüssel pro Klasse sind unten aufgeführt:

  • Bei generischen Kennwörtern umfassen die Primärschlüssel kSecAttrAccount und kSecAttrService.
  • Für Internetkennwörter umfassen die Primärschlüssel kSecAttrAccount, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrProtocol, kSecAttrAuthenticationType, kSecAttrPort und kSecAttrPath.
  • Bei Zertifikaten umfassen die Primärschlüssel kSecAttrCertificateType, kSecAttrIssuer und kSecAttrSerialNumber.
  • Für Schlüsselelemente umfassen die Primärschlüssel kSecAttrKeyClass, kSecAttrKeyType, kSecAttrApplicationLabel, kSecAttrApplicationTag, kSecAttrKeySizeInBits und kSecAttrEffectiveKeySize.
  • Bei Identitätselementen, bei denen es sich um ein Zertifikat und einen privaten Schlüssel handelt, sind die Primärschlüssel dieselben wie bei einem Zertifikat. Da ein privater Schlüssel mehrmals zertifiziert werden kann, bestimmt die Eindeutigkeit des Zertifikats die der Identität.
Julian Król
quelle
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - Von der Überprüfung
pwc
stimmte zu, obwohl es in diesem Fall bedeutete, den gesamten Link zu kopieren.
Julian Król
0

Im Folgenden finden Sie weitere nützliche Informationen zur Eindeutigkeit eines Schlüsselbundelements im Abschnitt "Suchbarkeit sicherstellen" auf dieser Apple-Dokumentseite .

Um das Objekt später finden zu können, verwenden Sie Ihr Wissen über seine Attribute. In diesem Beispiel sind der Server und das Konto die Unterscheidungsmerkmale des Elements. Verwenden Sie für konstante Attribute (hier den Server) während der Suche denselben Wert. Im Gegensatz dazu ist das Kontoattribut dynamisch, da es einen vom Benutzer zur Laufzeit bereitgestellten Wert enthält. Solange Ihre App niemals ähnliche Elemente mit unterschiedlichen Attributen hinzufügt (z. B. Kennwörter für verschiedene Konten auf demselben Server), können Sie diese dynamischen Attribute als Suchparameter weglassen und sie stattdessen zusammen mit dem Element abrufen. Wenn Sie das Passwort nachschlagen, erhalten Sie daher auch den entsprechenden Benutzernamen.

Wenn Ihre App Elemente mit unterschiedlichen dynamischen Attributen hinzufügt, müssen Sie beim Abrufen eine Auswahl treffen. Eine Möglichkeit besteht darin, Informationen zu den Elementen auf andere Weise aufzuzeichnen. Wenn Sie beispielsweise Aufzeichnungen über Benutzer in einem Core Data-Modell führen, speichern Sie dort den Benutzernamen, nachdem Sie das Kennwortfeld mithilfe von Schlüsselbunddiensten gespeichert haben. Später verwenden Sie den Benutzernamen aus Ihrem Datenmodell, um die Suche nach dem Kennwort zu konditionieren.

In anderen Fällen kann es sinnvoll sein, das Element durch Hinzufügen weiterer Attribute weiter zu charakterisieren. Beispielsweise können Sie das kSecAttrLabelAttribut in die ursprüngliche Add-Abfrage aufnehmen und eine Zeichenfolge bereitstellen, die das Element für den bestimmten Zweck markiert. Dann können Sie dieses Attribut verwenden, um Ihre Suche später einzugrenzen.

kSecClassInternetPasswordIm Beispiel wurde ein Klassengegenstand verwendet, aber es gibt einen Hinweis, der besagt:

Schlüsselbunddienste bieten auch die zugehörige Artikelklasse kSecClassGenericPassword an. Generische Kennwörter ähneln in den meisten Punkten Internetkennwörtern, es fehlen jedoch bestimmte Attribute für den Remotezugriff (z. B. haben sie kein kSecAttrServer-Attribut). Wenn Sie diese zusätzlichen Attribute nicht benötigen, verwenden Sie stattdessen ein generisches Kennwort.

Aleksandar
quelle