Що робить елемент брелока унікальним (в 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)

Після довгого прочитання документації щодо яблук, блогів та записів на форумах я виявив, що елемент типу брелока 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, див. Схеми.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перевірку Keychain також , якщо запис ( value) вже зберігається. Це не дозволяє два рази додавати один і той же сертифікат або ключ. Також якщо ви вказали інший kSecAttrApplicationTagдля ключа (який повинен бути унікальним щодо публікації вище), він не вдасться.
Кріс

1
Це може допомогти мислити kSecClassатрибут як ім'я таблиці , а вказані вище значення як просто primary keyвідповідність таблиці.
bobobobo

2
Що таке семантика kSecAttrAccountта kSecAttrService? - чи може програміст вибрати будь-яку семантику, яку вона вирішить?
wcochran

1
kSecAttrServiceпризначено для зберігання послуги, kSecAttrAccountце для збереження імені рахунку. Ви можете зберігати в них різні речі, але це може заплутатись.
Таммо Фрізе

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
  • Для елементів ідентичності, які є сертифікатом та приватним ключем, зв'язані разом, первинні ключі такі ж, як і для сертифіката. Оскільки приватний ключ може бути сертифікований не один раз, унікальність сертифіката визначає особу.

Хоча це посилання може відповісти на питання, краще включити сюди суттєві частини відповіді та надати посилання для довідки. Відповіді лише на посилання можуть стати недійсними, якщо пов’язана сторінка зміниться. - З огляду
pwc

погодилися, хоча в цьому випадку це означало копіювання всього посилання.
Julian Król

0

Ось ще один фрагмент корисної інформації про унікальність предмета брелока, який можна знайти в розділі "Забезпечити пошук" на цій сторінці документів Apple .

Щоб пізніше знайти предмет, ви будете використовувати свої знання про його атрибути. У цьому прикладі відмінною характеристикою елемента є сервер та обліковий запис. Для постійних атрибутів (тут, сервер) використовуйте те саме значення під час пошуку. На відміну від цього, атрибут облікового запису є динамічним, оскільки він містить значення, надане користувачем під час виконання. Поки ваша програма ніколи не додає подібні елементи з різними атрибутами (наприклад, паролі для різних облікових записів на одному сервері), ви можете опустити ці динамічні атрибути як параметри пошуку і замість цього отримати їх разом із елементом. Як результат, під час пошуку пароля ви також отримуєте відповідне ім’я користувача.

Якщо ваш додаток додає елементи з різними динамічними атрибутами, вам знадобиться спосіб вибору серед них під час пошуку. Один варіант - записати інформацію про предмети іншим способом. Наприклад, якщо ви зберігаєте записи користувачів у моделі Core Data, ви зберігаєте там ім’я користувача, використовуючи служби брелоків для зберігання поля пароля. Пізніше ви використовуєте ім'я користувача, витягнуте з вашої моделі даних, щоб обумовити пошук пароля.

В інших випадках може бути доцільним подальша характеристика елемента, додавши більше атрибутів. Наприклад, ви можете включити kSecAttrLabelатрибут у вихідний запит на додавання, надаючи рядок, який позначає елемент для певної мети. Тоді ви зможете скористатися цим атрибутом, щоб згодом звузити пошук.

Елемент класу kSecClassInternetPasswordбув використаний у прикладі, але є примітка, яка говорить:

Служби брелоків також пропонують відповідний клас елементів kSecClassGenericPassword. Загальні паролі багато в чому схожі з паролями в Інтернеті, але їм не вистачає певних атрибутів, характерних для віддаленого доступу (наприклад, вони не мають атрибута kSecAttrServer). Коли вам не потрібні ці додаткові атрибути, використовуйте натомість загальний пароль.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.