package com.fp.firmas.rules.common;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

import javax.persistence.NoResultException;
import javax.persistence.Query;

import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.ocsp.BasicOCSPResp;
import org.bouncycastle.cert.ocsp.CertificateID;
import org.bouncycastle.cert.ocsp.CertificateStatus;
import org.bouncycastle.cert.ocsp.OCSPException;
import org.bouncycastle.cert.ocsp.OCSPReq;
import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
import org.bouncycastle.cert.ocsp.OCSPResp;
import org.bouncycastle.cert.ocsp.RevokedStatus;
import org.bouncycastle.cert.ocsp.SingleResp;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;

import com.fp.base.persistence.TfirmDatosFirmante;
import com.fp.common.logger.APPLogger;
import com.fp.firmas.rules.common.enumerator.SignType;
import com.fp.firmas.rules.common.exception.FirmasException;
import com.fp.firmas.rules.common.resources.FirmMessages;
import com.fp.persistence.commondb.PersistenceHelper;
import com.fp.persistence.pfirmas.param.TfirmCertificado;
import com.fp.persistence.pgeneral.gene.TgeneParameters;
import com.fp.persistence.pgeneral.gene.TgeneParametersKey;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import com.itextpdf.text.pdf.parser.Vector;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.CertificateInfo;
import com.itextpdf.text.pdf.security.CertificateInfo.X500Name;
import com.itextpdf.text.pdf.security.CertificateUtil;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.OcspClient;
import com.itextpdf.text.pdf.security.OcspClientBouncyCastle;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
import com.itextpdf.text.pdf.security.TSAClient;

/**
 * Clase que contiene metodos utilitarios para manejar certificados
 * 
 * @author dcruz
 * 
 */
public class CertificateUtils {

    /*
     * CONSTANTES DESIGNADAS SEGUN LA NUEVA ESTRUCTURA DEL BCE
     */
    // OIDs de Campos del Certificado:
    public static final String OID_CEDULA_PASAPORTE = FirmMessages.getString("oid.cedula_pasaporte");

    public static final String OID_NOMBRES = FirmMessages.getString("oid.nombres_persona");

    public static final String OID_APELLIDO_1 = FirmMessages.getString("oid.apellido_persona1");

    public static final String OID_APELLIDO_2 = FirmMessages.getString("oid.apellido_persona2");

    public static final String OID_CARGO = FirmMessages.getString("oid.cargo");

    public static final String OID_INSTITUCION = FirmMessages.getString("oid.institucion");

    public static final String OID_DIRECCION = FirmMessages.getString("oid.direccion");

    public static final String OID_TELEFONO = FirmMessages.getString("oid.telefono");

    public static final String OID_CIUDAD = FirmMessages.getString("oid.ciudad");

    public static final String OID_RAZON_SOCIAL = FirmMessages.getString("oid.razon_social");

    public static final String OID_RUC = FirmMessages.getString("oid.ruc");

    public static final String X509 = "X.509";

    static {
        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
    }

    /**
     * Retorna el certificado del usuario contenido en la firma
     * 
     * @param store el store en el que se va a buscar los certificados
     * @param aliases los alias que estan dentro del keystore
     * @return el {@link java.security.Certificate}
     * @throws KeyStoreException
     */
    public synchronized static Certificate obtainCertificateInAlias(KeyStore store, Enumeration<String> aliases) throws KeyStoreException {
        Certificate certs[] = null;
        synchronized (aliases) {
            int i = 0;
            while (aliases.hasMoreElements()) {
                String alias = aliases.nextElement();
                //System.out.println("Se imprime los alias: " + i + " " + alias);
                certs = store.getCertificateChain(alias);
                for (int j = 0; j < certs.length; j++) {
                    X509Certificate certificate = (X509Certificate) certs[j];
                    boolean[] usages = certificate.getKeyUsage();
                    //    System.out.println("Certificado en primera posicion usado: " + j + " " + usages[0]);
                    if (usages[0]) {
                        return certificate;
                    }
                }
                i++;
            }

        }
        return null;
    }

    /**
     * Se devuelve todos los datos de la firma del usuario en base al certificado enviado
     * 
     * @param certificate el certificado enviado
     * @return Los datos del certificado de dicho usuario
     */
    public static TfirmDatosFirmante obtainDataForCertificate(Certificate certificate) {
        X509Certificate signedCertificate = (X509Certificate) certificate;
        TfirmDatosFirmante datosFirmante = new TfirmDatosFirmante();
        if (signedCertificate.getExtensionValue(OID_CEDULA_PASAPORTE) != null) {
            datosFirmante.setIdentificacion(new String(signedCertificate.getExtensionValue(OID_CEDULA_PASAPORTE)).trim());
        }
        if (signedCertificate.getExtensionValue(OID_NOMBRES) != null) {
            datosFirmante.setNombre(new String(signedCertificate.getExtensionValue(OID_NOMBRES)).trim());
        }
        if (signedCertificate.getExtensionValue(OID_APELLIDO_1) != null) {
            datosFirmante.setApellido1(new String(signedCertificate.getExtensionValue(OID_APELLIDO_1)).trim());
            if (signedCertificate.getExtensionValue(OID_APELLIDO_2) != null) {
                datosFirmante.setApellido2(new String(signedCertificate.getExtensionValue(OID_APELLIDO_2)).trim());
            } else {
                datosFirmante.setApellido2("");
            }
        }
        if (signedCertificate.getExtensionValue(OID_TELEFONO) != null) {
            datosFirmante.setTelefono(new String(signedCertificate.getExtensionValue(OID_TELEFONO)).trim());
        }
        if (signedCertificate.getExtensionValue(OID_CARGO) != null) {
            datosFirmante.setCargo(new String(signedCertificate.getExtensionValue(OID_CARGO)).trim());
        }
        if (signedCertificate.getExtensionValue(OID_CIUDAD) != null) {
            datosFirmante.setCiudad(new String(signedCertificate.getExtensionValue(OID_CIUDAD)).trim());
        }
        if (signedCertificate.getExtensionValue(OID_DIRECCION) != null) {
            datosFirmante.setDireccion(new String(signedCertificate.getExtensionValue(OID_DIRECCION)).trim());
        }
        if (signedCertificate.getExtensionValue(OID_INSTITUCION) != null) {
            datosFirmante.setInstitucion(new String(signedCertificate.getExtensionValue(OID_INSTITUCION)).trim());
        }
        if (signedCertificate.getExtensionValue(OID_RAZON_SOCIAL) != null) {
            datosFirmante.setInstitucion(new String(signedCertificate.getExtensionValue(OID_RAZON_SOCIAL)).trim());
        }
        if (signedCertificate.getExtensionValue(OID_RUC) != null) {
            datosFirmante.setRuc(new String(signedCertificate.getExtensionValue(OID_RUC)).trim());
        }
        datosFirmante.setFechaInicioVigencia(signedCertificate.getNotBefore());
        datosFirmante.setFechaVigencia(signedCertificate.getNotAfter());
        return datosFirmante;
    }

    /**
     * Valida que el certificado del usuario sea un certificado valido contra el servicio OCSP del proveedor
     * 
     * @param certificateUser
     * @throws FileNotFoundException
     * @throws CertificateException
     */
    public static void validateOcsCertificate(Certificate certificateUser) throws FileNotFoundException, CertificateException, FirmasException{
        //        System.out.println(((X509Certificate) certificateUser).getIssuerDN().getName());
        CertificateFactory cf = CertificateFactory.getInstance(X509);
        InputStream subordStream = new FileInputStream(FirmMessages.getString("dir.ruta.base.repositorio") + "/"
                + FirmMessages.getString("nombre.certificado.subordinado"));
        X509Certificate subordCertificate = (X509Certificate) cf.generateCertificate(subordStream);
        check((X509Certificate) certificateUser, subordCertificate);
        try{
            subordStream.close();
        }catch(Exception e){}
    }

    /**
     * Valida que los certificados enviados sean validos por la entidad certificadora
     * 
     * @param issuerCert certificado del usuario
     * @param x509Cert certificado que firmo el certificado expedido
     */
    public static void check(X509Certificate issuerCert, X509Certificate x509Cert) throws FirmasException{

        OutputStream out = null;
        DataOutputStream dataOut =null;
        InputStream in =null;

        try {

            BigInteger serialNumber = issuerCert.getSerialNumber();
            X509CertificateHolder holder;

            try {
                holder = new X509CertificateHolder(x509Cert.getEncoded());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            CertificateID id = new CertificateID(new JcaDigestCalculatorProviderBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build()
                    .get(CertificateID.HASH_SHA1), holder, serialNumber);

            OCSPReqBuilder ocspGen = new OCSPReqBuilder();
            ocspGen.addRequest(id);
            OCSPReq ocspReq = ocspGen.build();

            // Ir al OCSP
            String ocspUrl = CertificateUtil.getOCSPURL(issuerCert);

            if (ocspUrl == null) {
                APPLogger.getLogger().error("URL de OCSP is null");
                return;
            }

            URL url;

            try {
                url = new URL(ocspUrl);
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }

            HttpURLConnection con;
            OCSPResp ocspResponse;


            try {
                con = (HttpURLConnection) url.openConnection();

                con.setRequestProperty("Content-Type", "application/ocsp-request");
                con.setRequestProperty("Accept", "application/ocsp-response");
                con.setDoOutput(true);
                out = con.getOutputStream();
                dataOut = new DataOutputStream(new BufferedOutputStream(out));

                dataOut.write(ocspReq.getEncoded());

                APPLogger.getLogger().info("Estado de respuesta de la peticion=" + con.getResponseCode());

                /*
                 * Se parsea la respuesta y se obtiene el estado del certificado retornado por el OCSP
                 */
                in = (InputStream) con.getContent();
                byte[] resp = read(in); // Read the reponse
                ocspResponse = new OCSPResp(resp);


            } catch (IOException e) {
                throw new FirmasException("FIR-0001", "ERROR AL ESTABLECER CONEXI\u00d3N AL SERVICIO: {0}", url);
            }

            int status = ocspResponse.getStatus();
            APPLogger.getLogger().info("status=" + status);

            BasicOCSPResp basicResponse = (BasicOCSPResp) ocspResponse.getResponseObject();

            if (basicResponse != null) {
                SingleResp[] responses = basicResponse.getResponses();
                SingleResp response = responses[0];
                CertificateStatus certStatus = response.getCertStatus();

                if (certStatus instanceof RevokedStatus) {
                    APPLogger.getLogger().error("REVOKED");
                    RevokedStatus revokedStatus = (RevokedStatus) certStatus;
                    APPLogger.getLogger().error("Reason: " + revokedStatus.getRevocationReason());
                    APPLogger.getLogger().error("Date: " + revokedStatus.getRevocationTime());

                    throw new FirmasException("FIR-0002", "ERROR, CERTIFICADO REVOCADO POR {0} CON FECHA {1}", revokedStatus.getRevocationReason(),
                            revokedStatus.getRevocationTime());
                }
            }
        } catch (OCSPException e) {
            throw new RuntimeException(e);
        } catch (CertificateEncodingException e) {
            throw new RuntimeException(e);
        } catch (OperatorCreationException e) {
            throw new RuntimeException(e);
        }
        finally{
            try {
                dataOut.close();
                if(in!=null) {
                    in.close();
                }
                out.close();
            } catch (IOException e) {}
        }
    }

    /**
     * Devuelve los nombres de firmas de un documento PDF
     * 
     * @param docStream el documento a verificar
     * @return un lista de nombres de firmas
     */
    public static List<String> obtainNameSigns(InputStream docStream) {
        PdfReader docPdf = null;
        try {
            docPdf = new PdfReader(docStream);
            AcroFields af = docPdf.getAcroFields();
            return af.getSignatureNames();
        } catch (IOException e) {
            APPLogger.getLogger().error("Error al obtener los nombres del documentoss");
            return null;
        } finally {
            if(docPdf != null){
                docPdf.close();
            }
        }
    }

    /**
     * Metodo para firmar documentos
     * @param fileSrc
     * @param usuario
     * @param password
     * @param compania
     * @param reason
     * @param location
     * @param rectangle
     * @param numPage
     * @param nameSign
     * @return
     * @throws Exception
     */
    public static byte[] sign(InputStream fileSrc, String usuario, String password, Integer compania, String reason, String location,
            Rectangle rectangle, int numPage, String nameSign, String pathCertificate) throws Exception {
        String path = pathCertificate;
        FileInputStream ceritificateInputStream = new FileInputStream(path);
        return sign(fileSrc, ceritificateInputStream, password, reason, location, false, true, rectangle, numPage, nameSign);
    }

    /**
     * Metodo para firmar documentos
     * @param fileSrc
     * @param usuario
     * @param password
     * @param compania
     * @param reason
     * @param location
     * @param rectangle
     * @param numPage
     * @param nameSign
     * @return
     * @throws Exception
     */
    public static byte[] sign(InputStream fileSrc, String usuario, String password, Integer compania, String reason, String location,
            Rectangle rectangle, int numPage, String nameSign) throws Exception {
        String path = getPath(usuario, compania);
        FileInputStream ceritificateInputStream = new FileInputStream(path);
        return sign(fileSrc, ceritificateInputStream, password, reason, location, false, true, rectangle, numPage, nameSign);
    }

    /**
     * M&eacute;todo que firma un documento en base los par&aacute;metros indicados
     * 
     * @param fileSrc archivo origen
     * @param fileCert archivo destino
     * @param password contrasena
     * @param reason raz&oacute;n o motivo de la firma.
     * @param location localizaci&oacute;n coemtario adicional de la firma.
     * @param withTS tiene TS estamapado de tiempo.
     * @param withOCSP tiene OCSP verificacion de la firma por el la entidad certificadora BCE.
     * @param rectangle lugar localizaci&acute;n firma
     * @param numPage n&uacute;mero pagina
     * @param nameSign nombre firma
     * @return el documento firmado
     */
    private static byte[] sign(InputStream fileSrc, InputStream fileCert, String password, String reason, String location, boolean withTS,
            boolean withOCSP, Rectangle rectangle, int numPage, String nameSign) {
        OutputStream outputStream =null;
        PdfStamper stamper = null;
        try {
            PdfReader pdfReader = new PdfReader(fileSrc);
            PDFRendererListener listener  =  new PDFRendererListener();
            Integer numberPage = pdfReader.getNumberOfPages();
            PdfReaderContentParser parser =new PdfReaderContentParser(pdfReader);
            parser.processContent(numberPage, listener);
            List<Vector> listaI = listener.getListaImagenes();
            float llx = listaI.get(3).get(1);//50;
            float lly = listaI.get(3).get(1);//210;
            float urx = llx+250;//305;
            float ury = lly+60;//277;
            rectangle = new Rectangle(llx, lly, urx, ury);


            outputStream = new ByteArrayOutputStream(512);
            stamper = PdfStamper.createSignature(pdfReader, outputStream, '\0');
            PdfSignatureAppearance appearance = stamper.getSignatureAppearance();

            KeyStore store = KeyStore.getInstance("PKCS12");
            store.load(fileCert, password.toCharArray());
            String alias = store.aliases().nextElement();
            ExternalSignature signature = new PrivateKeySignature((PrivateKey) store.getKey(alias, password.toCharArray()), DigestAlgorithms.SHA256,
                    "SunRsaSign");
            appearance.setLayer2Text(generateSignText(store.getCertificateChain(alias), reason, location));
            appearance.setLayer2Font(new Font(Font.FontFamily.UNDEFINED, 8F));
            appearance.setVisibleSignature(rectangle, numPage, nameSign);
            TSAClient tsc = null;
            if (withTS) {

            }
            OcspClient ocsp = null;
            if (withOCSP) {
                ocsp = new OcspClientBouncyCastle();
            }

            ExternalDigest externalDigest = new BouncyCastleDigest();

            MakeSignature.signDetached(appearance, externalDigest, signature, store.getCertificateChain(alias), null, ocsp, tsc, 15000,
                    CryptoStandard.CADES);
            return ((ByteArrayOutputStream) outputStream).toByteArray();
        } catch (IOException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (DocumentException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (KeyStoreException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (CertificateException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (GeneralSecurityException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        }
        finally{
            try{
                fileCert.close();
                fileSrc.close();
                try {
                    stamper.close();
                } catch (Exception e2) {
                }

                if(outputStream!=null) {
                    outputStream.close();
                }
            }
            catch (IOException e){
                APPLogger.getLogger().error(e);
            }
        }
        return null;
    }

    public static byte[] sign(InputStream fileSrc, String usuario, String password, String reason, String location,
            String nameSign, String pathCertificate, SignType signType) throws Exception {
        String path = pathCertificate;
        FileInputStream certificateInputStream = null;
        try{
            certificateInputStream = new FileInputStream(path);
            return positionSign(fileSrc, certificateInputStream, password, reason, location, false, true, nameSign,signType);
        }finally{
            if(certificateInputStream !=null){
                certificateInputStream.close();
            }
        }

    }

    /**
     * M&eacute;todo que firma un documento en base los par&aacute;metros indicados
     * @param fileSrc
     * @param fileCert
     * @param password
     * @param reason
     * @param location
     * @param withTS
     * @param withOCSP
     * @param nameSign
     * @param signType
     * @return
     */
    private static byte[] positionSign(InputStream fileSrc, InputStream fileCert, String password, String reason, String location, boolean withTS,
            boolean withOCSP, String nameSign, SignType signType) {
        OutputStream outputStream =null;
        PdfStamper stamper = null;
        try {
            PdfReader pdfReader = new PdfReader(fileSrc);
            PDFRendererListener listener  =  new PDFRendererListener();
            Integer numPage = pdfReader.getNumberOfPages();
            PdfReaderContentParser parser =new PdfReaderContentParser(pdfReader);
            parser.processContent(numPage, listener);
            List<Vector> listaI = listener.getListaImagenes();
            float llx = listaI.get(listaI.size()-signType.getIndice()).get(0);
            float lly = listaI.get(listaI.size()-signType.getIndice()).get(1);
            float urx = llx+250;//305;
            float ury = lly+60;//277;
            Rectangle rectangle = new Rectangle(llx, lly, urx, ury);
            outputStream = new ByteArrayOutputStream(512);
            stamper = PdfStamper.createSignature(pdfReader, outputStream, '\0');
            PdfSignatureAppearance appearance = stamper.getSignatureAppearance();

            KeyStore store = KeyStore.getInstance("PKCS12");
            store.load(fileCert, password.toCharArray());
            String alias = store.aliases().nextElement();
            ExternalSignature signature = new PrivateKeySignature((PrivateKey) store.getKey(alias, password.toCharArray()), DigestAlgorithms.SHA256,
                    "SunRsaSign");
            appearance.setLayer2Text(generateSignText(store.getCertificateChain(alias), reason, location));
            appearance.setLayer2Font(new Font(Font.FontFamily.UNDEFINED, 8F));
            appearance.setVisibleSignature(rectangle, numPage, nameSign);
            TSAClient tsc = null;
            if (withTS) {

            }
            OcspClient ocsp = null;
            if (withOCSP) {
                ocsp = new OcspClientBouncyCastle();
            }

            ExternalDigest externalDigest = new BouncyCastleDigest();

            MakeSignature.signDetached(appearance, externalDigest, signature, store.getCertificateChain(alias), null, ocsp, tsc, 15000,
                    CryptoStandard.CADES);
            return ((ByteArrayOutputStream) outputStream).toByteArray();
        } catch (IOException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (DocumentException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (KeyStoreException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (CertificateException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        } catch (GeneralSecurityException e) {
            APPLogger.getLogger().error(e);
            e.printStackTrace();
        }
        finally{
            try{
                fileCert.close();
                fileSrc.close();
                try {
                    stamper.close();
                } catch (Exception e2) {
                }

                if(outputStream!=null) {
                    outputStream.close();
                }
            }
            catch (IOException e){
                APPLogger.getLogger().error(e);
            }
        }
        return null;
    }

    /**
     * Arma documento el texto a mostrar de la plantilla
     * @param chains certificados
     * @param reason raz&oacute;n
     * @param location lugar
     * @return una layout de la firma
     */
    private static String generateSignText(Certificate[] chains, String reason, String location){
        StringBuffer textLayout = new StringBuffer("Firmado digitalmente por: ");
        String name = null;
        X500Name x500name = CertificateInfo.getSubjectFields((X509Certificate)chains[0]);
        if (x500name != null) {
            name = x500name.getField("CN");
            if (name == null) {
                name = x500name.getField("E");
            }
        }
        if(name == null){
            name = "";
        }
        textLayout.append(name).append("\n");
        if(reason != null){
            textLayout.append("Raz\u00f3n: ").append(reason).append("\n");
        }
        /*
        if(location != null){
        	textLayout.append("Lugar: ").append(location).append("\n");
        }
         */
        SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        textLayout.append("Fecha: ").append(format.format(new Date(System.currentTimeMillis())));
        return textLayout.toString();
    }

    private static byte[] read(InputStream in) throws IOException {
        ByteArrayOutputStream bos = null;
        try {
            bos = new ByteArrayOutputStream();
            int next = in.read();
            while (next > -1) {
                bos.write(next);
                next = in.read();
            }
            bos.flush();

            return bos.toByteArray();
        } finally {
            if(in != null){
                in.close();
            }
            if(bos != null){
                bos.close();
            }
        }

    }

    /**
     * Entrega el path en el que se encuentra el certificado digital.
     * 
     * @param cusuario Codigo de usuario.
     * @param ccompania Codigo de compania.
     * @return String
     * @throws Exception
     */
    private static String getPath(String cusuario, Integer ccompania) throws Exception {
        TfirmCertificado tfirmcertificado = getTfirmCertificado(cusuario);
        TgeneParametersKey tgeneParametersKey = new TgeneParametersKey("PATH_CERTIFICADO_BCE", ccompania);
        TgeneParameters tgeneParameters = TgeneParameters.find(PersistenceHelper.getEntityManager(), tgeneParametersKey);
        String path = tgeneParameters.getTextvalue() + "/" + tfirmcertificado.getPk().getIdcertificado();
        return path;
    }

    /**
     * Sentencia que entrega la defincion vigente de un certificado digital para un usuario.
     */
    private static final String JPQL = "from TfirmCertificado where t.codigousuario = :cusuario";

    /**
     * Entrega defincion de certificados digitales vigente.
     * 
     * @param cusuario Codigo de usuario.
     * @return TfirmCertificado.
     * @throws Exception
     */
    private static TfirmCertificado getTfirmCertificado(String cusuario) throws Exception {
        TfirmCertificado tfirmCertificado = null;
        Query qry = PersistenceHelper.getEntityManager().createQuery(JPQL);
        qry.setParameter("cusuario", cusuario);
        try {
            tfirmCertificado = (TfirmCertificado) qry.getSingleResult();
        } catch (NoResultException e) {
            throw new FirmasException("FIR-0001", "PARAMETROS DEL CERTIFICADO DIGITAL NO DEFINIDO PARA EL USUARIO: {0}", cusuario);
        }
        return tfirmCertificado;
    }

    /**
     * Método para validar el password ingresado
     * @param path
     * @param usuario
     * @param password
     * @param compania
     * @return
     * @throws Exception
     */
    public static boolean validatePassword(String path, String usuario,
            String password, Integer compania) {
        FileInputStream certificateInputStream =null;
        try {
            certificateInputStream = new FileInputStream(path);
            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(certificateInputStream, password.toCharArray());
            return true;
        } catch (Exception e) {
            return false;
        }finally{
            try {
                if(certificateInputStream!=null)
                {
                    certificateInputStream.close();
                }
            } catch (IOException e) {}
        }

    }

}
