Mercurial > hg > release > icedtea8-forest-3.0 > jdk
changeset 1720:8252729d51a3
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
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/security/action/GetBooleanSecurityPropertyAction.java Wed Sep 09 09:54:13 2009 -0400 @@ -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; + } +}
--- a/src/share/classes/sun/security/provider/certpath/Builder.java Mon Aug 31 15:00:04 2009 -0700 +++ b/src/share/classes/sun/security/provider/certpath/Builder.java Wed Sep 09 09:54:13 2009 -0400 @@ -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 @@ * 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.
--- a/src/share/classes/sun/security/provider/certpath/CertId.java Mon Aug 31 15:00:04 2009 -0700 +++ b/src/share/classes/sun/security/provider/certpath/CertId.java Wed Sep 09 09:54:13 2009 -0400 @@ -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 @@ 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 @@ encoder.encode(issuerNameHash)); System.out.println("issuerKeyHash is " + encoder.encode(issuerKeyHash)); + System.out.println("SerialNumber is " + serialNumber.getNumber()); } } @@ -97,7 +107,6 @@ * 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 @@ * * @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 @@ * @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 @@ /** * 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");
--- a/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java Mon Aug 31 15:00:04 2009 -0700 +++ b/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java Wed Sep 09 09:54:13 2009 -0400 @@ -80,6 +80,7 @@ { 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 @@ 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 @@ } Date testDate = params.getDate(); mCurrentTime = (testDate != null ? testDate : new Date()); + mOnlyEECert = onlyEECert; init(false); } @@ -264,6 +272,13 @@ " ---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.
--- a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java Mon Aug 31 15:00:04 2009 -0700 +++ b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java Wed Sep 09 09:54:13 2009 -0400 @@ -32,7 +32,7 @@ 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 @@ * 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 =
--- a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java Mon Aug 31 15:00:04 2009 -0700 +++ b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java Wed Sep 09 09:54:13 2009 -0400 @@ -82,6 +82,7 @@ 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 @@ * @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 @@ } comparator = new PKIXCertComparator(trustedSubjectDNs); this.searchAllCertStores = searchAllCertStores; + this.onlyEECert = onlyEECert; } /** @@ -875,8 +878,8 @@ /* 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) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/security/provider/certpath/OCSP.java Wed Sep 09 09:54:13 2009 -0400 @@ -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(); + } +}
--- a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java Mon Aug 31 15:00:04 2009 -0700 +++ b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java Wed Sep 09 09:54:13 2009 -0400 @@ -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 @@ */ 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 @@ 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 @@ * 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 @@ } } - 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 @@ * @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); + } + + if (onlyEECert && currCertImpl.getBasicConstraints() != -1) { + if (DEBUG != null) { + DEBUG.println("Skipping revocation check, not end entity cert"); + } + return; + } - boolean seekIssuerCert = true; - X509CertImpl issuerCertImpl = null; - X509CertImpl currCertImpl = - X509CertImpl.toImpl((X509Certificate)cert); + /* + * 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 + URI uri = getOCSPServerURI(currCertImpl, properties[0]); - /* - * OCSP security property values, in the following order: - * 1. ocsp.responderURL - * 2. ocsp.responderCertSubjectName - * 3. ocsp.responderCertIssuerName - * 4. ocsp.responderCertSerialNumber - */ - String[] properties = getOCSPProperties(); + // 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"); + } - // Check whether OCSP is feasible before seeking cert information - URL url = getOCSPServerURL(currCertImpl, properties); + // 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; + } - // When responder's subject name is set then the issuer/serial - // properties are ignored - if (properties[1] != null) { - responderSubjectName = new X500Principal(properties[1]); + // 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 - } 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); + // 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"); + } + } + } - } else if (properties[2] != null || properties[3] != null) { - throw new CertPathValidatorException( - "Must specify both ocsp.responderCertIssuerName and " + - "ocsp.responderCertSerialNumber properties"); + // 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"); } - // 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; + // Extract the anchor certs + Iterator<TrustAnchor> anchors + = pkixParams.getTrustAnchors().iterator(); + if (!anchors.hasNext()) { + throw new CertPathValidatorException( + "Must specify at least one trust anchor"); } - // 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 + X500Principal certIssuerName = + currCertImpl.getIssuerX500Principal(); + while (anchors.hasNext() && (seekIssuerCert || seekResponderCert)) { + + TrustAnchor anchor = 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)) { + + 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 = certs[remainingCerts]; - if (DEBUG != null) { - DEBUG.println("Responder's certificate is the same " + - "as the issuer of the certificate being validated"); + // 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)."); - } - - // Construct an OCSP Request - OCSPRequest ocspRequest = - new OCSPRequest(currCertImpl, issuerCertImpl); - - // 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; - } + // 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)."); + } - 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)); - } + 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); + } - 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 @@ * 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 @@ 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(); } } }
--- a/src/share/classes/sun/security/provider/certpath/OCSPRequest.java Mon Aug 31 15:00:04 2009 -0700 +++ b/src/share/classes/sun/security/provider/certpath/OCSPRequest.java Wed Sep 09 09:54:13 2009 -0400 @@ -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 @@ 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); } - // used by OCSPChecker + OCSPRequest(List<CertId> certIds) { + this.certIds = certIds; + } + 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 @@ 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); - } - - // used by OCSPChecker - CertId getCertId() { - return certId; + return bytes; } - 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; } }
--- a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java Mon Aug 31 15:00:04 2009 -0700 +++ b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java Wed Sep 09 09:54:13 2009 -0400 @@ -28,17 +28,16 @@ import java.io.*; import java.math.BigInteger; import java.security.*; +import java.security.cert.CertificateException; +import java.security.cert.CertificateParsingException; import java.security.cert.CertPathValidatorException; import java.security.cert.CRLReason; import java.security.cert.X509Certificate; -import java.security.cert.PKIXParameters; -import javax.security.auth.x500.X500Principal; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.Iterator; import sun.misc.HexDumpEncoder; import sun.security.x509.*; import sun.security.util.*; @@ -113,32 +112,29 @@ * @author Ram Marti */ -class OCSPResponse { +public final class OCSPResponse { - // Certificate status CHOICE - public static final int CERT_STATUS_GOOD = 0; - public static final int CERT_STATUS_REVOKED = 1; - public static final int CERT_STATUS_UNKNOWN = 2; + public enum ResponseStatus { + SUCCESSFUL, // Response has valid confirmations + MALFORMED_REQUEST, // Illegal confirmation request + INTERNAL_ERROR, // Internal error in issuer + TRY_LATER, // Try again later + UNUSED, // is not used + SIG_REQUIRED, // Must sign the request + UNAUTHORIZED // Request unauthorized + }; + private static ResponseStatus[] rsvalues = ResponseStatus.values(); private static final Debug DEBUG = Debug.getInstance("certpath"); private static final boolean dump = false; - private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID; - private static final ObjectIdentifier OCSP_NONCE_EXTENSION_OID; - static { - ObjectIdentifier tmp1 = null; - ObjectIdentifier tmp2 = null; - try { - tmp1 = new ObjectIdentifier("1.3.6.1.5.5.7.48.1.1"); - tmp2 = new ObjectIdentifier("1.3.6.1.5.5.7.48.1.2"); - } catch (Exception e) { - // should not happen; log and exit - } - OCSP_BASIC_RESPONSE_OID = tmp1; - OCSP_NONCE_EXTENSION_OID = tmp2; - } + private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID = + ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 1}); + private static final ObjectIdentifier OCSP_NONCE_EXTENSION_OID = + ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 2}); - // OCSP response status code - private static final int OCSP_RESPONSE_OK = 0; + private static final int CERT_STATUS_GOOD = 0; + private static final int CERT_STATUS_REVOKED = 1; + private static final int CERT_STATUS_UNKNOWN = 2; // ResponderID CHOICE tags private static final int NAME_TAG = 1; @@ -147,7 +143,8 @@ // Object identifier for the OCSPSigning key purpose private static final String KP_OCSP_SIGNING_OID = "1.3.6.1.5.5.7.3.9"; - private SingleResponse singleResponse; + private final ResponseStatus responseStatus; + private final Map<CertId, SingleResponse> singleResponseMap; // Maximum clock skew in milliseconds (15 minutes) allowed when checking // validity of OCSP responses @@ -159,301 +156,300 @@ /* * Create an OCSP response from its ASN.1 DER encoding. */ - // used by OCSPChecker - OCSPResponse(byte[] bytes, PKIXParameters params, + OCSPResponse(byte[] bytes, Date dateCheckedAgainst, X509Certificate responderCert) throws IOException, CertPathValidatorException { - try { - int responseStatus; - ObjectIdentifier responseType; - int version; - CertificateIssuerName responderName = null; - Date producedAtDate; - AlgorithmId sigAlgId; - byte[] ocspNonce; + // OCSPResponse + if (dump) { + HexDumpEncoder hexEnc = new HexDumpEncoder(); + System.out.println("OCSPResponse bytes are..."); + System.out.println(hexEnc.encode(bytes)); + } + DerValue der = new DerValue(bytes); + if (der.tag != DerValue.tag_Sequence) { + throw new IOException("Bad encoding in OCSP response: " + + "expected ASN.1 SEQUENCE tag."); + } + DerInputStream derIn = der.getData(); - // OCSPResponse - if (dump) { - HexDumpEncoder hexEnc = new HexDumpEncoder(); - System.out.println("OCSPResponse bytes are..."); - System.out.println(hexEnc.encode(bytes)); - } - DerValue der = new DerValue(bytes); - if (der.tag != DerValue.tag_Sequence) { - throw new IOException("Bad encoding in OCSP response: " + - "expected ASN.1 SEQUENCE tag."); - } - DerInputStream derIn = der.getData(); - - // responseStatus - responseStatus = derIn.getEnumerated(); - if (DEBUG != null) { - DEBUG.println("OCSP response: " + - responseToText(responseStatus)); - } - if (responseStatus != OCSP_RESPONSE_OK) { - throw new CertPathValidatorException( - "OCSP Response Failure: " + - responseToText(responseStatus)); - } + // responseStatus + int status = derIn.getEnumerated(); + if (status >= 0 && status < rsvalues.length) { + responseStatus = rsvalues[status]; + } else { + // unspecified responseStatus + throw new IOException("Unknown OCSPResponse status: " + status); + } + if (DEBUG != null) { + DEBUG.println("OCSP response status: " + responseStatus); + } + if (responseStatus != ResponseStatus.SUCCESSFUL) { + // no need to continue, responseBytes are not set. + singleResponseMap = Collections.emptyMap(); + return; + } - // responseBytes - der = derIn.getDerValue(); - if (! der.isContextSpecific((byte)0)) { - throw new IOException("Bad encoding in responseBytes element " + - "of OCSP response: expected ASN.1 context specific tag 0."); - }; - DerValue tmp = der.data.getDerValue(); - if (tmp.tag != DerValue.tag_Sequence) { - throw new IOException("Bad encoding in responseBytes element " + - "of OCSP response: expected ASN.1 SEQUENCE tag."); - } + // responseBytes + der = derIn.getDerValue(); + if (!der.isContextSpecific((byte)0)) { + throw new IOException("Bad encoding in responseBytes element " + + "of OCSP response: expected ASN.1 context specific tag 0."); + } + DerValue tmp = der.data.getDerValue(); + if (tmp.tag != DerValue.tag_Sequence) { + throw new IOException("Bad encoding in responseBytes element " + + "of OCSP response: expected ASN.1 SEQUENCE tag."); + } - // responseType - derIn = tmp.data; - responseType = derIn.getOID(); - if (responseType.equals(OCSP_BASIC_RESPONSE_OID)) { - if (DEBUG != null) { - DEBUG.println("OCSP response type: basic"); - } - } else { - if (DEBUG != null) { - DEBUG.println("OCSP response type: " + responseType); - } - throw new IOException("Unsupported OCSP response type: " + - responseType); + // responseType + derIn = tmp.data; + ObjectIdentifier responseType = derIn.getOID(); + if (responseType.equals(OCSP_BASIC_RESPONSE_OID)) { + if (DEBUG != null) { + DEBUG.println("OCSP response type: basic"); + } + } else { + if (DEBUG != null) { + DEBUG.println("OCSP response type: " + responseType); } + throw new IOException("Unsupported OCSP response type: " + + responseType); + } - // BasicOCSPResponse - DerInputStream basicOCSPResponse = - new DerInputStream(derIn.getOctetString()); + // BasicOCSPResponse + DerInputStream basicOCSPResponse = + new DerInputStream(derIn.getOctetString()); - DerValue[] seqTmp = basicOCSPResponse.getSequence(2); - DerValue responseData = seqTmp[0]; + DerValue[] seqTmp = basicOCSPResponse.getSequence(2); + if (seqTmp.length < 3) { + throw new IOException("Unexpected BasicOCSPResponse value"); + } - // Need the DER encoded ResponseData to verify the signature later - byte[] responseDataDer = seqTmp[0].toByteArray(); + 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(); + // tbsResponseData + if (responseData.tag != DerValue.tag_Sequence) { + throw new IOException("Bad encoding in tbsResponseData " + + "element of OCSP response: expected ASN.1 SEQUENCE tag."); + } + DerInputStream seqDerIn = responseData.data; + DerValue seq = seqDerIn.getDerValue(); - // version - if (seq.isContextSpecific((byte)0)) { - // seq[0] is version - if (seq.isConstructed() && seq.isContextSpecific()) { - //System.out.println ("version is available"); - seq = seq.data.getDerValue(); - version = seq.getInteger(); - if (seq.data.available() != 0) { - throw new IOException("Bad encoding in version " + - " element of OCSP response: bad format"); - } - seq = seqDerIn.getDerValue(); - } - } - - // responderID - short tag = (byte)(seq.tag & 0x1f); - if (tag == NAME_TAG) { - responderName = new CertificateIssuerName(seq.getData()); - if (DEBUG != null) { - DEBUG.println("OCSP Responder name: " + responderName); + // version + if (seq.isContextSpecific((byte)0)) { + // seq[0] is version + if (seq.isConstructed() && seq.isContextSpecific()) { + //System.out.println ("version is available"); + seq = seq.data.getDerValue(); + int version = seq.getInteger(); + if (seq.data.available() != 0) { + throw new IOException("Bad encoding in version " + + " element of OCSP response: bad format"); } - } else if (tag == KEY_TAG) { - // Ignore, for now - } else { - throw new IOException("Bad encoding in responderID element " + - "of OCSP response: expected ASN.1 context specific tag 0 " + - "or 1"); + seq = seqDerIn.getDerValue(); } + } - // producedAt - seq = seqDerIn.getDerValue(); - producedAtDate = seq.getGeneralizedTime(); + // responderID + short tag = (byte)(seq.tag & 0x1f); + if (tag == NAME_TAG) { + if (DEBUG != null) { + X500Name responderName = new X500Name(seq.getData()); + DEBUG.println("OCSP Responder name: " + responderName); + } + } else if (tag == KEY_TAG) { + // Ignore, for now + } else { + throw new IOException("Bad encoding in responderID element of " + + "OCSP response: expected ASN.1 context specific tag 0 or 1"); + } - // responses - DerValue[] singleResponseDer = seqDerIn.getSequence(1); - // Examine only the first response - singleResponse = new SingleResponse(singleResponseDer[0]); + // producedAt + seq = seqDerIn.getDerValue(); + if (DEBUG != null) { + Date producedAtDate = seq.getGeneralizedTime(); + DEBUG.println("OCSP response produced at: " + producedAtDate); + } - // responseExtensions - if (seqDerIn.available() > 0) { - seq = seqDerIn.getDerValue(); - if (seq.isContextSpecific((byte)1)) { - DerValue[] responseExtDer = seq.data.getSequence(3); - Extension[] responseExtension = - new Extension[responseExtDer.length]; - for (int i = 0; i < responseExtDer.length; i++) { - responseExtension[i] = new Extension(responseExtDer[i]); - if (DEBUG != null) { - DEBUG.println("OCSP extension: " + - responseExtension[i]); - } - if ((responseExtension[i].getExtensionId()).equals( - OCSP_NONCE_EXTENSION_OID)) { - ocspNonce = - responseExtension[i].getExtensionValue(); + // responses + DerValue[] singleResponseDer = seqDerIn.getSequence(1); + singleResponseMap + = new HashMap<CertId, SingleResponse>(singleResponseDer.length); + if (DEBUG != null) { + DEBUG.println("OCSP number of SingleResponses: " + + singleResponseDer.length); + } + for (int i = 0; i < singleResponseDer.length; i++) { + SingleResponse singleResponse + = new SingleResponse(singleResponseDer[i]); + singleResponseMap.put(singleResponse.getCertId(), singleResponse); + } - } else if (responseExtension[i].isCritical()) { - throw new IOException( - "Unsupported OCSP critical extension: " + - responseExtension[i].getExtensionId()); - } + // responseExtensions + if (seqDerIn.available() > 0) { + seq = seqDerIn.getDerValue(); + if (seq.isContextSpecific((byte)1)) { + DerValue[] responseExtDer = seq.data.getSequence(3); + for (int i = 0; i < responseExtDer.length; i++) { + Extension responseExtension + = new Extension(responseExtDer[i]); + if (DEBUG != null) { + DEBUG.println("OCSP extension: " + responseExtension); + } + if (responseExtension.getExtensionId().equals( + OCSP_NONCE_EXTENSION_OID)) { + /* + ocspNonce = + responseExtension[i].getExtensionValue(); + */ + } else if (responseExtension.isCritical()) { + throw new IOException( + "Unsupported OCSP critical extension: " + + responseExtension.getExtensionId()); } } } - - // signatureAlgorithmId - sigAlgId = AlgorithmId.parse(seqTmp[1]); + } - // signature - byte[] signature = seqTmp[2].getBitString(); - X509CertImpl[] x509Certs = null; + // signatureAlgorithmId + AlgorithmId sigAlgId = AlgorithmId.parse(seqTmp[1]); + + // 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"); } - - // check the validity - try { - Date dateCheckedAgainst = params.getDate(); - if (dateCheckedAgainst == null) { - cert.checkValidity(); - } else { - cert.checkValidity(dateCheckedAgainst); - } - } catch (GeneralSecurityException e) { - if (DEBUG != null) { - DEBUG.println("Responder's certificate is not " + - "within the validity period."); - } - throw new CertPathValidatorException( - "Responder's certificate not within the " + - "validity period"); - } + } catch (CertificateParsingException cpe) { + // assume cert is not valid for signing + throw new CertPathValidatorException( + "Responder's certificate not valid for signing " + + "OCSP responses", cpe); + } - // check for revocation - // - // A CA may specify that an OCSP client can trust a - // responder for the lifetime of the responder's - // certificate. The CA does so by including the - // extension id-pkix-ocsp-nocheck. - // - Extension noCheck = - cert.getExtension(PKIXExtensions.OCSPNoCheck_Id); - if (noCheck != null) { - if (DEBUG != null) { - DEBUG.println("Responder's certificate includes " + - "the extension id-pkix-ocsp-nocheck."); - } + // check the validity + try { + if (dateCheckedAgainst == null) { + cert.checkValidity(); } else { - // we should do the revocating checking of the - // authorized responder in a future update. + cert.checkValidity(dateCheckedAgainst); } + } catch (GeneralSecurityException e) { + throw new CertPathValidatorException( + "Responder's certificate not within the " + + "validity period", e); + } - // verify the signature - try { - cert.verify(responderCert.getPublicKey()); - responderCert = cert; - // cert is trusted, now verify the signed response - - } catch (GeneralSecurityException e) { - responderCert = null; + // check for revocation + // + // A CA may specify that an OCSP client can trust a + // responder for the lifetime of the responder's + // certificate. The CA does so by including the + // extension id-pkix-ocsp-nocheck. + // + Extension noCheck = + cert.getExtension(PKIXExtensions.OCSPNoCheck_Id); + if (noCheck != null) { + if (DEBUG != null) { + DEBUG.println("Responder's certificate includes " + + "the extension id-pkix-ocsp-nocheck."); } } else { - if (DEBUG != null) { - DEBUG.println("Responder's certificate is not " + - "authorized to sign OCSP responses."); - } - throw new CertPathValidatorException( - "Responder's certificate not authorized to sign " + - "OCSP responses"); + // we should do the revocation checking of the + // authorized responder in a future update. } - } - // Confirm that the signed response was generated using the public - // key from the trusted responder cert - if (responderCert != null) { + // verify the signature + try { + cert.verify(responderCert.getPublicKey()); + responderCert = cert; + // cert is trusted, now verify the signed response - if (! verifyResponse(responseDataDer, responderCert, - sigAlgId, signature, params)) { - if (DEBUG != null) { - DEBUG.println("Error verifying OCSP Responder's " + - "signature"); - } - throw new CertPathValidatorException( - "Error verifying OCSP Responder's signature"); + } catch (GeneralSecurityException e) { + responderCert = null; } } else { - // Need responder's cert in order to verify the signature - if (DEBUG != null) { - DEBUG.println("Unable to verify OCSP Responder's " + - "signature"); - } + throw new CertPathValidatorException( + "Responder's certificate is not authorized to sign " + + "OCSP responses"); + } + } + + // Confirm that the signed response was generated using the public + // key from the trusted responder cert + if (responderCert != null) { + if (!verifyResponse(responseDataDer, responderCert, + sigAlgId, signature)) { throw new CertPathValidatorException( - "Unable to verify OCSP Responder's signature"); + "Error verifying OCSP Responder's signature"); } - } catch (CertPathValidatorException cpve) { - throw cpve; - } catch (Exception e) { - throw new CertPathValidatorException(e); + } else { + // Need responder's cert in order to verify the signature + throw new CertPathValidatorException( + "Unable to verify OCSP Responder's signature"); } } + /** + * Returns the OCSP ResponseStatus. + */ + ResponseStatus getResponseStatus() { + return responseStatus; + } + /* * Verify the signature of the OCSP response. * The responder's cert is implicitly trusted. */ private boolean verifyResponse(byte[] responseData, X509Certificate cert, - AlgorithmId sigAlgId, byte[] signBytes, PKIXParameters params) - throws SignatureException { + AlgorithmId sigAlgId, byte[] signBytes) + throws CertPathValidatorException { try { - Signature respSignature = Signature.getInstance(sigAlgId.getName()); respSignature.initVerify(cert); respSignature.update(responseData); @@ -472,92 +468,33 @@ return false; } } catch (InvalidKeyException ike) { - throw new SignatureException(ike); - + throw new CertPathValidatorException(ike); } catch (NoSuchAlgorithmException nsae) { - throw new SignatureException(nsae); + throw new CertPathValidatorException(nsae); + } catch (SignatureException se) { + throw new CertPathValidatorException(se); } } - /* - * Return the revocation status code for a given certificate. - */ - // used by OCSPChecker - int getCertStatus(SerialNumber sn) { - // ignore serial number for now; if we support multiple - // requests/responses then it will be used - return singleResponse.getStatus(); - } - - // used by OCSPChecker - CertId getCertId() { - return singleResponse.getCertId(); - } - - Date getRevocationTime() { - return singleResponse.getRevocationTime(); - } - - CRLReason getRevocationReason() { - return singleResponse.getRevocationReason(); - } - - Map<String, java.security.cert.Extension> getSingleExtensions() { - return singleResponse.getSingleExtensions(); - } - - /* - * Map an OCSP response status code to a string. + /** + * Returns the SingleResponse of the specified CertId, or null if + * there is no response for that CertId. */ - static private String responseToText(int status) { - switch (status) { - case 0: - return "Successful"; - case 1: - return "Malformed request"; - case 2: - return "Internal error"; - case 3: - return "Try again later"; - case 4: - return "Unused status code"; - case 5: - return "Request must be signed"; - case 6: - return "Request is unauthorized"; - default: - return ("Unknown status code: " + status); - } - } - - /* - * Map a certificate's revocation status code to a string. - */ - // used by OCSPChecker - static String certStatusToText(int certStatus) { - switch (certStatus) { - case 0: - return "Good"; - case 1: - return "Revoked"; - case 2: - return "Unknown"; - default: - return ("Unknown certificate status code: " + certStatus); - } + SingleResponse getSingleResponse(CertId certId) { + return singleResponseMap.get(certId); } /* * A class representing a single OCSP response. */ - private class SingleResponse { - private CertId certId; - private int certStatus; - private Date thisUpdate; - private Date nextUpdate; - private Date revocationTime; - private CRLReason revocationReason = CRLReason.UNSPECIFIED; - private HashMap<String, java.security.cert.Extension> singleExtensions; + final static class SingleResponse implements OCSP.RevocationStatus { + private final CertId certId; + private final CertStatus certStatus; + private final Date thisUpdate; + private final Date nextUpdate; + private final Date revocationTime; + private final CRLReason revocationReason; + private final Map<String, java.security.cert.Extension> singleExtensions; private SingleResponse(DerValue der) throws IOException { if (der.tag != DerValue.tag_Sequence) { @@ -568,35 +505,48 @@ certId = new CertId(tmp.getDerValue().data); DerValue derVal = tmp.getDerValue(); short tag = (byte)(derVal.tag & 0x1f); - if (tag == CERT_STATUS_GOOD) { - certStatus = CERT_STATUS_GOOD; - } else if (tag == CERT_STATUS_REVOKED) { - certStatus = CERT_STATUS_REVOKED; + if (tag == CERT_STATUS_REVOKED) { + certStatus = CertStatus.REVOKED; revocationTime = derVal.data.getGeneralizedTime(); if (derVal.data.available() != 0) { - int reason = derVal.getEnumerated(); - // if reason out-of-range just leave as UNSPECIFIED - if (reason >= 0 && reason < values.length) { - revocationReason = values[reason]; + DerValue dv = derVal.data.getDerValue(); + tag = (byte)(dv.tag & 0x1f); + if (tag == 0) { + int reason = dv.data.getEnumerated(); + // if reason out-of-range just leave as UNSPECIFIED + if (reason >= 0 && reason < values.length) { + revocationReason = values[reason]; + } else { + revocationReason = CRLReason.UNSPECIFIED; + } + } else { + revocationReason = CRLReason.UNSPECIFIED; } + } else { + revocationReason = CRLReason.UNSPECIFIED; } // RevokedInfo if (DEBUG != null) { DEBUG.println("Revocation time: " + revocationTime); DEBUG.println("Revocation reason: " + revocationReason); } - - } else if (tag == CERT_STATUS_UNKNOWN) { - certStatus = CERT_STATUS_UNKNOWN; - } else { - throw new IOException("Invalid certificate status"); + revocationTime = null; + revocationReason = CRLReason.UNSPECIFIED; + if (tag == CERT_STATUS_GOOD) { + certStatus = CertStatus.GOOD; + } else if (tag == CERT_STATUS_UNKNOWN) { + certStatus = CertStatus.UNKNOWN; + } else { + throw new IOException("Invalid certificate status"); + } } thisUpdate = tmp.getGeneralizedTime(); if (tmp.available() == 0) { // we are done + nextUpdate = null; } else { derVal = tmp.getDerValue(); tag = (byte)(derVal.tag & 0x1f); @@ -610,6 +560,8 @@ derVal = tmp.getDerValue(); tag = (byte)(derVal.tag & 0x1f); } + } else { + nextUpdate = null; } } // singleExtensions @@ -627,7 +579,11 @@ DEBUG.println("OCSP single extension: " + ext); } } + } else { + singleExtensions = Collections.emptyMap(); } + } else { + singleExtensions = Collections.emptyMap(); } long now = System.currentTimeMillis(); @@ -657,7 +613,7 @@ /* * Return the certificate's revocation status code */ - private int getStatus() { + @Override public CertStatus getCertStatus() { return certStatus; } @@ -665,28 +621,28 @@ return certId; } - private Date getRevocationTime() { - return revocationTime; + @Override public Date getRevocationTime() { + return (Date) revocationTime.clone(); } - private CRLReason getRevocationReason() { + @Override public CRLReason getRevocationReason() { return revocationReason; } - private Map<String, java.security.cert.Extension> getSingleExtensions() { - return singleExtensions; + @Override + public Map<String, java.security.cert.Extension> getSingleExtensions() { + return Collections.unmodifiableMap(singleExtensions); } /** * Construct a string representation of a single OCSP response. */ - public String toString() { + @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("SingleResponse: \n"); sb.append(certId); - sb.append("\nCertStatus: "+ certStatusToText(getCertStatus(null)) + - "\n"); - if (certStatus == CERT_STATUS_REVOKED) { + sb.append("\nCertStatus: "+ certStatus + "\n"); + if (certStatus == CertStatus.REVOKED) { sb.append("revocationTime is " + revocationTime + "\n"); sb.append("revocationReason is " + revocationReason + "\n"); }
--- a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java Mon Aug 31 15:00:04 2009 -0700 +++ b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java Wed Sep 09 09:54:13 2009 -0400 @@ -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 @@ 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.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 @@ 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 @@ 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 @@ 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); }
--- a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java Mon Aug 31 15:00:04 2009 -0700 +++ b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java Wed Sep 09 09:54:13 2009 -0400 @@ -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.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 @@ 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 @@ } catch (CertificateException e) { throw new CertPathBuilderException(e); } + onlyEECert = AccessController.doPrivileged( + new GetBooleanSecurityPropertyAction + ("com.sun.security.onlyCheckRevocationOfEECert")); } /** @@ -256,7 +262,6 @@ /* * Private build reverse method. - * */ private void buildReverse(List<List<Vertex>> adjacencyList, LinkedList<X509Certificate> certPathList) throws Exception @@ -296,7 +301,7 @@ 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 @@ 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 @@ 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++; } }
--- a/src/share/classes/sun/security/x509/AccessDescription.java Mon Aug 31 15:00:04 2009 -0700 +++ b/src/share/classes/sun/security/x509/AccessDescription.java Wed Sep 09 09:54:13 2009 -0400 @@ -113,7 +113,7 @@ } else { method = accessMethod.toString(); } - return ("accessMethod: " + method + + return ("\n accessMethod: " + method + "\n accessLocation: " + accessLocation.toString() + "\n"); } }