6745437: Add option to only check revocation of end-entity certificate in a chain of certificates
6869739: Cannot check revocation of single certificate without validating the entire chain Reviewed-by: xuelei
This commit is contained in:
parent
9ef7eb7884
commit
106b2d9f64
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package sun.security.action;
|
||||
|
||||
import java.security.Security;
|
||||
|
||||
/**
|
||||
* A convenience class for retrieving the boolean value of a security property
|
||||
* as a privileged action.
|
||||
*
|
||||
* <p>An instance of this class can be used as the argument of
|
||||
* <code>AccessController.doPrivileged</code>.
|
||||
*
|
||||
* <p>The following code retrieves the boolean value of the security
|
||||
* property named <code>"prop"</code> as a privileged action: <p>
|
||||
*
|
||||
* <pre>
|
||||
* boolean b = java.security.AccessController.doPrivileged
|
||||
* (new GetBooleanSecurityPropertyAction("prop")).booleanValue();
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public class GetBooleanSecurityPropertyAction
|
||||
implements java.security.PrivilegedAction<Boolean> {
|
||||
private String theProp;
|
||||
|
||||
/**
|
||||
* Constructor that takes the name of the security property whose boolean
|
||||
* value needs to be determined.
|
||||
*
|
||||
* @param theProp the name of the security property
|
||||
*/
|
||||
public GetBooleanSecurityPropertyAction(String theProp) {
|
||||
this.theProp = theProp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the boolean value of the security property whose name was
|
||||
* specified in the constructor.
|
||||
*
|
||||
* @return the <code>Boolean</code> value of the security property.
|
||||
*/
|
||||
public Boolean run() {
|
||||
boolean b = false;
|
||||
try {
|
||||
String value = Security.getProperty(theProp);
|
||||
b = (value != null) && value.equalsIgnoreCase("true");
|
||||
} catch (NullPointerException e) {}
|
||||
return b;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,12 +26,14 @@
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.cert.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.x509.GeneralNames;
|
||||
import sun.security.x509.GeneralNameInterface;
|
||||
@ -64,9 +66,8 @@ public abstract class Builder {
|
||||
* Authority Information Access extension shall be enabled. Currently
|
||||
* disabled by default for compatibility reasons.
|
||||
*/
|
||||
final static boolean USE_AIA =
|
||||
DistributionPointFetcher.getBooleanProperty
|
||||
("com.sun.security.enableAIAcaIssuers", false);
|
||||
final static boolean USE_AIA = AccessController.doPrivileged
|
||||
(new GetBooleanAction("com.sun.security.enableAIAcaIssuers"));
|
||||
|
||||
/**
|
||||
* Initialize the builder with the input parameters.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,9 +25,11 @@
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import sun.misc.HexDumpEncoder;
|
||||
import sun.security.x509.*;
|
||||
@ -54,21 +56,28 @@ import sun.security.util.*;
|
||||
public class CertId {
|
||||
|
||||
private static final boolean debug = false;
|
||||
private AlgorithmId hashAlgId;
|
||||
private byte[] issuerNameHash;
|
||||
private byte[] issuerKeyHash;
|
||||
private SerialNumber certSerialNumber;
|
||||
private static final AlgorithmId SHA1_ALGID
|
||||
= new AlgorithmId(AlgorithmId.SHA_oid);
|
||||
private final AlgorithmId hashAlgId;
|
||||
private final byte[] issuerNameHash;
|
||||
private final byte[] issuerKeyHash;
|
||||
private final SerialNumber certSerialNumber;
|
||||
private int myhash = -1; // hashcode for this CertId
|
||||
|
||||
/**
|
||||
* Creates a CertId. The hash algorithm used is SHA-1.
|
||||
*/
|
||||
public CertId(X509CertImpl issuerCert, SerialNumber serialNumber)
|
||||
throws Exception {
|
||||
public CertId(X509Certificate issuerCert, SerialNumber serialNumber)
|
||||
throws IOException {
|
||||
|
||||
// compute issuerNameHash
|
||||
MessageDigest md = MessageDigest.getInstance("SHA1");
|
||||
hashAlgId = AlgorithmId.get("SHA1");
|
||||
MessageDigest md = null;
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA1");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new IOException("Unable to create CertId", nsae);
|
||||
}
|
||||
hashAlgId = SHA1_ALGID;
|
||||
md.update(issuerCert.getSubjectX500Principal().getEncoded());
|
||||
issuerNameHash = md.digest();
|
||||
|
||||
@ -90,6 +99,7 @@ public class CertId {
|
||||
encoder.encode(issuerNameHash));
|
||||
System.out.println("issuerKeyHash is " +
|
||||
encoder.encode(issuerKeyHash));
|
||||
System.out.println("SerialNumber is " + serialNumber.getNumber());
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,7 +107,6 @@ public class CertId {
|
||||
* Creates a CertId from its ASN.1 DER encoding.
|
||||
*/
|
||||
public CertId(DerInputStream derIn) throws IOException {
|
||||
|
||||
hashAlgId = AlgorithmId.parse(derIn.getDerValue());
|
||||
issuerNameHash = derIn.getOctetString();
|
||||
issuerKeyHash = derIn.getOctetString();
|
||||
@ -157,7 +166,7 @@ public class CertId {
|
||||
*
|
||||
* @return the hashcode value.
|
||||
*/
|
||||
public int hashCode() {
|
||||
@Override public int hashCode() {
|
||||
if (myhash == -1) {
|
||||
myhash = hashAlgId.hashCode();
|
||||
for (int i = 0; i < issuerNameHash.length; i++) {
|
||||
@ -180,8 +189,7 @@ public class CertId {
|
||||
* @param other the object to test for equality with this object.
|
||||
* @return true if the objects are considered equal, false otherwise.
|
||||
*/
|
||||
public boolean equals(Object other) {
|
||||
|
||||
@Override public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
@ -203,7 +211,7 @@ public class CertId {
|
||||
/**
|
||||
* Create a string representation of the CertId.
|
||||
*/
|
||||
public String toString() {
|
||||
@Override public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("CertId \n");
|
||||
sb.append("Algorithm: " + hashAlgId.toString() +"\n");
|
||||
|
@ -80,6 +80,7 @@ class CrlRevocationChecker extends PKIXCertPathChecker {
|
||||
{ false, false, false, false, false, false, true };
|
||||
private static final boolean[] ALL_REASONS =
|
||||
{true, true, true, true, true, true, true, true, true};
|
||||
private boolean mOnlyEECert = false;
|
||||
|
||||
// Maximum clock skew in milliseconds (15 minutes) allowed when checking
|
||||
// validity of CRLs
|
||||
@ -114,6 +115,12 @@ class CrlRevocationChecker extends PKIXCertPathChecker {
|
||||
CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params,
|
||||
Collection<X509Certificate> certs) throws CertPathValidatorException
|
||||
{
|
||||
this(anchor, params, certs, false);
|
||||
}
|
||||
|
||||
CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params,
|
||||
Collection<X509Certificate> certs, boolean onlyEECert)
|
||||
throws CertPathValidatorException {
|
||||
mAnchor = anchor;
|
||||
mParams = params;
|
||||
mStores = new ArrayList<CertStore>(params.getCertStores());
|
||||
@ -133,6 +140,7 @@ class CrlRevocationChecker extends PKIXCertPathChecker {
|
||||
}
|
||||
Date testDate = params.getDate();
|
||||
mCurrentTime = (testDate != null ? testDate : new Date());
|
||||
mOnlyEECert = onlyEECert;
|
||||
init(false);
|
||||
}
|
||||
|
||||
@ -264,6 +272,13 @@ class CrlRevocationChecker extends PKIXCertPathChecker {
|
||||
" ---checking " + msg + "...");
|
||||
}
|
||||
|
||||
if (mOnlyEECert && currCert.getBasicConstraints() != -1) {
|
||||
if (debug != null) {
|
||||
debug.println("Skipping revocation check, not end entity cert");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// reject circular dependencies - RFC 3280 is not explicit on how
|
||||
// to handle this, so we feel it is safest to reject them until
|
||||
// the issue is resolved in the PKIX WG.
|
||||
|
@ -32,7 +32,7 @@ import java.security.*;
|
||||
import java.security.cert.*;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.DerOutputStream;
|
||||
import sun.security.x509.*;
|
||||
@ -62,28 +62,8 @@ class DistributionPointFetcher {
|
||||
* extension shall be enabled. Currently disabled by default for
|
||||
* compatibility and legal reasons.
|
||||
*/
|
||||
private final static boolean USE_CRLDP =
|
||||
getBooleanProperty("com.sun.security.enableCRLDP", false);
|
||||
|
||||
/**
|
||||
* Return the value of the boolean System property propName.
|
||||
*/
|
||||
public static boolean getBooleanProperty(String propName,
|
||||
boolean defaultValue) {
|
||||
// if set, require value of either true or false
|
||||
String b = AccessController.doPrivileged(
|
||||
new GetPropertyAction(propName));
|
||||
if (b == null) {
|
||||
return defaultValue;
|
||||
} else if (b.equalsIgnoreCase("false")) {
|
||||
return false;
|
||||
} else if (b.equalsIgnoreCase("true")) {
|
||||
return true;
|
||||
} else {
|
||||
throw new RuntimeException("Value of " + propName
|
||||
+ " must either be 'true' or 'false'");
|
||||
}
|
||||
}
|
||||
private final static boolean USE_CRLDP = AccessController.doPrivileged
|
||||
(new GetBooleanAction("com.sun.security.enableCRLDP"));
|
||||
|
||||
// singleton instance
|
||||
private static final DistributionPointFetcher INSTANCE =
|
||||
|
@ -82,6 +82,7 @@ class ForwardBuilder extends Builder {
|
||||
TrustAnchor trustAnchor;
|
||||
private Comparator<X509Certificate> comparator;
|
||||
private boolean searchAllCertStores = true;
|
||||
private boolean onlyEECert = false;
|
||||
|
||||
/**
|
||||
* Initialize the builder with the input parameters.
|
||||
@ -89,7 +90,8 @@ class ForwardBuilder extends Builder {
|
||||
* @param params the parameter set used to build a certification path
|
||||
*/
|
||||
ForwardBuilder(PKIXBuilderParameters buildParams,
|
||||
X500Principal targetSubjectDN, boolean searchAllCertStores)
|
||||
X500Principal targetSubjectDN, boolean searchAllCertStores,
|
||||
boolean onlyEECert)
|
||||
{
|
||||
super(buildParams, targetSubjectDN);
|
||||
|
||||
@ -108,6 +110,7 @@ class ForwardBuilder extends Builder {
|
||||
}
|
||||
comparator = new PKIXCertComparator(trustedSubjectDNs);
|
||||
this.searchAllCertStores = searchAllCertStores;
|
||||
this.onlyEECert = onlyEECert;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -875,8 +878,8 @@ class ForwardBuilder extends Builder {
|
||||
/* Check revocation if it is enabled */
|
||||
if (buildParams.isRevocationEnabled()) {
|
||||
try {
|
||||
CrlRevocationChecker crlChecker =
|
||||
new CrlRevocationChecker(anchor, buildParams);
|
||||
CrlRevocationChecker crlChecker = new CrlRevocationChecker
|
||||
(anchor, buildParams, null, onlyEECert);
|
||||
crlChecker.check(cert, anchor.getCAPublicKey(), true);
|
||||
} catch (CertPathValidatorException cpve) {
|
||||
if (debug != null) {
|
||||
|
329
jdk/src/share/classes/sun/security/provider/certpath/OCSP.java
Normal file
329
jdk/src/share/classes/sun/security/provider/certpath/OCSP.java
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.CRLReason;
|
||||
import java.security.cert.Extension;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static sun.security.provider.certpath.OCSPResponse.*;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.x509.AccessDescription;
|
||||
import sun.security.x509.AuthorityInfoAccessExtension;
|
||||
import sun.security.x509.GeneralName;
|
||||
import sun.security.x509.GeneralNameInterface;
|
||||
import sun.security.x509.URIName;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
|
||||
/**
|
||||
* This is a class that checks the revocation status of a certificate(s) using
|
||||
* OCSP. It is not a PKIXCertPathChecker and therefore can be used outside of
|
||||
* the CertPathValidator framework. It is useful when you want to
|
||||
* just check the revocation status of a certificate, and you don't want to
|
||||
* incur the overhead of validating all of the certificates in the
|
||||
* associated certificate chain.
|
||||
*
|
||||
* @author Sean Mullan
|
||||
*/
|
||||
public final class OCSP {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
private OCSP() {}
|
||||
|
||||
/**
|
||||
* Obtains the revocation status of a certificate using OCSP using the most
|
||||
* common defaults. The OCSP responder URI is retrieved from the
|
||||
* certificate's AIA extension. The OCSP responder certificate is assumed
|
||||
* to be the issuer's certificate (or issued by the issuer CA).
|
||||
*
|
||||
* @param cert the certificate to be checked
|
||||
* @param issuerCert the issuer certificate
|
||||
* @return the RevocationStatus
|
||||
* @throws IOException if there is an exception connecting to or
|
||||
* communicating with the OCSP responder
|
||||
* @throws CertPathValidatorException if an exception occurs while
|
||||
* encoding the OCSP Request or validating the OCSP Response
|
||||
*/
|
||||
public static RevocationStatus check(X509Certificate cert,
|
||||
X509Certificate issuerCert)
|
||||
throws IOException, CertPathValidatorException {
|
||||
CertId certId = null;
|
||||
URI responderURI = null;
|
||||
try {
|
||||
X509CertImpl certImpl = X509CertImpl.toImpl(cert);
|
||||
responderURI = getResponderURI(certImpl);
|
||||
if (responderURI == null) {
|
||||
throw new CertPathValidatorException
|
||||
("No OCSP Responder URI in certificate");
|
||||
}
|
||||
certId = new CertId(issuerCert, certImpl.getSerialNumberObject());
|
||||
} catch (CertificateException ce) {
|
||||
throw new CertPathValidatorException
|
||||
("Exception while encoding OCSPRequest", ce);
|
||||
} catch (IOException ioe) {
|
||||
throw new CertPathValidatorException
|
||||
("Exception while encoding OCSPRequest", ioe);
|
||||
}
|
||||
OCSPResponse ocspResponse = check(Collections.singletonList(certId),
|
||||
responderURI, issuerCert, null);
|
||||
return (RevocationStatus) ocspResponse.getSingleResponse(certId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the revocation status of a certificate using OCSP.
|
||||
*
|
||||
* @param cert the certificate to be checked
|
||||
* @param issuerCert the issuer certificate
|
||||
* @param responderURI the URI of the OCSP responder
|
||||
* @param responderCert the OCSP responder's certificate
|
||||
* @param date the time the validity of the OCSP responder's certificate
|
||||
* should be checked against. If null, the current time is used.
|
||||
* @return the RevocationStatus
|
||||
* @throws IOException if there is an exception connecting to or
|
||||
* communicating with the OCSP responder
|
||||
* @throws CertPathValidatorException if an exception occurs while
|
||||
* encoding the OCSP Request or validating the OCSP Response
|
||||
*/
|
||||
public static RevocationStatus check(X509Certificate cert,
|
||||
X509Certificate issuerCert, URI responderURI, X509Certificate
|
||||
responderCert, Date date)
|
||||
throws IOException, CertPathValidatorException {
|
||||
CertId certId = null;
|
||||
try {
|
||||
X509CertImpl certImpl = X509CertImpl.toImpl(cert);
|
||||
certId = new CertId(issuerCert, certImpl.getSerialNumberObject());
|
||||
} catch (CertificateException ce) {
|
||||
throw new CertPathValidatorException
|
||||
("Exception while encoding OCSPRequest", ce);
|
||||
} catch (IOException ioe) {
|
||||
throw new CertPathValidatorException
|
||||
("Exception while encoding OCSPRequest", ioe);
|
||||
}
|
||||
OCSPResponse ocspResponse = check(Collections.singletonList(certId),
|
||||
responderURI, responderCert, date);
|
||||
return (RevocationStatus) ocspResponse.getSingleResponse(certId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the revocation status of a list of certificates using OCSP.
|
||||
*
|
||||
* @param certs the CertIds to be checked
|
||||
* @param responderURI the URI of the OCSP responder
|
||||
* @param responderCert the OCSP responder's certificate
|
||||
* @param date the time the validity of the OCSP responder's certificate
|
||||
* should be checked against. If null, the current time is used.
|
||||
* @return the OCSPResponse
|
||||
* @throws IOException if there is an exception connecting to or
|
||||
* communicating with the OCSP responder
|
||||
* @throws CertPathValidatorException if an exception occurs while
|
||||
* encoding the OCSP Request or validating the OCSP Response
|
||||
*/
|
||||
static OCSPResponse check(List<CertId> certIds, URI responderURI,
|
||||
X509Certificate responderCert, Date date)
|
||||
throws IOException, CertPathValidatorException {
|
||||
|
||||
byte[] bytes = null;
|
||||
try {
|
||||
OCSPRequest request = new OCSPRequest(certIds);
|
||||
bytes = request.encodeBytes();
|
||||
} catch (IOException ioe) {
|
||||
throw new CertPathValidatorException
|
||||
("Exception while encoding OCSPRequest", ioe);
|
||||
}
|
||||
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
byte[] response = null;
|
||||
try {
|
||||
URL url = responderURI.toURL();
|
||||
if (debug != null) {
|
||||
debug.println("connecting to OCSP service at: " + url);
|
||||
}
|
||||
HttpURLConnection con = (HttpURLConnection)url.openConnection();
|
||||
con.setDoOutput(true);
|
||||
con.setDoInput(true);
|
||||
con.setRequestMethod("POST");
|
||||
con.setRequestProperty
|
||||
("Content-type", "application/ocsp-request");
|
||||
con.setRequestProperty
|
||||
("Content-length", String.valueOf(bytes.length));
|
||||
out = con.getOutputStream();
|
||||
out.write(bytes);
|
||||
out.flush();
|
||||
// Check the response
|
||||
if (debug != null &&
|
||||
con.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
debug.println("Received HTTP error: " + con.getResponseCode()
|
||||
+ " - " + con.getResponseMessage());
|
||||
}
|
||||
in = con.getInputStream();
|
||||
int contentLength = con.getContentLength();
|
||||
if (contentLength == -1) {
|
||||
contentLength = Integer.MAX_VALUE;
|
||||
}
|
||||
response = new byte[contentLength > 2048 ? 2048 : contentLength];
|
||||
int total = 0;
|
||||
while (total < contentLength) {
|
||||
int count = in.read(response, total, response.length - total);
|
||||
if (count < 0)
|
||||
break;
|
||||
|
||||
total += count;
|
||||
if (total >= response.length && total < contentLength) {
|
||||
response = Arrays.copyOf(response, total * 2);
|
||||
}
|
||||
}
|
||||
response = Arrays.copyOf(response, total);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ioe) {
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ioe) {
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OCSPResponse ocspResponse = null;
|
||||
try {
|
||||
ocspResponse = new OCSPResponse(response, date, responderCert);
|
||||
} catch (IOException ioe) {
|
||||
// response decoding exception
|
||||
throw new CertPathValidatorException(ioe);
|
||||
}
|
||||
if (ocspResponse.getResponseStatus() != ResponseStatus.SUCCESSFUL) {
|
||||
throw new CertPathValidatorException
|
||||
("OCSP response error: " + ocspResponse.getResponseStatus());
|
||||
}
|
||||
|
||||
// Check that the response includes a response for all of the
|
||||
// certs that were supplied in the request
|
||||
for (CertId certId : certIds) {
|
||||
SingleResponse sr = ocspResponse.getSingleResponse(certId);
|
||||
if (sr == null) {
|
||||
if (debug != null) {
|
||||
debug.println("No response found for CertId: " + certId);
|
||||
}
|
||||
throw new CertPathValidatorException(
|
||||
"OCSP response does not include a response for a " +
|
||||
"certificate supplied in the OCSP request");
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println("Status of certificate (with serial number " +
|
||||
certId.getSerialNumber() + ") is: " + sr.getCertStatus());
|
||||
}
|
||||
}
|
||||
return ocspResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URI of the OCSP Responder as specified in the
|
||||
* certificate's Authority Information Access extension, or null if
|
||||
* not specified.
|
||||
*
|
||||
* @param cert the certificate
|
||||
* @return the URI of the OCSP Responder, or null if not specified
|
||||
*/
|
||||
public static URI getResponderURI(X509Certificate cert) {
|
||||
try {
|
||||
return getResponderURI(X509CertImpl.toImpl(cert));
|
||||
} catch (CertificateException ce) {
|
||||
// treat this case as if the cert had no extension
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static URI getResponderURI(X509CertImpl certImpl) {
|
||||
|
||||
// Examine the certificate's AuthorityInfoAccess extension
|
||||
AuthorityInfoAccessExtension aia =
|
||||
certImpl.getAuthorityInfoAccessExtension();
|
||||
if (aia == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<AccessDescription> descriptions = aia.getAccessDescriptions();
|
||||
for (AccessDescription description : descriptions) {
|
||||
if (description.getAccessMethod().equals(
|
||||
AccessDescription.Ad_OCSP_Id)) {
|
||||
|
||||
GeneralName generalName = description.getAccessLocation();
|
||||
if (generalName.getType() == GeneralNameInterface.NAME_URI) {
|
||||
URIName uri = (URIName) generalName.getName();
|
||||
return uri.getURI();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Revocation Status of a certificate.
|
||||
*/
|
||||
public static interface RevocationStatus {
|
||||
public enum CertStatus { GOOD, REVOKED, UNKNOWN };
|
||||
|
||||
/**
|
||||
* Returns the revocation status.
|
||||
*/
|
||||
CertStatus getCertStatus();
|
||||
/**
|
||||
* Returns the time when the certificate was revoked, or null
|
||||
* if it has not been revoked.
|
||||
*/
|
||||
Date getRevocationTime();
|
||||
/**
|
||||
* Returns the reason the certificate was revoked, or null if it
|
||||
* has not been revoked.
|
||||
*/
|
||||
CRLReason getRevocationReason();
|
||||
|
||||
/**
|
||||
* Returns a Map of additional extensions.
|
||||
*/
|
||||
Map<String, Extension> getSingleExtensions();
|
||||
}
|
||||
}
|
@ -25,19 +25,20 @@
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.Security;
|
||||
import java.security.cert.*;
|
||||
import java.security.cert.CertPathValidatorException.BasicReason;
|
||||
import java.net.*;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.security.util.*;
|
||||
import static sun.security.provider.certpath.OCSP.*;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.x509.*;
|
||||
|
||||
/**
|
||||
@ -50,27 +51,18 @@ import sun.security.x509.*;
|
||||
*/
|
||||
class OCSPChecker extends PKIXCertPathChecker {
|
||||
|
||||
public static final String OCSP_ENABLE_PROP = "ocsp.enable";
|
||||
public static final String OCSP_URL_PROP = "ocsp.responderURL";
|
||||
public static final String OCSP_CERT_SUBJECT_PROP =
|
||||
static final String OCSP_ENABLE_PROP = "ocsp.enable";
|
||||
static final String OCSP_URL_PROP = "ocsp.responderURL";
|
||||
static final String OCSP_CERT_SUBJECT_PROP =
|
||||
"ocsp.responderCertSubjectName";
|
||||
public static final String OCSP_CERT_ISSUER_PROP =
|
||||
"ocsp.responderCertIssuerName";
|
||||
public static final String OCSP_CERT_NUMBER_PROP =
|
||||
static final String OCSP_CERT_ISSUER_PROP = "ocsp.responderCertIssuerName";
|
||||
static final String OCSP_CERT_NUMBER_PROP =
|
||||
"ocsp.responderCertSerialNumber";
|
||||
|
||||
private static final String HEX_DIGITS = "0123456789ABCDEFabcdef";
|
||||
private static final Debug DEBUG = Debug.getInstance("certpath");
|
||||
private static final boolean dump = false;
|
||||
|
||||
// Supported extensions
|
||||
private static final int OCSP_NONCE_DATA[] =
|
||||
{ 1, 3, 6, 1, 5, 5, 7, 48, 1, 2 };
|
||||
private static final ObjectIdentifier OCSP_NONCE_OID;
|
||||
static {
|
||||
OCSP_NONCE_OID = ObjectIdentifier.newInternal(OCSP_NONCE_DATA);
|
||||
}
|
||||
|
||||
private int remainingCerts;
|
||||
|
||||
private X509Certificate[] certs;
|
||||
@ -79,19 +71,26 @@ class OCSPChecker extends PKIXCertPathChecker {
|
||||
|
||||
private PKIXParameters pkixParams;
|
||||
|
||||
private boolean onlyEECert = false;
|
||||
|
||||
/**
|
||||
* Default Constructor
|
||||
*
|
||||
* @param certPath the X509 certification path
|
||||
* @param pkixParams the input PKIX parameter set
|
||||
* @exception CertPathValidatorException Exception thrown if cert path
|
||||
* does not validate.
|
||||
* @throws CertPathValidatorException if OCSPChecker can not be created
|
||||
*/
|
||||
OCSPChecker(CertPath certPath, PKIXParameters pkixParams)
|
||||
throws CertPathValidatorException {
|
||||
this(certPath, pkixParams, false);
|
||||
}
|
||||
|
||||
OCSPChecker(CertPath certPath, PKIXParameters pkixParams, boolean onlyEECert)
|
||||
throws CertPathValidatorException {
|
||||
|
||||
this.cp = certPath;
|
||||
this.pkixParams = pkixParams;
|
||||
this.onlyEECert = onlyEECert;
|
||||
List<? extends Certificate> tmp = cp.getCertificates();
|
||||
certs = tmp.toArray(new X509Certificate[tmp.size()]);
|
||||
init(false);
|
||||
@ -101,6 +100,7 @@ class OCSPChecker extends PKIXCertPathChecker {
|
||||
* Initializes the internal state of the checker from parameters
|
||||
* specified in the constructor
|
||||
*/
|
||||
@Override
|
||||
public void init(boolean forward) throws CertPathValidatorException {
|
||||
if (!forward) {
|
||||
remainingCerts = certs.length + 1;
|
||||
@ -110,11 +110,11 @@ class OCSPChecker extends PKIXCertPathChecker {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isForwardCheckingSupported() {
|
||||
@Override public boolean isForwardCheckingSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Set<String> getSupportedExtensions() {
|
||||
@Override public Set<String> getSupportedExtensions() {
|
||||
return Collections.<String>emptySet();
|
||||
}
|
||||
|
||||
@ -127,300 +127,233 @@ class OCSPChecker extends PKIXCertPathChecker {
|
||||
* @exception CertPathValidatorException Exception is thrown if the
|
||||
* certificate has been revoked.
|
||||
*/
|
||||
@Override
|
||||
public void check(Certificate cert, Collection<String> unresolvedCritExts)
|
||||
throws CertPathValidatorException {
|
||||
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
|
||||
// Decrement the certificate counter
|
||||
remainingCerts--;
|
||||
|
||||
X509CertImpl currCertImpl = null;
|
||||
try {
|
||||
X509Certificate responderCert = null;
|
||||
boolean seekResponderCert = false;
|
||||
X500Principal responderSubjectName = null;
|
||||
X500Principal responderIssuerName = null;
|
||||
BigInteger responderSerialNumber = null;
|
||||
currCertImpl = X509CertImpl.toImpl((X509Certificate)cert);
|
||||
} catch (CertificateException ce) {
|
||||
throw new CertPathValidatorException(ce);
|
||||
}
|
||||
|
||||
boolean seekIssuerCert = true;
|
||||
X509CertImpl issuerCertImpl = null;
|
||||
X509CertImpl currCertImpl =
|
||||
X509CertImpl.toImpl((X509Certificate)cert);
|
||||
if (onlyEECert && currCertImpl.getBasicConstraints() != -1) {
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("Skipping revocation check, not end entity cert");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* OCSP security property values, in the following order:
|
||||
* 1. ocsp.responderURL
|
||||
* 2. ocsp.responderCertSubjectName
|
||||
* 3. ocsp.responderCertIssuerName
|
||||
* 4. ocsp.responderCertSerialNumber
|
||||
*/
|
||||
String[] properties = getOCSPProperties();
|
||||
/*
|
||||
* OCSP security property values, in the following order:
|
||||
* 1. ocsp.responderURL
|
||||
* 2. ocsp.responderCertSubjectName
|
||||
* 3. ocsp.responderCertIssuerName
|
||||
* 4. ocsp.responderCertSerialNumber
|
||||
*/
|
||||
// should cache these properties to avoid calling every time?
|
||||
String[] properties = getOCSPProperties();
|
||||
|
||||
// Check whether OCSP is feasible before seeking cert information
|
||||
URL url = getOCSPServerURL(currCertImpl, properties);
|
||||
// Check whether OCSP is feasible before seeking cert information
|
||||
URI uri = getOCSPServerURI(currCertImpl, properties[0]);
|
||||
|
||||
// When responder's subject name is set then the issuer/serial
|
||||
// properties are ignored
|
||||
if (properties[1] != null) {
|
||||
responderSubjectName = new X500Principal(properties[1]);
|
||||
// When responder's subject name is set then the issuer/serial
|
||||
// properties are ignored
|
||||
X500Principal responderSubjectName = null;
|
||||
X500Principal responderIssuerName = null;
|
||||
BigInteger responderSerialNumber = null;
|
||||
if (properties[1] != null) {
|
||||
responderSubjectName = new X500Principal(properties[1]);
|
||||
} else if (properties[2] != null && properties[3] != null) {
|
||||
responderIssuerName = new X500Principal(properties[2]);
|
||||
// remove colon or space separators
|
||||
String value = stripOutSeparators(properties[3]);
|
||||
responderSerialNumber = new BigInteger(value, 16);
|
||||
} else if (properties[2] != null || properties[3] != null) {
|
||||
throw new CertPathValidatorException(
|
||||
"Must specify both ocsp.responderCertIssuerName and " +
|
||||
"ocsp.responderCertSerialNumber properties");
|
||||
}
|
||||
|
||||
} else if (properties[2] != null && properties[3] != null) {
|
||||
responderIssuerName = new X500Principal(properties[2]);
|
||||
// remove colon or space separators
|
||||
String value = stripOutSeparators(properties[3]);
|
||||
responderSerialNumber = new BigInteger(value, 16);
|
||||
// If the OCSP responder cert properties are set then the
|
||||
// identified cert must be located in the trust anchors or
|
||||
// in the cert stores.
|
||||
boolean seekResponderCert = false;
|
||||
if (responderSubjectName != null || responderIssuerName != null) {
|
||||
seekResponderCert = true;
|
||||
}
|
||||
|
||||
} else if (properties[2] != null || properties[3] != null) {
|
||||
// Set the issuer certificate to the next cert in the chain
|
||||
// (unless we're processing the final cert).
|
||||
X509Certificate issuerCert = null;
|
||||
boolean seekIssuerCert = true;
|
||||
X509Certificate responderCert = null;
|
||||
if (remainingCerts < certs.length) {
|
||||
issuerCert = certs[remainingCerts];
|
||||
seekIssuerCert = false; // done
|
||||
|
||||
// By default, the OCSP responder's cert is the same as the
|
||||
// issuer of the cert being validated.
|
||||
if (!seekResponderCert) {
|
||||
responderCert = issuerCert;
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("Responder's certificate is the same " +
|
||||
"as the issuer of the certificate being validated");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check anchor certs for:
|
||||
// - the issuer cert (of the cert being validated)
|
||||
// - the OCSP responder's cert
|
||||
if (seekIssuerCert || seekResponderCert) {
|
||||
|
||||
if (DEBUG != null && seekResponderCert) {
|
||||
DEBUG.println("Searching trust anchors for responder's " +
|
||||
"certificate");
|
||||
}
|
||||
|
||||
// Extract the anchor certs
|
||||
Iterator<TrustAnchor> anchors
|
||||
= pkixParams.getTrustAnchors().iterator();
|
||||
if (!anchors.hasNext()) {
|
||||
throw new CertPathValidatorException(
|
||||
"Must specify both ocsp.responderCertIssuerName and " +
|
||||
"ocsp.responderCertSerialNumber properties");
|
||||
"Must specify at least one trust anchor");
|
||||
}
|
||||
|
||||
// If the OCSP responder cert properties are set then the
|
||||
// identified cert must be located in the trust anchors or
|
||||
// in the cert stores.
|
||||
if (responderSubjectName != null || responderIssuerName != null) {
|
||||
seekResponderCert = true;
|
||||
}
|
||||
X500Principal certIssuerName =
|
||||
currCertImpl.getIssuerX500Principal();
|
||||
while (anchors.hasNext() && (seekIssuerCert || seekResponderCert)) {
|
||||
|
||||
// Set the issuer certificate to the next cert in the chain
|
||||
// (unless we're processing the final cert).
|
||||
if (remainingCerts < certs.length) {
|
||||
issuerCertImpl = X509CertImpl.toImpl(certs[remainingCerts]);
|
||||
seekIssuerCert = false; // done
|
||||
TrustAnchor anchor = anchors.next();
|
||||
X509Certificate anchorCert = anchor.getTrustedCert();
|
||||
X500Principal anchorSubjectName =
|
||||
anchorCert.getSubjectX500Principal();
|
||||
|
||||
// By default, the OCSP responder's cert is the same as the
|
||||
// issuer of the cert being validated.
|
||||
if (! seekResponderCert) {
|
||||
responderCert = certs[remainingCerts];
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("Responder's certificate is the same " +
|
||||
"as the issuer of the certificate being validated");
|
||||
if (dump) {
|
||||
System.out.println("Issuer DN is " + certIssuerName);
|
||||
System.out.println("Subject DN is " + anchorSubjectName);
|
||||
}
|
||||
|
||||
// Check if anchor cert is the issuer cert
|
||||
if (seekIssuerCert &&
|
||||
certIssuerName.equals(anchorSubjectName)) {
|
||||
|
||||
issuerCert = anchorCert;
|
||||
seekIssuerCert = false; // done
|
||||
|
||||
// By default, the OCSP responder's cert is the same as
|
||||
// the issuer of the cert being validated.
|
||||
if (!seekResponderCert && responderCert == null) {
|
||||
responderCert = anchorCert;
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("Responder's certificate is the" +
|
||||
" same as the issuer of the certificate " +
|
||||
"being validated");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if anchor cert is the responder cert
|
||||
if (seekResponderCert) {
|
||||
// Satisfy the responder subject name property only, or
|
||||
// satisfy the responder issuer name and serial number
|
||||
// properties only
|
||||
if ((responderSubjectName != null &&
|
||||
responderSubjectName.equals(anchorSubjectName)) ||
|
||||
(responderIssuerName != null &&
|
||||
responderSerialNumber != null &&
|
||||
responderIssuerName.equals(
|
||||
anchorCert.getIssuerX500Principal()) &&
|
||||
responderSerialNumber.equals(
|
||||
anchorCert.getSerialNumber()))) {
|
||||
|
||||
responderCert = anchorCert;
|
||||
seekResponderCert = false; // done
|
||||
}
|
||||
}
|
||||
}
|
||||
if (issuerCert == null) {
|
||||
throw new CertPathValidatorException(
|
||||
"No trusted certificate for " + currCertImpl.getIssuerDN());
|
||||
}
|
||||
|
||||
// Check anchor certs for:
|
||||
// - the issuer cert (of the cert being validated)
|
||||
// - the OCSP responder's cert
|
||||
if (seekIssuerCert || seekResponderCert) {
|
||||
|
||||
if (DEBUG != null && seekResponderCert) {
|
||||
DEBUG.println("Searching trust anchors for responder's " +
|
||||
// Check cert stores if responder cert has not yet been found
|
||||
if (seekResponderCert) {
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("Searching cert stores for responder's " +
|
||||
"certificate");
|
||||
}
|
||||
|
||||
// Extract the anchor certs
|
||||
Iterator anchors = pkixParams.getTrustAnchors().iterator();
|
||||
if (! anchors.hasNext()) {
|
||||
throw new CertPathValidatorException(
|
||||
"Must specify at least one trust anchor");
|
||||
X509CertSelector filter = null;
|
||||
if (responderSubjectName != null) {
|
||||
filter = new X509CertSelector();
|
||||
filter.setSubject(responderSubjectName);
|
||||
} else if (responderIssuerName != null &&
|
||||
responderSerialNumber != null) {
|
||||
filter = new X509CertSelector();
|
||||
filter.setIssuer(responderIssuerName);
|
||||
filter.setSerialNumber(responderSerialNumber);
|
||||
}
|
||||
|
||||
X500Principal certIssuerName =
|
||||
currCertImpl.getIssuerX500Principal();
|
||||
while (anchors.hasNext() &&
|
||||
(seekIssuerCert || seekResponderCert)) {
|
||||
|
||||
TrustAnchor anchor = (TrustAnchor)anchors.next();
|
||||
X509Certificate anchorCert = anchor.getTrustedCert();
|
||||
X500Principal anchorSubjectName =
|
||||
anchorCert.getSubjectX500Principal();
|
||||
|
||||
if (dump) {
|
||||
System.out.println("Issuer DN is " + certIssuerName);
|
||||
System.out.println("Subject DN is " +
|
||||
anchorSubjectName);
|
||||
}
|
||||
|
||||
// Check if anchor cert is the issuer cert
|
||||
if (seekIssuerCert &&
|
||||
certIssuerName.equals(anchorSubjectName)) {
|
||||
|
||||
issuerCertImpl = X509CertImpl.toImpl(anchorCert);
|
||||
seekIssuerCert = false; // done
|
||||
|
||||
// By default, the OCSP responder's cert is the same as
|
||||
// the issuer of the cert being validated.
|
||||
if (! seekResponderCert && responderCert == null) {
|
||||
responderCert = anchorCert;
|
||||
if (filter != null) {
|
||||
List<CertStore> certStores = pkixParams.getCertStores();
|
||||
for (CertStore certStore : certStores) {
|
||||
Iterator i = null;
|
||||
try {
|
||||
i = certStore.getCertificates(filter).iterator();
|
||||
} catch (CertStoreException cse) {
|
||||
// ignore and try next certStore
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("Responder's certificate is the" +
|
||||
" same as the issuer of the certificate " +
|
||||
"being validated");
|
||||
DEBUG.println("CertStore exception:" + cse);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if anchor cert is the responder cert
|
||||
if (seekResponderCert) {
|
||||
// Satisfy the responder subject name property only, or
|
||||
// satisfy the responder issuer name and serial number
|
||||
// properties only
|
||||
if ((responderSubjectName != null &&
|
||||
responderSubjectName.equals(anchorSubjectName)) ||
|
||||
(responderIssuerName != null &&
|
||||
responderSerialNumber != null &&
|
||||
responderIssuerName.equals(
|
||||
anchorCert.getIssuerX500Principal()) &&
|
||||
responderSerialNumber.equals(
|
||||
anchorCert.getSerialNumber()))) {
|
||||
|
||||
responderCert = anchorCert;
|
||||
if (i.hasNext()) {
|
||||
responderCert = (X509Certificate) i.next();
|
||||
seekResponderCert = false; // done
|
||||
}
|
||||
}
|
||||
}
|
||||
if (issuerCertImpl == null) {
|
||||
throw new CertPathValidatorException(
|
||||
"No trusted certificate for " +
|
||||
currCertImpl.getIssuerDN());
|
||||
}
|
||||
|
||||
// Check cert stores if responder cert has not yet been found
|
||||
if (seekResponderCert) {
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("Searching cert stores for responder's " +
|
||||
"certificate");
|
||||
}
|
||||
X509CertSelector filter = null;
|
||||
if (responderSubjectName != null) {
|
||||
filter = new X509CertSelector();
|
||||
filter.setSubject(responderSubjectName.getName());
|
||||
} else if (responderIssuerName != null &&
|
||||
responderSerialNumber != null) {
|
||||
filter = new X509CertSelector();
|
||||
filter.setIssuer(responderIssuerName.getName());
|
||||
filter.setSerialNumber(responderSerialNumber);
|
||||
}
|
||||
if (filter != null) {
|
||||
List<CertStore> certStores = pkixParams.getCertStores();
|
||||
for (CertStore certStore : certStores) {
|
||||
Iterator i =
|
||||
certStore.getCertificates(filter).iterator();
|
||||
if (i.hasNext()) {
|
||||
responderCert = (X509Certificate) i.next();
|
||||
seekResponderCert = false; // done
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Could not find the certificate identified in the OCSP properties
|
||||
if (seekResponderCert) {
|
||||
throw new CertPathValidatorException(
|
||||
"Cannot find the responder's certificate " +
|
||||
"(set using the OCSP security properties).");
|
||||
}
|
||||
// Could not find the certificate identified in the OCSP properties
|
||||
if (seekResponderCert) {
|
||||
throw new CertPathValidatorException(
|
||||
"Cannot find the responder's certificate " +
|
||||
"(set using the OCSP security properties).");
|
||||
}
|
||||
|
||||
// Construct an OCSP Request
|
||||
OCSPRequest ocspRequest =
|
||||
new OCSPRequest(currCertImpl, issuerCertImpl);
|
||||
CertId certId = null;
|
||||
OCSPResponse response = null;
|
||||
try {
|
||||
certId = new CertId
|
||||
(issuerCert, currCertImpl.getSerialNumberObject());
|
||||
response = OCSP.check(Collections.singletonList(certId), uri,
|
||||
responderCert, pkixParams.getDate());
|
||||
} catch (IOException ioe) {
|
||||
// should allow this to pass if network failures are acceptable
|
||||
throw new CertPathValidatorException
|
||||
("Unable to send OCSP request", ioe);
|
||||
}
|
||||
|
||||
// Use the URL to the OCSP service that was created earlier
|
||||
HttpURLConnection con = (HttpURLConnection)url.openConnection();
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("connecting to OCSP service at: " + url);
|
||||
}
|
||||
|
||||
// Indicate that both input and output will be performed,
|
||||
// that the method is POST, and that the content length is
|
||||
// the length of the byte array
|
||||
|
||||
con.setDoOutput(true);
|
||||
con.setDoInput(true);
|
||||
con.setRequestMethod("POST");
|
||||
con.setRequestProperty("Content-type", "application/ocsp-request");
|
||||
byte[] bytes = ocspRequest.encodeBytes();
|
||||
CertId certId = ocspRequest.getCertId();
|
||||
|
||||
con.setRequestProperty("Content-length",
|
||||
String.valueOf(bytes.length));
|
||||
out = con.getOutputStream();
|
||||
out.write(bytes);
|
||||
out.flush();
|
||||
|
||||
// Check the response
|
||||
if (DEBUG != null &&
|
||||
con.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
DEBUG.println("Received HTTP error: " + con.getResponseCode() +
|
||||
" - " + con.getResponseMessage());
|
||||
}
|
||||
in = con.getInputStream();
|
||||
|
||||
byte[] response = null;
|
||||
int total = 0;
|
||||
int contentLength = con.getContentLength();
|
||||
if (contentLength != -1) {
|
||||
response = new byte[contentLength];
|
||||
} else {
|
||||
response = new byte[2048];
|
||||
contentLength = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
while (total < contentLength) {
|
||||
int count = in.read(response, total, response.length - total);
|
||||
if (count < 0)
|
||||
break;
|
||||
|
||||
total += count;
|
||||
if (total >= response.length && total < contentLength) {
|
||||
response = Arrays.copyOf(response, total * 2);
|
||||
}
|
||||
}
|
||||
response = Arrays.copyOf(response, total);
|
||||
|
||||
OCSPResponse ocspResponse = new OCSPResponse(response, pkixParams,
|
||||
responderCert);
|
||||
// Check that response applies to the cert that was supplied
|
||||
if (! certId.equals(ocspResponse.getCertId())) {
|
||||
throw new CertPathValidatorException(
|
||||
"Certificate in the OCSP response does not match the " +
|
||||
"certificate supplied in the OCSP request.");
|
||||
}
|
||||
SerialNumber serialNumber = currCertImpl.getSerialNumberObject();
|
||||
int certOCSPStatus = ocspResponse.getCertStatus(serialNumber);
|
||||
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("Status of certificate (with serial number " +
|
||||
serialNumber.getNumber() + ") is: " +
|
||||
OCSPResponse.certStatusToText(certOCSPStatus));
|
||||
}
|
||||
|
||||
if (certOCSPStatus == OCSPResponse.CERT_STATUS_REVOKED) {
|
||||
Throwable t = new CertificateRevokedException(
|
||||
ocspResponse.getRevocationTime(),
|
||||
ocspResponse.getRevocationReason(),
|
||||
responderCert.getSubjectX500Principal(),
|
||||
ocspResponse.getSingleExtensions());
|
||||
throw new CertPathValidatorException(t.getMessage(), t,
|
||||
null, -1, BasicReason.REVOKED);
|
||||
|
||||
} else if (certOCSPStatus == OCSPResponse.CERT_STATUS_UNKNOWN) {
|
||||
throw new CertPathValidatorException(
|
||||
"Certificate's revocation status is unknown", null, cp,
|
||||
remainingCerts, BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CertPathValidatorException(e);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ioe) {
|
||||
throw new CertPathValidatorException(ioe);
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ioe) {
|
||||
throw new CertPathValidatorException(ioe);
|
||||
}
|
||||
}
|
||||
RevocationStatus rs = (RevocationStatus) response.getSingleResponse(certId);
|
||||
RevocationStatus.CertStatus certStatus = rs.getCertStatus();
|
||||
if (certStatus == RevocationStatus.CertStatus.REVOKED) {
|
||||
Throwable t = new CertificateRevokedException(
|
||||
rs.getRevocationTime(), rs.getRevocationReason(),
|
||||
responderCert.getSubjectX500Principal(),
|
||||
rs.getSingleExtensions());
|
||||
throw new CertPathValidatorException(t.getMessage(), t,
|
||||
null, -1, BasicReason.REVOKED);
|
||||
} else if (certStatus == RevocationStatus.CertStatus.UNKNOWN) {
|
||||
throw new CertPathValidatorException(
|
||||
"Certificate's revocation status is unknown", null, cp,
|
||||
remainingCerts, BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,20 +364,18 @@ class OCSPChecker extends PKIXCertPathChecker {
|
||||
* 3. ocsp.responderCertIssuerName
|
||||
* 4. ocsp.responderCertSerialNumber
|
||||
*/
|
||||
private static URL getOCSPServerURL(X509CertImpl currCertImpl,
|
||||
String[] properties)
|
||||
throws CertificateParsingException, CertPathValidatorException {
|
||||
private static URI getOCSPServerURI(X509CertImpl currCertImpl,
|
||||
String responderURL) throws CertPathValidatorException {
|
||||
|
||||
if (properties[0] != null) {
|
||||
try {
|
||||
return new URL(properties[0]);
|
||||
} catch (java.net.MalformedURLException e) {
|
||||
if (responderURL != null) {
|
||||
try {
|
||||
return new URI(responderURL);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new CertPathValidatorException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Examine the certificate's AuthorityInfoAccess extension
|
||||
|
||||
AuthorityInfoAccessExtension aia =
|
||||
currCertImpl.getAuthorityInfoAccessExtension();
|
||||
if (aia == null) {
|
||||
@ -459,13 +390,8 @@ class OCSPChecker extends PKIXCertPathChecker {
|
||||
|
||||
GeneralName generalName = description.getAccessLocation();
|
||||
if (generalName.getType() == GeneralNameInterface.NAME_URI) {
|
||||
try {
|
||||
URIName uri = (URIName) generalName.getName();
|
||||
return (new URL(uri.getName()));
|
||||
|
||||
} catch (java.net.MalformedURLException e) {
|
||||
throw new CertPathValidatorException(e);
|
||||
}
|
||||
URIName uri = (URIName) generalName.getName();
|
||||
return uri.getURI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,9 +26,9 @@
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import sun.misc.HexDumpEncoder;
|
||||
import sun.security.x509.*;
|
||||
import sun.security.util.*;
|
||||
|
||||
/**
|
||||
@ -77,47 +77,33 @@ class OCSPRequest {
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
private static final boolean dump = false;
|
||||
|
||||
// Serial number of the certificates to be checked for revocation
|
||||
private SerialNumber serialNumber;
|
||||
|
||||
// Issuer's certificate (for computing certId hash values)
|
||||
private X509CertImpl issuerCert;
|
||||
|
||||
// CertId of the certificate to be checked
|
||||
private CertId certId = null;
|
||||
// List of request CertIds
|
||||
private final List<CertId> certIds;
|
||||
|
||||
/*
|
||||
* Constructs an OCSPRequest. This constructor is used
|
||||
* to construct an unsigned OCSP Request for a single user cert.
|
||||
*/
|
||||
// used by OCSPChecker
|
||||
OCSPRequest(X509CertImpl userCert, X509CertImpl issuerCert)
|
||||
throws CertPathValidatorException {
|
||||
|
||||
if (issuerCert == null) {
|
||||
throw new CertPathValidatorException("Null IssuerCertificate");
|
||||
}
|
||||
this.issuerCert = issuerCert;
|
||||
serialNumber = userCert.getSerialNumberObject();
|
||||
OCSPRequest(CertId certId) {
|
||||
this.certIds = Collections.singletonList(certId);
|
||||
}
|
||||
|
||||
OCSPRequest(List<CertId> certIds) {
|
||||
this.certIds = certIds;
|
||||
}
|
||||
|
||||
// used by OCSPChecker
|
||||
byte[] encodeBytes() throws IOException {
|
||||
|
||||
// encode tbsRequest
|
||||
DerOutputStream tmp = new DerOutputStream();
|
||||
DerOutputStream derSingleReqList = new DerOutputStream();
|
||||
SingleRequest singleRequest = null;
|
||||
|
||||
try {
|
||||
singleRequest = new SingleRequest(issuerCert, serialNumber);
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Error encoding OCSP request");
|
||||
DerOutputStream requestsOut = new DerOutputStream();
|
||||
for (CertId certId : certIds) {
|
||||
DerOutputStream certIdOut = new DerOutputStream();
|
||||
certId.encode(certIdOut);
|
||||
requestsOut.write(DerValue.tag_Sequence, certIdOut);
|
||||
}
|
||||
|
||||
certId = singleRequest.getCertId();
|
||||
singleRequest.encode(derSingleReqList);
|
||||
tmp.write(DerValue.tag_Sequence, derSingleReqList);
|
||||
tmp.write(DerValue.tag_Sequence, requestsOut);
|
||||
// No extensions supported
|
||||
DerOutputStream tbsRequest = new DerOutputStream();
|
||||
tbsRequest.write(DerValue.tag_Sequence, tmp);
|
||||
@ -130,35 +116,14 @@ class OCSPRequest {
|
||||
|
||||
if (dump) {
|
||||
HexDumpEncoder hexEnc = new HexDumpEncoder();
|
||||
System.out.println ("OCSPRequest bytes are... ");
|
||||
System.out.println("OCSPRequest bytes are... ");
|
||||
System.out.println(hexEnc.encode(bytes));
|
||||
}
|
||||
|
||||
return(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// used by OCSPChecker
|
||||
CertId getCertId() {
|
||||
return certId;
|
||||
}
|
||||
|
||||
private static class SingleRequest {
|
||||
private CertId certId;
|
||||
|
||||
// No extensions are set
|
||||
|
||||
private SingleRequest(X509CertImpl cert, SerialNumber serialNo) throws Exception {
|
||||
certId = new CertId(cert, serialNo);
|
||||
}
|
||||
|
||||
private void encode(DerOutputStream out) throws IOException {
|
||||
DerOutputStream tmp = new DerOutputStream();
|
||||
certId.encode(tmp);
|
||||
out.write(DerValue.tag_Sequence, tmp);
|
||||
}
|
||||
|
||||
private CertId getCertId() {
|
||||
return certId;
|
||||
}
|
||||
List<CertId> getCertIds() {
|
||||
return certIds;
|
||||
}
|
||||
}
|
||||
|
@ -28,17 +28,16 @@ package sun.security.provider.certpath;
|
||||
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 @@ import sun.security.util.*;
|
||||
* @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 @@ class OCSPResponse {
|
||||
// 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,289 +156,289 @@ class OCSPResponse {
|
||||
/*
|
||||
* 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
|
||||
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;
|
||||
}
|
||||
|
||||
// responseStatus
|
||||
responseStatus = derIn.getEnumerated();
|
||||
// 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;
|
||||
ObjectIdentifier responseType = derIn.getOID();
|
||||
if (responseType.equals(OCSP_BASIC_RESPONSE_OID)) {
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("OCSP response: " +
|
||||
responseToText(responseStatus));
|
||||
DEBUG.println("OCSP response type: basic");
|
||||
}
|
||||
if (responseStatus != OCSP_RESPONSE_OK) {
|
||||
throw new CertPathValidatorException(
|
||||
"OCSP Response Failure: " +
|
||||
responseToText(responseStatus));
|
||||
} else {
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("OCSP response type: " + responseType);
|
||||
}
|
||||
throw new IOException("Unsupported OCSP response type: " +
|
||||
responseType);
|
||||
}
|
||||
|
||||
// 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.");
|
||||
}
|
||||
// BasicOCSPResponse
|
||||
DerInputStream basicOCSPResponse =
|
||||
new DerInputStream(derIn.getOctetString());
|
||||
|
||||
// responseType
|
||||
derIn = tmp.data;
|
||||
responseType = derIn.getOID();
|
||||
if (responseType.equals(OCSP_BASIC_RESPONSE_OID)) {
|
||||
if (DEBUG != null) {
|
||||
DEBUG.println("OCSP response type: basic");
|
||||
DerValue[] seqTmp = basicOCSPResponse.getSequence(2);
|
||||
if (seqTmp.length < 3) {
|
||||
throw new IOException("Unexpected BasicOCSPResponse value");
|
||||
}
|
||||
|
||||
DerValue responseData = seqTmp[0];
|
||||
|
||||
// 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();
|
||||
|
||||
// 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 (DEBUG != null) {
|
||||
DEBUG.println("OCSP response type: " + responseType);
|
||||
}
|
||||
throw new IOException("Unsupported OCSP response type: " +
|
||||
responseType);
|
||||
}
|
||||
|
||||
// BasicOCSPResponse
|
||||
DerInputStream basicOCSPResponse =
|
||||
new DerInputStream(derIn.getOctetString());
|
||||
|
||||
DerValue[] seqTmp = basicOCSPResponse.getSequence(2);
|
||||
DerValue responseData = seqTmp[0];
|
||||
|
||||
// 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();
|
||||
|
||||
// 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);
|
||||
}
|
||||
} 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");
|
||||
}
|
||||
|
||||
// producedAt
|
||||
seq = seqDerIn.getDerValue();
|
||||
producedAtDate = seq.getGeneralizedTime();
|
||||
|
||||
// responses
|
||||
DerValue[] singleResponseDer = seqDerIn.getSequence(1);
|
||||
// Examine only the first response
|
||||
singleResponse = new SingleResponse(singleResponseDer[0]);
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (responseExtension[i].isCritical()) {
|
||||
throw new IOException(
|
||||
"Unsupported OCSP critical extension: " +
|
||||
responseExtension[i].getExtensionId());
|
||||
}
|
||||
// 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");
|
||||
}
|
||||
|
||||
// producedAt
|
||||
seq = seqDerIn.getDerValue();
|
||||
if (DEBUG != null) {
|
||||
Date producedAtDate = seq.getGeneralizedTime();
|
||||
DEBUG.println("OCSP response produced at: " + producedAtDate);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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]);
|
||||
// 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 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");
|
||||
}
|
||||
} catch (CertificateParsingException cpe) {
|
||||
// assume cert is not valid for signing
|
||||
throw new CertPathValidatorException(
|
||||
"Responder's certificate not valid for signing " +
|
||||
"OCSP responses", cpe);
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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(
|
||||
"Unable to verify OCSP Responder's signature");
|
||||
"Responder's certificate is not authorized to sign " +
|
||||
"OCSP responses");
|
||||
}
|
||||
} catch (CertPathValidatorException cpve) {
|
||||
throw cpve;
|
||||
} catch (Exception e) {
|
||||
throw new CertPathValidatorException(e);
|
||||
}
|
||||
|
||||
// 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(
|
||||
"Error verifying OCSP Responder's signature");
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -449,11 +446,10 @@ class OCSPResponse {
|
||||
* 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);
|
||||
@ -472,92 +468,33 @@ class OCSPResponse {
|
||||
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.
|
||||
/**
|
||||
* Returns the SingleResponse of the specified CertId, or null if
|
||||
* there is no response for that CertId.
|
||||
*/
|
||||
// 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.
|
||||
*/
|
||||
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) {
|
||||
@ -568,35 +505,48 @@ class OCSPResponse {
|
||||
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);
|
||||
@ -610,6 +560,8 @@ class OCSPResponse {
|
||||
derVal = tmp.getDerValue();
|
||||
tag = (byte)(derVal.tag & 0x1f);
|
||||
}
|
||||
} else {
|
||||
nextUpdate = null;
|
||||
}
|
||||
}
|
||||
// singleExtensions
|
||||
@ -627,7 +579,11 @@ class OCSPResponse {
|
||||
DEBUG.println("OCSP single extension: " + ext);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
singleExtensions = Collections.emptyMap();
|
||||
}
|
||||
} else {
|
||||
singleExtensions = Collections.emptyMap();
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
@ -657,7 +613,7 @@ class OCSPResponse {
|
||||
/*
|
||||
* Return the certificate's revocation status code
|
||||
*/
|
||||
private int getStatus() {
|
||||
@Override public CertStatus getCertStatus() {
|
||||
return certStatus;
|
||||
}
|
||||
|
||||
@ -665,28 +621,28 @@ class OCSPResponse {
|
||||
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");
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,8 +28,6 @@ package sun.security.provider.certpath;
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.Security;
|
||||
import java.security.cert.CertPath;
|
||||
import java.security.cert.CertPathParameters;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
@ -49,6 +47,7 @@ import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import sun.security.action.GetBooleanSecurityPropertyAction;
|
||||
import sun.security.util.Debug;
|
||||
|
||||
/**
|
||||
@ -67,7 +66,8 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
|
||||
private List<PKIXCertPathChecker> userCheckers;
|
||||
private String sigProvider;
|
||||
private BasicChecker basicChecker;
|
||||
private String ocspProperty;
|
||||
private boolean ocspEnabled = false;
|
||||
private boolean onlyEECert = false;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
@ -253,13 +253,12 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
|
||||
|
||||
if (pkixParam.isRevocationEnabled()) {
|
||||
// Examine OCSP security property
|
||||
ocspProperty = AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return
|
||||
Security.getProperty(OCSPChecker.OCSP_ENABLE_PROP);
|
||||
}
|
||||
});
|
||||
ocspEnabled = AccessController.doPrivileged(
|
||||
new GetBooleanSecurityPropertyAction
|
||||
(OCSPChecker.OCSP_ENABLE_PROP));
|
||||
onlyEECert = AccessController.doPrivileged(
|
||||
new GetBooleanSecurityPropertyAction
|
||||
("com.sun.security.onlyCheckRevocationOfEECert"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,15 +300,15 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
|
||||
if (pkixParam.isRevocationEnabled()) {
|
||||
|
||||
// Use OCSP if it has been enabled
|
||||
if ("true".equalsIgnoreCase(ocspProperty)) {
|
||||
if (ocspEnabled) {
|
||||
OCSPChecker ocspChecker =
|
||||
new OCSPChecker(cpOriginal, pkixParam);
|
||||
new OCSPChecker(cpOriginal, pkixParam, onlyEECert);
|
||||
certPathCheckers.add(ocspChecker);
|
||||
}
|
||||
|
||||
// Always use CRLs
|
||||
CrlRevocationChecker revocationChecker =
|
||||
new CrlRevocationChecker(anchor, pkixParam, certList);
|
||||
CrlRevocationChecker revocationChecker = new
|
||||
CrlRevocationChecker(anchor, pkixParam, certList, onlyEECert);
|
||||
certPathCheckers.add(revocationChecker);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,6 +26,7 @@
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.Principal;
|
||||
@ -44,6 +45,7 @@ import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.security.action.GetBooleanSecurityPropertyAction;
|
||||
import sun.security.x509.X500Name;
|
||||
import sun.security.x509.PKIXExtensions;
|
||||
import sun.security.util.Debug;
|
||||
@ -85,6 +87,7 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
|
||||
private PublicKey finalPublicKey;
|
||||
private X509CertSelector targetSel;
|
||||
private List<CertStore> orderedCertStores;
|
||||
private boolean onlyEECert = false;
|
||||
|
||||
/**
|
||||
* Create an instance of <code>SunCertPathBuilder</code>.
|
||||
@ -97,6 +100,9 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
|
||||
} catch (CertificateException e) {
|
||||
throw new CertPathBuilderException(e);
|
||||
}
|
||||
onlyEECert = AccessController.doPrivileged(
|
||||
new GetBooleanSecurityPropertyAction
|
||||
("com.sun.security.onlyCheckRevocationOfEECert"));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -256,7 +262,6 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
|
||||
|
||||
/*
|
||||
* Private build reverse method.
|
||||
*
|
||||
*/
|
||||
private void buildReverse(List<List<Vertex>> adjacencyList,
|
||||
LinkedList<X509Certificate> certPathList) throws Exception
|
||||
@ -296,7 +301,7 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
|
||||
currentState.updateState(anchor);
|
||||
// init the crl checker
|
||||
currentState.crlChecker =
|
||||
new CrlRevocationChecker(null, buildParams);
|
||||
new CrlRevocationChecker(null, buildParams, null, onlyEECert);
|
||||
try {
|
||||
depthFirstSearchReverse(null, currentState,
|
||||
new ReverseBuilder(buildParams, targetSubjectDN), adjacencyList,
|
||||
@ -341,10 +346,12 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
|
||||
adjacencyList.add(new LinkedList<Vertex>());
|
||||
|
||||
// init the crl checker
|
||||
currentState.crlChecker = new CrlRevocationChecker(null, buildParams);
|
||||
currentState.crlChecker
|
||||
= new CrlRevocationChecker(null, buildParams, null, onlyEECert);
|
||||
|
||||
depthFirstSearchForward(targetSubjectDN, currentState,
|
||||
new ForwardBuilder(buildParams, targetSubjectDN, searchAllCertStores),
|
||||
new ForwardBuilder
|
||||
(buildParams, targetSubjectDN, searchAllCertStores, onlyEECert),
|
||||
adjacencyList, certPathList);
|
||||
}
|
||||
|
||||
@ -486,8 +493,8 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
|
||||
userCheckers.add(mustCheck, basicChecker);
|
||||
mustCheck++;
|
||||
if (buildParams.isRevocationEnabled()) {
|
||||
userCheckers.add(mustCheck,
|
||||
new CrlRevocationChecker(anchor, buildParams));
|
||||
userCheckers.add(mustCheck, new CrlRevocationChecker
|
||||
(anchor, buildParams, null, onlyEECert));
|
||||
mustCheck++;
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ public final class AccessDescription {
|
||||
} else {
|
||||
method = accessMethod.toString();
|
||||
}
|
||||
return ("accessMethod: " + method +
|
||||
return ("\n accessMethod: " + method +
|
||||
"\n accessLocation: " + accessLocation.toString() + "\n");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user