Depois de muitos testes com a classe SSLPoke, acabei sacando o problema que vinha enfrentando. O mau "bad_certificate"
public class SSLPoke {
public static void main(String[] args) {
// System.setProperty("javax.net.ssl.keyStoreType", "PKCS12");
// System.setProperty("javax.net.ssl.keyStore", "caminhoCertificadoCliente");
// System.setProperty("javax.net.ssl.keyStorePassword", "senha");
System.setProperty("javax.net.ssl.trustStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStore", "certificadosTrustStore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
String host = "homologacao.nfe2.fazenda.pr.gov.br";
host = "nfe2.fazenda.pr.gov.br";
int port = 443;
try {
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(host, port);
sslsocket.startHandshake();
InputStream in = sslsocket.getInputStream();
OutputStream out = sslsocket.getOutputStream();
// Write a test byte to get a reaction :)
out.write(1);
while (in.available() > 0) {
System.out.print(in.read());
}
System.out.println("Successfully connected");
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
Percebi que comentando as linhas que adicionam o keyStore nas propriedades do sistema, acontece a exceção:
javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1822)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1004)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1571)
Descomentando, a conexão é realizada com sucesso.
Chegando a concluir que o cliente gerado está considerando apenas o trustStore configurado. Por esse motivo o certificado do cliente não é enviado ao servidor da receita, causando a exceção no momento do "aperto de mãos" entre o cliente e o servidor.
Novamente, comecei a googlar sobre como configurar o keystore e trustStore no proxy criado.
Acabei encontrando um post no StackOverflow (http://stackoverflow.com/questions/8403949/apache-cxf-client-issue-with-calling-ssl-service) que me clareou a ideia e levantou outra duvida, tenho que setar isso no proxy mesmo ? E a definição das propriedades, foram ignoradas ? Tanto faz agora =).
Onde quero destacar o comentário retirado do post:
You develop a simple test CXF client which does mutual HTTPS connection, there is a very nice sample project available from cxf-samples that does exactly what you need: http://svn.apache.org/repos/asf/cxf/tags/cxf-2.4.4/distribution/src/main/release/samples/wsdl_first_https/
Através desse projeto exemplo, conseguir encontrar um fonte que configura o ketStore e o trustStore no proxy de seu cliente.
public static void setupTLS(Object port)
throws FileNotFoundException, IOException, GeneralSecurityException {
HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(port).getConduit();
TLSClientParameters tlsCP = new TLSClientParameters();
String keyPassword = "changeit";
KeyStore keyStore = KeyStore.getInstance("PKCS12");
String keyStoreLoc = "caminhoCertificadoCliente.pfx";
keyStore.load(new FileInputStream(keyStoreLoc), "senhaCertificadoCliente".toCharArray());
KeyManager[] myKeyManagers = getKeyManagers(keyStore, keyPassword);
tlsCP.setKeyManagers(myKeyManagers);
KeyStore trustStore = KeyStore.getInstance("JKS");
String trustStoreLoc = "caminhoDoTruststore";
trustStore.load(new FileInputStream(trustStoreLoc), keyPassword);
TrustManager[] myTrustStoreKeyManagers = getTrustManagers(trustStore);
tlsCP.setTrustManagers(myTrustStoreKeyManagers);
//The following is not recommended and would not be done in a prodcution environment,
//this is just for illustrative purpose
tlsCP.setDisableCNCheck(true);
httpConduit.setTlsClientParameters(tlsCP);
}
private static TrustManager[] getTrustManagers(KeyStore trustStore)
throws NoSuchAlgorithmException, KeyStoreException {
String alg = KeyManagerFactory.getDefaultAlgorithm();
TrustManagerFactory fac = TrustManagerFactory.getInstance(alg);
fac.init(trustStore);
return fac.getTrustManagers();
}
private static KeyManager[] getKeyManagers(KeyStore keyStore, String keyPassword)
throws GeneralSecurityException, IOException {
String alg = KeyManagerFactory.getDefaultAlgorithm();
char[] keyPass = keyPassword != null
? keyPassword.toCharArray()
: null;
KeyManagerFactory fac = KeyManagerFactory.getInstance(alg);
fac.init(keyStore, keyPass);
return fac.getKeyManagers();
}
Com o fonte acima, após criar o proxy, utilizo o metodo setupTLS() para configurar essa questão dos certificados.
setupTLS(port);
Sobre a gestão do trustStore, para o funcionamento é indiferente se foi criado dinamicamente ou importado na mão via keytool.
Outro ponto que quero comentar, criei o cliente usando JAX-WS, devido a facilidade para passar os headers da mensagem SOAP e não ter que adicionar bibliotecas adicionais no projeto.
Encontrei a dica para isso aqui no GUJ mesmo, através do post http://www.guj.com.br/java/206765-webservices-soap-12-headerresolvido/2
Obrigado a todos que leram ou responderam o post.
Concerveja, terei mais duvidas sobre isso =D.
Abraço