Assinatura de nota Fiscal Eletronica

4 respostas
gsfteodoro

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

luiz_renato

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.

gsfteodoro

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.

gsfteodoro

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