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.

Artigos relacionados