Что делает элемент цепочки для ключей уникальным (в iOS)?
Мой вопрос касается брелков в iOS (iPhone, iPad, ...). Я думаю (но не уверен), что реализация цепочек для ключей в Mac OS X поднимает тот же вопрос с тем же ответом.
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
, kSecAttrAccount
а также kSecAttrService
,
Если эти три атрибута в запросе 1 такие же, как и в запросе 2, вы получаете один и тот же элемент связки ключей общего пароля независимо от любых других атрибутов. Если один (или два, или все) из этого атрибута изменяет свое значение, то вы получаете разные предметы.
Но kSecAttrService
доступно только для предметов типа kSecClassGenericPassword
таким образом, он не может быть частью "уникального ключа" элемента любого другого типа, и, похоже, нет документации, которая четко указала бы, какие атрибуты однозначно определяют элемент цепочки для ключей.
Пример кода в классе "KeychainItemWrapper" из "GenericKeychain" использует атрибут kSecAttrGeneric
сделать предмет уникальным, но это ошибка. Две записи только в этом примере хранятся как две разные записи, потому что их kSecAttrAccessGroup
отличается (один имеет группу доступа установлен, другой позволяет его освободить). Если вы попытаетесь добавить второй пароль без группы доступа, используя Apple KeychainItemWrapper
, ты потерпишь неудачу.
Поэтому, пожалуйста, ответьте на мои вопросы:
- Правда ли, что комбинация
kSecAttrAccessGroup
,kSecAttrAccount
а такжеkSecAttrService
является "уникальным ключом" элемента цепочки для ключей, kSecClass которогоkSecClassGenericPassword
? - Какие атрибуты делают элемент цепочки для ключей уникальным, если его
kSecClass
не являетсяkSecClassGenericPassword
?
3 ответа
Основными являются следующие ключи (полученные из файлов с открытым исходным кодом от 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
Я не нашел информации о полях первичного ключа в файлах с открытым исходным кодом, но, поскольку идентичность представляет собой комбинацию личного ключа и сертификата, я предполагаю, что первичный ключ является комбинацией полей первичного ключа дляkSecClassKey
а такжеkSecClassCertificate
,
Поскольку каждый элемент цепочки для ключей относится к группе доступа цепочки для ключей, он ощущается как группа доступа цепочки для ключей (поле kSecAttrAccessGroup
) является добавленным полем для всех этих первичных ключей.
На днях я столкнулся с ошибкой (на iOS 7.1), которая связана с этим вопросом. Я использовал SecItemCopyMatching
читать kSecClassGenericPassword
пункт, и он продолжал возвращаться errSecItemNotFound
(-25300) хотя kSecAttrAccessGroup
, kSecAttrAccount
а также kSecAttrService
все соответствовали элементу в цепочке для ключей.
В конце концов я понял, что 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.
- Для элементов идентификации, которые представляют собой сертификат и закрытый ключ, связанные вместе, первичные ключи такие же, как и для сертификата. Поскольку закрытый ключ может быть сертифицирован более одного раза, уникальность сертификата определяет его идентичность.
Вот еще одна полезная информация об уникальности элемента связки ключей, которую можно найти в разделе "Обеспечение возможности поиска" на этой странице документации Apple.
Чтобы иметь возможность найти этот предмет позже, вы собираетесь использовать свои знания о его атрибутах. В этом примере отличительными характеристиками товара являются сервер и учетная запись. Для постоянных атрибутов (здесь сервер) используйте то же значение во время поиска. Напротив, атрибут учетной записи является динамическим, потому что он содержит значение, предоставленное пользователем во время выполнения. Если ваше приложение никогда не добавляет аналогичные элементы с разными атрибутами (например, пароли для разных учетных записей на одном сервере), вы можете опустить эти динамические атрибуты в качестве параметров поиска и вместо этого получать их вместе с элементом. В результате, когда вы ищите пароль, вы также получаете соответствующее имя пользователя.
Если ваше приложение добавляет элементы с различными динамическими атрибутами, вам понадобится способ выбора среди них во время извлечения. Один из вариантов - записать информацию об элементах другим способом. Например, если вы ведете учет пользователей в модели Core Data, вы сохраняете там имя пользователя после использования служб связки ключей для хранения поля пароля. Позже вы используете имя пользователя, полученное из вашей модели данных, чтобы обусловить поиск пароля.
В других случаях может иметь смысл дополнительно охарактеризовать элемент, добавив дополнительные атрибуты. Например, вы можете включить
kSecAttrLabel
в исходном запросе на добавление, предоставляя строку, которая отмечает элемент для конкретной цели. Затем вы сможете использовать этот атрибут, чтобы сузить область поиска позже.
Предмет класса kSecClassInternetPassword
был использован в примере, но есть примечание, в котором говорится:
Службы связки ключей также предлагают связанный класс элементов kSecClassGenericPassword. Общие пароли во многом аналогичны паролям в Интернете, но у них отсутствуют определенные атрибуты, характерные для удаленного доступа (например, у них нет атрибута kSecAttrServer). Если вам не нужны эти дополнительные атрибуты, используйте общий пароль.