Assinatura de nota Fiscal Eletronica

4 respostas
G

Olá a todos.

Eu estou desenvolvendo um tipo de envio de Nota Fiscal Eletrônica, consegui criar o XML, assinar o conteúdo total do XML porém não consigo fazer uma assinatura que fica no meio do corpo XML. Estou o dia inteiro buscando somente este ítem. Meu xml está assim:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header/> 
<soapenv:Body>
<e:EnviarLoteRpsEnvio xmlns:e="http://www.betha.com.br/e-nota-contribuinte-ws">
  <LoteRps Id="Lote5724">
    <NumeroLote>5724</NumeroLote>
    <Cnpj>02762121000449</Cnpj>
    <InscricaoMunicipal>265958</InscricaoMunicipal>
    <QuantidadeRps>1</QuantidadeRps>
    <ListaRps>
      <Rps>
        <InfRps Id="Rps5724">
            ......
        </InfRps>
      </Rps>
    </ListaRps>
  </LoteRps>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="#Rps5724">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>Q0Y1jQ+6GhKFBiFxh+PJcnn9hCg=</DigestValue>
</Reference>
<Reference URI="#Lote5724">
<Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>c+F1B/1qsr8MIdg7iOHFB39eMpE=</DigestValue></Reference>
</SignedInfo><SignatureValue>nhaaZRSRSxY49G6/bPq8B15avDY7F5XC2xJ1kOtagRoGRX17cz+jSQF39BubIE1gZv+6RoiFSzr9
NZ4/1nKnA2OXQJ1P5s9Jdt7skthxLdNGqE4r6vNeH/8ImeTzBo9mcVxozFNWo4fMHFE+coCF2MO1
rXECRAgNjXr1d/FIfk4=</SignatureValue><KeyInfo><X509Data><X509Certificate>MIIGMTCCBRmgAwIBAgIIGN1dKE9CR+UwDQYJKoZIhvcNAQEFBQAwTDELMAkGA1UEBhMCQlIxEzAR
BgNVBAoTCklDUC1CcmFzaWwxKDAmBgNVBAMTH1NFUkFTQSBDZXJ0aWZpY2Fkb3JhIERpZ2l0YWwg
djEwHhcNMTEwNzE5MTMwNjUyWhcNMTIwNzE4MTMwNjUyWjCB6zELMAkGA1UEBhMCQlIxEzARBgNV
BAoTCklDUC1CcmFzaWwxFDASBgNVBAsTCyhFTSBCUkFOQ08pMRgwFgYDVQQLEw8wMDAwMDEwMDE5
ODIyNTYxFDASBgNVBAsTCyhFTSBCUkFOQ08pMRQwEgYDVQQLEwsoRU0gQlJBTkNPKTEUMBIGA1UE
CxMLKEVNIEJSQU5DTykxFDASBgNVBAsTCyhFTSBCUkFOQ08pMRQwEgYDVQQLEwsoRU0gQlJBTkNP
KTEpMCcGA1UEAxMgU0FOVE9TIEJSQVNJTCBQQVJUSUNJUEFDT0VTIFMuQS4wgZ8wDQYJKoZIhvcN
AQEBBQADgY0AMIGJAoGBAOQ0nDNNXDLQZjYVWKPCO2UK5dgrogji1UB6TIOztlw11TJovP/qmlhy
NqhJCbl14mrfoMeH+1LCzgEct/68RrG57VRmliDApSnXwhrrLMYMmTLQvvYrrTMawe0kiUYeWQXt
DxKRQn4EfVYtiOcBYL4+F47Wx36J9UgZjzuSk8dxAgMBAAGjggL5MIIC9TAOBgNVHQ8BAf8EBAMC
BeAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB8GA1UdIwQYMBaAFLdgqFv5sqauAO10
69VKyZZoZvVcMIG8BgNVHREEgbQwgbGBF1JBRkBTQU5UT1NCUkFTSUwuQ09NLkJSoD0GBWBMAQME
oDQTMjEzMDgxOTY3MDU3NjQzMDk4NjcwMDAwMDAwMDAwMDAwMDAwMDAxMzk5ODU5NVNTUFNQoCMG
BWBMAQMCoBoTGFJJQ0FSRE8gQUJCUlVaWklOSSBGSUxIT6AZBgVgTAEDA6AQEw4wMjc2MjEyMTAw
MDEwNKAXBgVgTAEDB6AOEwwwMDAwMDAwMDAwMDAwVwYDVR0gBFAwTjBMBgZgTAECAQYwQjBABggr
BgEFBQcCARY0aHR0cDovL3d3dy5jZXJ0aWZpY2Fkb2RpZ2l0YWwuY29tLmJyL3JlcG9zaXRvcmlv
L2RwYzCB8AYDVR0fBIHoMIHlMEmgR6BFhkNodHRwOi8vd3d3LmNlcnRpZmljYWRvZGlnaXRhbC5j
b20uYnIvcmVwb3NpdG9yaW8vbGNyL3NlcmFzYWNkdjEuY3JsMEOgQaA/hj1odHRwOi8vbGNyLmNl
cnRpZmljYWRvcy5jb20uYnIvcmVwb3NpdG9yaW8vbGNyL3NlcmFzYWNkdjEuY3JsMFOgUaBPhk1o
dHRwOi8vcmVwb3NpdG9yaW8uaWNwYnJhc2lsLmdvdi5ici9sY3IvU2VyYXNhL3JlcG9zaXRvcmlv
L2xjci9zZXJhc2FjZHYxLmNybDCBlwYIKwYBBQUHAQEEgYowgYcwRwYIKwYBBQUHMAKGO2h0dHA6
Ly93d3cuY2VydGlmaWNhZG9kaWdpdGFsLmNvbS5ici9jYWRlaWFzL3NlcmFzYWNkdjEucDdiMDwG
CCsGAQUFBzABhjBodHRwOi8vb2NzcC5jZXJ0aWZpY2Fkb2RpZ2l0YWwuY29tLmJyL3NlcmFzYWNk
djEwDQYJKoZIhvcNAQEFBQADggEBAIvcpJ6piK2j8pKl/4wF7zY4ISRYYJhX6x3Jd3OtKyRLkMa9
kaNczv3kvitVywZwcSTYFx+rVDCGhIM80ZAo29XHUbdy/wscLEioQ/rz644SQ4NHuDo6KiG4Vjy0
BR2iST5UsRlQ9yS2YXPRFi+R3UviHmfvoXBHy3H4joNAJJ4U0yS4PFRHB36V32Pd3iQf30hdzdzM
V9CG6yyK6N5qNa9QkZBOpHRmHuiu8AMpLnoH+DF+v7D5pXs+f0l/DVspuSiCREYVTFO1KH97AKVw
QOlRucdhkF2WWTaTU2KiAFOgIx8/LoZDeqZvv6Pg9Sbn5i59vHwPFA3dknZB0ftUz9s=</X509Certificate></X509Data></KeyInfo></Signature></e:EnviarLoteRpsEnvio>

Porém, como podem observar, existe a URI Rps. De acordo com o exemplo que me foi passado, tenho que assinar o final do arquivo e cada Rps.
Como fazer isso?

Meu código:
String result = "";
        KeyStore ks;
        KeyInfo ki=null;
        KeyStore.PrivateKeyEntry keyEntry = null;
        
        try {
            ks = KeyStore.getInstance("JKS");

            ks.load(new FileInputStream(arquivo), senhaArquivo.toCharArray());

            keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry (chave, new KeyStore.PasswordProtection(senhaChave.toCharArray()));
                        
            X509Certificate cert = (X509Certificate) keyEntry.getCertificate();

            // Create the KeyInfo containing the X509Data.
            KeyInfoFactory kif = fac.getKeyInfoFactory();
            List x509Content = new ArrayList();   
            x509Content.add(cert.getSubjectX500Principal().getName());
            x509Content.add(cert);
            X509Data xd = kif.newX509Data(x509Content);
            ki = kif.newKeyInfo(Collections.singletonList(xd));
             
        }

        catch (KeyStoreException ex) {
            Logger.getLogger(AssinaturaRsa.class.getName()).log(Level.SEVERE, null, ex);
        }        catch (IOException ex) {
            Logger.getLogger(AssinaturaRsa.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(AssinaturaRsa.class.getName()).log(Level.SEVERE, null, ex);
        } catch (CertificateException ex) {
            Logger.getLogger(AssinaturaRsa.class.getName()).log(Level.SEVERE, null, ex);
        }        catch (UnrecoverableEntryException ex) {
            Logger.getLogger(AssinaturaRsa.class.getName()).log(Level.SEVERE, null, ex);
        } 
        
        // Instantiate the document to be signed.
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);

        Document doc = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(corpo.getBytes("UTF-8")));
        
        // Create a DOMSignContext and specify the RSA PrivateKey and
        // location of the resulting XMLSignature's parent element.
        DOMSignContext dsc = new DOMSignContext
            (keyEntry.getPrivateKey(), doc.getDocumentElement());
        // Create the XMLSignature, but don't sign it yet.
        XMLSignature signature = fac.newXMLSignature(si, ki);
        
        // Marshal, generate, and sign the enveloped signature.
        signature.sign(dsc);

        OutputStream f2 = new ByteArrayOutputStream();
        //OutputStream f2 = new ByteOutputStream();
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); 
        trans.transform(new DOMSource(doc), new StreamResult(f2));

        if (cabecalho) result =  "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"> <soapenv:Header/> \n";
        //xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance
        if (cabecalho)result += "<soapenv:Body>\n";

        result += f2.toString();

        if (cabecalho)result += "\n</soapenv:Body>\n";
        if (cabecalho)result += "</soapenv:Envelope>";

        return result;
Trecho que cria as URIs:
// Criação do DOM XMLSignatureFactory será usado
        // na criação do envelope de assinatura.
        fac = XMLSignatureFactory.getInstance("DOM");

        // Criando a referencia para o envelope da assinatura
        
        List<Reference> ref = new ArrayList<Reference>();
       
        
        try {
            ArrayList transformList = new ArrayList();
            TransformParameterSpec tps = null; 
            Transform envelopedTransform = fac.newTransform(Transform.ENVELOPED, tps);
            Transform c14NTransform = fac.newTransform("http://www.w3.org/TR/2001/REC-xml-c14n-20010315",tps);
            transformList.add(envelopedTransform);
            transformList.add(c14NTransform);

            for (String n : nos){
                ref.add(fac.newReference
                    ((n.equals("")?"":"#") + n, fac.newDigestMethod(DigestMethod.SHA1, null),
                    transformList,null,null));
            }
            // Criação do SignedInfo.
            si = fac.newSignedInfo
                    (fac.newCanonicalizationMethod
                    (CanonicalizationMethod.INCLUSIVE,
                    (C14NMethodParameterSpec) null),
                    fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
                    ref);

        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(AssinaturaRsa.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidAlgorithmParameterException ex) {
            Logger.getLogger(AssinaturaRsa.class.getName()).log(Level.SEVERE, null, ex);
        }

4 Respostas

L

gsfteodoro,

Essel link pode te ajudar: http://www.javac.com.br/jc/posts/list/106-nfe-assinatura-dos-xmls-de-envio-de-lote-cancelamento-e-inutilizacao-certificado-a1.page.

G

Fala luiz_renato.

Então, como disse, consigo assinar o XML.
O Problema é que tenho que assinar um conteúdo de dentro do XML e o XML inteiro, ou seja, haverão duas assinaturas.

Mas obrigado mesmo assim.

G

Então, na sua rotina que assina o xml, você deve estar passando uma String(todo conteudo do xml) como parametro para a função, certo ?
Você precisa pegar somente a parte do xml que diz respeito a RPS, e passar para esta mesma função, repetindo a operação para cada RPS do seu lote. Ao final, você junta tudo e assina novamente.

G

Entendi, guimoz.

Pensei que poderia haver outra forma… Vou Fazer assim então. Obrigado pela força.

Criado 20 de julho de 2011
Ultima resposta 20 de jul. de 2011
Respostas 4
Participantes 3