Ви встановлюєте профіль, тунель піднімається, і все виглядає завершеним. Потім телефон перезавантажується, on-demand будить з’єднання без застосунку на передньому плані, і тунель відмовляється запускатися. Профіль досі на місці, пароль досі правильний, і саме тому цей збій відправляє людей шукати не там. Network Extension не може прочитати ваш секрет із профілю: йому потрібне посилання на зв’язку ключів, яке він здатен розв’язати сам.

Розбір нижче простежує одну спробу з’єднання крізь цю передачу — від запиту, що будує посилання, до перезавантаження, яке його перевіряє.

Профіль зберігає дескриптор, а не секрет

NEVPNProtocol відкриває passwordReference і sharedSecretReference недарма. Коли демон запускає тунель, він може працювати не всередині вашого процесу, тож не може викликати ваш код і попросити пароль. Він читає постійне посилання на зв’язку ключів, розв’язує його у власному контексті й сам дістає елемент.

Ви будуєте це посилання, запитуючи його у зв’язки ключів; це інший запит, ніж запит даних:

let query: [String: Any] = [
  kSecClass as String: kSecClassGenericPassword,
  kSecAttrService as String: "vpn-credentials",
  kSecAttrAccount as String: "user",
  kSecReturnPersistentRef as String: true,
  kSecMatchLimit as String: kSecMatchLimitOne
]

Передайте протоколу повернутий об’єкт, а не дані елемента. На практиці профіль записує, де живе секрет, тому резервна копія конфігурації не копіює пароль мовчки в plist.

Чому API відповідає -50

errSecParam означає, що запит або значення були неправильно сформовані для операції, і це помилка, яку найчастіше бачать, коли запити посилання й даних плутаються. Запит даних, коли код-одержувач очікує посилання, присвоєння сирих байтів полю passwordReference або запит із групою доступу, яку застосунок не може використати, — усе це її породжує.

Обгорткові бібліотеки до цього спонукають. Помічник, що повертає байти, не взаємозамінний із тим, що повертає посилання, тому виправлення зазвичай полягає в іншому запиті, а не в іншому паролі.

Та сама невідповідність пояснює профіль, який зберігається без скарг, а потім не підключається: збережено блоб, а не дескриптор, і демонові нема чого розв’язувати.

Зберігається добре, падає під час підключення

Збереження задіює контекст вашого застосунку. Підключення задіює контекст демона, і доступ у них не однаковий. Тож профіль може пройти всі тести в симуляторі й упасти на першому запуску on-demand.

Така сама форма симптома після перезавантаження: працює, поки застосунок відкритий, і вмирає, коли система запускає тунель сама.

Перевірте фоновий шлях навмисно перед випуском. Викличте on-demand з’єднання із закритим застосунком, а потім читайте консоль пристрою, а не журнал застосунку, бо збій записує процес, який намагався розв’язати посилання. Якщо консоль показує, що демон відхиляє елемент, посилання гаразд, а проблема в доступності елемента.

Доступність вирішує, чи спрацює перезавантаження

Елемент має бути читабельним для будь-якого системного процесу, що запускає тунель, а це ширша авдиторія, ніж ваш застосунок на передньому плані. Це обмеження саме обирає атрибут доступності. Елемент, захищений до першого розблокування, доступний для фонового запуску після того, як пристрій розблокували один раз; елемент, що вимагає розблокованого пристрою просто зараз, — ні.

Обрати суворіший клас спокусливо, і саме це ламає on-demand профіль на заблокованому телефоні.

Після зміни класу створіть елемент заново, а не редагуйте атрибути наявного, потім збережіть протокол із новим посиланням. Зміни атрибутів наявного елемента не завжди дають поведінку, яку передбачає документація, а перестворений елемент знімає сумнів.

Ротація — це місце, де гниють збережені профілі

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

Ротуйте в одному порядку. Оновіть елемент, запитайте нове постійне посилання, збережіть протокол знову, а потім підключіться із закритим застосунком, щоб довести, що демон досі може його розв’язати. Тримайте пароль користувача й спільний секрет в окремих елементах, щоб кожен ротувався за власним графіком, і ніколи не логуйте словник запиту чи саме посилання. Дескриптор не секрет, але це мапа до нього.

Схожі статті