The problem I have is that I can sign the XML document, and during the
process, the signature validation is successful. However, once the file is
saved, the validation process throws an exception that says:
org.apache.xml.security.signature.MissingResourceFailureException: The
Reference for URI #SIGNED-PROPS-4ca238b2-09c4-4815-a513-f8ab4042cfed has no
XMLSignatureInput, but the reference exists, and the element with
id=SIGNED-PROPS-4ca238b2-09c4-4815-a513-f8ab4042cfed also exists in the
signed file.
I have a code to sign a xml inovice, here is part of it:
public static boolean Firmar(String nombre_archivo_a_firmar) {
try {
org.apache.xml.security.Init.init();
String dirBase = "/dir_project/";
String keyStoreFilePath = dirBase.concat("certificado.p12");
String filePath = "/tmp/" + nombre_archivo_a_firmar + ".xml";
String signedXmlFilePath = "/tmp/" + nombre_archivo_a_firmar +
"-firmada.xml";
String privateKeyPassword = "passwordCertificado";
String alias = "my name is the alias";
// Cargar el documento XML
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(new
FileInputStream(filePath));
// Establecer el prefijo para el namespace ds
String dsPrefix = "ds";
String dsNamespace = "http://www.w3.org/2000/09/xmldsig#";
ElementProxy.setDefaultPrefix(dsNamespace, dsPrefix);
// Crear un elemento de firma
XMLSignature sig = new XMLSignature(doc, null,
XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
...
// Cargar el almacén de claves (KeyStore)
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream(keyStoreFilePath),
privateKeyPassword.toCharArray());
PrivateKey privateKey = (PrivateKey) ks.getKey(alias,
privateKeyPassword.toCharArray());
X509Certificate cert = (X509Certificate)
ks.getCertificate(alias);
// Añadir las transformaciones necesarias
Transforms transforms = new Transforms(doc);
transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
sig.addDocument("", transforms,
MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256);
// Crear el elemento SignedProperties para XAdES-EPES
Element qualifyingProperties = doc.createElementNS("
http://uri.etsi.org/01903/v1.3.2#", "xades:QualifyingProperties");
qualifyingProperties.setAttribute("Target", "#" + sig.getId());
String signedPropsId = "SIGNED-PROPS-" + UUID.randomUUID();
Element signedProperties = doc.createElementNS("
http://uri.etsi.org/01903/v1.3.2#", "xades:SignedProperties");
signedProperties.setAttributeNS(null,"Id", signedPropsId);
signedProperties.setIdAttribute("Id", true);
...
obj.appendChild(qualifyingProperties);
// Añadir el ObjectContainer a la firma
sig.appendObject(obj);
System.out.println("object lenght: " + sig.getObjectLength());
...
// Agregar la referencia al ObjectContainer en la firma
sig.addDocument("#" + signedPropsId, null,
MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256);
sig.addKeyInfo(cert);
sig.addKeyInfo(cert.getPublicKey());
// Añadir la firma al documento
// Obtener el elemento de la segunda extensión y añadir la firma
Element secondUBLExtensionContent =
findSecondUBLExtension(doc.getDocumentElement());
if (secondUBLExtensionContent != null) {
secondUBLExtensionContent.appendChild(sig.getElement());
} else {
System.out.println("No se pudo encontrar la segunda
extensión UBLExtension.");
return false;
}
...
// Firmar el documento
sig.sign(privateKey);
// Guardar el documento firmado
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(doc), new StreamResult(new
FileOutputStream(signedXmlFilePath)));
// Validar la firma
boolean isValid = sig.checkSignatureValue(cert.getPublicKey());
System.out.println("FIRMA VÁLIDA " + isValid); //The result
here is TRUE - The signature is Valid
// ----- Validation from signed xml file
// Cargar el documento XML firmado para validación
DocumentBuilderFactory dbfVal =
DocumentBuilderFactory.newInstance();
dbfVal.setNamespaceAware(true);
Document signedDoc = dbfVal.newDocumentBuilder().parse(new
FileInputStream(signedXmlFilePath));
// Crear un objeto XMLSignature a partir del elemento Signature
XMLSignature signature = new XMLSignature(signatureElement, "");
// Obtener la clave pública del KeyInfo
KeyInfo keyInfo = signature.getKeyInfo();
if (keyInfo != null) {
System.out.println("clave pública: " +
keyInfo.getPublicKey().toString());
isValid =
signature.checkSignatureValue(keyInfo.getPublicKey());
System.out.println("FIRMA VÁLIDA: " + isValid); //here
launch an exception, it says:
org.apache.xml.security.signature.MissingResourceFailureException: The
Reference for URI #SIGNED-PROPS-... has no XMLSignatureInput
return isValid;
} else {
System.out.println("No se encontró KeyInfo en la firma.");
return false;
}
// return true;
} catch (IOException | ParserConfigurationException | SAXException
| XMLSecurityException | KeyStoreException | NoSuchAlgorithmException |
CertificateEncodingException ex) {
ex.printStackTrace();
} catch (UnrecoverableKeyException | CertificateException ex) {
ex.printStackTrace();
} catch (TransformerConfigurationException ex) {
Logger.getLogger(FirmaAS.class.getName()).log(Level.SEVERE,
null, ex);
} catch (TransformerException ex) {
Logger.getLogger(FirmaAS.class.getName()).log(Level.SEVERE,
null, ex);
}
return false;
}
Thanks for your hel