是什么使钥匙串物品与众不同(在iOS中)?


104

我的问题涉及iOS(iPhone,iPad等)中的钥匙串。我认为(但不确定)在Mac OS X下实施钥匙串会引起同样的问题,且答案相同。


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)

看完苹果的文档,博客和论坛条目的很长一段时间,我发现这种类型的钥匙串项目kSecClassGenericPassword从属性得到它的独特性kSecAttrAccessGroupkSecAttrAccountkSecAttrService

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

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

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

所以,请回答我的问题:

  • 这是真的,那的组合kSecAttrAccessGroupkSecAttrAccount并且kSecAttrService是一个钥匙串项目,其kSecClass是“唯一钥匙” kSecClassGenericPassword
  • 哪些属性可使钥匙串项与众不同(如果kSecClass不是)kSecClassGenericPassword

1
这里有一个博客条目
bobobobo

Answers:


179

主键如下所示(从Apple的开源文件派生,请参阅Schema.m4KeySchema.m4SecItem.cpp):

  • 对于类的钥匙串项目kSecClassGenericPassword,主键是的组合 kSecAttrAccountkSecAttrService
  • 对于类的钥匙串项目kSecClassInternetPassword,主键是的组合kSecAttrAccountkSecAttrSecurityDomainkSecAttrServerkSecAttrProtocolkSecAttrAuthenticationTypekSecAttrPortkSecAttrPath
  • 对于类的钥匙串项目kSecClassCertificate,主键是的组合kSecAttrCertificateTypekSecAttrIssuerkSecAttrSerialNumber
  • 对于类的钥匙串项目kSecClassKey,主键是的组合kSecAttrApplicationLabelkSecAttrApplicationTagkSecAttrKeyTypekSecAttrKeySizeInBitskSecAttrEffectiveKeySize,和创建者,开始其不被暴露SecItem还日期和结束日期。
  • 对于类的钥匙串项目,kSecClassIdentity我没有在开源文件的主键字段中找到信息,但是由于身份是私钥和证书的组合,因此我认为主键是主键的组合kSecClassKey和的字段kSecClassCertificate

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


听起来是一个很好的答案!谢谢!我会检查一下,我想等一两天以征询其他用户的其他意见,但是您是赏金+50分的热门人选。
休伯特·舍尔纳斯特(HubertSchölnast)2012年

3
好答案!我花了几天的时间来为证书和私钥实现通用的Keychain包装器。这与仅存储字符串凭证(用户名/密码)的Apple示例代码有很大不同。但是,我发现,当您将设置kSecClasskSecClassCertificate或时kSecClassKey,钥匙串还会检查条目(value)是否已经存储。这样可以防止两次添加相同的证书或密钥。同样,如果您kSecAttrApplicationTag为键指定了一个不同的键(对于上面的帖子,它必须是唯一的),它将失败。
克里斯(Chris)

1
kSecClass属性视为表名,将上面指定的值视为primary key相应表的,可能会有所帮助。
bobobobo

2
kSecAttrAccount和的语义是kSecAttrService什么?-还是程序员可以选择自己决定的任何语义?
wcochran 2014年

1
kSecAttrService用于存储服务,kSecAttrAccount用于存储帐户名。您可以在其中存储不同的内容,但这可能会造成混淆。
Tammo Freese 2014年

9

前几天(iOS 7.1),我遇到了一个与此问题相关的错误。我在用SecItemCopyMatching在阅读一个kSecClassGenericPassword项目,errSecItemNotFound即使,它也始终返回(-25300)kSecAttrAccessGroupkSecAttrAccount并且kSecAttrService都与钥匙串中的该项目匹配。

最终我发现那kSecAttrAccessible不匹配。钥匙串中的值保存为pdmn = dk(kSecAttrAccessibleAlways),但我正在使用kSecAttrAccessibleWhenUnlocked

当然,首先不需要此值 SecItemCopyMatching,但OSStatus不是(-25300)errSecParam也不errSecBadReqerrSecItemNotFound,这使得查找它有些棘手。

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

我希望此注释可以为你们中的一些人节省宝贵的调试时间。


4

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

苹果文档中提到了每种机密的主键(在下面引用):

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

  • 对于通用密码,主键包括kSecAttrAccount和kSecAttrService。
  • 对于Internet密码,主键包括kSecAttrAccount,kSecAttrSecurityDomain,kSecAttrServer,kSecAttrProtocol,kSecAttrAuthenticationType,kSecAttrPort和kSecAttrPath。
  • 对于证书,主键包括kSecAttrCertificateType,kSecAttrIssuer和kSecAttrSerialNumber。
  • 对于关键项,主键包括kSecAttrKeyClass,kSecAttrKeyType,kSecAttrApplicationLabel,kSecAttrApplicationTag,kSecAttrKeySizeInBits和kSecAttrEffectiveKeySize。
  • 对于身份项目,即证书和私钥捆绑在一起,其主密钥与证书相同。由于可以对私钥进行多次验证,因此证书的唯一性决定了身份的唯一性。

尽管此链接可以回答问题,但最好在此处包括答案的基本部分,并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会无效。- 来自评论
pwc '18

同意,尽管在这种情况下,这意味着复制整个链接。
朱利安·克罗尔(JulianKról)'18年

0

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

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

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

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

kSecClassInternetPassword在示例中使用了class项,但是有一条注释指出:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.