org.viafirma.nucleo.validacion.ValidadorHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.viafirma.nucleo.validacion.ValidadorHandler.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.nucleo.validacion;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.CertPathValidatorException;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Properties;
import java.util.Set;

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

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.XMLUtils;
import org.apache.xpath.XPathAPI;
import org.bouncycastle.util.encoders.Base64;
import org.viafirma.cliente.firma.TypeFormatSign;
import org.viafirma.excepciones.CodigoError;
import org.viafirma.excepciones.ExcepcionErrorInterno;
import org.viafirma.util.Constantes;
import org.viafirma.util.XmlSignUtil;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * Maneja todos los procesos relacionados con la validacin de certificados.
 * 
 * @author Felix Garcia Borrego (borrego at gmail.com)
 */
public class ValidadorHandler {

    /**
     * Manejador para las validaciones de certificados basadas en CRLs.
     */
    private CRLValidationHandler crlValidationHandler;

    /**
     * Manejador para las validaciones de certificados basadas en OCSP.
     */
    private OcspValidatorHandler ocspValidationHandler;

    private static ValidadorHandler singleton;

    private Set<TrustAnchor> certificadosConfianza;

    public static ValidadorHandler getCurrentInstance() {
        if (singleton == null) {
            singleton = new ValidadorHandler();
        }
        return singleton;
    }

    private ValidadorHandler() {
        // Singleton
    }

    /**
     * Crea un validador de certificados. Normalmente solo hay una instancia de
     * esta clase y esta contenida en el Nucleo. Solo el nucleo debe invocar
     * este constructor
     * 
     * @param validacionOnline
     * @param properties
     *                Propiedades para de conexin a crls
     */
    public static void init(boolean validacionOnline, Properties properties) {
        ValidadorHandler validador = getCurrentInstance();
        // Recuperamos los certificados de confianza que la plataforma puede
        // validar.
        validador.certificadosConfianza = validador.recuperarCertificadosDeConfianza();
        validador.crlValidationHandler = new CRLValidationHandler(validacionOnline,
                validador.certificadosConfianza);
        validador.ocspValidationHandler = new OcspValidatorHandler(validacionOnline,
                validador.certificadosConfianza);

        // Inicializa el acceso a las crls
        CRLUtil.init(properties);

    }

    /**
     * Valida el certificado indicado. Utilizando segn el tipo validacin OCSP
     * o CRL.
     * 
     * @param certificadoX509
     * @return
     */
    public CodigoError validar(X509Certificate certificadoX509) {
        // Si el protocolo es OCSP....
        if (isOCSPProtocol(certificadoX509)) {
            if (log.isDebugEnabled())
                log.debug("Validando con OCSP el certificado : " + certificadoX509.getSubjectDN().getName());
            try {
                return ocspValidationHandler.validarOCSP(certificadoX509);
            } catch (CertPathValidatorException e) {
                log.warn(e.getMessage());
                return CodigoError.ERROR_OCSP_INTERNAL_ERROR;
            }
        } else {
            // el certificado sera validado utilizando el mtodo de acceso a
            // CRLs
            if (log.isDebugEnabled())
                log.debug("Validando certificado : " + certificadoX509.getSubjectDN().getName());
            return crlValidationHandler.validarCRL(certificadoX509);
        }
    }

    /**
     * Inizializa el conjunto de certificados altualmente aceptados como de
     * confianza y con los que la plataforma funciona correctamente.
     * 
     */
    private Set<TrustAnchor> recuperarCertificadosDeConfianza() {
        // recupero el conjunto de certificados de confianza que hay en el
        // sistema
        Set<TrustAnchor> certificadosConfianza = KeyStoreLoader.getJSSETrustAnchors();
        if (certificadosConfianza.size() == 0) {
            log.error(
                    "No hay certificados de confianza, es necesario que almenos exista un certificado de confianza.");
        }
        return certificadosConfianza;
    }

    /**
     * Chequea el hash del documento original coincide con el hash del documento
     * custodiado.
     * 
     * @param originalData
     * @param id
     * @param xmlSig
     * @return
     */
    public boolean checkHash(byte[] originalData, String id, XMLSignature xmlSig) {
        // Realiza el digest del documento custodiado
        String digestCustodiadoString = XmlSignUtil.getInstance().getDigest(xmlSig, id)[1];
        // Lo pasamos a Byte[]
        byte[] digestCustodiado = Base64.decode(digestCustodiadoString);

        // Bytes del documento original preprocesados ( Canonizados si fuese
        // necesario)
        byte[] originalDataPreprocess = null;
        try {
            // Recuperamos el tipo de documento a comprobar
            TypeFormatSign typeFormatSign = XmlSignUtil.getTypeFormatSign(id);

            if (typeFormatSign == TypeFormatSign.XMLSIG_ENVELOPING) {
                // Para este tipo de formato no es necesario canonizar, ej:
                // binario de un PDF
                originalDataPreprocess = originalData;

            } else if (typeFormatSign == TypeFormatSign.XADES_EPES_ENVELOPED) {

                // Recupera el documento custodiado
                InputStream input = new ByteArrayInputStream(originalData);
                // Reader readerXML = new InputStreamReader(input);
                InputSource ioXml = new InputSource(input);
                // parser
                javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory
                        .newInstance();
                javax.xml.parsers.DocumentBuilder db;
                dbf.setNamespaceAware(true);
                dbf.setAttribute("http://xml.org/sax/features/namespaces", Boolean.TRUE);
                db = dbf.newDocumentBuilder();
                org.w3c.dom.Document doc = db.parse(ioXml);
                org.w3c.dom.Element nscontext = XMLUtils.createDSctx(doc, "ds", Constants.SignatureSpecNS);
                NodeList nodeIterator = XPathAPI.selectNodeList(doc, "//ds:Signature", nscontext);
                // Extrae los hijos que ds:signature
                for (int i = 0; i < nodeIterator.getLength(); i++) {
                    Node node = nodeIterator.item(i);
                    node.getParentNode().removeChild(node);
                }
                // Canoniza el documento
                originalDataPreprocess = XmlSignUtil.getInstance().canonizar(doc);
            } else {
                throw new UnsupportedOperationException(
                        "El tipo de firma no es soportado para su verificacion. " + typeFormatSign);
            }

            // Digiere los datos a comprobar
            byte[] digestOriginal = DigestUtils.sha(originalDataPreprocess);

            // Comprueba que los disges son efectivamente iguales
            if (Arrays.equals(digestCustodiado, digestOriginal)) {
                return true;
            }
            return false;

        } catch (ParserConfigurationException e) {
            log.error("Error con el configurador al parsear el documento ", e);
        } catch (SAXException e) {
            log.error("Error de nivel Sax al parsear el documento ", e);
        } catch (IOException e) {
            log.error("Error de flujo al parsear el documento", e);
        } catch (TransformerException e) {
            log.error("Error al transformar el documento", e);
        } catch (ExcepcionErrorInterno e) {
            log.error("Error de seguridad al digerir el documento", e);
        }
        return false;
    }

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

    /**
     * 
     * Comprueba si el protocolo utilizado es OCSP 
     * 
     * @param certificadoX509
     * @return
     */
    public boolean isOCSPProtocol(X509Certificate certificadoX509) {
        boolean isEDNI = certificadoX509.getIssuerDN().getName().contains(Constantes.EDNI_ISSUERDN);
        // Si es de tipo FNMT y.....
        boolean isFNMT = certificadoX509.getIssuerDN().getName().contains(Constantes.FNMT_ISSUERDN);

        // Comprobamos si no hay parametros de configuracin para FNMT LDAP.
        boolean hayFNMTViaOCSP = StringUtils.isEmpty(CRLUtil.getCurrentInstance().fnmtLDAPHostURL);
        if (isEDNI || (isFNMT && hayFNMTViaOCSP)) {
            return true;
        }
        return false;
    }

    /** Retorna el conjunto de certificados de confianza.
     * @return Returns the certificadosConfianza.
     */
    public Set<TrustAnchor> getCertificadosConfianza() {
        return certificadosConfianza;
    }

}