使用 OCSP协议 发送请求验证证书状态,OCSP验证苹果P12证书状态(有效 | 撤销)

鉴于公司有需求 需要Java服务端进行证书的校验,怎奈java实现的案列太少,苦苦搜寻2天,百度、谷歌、OCSP协议文档 、最后终于实现了,可以利用该 Demo 进行任何 OCSP协议的证书校验!!!

找了好多,最后使用  bouncycastle 完成了OCSP校验  

Maven 需要引入的包:

 
        
            org.bouncycastle
            bcprov-jdk15on
            1.64
        
        
            org.bouncycastle
            bcpkix-jdk15on
            1.64
        
        
            org.bouncycastle
            bcmail-jdk15on
            1.64
        
        
            org.bouncycastle
            bctls-jdk15on
            1.64
        
        
            org.bouncycastle
            bcprov-ext-jdk15on
            1.64
        
        
            org.bouncycastle
            bcpg-jdk15on
            1.64
        
        
        
            commons-codec
            commons-codec
            1.7
        
        
            commons-lang
            commons-lang
            2.6
        
        
            commons-io
            commons-io
            2.4
        
        
            commons-beanutils
            commons-beanutils
            1.8.3
        
        
            commons-collections
            commons-collections
            3.2.2
        
        
            commons-net
            commons-net
            3.0
        
        
            commons-configuration
            commons-configuration
            1.9
        
        
            commons-digester
            commons-digester
            2.1
        
        
            commons-httpclient
            commons-httpclient
            3.1
        
        
            commons-cli
            commons-cli
            1.3.1
        
        
            org.apache.commons
            commons-pool2
            2.4.2
        

 普通java项目的包 :bouncycastle  + commons 相关包

使用 OCSP协议 发送请求验证证书状态,OCSP验证苹果P12证书状态(有效 | 撤销)_第1张图片

以下是工具代码:

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import org.apache.commons.io.IOUtils;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
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.cert.ocsp.UnknownStatus;
import org.bouncycastle.operator.DigestCalculatorProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;

import sun.misc.BASE64Decoder;

import com.sun.xml.internal.messaging.saaj.util.ByteInputStream;

/**
 * 使用 OCSP协议请求 验证证书状态(有效|撤销|未知)
 * @author i4026
 *
 */
public class OCSPTool {

	//苹果根证书对象
    private static X509Certificate issuerCert;

    /**
     * 初始实例化苹果根证书对象 ( 发行者证书 )
     * @return
     */
    private static X509Certificate getIssuerCert() {
        if(issuerCert == null) {
            //苹果根证书
            String issuerCertStr = "MIIEIjCCAwqgAwIBAgIIAd68xDltoBAwDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UE\n" +
                    "BhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRp\n" +
                    "ZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEz\n" +
                    "MDIwNzIxNDg0N1oXDTIzMDIwNzIxNDg0N1owgZYxCzAJBgNVBAYTAlVTMRMwEQYD\n" +
                    "VQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxv\n" +
                    "cGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERldmVsb3Bl\n" +
                    "ciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3\n" +
                    "DQEBAQUAA4IBDwAwggEKAoIBAQDKOFSmy1aqyCQ5SOmM7uxfuH8mkbw0U3rOfGOA\n" +
                    "YXdkXqUHI7Y5/lAtFVZYcC1+xG7BSoU+L/DehBqhV8mvexj/avoVEkkVCBmsqtsq\n" +
                    "Mu2WY2hSFT2Miuy/axiV4AOsAX2XBWfODoWVN2rtCbauZ81RZJ/GXNG8V25nNYB2\n" +
                    "NqSHgW44j9grFU57Jdhav06DwY3Sk9UacbVgnJ0zTlX5ElgMhrgWDcHld0WNUEi6\n" +
                    "Ky3klIXh6MSdxmilsKP8Z35wugJZS3dCkTm59c3hTO/AO0iMpuUhXf1qarunFjVg\n" +
                    "0uat80YpyejDi+l5wGphZxWy8P3laLxiX27Pmd3vG2P+kmWrAgMBAAGjgaYwgaMw\n" +
                    "HQYDVR0OBBYEFIgnFwmpthhgi+zruvZHWcVSVKO3MA8GA1UdEwEB/wQFMAMBAf8w\n" +
                    "HwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wLgYDVR0fBCcwJTAjoCGg\n" +
                    "H4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5jcmwwDgYDVR0PAQH/BAQDAgGG\n" +
                    "MBAGCiqGSIb3Y2QGAgEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQBPz+9Zviz1smwv\n" +
                    "j+4ThzLoBTWobot9yWkMudkXvHcs1Gfi/ZptOllc34MBvbKuKmFysa/Nw0Uwj6OD\n" +
                    "Dc4dR7Txk4qjdJukw5hyhzs+r0ULklS5MruQGFNrCk4QttkdUGwhgAqJTleMa1s8\n" +
                    "Pab93vcNIx0LSiaHP7qRkkykGRIZbVf1eliHe2iK5IaMSuviSRSqpd1VAKmuu0sw\n" +
                    "ruGgsbwpgOYJd+W+NKIByn/c4grmO7i77LpilfMFY0GCzQ87HUyVpNur+cmV6U/k\n" +
                    "TecmmYHpvPm0KdIBembhLoz2IYrF+Hjhga6/05Cdqa3zr/04GpZnMBxRpVzscYqC\n" +
                    "tGwPDBUf";
            try {
                byte[] issuerByte = new BASE64Decoder().decodeBuffer(issuerCertStr);
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                issuerCert = (X509Certificate) cf.generateCertificate(new ByteInputStream(issuerByte, issuerByte.length));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return issuerCert;
    }


    /*
     *  通过ocsp 验证证书状态
     * 0 有效证书
     * 1 未知证书
     * -1 吊销证书
     * retry 重试次数
     */
    public static Integer checkCertStatus(String certStr, String pwd, int retry) {
        int resultNum = -2;
        while (retry > 0) {
            try {
                byte[] p12Byte = new BASE64Decoder().decodeBuffer(certStr);
                KeyStore ks = KeyStore.getInstance("PKCS12");
                ks.load(new ByteInputStream(p12Byte, p12Byte.length), pwd.toCharArray());
                X509Certificate cert = (X509Certificate)ks.getCertificate("1");
                OCSPReq ocspReq = GenOcspReq(cert, getIssuerCert());
                OCSPResp ocspResp = requestOCSPResponse(getOCSPUrl(cert), ocspReq);
                if(OCSPResp.SUCCESSFUL == ocspResp.getStatus()) {
                    BasicOCSPResp basic = (BasicOCSPResp) ocspResp.getResponseObject();
                    SingleResp[] resps = basic.getResponses();
                    if (resps != null && resps.length == 1) {
                        SingleResp resp = resps[0];
                        CertificateStatus certStatus = resp.getCertStatus();
                        if (certStatus == CertificateStatus.GOOD) {
                            resultNum = 0;
                        } else {
                            if (certStatus instanceof RevokedStatus) {
                                resultNum = -1;
                            } else if (certStatus instanceof UnknownStatus) {
                                resultNum = 1;
                            }
                        }
                        retry = 0;
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                retry --;
            }
        }

        return resultNum;
    }

    /**
     * 创建 OCSP requestq  请求
     * @param nextCert  需要检验 的证书
     * @param nextIssuer   发行者证书 (苹果根证书)
     * @return
     * @throws OCSPException
     * @throws OperatorCreationException
     * @throws CertificateEncodingException
     * @throws IOException
     */
    public static OCSPReq GenOcspReq(X509Certificate nextCert,
                                     X509Certificate nextIssuer) throws OCSPException, OperatorCreationException, CertificateEncodingException, IOException {
        OCSPReqBuilder ocspRequestGenerator = new OCSPReqBuilder();
        DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider("BC").build();
        // 获取 certId
        CertificateID certId = new CertificateID(
                (new BcDigestCalculatorProvider())
                        .get(CertificateID.HASH_SHA1),
                new X509CertificateHolder(nextIssuer.getEncoded()),
                nextCert.getSerialNumber());
        ocspRequestGenerator.addRequest(certId);
        BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis());
        Extension ext = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, new DEROctetString(nonce.toByteArray()));
        ocspRequestGenerator.setRequestExtensions(new Extensions(new Extension[]{ext}));
        return ocspRequestGenerator.build();
    }


    /**
     * 发送请求并接收返回值
     * @param url       请求地址,可以从证书中获取
     * @param ocspReq   请求对象
     * @return
     * @throws IOException
     * @throws MalformedURLException
     */
    public static OCSPResp requestOCSPResponse(String url, OCSPReq ocspReq) throws IOException, MalformedURLException {
        byte[] ocspReqData = ocspReq.getEncoded();
        HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
        try {
            con.setRequestProperty("Content-Type", "application/ocsp-request");
            con.setRequestProperty("Accept", "application/ocsp-response");
            con.setDoInput(true);
            con.setDoOutput(true);
            con.setUseCaches(false);

            OutputStream out = con.getOutputStream();
            try {
                IOUtils.write(ocspReqData, out);
                out.flush();
            } finally {
                IOUtils.closeQuietly(out);
            }

            byte[] responseBytes = IOUtils.toByteArray(con.getInputStream());
            OCSPResp ocspResp = new OCSPResp(responseBytes);

            return ocspResp;
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
    }


    /**
     * 获取证书中 OSCP的请求地址
     * @param certificate
     * @return
     * @throws IOException
     */
    public static String getOCSPUrl(X509Certificate certificate) throws IOException {
        ASN1Primitive obj;
        try {
            obj = getExtensionValue(certificate, Extension.authorityInfoAccess.getId());
        } catch (IOException ex) {
            return null;
        }

        if (obj == null) {
            return null;
        }

        AuthorityInformationAccess authorityInformationAccess = AuthorityInformationAccess.getInstance(obj);

        AccessDescription[] accessDescriptions = authorityInformationAccess.getAccessDescriptions();
        for (AccessDescription accessDescription : accessDescriptions) {
            boolean correctAccessMethod = accessDescription.getAccessMethod().equals(X509ObjectIdentifiers.ocspAccessMethod);
            if (!correctAccessMethod) {
                continue;
            }

            GeneralName name = accessDescription.getAccessLocation();
            if (name.getTagNo() != GeneralName.uniformResourceIdentifier) {
                continue;
            }

            DERIA5String derStr = DERIA5String.getInstance((ASN1TaggedObject) name.toASN1Primitive(), false);
            return derStr.getString();
        }

        return null;
    }

    /**
     * @param certificate
     *            the certificate from which we need the ExtensionValue
     * @param oid
     *            the Object Identifier value for the extension.
     * @return the extension value as an ASN1Primitive object
     * @throws IOException
     */
    private static ASN1Primitive getExtensionValue(X509Certificate certificate, String oid) throws IOException {
        byte[] bytes = certificate.getExtensionValue(oid);
        if (bytes == null) {
            return null;
        }
        ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(bytes));
        ASN1OctetString octs = (ASN1OctetString) aIn.readObject();
        aIn = new ASN1InputStream(new ByteArrayInputStream(octs.getOctets()));
        return aIn.readObject();
    }

    
    /**
     * 测试Demo
     * @param args
     */
    public static void main(String[] args) {
      String p12 = "MIIL1QIBAzCCC58GCSqGSIb3DQEHA----需要校验的证书----";
      String pdw = "证书密码";
      int checkStatus = checkCertStatus(p12, pdw, 3);
      String data = "未知";
      if (checkStatus == 0) {
	      data = "证书有效";
	  } else if (checkStatus == 1) {
	      data = "证书未知";
	  } else if (checkStatus == -1) {
	      data = "证书撤销";
	  } else if (checkStatus == -2) {
	      data = "验证异常";
	  }
      System.out.println(data);
    	
    }
}

运行结果:

使用 OCSP协议 发送请求验证证书状态,OCSP验证苹果P12证书状态(有效 | 撤销)_第2张图片

 

这代码没经过优化,纯属第一个Demo版本,但是能够正常校验,发这博客是因为java做这个的案列太少了,不希望其他开发人员遇到这种需求像我一样浪费那么多时间(大牛除外哈)!

有哪儿写的不对了可以指出哈 

你可能感兴趣的:(OCSP证书校验,java)