Инсталирате профил, тунелът се вдига и всичко изглежда готово. После телефонът се рестартира, 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 или заявка с група за достъп, която приложението не може да използва, всички я пораждат.

Обвиващите библиотеки канят това. Помощник, който връща байтове, не е взаимозаменяем с такъв, който връща референция, затова поправката обикновено е друга заявка, а не друга парола.

Същото несъответствие обяснява профил, който се записва без оплакване и после не се свързва: запазеното е blob, не дръжка, и на демона няма какво да разреши.

Записва се добре, проваля се при свързване

Записът упражнява контекста на приложението ви. Свързването упражнява този на демона и двамата нямат еднакъв достъп. Затова профил може да мине всеки тест в симулатора и да се провали при първия on-demand старт.

Същата е формата на симптома при рестарт: работи, докато приложението е отворено, и умира, когато системата стартира тунела сама.

Тествайте фоновия път нарочно преди пускане. Задействайте on-demand връзка със затворено приложение, после четете конзолата на устройството, а не журнала на приложението, защото повредата се записва от процеса, който е опитал да разреши референцията. Ако конзолата показва, че демонът отхвърля елемента, референцията е наред и проблемът е в достъпността на елемента.

Достъпността решава дали рестартът работи

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

Изборът на по-строгия клас е изкушаващ и точно той чупи on-demand профил на заключен телефон.

След смяна на класа пресъздайте елемента, вместо да редактирате атрибути на съществуващия, после запишете протокола отново с нова референция. Промените на атрибути върху съществуващ елемент не винаги дават поведението, което документацията предполага, а пресъздаденият елемент маха съмнението.

Ротацията е мястото, където запазените профили гният

Смяната на паролата в ключодържателя не променя автоматично това, към което сочи запазеният профил. Изтриването на елемента е по-лошо: профилът пази референция към нещо, което вече не съществува, и повредата изглежда като отказ при удостоверяване.

Ротирайте в един ред. Обновете елемента, поискайте нова постоянна референция, запишете протокола отново, после се свържете със затворено приложение, за да докажете, че демонът още може да я разреши. Дръжте паролата на потребителя и споделената тайна в отделни елементи, за да се ротира всяка по свой график, и никога не логвайте речника на заявката или самата референция. Дръжката не е тайна, но е карта към такава.

Подобни статии