Что делает объект связки ключей уникальным (в iOS)?
Мой вопрос касается брелоков в iOS (iPhone, iPad,...). Я думаю (но не уверен), что реализация keychains под Mac OS X ставит один и тот же вопрос с тем же ответом.
iOS предоставляет пять типов (классов) элементов keychain. Вы должны выбрать одно из этих пяти значений для ключа 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)
После долгого времени чтения документации яблок, блогов и записей в форуме я узнал, что элемент keychain типа kSecClassGenericPassword
получает свою уникальность от атрибутов kSecAttrAccessGroup
, kSecAttrAccount
и kSecAttrService
.
Если эти три атрибута в запросе 1 те же, что и в запросе 2, вы получаете тот же общий ключевой элемент пароля, независимо от каких-либо других атрибутов. Если один (или два или все) из этих атрибутов изменяет свое значение, вы получаете разные элементы.
Но kSecAttrService
доступен только для элементов типа kSecClassGenericPassword
, поэтому он не может быть частью "уникального ключа" элемента любого другого типа, и, похоже, нет документации, которая четко указывает который атрибуты однозначно определяют элемент keychain.
Пример кода в классе "KeychainItemWrapper" из "GenericKeychain" использует атрибут kSecAttrGeneric
, чтобы сделать элемент уникальным, но это ошибка. Две записи в этом примере сохраняются только как две разные записи, потому что их kSecAttrAccessGroup
отличается (у одного есть группа групп доступа, а другая освобождается). Если вы попытаетесь добавить второй пароль без группы доступа, используя Apple KeychainItemWrapper
, вы потерпите неудачу.
Итак, пожалуйста, ответьте на мои вопросы:
- Правда ли, что комбинация
kSecAttrAccessGroup
, kSecAttrAccount
и kSecAttrService
является "уникальным ключом" элемента keychain, kSecClass которого kSecClassGenericPassword
?
- Какие атрибуты делают элемент keychain уникальным, если его
kSecClass
не kSecClassGenericPassword
?
Ответы
Ответ 1
Первичные ключи следующие (полученные из файлов с открытым исходным кодом из Apple, см. Schema.m4, KeySchema.m4 и SecItem.cpp):
- Для элемента keychain класса
kSecClassGenericPassword
первичный ключ представляет собой комбинацию
kSecAttrAccount
и kSecAttrService
.
- Для элемента keychain класса
kSecClassInternetPassword
первичный ключ представляет собой комбинацию kSecAttrAccount
, kSecAttrSecurityDomain
, kSecAttrServer
, kSecAttrProtocol
, kSecAttrAuthenticationType
, kSecAttrPort
и kSecAttrPath
.
- Для элемента keychain класса
kSecClassCertificate
первичный ключ представляет собой комбинацию kSecAttrCertificateType
, kSecAttrIssuer
и kSecAttrSerialNumber
.
- Для элемента keychain класса
kSecClassKey
первичный ключ представляет собой комбинацию kSecAttrApplicationLabel
, kSecAttrApplicationTag
, kSecAttrKeyType
,
kSecAttrKeySizeInBits
, kSecAttrEffectiveKeySize
, и создатель, дата начала и дата окончания, которые еще не открываются SecItem.
- Для элемента keychain класса
kSecClassIdentity
я не нашел информацию о полях первичного ключа в файлах с открытым исходным кодом, но поскольку идентификатор представляет собой комбинацию закрытого ключа и сертификата, я предполагаю, что первичный ключ комбинация полей первичного ключа для kSecClassKey
и kSecClassCertificate
.
Поскольку каждый элемент keychain принадлежит группе доступа к цепочке ключей, похоже, что группа доступа к keychain (поле kSecAttrAccessGroup
) является добавленным полем ко всем этим основным ключам.
Ответ 2
Я наткнулся на ошибку на днях (на iOS 7.1), которая связана с этим вопросом. Я использовал SecItemCopyMatching
для чтения элемента kSecClassGenericPassword
, и он продолжал возвращать errSecItemNotFound
(-25300), хотя kSecAttrAccessGroup
, kSecAttrAccount
и kSecAttrService
все соответствовали элементу в цепочке ключей.
В конце концов я понял, что kSecAttrAccessible
не соответствует. Значение в цепочке ключей содержало pdmn = dk (kSecAttrAccessibleAlways
), но я использовал kSecAttrAccessibleWhenUnlocked
.
Конечно, это значение не требуется в первую очередь для SecItemCopyMatching
, но OSStatus
не было errSecParam
и errSecBadReq
, а просто errSecItemNotFound
(-25300), что сделало его несколько сложным, чтобы найти.
Для SecItemUpdate
у меня возникла одна и та же проблема, но в этом методе даже с использованием того же kSecAttrAccessible
в параметре query
не работает. Исправлено только полное удаление этого атрибута.
Я надеюсь, что этот комментарий спасет несколько важных отладочных моментов для некоторых из вас.