Como acessar um WebService via HTTPS estando o certificado/chave privada num Token USB (eCNPJ)?

28 respostas
elissandromendes

Pessoal,

Num teste que fiz consigo acessar beleza quando o keystore está em arquivo do tipo JKS, mas quando as informações de chave privada estão num token ? No caso é um token do tipo eCNPJ sendo que a chave privada não pode ser extraida. Como configurar para o servidor “enxergar” minhas credencias.

Agradeço qualquer ajuda.

abracos.

28 Respostas

O

Opções:

  1. Criar/obter um provider JCE para acessar o token.
  2. Implementar/obter um protocolo que comunica com este tipo de dispositivo, tipo PKCS#11.
  3. Se este dispositivo tiver biblioteca de acesso em código nativo, fazer chamadas via JNI.

O mais fácil é se o fornecedor do token fornecer um provider JCE para acessa-lo.

Você não precisa extrair a chave do token. O token tem que ter a capacidade de criptografar/descriptografar um dado que é passado para ele.
Existem métodos em classes JCE que fazem esta parte. Procure por wrap/unwrap da classe Cipher.

Não entendi o que você chamou de servidor na frase acima.

T

Experimente para ver se os providers da Sun (SunPKCS11, disponível a partir do Java 5.0, e SunMSCAPI, disponível a partir do java 6.0) conseguem efetuar as operações com seu token USB.
Eles dependem de o driver criptográfico estar corretamente instalado na máquina.
A configuração desses providers é feita através do arquivo java.security dentro do diretório jre/lib/security.
Uma vez consegui usar o SunPKCS11 - mas não sei se as operações criptográficas que você precisa são suportadas pelo SunPKCS11.

victorwss

Deixa eu adivinhar, você está tentando implementar um programa para conectar em webservices de secretarias de fazenda para emitir notas fiscais eletrônicas?

elissandromendes

Sim.

elissandromendes

thingol:
Experimente para ver se os providers da Sun (SunPKCS11, disponível a partir do Java 5.0, e SunMSCAPI, disponível a partir do java 6.0) conseguem efetuar as operações com seu token USB.
Eles dependem de o driver criptográfico estar corretamente instalado na máquina.
A configuração desses providers é feita através do arquivo java.security dentro do diretório jre/lib/security.
Uma vez consegui usar o SunPKCS11 - mas não sei se as operações criptográficas que você precisa são suportadas pelo SunPKCS11.

Com o codigo abaixo consigo “enxergar” várias informações do meu token:

public class Teste {

public static void main( String args[] ) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException {

Provider p = new sun.security.pkcs11.SunPKCS11(“c:/temp/security/security.cfg);
Security.addProvider(p);
    
    KeyStore ks = KeyStore.getInstance("PKCS11");
    ks.load(null, new String("xxxxxx").toCharArray());
    
    PrivateKey privateKey = (PrivateKey) ks.getKey("ALIAS", new String("xxxxxx").toCharArray());
    Certificate certificate = (Certificate) ks.getCertificate("ALIAS");
    
    System.out.println(privateKey.toString());
}

}

Conteúdo do arquivo de configuração:

name=Safenetikey2032
library=c:\windows\system32\dkck201.dll

attributes = compatibility

*** Essa DLL encontrei citada num exemplo da net e verifiquei que tinha no meu windows. Usei e deu “certo”, outra citada para o modelo do token (SafeNet ikey 2032) seria dkck2032.dll mas essa nao tenho e nao encontrei no site do fabricante para download ****

Isso me retorna para a chave privada:

SunPKCS11-Safenetikey2032 RSA private key, 1024 bits (id 2293760, token object, sensitive, unextractable)

O que gostaria de ajuda para entender seria:

  1. Se é possível e como utilizar esse token USB para assinar um arquivo XML ?

  2. Como configurar no java/netbeans o acesso ao web service via HTTPS usando o certificado contido nesse token ? O WS a ser acessado requer autenticação do cliente, isso já está como uma extensão do certificado do token.

Segue um código de teste de assinatura e a exceção levantada:

public class XMLSigner {

private static final String CANONICALIZE_METHOD = <a href="http://www.w3.org/TR/2001/REC-xml-c14n-20010315">http://www.w3.org/TR/2001/REC-xml-c14n-20010315</a>”;

private static final String C14N_TRANSFORM_METHOD = <a href="http://www.w3.org/TR/2001/REC-xml-c14n-20010315">http://www.w3.org/TR/2001/REC-xml-c14n-20010315</a>”;

private static final String PROVIDER_CLASS_NAME = org.jcp.xml.dsig.internal.dom.XMLDSigRI;

private static final String PROVIDER_NAME = jsr105Provider;
public static OutputStream sign( File inXML, File ouXML ) {
    OutputStream os = null;
    try {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(false);
        // Obtem DOM do documento
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(inXML);

        // Obtem elemento do documento a ser assinado, será criado uma REFERENCE para o mesmo
        NodeList elements = doc.getElementsByTagName("infNFe");
        Element el = (Element) elements.item(0);
        String id = el.getAttribute("Id");

        // Cria uma factory representando o elemento XML Signature, a partir dela serão criados as parte desse elemento
        String providerName = System.getProperty(PROVIDER_NAME, PROVIDER_CLASS_NAME);
        XMLSignatureFactory signatureFactory = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance());

        // Cria método de Digest e canonicalização
        DigestMethod digestMethod = signatureFactory.newDigestMethod(DigestMethod.SHA1, null);
        C14NMethodParameterSpec c14NMethodParameterSpec = null;
        CanonicalizationMethod canonicalMethod = signatureFactory.newCanonicalizationMethod(CANONICALIZE_METHOD, c14NMethodParameterSpec);
        
        // Cria classe representando o Hash e algoritmo de criptografia a ser aplicado
        SignatureMethod sm = signatureFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, null);

        // Cria a lista de tranformações a serem aplicadas as referencias a serem assinadas
        ArrayList transformList = new ArrayList();
        TransformParameterSpec tps = null;
        Transform envelopedTransform = signatureFactory.newTransform(Transform.ENVELOPED, tps);
        Transform c14NTransform = signatureFactory.newTransform(C14N_TRANSFORM_METHOD, tps);
        transformList.add(envelopedTransform);
        transformList.add(c14NTransform);

        // Cria referencia, parte do XML a ser assinado 
        Reference ref = signatureFactory.newReference("#" + id, digestMethod, transformList, null, null);
        ArrayList refList = new ArrayList();
        refList.add(ref);

        SignedInfo signedInfo = signatureFactory.newSignedInfo(canonicalMethod, sm, refList);

        Provider p = new sun.security.pkcs11.SunPKCS11("c:/temp/security/security.cfg");
        Security.addProvider(p);

        KeyStore ks = KeyStore.getInstance("PKCS11");
        ks.load(null, new String("inteqq").toCharArray());

        PrivateKey privateKey = (PrivateKey) ks.getKey("4e1ece83-89de-4ae8-86f1-9564d7fdf945", new String("inteqq").toCharArray());
        Certificate certificate = (Certificate) ks.getCertificate("4e1ece83-89de-4ae8-86f1-9564d7fdf945");

        DOMSignContext dsc = new DOMSignContext(privateKey, doc.getDocumentElement());

        KeyInfoFactory kif = signatureFactory.getKeyInfoFactory();
        X509Data x509Data = kif.newX509Data(Collections.singletonList(certificate));

        KeyInfo keyInfo = kif.newKeyInfo(Collections.singletonList(x509Data));

        XMLSignature signature = signatureFactory.newXMLSignature(signedInfo, keyInfo);
        signature. sign(dsc);

        os = new FileOutputStream(ouXML);

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
    } catch (TransformerException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (MarshalException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (XMLSignatureException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (UnrecoverableKeyException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (CertificateException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (KeyStoreException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidAlgorithmParameterException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (ClassNotFoundException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (SAXException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    } catch (ParserConfigurationException ex) {
        Logger.getLogger(XMLSigner.class.getName()).log(Level.SEVERE, null, ex);
    }
    return os;
}

public static void main( String[] args ) {
    OutputStream out = XMLSigner.sign(new File("c:/temp/entrada/teste-nfe.xml"), new File("c:/temp/entrada/teste-nfe-out.xml"));
}

}

Exceção:

01/02/2008 10:07:01 inteq.nfe.servicos.util.XMLSigner sign

SEVERE: null

javax.xml.crypto.dsig.XMLSignatureException: javax.xml.crypto.dsig.TransformException: java.security.ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_MECHANISM_INVALID

at org.jcp.xml.dsig.internal.dom.DOMSignedInfo.canonicalize(DOMSignedInfo.java:175)

at org.jcp.xml.dsig.internal.dom.DOMRSASignatureMethod.sign(DOMRSASignatureMethod.java:140)

at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(DOMXMLSignature.java:367)

at inteq.nfe.servicos.util.XMLSigner.sign(XMLSigner.java:128)

at inteq.nfe.servicos.util.XMLSigner.main(XMLSigner.java:169)

Caused by: javax.xml.crypto.dsig.TransformException: java.security.ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_MECHANISM_INVALID

at org.jcp.xml.dsig.internal.dom.ApacheCanonicalizer.transform(ApacheCanonicalizer.java:231)

at org.jcp.xml.dsig.internal.dom.DOMTransform.transform(DOMTransform.java:129)

at org.jcp.xml.dsig.internal.dom.DOMCanonicalizationMethod.canonicalize(DOMCanonicalizationMethod.java:67)

at org.jcp.xml.dsig.internal.dom.DOMSignedInfo.canonicalize(DOMSignedInfo.java:172)

 4 more

Caused by: java.security.ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_MECHANISM_INVALID

at sun.security.pkcs11.P11Signature.engineUpdate(P11Signature.java:371)

at java.security.Signature$Delegate.engineUpdate(Signature.java:1118)

at java.security.Signature.update(Signature.java:684)

at org.jcp.xml.dsig.internal.SignerOutputStream.write(SignerOutputStream.java:68)

at com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream.flushBuffer(UnsyncBufferedOutputStream.java:62)

at com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream.flush(UnsyncBufferedOutputStream.java:78)

at com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream.close(UnsyncBufferedOutputStream.java:84)

at com.sun.org.apache.xml.internal.security.c14n.implementations.CanonicalizerBase.engineCanonicalizeSubTree(CanonicalizerBase.java:192)

at com.sun.org.apache.xml.internal.security.c14n.implementations.CanonicalizerBase.engineCanonicalize(CanonicalizerBase.java:138)

at com.sun.org.apache.xml.internal.security.transforms.implementations.TransformC14N.enginePerformTransform(TransformC14N.java:65)

at com.sun.org.apache.xml.internal.security.transforms.Transform.performTransform(Transform.java:350)

at org.jcp.xml.dsig.internal.dom.ApacheCanonicalizer.transform(ApacheCanonicalizer.java:218)

 7 more

Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_MECHANISM_INVALID

at sun.security.pkcs11.wrapper.PKCS11.C_SignUpdate(Native Method)

at sun.security.pkcs11.P11Signature.engineUpdate(P11Signature.java:365)

 18 more

javax.xml.crypto.dsig.TransformException: java.security.ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_MECHANISM_INVALID

at org.jcp.xml.dsig.internal.dom.ApacheCanonicalizer.transform(ApacheCanonicalizer.java:231)

at org.jcp.xml.dsig.internal.dom.DOMTransform.transform(DOMTransform.java:129)

at org.jcp.xml.dsig.internal.dom.DOMCanonicalizationMethod.canonicalize(DOMCanonicalizationMethod.java:67)

at org.jcp.xml.dsig.internal.dom.DOMSignedInfo.canonicalize(DOMSignedInfo.java:172)

at org.jcp.xml.dsig.internal.dom.DOMRSASignatureMethod.sign(DOMRSASignatureMethod.java:140)

at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(DOMXMLSignature.java:367)

at inteq.nfe.servicos.util.XMLSigner.sign(XMLSigner.java:128)

at inteq.nfe.servicos.util.XMLSigner.main(XMLSigner.java:169)

Caused by: java.security.ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_MECHANISM_INVALID

at sun.security.pkcs11.P11Signature.engineUpdate(P11Signature.java:371)

at java.security.Signature$Delegate.engineUpdate(Signature.java:1118)

at java.security.Signature.update(Signature.java:684)

at org.jcp.xml.dsig.internal.SignerOutputStream.write(SignerOutputStream.java:68)

at com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream.flushBuffer(UnsyncBufferedOutputStream.java:62)

at com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream.flush(UnsyncBufferedOutputStream.java:78)

at com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream.close(UnsyncBufferedOutputStream.java:84)

at com.sun.org.apache.xml.internal.security.c14n.implementations.CanonicalizerBase.engineCanonicalizeSubTree(CanonicalizerBase.java:192)

at com.sun.org.apache.xml.internal.security.c14n.implementations.CanonicalizerBase.engineCanonicalize(CanonicalizerBase.java:138)

at com.sun.org.apache.xml.internal.security.transforms.implementations.TransformC14N.enginePerformTransform(TransformC14N.java:65)

at com.sun.org.apache.xml.internal.security.transforms.Transform.performTransform(Transform.java:350)

at org.jcp.xml.dsig.internal.dom.ApacheCanonicalizer.transform(ApacheCanonicalizer.java:218)

 7 more

Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_MECHANISM_INVALID

at sun.security.pkcs11.wrapper.PKCS11.C_SignUpdate(Native Method)

at sun.security.pkcs11.P11Signature.engineUpdate(P11Signature.java:365)

 18 more

java.security.ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_MECHANISM_INVALID

at sun.security.pkcs11.P11Signature.engineUpdate(P11Signature.java:371)

at java.security.Signature$Delegate.engineUpdate(Signature.java:1118)

at java.security.Signature.update(Signature.java:684)

at org.jcp.xml.dsig.internal.SignerOutputStream.write(SignerOutputStream.java:68)

at com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream.flushBuffer(UnsyncBufferedOutputStream.java:62)

at com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream.flush(UnsyncBufferedOutputStream.java:78)

at com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream.close(UnsyncBufferedOutputStream.java:84)

at com.sun.org.apache.xml.internal.security.c14n.implementations.CanonicalizerBase.engineCanonicalizeSubTree(CanonicalizerBase.java:192)

at com.sun.org.apache.xml.internal.security.c14n.implementations.CanonicalizerBase.engineCanonicalize(CanonicalizerBase.java:138)

at com.sun.org.apache.xml.internal.security.transforms.implementations.TransformC14N.enginePerformTransform(TransformC14N.java:65)

at com.sun.org.apache.xml.internal.security.transforms.Transform.performTransform(Transform.java:350)

at org.jcp.xml.dsig.internal.dom.ApacheCanonicalizer.transform(ApacheCanonicalizer.java:218)

at org.jcp.xml.dsig.internal.dom.DOMTransform.transform(DOMTransform.java:129)

at org.jcp.xml.dsig.internal.dom.DOMCanonicalizationMethod.canonicalize(DOMCanonicalizationMethod.java:67)

at org.jcp.xml.dsig.internal.dom.DOMSignedInfo.canonicalize(DOMSignedInfo.java:172)

at org.jcp.xml.dsig.internal.dom.DOMRSASignatureMethod.sign(DOMRSASignatureMethod.java:140)

at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(DOMXMLSignature.java:367)

at inteq.nfe.servicos.util.XMLSigner.sign(XMLSigner.java:128)

at inteq.nfe.servicos.util.XMLSigner.main(XMLSigner.java:169)

Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_MECHANISM_INVALID

at sun.security.pkcs11.wrapper.PKCS11.C_SignUpdate(Native Method)

at sun.security.pkcs11.P11Signature.engineUpdate(P11Signature.java:365)

O que siginifica esse CKR_MECHANISM_INVALID ?

Desculpem o tamanho da mensagem.

Desde java agradeço qualquer ajudar.

T

Isso é um erro definido pelas bibliotecas de PKCS#11 (Mecanismo inválido).

Pode ocorrer quando o algoritmo de assinatura ou de digest, ou de padding da assinatura, não é o aceito pelo dispositivo, mas isso é estranho no seu caso, já que você está solicitando RSA + SHA1, que costuma ser o padrão.

Você tem algum contato com o fabricante (Safenet, que tinha comprado a Rainbow - no meu tempo esse iKey era fabricado pela Rainbow)?

victorwss

Hahaha, eu sabia!
Eu também estou tendo que enfrentar este dragão que o governo inventou.
Infelizmente quanto a essa parte da chave, eu não posso ajudar muito porque foi um outro cara aqui da equipe que fez essa parte e nesse ponto eu entendo muito pouco.

elissandromendes

victorwss:
elissandromendes:

Sim

Hahaha, eu sabia!
Eu também estou tendo que enfrentar este dragão que o governo inventou.
Infelizmente quanto a essa parte da chave, eu não posso ajudar muito porque foi um outro cara aqui da equipe que fez essa parte e nesse ponto eu entendo muito pouco.

Verdade, é um dragão !! rs

Qual o token que vcs utilizaram ?

Teria como ver se no codigo acima estou cometendo algum erro, ou de repente manda um codigo de vcs pra eu verificar contra esse meu token aqui ?

abracos.

elissandromendes

Amigos,

E quanto a acessar o WS via HTTPS usando esse token alguma dica ?

Usando o IE consigo ver blz o WSDL de um dos serviços. Como faco isso no Java e de preferencia no ambiente do Netbeans.

Isso já me adiantaria bastante, pois o token de assinatura do xml será o da empresa que parece será em arquivo, daí esse meu seria apenas para agir como do transmissor.

Agradeco.

victorwss

Cara, tenta algo mais ou menos assim. Não sei se vai ajudar:

System.setProperty("javax.net.ssl.trustStore", "C:\\blablabla\\tstore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "sua_senha_aqui");
System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
O

Bem, como diria o estripador, vamos por parte:

  1. Web Services
    Procure por um framework que implemente WS-SOAP. Exemplos: Axis, XFire.

  2. É necessário certificação do cliente para acessar este Web Service?
    Se sim, você vai ter que usar JSSE. De uma procurada por exemplos aqui mesmo no GUJ.

  3. É a mesma chave (eCNPJ) que vai assinar a mensagem que vai autenticar para acesso via Web Services?
    Se sim, você vai ter que setar assim:

System.setProperty("javax.net.ssl.keyStoreType", "pkcs11");

e configurar a parte de certificados em uma outra keystore.

elissandromendes

oyama:
Bem, como diria o estripador, vamos por parte:

  1. Web Services
    Procure por um framework que implemente WS-SOAP. Exemplos: Axis, XFire.

Estou usando o JAX-WS do Java 6 para implementar o cliente. Aparentemente está OK, testei acessando um servidor construido com os WSDLs dos servicos da sefaz que consegui baixar, porem sem acessar via HTTPS.

Tranquilo irei dar uma olhada.

oyama:

3) É a mesma chave (eCNPJ) que vai assinar a mensagem que vai autenticar para acesso via Web Services?
Se sim, você vai ter que setar assim:

System.setProperty("javax.net.ssl.keyStoreType", "pkcs11");

e configurar a parte de certificados em uma outra keystore.

Quando em produção não serão a mesma. Teremos a nossa, um eCNPJ para acessar o WS e nosso cliente terá a de assinatura ou essa de assinatura do cliente servirá tambem para acessar o WS.

Um pergunta quanto a configuração que vc citou, tenho como exportar o certificado do token e converte-lo de forma a importa-lo num arquivo JKS e assim informar esse JKS como sendo o meu keystore donde o SSL buscara a autenticacao.

Vi alguma coisa na net vou dar uma olhada, se já tiver algo por ai agradeco.

abracos.

victorwss

Olha, vou te dar essa dica: Não confie no WSDL porque algumas UFs não o geram corretamente (e o azar por isso é do contribuinte). Analise-o já pensando em que tipo de atitude tomar para remendar quaisquer inconsistências que tiver.

elissandromendes

Bom galera,

Estou aguardando resposta do pessoal sa SafeNet BR pra saber o que seria esse problema de INVALID MECHANISM.

Acredito que o código que estou usando está ok! Dever ser algum pro de configuração, onde devo estar deixando ligado alguns dos mecanismos que são citados na documentação só que não é o correto pra esse meu modelo.

Assim que tiver uma resposta positiva posto aqui.

De agora, muito massa ajuda de vcs.

Obrigado mesmo !!

abraços.

philler

elissandromendes:
Bom galera,

Estou aguardando resposta do pessoal sa SafeNet BR pra saber o que seria esse problema de INVALID MECHANISM.

Acredito que o código que estou usando está ok! Dever ser algum pro de configuração, onde devo estar deixando ligado alguns dos mecanismos que são citados na documentação só que não é o correto pra esse meu modelo.

Assim que tiver uma resposta positiva posto aqui.

De agora, muito massa ajuda de vcs.

Obrigado mesmo !!

abraços.

Opa, estou com a mesma bronca. Tem alguma dica?

Grato

Alencar

guilherme_ha

Galera… estou com um problema parecido…
tenho um programa pra emissao da nfe que funciona perfeitamente com os certificados PFX e SmartCard(CartaoInteligente)

Porem agora tenho que implementar para o certificado no dispositivo de token(pendrive)

So que nao vai nem a pau…
eu até consigo ler o certificado do token usando o esquema do .cfg… com a dll do fornecedor e tal…

Porem qdo mando a mensagem soap, da o seguinte erro:

14/05/2010 16:24:22 com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection post
SEVERE: SAAJ0009: Message send failed
com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: java.security.PrivilegedActionException: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Message send failed
at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.call(HttpSOAPConnection.java:146)

Estou usando o Safenet iKey 2032

Alguem tem alguma dica pra me dar ??
Obrigado…

philler

O conteudo do arquivo de configuração (pkcs11.cfg) é um pouco diferente para este Token:

name=eToken

library=c:\windows\system32\dkck201.dll

disabledMechanisms = {

CKM_SHA1_RSA_PKCS

}

Alencar

guilherme_ha

Ainda esta dando o mesmo erro…!!

MInha conexao esta assim:

String keyPass = "";
        String proto = "SSLv3";
        keyPass = nfs.getCfg().getDescriptoSenha();
        Provider p = null;
        if(nfs.getCfg().getUsaToken().equalsIgnoreCase("S")){

        p = new sun.security.pkcs11.SunPKCS11(nfs.getCfg().getCfg());
        ks = KeyStore.getInstance("PKCS11", p);
        ks.load(null, keyPass.toCharArray());
        }else{
        p = new com.sun.net.ssl.internal.ssl.Provider();
        ks = KeyStore.getInstance("PKCS12", p);
        ks.load(new FileInputStream(nfs.getCfg().getLocalPFX()), keyPass.toCharArray());
        }

        Security.addProvider(p);

        KeyManagerFactory kmf = null;
        kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(ks, keyPass.toCharArray ());
        KeyManager[] km =  kmf.getKeyManagers();
        TrustManagerFactory tmf = null;
        tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(ks);

        SSLContext sc = null;
        sc = SSLContext.getInstance(proto);
        sc.init(km, trustAllCerts, new java.security.SecureRandom());
        SSLContext.setDefault(sc);
 
        SSLSocketFactory socketFactory = sc.getSocketFactory();
        socket = (SSLSocket)socketFactory.createSocket(host, port);
        socket.addHandshakeCompletedListener(this);
        socket.setUseClientMode(true);
        socket.startHandshake();

Valew

L

Boa tarde elissandromendes

Estou com o mesmo problema seu, verifiquei o seguinte (token da rainbow);

No token existe a seguinte cadeia:
[color=blue] AC Raiz
AC Secretaria da Receita Federal do Brasil
AC Serasa RFB
Empresa com o certificado E-CNPJ
[/color]

No momento que executo o comando:

ks.load(null, new String("xxxxxx").toCharArray());

o mesmo me retorna a informaçao da AC Secretaria da Receita Federal do Brasil (subject=CN=AC Secretaria da Receita Federal do Brasil, O=ICP-Brasil, C=BR)
no entanto deveria vir a informação do “Empresa com o certificado E-CNPJ”.

Como que está retornando para ti esta informação?

Talvez já tenha resolvido, pela data, é bem antiga, teria alguma resposta para mim?

Muito obrigado

philler

lcspohn:
Boa tarde elissandromendes

Estou com o mesmo problema seu, verifiquei o seguinte (token da rainbow);

No token existe a seguinte cadeia:
[color=blue] AC Raiz
AC Secretaria da Receita Federal do Brasil
AC Serasa RFB
Empresa com o certificado E-CNPJ
[/color]

No momento que executo o comando:

ks.load(null, new String("xxxxxx").toCharArray());

o mesmo me retorna a informaçao da AC Secretaria da Receita Federal do Brasil (subject=CN=AC Secretaria da Receita Federal do Brasil, O=ICP-Brasil, C=BR)
no entanto deveria vir a informação do “Empresa com o certificado E-CNPJ”.

Como que está retornando para ti esta informação?

Talvez já tenha resolvido, pela data, é bem antiga, teria alguma resposta para mim?

Muito obrigado

Neste caso, você precisa “varrer” os certificados que retornam do token e tentar extrair a PK. Quando conseguir, será o certificado do seu cliente.
Caso contrário, é tão somente um certificado da cadeia validadora.
Para facilitar eu criei um arquivo de configuração onde o meu sistema extrai o alias correto e seta neste arquivo.
Isso evita que tenha que pesquisar todas as vezes que vai usar o token/cartão. Além disso, caso o processo falhe na localização do alias correto,
ainda tenho a possibilidade de setá-lo a mão.

Alencar

L

Boa Tarde Alencar

Muito obrigado pelo retorno.

Ref. ao que vc falou, eu já faço isso, segue modelo que fiz para teste:

KeyStore ks = KeyStore.getInstance("PKCS11");
	ks.load(null, certificado.getcertificadoPassword().toCharArray());
	
    Enumeration<String> aliasesEnum = ks.aliases();
    while (aliasesEnum.hasMoreElements()) {  
        String alias = (String) aliasesEnum.nextElement();
	        
        X509Certificate certif = (X509Certificate)ks.getCertificate(alias);
        System.out.println( "SN =     " + certif.getSerialNumber().toString(16) );
        System.out.println( "Issuer = " + certif.getIssuerDN().toString() );
        System.out.println( "subject= " + certif.getSubjectDN().toString() );
	}

Neste caso acima é para varrer todos os certificados que existem no token.

Normalmente só traz o certificado da empresa e neste token que eu tenho está estranho, está trazendo somente o da secretaria da receita federal.

[color=red]SunPKCS11-Safenetikey2032 RSA private key, 1024 bits (id 2621440, token object, sensitive, unextractable)
SN = 5
Issuer = CN=Autoridade Certificadora Raiz Brasileira v1, OU=Instituto Nacional de Tecnologia da Informacao - ITI, O=ICP-Brasil, C=BR
subject= CN=AC Secretaria da Receita Federal do Brasil, O=ICP-Brasil, C=BR
[/color]

No subject deveria trazer o nome da empresa e ou cnpj, se eu visualizar este certificado pelo próprio token está correto e pelo internet explorer também, consegui emitir uma nota fiscal pelo site da receita normalmente com este token.

Mas via código java não consigo, estou utilizando a versão 1.6.0_20 do java.

philler

Eis o motivo pelo qual fiz um arquivo de configuração. Quando nada mais funciona, seto o alias do certificado certo no braço.

Alencar

L

Bom dia Alencar,

Mas neste caso o arquivo de configuiração para mim não irá resolver, fiz este teste não deu certo, o problema que não aparece os certificados após o load. Pode ser que eu esteja enganado, mas o código abaixo deveria listar todos os certificados no token, correto?
Provider p = new sun.security.pkcs11.SunPKCS11(getcertificadoFile());

Security.addProvider(p);

KeyStore ks = KeyStore.getInstance("PKCS11");
ks.load(null, null);
	
Enumeration<String> aliasesEnum = ks.aliases();
while (aliasesEnum.hasMoreElements()) {  
    String alias = (String) aliasesEnum.nextElement();
	        
    System.out.println("----> Certificado alias: " + alias + "    Key store type: " + ks.getType());
    X509Certificate certif = (X509Certificate)ks.getCertificate(alias);
    System.out.println( "SN =     " + certif.getSerialNumber().toString(16) );
    System.out.println( "Issuer = " + certif.getIssuerDN().toString() );
    System.out.println( "subject= " + certif.getSubjectDN().toString() );
}
No entanto só me mostra uma cadeia.

o problema é: No IE mostra a cadeia completa e o certificado está OK (Repositório de certificados do windows), já neste código acima só mostra um certificado da cadeia, no caso o da secretaria da receita federal. Será por que?

philler

lcspohn:
Bom dia Alencar,

…o problema é: No IE mostra a cadeia completa e o certificado está OK (Repositório de certificados do windows), já neste código acima só mostra um certificado da cadeia, no caso o da secretaria da receita federal. Será por que?

Ja tive casos em que foi necessário incluir no token a cadeia certificadora correta, pois a que tinha no token não validava o
certificado do cliente.
No IE, a cadeia é auto instalada (não sei como), por isso lá você vê ela completa.

O que eu faço: Pelo software de instalação/administração do token, analiso a cadeia visualmente. Caso ela não feche com o certificado
ou falte parte dela, importo o certificado correto/restante pelo software do token.

QQ coisa, contate-me em pvt. Após resolver o problema, você publica a solução aqui, para conhecimento de todos.

Alencar

Mackrophus

Olá Meus Camaradas, eu já to sendo chamado se São Jorge aqui na firma.

Segue abaixo o codigo que usei para assinar e enviar com o SmartCard da Safeweb, por pendrive é a mesma coisa, só que já vou avisando, fica consideravelmente lento para um numero grande de nf-es.

Espero que ajude.

try {
			
			String tag = "infNFe";
			String caminhoCertificado = Utilitario.caminhoCertCli();
			String senha = Utilitario.senhaCertCli();
			
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			factory.setNamespaceAware(false);
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document docs = builder.parse(new File(caminhoNfe));
			
			NodeList elements = docs.getElementsByTagName(tag);
			Element el = (Element) elements.item(0);
			String id = el.getAttribute("Id");
			
			NodeList elements2 = docs.getElementsByTagName("nNF");
			Element elIdNfe = (Element) elements2.item(0);
			idNfeS = elIdNfe.getTextContent();
			
			String providerName = System.getProperty(PROVIDER_NAME, PROVIDER_CLASS_NAME);
			XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance());		

			ArrayList transformList = new ArrayList(); 
			TransformParameterSpec tps = null; 
			Transform envelopedTransform = fac.newTransform(Transform.ENVELOPED,tps); 
			Transform c14NTransform = fac.newTransform(C14N_TRANSFORM_METHOD, tps); 
			transformList.add(envelopedTransform); 
			transformList.add(c14NTransform); 

			Reference ref = fac.newReference("#" + id, fac.newDigestMethod(DigestMethod.SHA1, null), transformList, null, null); 
			SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,(C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref)); 

			//A3
			Provider p = new sun.security.pkcs11.SunPKCS11("c:/sistema/token.cfg");
			Security.addProvider(p);
			
			X509Certificate certificado = null;
			KeyStore ks = null;
			try {
				ks = KeyStore.getInstance("PKCS11");
			} catch (KeyStoreException e2) {
				// TODO Auto-generated catch block
				e2.printStackTrace();
			}
			try {
				ks.load(null, "safeweb".toCharArray());
			} catch (NoSuchAlgorithmException e) {
				log.info("Erro Assinatura Envio 1: " + e.getMessage());
				e.printStackTrace();
			} catch (CertificateException e) {
				log.info("Erro Assinatura Envio 2: " + e.getMessage());
				e.printStackTrace();
			} catch (IOException e) {
				log.info("Erro Assinatura Envio 3: " + e.getMessage());
				e.printStackTrace();
			}
			
			Enumeration aliasesEnum = ks.aliases(); 
			String alias = ""; 
			while (aliasesEnum.hasMoreElements()) { 
				alias = (String) aliasesEnum.nextElement(); 
				if (ks.isKeyEntry(alias)) {
					//log.info("Entrou: " + alias);
					certificado = (X509Certificate) ks.getCertificate(alias);
					break; 
				} 
			} 


			//A3
                        //aqui eu coloquei fixo, mas, pode ficar conforme a linha de baixo
			KeyStore.PrivateKeyEntry keyEntryA3 = (PrivateKeyEntry) ks.getEntry("3ab3ec9f-2b00-434e-9b88-4154f3853a08", new KeyStore.PasswordProtection("safeweb".toCharArray()));
                        //KeyStore.PrivateKeyEntry keyEntryA3 = (PrivateKeyEntry) ks.getEntry(alias, new KeyStore.PasswordProtection("safeweb".toCharArray()));
			X509Certificate cert = (X509Certificate) keyEntryA3.getCertificate();
						
			//log.info("Certificado: " + keyEntryA3);
			KeyInfoFactory kif = fac.getKeyInfoFactory(); 
			List x509Content = new ArrayList(); 
			
			x509Content.add(cert);
			X509Data xd = kif.newX509Data(x509Content); 
			KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd)); 

			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
			dbf.setNamespaceAware(true); 
			Document doc = dbf.newDocumentBuilder().parse(new FileInputStream(caminhoNfe)); 

			DOMSignContext dsc = new DOMSignContext(keyEntryA3.getPrivateKey(), doc.getDocumentElement().getElementsByTagName("NFe").item(0));
			
			XMLSignature signature = fac.newXMLSignature(si, ki); 
			signature.sign(dsc); 

			doc.setXmlStandalone(true);
			
			NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); 
			
			if (nl.getLength() == 0) { 
				throw new Exception("Elemento assinatura não encontrado"); 
			} 
			DOMValidateContext valContext = new DOMValidateContext( new X509KeySelector(ks), nl.item(0)); 
			XMLSignature signatures = fac.unmarshalXMLSignature(valContext); 
			boolean coreValidity = signatures.validate(valContext); 
			if (coreValidity == false) { 
				System.err.println("Falha na Assinatura!");			
				log.info("Falha na Assinatura da NF-e " + idNfeS);				
			} else { 
				System.out.println("Assinatura Correta!");				
				log.info("Assinatura  da NF-e " + idNfeS + " correta.");
			} 
						
			OutputFormat format    = new OutputFormat(doc); 
			StringWriter stringOut = new StringWriter ();    
	    	XMLSerializer serial   = new XMLSerializer (stringOut,format);
		    serial.serialize(doc);
		    
		    nfeDadosMsg = stringOut.toString();
		
		} catch (Exception e){
			texto.append("Exception a: " + e.getMessage() + "\n");
			texto.setCaretPosition(texto.getText().length());
			texto.repaint();
		}
	
		String retornoProc = null;
		
		Provider p = new sun.security.pkcs11.SunPKCS11("c:/sistema/token.cfg");
		Security.addProvider(p);
				
		KeyStore ks = null;
		try {
			ks = KeyStore.getInstance("PKCS11");
		} catch (KeyStoreException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}
		try {
			ks.load(null, "safeweb".toCharArray());			
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (CertificateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		Enumeration aliasesEnum = null;
		try {
			aliasesEnum = ks.aliases();
		} catch (KeyStoreException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		while (aliasesEnum.hasMoreElements()) {
		   String alias = (String)aliasesEnum.nextElement();
		   X509Certificate cert = null;
		   try {
			   cert = (X509Certificate) ks.getCertificate(alias);			   
			   certificadoVector.add(cert);
		   } catch (KeyStoreException e) {
			   // TODO Auto-generated catch block
			   e.printStackTrace();
		   }
		   
		   //System.out.println("Certificate: " + cert);
		   PrivateKey privateKey = null;
		   try {
			   privateKey = (PrivateKey) ks.getKey(alias, null);
		   } catch (UnrecoverableKeyException e) {
			   // TODO Auto-generated catch block
			   e.printStackTrace();
		   } catch (KeyStoreException e) {
			   // TODO Auto-generated catch block
			   e.printStackTrace();
		   } catch (NoSuchAlgorithmException e) {
			   // TODO Auto-generated catch block
			   e.printStackTrace();
		   }
		   //System.out.println("Private key: " + privateKey);
		}
		
		DocumentBuilderFactory factoryV = DocumentBuilderFactory.newInstance();
        System.out.println("DocumentBuilderFactory: "+ factoryV.getClass().getName());
        
	System.setProperty("javax.net.ssl.keyStoreType", ks.getType());   
        System.setProperty("javax.net.ssl.keyStore", "NONE"); 
        System.setProperty("javax.net.ssl.keyStoreProvider", "SunPKCS11-Safeweb");   
        System.setProperty("javax.net.ssl.keyStorePassword", "safeweb");   
		
        System.setProperty("javax.net.ssl.trustStoreType", Utilitario.tipoCertSrv());
		System.setProperty("javax.net.ssl.trustStore", Utilitario.caminhoCertSrv());//Aqui vem o arquivo criado através do comando keytool no passo 3
		System.setProperty("javax.net.ssl.trustStorePassword", Utilitario.senhaCertSrv());//Aqui a senha deste keystore
		
		//versao 2.00
		br.inf.portalfiscal.www.nfe.wsdl.nferecepcao2.NfeRecepcao2Stub.NfeCabecMsg cabecalho = new br.inf.portalfiscal.www.nfe.wsdl.nferecepcao2.NfeRecepcao2Stub.NfeCabecMsg();
		cabecalho.setCUF("43");
		cabecalho.setVersaoDados("2.00");

		br.inf.portalfiscal.www.nfe.wsdl.nferecepcao2.NfeRecepcao2Stub.NfeCabecMsgE cabE = new br.inf.portalfiscal.www.nfe.wsdl.nferecepcao2.NfeRecepcao2Stub.NfeCabecMsgE();     
		cabE.setNfeCabecMsg(cabecalho);     
		
		OMElement el = null;
		try {
			el = AXIOMUtil.stringToOM(nfeDadosMsg);
		} catch (XMLStreamException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		el.build();
		System.out.println("el -> " + el.toString());
		
		br.inf.portalfiscal.www.nfe.wsdl.nferecepcao2.NfeRecepcao2Stub.NfeDadosMsg dadosMsg = new br.inf.portalfiscal.www.nfe.wsdl.nferecepcao2.NfeRecepcao2Stub.NfeDadosMsg();
		//dadosMsg.setExtraElement(oNfeDadosMsg.getFirstElement());
		dadosMsg.setExtraElement(el);

		br.inf.portalfiscal.www.nfe.wsdl.nferecepcao2.NfeRecepcao2Stub.NfeRecepcaoLote2Result result = null;
		try {
			result = new br.inf.portalfiscal.www.nfe.wsdl.nferecepcao2.NfeRecepcao2Stub().nfeRecepcaoLote2(dadosMsg, cabE);			
		} catch (AxisFault e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
L

Pessoal, pegando o código do repositório do windows conseguir assinar o aquivo

//  KeyStore ks = KeyStore.getInstance("PKCS11");  
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, certificado.getcertificadoPassword().toCharArray());  
   
Enumeration<String> aliasesEnum = ks.aliases();  
while (aliasesEnum.hasMoreElements()) {    
  String alias = (String) aliasesEnum.nextElement();  
          
  X509Certificate certif = (X509Certificate)ks.getCertificate(alias);  
  System.out.println( "SN =     " + certif.getSerialNumber().toString(16) );  
  System.out.println( "Issuer = " + certif.getIssuerDN().toString() );  
  System.out.println( "subject= " + certif.getSubjectDN().toString() );  
}

Mas, no momento que assinar pede a senha PIN na tela e no momento que tentar enviar para a SEFAZ apresente erro:

; nested exception is:
javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate

F

Pessoal,

Bom dia!

Estou com um problema com o token ikey2032.

Para me conectar a base de dados da empresa naqual trabalho utilizo os progrmas pageantsc e puttysc, no windows xp eu configurava o puttysc com a dll (dkck201.dll) onde tinha a chave do meu Certificado.

Com a nova versão para windows 7 (http://loja.certificadodigital.com.br/Serasa/Instale%20o%20token/D162) Minha chave não reconhece.

Tem como descobrir se há uma nova dll para o windows 7 ?

Agradeço muito a ajuda de vocês.

att.:
Fábio Araújo

F

Consegui…

No Windows XP a DLL que você informava era dkck201.dll, em C:\WINDOWS\system32\ na opção SSH > pkcs11 do Putty.

Para o Windows 7, você terá que informar a dll: eTPKCS11.dll, no mesmo caminho C:\WINDOWS\system32\

Criado 31 de janeiro de 2008
Ultima resposta 2 de set. de 2010
Respostas 28
Participantes 9