What makes a keychain item unique (in iOS)?
Solution 1
The primary keys are as follows (derived from open source files from Apple, see Schema.m4, KeySchema.m4 and SecItem.cpp):
- For a keychain item of class
kSecClassGenericPassword
, the primary key is the combination ofkSecAttrAccount
andkSecAttrService
. - For a keychain item of class
kSecClassInternetPassword
, the primary key is the combination ofkSecAttrAccount
,kSecAttrSecurityDomain
,kSecAttrServer
,kSecAttrProtocol
,kSecAttrAuthenticationType
,kSecAttrPort
andkSecAttrPath
. - For a keychain item of class
kSecClassCertificate
, the primary key is the combination ofkSecAttrCertificateType
,kSecAttrIssuer
andkSecAttrSerialNumber
. - For a keychain item of class
kSecClassKey
, the primary key is the combination ofkSecAttrApplicationLabel
,kSecAttrApplicationTag
,kSecAttrKeyType
,kSecAttrKeySizeInBits
,kSecAttrEffectiveKeySize
, and the creator, start date and end date which are not exposed by SecItem yet. - For a keychain item of class
kSecClassIdentity
I haven't found info on the primary key fields in the open source files, but as an identity is the combination of a private key and a certificate, I assume the primary key is the combination of the primary key fields forkSecClassKey
andkSecClassCertificate
.
As each keychain item belongs to a keychain access group, it feels like the keychain access group (field kSecAttrAccessGroup
) is an added field to all these primary keys.
Solution 2
I was hitting a bug the other day (on iOS 7.1) that is related to this question. I was using SecItemCopyMatching
to read a kSecClassGenericPassword
item and it kept returning errSecItemNotFound
(-25300) even though kSecAttrAccessGroup
, kSecAttrAccount
and kSecAttrService
were all matching the item in the keychain.
Eventually I figured out that kSecAttrAccessible
didn't match. The value in the keychain held pdmn = dk (kSecAttrAccessibleAlways
), but I was using kSecAttrAccessibleWhenUnlocked
.
Of course this value is not needed in the first place for SecItemCopyMatching
, but the OSStatus
was not errSecParam
nor errSecBadReq
but just errSecItemNotFound
(-25300) which made it a bit tricky to find.
For SecItemUpdate
I have experienced the same issue but in this method even using the same kSecAttrAccessible
in the query
parameter didn't work. Only completely removing this attribute fixed it.
I hope this comment will save few precious debugging moments for some of you.
Solution 3
Answer given by @Tammo Freese seems to be correct (but not mentioning all primary keys). I was searching for some proof in the documentation. Finally found:
Apple Documentation mentioning primary keys for each class of secret (quote below):
The system considers an item to be a duplicate for a given keychain when that keychain already has an item of the same class with the same set of composite primary keys. Each class of keychain item has a different set of primary keys, although a few attributes are used in common across all classes. In particular, where applicable, kSecAttrSynchronizable and kSecAttrAccessGroup are part of the set of primary keys. The additional per-class primary keys are listed below:
- For generic passwords, the primary keys include kSecAttrAccount and kSecAttrService.
- For internet passwords, the primary keys include kSecAttrAccount, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrProtocol, kSecAttrAuthenticationType, kSecAttrPort, and kSecAttrPath.
- For certificates, the primary keys include kSecAttrCertificateType, kSecAttrIssuer, and kSecAttrSerialNumber.
- For key items, the primary keys include kSecAttrKeyClass, kSecAttrKeyType, kSecAttrApplicationLabel, kSecAttrApplicationTag, kSecAttrKeySizeInBits, and kSecAttrEffectiveKeySize.
- For identity items, which are a certificate and a private key bundled together, the primary keys are the same as for a certificate. Because a private key may be certified more than once, the uniqueness of the certificate determines that of the identity.
Related videos on Youtube
Hubert Schölnast
Researcher and lecturer for IT Security and Data Science at the University of Applied Sciences St. Pölten. Native language: German
Updated on March 19, 2020Comments
-
Hubert Schölnast about 4 years
My question concerns keychains in iOS (iPhone, iPad, ...). I think (but am not sure) that the implementation of keychains under Mac OS X raises the same question with the same answer.
iOS provides five types (classes) of keychain items. You must chose one of those five values for the key
kSecClass
to determine the 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)
After long time of reading apples documentation, blogs and forum-entries, I found out that a keychain item of type
kSecClassGenericPassword
gets its uniqueness from the attributeskSecAttrAccessGroup
,kSecAttrAccount
andkSecAttrService
.If those three attributes in request 1 are the same as in request 2, then you receive the same generic password keychain item, regardless of any other attributes. If one (or two or all) of this attributes changes its value, then you get different items.
But
kSecAttrService
is only available for items of typekSecClassGenericPassword
, so it can't be part of the "unique key" of an item of any other type, and there seems to be no documentation that points out clearly which attributes uniquely determine a keychain item.The sample code in the class "KeychainItemWrapper" of "GenericKeychain" uses the attribute
kSecAttrGeneric
to make an item unique, but this is a bug. The two entries in this example only are stored as two distinct entries, because theirkSecAttrAccessGroup
is different (one has the access group set, the other lets it free). If you try to add a 2nd password without an access group, using Apple'sKeychainItemWrapper
, you will fail.So, please, answer my questions:
- Is it true, that the combination of
kSecAttrAccessGroup
,kSecAttrAccount
andkSecAttrService
is the "unique key" of a keychain item whose kSecClass iskSecClassGenericPassword
? - Which attributes makes a keychain item unique if its
kSecClass
is notkSecClassGenericPassword
?
-
bobobobo over 10 yearsThere is a blog entry here about this.
- Is it true, that the combination of
-
Hubert Schölnast almost 12 yearsSounds like a really good answer! Thank you! I'll check it and I want to wait one or two days for additional comments from other users, but you are a hot candidate for the +50 points from the bounty.
-
Chris almost 12 yearsGreat answer! I am working for some days on implementing a generic Keychain wrapper for certificates and private keys. That's a lot different to Apple's sample code that only stores string credentials (username/password). However, I have found out that when you set the
kSecClass
tokSecClassCertificate
orkSecClassKey
the Keychain checks also if the entry (thevalue
) is already stored. This prevents from adding the same certificate or key twice. Also if you specify a differentkSecAttrApplicationTag
for a key (which must be unique, regarding the post above) it'll fail. -
Tammo Freese about 11 years@Chris It's good to know about that additional check, thanks!
-
bobobobo over 10 yearsIt may help to think of the
kSecClass
attribute as the table name, and the specified values above as just theprimary key
of the respective table. -
wcochran almost 10 yearsWhat is the semantics of
kSecAttrAccount
andkSecAttrService
? -- or can the programmer choose any semantics she decides? -
Tammo Freese almost 10 years
kSecAttrService
is for storing the service,kSecAttrAccount
is for storing the account name. You could store different things in them, but that may get confusing. -
mfaani over 7 yearswhat's the diff between
kSecAttrLabel
&ksecValueData
? -
pwc almost 6 yearsWhile this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review
-
Julian almost 6 yearsagreed, although in this case it meant copying the whole link.
-
delarcomarta over 4 yearsDoes anyone know the difference between kSecAttrAccount and kSecAttrGeneric and when/how should I use each one? Thanks.
-
xaphod about 4 yearsI ended up here because I had used Apple's KeychainItem wrapper. Turns out it has a bad bug, which you likely hit as soon as you store 2 things with it: change
kSecAttrGeneric
(everywhere it appears) tokSecAttrAccount