Cosa rende unico un oggetto portachiavi (in iOS)?


104

La mia domanda riguarda i portachiavi in ​​iOS (iPhone, iPad, ...). Penso (ma non sono sicuro) che l'implementazione dei portachiavi in ​​Mac OS X solleva la stessa domanda con la stessa risposta.


iOS fornisce cinque tipi (classi) di elementi portachiavi. Devi scegliere uno di questi cinque valori per la chiave kSecClassper determinare il 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)

Dopo lungo periodo di documentazione di lettura mele, blog e forum-iscrizioni, ho scoperto che una voce di portachiavi di tipo kSecClassGenericPasswordottiene la sua unicità dagli attributi kSecAttrAccessGroup, kSecAttrAccounte kSecAttrService.

Se questi tre attributi nella richiesta 1 sono gli stessi della richiesta 2, si riceve lo stesso elemento portachiavi con password generica, indipendentemente da qualsiasi altro attributo. Se uno (o due o tutti) di questi attributi cambia il suo valore, otterrai elementi diversi.

Ma kSecAttrServiceè disponibile solo per elementi di tipo kSecClassGenericPassword, quindi non può far parte della "chiave univoca" di un elemento di qualsiasi altro tipo e non sembra esserci alcuna documentazione che indichi chiaramente quali attributi determinano in modo univoco un elemento portachiavi.

Il codice di esempio nella classe "KeychainItemWrapper" di "GenericKeychain" utilizza l'attributo kSecAttrGenericper rendere un elemento univoco, ma si tratta di un bug. Le due voci solo in questo esempio sono memorizzate come due voci distinte, perché la loro kSecAttrAccessGroupè diversa (una ha il gruppo di accesso impostato, l'altra lo lascia libero). Se provi ad aggiungere una seconda password senza un gruppo di accesso, utilizzando quello di Apple KeychainItemWrapper, fallirai.

Quindi, per favore, rispondi alle mie domande:

  • E 'vero, che la combinazione di kSecAttrAccessGroup, kSecAttrAccounted kSecAttrServiceè la "chiave unica" di un elemento portachiavi cui kSecClass è kSecClassGenericPassword?
  • Quali attributi rendono unico un oggetto portachiavi se kSecClassnon lo è kSecClassGenericPassword?

1
C'è un post sul blog qui su questo.
bobobobo

Risposte:


179

Le chiavi primarie sono le seguenti (derivate da file open source di Apple, vedere Schema.m4 , KeySchema.m4 e SecItem.cpp ):

  • Per un elemento di classe portachiavi kSecClassGenericPassword, la chiave primaria è la combinazione di kSecAttrAccounte kSecAttrService.
  • Per un elemento portachiavi della classe kSecClassInternetPassword, la chiave primaria è la combinazione di kSecAttrAccount, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrProtocol, kSecAttrAuthenticationType, kSecAttrPorte kSecAttrPath.
  • Per un elemento di classe portachiavi kSecClassCertificate, la chiave primaria è la combinazione di kSecAttrCertificateType, kSecAttrIssuere kSecAttrSerialNumber.
  • Per un elemento portachiavi della classe kSecClassKey, la chiave primaria è la combinazione di kSecAttrApplicationLabel, kSecAttrApplicationTag, kSecAttrKeyType, kSecAttrKeySizeInBits, kSecAttrEffectiveKeySize, e il creatore, data di inizio e di conclusione che non sono ancora esposti per SecItem.
  • Per un elemento portachiavi di classe kSecClassIdentitynon ho trovato informazioni sui campi della chiave primaria nei file open source, ma poiché un'identità è la combinazione di una chiave privata e un certificato, presumo che la chiave primaria sia la combinazione della chiave primaria campi per kSecClassKeye kSecClassCertificate.

Poiché ogni elemento del portachiavi appartiene a un gruppo di accesso al portachiavi, sembra che il gruppo (campo kSecAttrAccessGroup) di accesso al portachiavi sia un campo aggiunto a tutte queste chiavi primarie.


Sembra davvero una buona risposta! Grazie! Lo controllerò e voglio aspettare uno o due giorni per ulteriori commenti da altri utenti, ma sei un candidato caldo per i +50 punti dalla taglia.
Hubert Schölnast

3
Bella risposta! Sto lavorando da alcuni giorni all'implementazione di un wrapper portachiavi generico per certificati e chiavi private. È molto diverso dal codice di esempio di Apple che memorizza solo le credenziali di stringa (nome utente / password). Tuttavia, ho scoperto che quando si imposta la kSecClassper kSecClassCertificateo kSecClassKeycontrolli Portachiavi anche se la voce (la value) è già memorizzato. Ciò impedisce di aggiungere due volte lo stesso certificato o chiave. Inoltre, se specifichi un diverso kSecAttrApplicationTagper una chiave (che deve essere univoca, per quanto riguarda il post sopra) fallirà.
Chris

1
Può essere utile pensare kSecClassall'attributo come al nome della tabella e ai valori specificati sopra come solo primary keyalla rispettiva tabella.
bobobobo

2
Qual è la semantica di kSecAttrAccounte kSecAttrService? - oppure il programmatore può scegliere una semantica che decide?
wcochran

1
kSecAttrServiceserve per memorizzare il servizio, kSecAttrAccountserve per memorizzare il nome dell'account. Potresti memorizzare cose diverse al loro interno, ma ciò potrebbe creare confusione.
Tammo Freese

9

L'altro giorno stavo colpendo un bug (su iOS 7.1) relativo a questa domanda. Stavo usando SecItemCopyMatchingper leggere un kSecClassGenericPasswordoggetto e continuava a tornare errSecItemNotFound(-25300) anche se kSecAttrAccessGroup, kSecAttrAccounte kSecAttrServicetutti corrispondevano all'elemento nel portachiavi.

Alla fine ho capito che kSecAttrAccessiblenon corrispondeva. Il valore nel portachiavi conteneva pdmn = dk ( kSecAttrAccessibleAlways), ma stavo usando kSecAttrAccessibleWhenUnlocked.

Ovviamente questo valore non è necessario in primo luogo per SecItemCopyMatching, ma OSStatusnon era errSecParamerrSecBadReqma solo errSecItemNotFound(-25300) che lo ha reso un po 'difficile da trovare.

Perché SecItemUpdateho riscontrato lo stesso problema, ma con questo metodo anche l'utilizzo dello stesso kSecAttrAccessiblenel queryparametro non ha funzionato. Solo la rimozione completa di questo attributo lo ha risolto.

Spero che questo commento salverà alcuni preziosi momenti di debug per alcuni di voi.


4

La risposta data da @Tammo Freese sembra essere corretta (ma senza menzionare tutte le chiavi primarie). Stavo cercando delle prove nella documentazione. Finalmente trovato:

Documentazione Apple che menziona le chiavi primarie per ogni classe di segreto (citazione sotto):

Il sistema considera un elemento come un duplicato per un determinato portachiavi quando quel portachiavi ha già un elemento della stessa classe con lo stesso set di chiavi primarie composite. Ogni classe di elemento portachiavi ha un diverso set di chiavi primarie, sebbene alcuni attributi siano usati in comune a tutte le classi. In particolare, dove applicabile, kSecAttrSynchronizable e kSecAttrAccessGroup fanno parte del set di chiavi primarie . Le chiavi primarie aggiuntive per classe sono elencate di seguito:

  • Per le password generiche, le chiavi primarie includono kSecAttrAccount e kSecAttrService.
  • Per le password Internet, le chiavi primarie includono kSecAttrAccount, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrProtocol, kSecAttrAuthenticationType, kSecAttrPort e kSecAttrPath.
  • Per i certificati, le chiavi primarie includono kSecAttrCertificateType, kSecAttrIssuer e kSecAttrSerialNumber.
  • Per gli elementi chiave, le chiavi primarie includono kSecAttrKeyClass, kSecAttrKeyType, kSecAttrApplicationLabel, kSecAttrApplicationTag, kSecAttrKeySizeInBits e kSecAttrEffectiveKeySize.
  • Per gli elementi di identità, che sono un certificato e una chiave privata raggruppati insieme, le chiavi primarie sono le stesse di un certificato. Poiché una chiave privata può essere certificata più di una volta, l'unicità del certificato determina quella dell'identità.

Sebbene questo collegamento possa rispondere alla domanda, è meglio includere le parti essenziali della risposta qui e fornire il collegamento come riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia. - Dalla recensione
pwc

d'accordo, anche se in questo caso significava copiare l'intero link.
Julian Król

0

Ecco un'altra informazione utile sull'unicità di un elemento portachiavi, disponibile nella sezione "Garantire la ricerca" di questa pagina dei documenti di Apple .

Per poter trovare l'oggetto in un secondo momento, utilizzerai la tua conoscenza dei suoi attributi. In questo esempio, il server e l'account sono le caratteristiche distintive dell'articolo. Per gli attributi costanti (qui, il server), utilizzare lo stesso valore durante la ricerca. Al contrario, l'attributo account è dinamico, perché contiene un valore fornito dall'utente in fase di esecuzione. Finché la tua app non aggiunge mai elementi simili con attributi diversi (come password per account diversi sullo stesso server), puoi omettere questi attributi dinamici come parametri di ricerca e recuperarli insieme all'elemento. Di conseguenza, quando cerchi la password, ottieni anche il nome utente corrispondente.

Se la tua app aggiunge elementi con attributi dinamici variabili, avrai bisogno di un modo per scegliere tra di essi durante il recupero. Un'opzione è registrare le informazioni sugli articoli in un altro modo. Ad esempio, se conservi i record degli utenti in un modello Core Data, memorizzi il nome utente lì dopo aver utilizzato i servizi portachiavi per memorizzare il campo della password. Successivamente, si utilizza il nome utente estratto dal modello di dati per condizionare la ricerca della password.

In altri casi, può avere senso caratterizzare ulteriormente l'articolo aggiungendo più attributi. Ad esempio, potresti includere l' kSecAttrLabelattributo nella query di aggiunta originale, fornendo una stringa che contrassegna l'elemento per lo scopo particolare. Quindi sarai in grado di utilizzare questo attributo per restringere la ricerca in un secondo momento.

kSecClassInternetPasswordNell'esempio è stato utilizzato l' elemento di classe , ma c'è una nota che dice:

I servizi portachiavi offrono anche la relativa classe di elementi kSecClassGenericPassword. Le password generiche sono simili per molti aspetti alle password Internet, ma mancano di alcuni attributi specifici per l'accesso remoto (ad esempio, non hanno un attributo kSecAttrServer). Quando non hai bisogno di questi attributi extra, usa invece una password generica.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.