import java.io.InputStream; import java.io.Serializable; import java.security.KeyStore; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.xml.crypto.dsig.dom.DOMSignContext; 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 org.w3c.dom.Element; //Ref: https://repo1.maven.org/maven2/com/oracle/database/xml/xmlparserv2/21.8.0.0/xmlparserv2-21.8.0.0.jar import oracle.xml.parser.v2.DOMParser; import oracle.xml.parser.v2.XMLDocument; import javax.xml.crypto.dsig.CanonicalizationMethod; import javax.xml.crypto.dsig.DigestMethod; import javax.xml.crypto.dsig.Reference; import javax.xml.crypto.dsig.SignedInfo; import javax.xml.crypto.dsig.Transform; import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignatureFactory; public class SignManager{ private static final String algoritmoSignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; /* * Método para el firmado un XML utilizando un certificado digital (.p12) * @param streamXML InputStream del xml que será firmado. * @param pathCerticate ruta del certificado digital (archivo extension .p12) * @param passwordCertificate contraseña del certificado digital * @param pathFirmado Ruta donde sera almacenado el XML firmado * @throws Exception */ public Element SignXML(InputStream streamXML, InputStream streamCerticate,String passwordCertificate) throws Exception { try { // Creamos un DOM XMLSignatureFactory. Se usará para generar la firma XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA256, null), Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null, null); // Creamos el objeto SignedInfo SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), fac.newSignatureMethod(algoritmoSignatureMethod, null), Collections.singletonList(ref)); // Cargamos el archivo p12 desde disco KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(streamCerticate, passwordCertificate.toCharArray()); String param = ks.aliases().nextElement(); // Extraemos los datos del archivo p12 KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks .getEntry(param, new KeyStore.PasswordProtection(passwordCertificate.toCharArray())); X509Certificate cert = (X509Certificate) keyEntry.getCertificate(); KeyInfoFactory kinfoFactory = fac.getKeyInfoFactory(); // Cargamos nuestro certificado List x509Content = new ArrayList(); x509Content.add(cert); // Objetos para extraer la llave privada X509Data x509d = kinfoFactory.newX509Data(x509Content); KeyInfo kinfo = kinfoFactory.newKeyInfo(Collections.singletonList(x509d)); DOMParser parser = new DOMParser(); parser.setPreserveWhitespace(false); parser.parse(streamXML); XMLDocument xml =parser.getDocument(); Element xmlRoot = xml.getDocumentElement(); // Crea el contexto de firmma y especifica las llaves privadas DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), xmlRoot); // crea los nodos de firmas xml XMLSignature signature = fac.newXMLSignature(si, kinfo); // en esta etapa dsc modifica el objeto xmlRoot insertándole la firma signature.sign(dsc); return xmlRoot; } catch (Exception e) { throw e; } } }