Como posso fazer com que o apache solicite um certificado SSL de cliente sem precisar verificar com uma CA conhecida?

9

Estou usando o apache2 (2.2.3) para servir um site em que gostaria de ter clientes autenticados com certificados. Como só preciso verificar se um usuário que apresenta um certificado específico é o mesmo usuário que apresentou esse certificado no passado, a CA que assina o certificado é irrelevante. Parece, no entanto, que o uso SSLVerifyClient requireexige SSLCACertificateFile ...(ou SSLCACertificatePath ...) e o apache aceita apenas certificados assinados por uma CA nesse arquivo / caminho. Existe uma maneira de o apache aceitar qualquer certificado de cliente, independentemente da CA de emissão / canto? (ou seja, verifique se o cliente possui a chave privada correspondente à chave pública apresentada, mas não se preocupe em verificar a CA de emissão / assinatura)

Isaac
fonte
Como você planeja rastrear quais certificados foram autenticados?
21712 Shane Madden
@ShaneMadden: Algo como uma tabela de mapeamento de certificados para IDs de usuários internos. A mecânica da criptografia de chave pública substituiria a troca de senhas.
21412 Isaac
2
Certo - o que estou dizendo é que o Apache não faz certificados de mapeamento de tabela para IDs de usuário internos. Se você deseja que os usuários se autentiquem com certificados de cliente, por que não dar aos usuários os certificados que você assina? Como você mencionou, existem provedores OpenID que fazem exatamente isso. O Apache mod_sslfoi projetado para autenticar usuários com base em um relacionamento de assinatura de certificado; se você preferir desconsiderar isso por algum motivo, precisará implementar a autenticação de certificado em seu próprio código, que também trata do mapeamento de certificado para usuário.
21712 Shane Madden
@ShaneMadden: Eu esperava evitar a emissão de certificados e, se eu aceitar apenas os certificados emitidos, os certificados baseados em cartões inteligentes serão lançados. Não importa o que eu faça, uma parte do sistema ocorrerá no nível do aplicativo, mas como há todo o mod_sslmaquinário lá, eu esperava que ele pudesse cuidar de parte do trabalho para mim.
Isaac
1
@ShaneMadden Uma vantagem optional_no_caé que pode ser melhor para a interface do usuário, pois você pode exibir uma mensagem de erro HTTP se algo estiver errado com o certificado (você não poderia, caso contrário, uma certificação de cliente ruim interromperia a conexão antes da camada HTTP ) Também é útil se você quiser tentar maneiras alternativas de verificar um certificado (por exemplo, WebID ). Você está certo de que deseja algo para fazer a verificação, e isso só funcionaria realmente quando a solicitação for tratada por código (por exemplo, dentro de PHP / CGI / Java), não tanto com arquivos.
22412 Bruno

Respostas:

10

Como você descobriu, é possível desativar a verificação do certificado no nível do handshake SSL / TLS no Apache Httpd usando SSLVerifyCLient optional_no_ca.

O segundo problema que você vai enfrentar com o que está tentando fazer é fazer com que o cliente envie o certificado. Como o seu certificado não se destina a estar dentro de uma PKI, ele pode ser autoassinado e ter vários emissores.

Ao solicitar um certificado de cliente, o servidor envia uma CertificateRequestmensagem TLS ao cliente durante o handhsake. Esta mensagem contém a certificate_authoritieslista:

Uma lista dos nomes distintos das autoridades de certificação aceitáveis. Esses nomes distintos podem especificar um nome distinto desejado para uma autoridade de certificação raiz ou para uma autoridade de certificação subordinada; portanto, essa mensagem pode ser usada para descrever as raízes conhecidas e um espaço de autorização desejado. Se a lista certificate_authorities estiver vazia, o cliente PODE enviar qualquer certificado do ClientCertificateType apropriado, a menos que haja algum acordo externo em contrário.

Os navegadores usam isso para escolher qual certificado de cliente enviar (se houver).

(Observe que a parte sobre a lista vazia está apenas na especificação do TLS 1.1 em diante. O SSL 3.0 e o TLS 1.0 são omissos e, na prática, também funcionará.)

Você tem duas opções para isso.

  • Se os certificados de cliente que você espera serão autoassinados, todos terão emissores diferentes. Como você não sabe o que esperar, o servidor precisará enviar uma lista vazia. Para fazer isso, use a SSLCADNRequestFilediretiva e aponte-a para um arquivo que contenha apenas uma linha vazia (se bem me lembro, ela não funciona com um arquivo completamente vazio).

  • A segunda opção (menos limpa). É concordar com um DN de emissor comum a todos os certificados de cliente que você espera, independentemente de eles terem sido realmente emitidos por esse certificado de CA (ou se essa CA existe ou não). Ao fazer isso, você quebraria o modelo de PKI consideravelmente (mais).

    Se você concorda com um DN do emissor como CN=Dummy CA(por exemplo). Qualquer pessoa pode criar um certificado autoassinado usando CN=Dummy CAcomo DN do Assunto (e DN do emissor), possivelmente com chaves diferentes. Embora a SSLCADNRequestFilediretiva espere ser configurada com certificados para criar a lista, eles não são usados ​​para verificar o certificado do cliente, é apenas uma maneira complicada (mas natural no contexto das outras diretivas) de configurar a certificate_authoritieslista. Se você, como serviço, colocar um certificado autoassinado com esses nomes SSLCADNRequestFile, isso fará com que a CertificateRequestmensagem TLS seja usada CN=Dummy CAna certificate_authoritieslista (estes são apenas nomes, não certs neste estágio). O cliente poderá então pegar seu próprio certificado com o DN do emissorCN=Dummy CA, se sua assinatura pode ou não ser verificada por esse certificado (mesmas chaves) ou não, pois nenhuma verificação de assinatura está envolvida nessas etapas.

Dito isto, lembre-se de que SSLVerifyCLient optional_no_ca, com , nenhuma verificação real do certificado é feita (suponho que você possa verificar a SSL_CLIENT_VERIFYvariável se a verificação manual for apenas uma solução de fallback para uma PKI que você configurou de qualquer maneira). Tudo o que você saberá nesse estágio é que o cliente possui a chave privada para o certificado de chave pública que ele apresentou (garantido pela CertificateVerifymensagem TLS ): você precisará executar alguma forma de verificação se desejar que haja autenticação de alguns ordenar. (Você não pode confiar em nenhum conteúdo do certificado, que é uma ligação entre sua chave pública e os nomes / atributos que ela contém.)

Isso não funcionará bem para arquivos, mas você pode fazer isso para um aplicativo (por exemplo, PHP / CGI / ... até Java, se você passar o certificado para o servidor Java em proxy). Uma maneira básica seria ter uma lista pré-conhecida de chaves públicas, ou você poderia examinar as idéias em FOAF + SSL / WebID .

Bruno
fonte
2

Usar SSLVerifyCLient optional_no_ca(em vez de require) faz com que o apache não verifique a CA de emissão (e, portanto, não precisa de um arquivo ou caminho de certificado de CA). Ele permite que o cliente / usuário não envie um certificado, portanto, a verificação de que um certificado foi usado deve ser feita separadamente.

(Aparentemente, não consegui ler completamente a mod_ssldocumentação.)

Isaac
fonte