我使用 Bouncy castle API 创建了一个 OCSP 客户端。我无法从收到的 OCSP 响应中找到证书状态(说明其是否已撤销)。从 resp.getCertStatus() 返回的值始终为空。这就是我创建 OCSP 请求的方式。
private OCSPReq generateOCSPRequest(X509Certificate issuerCert, BigInteger serialNumber)
throws CertificateVerificationException {
//Add provider BC
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
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 (OCSPException e) {
e.printStackTrace();
throw new CertificateVerificationException("Cannot generate OSCP Request with the given certificate",e);
}
}
我从服务 URL 获得 OCSP 响应,如下所示。
private OCSPResp getOCSPResponce(String serviceUrl, OCSPReq request) throws CertificateVerificationException {
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 {
throw new CertificateVerificationException("Only http is supported for ocsp calls");
}
} catch (IOException e) {
e.printStackTrace();
throw new CertificateVerificationException("Cannot get ocspResponse from url: "+ serviceUrl, e);
}
}
撤销状态检查如下。这里从 BasicOCSPResp 对象 (basicResponse) 获取的 SingleResp 对象 (resp) 应该具有证书的状态(良好、已撤销或未知)。但是这里的状态总是空的。
public void checkRevocationStatus(X509Certificate peerCert, X509Certificate issuerCert)
throws CertificateVerificationException {
try {
OCSPReq request = generateOCSPRequest(issuerCert, peerCert.getSerialNumber());
List<String> locations = getAIALocations(peerCert);
Iterator it = locations.iterator();
if (it.hasNext()) {
String serviceUrl = (String) it.next();
OCSPResp ocspResponse = getOCSPResponce(serviceUrl, 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!=null) {
if (status == CertificateStatus.GOOD) {
System.out.println("OCSP Status is good!");
} else if (status instanceof org.bouncycastle.ocsp.RevokedStatus) {
System.out.println("OCSP Status is revoked!");
} else if (status instanceof org.bouncycastle.ocsp.UnknownStatus) {
System.out.println("OCSP Status is unknown!");
}
}
}
}
}
catch (Exception e) {
System.out.println(e);
}
}
我真的很感谢你的帮助。非常感谢。