org.viafirma.util.XmlSignUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.viafirma.util.XmlSignUtil.java

Source

/* Copyright (C) 2007 Flix Garca Borrego (borrego at gmail.com)
      
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
      
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.
      
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
   MA 02111-1307, USA 
 */

package org.viafirma.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
import org.apache.xml.security.exceptions.Base64DecodingException;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.keys.keyresolver.KeyResolverException;
import org.apache.xml.security.signature.ObjectContainer;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.signature.XMLSignatureException;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.XMLUtils;
import org.apache.xpath.XPathAPI;
import org.viafirma.cliente.exception.InternalException;
import org.viafirma.cliente.firma.TypeFile;
import org.viafirma.cliente.firma.TypeFormatSign;
import org.viafirma.excepciones.CodigoError;
import org.viafirma.excepciones.ExcepcionCertificadoNoEncontrado;
import org.viafirma.excepciones.ExcepcionErrorInterno;
import org.viafirma.excepciones.ExcepcionManejoCertificado;
import org.viafirma.nucleo.validacion.KeyStoreLoader;
import org.viafirma.vo.Documento;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * Contiene los mtodos de utilidad para manejar XmlSignatures.
 * 
 * Recupera el certificado desde un xmlSign codificado en Base64. Obtiene los
 * datos contenidos dentro de un XmlSignature de tipo Enveloped.
 * 
 * 
 * @author Felix Garcia Borrego (borrego at gmail.com)
 * @author Alexis Castilla Armero (Pencerval at gmail.com)
 */
public class XmlSignUtil {

    private Log log = LogFactory.getLog(XmlSignUtil.class);

    private static String BaseURI = "signature.xml";

    private static XmlSignUtil singleton;

    // private XPathFactory xPathFactory;

    public static XmlSignUtil getInstance() {
        if (singleton == null) {
            singleton = new XmlSignUtil();
        }
        return singleton;
    }

    /**
     * 
     */
    private XmlSignUtil() {
        // singleton.
        // xPathFactory = XPathFactory.newInstance();
    }

    /**
     * Recupera el certificado parseando un String (Base64) Recupera el
     * XmlSignature y delega en getCertificado(XMLSignature signature)
     * 
     * @param xmldoc_b64
     * @return Certificado del usuario
     * @throws ExcepcionErrorInterno
     * @throws ExcepcionManejoCertificado
     * @throws ExcepcionCertificadoNoEncontrado
     * @throws ExcepcionManejoCertificado
     *             Error al procesar el certificado dentro del xmls
     * @throws ExcepcionCertificadoNoEncontrado
     *             No hay certificado
     */
    public List<X509Certificate> parseCertificado(String xmldoc_b64)
            throws ExcepcionErrorInterno, ExcepcionCertificadoNoEncontrado, ExcepcionManejoCertificado {
        List<X509Certificate> listCertificados = new LinkedList<X509Certificate>();
        Document documento = getDocumentFromBase64(xmldoc_b64);
        // recupera los XMLSignature almacenados en el documento
        List<XMLSignature> signatureList = getXMLSignatureFormDocument(documento);
        // Para cada elemento recuperamos su certificado asociado.
        for (XMLSignature signature : signatureList) {
            listCertificados.add(getX509(signature));
        }
        return listCertificados;
    }

    /**
     * Parsea el XML y recupera el xmlsignature 1.- Decodifica el string en
     * base64 para obtener el xml. 2.- Parsea el xml para obtener un DOM ( NOTA:
     * este punto se puede obtimizar en el futuro para que utilize SAX. 3.-
     * Retorna el objeto XMLSignature que contiene el restultado de la firma( o
     * autenticacin)
     * 
     * @param xmldoc_b64
     *            xml en Base64
     * @return Documento que contiene el resultado de la firma o autenticacin.
     * @throws ExcepcionManejoCertificado
     *             No se puede recuperar el certificado
     */
    public Document getDocumentFromBase64(String xmldoc_b64) throws ExcepcionErrorInterno {
        // Obtenemos el String con el XML desde el String base 64
        String xmlDoc;
        try {
            xmlDoc = new String(org.apache.xml.security.utils.Base64.decode(xmldoc_b64), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            // no se ha podido decodificar la base64. el usuario no esta
            // enviando un certificdo valido
            throw new ExcepcionErrorInterno("Conjunto de caracteres no soportado", e);
        } catch (Base64DecodingException e) {
            // no se ha podido decodificar la base64.el usuario no esta enviando
            // un certificado valio
            throw new ExcepcionErrorInterno("Error al decodificar Base64", e);
        }

        if (log.isDebugEnabled()) {
            log.debug("XMLSign:" + xmlDoc);
        }
        return parseDocument(xmlDoc);
    }

    /**
     * Parsea un String que contiene un XmlSignature retornando la estructura
     * XMLSignature.
     * 
     * @param xmlDoc
     * @return
     * @throws ExcepcionManejoCertificado
     */
    public Document parseDocument(String xmlDoc) throws ExcepcionErrorInterno {
        StringReader readerXml = new StringReader(xmlDoc);
        return parseDocument(readerXml);
    }

    /**
     * Parsea un String que contiene un XmlSignature retornando la estructura
     * XMLSignature.
     * 
     * @param xmlDoc
     * @return
     * @throws ExcepcionManejoCertificado
     */
    public Document parseDocument(InputStream input) throws ExcepcionErrorInterno {
        InputStreamReader readerXml = new InputStreamReader(input);
        return parseDocument(readerXml);
    }

    /**
     * Parsea un String que contiene un XmlSignature retornando la estructura
     * XMLSignature.
     * 
     * @param xmlDoc
     * @return
     * @throws ExcepcionManejoCertificado
     */
    public Document parseDocument(byte[] input) throws ExcepcionErrorInterno {
        InputStreamReader readerXml = new InputStreamReader(new ByteArrayInputStream(input));
        return parseDocument(readerXml);
    }

    /**
     * Parsea el xml asociado
     * 
     * @param xmldoc_b64 
     * @return
     * @throws ExcepcionManejoCertificado
     */
    public Document parseDocument(Reader readerXml) throws ExcepcionErrorInterno {
        try {
            // parser
            InputSource ioXml = new InputSource(readerXml);
            // InputStream in=ioXml.getByteStream();
            javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            dbf.setAttribute("http://xml.org/sax/features/namespaces", Boolean.TRUE);
            dbf.setValidating(false);
            javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder();
            org.w3c.dom.Document doc = db.parse(ioXml);
            return doc;
        } catch (ParserConfigurationException e) {
            throw new ExcepcionErrorInterno("ParserConfigurationException", e);
        } catch (SAXException e) {
            throw new ExcepcionErrorInterno("ParserConfigurationException", e);
        } catch (IOException e) {
            throw new ExcepcionErrorInterno("ParserConfigurationException", e);
        } finally {
            if (readerXml != null) {
                try {
                    readerXml.close();
                } catch (IOException e) {
                    log.warn("No se puede cerrar el InputStream para el XmlSignature");
                }
            }
        }
    }

    /*
     * Recupera todos los XMLSignature incorporados dentro del documento.
     */
    public List<XMLSignature> getXMLSignatureFormDocument(Document documento) throws ExcepcionErrorInterno {
        try {
            // Aadimos al documento los Signatures que tenia anteriormente para
            // permitir la multifirma

            // recuperamos el elemento DOM
            Element nscontext = XMLUtils.createDSctx(documento, "ds", Constants.SignatureSpecNS);
            // Element nscontext = XMLUtils.createDSctx(doc,
            // "ds","http://www.w3.org/2000/09/xmldsig#");
            NodeList nodeList = XPathAPI.selectNodeList(documento, "//ds:Signature", nscontext);

            // Si se contien

            List<XMLSignature> xmlSignatureList = new ArrayList<XMLSignature>(nodeList.getLength());
            // Extrae los hijos que ds:signature
            for (int i = 0; i < nodeList.getLength(); i++) {
                Element node = (Element) nodeList.item(i);
                XMLSignature signature = buildXMLSignature(node);
                xmlSignatureList.add(signature);
            }
            return xmlSignatureList;
        } catch (TransformerException e) {
            throw new ExcepcionErrorInterno("TransformerException", e);
        } catch (XMLSignatureException e) {
            throw new ExcepcionErrorInterno("XMLSignatureException", e);
        } catch (XMLSecurityException e) {
            throw new ExcepcionErrorInterno("XMLSecurityException", e);
        }
    }

    /**
     * Crea un XML Signature desde un nodo.
     * Considerando que el nodo tiene estructura de xmlSignature
     * @param node
     * @return
     * @throws XMLSignatureException
     * @throws XMLSecurityException
     */
    public XMLSignature buildXMLSignature(Element node) throws XMLSignatureException, XMLSecurityException {
        XMLSignature signature = new XMLSignature(node, "viafirmaXMLSignature");
        signature.addResourceResolver(new OfflineResolver());
        return signature;
    }

    /**
     * Comprueba si el documento xml indicado esta vlido.
     * 
     * Para ser vlido debe tener todas sus Signatures validas. Si no tiene
     * signatures es vlida
     * 
     * @param documento
     * @return
     */
    public boolean checkSignatureFrom(Document xmlDocument, boolean permitirNoFirmados) {
        boolean isValid = true;
        try {
            // Recuperamos todas las signatures del documento:
            List<XMLSignature> listSignatures = getXMLSignatureFormDocument(xmlDocument);

            // Comprueba que todas las Signatures del documento son vlidas.
            for (XMLSignature signature : listSignatures) {
                isValid = isValid && isValid(signature);

            }
            if (listSignatures.size() == 0) {
                isValid = permitirNoFirmados;
            }
        } catch (ExcepcionErrorInterno e) {
            log.warn(
                    "Problemas al comprobar la seguridad del documento. La firma no se realizo correctamente, el formato no es el esperado o el documento ha sido modificado.",
                    e);
            isValid = false;
        }
        return isValid;

    }

    /**
     * Retorna el tipo de formato utilizado para la firma
     * 
     * @param newId
     * @return
     * @throws ExcepcionErrorInterno
     *             El formato no es reconocido
     */
    public static TypeFormatSign getTypeFormatSign(String newId) throws ExcepcionErrorInterno {
        try {
            int codTipo = Integer.parseInt(newId.substring(1, 2)); // Equivale
            // a esto
            // id.charAt(1);
            return TypeFormatSign.getByCode(codTipo);
        } catch (InternalException e) {
            throw new ExcepcionErrorInterno(CodigoError.ERROR_XMLSIGN_FORMAT, e);
        }
    }

    /**
     * Retorna el Documento custodiado preparado para su transmisin.
     * 
     * @param signature
     * @param identificador
     * @return
     * @throws ExcepcionErrorInterno
     */
    public Documento getDocument(Document xmlDocument, String identificador) throws ExcepcionErrorInterno {
        // Retorna el document en funcin del tipo
        TypeFormatSign typeFormatSign = getTypeFormatSign(identificador);
        if (typeFormatSign.equals(TypeFormatSign.XMLSIG_ENVELOPING)) {
            return getDocumentFromContentObjectInXMLSIG_ENVELOPING(xmlDocument, identificador);
        } else if (typeFormatSign.equals(TypeFormatSign.XADES_EPES_ENVELOPED)) {
            // es un Formato xml
            return getDocumentFromContentObjectInXADES_EPES_ENVELOPED(xmlDocument, identificador);
        } else {
            // Tipo de dato no reconocido
            throw new ExcepcionErrorInterno(CodigoError.ERROR_XMLSIGN_FORMAT);
        }
    }

    /**
     * Retorna el documento XML custodiado.
     * 
     * @param signature
     * @param identificador
     * @return
     */
    private Documento getDocumentFromContentObjectInXADES_EPES_ENVELOPED(Document xmlDocument,
            String identificador) {
        throw new UnsupportedOperationException(
                "Esta operacin no esta soportada o implementada en la versin Viafirma GPL/Estandar");
    }

    /**
     * Retorna el contenido del objeto contenido en el xmlSignature. Si hay mas
     * de un objeto retorna el ltimo.
     * 
     * @param signature
     * @return
     * @throws ExcepcionManejoCertificado
     */
    public Documento getDocumentFromContentObjectInXMLSIG_ENVELOPING(Document xmlDocument, String identificador)
            throws ExcepcionErrorInterno {
        try {
            // Recupero las signaturas almacenadas en el documento
            List<XMLSignature> signatureList = getXMLSignatureFormDocument(xmlDocument);
            // En este tipo de formato solo tenemos una firma
            XMLSignature signature = signatureList.get(0);

            // Por convencin el ultimo objeto es el PDF firmado.
            ObjectContainer object = signature.getObjectItem(signature.getObjectLength() - 1);
            // Suponemos que el encoding es Base64
            String base64 = object.getTextFromTextChild();
            // Recupero el tipo de dato
            String mimeType = object.getMimeType();
            TypeFile typeFile = TypeFile.getFromMimeType(mimeType);
            byte[] datos = org.apache.xml.security.utils.Base64.decode(base64);
            Documento documento = new Documento(identificador, identificador + typeFile.getExtension(), datos,
                    typeFile, TypeFormatSign.XMLSIG_ENVELOPING);
            return documento;
        } catch (Base64DecodingException e) {
            throw new ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA);
        }
    }

    /**
     * Recupera el XMLSignature desde un Xml en formato Base64.
     * 
     * @param xmldoc_b64n
     *            String en Base64 que contiene un XmlSign
     * @return Xml con la firma
     * @throws ExcepcionManejoCertificado
     *             No se ha podido generar el XMLSign
     * @throws ExcepcionCertificadoNoEncontrado
     *             No hay certificado
     */

    public X509Certificate getX509(XMLSignature signature)
            throws ExcepcionCertificadoNoEncontrado, ExcepcionManejoCertificado {
        try {
            // intento recuperar la informacin del firmante.
            KeyInfo ki = signature.getKeyInfo();
            if (ki != null) {
                if (!ki.containsX509Data()) {
                    // No hay informacin del firmante
                    System.out.println("Could find a X509Data element in the KeyInfo");
                    throw new ExcepcionCertificadoNoEncontrado(CodigoError.ERROR_XMLSIGN_SIN_CERTIFICADO);
                } else {
                    // el XMLSign si contiene un certificado de usuario
                    X509Certificate cert = signature.getKeyInfo().getX509Certificate();
                    // if(signature.checkSignatureValue(cert)){
                    // System.out.println("Certificado valido");
                    // }else{
                    // System.out.println("Certificado No valido");
                    // }

                    if (cert != null) {
                        return cert;
                    } else {
                        // no se ha encontrado un certificado vlido
                        throw new ExcepcionCertificadoNoEncontrado(CodigoError.ERROR_XMLSIGN_SIN_CERTIFICADO);
                    }
                }
            } else {
                throw new ExcepcionCertificadoNoEncontrado(CodigoError.ERROR_XMLSIGN_SIN_CERTIFICADO);
            }
        } catch (XMLSecurityException e) {
            throw new ExcepcionManejoCertificado("XMLSecurityException", e);
        }
    }

    // **********************************************************************
    // Mtodos para la generacin de XML Signatures
    // **********************************************************************

    /**
     * Genera un XMLSignature de tipo Enveloped firmado por el alias indicado.
     * 
     * @parm documeto Documento a firmar
     * @param alias
     *            Alias del certificado utilizado.
     * @throws ExcepcionErrorInterno
     *             No se ha podido generar la firma del documento
     * @throws ExcepcionCertificadoNoEncontrado
     *             No existe el alias
     */
    public Document signDocument(Documento documento, String alias, String password)
            throws ExcepcionErrorInterno, ExcepcionCertificadoNoEncontrado {

        // Recuperamos el certificado que vamos a utilizar
        PrivateKey privateKey;
        try {
            if (alias == null) {
                throw new ExcepcionCertificadoNoEncontrado("Alias indicado incorrecto");
            }
            privateKey = KeyStoreLoader.getPrivateKey(alias, password);
            if (privateKey == null) {
                throw new ExcepcionCertificadoNoEncontrado(
                        "No existe una clave privada para el alias '" + alias + "'");
            }
            log.info("Firmando el documento con el certificado " + alias);
            // Creamos el documento que se convertira en un XMLSignature
            javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance();
            javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder();
            org.w3c.dom.Document doc = db.newDocument();

            // Preparamos la estructura para la firma XML Signature

            XMLSignature sig = new XMLSignature(doc, BaseURI, XMLSignature.ALGO_ID_SIGNATURE_RSA);
            doc.appendChild(sig.getElement());

            // Aadimos los datos a firmar al documento
            String idAttachment = "attachment-0";
            ObjectContainer obj2 = new ObjectContainer(doc);
            obj2.setEncoding("base64");
            obj2.setId(idAttachment);
            obj2.setMimeType(documento.getTipo().getMimetype());
            obj2.addBase64Text(documento.getDatos());
            sig.appendObject(obj2);
            // Creamos el tansformador a XMlSignature
            Transforms transforms = new Transforms(doc);

            transforms.addTransform(Transforms.TRANSFORM_C14N_WITH_COMMENTS);
            sig.addDocument("#" + idAttachment, transforms, Constants.ALGO_ID_DIGEST_SHA1);

            // Aadimos la informacin del certificado usado
            X509Certificate certificado = KeyStoreLoader.getCertificate(alias);
            // Aadimos la informacin del firmante
            sig.addKeyInfo(certificado);
            sig.addKeyInfo(certificado.getPublicKey());
            // Firmamos el documento
            sig.sign(privateKey);
            log.debug("Firma completada.");
            return sig.getDocument();
        } catch (ExcepcionErrorInterno e) {
            throw e;
        } catch (ParserConfigurationException e) {
            throw new ExcepcionErrorInterno(CodigoError.ERROR_MANEJO_CERTIFICADO,
                    "No se puede genera el XMLSignature.", e);
        } catch (XMLSecurityException e) {
            throw new ExcepcionErrorInterno(CodigoError.ERROR_MANEJO_CERTIFICADO,
                    "No se puede genera el XMLSignature.", e);
        }

    }

    /**
     * Retorna el digest en array
     * 
     * @param XMLSignature
     * @return boolean
     * 
     * @author Alexis Castilla Armero (Pencerval at gmail.com)
     */

    public String[] getDigest(XMLSignature signature, String identificador) {
        try {
            String[] typePlusValue = new String[2];
            TypeFormatSign formatSign = getTypeFormatSign(identificador);
            if (TypeFormatSign.XMLSIG_ENVELOPING == formatSign) {
                /*
                 * ej: <ds:SignedInfo> <ds:CanonicalizationMethod
                 * Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
                 * ></ds:CanonicalizationMethod> <ds:SignatureMethod
                 * Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"
                 * ></ds:SignatureMethod> <ds:Reference URI="#ToBeSigned">
                 * <ds:DigestMethod
                 * Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"
                 * ></ds:DigestMethod>
                 * <ds:DigestValue>PR1yAlUUyMinlz2dUHMTn5icNm8=</ds:DigestValue>
                 * </ds:Reference> <ds:Reference
                 * Type="http://www.w3.org/2000/09/xmldsig#Object"
                 * URI="#attachment-0"> <ds:DigestMethod
                 * Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"
                 * ></ds:DigestMethod>
                 * <ds:DigestValue>1Gq4NHx9jdoIHeoy4YB9omeLKM4=</ds:DigestValue>
                 * </ds:Reference> </ds:SignedInfo>
                 */
                // Recuperamos el valor almacenado en el
                Element nscontext = XMLUtils.createDSctx(signature.getSignedInfo().getDocument(), "ds",
                        Constants.SignatureSpecNS);
                typePlusValue[0] = XPathAPI
                        .selectSingleNode(signature.getSignedInfo().getElement(),
                                "//ds:SignedInfo[1]/ds:Reference/ds:DigestMethod/@Algorithm", nscontext)
                        .getNodeValue();
                // typePlusValue[0] =
                //signature.getSignedInfo().getElement().getChildNodes().item(7)
                // .getChildNodes().item(1).getAttributes().getNamedItem(
                // "Algorithm").getTextContent();
                typePlusValue[0] = StringUtils.substringAfterLast(typePlusValue[0], "#");
                // typePlusValue[1] =
                //signature.getSignedInfo().getElement().getChildNodes().item(7)
                // .getChildNodes().item(3).getTextContent();
                typePlusValue[1] = XPathAPI.selectSingleNode(signature.getSignedInfo().getElement(),
                        "//ds:SignedInfo[1]/ds:Reference/ds:DigestValue/text()", nscontext).getNodeValue();
                return typePlusValue;

            } else if (TypeFormatSign.XADES_EPES_ENVELOPED == formatSign) {
                throw new UnsupportedOperationException(
                        "Esta operacin no esta soportada o implementada en la versin Viafirma GPL/Estandar");
            } else {
                throw new UnsupportedOperationException(
                        "El metodo no esta implementado para el tipo de formato: " + formatSign);
            }
        } catch (Exception e) {
            log.fatal("Hay problemas al procesar la estructura XML, no parece tener el formato esperado. id:"
                    + identificador, e);
            return null;
        }
    }

    /**
     * Recupera informacin sobre el hash del documento.
     * 
     * Nota: Recupera el valor del hash que aparece en la primera referencia del
     * documento en caso de se un XADES.
     * ej:http://www.w3.org/2000/09/xmldsig#sha1 --> sha1
     * 
     * @param xmlSig
     * @return
     */
    public String getDigestFormated(XMLSignature signature, String identificador) {
        String[] typePlusValue = getDigest(signature, identificador);
        if (typePlusValue != null) {
            String type = typePlusValue[0];
            String value = typePlusValue[1];
            return type + ": " + value;
        }
        return null;
    }

    /**
     * Canonizacin del xml
     * 
     * @param datos
     * @return
     */
    public byte[] canonizar(byte[] datos) {
        try {
            Canonicalizer c14n = Canonicalizer.getInstance(Transforms.TRANSFORM_C14N_OMIT_COMMENTS);
            // Canoniza el documento
            return c14n.canonicalize(datos);
        } catch (InvalidCanonicalizerException e) {
            log.warn("El XML no se puede canonizar.", e);
        } catch (CanonicalizationException e) {
            log.warn("El XML no se puede canonizar.", e);
        } catch (ParserConfigurationException e) {
            log.warn("El XML no se puede canonizar.", e);
        } catch (IOException e) {
            log.warn("El XML no se puede canonizar.", e);
        } catch (SAXException e) {
            log.warn("El XML no se puede canonizar.", e);
        }
        return null;
    }

    /**
     * Canonizacin del xml
     * 
     * @param doc
     * @return
     */
    public byte[] canonizar(Node doc) {
        try {
            Canonicalizer c14n = Canonicalizer.getInstance(Transforms.TRANSFORM_C14N_WITH_COMMENTS);
            // Canoniza el documento
            return c14n.canonicalizeSubtree(doc);
        } catch (InvalidCanonicalizerException e) {
            log.warn("El XML no se puede canonizar.", e);
        } catch (CanonicalizationException e) {
            log.warn("El XML no se puede canonizar.", e);
        }
        return null;
    }

    /**
     * Transforma un xml a un String
     * @param doc
     * @return
     */
    public String toString(Node doc) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        XMLUtils.outputDOM(doc, out);
        return new String(out.toByteArray());
    }

    /**
     * Valida un XML Signature.
     * Calcula el keyInfo de una signature y la comprueba
     * 
     * @param XMLSignature
     * @return boolean
     * 
     * @author Alexis Castilla Armero (Pencerval at gmail.com)
     */
    public boolean isValid(XMLSignature signature) {
        try {
            X509Certificate cert = signature.getKeyInfo().getX509Certificate();
            return signature.checkSignatureValue(cert);

        } catch (KeyResolverException e) {
            // TODO Auto-generated catch block
            log.warn("XML Signature invalido (Imposible resolver la clave).");
        } catch (XMLSignatureException e) {
            // TODO Auto-generated catch block
            log.warn("XML Signature invalido.", e);
        }
        return false;
    }

}