Perfil de VPN en iOS: passwordReference, non o contrasinal
Unha referencia do chaveiro é unha asa, non o segredo. Pasar bytes explica o erro -50, o fallo ao reiniciar e a trampa de rotación nos perfís de VPN gardados.
Instalas un perfil, o túnel érguense e todo parece rematado. Despois o teléfono reiníciase, on-demand esperta a conexión sen ningunha app en primeiro plano e o túnel négase a arrincar. O perfil segue aí e o contrasinal segue sendo correcto, e por iso este fallo manda á xente buscar no lugar equivocado. Unha Network Extension non pode ler o teu segredo do perfil: necesita unha referencia do chaveiro que poida resolver por si mesma.
O percorrido de abaixo segue un só intento de conexión por esa entrega, desde a consulta que constrúe a referencia ata o reinicio que a pon a proba.
O perfil garda unha asa, non o segredo
NEVPNProtocol expón passwordReference e sharedSecretReference por un motivo. Cando o demonio inicia un túnel pode que non se execute dentro do teu proceso, así que non pode chamar o teu código e pedir un contrasinal. Le unha referencia persistente do chaveiro, resólvea no seu propio contexto e obtén o elemento el mesmo.
Constrúes esa referencia pedíndolla ao chaveiro, que é unha petición distinta de pedir os datos:
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
]Entrega o obxecto devolto ao protocolo, non os datos do elemento. Na práctica o perfil rexistra onde vive o segredo, e por iso unha copia de seguridade da configuración non duplica o contrasinal en silencio dentro dun plist.
Por que a API responde -50
errSecParam significa que a petición ou o valor estaban mal formados para a operación, e é o erro que máis se ve cando se mesturan as peticións de referencia e de datos. Pedir datos mentres o código receptor agarda unha referencia, asignar bytes en bruto a passwordReference ou consultar cun grupo de acceso que a app non pode usar, todos o producen.
As bibliotecas envoltorio invitan a isto. Un axudante que devolve bytes non é intercambiable cun que devolve unha referencia, así que a reparación adoita ser outra consulta e non outro contrasinal.
A mesma desavinza explica un perfil que se garda sen queixa e despois non conecta: o que se gardou é un blob, non unha asa, e o demonio non ten nada que resolver.
Garda ben, falla ao conectar
Gardar exercita o contexto da túa app. Conectar exercita o do demonio, e os dous non teñen o mesmo acceso. Por iso un perfil pode pasar todas as probas do simulador e fallar no primeiro arrinque on-demand.
Esa é tamén a forma do síntoma do reinicio: funciona mentres a app está aberta e morre cando o sistema inicia o túnel pola súa conta.
Proba o camiño en segundo plano a propósito antes de publicar. Dispara unha conexión on-demand coa app pechada e despois le a consola do dispositivo en lugar do log da app, porque o fallo rexístrao o proceso que intentou resolver a referencia. Se a consola mostra que o demonio rexeita o elemento, a referencia está ben e o problema é a accesibilidade do elemento.
A accesibilidade decide se un reinicio funciona
O elemento ten que ser lexible polo proceso do sistema que arrinque o túnel, e iso é un público máis amplo que a túa app mentres está en primeiro plano. Esa restrición escolle o atributo de accesibilidade por ti. Un elemento protexido ata o primeiro desbloqueo está dispoñible para un arrinque en segundo plano despois de que o dispositivo se desbloquease unha vez; un elemento que esixe que o dispositivo estea desbloqueado agora mesmo non o está.
Escoller a clase máis estrita é tentador e é exactamente o que rompe un perfil on-demand nun teléfono bloqueado.
Despois de cambiar a clase, recrea o elemento en lugar de editar atributos no existente, e volve gardar o protocolo cunha referencia nova. Os cambios de atributos nun elemento existente non sempre producen o comportamento que implica a documentación, e un elemento reconstruído elimina a dúbida.
A rotación é onde se podrecen os perfís gardados
Cambiar o contrasinal no chaveiro non cambia automaticamente aquilo a que apunta o perfil gardado. Borrar o elemento é peor: o perfil conserva unha referencia a algo que xa non existe, e o fallo parece un rexeitamento de autenticación.
Rota nunha soa orde. Actualiza o elemento, consulta unha referencia persistente nova, volve gardar o protocolo e despois conecta coa app pechada para demostrar que o demonio aínda pode resolvela. Mantén o contrasinal do usuario e o segredo compartido en elementos separados para que cada un rote segundo o seu propio calendario, e non rexistres nunca o dicionario da consulta nin a referencia mesma. A asa non é un segredo, pero é un mapa cara a un.