--- a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java Thu Sep 24 22:50:41 2009 +0100
+++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java Tue Oct 06 21:40:55 2009 -0700
@@ -28,17 +28,16 @@
import java.io.*;
import java.math.BigInteger;
import java.security.*;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateParsingException;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CRLReason;
import java.security.cert.X509Certificate;
-import java.security.cert.PKIXParameters;
-import javax.security.auth.x500.X500Principal;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-import java.util.Iterator;
import sun.misc.HexDumpEncoder;
import sun.security.x509.*;
import sun.security.util.*;
@@ -113,32 +112,29 @@
* @author Ram Marti
*/
-class OCSPResponse {
+public final class OCSPResponse {
- // Certificate status CHOICE
- public static final int CERT_STATUS_GOOD = 0;
- public static final int CERT_STATUS_REVOKED = 1;
- public static final int CERT_STATUS_UNKNOWN = 2;
+ public enum ResponseStatus {
+ SUCCESSFUL, // Response has valid confirmations
+ MALFORMED_REQUEST, // Illegal confirmation request
+ INTERNAL_ERROR, // Internal error in issuer
+ TRY_LATER, // Try again later
+ UNUSED, // is not used
+ SIG_REQUIRED, // Must sign the request
+ UNAUTHORIZED // Request unauthorized
+ };
+ private static ResponseStatus[] rsvalues = ResponseStatus.values();
private static final Debug DEBUG = Debug.getInstance("certpath");
private static final boolean dump = false;
- private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID;
- private static final ObjectIdentifier OCSP_NONCE_EXTENSION_OID;
- static {
- ObjectIdentifier tmp1 = null;
- ObjectIdentifier tmp2 = null;
- try {
- tmp1 = new ObjectIdentifier("1.3.6.1.5.5.7.48.1.1");
- tmp2 = new ObjectIdentifier("1.3.6.1.5.5.7.48.1.2");
- } catch (Exception e) {
- // should not happen; log and exit
- }
- OCSP_BASIC_RESPONSE_OID = tmp1;
- OCSP_NONCE_EXTENSION_OID = tmp2;
- }
+ private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID =
+ ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 1});
+ private static final ObjectIdentifier OCSP_NONCE_EXTENSION_OID =
+ ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 2});
- // OCSP response status code
- private static final int OCSP_RESPONSE_OK = 0;
+ private static final int CERT_STATUS_GOOD = 0;
+ private static final int CERT_STATUS_REVOKED = 1;
+ private static final int CERT_STATUS_UNKNOWN = 2;
// ResponderID CHOICE tags
private static final int NAME_TAG = 1;
@@ -147,7 +143,8 @@
// Object identifier for the OCSPSigning key purpose
private static final String KP_OCSP_SIGNING_OID = "1.3.6.1.5.5.7.3.9";
- private SingleResponse singleResponse;
+ private final ResponseStatus responseStatus;
+ private final Map<CertId, SingleResponse> singleResponseMap;
// Maximum clock skew in milliseconds (15 minutes) allowed when checking
// validity of OCSP responses
@@ -159,312 +156,300 @@
/*
* Create an OCSP response from its ASN.1 DER encoding.
*/
- // used by OCSPChecker
- OCSPResponse(byte[] bytes, PKIXParameters params,
+ OCSPResponse(byte[] bytes, Date dateCheckedAgainst,
X509Certificate responderCert)
throws IOException, CertPathValidatorException {
- try {
- int responseStatus;
- ObjectIdentifier responseType;
- int version;
- CertificateIssuerName responderName = null;
- Date producedAtDate;
- AlgorithmId sigAlgId;
- byte[] ocspNonce;
+ // OCSPResponse
+ if (dump) {
+ HexDumpEncoder hexEnc = new HexDumpEncoder();
+ System.out.println("OCSPResponse bytes are...");
+ System.out.println(hexEnc.encode(bytes));
+ }
+ DerValue der = new DerValue(bytes);
+ if (der.tag != DerValue.tag_Sequence) {
+ throw new IOException("Bad encoding in OCSP response: " +
+ "expected ASN.1 SEQUENCE tag.");
+ }
+ DerInputStream derIn = der.getData();
- // OCSPResponse
- if (dump) {
- HexDumpEncoder hexEnc = new HexDumpEncoder();
- System.out.println("OCSPResponse bytes are...");
- System.out.println(hexEnc.encode(bytes));
- }
- DerValue der = new DerValue(bytes);
- if (der.tag != DerValue.tag_Sequence) {
- throw new IOException("Bad encoding in OCSP response: " +
- "expected ASN.1 SEQUENCE tag.");
- }
- DerInputStream derIn = der.getData();
-
- // responseStatus
- responseStatus = derIn.getEnumerated();
- if (DEBUG != null) {
- DEBUG.println("OCSP response: " +
- responseToText(responseStatus));
- }
- if (responseStatus != OCSP_RESPONSE_OK) {
- throw new CertPathValidatorException(
- "OCSP Response Failure: " +
- responseToText(responseStatus));
- }
+ // responseStatus
+ int status = derIn.getEnumerated();
+ if (status >= 0 && status < rsvalues.length) {
+ responseStatus = rsvalues[status];
+ } else {
+ // unspecified responseStatus
+ throw new IOException("Unknown OCSPResponse status: " + status);
+ }
+ if (DEBUG != null) {
+ DEBUG.println("OCSP response status: " + responseStatus);
+ }
+ if (responseStatus != ResponseStatus.SUCCESSFUL) {
+ // no need to continue, responseBytes are not set.
+ singleResponseMap = Collections.emptyMap();
+ return;
+ }
- // responseBytes
- der = derIn.getDerValue();
- if (! der.isContextSpecific((byte)0)) {
- throw new IOException("Bad encoding in responseBytes element " +
- "of OCSP response: expected ASN.1 context specific tag 0.");
- };
- DerValue tmp = der.data.getDerValue();
- if (tmp.tag != DerValue.tag_Sequence) {
- throw new IOException("Bad encoding in responseBytes element " +
- "of OCSP response: expected ASN.1 SEQUENCE tag.");
- }
+ // responseBytes
+ der = derIn.getDerValue();
+ if (!der.isContextSpecific((byte)0)) {
+ throw new IOException("Bad encoding in responseBytes element " +
+ "of OCSP response: expected ASN.1 context specific tag 0.");
+ }
+ DerValue tmp = der.data.getDerValue();
+ if (tmp.tag != DerValue.tag_Sequence) {
+ throw new IOException("Bad encoding in responseBytes element " +
+ "of OCSP response: expected ASN.1 SEQUENCE tag.");
+ }
- // responseType
- derIn = tmp.data;
- responseType = derIn.getOID();
- if (responseType.equals(OCSP_BASIC_RESPONSE_OID)) {
- if (DEBUG != null) {
- DEBUG.println("OCSP response type: basic");
- }
- } else {
- if (DEBUG != null) {
- DEBUG.println("OCSP response type: " + responseType);
- }
- throw new IOException("Unsupported OCSP response type: " +
- responseType);
+ // responseType
+ derIn = tmp.data;
+ ObjectIdentifier responseType = derIn.getOID();
+ if (responseType.equals(OCSP_BASIC_RESPONSE_OID)) {
+ if (DEBUG != null) {
+ DEBUG.println("OCSP response type: basic");
+ }
+ } else {
+ if (DEBUG != null) {
+ DEBUG.println("OCSP response type: " + responseType);
}
+ throw new IOException("Unsupported OCSP response type: " +
+ responseType);
+ }
- // BasicOCSPResponse
- DerInputStream basicOCSPResponse =
- new DerInputStream(derIn.getOctetString());
+ // BasicOCSPResponse
+ DerInputStream basicOCSPResponse =
+ new DerInputStream(derIn.getOctetString());
- DerValue[] seqTmp = basicOCSPResponse.getSequence(2);
+ DerValue[] seqTmp = basicOCSPResponse.getSequence(2);
+ if (seqTmp.length < 3) {
+ throw new IOException("Unexpected BasicOCSPResponse value");
+ }
- if (seqTmp.length < 3) {
- throw new IOException("Unexpected BasicOCSPResponse value");
- }
+ DerValue responseData = seqTmp[0];
- DerValue responseData = seqTmp[0];
+ // Need the DER encoded ResponseData to verify the signature later
+ byte[] responseDataDer = seqTmp[0].toByteArray();
- // Need the DER encoded ResponseData to verify the signature later
- byte[] responseDataDer = seqTmp[0].toByteArray();
-
- // tbsResponseData
- if (responseData.tag != DerValue.tag_Sequence) {
- throw new IOException("Bad encoding in tbsResponseData " +
- " element of OCSP response: expected ASN.1 SEQUENCE tag.");
- }
- DerInputStream seqDerIn = responseData.data;
- DerValue seq = seqDerIn.getDerValue();
+ // tbsResponseData
+ if (responseData.tag != DerValue.tag_Sequence) {
+ throw new IOException("Bad encoding in tbsResponseData " +
+ "element of OCSP response: expected ASN.1 SEQUENCE tag.");
+ }
+ DerInputStream seqDerIn = responseData.data;
+ DerValue seq = seqDerIn.getDerValue();
- // version
- if (seq.isContextSpecific((byte)0)) {
- // seq[0] is version
- if (seq.isConstructed() && seq.isContextSpecific()) {
- //System.out.println ("version is available");
- seq = seq.data.getDerValue();
- version = seq.getInteger();
- if (seq.data.available() != 0) {
- throw new IOException("Bad encoding in version " +
- " element of OCSP response: bad format");
- }
- seq = seqDerIn.getDerValue();
- }
- }
-
- // responderID
- short tag = (byte)(seq.tag & 0x1f);
- if (tag == NAME_TAG) {
- responderName = new CertificateIssuerName(seq.getData());
- if (DEBUG != null) {
- DEBUG.println("OCSP Responder name: " + responderName);
+ // version
+ if (seq.isContextSpecific((byte)0)) {
+ // seq[0] is version
+ if (seq.isConstructed() && seq.isContextSpecific()) {
+ //System.out.println ("version is available");
+ seq = seq.data.getDerValue();
+ int version = seq.getInteger();
+ if (seq.data.available() != 0) {
+ throw new IOException("Bad encoding in version " +
+ " element of OCSP response: bad format");
}
- } else if (tag == KEY_TAG) {
- // Ignore, for now
- } else {
- throw new IOException("Bad encoding in responderID element " +
- "of OCSP response: expected ASN.1 context specific tag 0 " +
- "or 1");
+ seq = seqDerIn.getDerValue();
}
+ }
- // producedAt
- seq = seqDerIn.getDerValue();
- producedAtDate = seq.getGeneralizedTime();
+ // responderID
+ short tag = (byte)(seq.tag & 0x1f);
+ if (tag == NAME_TAG) {
+ if (DEBUG != null) {
+ X500Name responderName = new X500Name(seq.getData());
+ DEBUG.println("OCSP Responder name: " + responderName);
+ }
+ } else if (tag == KEY_TAG) {
+ // Ignore, for now
+ } else {
+ throw new IOException("Bad encoding in responderID element of " +
+ "OCSP response: expected ASN.1 context specific tag 0 or 1");
+ }
- // responses
- DerValue[] singleResponseDer = seqDerIn.getSequence(1);
- // Examine only the first response
- singleResponse = new SingleResponse(singleResponseDer[0]);
+ // producedAt
+ seq = seqDerIn.getDerValue();
+ if (DEBUG != null) {
+ Date producedAtDate = seq.getGeneralizedTime();
+ DEBUG.println("OCSP response produced at: " + producedAtDate);
+ }
- // responseExtensions
- if (seqDerIn.available() > 0) {
- seq = seqDerIn.getDerValue();
- if (seq.isContextSpecific((byte)1)) {
- DerValue[] responseExtDer = seq.data.getSequence(3);
- Extension[] responseExtension =
- new Extension[responseExtDer.length];
- for (int i = 0; i < responseExtDer.length; i++) {
- responseExtension[i] = new Extension(responseExtDer[i]);
- if (DEBUG != null) {
- DEBUG.println("OCSP extension: " +
- responseExtension[i]);
- }
- if ((responseExtension[i].getExtensionId()).equals(
- OCSP_NONCE_EXTENSION_OID)) {
- ocspNonce =
- responseExtension[i].getExtensionValue();
+ // responses
+ DerValue[] singleResponseDer = seqDerIn.getSequence(1);
+ singleResponseMap
+ = new HashMap<CertId, SingleResponse>(singleResponseDer.length);
+ if (DEBUG != null) {
+ DEBUG.println("OCSP number of SingleResponses: "
+ + singleResponseDer.length);
+ }
+ for (int i = 0; i < singleResponseDer.length; i++) {
+ SingleResponse singleResponse
+ = new SingleResponse(singleResponseDer[i]);
+ singleResponseMap.put(singleResponse.getCertId(), singleResponse);
+ }
- } else if (responseExtension[i].isCritical()) {
- throw new IOException(
- "Unsupported OCSP critical extension: " +
- responseExtension[i].getExtensionId());
- }
+ // responseExtensions
+ if (seqDerIn.available() > 0) {
+ seq = seqDerIn.getDerValue();
+ if (seq.isContextSpecific((byte)1)) {
+ DerValue[] responseExtDer = seq.data.getSequence(3);
+ for (int i = 0; i < responseExtDer.length; i++) {
+ Extension responseExtension
+ = new Extension(responseExtDer[i]);
+ if (DEBUG != null) {
+ DEBUG.println("OCSP extension: " + responseExtension);
+ }
+ if (responseExtension.getExtensionId().equals(
+ OCSP_NONCE_EXTENSION_OID)) {
+ /*
+ ocspNonce =
+ responseExtension[i].getExtensionValue();
+ */
+ } else if (responseExtension.isCritical()) {
+ throw new IOException(
+ "Unsupported OCSP critical extension: " +
+ responseExtension.getExtensionId());
}
}
}
-
- // signatureAlgorithmId
- sigAlgId = AlgorithmId.parse(seqTmp[1]);
+ }
- // check that the signature algorithm is not disabled.
- AlgorithmChecker.check(sigAlgId);
+ // signatureAlgorithmId
+ AlgorithmId sigAlgId = AlgorithmId.parse(seqTmp[1]);
- // signature
- byte[] signature = seqTmp[2].getBitString();
- X509CertImpl[] x509Certs = null;
+ // signature
+ byte[] signature = seqTmp[2].getBitString();
+ X509CertImpl[] x509Certs = null;
- // if seq[3] is available , then it is a sequence of certificates
- if (seqTmp.length > 3) {
- // certs are available
- DerValue seqCert = seqTmp[3];
- if (! seqCert.isContextSpecific((byte)0)) {
- throw new IOException("Bad encoding in certs element " +
- "of OCSP response: expected ASN.1 context specific tag 0.");
- }
- DerValue[] certs = (seqCert.getData()).getSequence(3);
- x509Certs = new X509CertImpl[certs.length];
+ // if seq[3] is available , then it is a sequence of certificates
+ if (seqTmp.length > 3) {
+ // certs are available
+ DerValue seqCert = seqTmp[3];
+ if (!seqCert.isContextSpecific((byte)0)) {
+ throw new IOException("Bad encoding in certs element of " +
+ "OCSP response: expected ASN.1 context specific tag 0.");
+ }
+ DerValue[] certs = seqCert.getData().getSequence(3);
+ x509Certs = new X509CertImpl[certs.length];
+ try {
for (int i = 0; i < certs.length; i++) {
x509Certs[i] = new X509CertImpl(certs[i].toByteArray());
}
+ } catch (CertificateException ce) {
+ throw new IOException("Bad encoding in X509 Certificate", ce);
}
+ }
- // Check whether the cert returned by the responder is trusted
- if (x509Certs != null && x509Certs[0] != null) {
- X509CertImpl cert = x509Certs[0];
+ // Check whether the cert returned by the responder is trusted
+ if (x509Certs != null && x509Certs[0] != null) {
+ X509CertImpl cert = x509Certs[0];
- // First check if the cert matches the responder cert which
- // was set locally.
- if (cert.equals(responderCert)) {
- // cert is trusted, now verify the signed response
+ // First check if the cert matches the responder cert which
+ // was set locally.
+ if (cert.equals(responderCert)) {
+ // cert is trusted, now verify the signed response
- // Next check if the cert was issued by the responder cert
- // which was set locally.
- } else if (cert.getIssuerX500Principal().equals(
- responderCert.getSubjectX500Principal())) {
+ // Next check if the cert was issued by the responder cert
+ // which was set locally.
+ } else if (cert.getIssuerX500Principal().equals(
+ responderCert.getSubjectX500Principal())) {
- // check the certificate algorithm
- AlgorithmChecker.check(cert);
-
- // Check for the OCSPSigning key purpose
+ // Check for the OCSPSigning key purpose
+ try {
List<String> keyPurposes = cert.getExtendedKeyUsage();
if (keyPurposes == null ||
!keyPurposes.contains(KP_OCSP_SIGNING_OID)) {
- if (DEBUG != null) {
- DEBUG.println("Responder's certificate is not " +
- "valid for signing OCSP responses.");
- }
throw new CertPathValidatorException(
"Responder's certificate not valid for signing " +
"OCSP responses");
}
-
- // check the validity
- try {
- Date dateCheckedAgainst = params.getDate();
- if (dateCheckedAgainst == null) {
- cert.checkValidity();
- } else {
- cert.checkValidity(dateCheckedAgainst);
- }
- } catch (GeneralSecurityException e) {
- if (DEBUG != null) {
- DEBUG.println("Responder's certificate is not " +
- "within the validity period.");
- }
- throw new CertPathValidatorException(
- "Responder's certificate not within the " +
- "validity period");
- }
+ } catch (CertificateParsingException cpe) {
+ // assume cert is not valid for signing
+ throw new CertPathValidatorException(
+ "Responder's certificate not valid for signing " +
+ "OCSP responses", cpe);
+ }
- // check for revocation
- //
- // A CA may specify that an OCSP client can trust a
- // responder for the lifetime of the responder's
- // certificate. The CA does so by including the
- // extension id-pkix-ocsp-nocheck.
- //
- Extension noCheck =
- cert.getExtension(PKIXExtensions.OCSPNoCheck_Id);
- if (noCheck != null) {
- if (DEBUG != null) {
- DEBUG.println("Responder's certificate includes " +
- "the extension id-pkix-ocsp-nocheck.");
- }
+ // check the validity
+ try {
+ if (dateCheckedAgainst == null) {
+ cert.checkValidity();
} else {
- // we should do the revocating checking of the
- // authorized responder in a future update.
+ cert.checkValidity(dateCheckedAgainst);
}
+ } catch (GeneralSecurityException e) {
+ throw new CertPathValidatorException(
+ "Responder's certificate not within the " +
+ "validity period", e);
+ }
- // verify the signature
- try {
- cert.verify(responderCert.getPublicKey());
- responderCert = cert;
- // cert is trusted, now verify the signed response
-
- } catch (GeneralSecurityException e) {
- responderCert = null;
+ // check for revocation
+ //
+ // A CA may specify that an OCSP client can trust a
+ // responder for the lifetime of the responder's
+ // certificate. The CA does so by including the
+ // extension id-pkix-ocsp-nocheck.
+ //
+ Extension noCheck =
+ cert.getExtension(PKIXExtensions.OCSPNoCheck_Id);
+ if (noCheck != null) {
+ if (DEBUG != null) {
+ DEBUG.println("Responder's certificate includes " +
+ "the extension id-pkix-ocsp-nocheck.");
}
} else {
- if (DEBUG != null) {
- DEBUG.println("Responder's certificate is not " +
- "authorized to sign OCSP responses.");
- }
- throw new CertPathValidatorException(
- "Responder's certificate not authorized to sign " +
- "OCSP responses");
+ // we should do the revocation checking of the
+ // authorized responder in a future update.
}
- }
- // Confirm that the signed response was generated using the public
- // key from the trusted responder cert
- if (responderCert != null) {
+ // verify the signature
+ try {
+ cert.verify(responderCert.getPublicKey());
+ responderCert = cert;
+ // cert is trusted, now verify the signed response
- if (! verifyResponse(responseDataDer, responderCert,
- sigAlgId, signature, params)) {
- if (DEBUG != null) {
- DEBUG.println("Error verifying OCSP Responder's " +
- "signature");
- }
- throw new CertPathValidatorException(
- "Error verifying OCSP Responder's signature");
+ } catch (GeneralSecurityException e) {
+ responderCert = null;
}
} else {
- // Need responder's cert in order to verify the signature
- if (DEBUG != null) {
- DEBUG.println("Unable to verify OCSP Responder's " +
- "signature");
- }
+ throw new CertPathValidatorException(
+ "Responder's certificate is not authorized to sign " +
+ "OCSP responses");
+ }
+ }
+
+ // Confirm that the signed response was generated using the public
+ // key from the trusted responder cert
+ if (responderCert != null) {
+ if (!verifyResponse(responseDataDer, responderCert,
+ sigAlgId, signature)) {
throw new CertPathValidatorException(
- "Unable to verify OCSP Responder's signature");
+ "Error verifying OCSP Responder's signature");
}
- } catch (CertPathValidatorException cpve) {
- throw cpve;
- } catch (Exception e) {
- throw new CertPathValidatorException(e);
+ } else {
+ // Need responder's cert in order to verify the signature
+ throw new CertPathValidatorException(
+ "Unable to verify OCSP Responder's signature");
}
}
+ /**
+ * Returns the OCSP ResponseStatus.
+ */
+ ResponseStatus getResponseStatus() {
+ return responseStatus;
+ }
+
/*
* Verify the signature of the OCSP response.
* The responder's cert is implicitly trusted.
*/
private boolean verifyResponse(byte[] responseData, X509Certificate cert,
- AlgorithmId sigAlgId, byte[] signBytes, PKIXParameters params)
- throws SignatureException {
+ AlgorithmId sigAlgId, byte[] signBytes)
+ throws CertPathValidatorException {
try {
-
Signature respSignature = Signature.getInstance(sigAlgId.getName());
respSignature.initVerify(cert);
respSignature.update(responseData);
@@ -483,92 +468,33 @@
return false;
}
} catch (InvalidKeyException ike) {
- throw new SignatureException(ike);
-
+ throw new CertPathValidatorException(ike);
} catch (NoSuchAlgorithmException nsae) {
- throw new SignatureException(nsae);
+ throw new CertPathValidatorException(nsae);
+ } catch (SignatureException se) {
+ throw new CertPathValidatorException(se);
}
}
- /*
- * Return the revocation status code for a given certificate.
- */
- // used by OCSPChecker
- int getCertStatus(SerialNumber sn) {
- // ignore serial number for now; if we support multiple
- // requests/responses then it will be used
- return singleResponse.getStatus();
- }
-
- // used by OCSPChecker
- CertId getCertId() {
- return singleResponse.getCertId();
- }
-
- Date getRevocationTime() {
- return singleResponse.getRevocationTime();
- }
-
- CRLReason getRevocationReason() {
- return singleResponse.getRevocationReason();
- }
-
- Map<String, java.security.cert.Extension> getSingleExtensions() {
- return singleResponse.getSingleExtensions();
- }
-
- /*
- * Map an OCSP response status code to a string.
+ /**
+ * Returns the SingleResponse of the specified CertId, or null if
+ * there is no response for that CertId.
*/
- static private String responseToText(int status) {
- switch (status) {
- case 0:
- return "Successful";
- case 1:
- return "Malformed request";
- case 2:
- return "Internal error";
- case 3:
- return "Try again later";
- case 4:
- return "Unused status code";
- case 5:
- return "Request must be signed";
- case 6:
- return "Request is unauthorized";
- default:
- return ("Unknown status code: " + status);
- }
- }
-
- /*
- * Map a certificate's revocation status code to a string.
- */
- // used by OCSPChecker
- static String certStatusToText(int certStatus) {
- switch (certStatus) {
- case 0:
- return "Good";
- case 1:
- return "Revoked";
- case 2:
- return "Unknown";
- default:
- return ("Unknown certificate status code: " + certStatus);
- }
+ SingleResponse getSingleResponse(CertId certId) {
+ return singleResponseMap.get(certId);
}
/*
* A class representing a single OCSP response.
*/
- private class SingleResponse {
- private CertId certId;
- private int certStatus;
- private Date thisUpdate;
- private Date nextUpdate;
- private Date revocationTime;
- private CRLReason revocationReason = CRLReason.UNSPECIFIED;
- private HashMap<String, java.security.cert.Extension> singleExtensions;
+ final static class SingleResponse implements OCSP.RevocationStatus {
+ private final CertId certId;
+ private final CertStatus certStatus;
+ private final Date thisUpdate;
+ private final Date nextUpdate;
+ private final Date revocationTime;
+ private final CRLReason revocationReason;
+ private final Map<String, java.security.cert.Extension> singleExtensions;
private SingleResponse(DerValue der) throws IOException {
if (der.tag != DerValue.tag_Sequence) {
@@ -579,35 +505,48 @@
certId = new CertId(tmp.getDerValue().data);
DerValue derVal = tmp.getDerValue();
short tag = (byte)(derVal.tag & 0x1f);
- if (tag == CERT_STATUS_GOOD) {
- certStatus = CERT_STATUS_GOOD;
- } else if (tag == CERT_STATUS_REVOKED) {
- certStatus = CERT_STATUS_REVOKED;
+ if (tag == CERT_STATUS_REVOKED) {
+ certStatus = CertStatus.REVOKED;
revocationTime = derVal.data.getGeneralizedTime();
if (derVal.data.available() != 0) {
- int reason = derVal.getEnumerated();
- // if reason out-of-range just leave as UNSPECIFIED
- if (reason >= 0 && reason < values.length) {
- revocationReason = values[reason];
+ DerValue dv = derVal.data.getDerValue();
+ tag = (byte)(dv.tag & 0x1f);
+ if (tag == 0) {
+ int reason = dv.data.getEnumerated();
+ // if reason out-of-range just leave as UNSPECIFIED
+ if (reason >= 0 && reason < values.length) {
+ revocationReason = values[reason];
+ } else {
+ revocationReason = CRLReason.UNSPECIFIED;
+ }
+ } else {
+ revocationReason = CRLReason.UNSPECIFIED;
}
+ } else {
+ revocationReason = CRLReason.UNSPECIFIED;
}
// RevokedInfo
if (DEBUG != null) {
DEBUG.println("Revocation time: " + revocationTime);
DEBUG.println("Revocation reason: " + revocationReason);
}
-
- } else if (tag == CERT_STATUS_UNKNOWN) {
- certStatus = CERT_STATUS_UNKNOWN;
-
} else {
- throw new IOException("Invalid certificate status");
+ revocationTime = null;
+ revocationReason = CRLReason.UNSPECIFIED;
+ if (tag == CERT_STATUS_GOOD) {
+ certStatus = CertStatus.GOOD;
+ } else if (tag == CERT_STATUS_UNKNOWN) {
+ certStatus = CertStatus.UNKNOWN;
+ } else {
+ throw new IOException("Invalid certificate status");
+ }
}
thisUpdate = tmp.getGeneralizedTime();
if (tmp.available() == 0) {
// we are done
+ nextUpdate = null;
} else {
derVal = tmp.getDerValue();
tag = (byte)(derVal.tag & 0x1f);
@@ -621,6 +560,8 @@
derVal = tmp.getDerValue();
tag = (byte)(derVal.tag & 0x1f);
}
+ } else {
+ nextUpdate = null;
}
}
// singleExtensions
@@ -638,7 +579,11 @@
DEBUG.println("OCSP single extension: " + ext);
}
}
+ } else {
+ singleExtensions = Collections.emptyMap();
}
+ } else {
+ singleExtensions = Collections.emptyMap();
}
long now = System.currentTimeMillis();
@@ -668,7 +613,7 @@
/*
* Return the certificate's revocation status code
*/
- private int getStatus() {
+ @Override public CertStatus getCertStatus() {
return certStatus;
}
@@ -676,28 +621,28 @@
return certId;
}
- private Date getRevocationTime() {
- return revocationTime;
+ @Override public Date getRevocationTime() {
+ return (Date) revocationTime.clone();
}
- private CRLReason getRevocationReason() {
+ @Override public CRLReason getRevocationReason() {
return revocationReason;
}
- private Map<String, java.security.cert.Extension> getSingleExtensions() {
- return singleExtensions;
+ @Override
+ public Map<String, java.security.cert.Extension> getSingleExtensions() {
+ return Collections.unmodifiableMap(singleExtensions);
}
/**
* Construct a string representation of a single OCSP response.
*/
- public String toString() {
+ @Override public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("SingleResponse: \n");
sb.append(certId);
- sb.append("\nCertStatus: "+ certStatusToText(getCertStatus(null)) +
- "\n");
- if (certStatus == CERT_STATUS_REVOKED) {
+ sb.append("\nCertStatus: "+ certStatus + "\n");
+ if (certStatus == CertStatus.REVOKED) {
sb.append("revocationTime is " + revocationTime + "\n");
sb.append("revocationReason is " + revocationReason + "\n");
}