Bom, incrível como a comunidade java é desunida, aposto que muitos já conseguiram solucionar este problema , mas cada um que se vire né?!
Nem adianta falar que já postou que resolveu utilizando isso ou aquilo. Fazer somente isso e nada é a mesma coisa. Como diz Linus Torvalds: “show me the code”.
Pois eh galera, sobre este erro, o meu XML não continha os caracteres de edição conforme o SCAN validara (isso mesmo, essa rejeição só aparecia no ambiente de homologação do SCAN).
Como sempre, a SEFAZ não respondeu à minhas dúvidas e tive que me virar - novamente…
O problema de rejeição 588 só acontecia porque o algorítimo e componentes que utilizava para assinar (ou assassinar[i], como preferir…) o XML gerava a assinatura com caracteres de quebra de linha entre as tags internasdo elemento <signature>. Os valores das tags de assinatura podem ter quebras de linha ("\n") normalmente, mas entre as tags JAMAIS isso deve acontecer.
Enfim, utilizava a api Apache org.apache.xml.security para assinar (com o erro) e substitui o código pelos componentes do próprio java (javax.xml.crypto.dsig) e a coisa funfou…
No meu caso eu utilizo o HSM para manter o certificado mas depois de obtido, não muda em nada para quem adota outros modelos de certificados.
Final Code:
//Assina o xml da nota....o parâmetro xml contém todo o arquivo xml <NFe>...</NFe> preenchido
//O parâmetro tagname contém o nome da tag infNFe e o parâmetro nome possui o cnpj do emitente para que seja possível
//encontrar o certificado do cnpj no cache....
// O restante é bem legível
private static String signX(String xml, String tagname, String nome) throws Exception {
//Converte a string do xml em um objeto Document
Document document = DOMUtils.stringToDocument(xml);
Key key = KeyStoreBuilder.get(nome).getKey();
X509Certificate x509Certificate = getCertificadoDoBuffer(nome);
XMLSignatureFactory sf = XMLSignatureFactory.getInstance("DOM");
List<Transform> lt = new ArrayList<Transform>();
Node infNFe = document.getElementsByTagName(tagname).item(0);
((Element)infNFe).setIdAttribute("Id", true);
String id = "#"+infNFe.getAttributes().getNamedItem("Id").getNodeValue();
lt.add(sf.newTransform("http://www.w3.org/2000/09/xmldsig#enveloped-signature", (TransformParameterSpec) null));
lt.add(sf.newTransform("http://www.w3.org/TR/2001/REC-xml-c14n-20010315", (TransformParameterSpec) null));
Reference ref = sf.newReference(id, sf.newDigestMethod("http://www.w3.org/2000/09/xmldsig#sha1", null), lt, null, null);
SignedInfo si = sf.newSignedInfo(sf.newCanonicalizationMethod("http://www.w3.org/TR/2001/REC-xml-c14n-20010315", (C14NMethodParameterSpec) null), sf.newSignatureMethod("http://www.w3.org/2000/09/xmldsig#rsa-sha1", null), Collections.singletonList(ref));
KeyInfoFactory kif = sf.getKeyInfoFactory();
X509Data data = kif.newX509Data(Collections.singletonList(x509Certificate));
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(data));
DOMSignContext sc = new DOMSignContext(key, document.getDocumentElement());
javax.xml.crypto.dsig.XMLSignature signature = sf.newXMLSignature(si, ki);
signature.sign(sc);
//Obtem somente o conteúdo da tag <signature> da estrutura Documento - neste ponto ela já foi gerada.
//Converte o conteúdo da assinatura <signature> em string e devolve apenas a string da assinatura para o cliente - esta é a minha necessidade, pode não ser a sua!
return DOMUtils.nodeToString(document.getDocumentElement().getElementsByTagName("Signature").item(0));
}
Espero ter ajudado. Vou almoçar!!
bye!