2012-07-23 61 views
80

我的問題涉及iOS中的鑰匙串(iPhone,iPad,...)。我認爲(但我不確定)在Mac OS X下實施鑰匙鏈是否會給出同樣的問題並提供相同的答案。什麼使鑰匙串項目在iOS中獨一無二?


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類型的鑰匙串項目獲取其從屬性kSecAttrAccessGroup,kSecAttrAccountkSecAttrService的唯一性。

如果請求1中的這三個屬性與請求2中的屬性相同,那麼您將收到相同的通用密碼鑰匙串項目,而不管其他屬性如何。如果這些屬性中的一個(或兩個或全部)更改其值,則會得到不同的項目。

kSecAttrService僅適用於kSecClassGenericPassword類型的項目,因此它不能是任何其他類型的項目的「唯一密鑰」的一部分,似乎有其獨特的屬性是沒有文件明確指出,確定鑰匙鏈項目。

「GenericKeychain」類「KeychainItemWrapper」中的示例代碼使用屬性kSecAttrGeneric使項目具有唯一性,但這是一個錯誤。這個例子中的兩個條目僅存儲爲兩個不同的條目,因爲它們的kSecAttrAccessGroup不同(一個訪問組已設置,另一個允許它自由)。如果您嘗試使用Apple的KeychainItemWrapper添加沒有訪問組的第二個密碼,則會失敗。

因此,請回答我的問題:

  • 這是真的,那的kSecAttrAccessGroupkSecAttrAccountkSecAttrService的組合是一個鑰匙串項目,其kSecClass爲kSecClassGenericPassword的「唯一鍵」?
  • 如果鑰匙串項目的kSecClass不是kSecClassGenericPassword,哪些屬性使鑰匙串項目具有唯一性?
+1

有關於此的[博客條目](http://useyourloaf.com/blog/2010/04/28/keychain-duplicate-item-when-adding-password.html)。 – bobobobo 2013-10-10 21:13:01

回答

134

的主鍵如下(從打開源文件衍生自蘋果,見Schema.m4KeySchema.m4SecItem.cpp):

  • 對於kSecClassGenericPassword類的鑰匙串項目,主鍵是組合 kSecAttrAccountkSecAttrService
  • 對於kSecClassInternetPassword類的鑰匙串項目,主鍵是kSecAttrAccountkSecAttrSecurityDomainkSecAttrServerkSecAttrProtocolkSecAttrAuthenticationTypekSecAttrPortkSecAttrPath組合。
  • 對於kSecClassCertificate類別的鑰匙圈項目,主鑰匙爲kSecAttrCertificateType,kSecAttrIssuerkSecAttrSerialNumber的組合。
  • 對於kSecClassKey類的鑰匙串項目,主鍵是kSecAttrApplicationLabelkSecAttrApplicationTagkSecAttrKeyTypekSecAttrKeySizeInBitskSecAttrEffectiveKeySize的組合,和創建者,開始其不被暴露SecItem還日期和結束日期。
  • 對於類kSecClassIdentity的鑰匙扣項目,我還沒有找到關於開源文件中的主鍵字段的信息,但作爲身份是私鑰和證書的組合,我假設主鍵是組合主要關鍵字段爲kSecClassKeykSecClassCertificate

由於每個鑰匙串項目屬於鑰匙串訪問組,所以感覺像鑰匙串訪問組(字段kSecAttrAccessGroup)是所有這些主鍵的添加字段。

+0

聽起來像一個非常好的答案!謝謝!我會檢查它,並且我想等待一兩天,以便從其他用戶那裏獲得額外的評論,但是您是來自賞金的+50分的熱門人選。 – 2012-07-26 16:01:52

+3

很好的回答!我工作了一段時間,爲證書和私鑰實現通用Keychain包裝器。這與Apple僅存儲字符串憑證(用戶名/密碼)的示例代碼有很大不同。然而,我發現當你將'kSecClass'設置爲'kSecClassCertificate'或'kSecClassKey'時,鑰匙串還檢查是否已經存儲了條目('value')。這可以防止添加相同的證書或密鑰兩次。此外,如果您爲某個鍵指定了不同的'kSecAttrApplicationTag'(關於上述文章,該鍵必須是唯一的),它將失敗。 – Chris 2012-07-27 08:00:20

+0

@Chris很高興知道額外支票,謝謝! – 2013-03-22 08:09:32

7

我在前一天遇到了一個與此問題相關的bug(在iOS 7.1上)。我使用SecItemCopyMatching來閱讀kSecClassGenericPassword項目,並且它始終返回errSecItemNotFound(-25300),儘管kSecAttrAccessGroup,kSecAttrAccountkSecAttrService都與鑰匙串中的項目匹配。

最終我發現kSecAttrAccessible沒有匹配。鑰匙串中的值爲pdmn = dk(kSecAttrAccessibleAlways),但我使用的是kSecAttrAccessibleWhenUnlocked

當然不需要該值在首位SecItemCopyMatching,但OSStatus不是errSecParam也不errSecBadReq只是errSecItemNotFound(-25300),這使得它有點棘手找到。

對於SecItemUpdate我遇到過同樣的問題,但在這種方法中,即使使用相同的kSecAttrAccessible中的query參數也無效。只有徹底刪除這個屬性才能修復它。

我希望這個評論能爲您省去一些寶貴的調試時間。