私の質問は、iOS(iPhone、iPadなど)のキーチェーンに関するものです。 Mac OS Xでのキーチェーンの実装は、同じ答えで同じ質問を提起すると思います(しかし確信はありません)。
iOSは、5種類(クラス)のキーチェーンアイテムを提供します。タイプを決定するには、キーkSecClass
にこれらの5つの値のいずれかを選択する必要があります。
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
、kSecAttrAccount
、およびkSecAttrService
からその一意性を取得することがわかりました。
リクエスト1のこれら3つの属性がリクエスト2と同じ場合、他の属性に関係なく、同じ汎用パスワードキーチェーンアイテムを受け取ります。この属性の1つ(または2つまたはすべて)が値を変更すると、異なるアイテムが取得されます。
ただし、kSecAttrService
はkSecClassGenericPassword
タイプのアイテムでのみ使用できるため、他のタイプのアイテムの「一意のキー」の一部にすることはできません。また、キーチェーンアイテムを一意に決定する属性を明確に示すドキュメントはないようです。
「GenericKeychain」のクラス「KeychainItemWrapper」のサンプルコードは、属性kSecAttrGeneric
を使用してアイテムを一意にしますが、これはバグです。この例の2つのエントリは、kSecAttrAccessGroup
が異なるため、2つの異なるエントリとしてのみ格納されます(一方はアクセスグループが設定され、もう一方は解放されます)。 AppleのKeychainItemWrapper
を使用して、アクセスグループなしで2番目のパスワードを追加しようとすると、失敗します。
だから、私の質問に答えてください:
kSecAttrAccessGroup
、kSecAttrAccount
、およびkSecAttrService
の組み合わせが、kSecClassがkSecClassGenericPassword
であるキーチェーン項目の「固有キー」であることは本当ですか?kSecClass
がkSecClassGenericPassword
ではない場合、どの属性がキーチェーンアイテムを一意にしますか?主キーは次のとおりです(Appleのオープンソースファイルから派生、 Schema.m4 、 KeySchema.m4 および SecItem.cpp を参照):
kSecClassGenericPassword
のキーチェーンアイテムの場合、主キーはkSecAttrAccount
とkSecAttrService
の組み合わせです。kSecClassInternetPassword
のキーチェーン項目の場合、主キーはkSecAttrAccount
、kSecAttrSecurityDomain
、kSecAttrServer
、kSecAttrProtocol
、kSecAttrAuthenticationType
、kSecAttrPort
およびkSecAttrPath
。kSecClassCertificate
のキーチェーンアイテムの場合、主キーはkSecAttrCertificateType
、kSecAttrIssuer
およびkSecAttrSerialNumber
の組み合わせです。kSecClassKey
のキーチェーン項目の場合、主キーはkSecAttrApplicationLabel
、kSecAttrApplicationTag
、kSecAttrKeyType
、kSecAttrKeySizeInBits
、kSecAttrEffectiveKeySize
、および作成者、開始日と終了日。これらはまだSecItemによって公開されていません。kSecClassIdentity
のキーチェーンアイテムの場合、オープンソースファイルのプライマリキーフィールドに関する情報は見つかりませんでしたが、IDはプライベートキーと証明書の組み合わせであるため、プライマリキーはkSecClassKey
およびkSecClassCertificate
の主キーフィールドの組み合わせ。各キーチェーンアイテムはキーチェーンアクセスグループに属しているため、キーチェーンアクセスグループ(フィールドkSecAttrAccessGroup
)はこれらすべてのプライマリキーに追加されたフィールドのように感じられます。
先日(iOS 7.1で)この質問に関連するバグを見つけました。 SecItemCopyMatching
アイテムを読み取るためにkSecClassGenericPassword
を使用しており、errSecItemNotFound
、kSecAttrAccessGroup
、およびkSecAttrAccount
があったにもかかわらず、kSecAttrService
(-25300)を返し続けました。キーチェーン内のアイテムに一致するすべて。
最終的に、kSecAttrAccessible
が一致しないことがわかりました。キーチェーンの値はpdmn = dk(kSecAttrAccessibleAlways
)を保持していましたが、kSecAttrAccessibleWhenUnlocked
を使用していました。
もちろん、この値はSecItemCopyMatching
の最初の場所では必要ありませんが、OSStatus
はerrSecParam
でもerrSecBadReq
ではなく、errSecItemNotFound
(-25300)だけでした見つけるのが少し難しくなりました。
SecItemUpdate
については同じ問題が発生しましたが、このメソッドではkSecAttrAccessible
パラメーターで同じquery
を使用しても機能しませんでした。この属性を完全に削除するだけで修正されました。
このコメントがあなたの一部にとって貴重なデバッグの時間をほとんど節約しないことを願っています。
@Tammo Freeseの回答は正しいようです(ただし、すべての主キーについては言及していません)。私はドキュメントでいくつかの証拠を探していました。ついに見つけた:
シークレットの各クラスのプライマリキーについて言及しているAppleドキュメント(下記引用):
システムは、そのキーチェーンに同じクラスの複合主キーのセットを持つアイテムがすでにある場合、そのキーチェーンのアイテムは重複していると見なします。キーチェーンアイテムの各クラスには主キーの異なるセットがありますが、いくつかの属性はすべてのクラスで共通に使用されます。特に、該当する場合、kSecAttrSynchronizableとkSecAttrAccessGroupは主キーのセットの一部です。追加のクラスごとの主キーは次のとおりです。
- 汎用パスワードの場合、主キーにはkSecAttrAccountおよびkSecAttrServiceが含まれます。
- インターネットパスワードの場合、主キーにはkSecAttrAccount、kSecAttrSecurityDomain、kSecAttrServer、kSecAttrProtocol、kSecAttrAuthenticationType、kSecAttrPort、およびkSecAttrPathが含まれます。
- 証明書の場合、主キーにはkSecAttrCertificateType、kSecAttrIssuer、およびkSecAttrSerialNumberが含まれます。
- キー項目の場合、主キーにはkSecAttrKeyClass、kSecAttrKeyType、kSecAttrApplicationLabel、kSecAttrApplicationTag、kSecAttrKeySizeInBits、およびkSecAttrEffectiveKeySizeが含まれます。
- 証明書と秘密キーが一緒にバンドルされているIDアイテムの場合、主キーは証明書の場合と同じです。秘密キーは2回以上認証されると、証明書の一意性によってIDの一意性が決まります。