Hello. I developed a Java software to send invoices to Thema (Cachoeirinha / RS) and I received the error message E515, stating that the Shipment was tampered with, ie the .xml file was changed after the signature. The problem is that nothing is done after signing. The file is only called again to be sent to city hall.
How it's signed:
public static void assinarXML(String aliasCertificado, int codLancamento, TiposKeyStore tipoKeystore, String caminhoXML, String tagParaAssinar, String tagParaAssinar2, long loteRps, NFSeParametrosDAO nfseparametrosDAO) throws Exception {
OutputStream os = new FileOutputStream(new File(caminhoXML.substring(0, caminhoXML.length()-4) + "Assinado.xml" ));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.parse(new FileInputStream(caminhoXML));
char[] senhaCertificado = "".toCharArray();
String alias = aliasCertificado;
dbf.setNamespaceAware(true);
KeyStore ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
List<String> optionList = new ArrayList<String>();
ks.load(null, null);
Enumeration<String> aliasEnum = ks.aliases();
while (aliasEnum.hasMoreElements()) {
String aliasKey = (String) aliasEnum.nextElement();
if (ks.isKeyEntry(aliasKey)) {
System.out.println(aliasKey);
optionList.add(aliasKey);
}
}
alias = "";
try {
Object[] options = optionList.toArray();
if (alias.equals("")){
Object value = JOptionPane.showInputDialog(null,
"Escolha o Certificado",
"Certificados",
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
alias = value.toString();
nfseparametrosDAO.updateAliasCertificado(codLancamento, alias);
}
if (ks.getEntry(alias, new KeyStore.PasswordProtection(senhaCertificado ))==null){
throw new Exception("O Certificado Parametrizado não foi encontrado");
}
} catch (IOException e) {
throw new Exception("Senha do Certificado Digital incorreta ou Certificado inválido.");
}
KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry)
ks.getEntry(alias, new KeyStore.PasswordProtection(senhaCertificado));
NodeList elements = doc.getElementsByTagName(tagParaAssinar);
org.w3c.dom.Element el = (org.w3c.dom.Element) elements.item(0);
org.w3c.dom.Element el2 = null;
el.setAttribute("Id", String.valueOf(loteRps));
String id = el.getAttribute("Id");
el.setIdAttribute("Id", true);
if (!tagParaAssinar2.equals("")){
NodeList elements2 = doc.getElementsByTagName(tagParaAssinar2);
el2 = (org.w3c.dom.Element) elements2.item(0);
el2.setAttribute("Id", "L" + String.valueOf(loteRps));
el2.setIdAttribute("Id", true);
id = el2.getAttribute("Id");
}
DOMSignContext dsc = null;
DOMSignContext dsc1 = null;
if (tagParaAssinar2.equals("")){
dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getElementsByTagName(tagParaAssinar).item(0));
}else{
dsc = new DOMSignContext(keyEntry.getPrivateKey(), el);
dsc1 = new DOMSignContext(keyEntry.getPrivateKey(), el2);
}
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
List transforms = new ArrayList();
transforms.add(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null));
transforms.add(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null));
Reference ref = fac.newReference("#" + id,
fac.newDigestMethod(DigestMethod.SHA1, null),
transforms, null, null);
SignedInfo si = fac.newSignedInfo(
fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null),
fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref));
KeyInfoFactory kif = fac.getKeyInfoFactory();
List x509Content = new ArrayList();
x509Content.add(keyEntry.getCertificate());
X509Data kv = kif.newX509Data(x509Content);
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));
XMLSignature signature = fac.newXMLSignature(si, ki, null, "Ass_Lote" + loteRps, null );
if (!tagParaAssinar2.equals("")){
signature.sign(dsc1);
}
signature.sign(dsc);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
trans.transform(new DOMSource(doc), new StreamResult(os));
os.close();
}
How it is sent:
public String enviarXMLThema(String caminhoXML, int codLancamento, String basedados, String servidor) {
String ret = "";
try{
NFSeParametrosDAO nfseparametrosdao = new NFSeParametrosDAO(servidor, "5432", basedados, "postgres", "");
String endpoint = nfseparametrosdao.getUrlWsdl(codLancamento, "EnviarRps");
if (endpoint.equals("")){
JOptionPane.showMessageDialog(null, "Não foi localizada a URL para envio do Arquivo XML");
System.exit(0);
}
Service service = new Service();
Call call = (Call) service.createCall();
call.setSOAPActionURI(nfseparametrosdao.getMetodoServico(codLancamento, "EnviarRps"));
call.setTargetEndpointAddress(new java.net.URL(endpoint) );
String namespace = "";
namespace = nfseparametrosdao.getNamespaceServico(codLancamento, "EnviarRps");
String servico = "";
servico = nfseparametrosdao.getServico(codLancamento, "EnviarRps");
call.setOperationName(new QName(namespace, servico));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.parse(new FileInputStream(caminhoXML));
DOMSource domSource = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
String xml = writer.toString();
System.out.println("Inicio WS Envio: " + new Date());
ret = (String) call.invoke( new Object[] {xml} );
System.out.println("Fim WS Envio: " + new Date());
System.out.println("Resposta:/n" + ret);
} catch (Exception e) {
System.out.println("Fim WS Envio Erro: " + new Date());
JOptionPane.showMessageDialog(null, "Exception:" + e.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
ALLogger.getInstance().error(sw.toString());
e.printStackTrace();
System.exit(0);
}
return ret;
}
Between Signature and Submission it goes through this part of the code, which in this case only transfers the parameters from one object to another:
tela.setStatus("Gerando XML Assinado...");
AssinarXML.assinarXML(aliasCertificado, codLancamento, TiposKeyStore.PKCS12, savePath + "enviaRPS" + String.valueOf(codLancamento) + ".xml", "EnviarLoteRpsEnvio", "", Long.parseLong(String.valueOf(nfse.getLoterps())), nfseparametrosdao);
tela.setStatus("Conectando ao Web Service...");
WsClient ws = new WsClient();
String CaminhoXML = savePath + "enviaRPS" + nfse.getCodlancamento() + "Assinado.xml";
String xmlString = ws.enviarXMLThema(CaminhoXML, nfse.getCodlancamento(), basedados, servidor);
The signed .xml is not saved anywhere except the "Xml ()" sign, so I do not understand what might be causing this adulteration.