package org.openstack.atlas.util.ca;
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.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.cert.CertPathValidatorException;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Date;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.HttpsURLConnection;
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.jce.provider.X509CertificateObject;
import org.bouncycastle.ocsp.BasicOCSPResp;
import org.bouncycastle.ocsp.CertificateID;
import org.bouncycastle.ocsp.OCSPException;
import org.bouncycastle.ocsp.OCSPReq;
import org.bouncycastle.ocsp.OCSPReqGenerator;
import org.bouncycastle.ocsp.OCSPResp;
import org.openstack.atlas.util.ca.exceptions.NotAnX509CertificateException;
import org.openstack.atlas.util.ca.primitives.OCSPResponseEvent;
import org.openstack.atlas.util.ca.primitives.OCSPResponseContainer;
import org.openstack.atlas.util.ca.primitives.RsaConst;
import org.openstack.atlas.util.ca.util.StaticHelpers;
import org.openstack.atlas.util.ca.util.X509Inspector;
import sun.security.provider.certpath.OCSP;
import sun.security.provider.certpath.OCSP.RevocationStatus;
import sun.security.provider.certpath.OCSP.RevocationStatus.CertStatus;
import sun.security.provider.certpath.OCSP.RevocationStatus.Reason;
import sun.security.provider.certpath.OCSPResponse;
public class OCSPUtils {
private static final SecureRandom sr;
private static final int PAGESIZE = 4096;
static {
RsaConst.init();
SecureRandom srTmp;
try {
srTmp = SecureRandom.getInstance("SHA1PRNG", "SUN");
} catch (NoSuchAlgorithmException ex) {
srTmp = new SecureRandom();
} catch (NoSuchProviderException ex) {
srTmp = new SecureRandom();
}
sr = srTmp;
}
public static OCSPReq newOCSPReq(X509Certificate issuerCrt, BigInteger subjectSerial) throws OCSPException {
SecureRandom sr = new SecureRandom();
CertificateID crtId = new CertificateID(CertificateID.HASH_SHA1, issuerCrt, subjectSerial);
OCSPReqGenerator gen = new OCSPReqGenerator();
gen.addRequest(crtId);
byte[] randBytes = new byte[8];
sr.nextBytes(randBytes);
Vector oids = new Vector();
Vector vals = new Vector();
oids.add(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
X509Extension ext = new X509Extension(false, new DEROctetString(randBytes));
vals.add(ext);
X509Extensions exts = new X509Extensions(oids, vals);
gen.setRequestExtensions(exts);
OCSPReq req = gen.generate();
return req;
}
public static RevocationStatus check(X509Certificate usrX509, X509Certificate caX509) throws IOException, CertPathValidatorException {
return OCSP.check(usrX509, caX509);
}
public static RevocationStatus check(X509CertificateObject usr509obj, X509CertificateObject caX509obj) throws IOException, CertPathValidatorException {
return check((X509Certificate) usr509obj, (X509Certificate) caX509obj);
}
@Deprecated
public static OCSPResponseContainer checkCertOCSP(X509CertificateObject userCrt, X509CertificateObject caCrt) {
OCSPResponseContainer resp = new OCSPResponseContainer();
BigInteger userSerial = userCrt.getSerialNumber();
OCSPReq req;
try {
req = newOCSPReq(userCrt, userSerial);
} catch (OCSPException ex) {
resp.setException(ex);
return resp;
}
X509Inspector xi;
HttpURLConnection con;
try {
xi = new X509Inspector(userCrt);
} catch (NotAnX509CertificateException ex) {
resp.setException(ex);
resp.setOcspResponseEvent(OCSPResponseEvent.USER_CRT_WAS_NULL);
return resp;
}
URI uri = xi.getOCSPUri();
if (uri == null) {
resp.setOcspResponseEvent(OCSPResponseEvent.NO_OCSP_URI_FOUND);
return resp;
}
URL url;
try {
url = uri.toURL();
} catch (MalformedURLException ex) {
resp.setException(ex);
resp.setOcspResponseEvent(OCSPResponseEvent.OCSP_URI_MALFORMED);
return resp;
}
String uriScheme = uri.getScheme();
if (uriScheme.equals("http")) {
try {
con = (HttpURLConnection) url.openConnection();
} catch (IOException ex) {
resp.setException(ex);
resp.setOcspResponseEvent(OCSPResponseEvent.IO_EXCEPTION_OPENING_URL);
return resp;
}
} else if (uriScheme.equals("https")) {
try {
con = (HttpsURLConnection) url.openConnection();
} catch (IOException ex) {
resp.setException(ex);
resp.setOcspResponseEvent(OCSPResponseEvent.IO_EXCEPTION_OPENING_URL);
return resp;
}
} else {
resp.setOcspResponseEvent(OCSPResponseEvent.CANT_HANDLE_SCHEMA_ON_OCSP_URI);
return resp;
}
con.setRequestProperty("content-type", "application/ocsp-request");
con.setRequestProperty("accept", "application/ocsp-response");
con.setDoOutput(true);
OutputStream ostream;
DataOutputStream das;
InputStream in;
OCSPResp ocspResp;
try {
ostream = con.getOutputStream();
das = new DataOutputStream(new BufferedOutputStream(ostream, PAGESIZE * 8));
das.write(req.getEncoded());
das.flush();
das.close();
if (con.getResponseCode() / 100 != 2) {
resp.setOcspResponseEvent(OCSPResponseEvent.BAD_HTTP_STATUS_CODE_CALLING_OSCP_URI);
resp.setOcspHttpResponseCode(con.getResponseCode());
}
in = (InputStream) con.getContent();
ocspResp = new OCSPResp(in);
resp.setRawOCSPResponse(ocspResp);
} catch (IOException ex) {
resp.setException(ex);
resp.setOcspResponseEvent(OCSPResponseEvent.IO_EXCEPTION_SENDING_REQUEST);
return resp;
}
int statusCode = ocspResp.getStatus();
statusCode = ocspResp.getStatus();
return resp;
}
public String getOCSPStatusMsg(OCSPResponseContainer rc) throws OCSPException {
StringBuilder sb = new StringBuilder();
OCSPResp rr = rc.getRawOCSPResponse();
BasicOCSPResp br = (BasicOCSPResp) rr.getResponseObject();
return sb.toString();
}
public static String getRevocationStatusMsg(RevocationStatus revStatus) {
StringBuilder sb = new StringBuilder();
sb.append("{");
CertStatus certStatus = revStatus.getCertStatus();
Reason reason = revStatus.getRevocationReason();
Date revokeDate;
try {
revokeDate = revStatus.getRevocationTime();
} catch (NullPointerException ex) {
// If the revocationTime field is null then the accessor to getRevocationTime()
// triggers a nullpointer bug as it attempts to cal Date.clone on a null object
// at least as of Java 1.6
//
// public java.util.Date getRevocationTime();
// Code:
//0: aload_0
//1: getfield #175; //Field revocationTime:Ljava/util/Date;
//4: invokevirtual #192; //Method java/util/Date.clone:()Ljava/lang/Object;
//7: checkcast #103; //class java/util/Date
//10: areturn
revokeDate = null;
}
sb.append("status=");
sb.append(certStatus.name());
sb.append(",RevocationDate=");
if (revokeDate == null) {
sb.append("null");
} else {
Calendar cal = StaticHelpers.dateToCalendar(revokeDate);
String revokedDateString = StaticHelpers.getCalendarString(cal);
sb.append(revokedDateString);
}
sb.append(",reason=");
if (reason == null) {
return "null";
} else {
sb.append(reason.name());
}
sb.append("}");
return sb.toString();
}
}