Wednesday, November 23, 2011

Autenticação com Certificados Digitais em Java (Portuguese)

Como autenticar usuários na Internet usando Java e certificados digitais.

Tutorial mostrando como fazer conexão segura de uma aplicação Web feita em Java com autenticação usando  certificados digitais. Como certificado digital será utilizado e-CPF/e-CNPJ emitidos pela estrutura de chaves públicas ICP-Brasil. Como servidor usaremos o Tomcat. O certificado do servidor será auto assinado.


Configurar o servidor


Usando a ferramenta Keytool, crie uma chave privada RSA para o servidor:

# keytool -genkey -alias tomcat -keyalg RSA

Informe os parâmetros que o keytool pedirá para criar o certificado. Será necessário informar uma senha. Nesse tutorial sempre será usado a palavra 'password'.


Depois, auto assine o certificado criado:

# keytool -selfcert -alias tomcat
Liste seu certificado criado executando o comando:
# keytool -list


Agora abra o arquivo de configuração, no Tomcat é o server.xml. Configure um Connector para usar SSL e requisitar certificados digitais da máquina cliente:

<Service name="Catalina">
  ...
  <Connector acceptCount="100" connectionTimeout="20000"
    executor="tomcatThreadPool" maxKeepAliveRequests="15" port="8080"
    protocol="HTTP/1.1" redirectPort="8443" />
  <Connector port="8443" maxThreads="200"
    scheme="https" secure="true" SSLEnabled="true"
    keystoreFile="${user.home}/.keystore" keystorePass="password"
    clientAuth="true" sslProtocol="TLS"/>
  ...
</Service>


O parâmetro
clientAuth é o que faz o SSL requisitar certificados digitais. Conforme mostra na documentação do Tomcat, esse valor pode ser true, false ou want.


Passo dois: Instalar as autoridades CA (Certificate Authorities) confiáveis:


Instalar no key store utilizado pelo Tomcat as autoridades confiáveis. Para isso, baixe os arquivos das ACs no repositório da autoridade raiz brasileira.
Execute o comando no shell:

# keytool -import -keystore $JAVA_HOME/jre/lib/security/cacerts -file certificadoDaAc.cer -alias NOME_DA_CA
A senha padrão desse repositório é changeit.

Após importar os certificados, se fizer:

# keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts

Será listado os certificados confiáveis de autoridades instalados.


Passo três: Ler o certificado digital da sessão


Instale seu certificado digital no navegador e teste iniciando o Tomcat e abrindo a página https://localhost:8443. Se você tiver um certificado digital emitido por alguma autoridade confiável cadastrada no keystore do Java, irá aparecer uma janela para que você escolha o certificado digital e digite sua senha.
Note que se você não tiver instalado no navegador nenhum certificado digital válido, ou se tiver instalado algum vencido, ou de uma autoridade certificado não cadastrada, a página nem irá abrir.

Se tudo estiver correto e você visualizar a página, sua aplicação web já poderá ler os dados desse certificado digital após estabelecer a sessão.

Em Java, isso pode ser feito da seguinte maneira:

public class LerCertificado extends HttpServlet {
  protected void doGet(HttpServletRequest request,
      HttpServletResponse response)
throws ServletException, IOException {
    PrintWriter out = response.getWriter();
    out.println(
"<html>");
    out.println(
"<head><title>ServletLerCertificado</title></head>");
    out.println(
"<body>");
    out.println(
"<p>Certificado digital:</p>");

   
//
    String cipherSuite = (String) request
        .getAttribute(
"javax.servlet.request.cipher_suite");

   
if (cipherSuite != null) {
      java.security.cert.X509Certificate certChain[] = (java.security.cert.X509Certificate[]) request
          .getAttribute(
"javax.servlet.request.X509Certificate");
      System.out.println(
"Array size: " + certChain.length);
     
if (certChain != null) {
       
for (int i = 0; i < certChain.length; i++) {
          String certInfo =
"Client Certificate [" + i + "] = "
              + certChain[i].toString();
         
          out.println(certInfo);
        }
      }
    }
else {
      out.println(
"Cliente sem Certificado Digital");
    }

   
//
    out.println(
"</body></html>");
    out.close();
  }


Uma vez lido o certificado digital da sessão, tem-se acesso ao CPF ou CNPJ do dono do certificado, podendo assim utilizá-lo para validação na autenticação do usuário no sistema.  

Projeto de exemplo no GitHub: 



Para facilitar a leitura dos dados certificado digital, foi utilizado a biblioteca Boncy Castle.


Leitoras de Smart Card


Para ler o certificado digital do e-CPF/e-CNPJ, ou outro smart card qualquer, o processo é o mesmo. A diferença é que não é necessário instalar certificados digitais no navegador, basta instalar o driver de sua leitora de smart card, que caso forneça um certificado válido, irá abrir a mesma tela no browser pedindo que você escolha o certificado que irá usar para estabelecer a conexão.


Conclusão


Certificados digitais são maneiras muito seguras e confiáveis de trafegar dados na Web. Facilmente pode ser configurado nas aplicações. O SSL cuida de todo o resto.


Veja também





References

  1. Cristiano Andrade Blog. Acessado em 30 de julho de 2010.
    http://cristianosandrade.blogspot.com/2010/03/extrair-dados-de-um-certificado-icp.html

7 comments:

  1. Cara, eu fiz tudo certinho, mas no passo 3 quando digito http://localhost:8443, recebo o erro: "Erro 324 (net::ERR_EMPTY_RESPONSE): O servidor encerrou a conexão sem enviar os dados"... Alguma idéia do que pode ter acontecido?

    ReplyDelete
    Replies
    1. Sugiro criar um projeto web normal e fazer funcionar. Depois adicionar a segurança. Não sei o que pode ter ocasionado esse erro.

      Delete
  2. Parabéns pelo post. Eu estava procurando uma direção sobre como implementar autenticação com certificados digitais. Me ajudou bastante.

    ReplyDelete
  3. Cara, não estou conseguindo baixar seu projeto de exemplo no tal de minus.
    Tem ele hospedado em outro lugar?

    Obrigado!

    ReplyDelete
    Replies
    1. O minus.com realmente está com problemas. Obrigado por avisar.
      Eu alterei o post apontando para o caminho do projeto de exemplo no GitHub.

      https://github.com/edpichler/Digital_Certificates_with_SSL_on_Tomcat

      Delete
  4. Olá estou com problemas para implementar no passo 3

    Erro:

    type Status report

    message /LerCertificado/servlet/main.java.br.com.mycompany.LerCertificado

    description The requested resource is not available.

    Poderia me dar uma direciontamento?

    Grato,

    ReplyDelete