Index: TibisayMovil/src/ve/gob/cenditel/tibisaymovil/CertificateUtils.java
===================================================================
--- TibisayMovil/src/ve/gob/cenditel/tibisaymovil/CertificateUtils.java	(revision 288126d7faf1d05b5222029383542ccbbb4d4a26)
+++ TibisayMovil/src/ve/gob/cenditel/tibisaymovil/CertificateUtils.java	(revision 288126d7faf1d05b5222029383542ccbbb4d4a26)
@@ -0,0 +1,266 @@
+package ve.gob.cenditel.tibisaymovil;
+
+import java.io.BufferedOutputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.Security;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.ocsp.OCSPObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x509.AccessDescription;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityInformationAccess;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.cert.CertException;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cert.ocsp.BasicOCSPResp;
+import org.spongycastle.cert.ocsp.CertificateID;
+import org.spongycastle.cert.ocsp.CertificateStatus;
+import org.spongycastle.cert.ocsp.OCSPException;
+import org.spongycastle.cert.ocsp.OCSPReq;
+import org.spongycastle.cert.ocsp.OCSPReqBuilder;
+import org.spongycastle.cert.ocsp.OCSPResp;
+import org.spongycastle.cert.ocsp.OCSPRespBuilder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.bc.BcDigestCalculatorProvider;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+
+/**
+ * Utilities to deal with X509 certificates.
+ *
+ * @author José M. Prieto (jmprieto@emergya.com)
+ */
+public class CertificateUtils {
+
+    static {
+      Security.addProvider(new BouncyCastleProvider());
+    }
+
+    /**
+     * Default OCSP responder.
+     *
+     * @see #checkWithOCSP(X509Certificate, X509Certificate)
+     */
+    private static final String DEFAULT_OCSP_RESPONDER = "http://publicador-psc.fii.gob.ve:2560/ocsp/";
+
+    /**
+     * Validates the status of a certificate with an OCSP responder, according to RFC 2560. The Online Certificate
+     * Status Protocol (OCSP) enables applications to determine the (revocation) state of an identified certificate.
+     * Uses the responder specified in the corresponding certificate extension if any or a default one.
+     *
+     * @param certificate the certificate to be validated
+     * @param issuerCertificate the certificate of the issuer authority
+     * @param responderUrl the URL of the OCSP responder service to be used
+     * @return true if the certificate is known by the responder and good, false if it is unknown or revoked
+     * @throws CertificateException on errors when dealing with certificates
+     * @throws IOException on I/O errors
+     * @throws OCSPException on OCSP protocol errors
+     */
+    public static ValidationResult checkWithOCSP(X509Certificate certificate, X509Certificate issuerCertificate)
+    throws CertificateException, IOException, OCSPException {
+
+        String responderUrl = DEFAULT_OCSP_RESPONDER;
+        X509CertificateHolder holder = new JcaX509CertificateHolder(certificate);
+        Extension extension = holder.getExtension(X509Extension.authorityInfoAccess);
+        if (extension != null) {
+            AuthorityInformationAccess authority = AuthorityInformationAccess.getInstance(extension.getParsedValue());
+            AccessDescription[] descriptions = authority.getAccessDescriptions();
+            for (AccessDescription description : descriptions) {
+                if (AccessDescription.id_ad_ocsp.equals(description.getAccessMethod())) {
+                    responderUrl = description.getAccessLocation().getName().toString();
+                }
+            }
+        }
+        return checkWithOCSP(certificate, issuerCertificate, responderUrl);
+    }
+
+    public static String getSubject(X509Certificate cert) {
+
+        return cert.getSubjectDN().getName();
+    }
+
+    public static String getSerial(X509Certificate cert) {
+
+        return cert.getSerialNumber().toString();
+    }
+
+    public static String getIssuer(X509Certificate cert) {
+
+        return cert.getIssuerDN().getName();
+    }
+
+    /**
+     * Validates the status of a certificate with the specified OCSP responder, according to RFC 2560.
+     *
+     * @param certificate the certificate to be validated
+     * @param issuerCertificate the certificate of the issuer authority
+     * @param responderUrl the URL of the OCSP responder service to be used
+     * @return true if the certificate is known by the responder and good, false if it is unknown or revoked
+     * @throws CertificateException on errors when dealing with certificates
+     * @throws IOException on I/O errors
+     * @throws OCSPException on OCSP protocol errors
+     */
+    static ValidationResult checkWithOCSP(X509Certificate certificate, X509Certificate issuerCertificate, String responderUrl)
+    throws CertificateException, IOException, OCSPException {
+
+        try {
+            OCSPReq request = buildOCSPRequest(certificate, issuerCertificate);
+
+            URL url = new URL(responderUrl);
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+            connection.setRequestProperty("Content-Type", "application/ocsp-request");
+            connection.setRequestProperty("Accept", "application/ocsp-response");
+            connection.setDoOutput(true);
+            DataOutputStream output = new DataOutputStream(new BufferedOutputStream(connection.getOutputStream()));
+            output.write(request.getEncoded());
+            output.flush();
+            output.close();
+
+            int statusCode = connection.getResponseCode();
+            if (statusCode == 301 || statusCode == 302 || statusCode == 307) {
+                return checkWithOCSP(certificate, issuerCertificate, connection.getHeaderField("Location"));
+            } else if (statusCode < 200 || statusCode >= 300) {
+                throw new IOException();
+            }
+
+            return isOCSPResponseValid(new OCSPResp(
+                    getBytesFromStream((InputStream) connection.getContent(), connection.getContentLength())),
+                    issuerCertificate);
+        } catch (OperatorCreationException e) {
+        	//throw new RuntimeException(e);
+             throw new CertificateException(e);
+        } catch (CertException e) {
+        	//throw new RuntimeException(e);
+            throw new CertificateException(e);
+        }
+    }
+
+    /**
+     * Checks a response received from the OCSP service.
+     *
+     * @param response the OCSP service response
+     * @param issuerCertificate X509Certificate of the certificate being checked
+     * @return true if the certificate is known by the responder and good, false if it is unknown or revoked
+     * @throws CertificateException on errors when dealing with certificates
+     * @throws IOException on I/O errors
+     * @throws OCSPException on OCSP protocol errors
+     * @throws OperatorCreationException on errors from the crypto library (hopefully never)
+     * @throws CertException on certificate handling errors
+     */
+    private static ValidationResult isOCSPResponseValid(OCSPResp response, X509Certificate issuerCertificate)
+    throws IOException, OCSPException, OperatorCreationException, CertificateException, CertException {
+
+        if (response.getStatus() != OCSPRespBuilder.SUCCESSFUL) {
+            throw new IOException();
+        }
+
+        BasicOCSPResp validations = (BasicOCSPResp) response.getResponseObject();
+        assert validations.getResponses().length == 1;
+
+        CertificateStatus status = validations.getResponses()[0].getCertStatus();
+        X509CertificateHolder signer = validations.getCerts()[0];
+        ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().build(signer);
+        //return (status == null) && validations.isSignatureValid(verifier) && isValidSigner(signer, issuerCertificate);
+    
+        return new ValidationResult(status, validations.isSignatureValid(verifier), isValidSigner(signer, issuerCertificate));
+    
+    }
+    
+    
+    
+
+    /**
+     * Check if the OCSP response has been signed by a legitimate authority. From the RFC:
+     *
+     * All definitive response messages SHALL be digitally signed. The key
+     * used to sign the response MUST belong to one of the following:
+     *
+     * -- the CA who issued the certificate in question
+     * -- a Trusted Responder whose public key is trusted by the requester
+     * -- a CA Designated Responder (Authorized Responder) who holds a
+     *    specially marked certificate issued directly by the CA, indicating
+     *    that the responder may issue OCSP responses for that CA
+     *
+     * @param signer
+     * @param issuerCertificate
+     * @return true if the signer is valid. false otherwise
+     * @throws CertificateException on certificate handling errors
+     * @throws CertException if the signature cannot be processed or is inappropriate
+     * @throws OperatorCreationException on errors from the crypto library (hopefully never)
+     */
+    private static boolean isValidSigner(X509CertificateHolder signer, X509Certificate issuerCertificate)
+    throws CertificateException, CertException, OperatorCreationException {
+
+        X509Certificate signerCertificate = new JcaX509CertificateConverter().getCertificate(signer);
+        ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().build(issuerCertificate);
+        return signerCertificate.equals(issuerCertificate) || signer.isSignatureValid(verifier);
+    }
+
+    /**
+     * Build a request to validate a certificate with an OCSP responder.
+     *
+     * @param certificate the certificate to be validated
+     * @param issuerCertificate the certificate of the issuer authority
+     * @return the request object
+     * @throws CertificateException on errors when dealing with certificates
+     * @throws OCSPException on OCSP protocol errors
+     * @throws OperatorCreationException on errors from the crypto library (hopefully never)
+     */
+    private static OCSPReq buildOCSPRequest(X509Certificate certificate, X509Certificate issuerCertificate)
+    throws OperatorCreationException, CertificateEncodingException, OCSPException {
+
+        DigestCalculator sha1;
+        sha1 = new BcDigestCalculatorProvider().get(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1));
+        X509CertificateHolder issuer = new JcaX509CertificateHolder(issuerCertificate);
+        CertificateID id = new CertificateID(sha1, issuer, certificate.getSerialNumber());
+        OCSPReqBuilder gen = new OCSPReqBuilder();
+        BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis());
+        Extension extension = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, new DEROctetString(
+                nonce.toByteArray()));
+
+        gen.addRequest(id);
+        gen.setRequestExtensions(new Extensions(new Extension[] { extension }));
+        OCSPReq request = gen.build();
+        return request;
+    }
+
+    /**
+     * Read data from a stream.
+     *
+     * @param stream the stream to be read
+     * @param length number of bytes to read
+     * @return the data read
+     * @throws EOFException if the file has less than length bytes available to read
+     * @throws IOException on I/O errors
+     */
+    private static byte[] getBytesFromStream(InputStream stream, int length) throws IOException {
+
+        byte[] bytes = new byte[length];
+        int numRead = 0;
+
+        for (int offset = 0; offset < length; offset += (numRead = stream.read(bytes, offset, length - offset))) {
+            if (numRead < 0) {
+                throw new EOFException();
+            }
+        }
+
+        stream.close();
+        return bytes;
+    }
+}
