Perfil de VPN no iOS: passwordReference, não a senha
Uma referência do chaveiro é um cabo, não o segredo. Passar bytes explica o erro -50, a falha após reiniciar e a armadilha da rotação nos perfis de VPN salvos.
Você instala um perfil, o túnel sobe e tudo parece pronto. Então o telefone reinicia, o on-demand desperta a conexão sem nenhum app em primeiro plano, e o túnel se recusa a iniciar. O perfil continua lá e a senha continua correta, e é por isso que essa falha manda as pessoas procurarem no lugar errado. Uma Network Extension não consegue ler seu segredo do perfil: ela precisa de uma referência do chaveiro que possa resolver sozinha.
O passo a passo abaixo acompanha uma única tentativa de conexão por essa entrega, da consulta que constrói a referência ao reinício que a testa.
O perfil guarda um cabo, não o segredo
O NEVPNProtocol expõe passwordReference e sharedSecretReference por um motivo. Quando o daemon inicia um túnel, ele pode não estar rodando dentro do seu processo, então não pode chamar seu código e pedir uma senha. Ele lê uma referência persistente do chaveiro, resolve no próprio contexto e busca o item sozinho.
Você constrói essa referência pedindo-a ao chaveiro, o que é uma requisição diferente da requisição dos dados:
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
]Entregue o objeto retornado ao protocolo, não os dados do item. Na prática o perfil registra onde o segredo mora, e por isso um backup da configuração não duplica a senha silenciosamente em um plist.
Por que a API responde -50
errSecParam significa que a requisição ou o valor estava malformado para a operação, e é o erro mais visto quando as requisições de referência e de dados se misturam. Pedir dados enquanto o código receptor espera uma referência, atribuir bytes crus a passwordReference ou consultar com um grupo de acesso que o app não pode usar, todos o produzem.
Bibliotecas de invólucro convidam a isso. Um auxiliar que devolve bytes não é intercambiável com um que devolve uma referência, então o conserto costuma ser outra consulta, não outra senha.
A mesma divergência explica um perfil que é salvo sem queixa e depois não conecta: o que foi guardado é um blob, não um cabo, e o daemon não tem nada para resolver.
Salva bem, falha na conexão
Salvar exercita o contexto do seu app. Conectar exercita o do daemon, e os dois não têm o mesmo acesso. Por isso um perfil pode passar em todos os testes do simulador e falhar na primeira inicialização on-demand.
Essa é também a forma do sintoma do reinício: funciona enquanto o app está aberto e morre quando o sistema inicia o túnel sozinho.
Teste o caminho em segundo plano de propósito antes de publicar. Dispare uma conexão on-demand com o app fechado e depois leia o console do dispositivo, não o log do app, porque a falha é registrada pelo processo que tentou resolver a referência. Se o console mostra o daemon rejeitando o item, a referência está boa e o problema é a acessibilidade do item.
A acessibilidade decide se um reinício funciona
O item precisa ser legível pelo processo do sistema que inicia o túnel, e isso é um público mais amplo que o seu app em primeiro plano. Essa restrição escolhe o atributo de acessibilidade por você. Um item protegido até o primeiro desbloqueio fica disponível para uma inicialização em segundo plano depois que o dispositivo é desbloqueado uma vez; um item que exige o dispositivo desbloqueado agora não fica.
Escolher a classe mais estrita é tentador e é exatamente o que quebra um perfil on-demand em um telefone bloqueado.
Depois de mudar a classe, recrie o item em vez de editar atributos no existente, e salve o protocolo novamente com uma referência nova. Mudanças de atributo em um item existente nem sempre produzem o comportamento que a documentação sugere, e um item reconstruído elimina a dúvida.
A rotação é onde os perfis salvos apodrecem
Trocar a senha no chaveiro não muda automaticamente aquilo a que o perfil salvo aponta. Apagar o item é pior: o perfil mantém uma referência a algo que não existe mais, e a falha parece uma rejeição de autenticação.
Faça a rotação em uma única ordem. Atualize o item, consulte uma nova referência persistente, salve o protocolo outra vez e então conecte com o app fechado para provar que o daemon ainda consegue resolvê-la. Mantenha a senha do usuário e o segredo compartilhado em itens separados para que cada um rotacione no seu próprio calendário, e nunca registre o dicionário da consulta nem a própria referência. O cabo não é um segredo, mas é um mapa até um.