Что делает брелок уникальным (в iOS)?


104

Мой вопрос касается брелков в 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)

После долгого чтения документации Apple, блогов и записей на форумах, я обнаружил, что элемент цепочки для ключей kSecClassGenericPasswordполучает свою уникальность от атрибутов kSecAttrAccessGroup, kSecAttrAccountи kSecAttrService.

Если эти три атрибута в запросе 1 такие же, как в запросе 2, то вы получите тот же элемент цепочки ключей общего пароля, независимо от любых других атрибутов. Если один (два или все) из этих атрибутов изменяет свое значение, вы получаете разные элементы.

Но kSecAttrServiceон доступен только для элементов типа kSecClassGenericPassword, поэтому он не может быть частью «уникального ключа» элемента любого другого типа, и, похоже, нет документации, которая четко указывает, какие атрибуты однозначно определяют элемент цепочки для ключей.

Пример кода в классе «KeychainItemWrapper» из «GenericKeychain» использует атрибут, kSecAttrGenericчтобы сделать элемент уникальным, но это ошибка. Только две записи в этом примере хранятся как две отдельные записи, потому что они kSecAttrAccessGroupразные (одна имеет группу доступа, другая позволяет освободить). Если вы попытаетесь добавить второй пароль без группы доступа, используя Apple KeychainItemWrapper, у вас ничего не получится.

Итак, ответьте, пожалуйста, на мои вопросы:

  • Верно ли, что сочетание kSecAttrAccessGroup, kSecAttrAccountи kSecAttrServiceэто «уникальный ключ» из брелка элемента которого kSecClass это kSecClassGenericPassword?
  • Какие атрибуты делают элемент цепочки для ключей уникальным, если kSecClassэто не так kSecClassGenericPassword?

1
Об этом есть запись в блоге .
bobobobo

Ответы:


179

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


Похоже, действительно хороший ответ! Спасибо! Я проверю это и хочу подождать один или два дня дополнительных комментариев от других пользователей, но вы - горячий кандидат на +50 баллов от награды.
Hubert Schölnast

3
Отличный ответ! Я работаю в течение нескольких дней над реализацией общей оболочки Keychain для сертификатов и закрытых ключей. Это сильно отличается от примера кода Apple, в котором хранятся только строковые учетные данные (имя пользователя / пароль). Однако я обнаружил, что, когда вы устанавливаете kSecClassзначение kSecClassCertificateили, kSecClassKeyСвязка ключей также проверяет, сохранена ли уже запись ( value). Это предотвращает добавление одного и того же сертификата или ключа дважды. Также, если вы укажете другой kSecAttrApplicationTagключ (который должен быть уникальным, как указано в сообщении выше), это не сработает.
Крис

1
Это может помочь думать об kSecClassатрибуте как об имени таблицы , а указанные выше значения - как об атрибуте primary keyсоответствующей таблицы.
bobobobo

2
Что такое семантика kSecAttrAccountи kSecAttrService? - или может программист выбрать любую семантику, которую он решит?
wcochran

1
kSecAttrServiceдля хранения службы, kSecAttrAccountдля хранения имени учетной записи. В них можно хранить разные вещи, но это может запутать.
Tammo Freese

9

На днях я обнаружил ошибку (в iOS 7.1), связанную с этим вопросом. Я использовалSecItemCopyMatching , чтобы прочитать kSecClassGenericPasswordэлемент , и он постоянно возвращался errSecItemNotFound(-25300) , хотя kSecAttrAccessGroup, kSecAttrAccountи kSecAttrServiceбыли все соответствующие пункт в связке ключей.

В конце концов я понял, что kSecAttrAccessibleэто не соответствует. Значение в связке ключей содержало pdmn = dk ( kSecAttrAccessibleAlways), но я использовал kSecAttrAccessibleWhenUnlocked.

Конечно, это значение в первую очередь не нужно для SecItemCopyMatching , но OSStatusне было errSecParamни errSecBadReqа просто errSecItemNotFound(-25300) , который сделал это немного сложно найти.

Потому SecItemUpdateчто у меня возникла та же проблема, но в этом методе даже использование того же параметра kSecAttrAccessibleв queryпараметре не сработало. Только полное удаление этого атрибута исправило его.

Я надеюсь, что этот комментарий сэкономит несколько драгоценных моментов отладки для некоторых из вас.


4

Ответ @Tammo Freese кажется правильным (но без упоминания всех первичных ключей). Я искал доказательства в документации. Наконец-то нашел:

Документация Apple, в которой указаны первичные ключи для каждого класса секретов (цитата ниже):

Система считает элемент дубликатом данной цепочки для ключей, если в этой цепочке для ключей уже есть элемент того же класса с тем же набором составных первичных ключей. Каждый класс элемента цепочки для ключей имеет разный набор первичных ключей, хотя несколько атрибутов используются совместно для всех классов. В частности, где это применимо, kSecAttrSynchronizable и kSecAttrAccessGroup являются частью набора первичных ключей . Дополнительные первичные ключи для каждого класса перечислены ниже:

  • Для общих паролей первичные ключи включают kSecAttrAccount и kSecAttrService.
  • Для интернет-паролей первичные ключи включают kSecAttrAccount, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrProtocol, kSecAttrAuthenticationType, kSecAttrPort и kSecAttrPath.
  • Для сертификатов первичные ключи включают kSecAttrCertificateType, kSecAttrIssuer и kSecAttrSerialNumber.
  • Для ключевых элементов первичные ключи включают kSecAttrKeyClass, kSecAttrKeyType, kSecAttrApplicationLabel, kSecAttrApplicationTag, kSecAttrKeySizeInBits и kSecAttrEffectiveKeySize.
  • Для элементов идентификации, которые представляют собой вместе сертификат и закрытый ключ, первичные ключи такие же, как и для сертификата. Поскольку закрытый ключ может быть сертифицирован более одного раза, уникальность сертификата определяет идентичность.

Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если ссылка на страницу изменится. - Из
отзыва

согласился, хотя в данном случае это означало копирование всей ссылки.
Julian Król

0

Вот еще одна полезная информация об уникальности элемента связки ключей, которую можно найти в разделе «Обеспечение возможности поиска» на этой странице документации Apple .

Чтобы иметь возможность найти этот предмет позже, вы собираетесь использовать свои знания о его атрибутах. В этом примере отличительными характеристиками товара являются сервер и учетная запись. Для постоянных атрибутов (здесь сервер) используйте то же значение во время поиска. Напротив, атрибут учетной записи является динамическим, потому что он содержит значение, предоставленное пользователем во время выполнения. Если ваше приложение никогда не добавляет аналогичные элементы с разными атрибутами (например, пароли для разных учетных записей на одном сервере), вы можете опустить эти динамические атрибуты в качестве параметров поиска и вместо этого получать их вместе с элементом. В результате, когда вы ищите пароль, вы также получаете соответствующее имя пользователя.

Если ваше приложение добавляет элементы с различными динамическими атрибутами, вам понадобится способ выбора среди них во время извлечения. Один из вариантов - записать информацию об элементах другим способом. Например, если вы ведете учет пользователей в модели Core Data, вы сохраняете там имя пользователя после использования служб связки ключей для хранения поля пароля. Позже вы используете имя пользователя, полученное из вашей модели данных, чтобы обусловить поиск пароля.

В других случаях может иметь смысл дополнительно охарактеризовать элемент, добавив дополнительные атрибуты. Например, вы можете включить kSecAttrLabelатрибут в исходный запрос добавления, предоставив строку, которая помечает элемент для конкретной цели. Затем вы сможете использовать этот атрибут, чтобы сузить область поиска позже.

В kSecClassInternetPasswordпримере использовался элемент класса , но есть примечание, в котором говорится:

Службы связки ключей также предлагают связанный класс элементов kSecClassGenericPassword. Общие пароли во многом похожи на пароли в Интернете, но им не хватает определенных атрибутов, специфичных для удаленного доступа (например, у них нет атрибута kSecAttrServer). Если вам не нужны эти дополнительные атрибуты, используйте общий пароль.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.