es.mityc.firmaJava.ts.TSCliente.java Source code

Java tutorial

Introduction

Here is the source code for es.mityc.firmaJava.ts.TSCliente.java

Source

/**
 * LICENCIA LGPL:
 * 
 * Esta librera es Software Libre; Usted puede redistribuirlo y/o modificarlo
 * bajo los trminos de la GNU Lesser General Public License (LGPL)
 * tal y como ha sido publicada por la Free Software Foundation; o
 * bien la versin 2.1 de la Licencia, o (a su eleccin) cualquier versin posterior.
 * 
 * Esta librera se distribuye con la esperanza de que sea til, pero SIN NINGUNA
 * GARANT?A; tampoco las implcitas garantas de MERCANTILIDAD o ADECUACIN A UN
 * PROPSITO PARTICULAR. Consulte la GNU Lesser General Public License (LGPL) para ms
 * detalles
 * 
 * Usted debe recibir una copia de la GNU Lesser General Public License (LGPL)
 * junto con esta librera; si no es as, escriba a la Free Software Foundation Inc.
 * 51 Franklin Street, 5 Piso, Boston, MA 02110-1301, USA o consulte
 * <http://www.gnu.org/licenses/>.
 *
 * Copyright 2008 Ministerio de Industria, Turismo y Comercio
 * 
 */

package es.mityc.firmaJava.ts;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertStoreException;
import java.text.SimpleDateFormat;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEREncodable;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.tsp.GenTimeAccuracy;
import org.bouncycastle.tsp.TSPException;
import org.bouncycastle.tsp.TimeStampRequest;
import org.bouncycastle.tsp.TimeStampRequestGenerator;
import org.bouncycastle.tsp.TimeStampResponse;
import org.bouncycastle.tsp.TimeStampToken;
import org.bouncycastle.tsp.TimeStampTokenInfo;

/**
 * Clase encargada de generar y validar los sellos de tiempo
 * 
 * @author  Ministerio de Industria, Turismo y Comercio
 * @version 0.9 beta
 */

public class TSCliente implements ConstantesTSA {

    /**
     * Servidor que da el servicio de sellado de tiempo
     */
    private String servidorTSA;
    /**
     * Algoritmo hash del sello de tiempo
     */
    private String algoritmoHash;

    private static final HttpClient cliente = new HttpClient();

    private static final Integer INT5000 = new Integer(5000);

    static Log log = LogFactory.getLog(TSCliente.class.getName());

    /**
     * Crea una nueva instancia de TSCliente
     * @param nombreServidor Nombre del servidor
     * @param algoritmoHash Algoritmo del hash del Sello de Tiempo
     */
    public TSCliente(String nombreServidor, String algoritmoHash) {
        super();
        this.servidorTSA = nombreServidor;

        // Algoritmo para digest aceptado por defecto
        this.algoritmoHash = TSPAlgoritmos.SHA1;

        // Comprueba que el algoritmo configurado en propiedades es aceptado. Si no lo es deja el algoritmo por defecto.
        // Los algoritmos aceptados se pueden ver en la clase TSPAlgorithms (excepto MD5)
        if (algoritmoHash != null) {
            String temp = algoritmoHash.trim().toUpperCase();
            if (TSPAlgoritmos.getPermitidos().contains(algoritmoHash))
                this.algoritmoHash = temp;
            else {
                log.warn(MENSAJE_NO_ALGORITMO_HASH);
            }
        }

    }

    /**
     * Este mtodo genera el Sello de Tiempo
     * @param binarioaSellar fichero binario que se va a sellar
     * @return TimeStampToken en formato binario
     * @throws TSClienteError
     */
    public byte[] generarSelloTiempo(byte[] binarioaSellar) throws TSClienteError {

        if (binarioaSellar == null) {
            log.error(MENSAJE_NO_DATOS_SELLO_TIEMPO);
            throw new TSClienteError(I18n.getResource(LIBRERIA_TSA_ERROR_1));
        } else {
            log.info(MENSAJE_GENERANDO_SELLO_TIEMPO);
            TimeStampRequestGenerator generadorPeticion = new TimeStampRequestGenerator();
            TimeStampRequest peticion = null;
            TimeStampResponse respuesta = null;

            try {
                MessageDigest resumen = MessageDigest.getInstance(algoritmoHash);
                resumen.update(binarioaSellar);
                peticion = generadorPeticion.generate(TSPAlgoritmos.getOID(algoritmoHash), resumen.digest());
                log.info(MENSAJE_PETICION_TSA_GENERADA);
            } catch (Exception e) {
                log.error(MENSAJE_ERROR_PETICION_TSA);
                throw new TSClienteError(I18n.getResource(LIBRERIA_TSA_ERROR_10));
            }

            cliente.getParams().setParameter(HttpClientParams.SO_TIMEOUT, INT5000);

            // Comprueba si hay configurado un proxy
            String servidorProxy = System.getProperty("http.proxyHost");
            if (servidorProxy != null && !servidorProxy.trim().equals(CADENA_VACIA)) {
                int puertoProxy = 80;
                try {
                    puertoProxy = Integer.parseInt(System.getProperty("http.proxyPort"));
                } catch (NumberFormatException ex) {
                }
                cliente.getHostConfiguration().setProxy(servidorProxy, puertoProxy);

                Credentials defaultcreds = new AuthenticatorProxyCredentials(servidorProxy, CADENA_VACIA);
                cliente.getState().setProxyCredentials(AuthScope.ANY, defaultcreds);
            }

            PostMethod metodo = new PostMethod(servidorTSA);
            metodo.addRequestHeader(CONTENT_TYPE, APPLICATION_TIMESTAMP_QUERY);
            ByteArrayInputStream datos = null;
            try {
                datos = new ByteArrayInputStream(peticion.getEncoded());
            } catch (IOException e) {
                log.error(MENSAJE_ERROR_PETICION + e.getMessage());
                throw new TSClienteError(
                        I18n.getResource(LIBRERIA_TSA_ERROR_11) + DOS_PUNTOS_ESPACIO + e.getMessage());
            }

            InputStreamRequestEntity rq = new InputStreamRequestEntity(datos);
            metodo.setRequestEntity(rq);

            metodo.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                    new DefaultHttpMethodRetryHandler(3, false));

            byte[] cuerpoRespuesta = null;
            try {
                int estadoCodigo = cliente.executeMethod(metodo);
                log.info(MENSAJE_PETICION_TSA_ENVIADA);

                if (estadoCodigo != HttpStatus.SC_OK) {

                    log.error(MENSAJE_FALLO_EJECUCION_METODO + metodo.getStatusLine());
                    throw new TSClienteError(
                            I18n.getResource(LIBRERIA_TSA_ERROR_12) + DOS_PUNTOS_ESPACIO + metodo.getStatusLine());
                }

                cuerpoRespuesta = metodo.getResponseBody();
                log.info(MENSAJE_RESPUESTA_TSA_OBTENIDA);

                try {
                    respuesta = new TimeStampResponse(cuerpoRespuesta);
                    try {

                        respuesta.validate(peticion);

                        log.info(MENSAJE_RESPUESTA_TSA_VALIDADA_OK);
                        // Para solucionar bug en libreria bouncycastle
                        //return respuesta.getTimeStampToken().getEncoded();
                        //AppPerfect: Falso positivo
                        ASN1InputStream is = new ASN1InputStream(cuerpoRespuesta);
                        ASN1Sequence seq = ASN1Sequence.getInstance(is.readObject());
                        DEREncodable enc = seq.getObjectAt(1);
                        if (enc == null)
                            return null;
                        return enc.getDERObject().getEncoded();
                        //Fin Para solucionar bug en libreria bouncycastle
                    } catch (TSPException e) {
                        log.error(MENSAJE_RESPUESTA_NO_VALIDA + e.getMessage());
                        throw new TSClienteError(
                                I18n.getResource(LIBRERIA_TSA_ERROR_9) + DOS_PUNTOS_ESPACIO + e.getMessage());
                    }
                } catch (TSPException e) {
                    log.error(MENSAJE_RESPUESTA_MAL_FORMADA + e.getMessage());
                    throw new TSClienteError(
                            I18n.getResource(LIBRERIA_TSA_ERROR_8) + DOS_PUNTOS_ESPACIO + e.getMessage());
                } catch (IOException e) {

                    log.error(MENSAJE_SECUENCIA_BYTES_MAL_CODIFICADA + e.getMessage());
                    throw new TSClienteError(
                            I18n.getResource(LIBRERIA_TSA_ERROR_7) + DOS_PUNTOS_ESPACIO + e.getMessage());
                }
            } catch (HttpException e) {
                log.error(MENSAJE_VIOLACION_PROTOCOLO_HTTP + e.getMessage());
                throw new TSClienteError(
                        I18n.getResource(LIBRERIA_TSA_ERROR_6) + DOS_PUNTOS_ESPACIO + e.getMessage());
            } catch (IOException e) {
                String mensajeError = I18n.getResource(LIBRERIA_TSA_ERROR_4) + DOS_PUNTOS_ESPACIO + servidorTSA;
                log.error(MENSAJE_ERROR_CONEXION_SERVIDOR_OCSP + e.getMessage());

                throw new TSClienteError(mensajeError);
            } finally {
                // Termina la conexin
                metodo.releaseConnection();
            }
        }
    }

    /**
     * Este mtodo valida el Sello de Tiempo
     * @param binarioaSellar fichero binario a validar
     * @param sellodeTiempo El Sello de Tiempo se ingresa en formato binario
     * @return TSValidacion Valores TSA
     * @throws NoSuchAlgorithmException
     * @throws TSPException
     * @throws IOException
     * @throws NoSuchProviderException
     * @throws CertStoreException
     * @throws TSClienteError
     */
    public static TSValidacion validarSelloTiempo(byte[] binarioaSellar, byte[] sellodeTiempo)
            throws NoSuchAlgorithmException, TSPException, IOException, NoSuchProviderException, CertStoreException,
            TSClienteError {

        //       Set permitidos = new HashSet(Arrays.asList(TSPAlgoritmos.getValoresPermitidos()));
        //       si el algoritmo pasado no es permitido o es nulo se usa el algortimo por defecto

        TimeStampToken tst = null;
        TSValidacion tsv = new TSValidacion();

        try {
            tst = new TimeStampToken(new CMSSignedData(sellodeTiempo));
        } catch (CMSException e) {
            // Intenta obtenerlo como una TimeStampResp
            try {
                TimeStampResponse tsr = new TimeStampResponse(sellodeTiempo);
                tst = tsr.getTimeStampToken();
                if (tst == null)
                    throw new TSClienteError(I18n.getResource(ConstantesTSA.LIBRERIA_TSA_ERROR_2));
            } catch (TSPException ex) {
                throw new TSClienteError(I18n.getResource(ConstantesTSA.LIBRERIA_TSA_ERROR_2));
            } catch (IOException ex) {
                throw new TSClienteError(I18n.getResource(ConstantesTSA.LIBRERIA_TSA_ERROR_2));
            }
        }

        tsv.setTst(tst);
        TimeStampTokenInfo tokenInfo = tst.getTimeStampInfo();

        MessageDigest resumen = TSPAlgoritmos.getDigest(tokenInfo.getMessageImprintAlgOID());
        if (resumen == null) {
            tsv.setRespuesta(false);
            return tsv;
        }

        resumen.update(binarioaSellar);
        if (MessageDigest.isEqual(resumen.digest(), tst.getTimeStampInfo().getMessageImprintDigest())) {
            //TimeStampTokenInfo tokenInfo = tst.getTimeStampInfo();                          
            SimpleDateFormat formato = new SimpleDateFormat(FORMATO_FECHA);
            tsv.setFecha(formato.format(tokenInfo.getGenTime()));
            tsv.setFechaDate(tokenInfo.getGenTime());

            GenTimeAccuracy precision = tokenInfo.getGenTimeAccuracy();
            tsv.setPrecision(precision);

            long accuLong = 0;
            if (precision != null) {
                accuLong = (precision.getMicros() * 1L) + (precision.getMillis() * 1000L)
                        + (precision.getSeconds() * 1000000L);
            }
            tsv.setPrecisionLong(accuLong);

            tsv.setSello(tokenInfo.getSerialNumber());
            tsv.setFirmaDigest(new String(Base64Coder.encode(tokenInfo.getMessageImprintDigest())));
            tsv.setRespuesta(true);
            tsv.setSelloAlg(tokenInfo.getMessageImprintAlgOID());
            tsv.setEmisor(tst.getSID().getIssuer());
        } else {
            tsv.setRespuesta(false);
        }
        return tsv;
    }

    /**
     * Ejemplo de validacion del sello de tiempo
     * @param args
     */
    public static void main(String[] args) {
        //       TSCliente cliente = new TSCliente("http://minister-6vp1kq.mityc.age:9207","SHA-1", null, 0);
        //        byte[] firma = Base64.decode(("X1MlQzZRNqBeJR2hjunePlD+ywlkdgaBAo3QDRhItXGhb1k4FffA6V2w5KZoSjPCaDhMgwcTXxz3"+
        //              "UThBmRlOxfZaPCpne63jRlkp63g2IclrmBRKFgsb+Wzb0/pNh/ITffiARrRpYqtO7M92V1+GZbph"+
        //              "m8swQHEJlCtiOyJvwPsFkq5LyB8Zm9pBhUo12oVWnU2sCi9EMl1wIGpr71o7rm0XeudCnFS+45pb"+
        //              "1uQNOILSYizSEnFZpa81/nSgjlW93q0xcE5wrzBsHvUPvhRHydXyYzITXYiSKSFFBuM/N/dcrn57"+
        //        "HoaCGoJP6zQ/Wd00c7AopMxM4qFcLSuljIRSag==")) ;
        //        byte[] tiempoSello = Base64.decode(("MIAGCSqGSIb3DQEHAqCAMIICdgIBAzELMAkGBSsOAwIaBQAwgZwGCyqGSIb3DQEJEAEEoIGMBIGJMIGGAgEBBgUqAwQFBjAhMAkGBSsOAwIaBQAEFLLvwLC3nEd02gNUWVajJdZXzgCuAhDYJoYNZgUCsQnl459uAPTjGA8yMDA3MDQxODE1MjIyM1qgNKQyMDAxCzAJBgNVBAYTAkVTMQ0wCwYDVQQLEwRERU1PMRIwEAYDVQQDEwlNSVRZQyBUU1AxggHDMIIBvwIBATBEMDAxCzAJBgNVBAYTAkVTMQ0wCwYDVQQLEwRERU1PMRIwEAYDVQQDEwlNSVRZQyBUU1ACEACk/CLM7Wk3DZLGU0wsw+4wCQYFKw4DAhoFAKCB1jAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTA3MDQxODE1MjIyM1owIwYJKoZIhvcNAQkEMRYEFEF7oHc9iR2uGAGjO+rta/Qqy5OpMHUGCyqGSIb3DQEJEAIMMWYwZDBiMGAEFCzqcQksWEIV1+dMt+JE/PEKjp1zMEgwNKQyMDAxCzAJBgNVBAYTAkVTMQ0wCwYDVQQLEwRERU1PMRIwEAYDVQQDEwlNSVRZQyBUU1ACEACk/CLM7Wk3DZLGU0wsw+4wDQYJKoZIhvcNAQEBBQAEgYCMr1HUe8xtsJ+a4cwQoV1DeTarNP4BLpSDM0qQky/ZKJgmsldaIUIG9j246njLAMGBURU1rbi+HhOKbIVImjWk7G/hzn/sUQsgrIqdffoGW5PSnVR5hKBPsTDUvdnZ8LvHLCLbir44TDVhF2ewzjp9lYXjM9/cMNU8cS3vePmftgAAAAA=")) ;
        //        TSValidacion tsv = null;
        //        try {
        //            tsv = cliente.validarSelloTiempo(firma, tiempoSello);
        //            
        //        } catch (Exception ex) {
        //            ex.printStackTrace();
        //        }
        //        
        //        log.info("------------------------------------------");
        //        if (tsv != null){
        //           log.info(tsv.getFecha());   
        //        }
    }
}