Sunday, March 15, 2015

Check online certificate status through OCSP

P
The Online Certificate Status Protocol (OCSP) is an Internet protocol used for obtaining the revocation status of an X.509 digital certificate. It is described in RFC 6960 and is on the Internet standards track. It was created as an alternative to certificate revocation lists (CRL), specifically addressing certain problems associated with using CRLs in a public key infrastructure (PKI). Messages communicated via OCSP are encoded in ASN.1 and are usually communicated over HTTP. The "request/response" nature of these messages leads to OCSP servers being termed OCSP responders.

Today, I will show you how to implement that in Java. In this post, I will create a simple project and use third-party Bouncy Castle 1.47. You can download it from here.
Now we go:


package com.it4shared.ocsp;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.Vector;

import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.ocsp.BasicOCSPResp;
import org.bouncycastle.ocsp.CertificateID;
import org.bouncycastle.ocsp.OCSPReq;
import org.bouncycastle.ocsp.OCSPReqGenerator;
import org.bouncycastle.ocsp.OCSPResp;
import org.bouncycastle.ocsp.OCSPRespStatus;
import org.bouncycastle.ocsp.SingleResp;

public class Ocsp {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  X509Certificate issuer; // the certificate which issued client certificate
  X509Certificate clientCertificate; // the client certificate which is checked online status
  boolean result = checkRevocationStatus("http://ocsp.ca.vn", clientCertificate.getSerialNumber(), issuer);
 }
 
    public static boolean checkRevocationStatus(String ocspURL, BigInteger serialNumber, X509Certificate issuerCert) {

     try {
         OCSPReq request = generateOCSPRequest(issuerCert, serialNumber); 
 
            OCSPResp ocspResponse = getOCSPResponce(ocspURL, request);
            if(OCSPRespStatus.SUCCESSFUL==ocspResponse.getStatus())
                System.out.println("server gave response fine");

            BasicOCSPResp basicResponse = (BasicOCSPResp) ocspResponse.getResponseObject();
            SingleResp[] responses = (basicResponse==null) ? null : basicResponse.getResponses();

            if (responses!=null && responses.length == 1) {
                SingleResp resp = responses[0];
                Object status = resp.getCertStatus();
                if (status instanceof org.bouncycastle.ocsp.RevokedStatus) {
                    System.out.println("OCSP Status is revoked!");
                    return false;
                }  else if (status instanceof org.bouncycastle.ocsp.UnknownStatus) {
                    System.out.println("OCSP Status is unknown!");
                    return false;
                } else {
                 System.out.println("OCSP Status is good!");
                 return true;
                }
            }
     }
     catch (Exception e) {
         e.printStackTrace();
     }
     return false;
    }
    private static OCSPResp getOCSPResponce(String serviceUrl, OCSPReq request) {
     try {
         byte[] array = request.getEncoded();
         if (serviceUrl.startsWith("http")) {
             HttpURLConnection con;
             URL url = new URL(serviceUrl);
             con = (HttpURLConnection) url.openConnection();
             con.setRequestProperty("Content-Type", "application/ocsp-request");
             con.setRequestProperty("Accept", "application/ocsp-response");
             con.setDoOutput(true);
             OutputStream out = con.getOutputStream();
             DataOutputStream dataOut = new DataOutputStream(new BufferedOutputStream(out));
             dataOut.write(array);
 
             dataOut.flush();
             dataOut.close();
 
             //Get Response
             InputStream in = (InputStream) con.getContent();
             OCSPResp ocspResponse = new OCSPResp(in);
             return ocspResponse;
         }
         else {
             System.out.println("Only http is supported for ocsp calls");
         }
     } catch (IOException e) {
         e.printStackTrace();
         System.out.println("Cannot get ocspResponse from url: "+ serviceUrl);
     }
     return null;
    }
    
    private static OCSPReq generateOCSPRequest(X509Certificate issuerCert, BigInteger serialNumber) {

        try {
            //  CertID structure is used to uniquely identify certificates that are the subject of
            // an OCSP request or response and has an ASN.1 definition. CertID structure is defined in RFC 2560
            CertificateID id = new CertificateID(CertificateID.HASH_SHA1, issuerCert, serialNumber);

            // basic request generation with nonce
            OCSPReqGenerator generator = new OCSPReqGenerator();
            generator.addRequest(id);

            // create details for nonce extension. The nonce extension is used to bind
            // a request to a response to prevent replay attacks. As the name implies,
            // the nonce value is something that the client should only use once within a reasonably small period.
            BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis());
            Vector objectIdentifiers = new Vector();
            Vector values = new Vector();

            //to create the request Extension
            objectIdentifiers.add(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
            values.add(new X509Extension(false, new DEROctetString(nonce.toByteArray())));
            generator.setRequestExtensions(new X509Extensions(objectIdentifiers, values));

            return generator.generate();
        }
        catch (org.bouncycastle.ocsp.OCSPException e) {
            e.printStackTrace();
            System.out.println("Cannot generate OSCP Request with the given certificate");
        }
        return null;
    }
}



References:

No comments:

Post a Comment