Falha no XML da cartão de correção - Assinatura do XML [RESOLVIDO]

Gujeiros boa tarde…hehe

Estou tentando assinar um xml referênte à nota fiscal eletrônica(NF-e). Para ser mais exato, trata-se do xml da carta de correção eletrônica (CC-e).

Tenho uma aplicaçãozinha aqui que assina todos os xml da Nfe (inutilização, cancelamento, etc), mas não está assinando o da CCe (talvez pelo mal formato do arquivo xml da carta de correção).

Vou postar a classe em java que faz o processo de assinatura, postando também o XML da CCe que estou na luta pra assinar…hehe

Segue:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package assinador;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.Provider;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 *
 * @author Albert Eije
 */
public class Assinador {

	private static final String C14N_TRANSFORM_METHOD = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
	private static final String PROVIDER_CLASS_NAME = "org.jcp.xml.dsig.internal.dom.XMLDSigRI";
	private static final String PROVIDER_NAME = "jsr105Provider";

	public void assinar(String arquivoXML, String arquivoCertificado,
			  String password, String arquivoXMLNovo, String operacao) throws Exception {

		/*
		operacao
		'1' - NFE
		'2' - CANCELAMENTO
		'3' - INUTILIZACAO
		 */
		String tag = "";
		if (operacao.equals("1")) {
			tag = "infNFe";
		} else if (operacao.equals("2")) {
			tag = "infCanc";
		} else if (operacao.equals("3")) {
			tag = "infInut";
		}
                else if (operacao.equals("4"))
                    tag = "infEvento";

		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setNamespaceAware(false);
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document docs = builder.parse(new File(arquivoXML));
		NodeList elements = docs.getElementsByTagName(tag);
		Element el = (Element) elements.item(0);
		String id = el.getAttribute("Id");

		// Cria um DOM do tipo XMLSignatureFactory que será utilizado
		// para gerar a assinatura envelopada (enveloped signature)
		String providerName = System.getProperty(PROVIDER_NAME,
				  PROVIDER_CLASS_NAME);

		XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM",
				  (Provider) Class.forName(providerName).newInstance());

		// Define os algoritmos de transformação
		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);

		// Cria o objeto Reference
		Reference ref = fac.newReference("#" + id, fac.newDigestMethod(
				  DigestMethod.SHA1, null), transformList, null, null);

		// Cria o elemento SignedInfo
		SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(
				  CanonicalizationMethod.INCLUSIVE,
				  (C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
				  Collections.singletonList(ref));

		// Carrega o KeyStore e obtem a chave do certificado
		KeyStore ks = KeyStore.getInstance("PKCS12");
		ks.load(new FileInputStream(arquivoCertificado), password.toCharArray());
		Enumeration aliasesEnum = ks.aliases();
		String alias = "";
		while (aliasesEnum.hasMoreElements()) {
			alias = (String) aliasesEnum.nextElement();
			if (ks.isKeyEntry(alias)) {
				break;
			}
		}

		KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(alias, new KeyStore.PasswordProtection(password.toCharArray()));

		// Instancia um certificado do tipo X509
		X509Certificate cert = (X509Certificate) keyEntry.getCertificate();

		// Cria o elemente KeyInfo contendo a X509Data.
		KeyInfoFactory kif = fac.getKeyInfoFactory();
		List x509Content = new ArrayList();
		x509Content.add(cert);
		X509Data xd = kif.newX509Data(x509Content);
		KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));

		// Instancia o documento que será assinado
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setNamespaceAware(true);
		Document doc = dbf.newDocumentBuilder().parse(
				  new FileInputStream(arquivoXML));

		// Cria o DOMSignContext especificando a chave e o nó pai
		DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getDocumentElement());

		// Cria a XMLSignature, mas não assina ainda
		XMLSignature signature = fac.newXMLSignature(si, ki);

		// Empacota (marshal), gera e assina
		signature.sign(dsc);

		// Arquivo novo assinado
		OutputStream os = new FileOutputStream(arquivoXMLNovo);
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer trans = tf.newTransformer();
		trans.transform(new DOMSource(doc), new StreamResult(os));

		// Encontra o elemente Signature
		NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS,
				  "Signature");

		if (nl.getLength() == 0) {
			throw new Exception("Não foi possível encontrar o elemente Signature");
		}

		// Cria um DOMValidateContext
		DOMValidateContext valContext = new DOMValidateContext(
				  new X509KeySelector(ks), nl.item(0));

		// Dsempacota (unmarshal) a XMLSignature
		XMLSignature signatures = fac.unmarshalXMLSignature(valContext);

		// Valida a XMLSignature.
		boolean coreValidity = signatures.validate(valContext);

		// Checa o status da validação
		if (coreValidity == false) {
			System.err.println("Falha na Assinatura!");
		} else {
			System.out.println("Assinatura Correta!");
		}
	}

	public static void main(String[] args) throws Exception {

		/*if (args.length != 5) {
			System.out.println("Passe os cinco parâmetros necessários");
			return;
		}*/
		String caminhoXml = "D:\\XML-LoteCCe-1.xml";
		String caminhoCertificado = "D:/thiago_beserra/certificados_a1/cert_e/dzyon.pfx";
		String senha = "***";
		String arquivoXmlNovo = "D:\\XML-ped-inu-ass.xml";
		String tipo = "4";

		File file = new File(caminhoXml);
		if (!file.exists()) {
			System.out.println("Arquivo " + caminhoXml + " não encontrado!");
			return;
		}
		file = new File(caminhoCertificado);
		if (!file.exists()) {
			System.out.println("Arquivo " + caminhoCertificado + " não encontrado!");
			return;
		}
		try {
			Assinador t = new Assinador();
			t.assinar(caminhoXml, caminhoCertificado, senha, arquivoXmlNovo,
					  tipo);
			System.out.println("Arquivo XML assinado com sucesso" + caminhoXml + "!");
		} catch (Exception e) {
			System.out.println("Erro ao tentar assinar arquivo XML! \n\n" + e.toString());
		}
	}
}

Agora o XML CCe:

<envEvento versao="1.00" xmlns="http://www.portalfiscal.inf.br/nfe">
<idLote>000000000015255</idLote>
<evento versao="1.00" xmlns="http://www.portalfiscal.inf.br/nfe">
<infEvento Id="ID1101103511031029073900013955001000000001105112804108">
<cOrgao>35</cOrgao>
<tpAmb>2</tpAmb>
<CNPJ>10290739000139</CNPJ>
<chNFe>35110310290739000139550010000000011051128041</chNFe>
<dhEvento>2011-03-03T08:06:00-03:00</dhEvento>
<tpEvento>110110</tpEvento>
<nSeqEvento>8</nSeqEvento>
<verEvento>1.00</verEvento>
<detEvento versao="1.00">
<descEvento>Carta de Correcao</descEvento>
<xCorrecao>Texto de teste para Carta de Correcao. Conteudo do campo xCorrecao.</xCorrecao>
<xCondUso>A Carta de Correcao e disciplinada pelo 1o-A do art. 7o do Convenio SN, de 15 de dezembro de 1970 e pode ser utilizada para regularizacao de erro ocorrido na emissao de documento fiscal, desde que o erro nao esteja relacionado com: I - as variaveis que determinam o valor do imposto tais como: base de calculo, aliquota, diferenca de preco, quantidade, valor da operacao ou da prestacao; II - a correcao de dados cadastrais que implique mudanca do remetente ou do destinatario; III - a data de emissao ou de saida.</xCondUso>
</detEvento>
</infEvento>

E o bendito erro que aparece na console do netbeans…hehe

Erro ao tentar assinar arquivo XML! 
[Fatal Error] XML-LoteCCe-1.xml:19:1: As estruturas do documento XML devem começar e terminar com a mesma entidade.

org.xml.sax.SAXParseException; systemId: file:/D:/XML-LoteCCe-1.xml; lineNumber: 19; columnNumber: 1; As estruturas do documento XML devem começar e terminar com a mesma entidade.
CONSTRUÍDO COM SUCESSO (tempo total: 0 segundos)

Ressaltando que, o xml foi pego na web, ou seja, do jeito que baixei ele já mandei pra aplicação…=)

Creio que é problema no schema do XML que estou usando…

Se alguem tiver algum xml da CCe, fico grato.

Desde já, obrigado! :smiley:

está meio óbvio…

As estruturas do documento XML devem começar e terminar com a mesma entidade.

Esse xml começa com a tag e termina com a tag

Acredito que só falta fechar as tags: .

[quote=andreiribas]está meio óbvio…

As estruturas do documento XML devem começar e terminar com a mesma entidade.

Esse xml começa com a tag e termina com a tag

Acredito que só falta fechar as tags: .

[/quote]

E como estava óbvio, andreiribas…hehe
minha mente ontem não tava servindo pra nada…
mandei as tags , conforme você falo e pronto, XML assinado!

Valeu pela dica, RESOLVIDO! XD