什么使钥匙串项目独特(在iOS中)?

我的问题涉及iOS(iPhone,iPad,…)中的钥匙链。 我认为(但不是很确定)在Mac OS X下实现钥匙链引发了同样的问题。


iOS提供了五种types的钥匙串项目。 您必须为密钥kSecClassselect这五个值中的kSecClass来确定types:

 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) 

经过长时间阅读苹果文档,博客和论坛条目,我发现kSecClassGenericPasswordtypes的钥匙串项目从属性kSecAttrAccessGroupkSecAttrAccountkSecAttrService获得其唯一性。

如果请求1中的这三个属性与请求2中的相同,那么无论其他属性如何,您都会收到相同的通用密码钥匙串项目。 如果一个(或两个或全部)这个属性改变了它的值,那么你会得到不同的项目。

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

“GenericKeychain”类的“KeychainItemWrapper”中的示例代码使用属性kSecAttrGeneric使项目具有唯一性,但这是一个错误。 这个例子中的两个条目仅被存储为两个不同的条目,因为它们的kSecAttrAccessGroup是不同的(一个访问组已设置,另一个允许它自由)。 如果您尝试使用Apple的KeychainItemWrapper添加没有访问组的第二个密码,则会失败。

所以,请回答我的问题:

  • 是真的, kSecAttrAccessGroupkSecAttrAccountkSecAttrService的组合是kSecClass是kSecClassGenericPassword的keychain项目的“唯一键”吗?
  • 如果kSecClass不是kSecClassGenericPassword哪些属性使钥匙串项唯一?

主键如下(从Apple的开源文件派生而来,请参阅Schema.m4 , KeySchema.m4和SecItem.cpp ):

  • 对于kSecClassGenericPassword类的钥匙串项目,主键是kSecAttrAccountkSecAttrService的组合。
  • 对于类kSecClassInternetPassword的keychain项,主键是kSecAttrAccountkSecAttrSecurityDomainkSecAttrServerkSecAttrProtocolkSecAttrAuthenticationTypekSecAttrPortkSecAttrPath
  • 对于类kSecClassCertificate的keychain项,主键是kSecAttrCertificateTypekSecAttrIssuerkSecAttrSerialNumber的组合。
  • 对于类kSecClassKey的keychain项,主键是kSecAttrApplicationLabelkSecAttrApplicationTagkSecAttrKeyTypekSecAttrKeySizeInBitskSecAttrEffectiveKeySizekSecAttrEffectiveKeySize未公开的创build者,开始date和结束date的组合。
  • 对于kSecClassIdentity类的keychain项目,我没有find关于开源文件中的主键字段的信息,但是作为一个身份是一个私钥和一个证书的组合,我假设主键是主kSecClassKeykSecClassCertificate关键字段。

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

我在前一天(在iOS 7.1上)发现了一个与这个问题有关的bug。 我正在使用SecItemCopyMatching来读取一个kSecClassGenericPassword项目,并且它仍然返回errSecItemNotFound (-25300),即使kSecAttrAccessGroupkSecAttrAccountkSecAttrService都是匹配钥匙串中的项目。

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

当然, SecItemCopyMatching首先不需要这个值,但是OSStatus不是errSecParam也不是errSecBadReq而是errSecItemNotFound (-25300),这使得它有点棘手。

对于SecItemUpdate我遇到了同样的问题,但是在这种方法中,即使在query参数中使用相同的kSecAttrAccessible也不起作用。 只有彻底删除这个属性才能修复它。

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