Что делает элемент цепочки для ключей уникальным (в 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). Если вам не нужны эти дополнительные атрибуты, используйте общий пароль.

Другие вопросы по тегам