Nfe + transmissao + Repositorio de Certificado do Windows

8 respostas
G

Bom. . Ja estou um tempo apanhando para conseguri transmitir uma NFe (usando o respositorio de certificado do windows). Consigo obter um certificado do repositorio de certificados do windows para assinar uma nota, para validar a assinatura da nota.. eu recorri ao site da sefaz do RS que comprova que a assinatura é valida.
Também se eu uso outra forma de obter o certificado para transmitir e não tenho problema algum.

O problema aparece apenas quando tento usar um certificado obtido do Windows-MY para estabelecer uma conexao SSL java. De acordo com alguns testes, quando o certificado esta expirado ,o problema é notificado (o que comprova que ele consegue obter do certificado de repositorio).
Entretando (com as informacoes correta de senha e afins) ao tentar escrever no outputstream do socket ele da o seguinte erro:

javax.net.ssl.SSLException: Received fatal alert: internal_error

Ja busquei em alguns foruns. máximo que encontrei foi um caso antigo (2007) semelhante mas não tem um direcionamento ou resposta se foi solucionado ou nao:

http://forums.sun.com/thread.jspa?forumID=2&threadID=5170899

Como o sistema da NFe de SP também possui como opção trabalhar com o repositorio de certificado do windows, logo sei que isto é bem possível, ainda mais com o JDK 6 (ou se não pode se recorrer ao uso do capicom.dll)

Se alguem tiver algum direcionamento de como fazer uma conexão segura fazendo uso de certificado que se encontra no repositório de certificaod do windows..

Segue exemplo de teste

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;

import javax.net.ssl.SSLSocketFactory;

public class SunMSCAPITest {
	
	// Website to access
	public static final String TARGET_HTTPS_SERVER = "localhost";
	public static final int TARGET_HTTPS_PORT = 8443;

	public static void main(String[] args) throws Exception {
		
		System.setProperty("javax.net.ssl.keyStoreProvider","SunMSCAPI");
		System.setProperty("javax.net.ssl.keyStoreType","Windows-MY");
		System.setProperty("javax.net.ssl.trustStoreProvider","SunMSCAPI");
		System.setProperty("javax.net.ssl.trustStoreType","Windows-ROOT");

		Socket socket = SSLSocketFactory.getDefault().createSocket(TARGET_HTTPS_SERVER,
				TARGET_HTTPS_PORT);
		
		try {
			Writer out = new OutputStreamWriter(socket.getOutputStream(),
					"UTF-8");
			out.write("Host: " + TARGET_HTTPS_SERVER + ":" + TARGET_HTTPS_PORT
					+ "\r\n");

			out.flush();
			BufferedReader in = new BufferedReader(new InputStreamReader(socket
					.getInputStream(), "UTF-8"));
			String line = null;
			while ((line = in.readLine()) != null) {
				System.out.println(line);
			}
		} finally {
			socket.close();
		}
	}
}

8 Respostas

G
byte[] decodedBar = Base64.decode(t.exportCertificate(certificate2).getString()); // obtenho do repositorio do windows

String pwdString = Crypto.decrypt(certificado.getDescPrivatekeypass());
char[] pwd = pwdString.toCharArray();

 keyStore = KeyStore.getInstance("Windows-MY");
 ByteArrayInputStream is = new ByteArrayInputStream(decodedBar);
 keyStore.load(is, pwd);
 is.close();

 privateKey = (PrivateKey) keyStore.getKey(alias, pwd);

Quando eu pego a privakeye a uso para assinar um documento , não obtenho problema algum.
Entretanto nao consigo criar uma conexao SSL in Java usando essa privatekey =/ (quando eu a obtenho a partir do "Windows-MY".
Se eu exportar pra um keystore.jks eu consigo, o problema surge, que nem todos os certificados podem ser exportados.

Alguem nao teve algum problema parecido ou sei la..

L

Goianinho eu tb estou com esse problema, ja nao sei mais o que fazer.
Utilizando “Windows-MY” nao consigo utilizar uma conexao SSL.

Voce ja conseguiu resolver esse problema???

Abs

R

Ola estou tentando utilizar o repositorio do windows com certificado a3 e nfe
consultando o sistema da sefas de sp consegui criar este codigo onde eu acesso a url atravez do certificado do repositorio.
funcionando 100%

o problema agora eh outro
tenho um SSLSocketFactory agora como posso utilizar ele para acessar o webservice?

segue a classe e as apis etc para utilizacao

package repositorio;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.sql.SQLException;
import java.util.Enumeration;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509KeyManager;
import javax.xml.rpc.ServiceException;
import org.apache.axis.EngineConfiguration;
import com.sun.mail.iap.Protocol;
import sun.security.mscapi2.DSGEProvider;

public class Repositorio_Cert {

	private static final boolean debug = true;
    public static SSLSocketFactory factory;
    
	public static void main(String[] args) throws NoSuchProviderException, ServiceException, SQLException, ClassNotFoundException {
		//C A M I N H O
		String url = "https://homologacao.nfe.sefazvirtual.rs.gov.br/ws/nfestatusservico/NfeStatusServico.asmx";
		String keyStoreFileName = "key.jks";		
		//S E N H A CERTIFICADO
		String keyStorePassword = "SENHA DO CERTIFICADO";
		String trustStoreFileName = "key.jks";
		String trustStorePassword = "WebAS";
		//A L I A S CERTIFICADO
		String alias = "DESCRICAO ALIAS DO CERTIFICADO";
		
		try {
			// create key and trust managers
			KeyManager[] keyManagers = createKeyManagers(keyStoreFileName,keyStorePassword, alias);
			TrustManager[] trustManagers = createTrustManagers(trustStoreFileName, trustStorePassword);
			// init context with managers data			
			factory = initItAll(keyManagers, trustManagers);
			// get the url and display content
			doitAll(url, factory);
									
		} catch (KeyStoreException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (CertificateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (UnrecoverableKeyException e) {
			e.printStackTrace();
		} catch (KeyManagementException e) {
			e.printStackTrace();
		}
	}

	//TESTA A CONEXAO
	private static void doitAll(String urlString,SSLSocketFactory sslSocketFactory) throws IOException {
				 	
		URL url = new URL(urlString);
		URLConnection connection = url.openConnection();
		if (connection instanceof HttpsURLConnection) {
			((HttpsURLConnection) connection).setSSLSocketFactory(sslSocketFactory);
		}
		int x;
		while ((x = ((InputStream) connection.getContent()).read()) != -1) {
			System.out.print(new String(new byte[] { (byte) x }));
		}
	}

	private static SSLSocketFactory initItAll(KeyManager[] keyManagers,TrustManager[] trustManagers) throws NoSuchAlgorithmException,KeyManagementException {
		// SSLContext context = SSLContext.getInstance("SSLv3");
		// TODO investigate: could also be
		// "SSLContext context = SSLContext.getInstance("TLS");" Why?
		SSLContext context = SSLContext.getInstance("TLS");
		context.init(keyManagers, trustManagers, null);
		SSLSocketFactory socketFactory = context.getSocketFactory();
		return socketFactory;
	}

	private static KeyManager[] createKeyManagers(String keyStoreFileName,
			String keyStorePassword, String alias) throws CertificateException,
			IOException, KeyStoreException, NoSuchAlgorithmException,
			UnrecoverableKeyException, NoSuchProviderException {
		java.io.InputStream inputStream = new java.io.FileInputStream(keyStoreFileName);
		if (Security.getProvider("DSGEProvider") == null)
			Security.addProvider(new DSGEProvider());
		KeyStore keyStore = KeyStore.getInstance("Windows-MY", "DSGEProvider");

		keyStore.load(inputStream, keyStorePassword == null ? null : keyStorePassword.toCharArray());
		if (debug) {
			printKeystoreInfo(keyStore);
		}
		KeyManager[] managers;
		if (alias != null) {
			managers = new KeyManager[] { new Repositorio_Cert().new AliasKeyManager(
					keyStore, alias, keyStorePassword) };
		} else {		
			KeyManagerFactory keyManagerFactory = KeyManagerFactory
					.getInstance(KeyManagerFactory.getDefaultAlgorithm());
			keyManagerFactory.init(keyStore, keyStorePassword == null ? null
					: keyStorePassword.toCharArray());
			managers = keyManagerFactory.getKeyManagers();
		}
		return managers;
	}

	private static TrustManager[] createTrustManagers(
			String trustStoreFileName, String trustStorePassword)
			throws KeyStoreException, NoSuchAlgorithmException,
			CertificateException, IOException, NoSuchProviderException {

		java.io.InputStream inputStream = new java.io.FileInputStream(trustStoreFileName);
		if (Security.getProvider("DSGEProvider") == null)
			Security.addProvider(new DSGEProvider());
		KeyStore trustStore = KeyStore.getInstance("Windows-MY", "DSGEProvider");

		trustStore.load(inputStream, trustStorePassword == null ? null : trustStorePassword.toCharArray());
		if (debug) {
			printKeystoreInfo(trustStore);
		}

		TrustManagerFactory trustManagerFactory = TrustManagerFactory
				.getInstance(TrustManagerFactory.getDefaultAlgorithm());
		trustManagerFactory.init(trustStore);
		return trustManagerFactory.getTrustManagers();
	}

	private static void printKeystoreInfo(KeyStore keystore)
			throws KeyStoreException {
		System.out.println();
		System.out.println("Provider : " + keystore.getProvider().getName());
		System.out.println("Type : " + keystore.getType());
		System.out.println("Size : " + keystore.size());

		Enumeration en = keystore.aliases();
		while (en.hasMoreElements()) {
			System.out.println("Alias: " + en.nextElement());
		}
	}

	private class AliasKeyManager implements X509KeyManager {

		private KeyStore _ks;
		private String _alias;
		private String _password;

		public AliasKeyManager(KeyStore ks, String alias, String password) {
			_ks = ks;
			_alias = alias;
			_password = password;
		}

		public String chooseClientAlias(String[] str, Principal[] principal,
				Socket socket) {
			return _alias;
		}

		public String chooseServerAlias(String str, Principal[] principal,
				Socket socket) {
			return _alias;
		}

		public X509Certificate[] getCertificateChain(String alias) {
			try {
				java.security.cert.Certificate[] certificates = this._ks
						.getCertificateChain(alias);
				if (certificates == null) {
					throw new FileNotFoundException(
							"no certificate found for alias:" + alias);
				}
				X509Certificate[] x509Certificates = new X509Certificate[certificates.length];
				System.arraycopy(certificates, 0, x509Certificates, 0,certificates.length);
				return x509Certificates;
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		}

		public String[] getClientAliases(String str, Principal[] principal) {
			return new String[] { _alias };
		}

		public PrivateKey getPrivateKey(String alias) {
			try {
				return (PrivateKey) _ks.getKey(alias, _password == null ? null
						: _password.toCharArray());
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		}

		public String[] getServerAliases(String str, Principal[] principal) {
			return new String[] { _alias };
		}

	}
}
C

Consegui resolver de outra forma.

Está na thread:

http://www.guj.com.br/java/238251

e no meu blog também:
http://a4t.in/xwiki/bin/view/Blog/ForbiddenNFe

Espero ter ajudado

R

blz

C

Amigos

To precisando ler o repositorio do windows = o programa do governo faz

E deixar o usuario escolher qual certificado ele quer usar para assinar

Alguem tem ideia de como faz?

Dario

R

Ola,

Amigo se vc seguir os posts meu e do chicocx vc consegue

vlws

C

olá,

hoje já assino via A1 e A3 pelo arquivo .PFX ou pelo eToken.cfg

funcionava de boa, mas agora um novo cliente adquiriu um token safenet ikey 2032 e não funciona

o unico jeito que vi funcionar foi pelo repositorio do windows

pelo sistema de teste do governo, ele nao consegue achar o token como achava os outros

se eu marco o repositorio do windows da certo

gostaria de criar uma tela no java que lista-se o repositorio do windows e ao selecionar o certificado, que ele assina-se o arquivo

ja tenho implentando via arquivo .PFX e via token pelo eToken.cfg

não tenho ideia de como faria pelo repositorio do windows

não tem como você me fazer um codigo de como gerar isto, qual seria o custo?

Dario

Criado 26 de novembro de 2009
Ultima resposta 2 de ago. de 2011
Respostas 8
Participantes 5