是什么让钥匙串项目独一无二(在 iOS 中)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11614047/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 19:23:52  来源:igfitidea点击:

What makes a keychain item unique (in iOS)?

objective-ciosmacoskeychain

提问by Hubert Sch?lnast

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(iPhone、iPad 等)中的钥匙串。我认为(但我不确定)Mac OS X 下钥匙串的实现提出了相同的问题和相同的答案。



iOS provides five types (classes) of keychain items. You must chose one of those five values for the key kSecClassto determine the type:

iOS 提供了五种类型(类)的钥匙串项目。您必须为键选择这五个值之一kSecClass来确定类型:

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 kSecClassGenericPasswordgets its uniqueness from the attributes kSecAttrAccessGroup, kSecAttrAccountand kSecAttrService.

在长时间阅读苹果文档、博客和论坛条目后,我发现 type 类型的钥匙串项目kSecClassGenericPassword从属性中获得其唯一性kSecAttrAccessGroup,kSecAttrAccountkSecAttrService

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.

如果请求 1 中的这三个属性与请求 2 中的相同,那么您将收到相同的通用密码钥匙串项目,而不管任何其他属性。如果此属性中的一个(或两个或全部)更改了其值,则您将获得不同的项目。

But kSecAttrServiceis only available for items of type kSecClassGenericPassword, 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.

kSecAttrService仅适用于 type 的项目kSecClassGenericPassword,因此它不能成为任何其他类型项目的“唯一键”的一部分,并且似乎没有文档明确指出哪些属性唯一地确定了钥匙串项目。

The sample code in the class "KeychainItemWrapper" of "GenericKeychain" uses the attribute kSecAttrGenericto make an item unique, but this is a bug. The two entries in this example only are stored as two distinct entries, because their kSecAttrAccessGroupis 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's KeychainItemWrapper, you will fail.

“GenericKeychain”的“KeychainItemWrapper”类中的示例代码使用该属性kSecAttrGeneric使项目唯一,但这是一个错误。本示例中的两个条目仅存储为两个不同的条目,因为它们kSecAttrAccessGroup是不同的(一个设置了访问组,另一个让它自由)。如果您尝试使用 Apple 的KeychainItemWrapper,在没有访问组的情况下添加第二个密码,您将失败。

So, please, answer my questions:

所以,请回答我的问题:

  • Is it true, that the combination of kSecAttrAccessGroup, kSecAttrAccountand kSecAttrServiceis the "unique key" of a keychain item whose kSecClass is kSecClassGenericPassword?
  • Which attributes makes a keychain item unique if its kSecClassis not kSecClassGenericPassword?
  • 这是真的,那的组合kSecAttrAccessGroupkSecAttrAccount并且kSecAttrService是一个钥匙串项目,其kSecClass是“唯一钥匙” kSecClassGenericPassword
  • 如果kSecClass不是,哪些属性使钥匙串项目独一无二kSecClassGenericPassword

回答by Tammo Freese

The primary keys are as follows (derived from open source files from Apple, see Schema.m4, KeySchema.m4and SecItem.cpp):

主键如下(源自苹果的开源文件,参见Schema.m4KeySchema.m4SecItem.cpp):

  • For a keychain item of class kSecClassGenericPassword, the primary key is the combination of kSecAttrAccountand kSecAttrService.
  • For a keychain item of class kSecClassInternetPassword, the primary key is the combination of kSecAttrAccount, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrProtocol, kSecAttrAuthenticationType, kSecAttrPortand kSecAttrPath.
  • For a keychain item of class kSecClassCertificate, the primary key is the combination of kSecAttrCertificateType, kSecAttrIssuerand kSecAttrSerialNumber.
  • For a keychain item of class kSecClassKey, the primary key is the combination of kSecAttrApplicationLabel, 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 kSecClassIdentityI 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 for kSecClassKeyand kSecClassCertificate.
  • 对于类的钥匙串项目kSecClassGenericPassword,主键是的组合 kSecAttrAccountkSecAttrService
  • 对于类的钥匙串项目kSecClassInternetPassword,主键是的组合kSecAttrAccountkSecAttrSecurityDomainkSecAttrServerkSecAttrProtocolkSecAttrAuthenticationTypekSecAttrPortkSecAttrPath
  • 对于类的钥匙串项kSecClassCertificate,主键是kSecAttrCertificateType,kSecAttrIssuer和的组合kSecAttrSerialNumber
  • 对于类的钥匙串项目kSecClassKey,主键是的组合kSecAttrApplicationLabelkSecAttrApplicationTagkSecAttrKeyTypekSecAttrKeySizeInBitskSecAttrEffectiveKeySize,和创建者,开始其不被暴露SecItem还日期和结束日期。
  • 对于类的钥匙串项目,kSecClassIdentity我没有在开源文件中找到有关主键字段的信息,但由于身份是私钥和证书的组合,我假设主键是主键的组合kSecClassKey和 的字段kSecClassCertificate

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.

由于每个钥匙串项都属于一个钥匙串访问组,所以感觉钥匙串访问组(字段kSecAttrAccessGroup)是所有这些主键的附加字段。

回答by izik lisbon

I was hitting a bug the other day (on iOS 7.1) that is related to this question. I was using SecItemCopyMatchingto read a kSecClassGenericPassworditem and it kept returning errSecItemNotFound(-25300) even though kSecAttrAccessGroup, kSecAttrAccountand kSecAttrServicewere all matching the item in the keychain.

前几天(在 iOS 7.1 上)我遇到了一个与这个问题相关的错误。我正在使用SecItemCopyMatching读取一个kSecClassGenericPassword项目,但它一直返回errSecItemNotFound(-25300)kSecAttrAccessGroupkSecAttrAccount并且kSecAttrService都与钥匙串中的项目匹配。

Eventually I figured out that kSecAttrAccessibledidn't match. The value in the keychain held pdmn = dk (kSecAttrAccessibleAlways), but I was using kSecAttrAccessibleWhenUnlocked.

最后我发现这kSecAttrAccessible不匹配。钥匙串中的值是 pdmn = dk ( kSecAttrAccessibleAlways),但我使用的是kSecAttrAccessibleWhenUnlocked.

Of course this value is not needed in the first place for SecItemCopyMatching, but the OSStatuswas not errSecParamnor errSecBadReqbut just errSecItemNotFound(-25300) which made it a bit tricky to find.

当然,首先不需要这个值SecItemCopyMatching,但OSStatus不是errSecParamerrSecBadReq只是errSecItemNotFound(-25300) 这使得它有点难以找到。

For SecItemUpdateI have experienced the same issue but in this method even using the same kSecAttrAccessiblein the queryparameter didn't work. Only completely removing this attribute fixed it.

因为SecItemUpdate我遇到了同样的问题,但在这种方法中,即使kSecAttrAccessiblequery参数中使用相同的问题也不起作用。只有完全删除此属性才能修复它。

I hope this comment will save few precious debugging moments for some of you.

我希望这条评论能为你们中的一些人节省一些宝贵的调试时间。

回答by Julian Król

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:

@Tammo Freese 给出的答案似乎是正确的(但没有提到所有主键)。我在文档中寻找一些证据。终于找到了:

Apple Documentation mentioning primary keys for each class of secret (quote below):

Apple 文档中提到了每类机密的主键(引用如下):

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.

当该钥匙串已经具有具有相同组合主键集的相同类别的项目时,系统认为该项目是给定钥匙串的重复项。每个类别的钥匙串项目都有一组不同的主键,尽管一些属性在所有类别中通用。特别是,在适用的情况下,kSecAttrSynchronizable 和 kSecAttrAccessGroup 是主键集的一部分。下面列出了额外的每类主键:

  • 对于通用密码,主键包括 kSecAttrAccount 和 kSecAttrService。
  • 对于 Internet 密码,主键包括 kSecAttrAccount、kSecAttrSecurityDomain、kSecAttrServer、kSecAttrProtocol、kSecAttrAuthenticationType、kSecAttrPort 和 kSecAttrPath。
  • 对于证书,主键包括 kSecAttrCertificateType、kSecAttrIssuer 和 kSecAttrSerialNumber。
  • 对于关键项,主键包括kSecAttrKeyClass、kSecAttrKeyType、kSecAttrApplicationLabel、kSecAttrApplicationTag、kSecAttrKeySizeInBits和kSecAttrEffectiveKeySize。
  • 对于身份项,证书和私钥捆绑在一起,主密钥与证书相同。因为一个私钥可能被多次认证,所以证书的唯一性决定了身份的唯一性。

回答by Aleksandar

Here is another piece of useful information about uniqueness of a keychain item, found in the "Ensure Searchability" section of this Apple docs page.

这是有关钥匙串项目唯一性的另一条有用信息,可在此 Apple 文档页面的“确保可搜索性”部分找到

To be able to find the item later, you're going to use your knowledge of its attributes. In this example, the server and the account are the item's distinguishing characteristics. For constant attributes (here, the server), use the same value during lookup. In contrast, the account attribute is dynamic, because it holds a value provided by the user at runtime. As long as your app never adds similar items with varying attributes (such as passwords for different accounts on the same server), you can omit these dynamic attributes as search parameters and instead retrieve them along with the item. As a result, when you look up the password, you also get the corresponding username.

If your app does add items with varying dynamic attributes, you'll need a way to choose among them during retrieval. One option is to record information about the items in another way. For example, if you keep records of users in a Core Data model, you store the username there after using keychain services to store the password field. Later, you use the user name pulled from your data model to condition the search for the password.

In other cases, it may make sense to further characterize the item by adding more attributes. For example, you might include the kSecAttrLabelattribute in the original add query, providing a string that marks the item for the particular purpose. Then you'll be able to use this attribute to narrow your search later.

为了以后能够找到该项目,您将使用您对其属性的了解。在此示例中,服务器和帐户是项目的区别特征。对于常量属性(这里是服务器),在查找期间使用相同的值。相反,帐户属性是动态的,因为它保存了用户在运行时提供的值。只要您的应用程序从不添加具有不同属性的类似项目(例如同一服务器上不同帐户的密码),您就可以省略这些动态属性作为搜索参数,而是将它们与项目一起检索。结果,当你查找密码时,你也得到了相应的用户名。

如果您的应用确实添加了具有不同动态属性的项目,您将需要一种在检索期间从中进行选择的方法。一种选择是以另一种方式记录有关项目的信息。例如,如果您在 Core Data 模型中保存用户记录,则在使用钥匙串服务存储密码字段后将用户名存储在那里。稍后,您使用从数据模型中提取的用户名来确定密码搜索的条件。

在其他情况下,通过添加更多属性来进一步表征项目可能是有意义的。例如,您可以kSecAttrLabel在原始添加查询中包含属性,提供一个字符串来标记特定用途的项目。然后,您可以稍后使用此属性来缩小搜索范围。

Item of class kSecClassInternetPasswordwas used in the example, but there is a note that says:

kSecClassInternetPassword示例中使用了类的项目,但有一条注释说:

Keychain services also offers the related kSecClassGenericPassword item class. Generic passwords are similar in most respects to Internet passwords, but they lack certain attributes specific to remote access (for example, they don't have a kSecAttrServer attribute). When you don't need these extra attributes, use a generic password instead.

钥匙串服务还提供相关的 kSecClassGenericPassword 项目类。通用密码在大多数方面与 Internet 密码相似,但它们缺少特定于远程访问的某些属性(例如,它们没有 kSecAttrServer 属性)。当您不需要这些额外属性时,请改用通用密码。