[RESOLVIDO] Tomcat 6 + SSL + Certificado Digital

Bom dia pessoal

Preciso construir um web service que deverá acessar o INFOCONV (web service da Receita, pra consultar CPF/CNPJ). As questões legais já estão todas resolvidas pela minha empresa, e iniciamos a fase de desenvolvimento.

O cenário é basicamente o seguinte:

Existe hoje uma aplicação em Java, em produção, que emite alguns relatórios com relação aos eleitores de uma cidade. Há um novo caso de uso que torna necessário a consulta de CPFs na Receita. Porém, há um entrave que impede que façamos essa aplicação acessar diretamente o ws da Receita. Por isso, foi solicitada a construção de um web service para intermediar a conversa entre os dois.

Para testar a conexão com o WS da Receita tenho uma aplicação bem simples, feita por um outro desenvolvedor (terceirizado, que não está mais aqui - é sempre assim…) que acessa o web service da receita e efetua corretamente uma consulta por um CPF qualquer. No programa de teste é utlizado um cliente desktop (o básico, com um método main) que se comunica com o ws da Receita da seguinte forma:

URL wsdlURL = new URL("https://infoconv.receita.fazenda.gov.br/ws/cpf/ConsultarCPF.asmx?wsdl"); QName SERVICE_NAME = new QName("https://infoconv.receita.fazenda.gov.br/ws/cpf/", "ConsultarCPF"); Service wsService = Service.create(wsdlURL, SERVICE_NAME);

Para quem não conhece (como eu), o acesso ao INFOCONV requer o uso de certificado digital. Na aplicação de teste, a configuração do certificado é feita por meio de propriedades do sistema, assim:

... System.setProperty("javax.net.ssl.keyStoreType", "pkcs12"); System.setProperty("javax.net.ssl.keyStore", keyStorePath); System.setProperty("javax.net.ssl.keyStorePassword", "senha"); ... System.setProperty("javax.net.ssl.trustStoreType", "JKS"); System.setProperty("javax.net.ssl.trustStore", trustStorePath); System.setProperty("javax.net.ssl.trustStorePassword", "senha"); ...

Sendo:

keyStorePath: String com o caminho para o arquivo *.pfx
trustStorePath: String com o caminho para o arquivo *.jks

Ambos arquivos já estavam gerados quando o projeto caiu para mim. Segundo informações que me foram dadas, o arquivo *.pfx é um certificado e-Equipamento obtido junto ao SERPRO e o arquivo *.jks foi gerado com o keytool do java.

Sou 100% newbie em cetificação digital, e a parte que estou apanhando é justamente essa. Criei um web service simples com o Apache CXF, da seguinte forma:

[code]@WebService
public interface NomeService {
public String consultaCPF (String cpfConsultar);
}

@WebService(endpointInterface = “caminho.para.a.interface.NomeService”, serviceName = “NomeService”)
public class NomeServiceImpl implements NomeService {
public String consultaCPF (String cpfConsultar){
//validacoes basicas
//Acesso ao web service da receita
}
}[/code]

Eu faço o acesso ao web service da Receita da mesma forma como na classe de teste, mostrada acima. Após isso, comecei a procurar como fazer a configuração do SSL no Tomcat 6, mas não estou entendendo exatamente como funciona.

Por exemplo, na documentação oficial, o primeiro passo descrito é criar o arquivo keystore. No meu cenário, pelo que entendi, não devo fazer esse passo, pois já possuo o arquivo keystore, que seria o meu arquivo *.jks. Procede?

O passo seguinte seria editar o server.xml, descomentando o “SSL HTTP/1.1 Connector” e acertando os valores. Tentei algo assim:

<Connector port="8443" maxThreads="200" scheme="https" secure="true" SSLEnabled="true" keystoreFile="meu_arquivo_jks" keystorePass="senha" clientAuth="false" sslProtocol="TLS"/>

No caso, coloquei no parâmetro keystoreFile o caminho para o meu arquivo *.jks. Testei iniciar o Tomcat para confirmar esta configuração, logo na inicialização ocorre o erro:

java.io.IOException: jsse.invalid_ssl_conf at org.apache.tomcat.util.net.jsse.JSSESocketFactory.checkConfig(JSSESocketFactory.java:817) at org.apache.tomcat.util.net.jsse.JSSESocketFactory.init(JSSESocketFactory.java:522) at org.apache.tomcat.util.net.jsse.JSSESocketFactory.createSocket(JSSESocketFactory.java:156) at org.apache.tomcat.util.net.JIoEndpoint.init(JIoEndpoint.java:538) at org.apache.coyote.http11.Http11Protocol.init(Http11Protocol.java:176) at org.apache.catalina.connector.Connector.initialize(Connector.java:1022) at org.apache.catalina.core.StandardService.initialize(StandardService.java:703) at org.apache.catalina.core.StandardServer.initialize(StandardServer.java:838) at org.apache.catalina.startup.Catalina.load(Catalina.java:538) at org.apache.catalina.startup.Catalina.load(Catalina.java:562) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:261) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413) Caused by: javax.net.ssl.SSLException: No available certificate or key corresponds to the SSL cipher suites which are enabled. at com.sun.net.ssl.internal.ssl.SSLServerSocketImpl.checkEnabledSuites(SSLServerSocketImpl.java:310) at com.sun.net.ssl.internal.ssl.SSLServerSocketImpl.accept(SSLServerSocketImpl.java:255) at org.apache.tomcat.util.net.jsse.JSSESocketFactory.checkConfig(JSSESocketFactory.java:813)

Achei vários artigos falando sobre este problema, mas, com o WebShepre ou o Jboss, nada no Tomcat. Fiz um teste diferente, retirando esta configuração e tentando a importação do certificado, seguindo este artigo:

Desta vez, inicio o tomcat sem erros, mas, quando vou testar a aplicação, sempre paro na exceção:

Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318) ... 72 more

Passei por alguns outros artigos enquanto googlava estas exceções, mas, vejo que o problema é conceitual meu, de não estar entendendo exatamente o que deve ser feito. :oops:

Alguém poderia me dar uma luz?

Muito obrigada!

Olá Alys,

Também não sou muito do mundo certificado digital, mas o que eu fiz aqui foi o seguinte: após criar o jks, eu alterei o server.xml[code]

<!-- HTTPS Port, active by default -->
<Connector port="${ssl.port}" protocol="HTTP/1.1" SSLEnabled="true"
           maxThreads="150" scheme="https" secure="true"
           clientAuth="false" sslProtocol="TLS"
           keystoreFile="${host.key.file}"
           keystorePass="${host.key.pass}" />[/code] Primeiro pra redirecionar pra porta ssl. Eu também coloquei valores no catalina.properties, daí chamo meu host.key.file = endereço do meu arquivo e host.key.pass = minha senha

Oi jaboot,

Muito obrigada pelo retorno.

Testei fazendo conforme seu exemplo, mas, o Tomcat só inicia sem erros quando coloco também o tipo: keystoreType=“PKCS12”, por exemplo. Feito isso, consigo iniciar o Tomcat normalmente, mas, quando tento executar o Web Service da Receita, ele dá erro por causa do certificado:

INFO: Creating Service {https://infoconv.receita.fazenda.gov.br/ws/cpf/}ConsultarCPF from WSDL: https://infoconv.receita.fazenda.gov.br/ws/cpf/ConsultarCPF.asmx?wsdl Oct 19, 2011 10:38:55 AM org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging WARNING: Interceptor for {https://infoconv.receita.fazenda.gov.br/ws/cpf/}ConsultarCPF#{https://infoconv.receita.fazenda.gov.br/ws/cpf/}ConsultarCPFP2T has thrown exception, unwinding now org.apache.cxf.interceptor.Fault: Could not send Message. at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:64) (...) Caused by: org.apache.cxf.transport.http.HTTPException: HTTP response '403: Forbidden' when communicating with https://infoconv.receita.fazenda.gov.br/ws/cpf/ConsultarCPF.asmx at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1539) at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1485) at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1393) at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56) at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:640) at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62) ... 45 more

Uma outra dúvida (de newbie, claro) me passou pela cabeça também: estava lendo este tópico no JavaRanch, sobre a diferença entre KeyStore e TrustStore; a configuração no Tomcat não deveria ser algo assim:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
	maxThreads="150" scheme="https" secure="true" clientAuth="false"
	sslProtocol="TLS" 
	keystoreFile="caminho-para-arquivo-*.pfx" keystorePass="senha" keystoreType="PKCS12" 
	truststoreFile="caminho-para-arquivo-*.jks" truststorePass="senha" truststoreType="JKS"
/>  

?

Em todo caso, mesmo fazendo desta forma, recebo o mesmo erro que indiquei acima, o 403: Forbidden :cry:

Bom dia pessoal,

Enfim, conseguimos (nosso arquiteto conseguiu, na realidade 8) ) encontrar a solução para o problema do certificado: setar as configurações pelo Apache CXF.

Deste modo, precisei alterar meu arquivo beans.xml para a forma descrita na documentação: Configuring SSL Support

Funciona, inclusive, se eu quisesse deixar todas as propriedades sendo setadas através do System.setProperty(…), só precisaria adicionar o seguinte trecho:

	<http:conduit name="https://infoconv.receita.fazenda.gov.br/.*">
		<http:tlsClientParameters
			useHttpsURLConnectionDefaultSslSocketFactory="true" />
	</http:conduit>

(Não é a opção mais correta/elegante, claro, quis só ilustrar que também funciona)

Ainda não sei explicar, contudo, porque as configurações feitas diretamente no Tomcat não funcionam; talvez tenha a ver com a forma como o CXF implementa a JAX-WS API.

Bom dia Alys,

Qual é o canal de comunicação com a receita para efetuar acesso via infoconv.

Aguardo.

Obrigado

Bom dia!

Levantando o tópico, qual o custo por consulta que vocês pagam? Quais os dados retornados?

Obrigado

Douglas