web-dev-qa-db-ja.com

キーチェーンアイテムを一意にする理由(iOSで)

私の質問は、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のキーチェーン項目は、属性kSecAttrAccessGroupkSecAttrAccount、およびkSecAttrServiceからその一意性を取得することがわかりました。

リクエスト1のこれら3つの属性がリクエスト2と同じ場合、他の属性に関係なく、同じ汎用パスワードキーチェーンアイテムを受け取ります。この属性の1つ(または2つまたはすべて)が値を変更すると、異なるアイテムが取得されます。

ただし、kSecAttrServicekSecClassGenericPasswordタイプのアイテムでのみ使用できるため、他のタイプのアイテムの「一意のキー」の一部にすることはできません。また、キーチェーンアイテムを一意に決定する属性を明確に示すドキュメントはないようです。

「GenericKeychain」のクラス「KeychainItemWrapper」のサンプルコードは、属性kSecAttrGenericを使用してアイテムを一意にしますが、これはバグです。この例の2つのエントリは、kSecAttrAccessGroupが異なるため、2つの異なるエントリとしてのみ格納されます(一方はアクセスグループが設定され、もう一方は解放されます)。 AppleのKeychainItemWrapperを使用して、アクセスグループなしで2番目のパスワードを追加しようとすると、失敗します。

だから、私の質問に答えてください:

  • kSecAttrAccessGroupkSecAttrAccount、およびkSecAttrServiceの組み合わせが、kSecClassがkSecClassGenericPasswordであるキーチェーン項目の「固有キー」であることは本当ですか?
  • kSecClasskSecClassGenericPasswordではない場合、どの属性がキーチェーンアイテムを一意にしますか?
92

主キーは次のとおりです(Appleのオープンソースファイルから派生、 Schema.m4KeySchema.m4 および SecItem.cpp を参照):

  • クラスkSecClassGenericPasswordのキーチェーンアイテムの場合、主キーはkSecAttrAccountkSecAttrServiceの組み合わせです。
  • クラスkSecClassInternetPasswordのキーチェーン項目の場合、主キーはkSecAttrAccountkSecAttrSecurityDomainkSecAttrServerkSecAttrProtocolkSecAttrAuthenticationTypekSecAttrPortおよびkSecAttrPath
  • クラスkSecClassCertificateのキーチェーンアイテムの場合、主キーはkSecAttrCertificateTypekSecAttrIssuerおよびkSecAttrSerialNumberの組み合わせです。
  • クラスkSecClassKeyのキーチェーン項目の場合、主キーはkSecAttrApplicationLabelkSecAttrApplicationTagkSecAttrKeyTypekSecAttrKeySizeInBitskSecAttrEffectiveKeySize、および作成者、開始日と終了日。これらはまだSecItemによって公開されていません。
  • クラスkSecClassIdentityのキーチェーンアイテムの場合、オープンソースファイルのプライマリキーフィールドに関する情報は見つかりませんでしたが、IDはプライベートキーと証明書の組み合わせであるため、プライマリキーはkSecClassKeyおよびkSecClassCertificateの主キーフィールドの組み合わせ。

各キーチェーンアイテムはキーチェーンアクセスグループに属しているため、キーチェーンアクセスグループ(フィールドkSecAttrAccessGroup)はこれらすべてのプライマリキーに追加されたフィールドのように感じられます。

156
Tammo Freese

先日(iOS 7.1で)この質問に関連するバグを見つけました。 SecItemCopyMatchingアイテムを読み取るためにkSecClassGenericPasswordを使用しており、errSecItemNotFoundkSecAttrAccessGroup、およびkSecAttrAccountがあったにもかかわらず、kSecAttrService(-25300)を返し続けました。キーチェーン内のアイテムに一致するすべて。

最終的に、kSecAttrAccessibleが一致しないことがわかりました。キーチェーンの値はpdmn = dk(kSecAttrAccessibleAlways)を保持していましたが、kSecAttrAccessibleWhenUnlockedを使用していました。

もちろん、この値はSecItemCopyMatchingの最初の場所では必要ありませんが、OSStatuserrSecParamでもerrSecBadReqではなく、errSecItemNotFound(-25300)だけでした見つけるのが少し難しくなりました。

SecItemUpdateについては同じ問題が発生しましたが、このメソッドではkSecAttrAccessibleパラメーターで同じqueryを使用しても機能しませんでした。この属性を完全に削除するだけで修正されました。

このコメントがあなたの一部にとって貴重なデバッグの時間をほとんど節約しないことを願っています。

8
izik lisbon

@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の一意性が決まります。
2
Julian Król