jdk/src/share/classes/sun/security/provider/certpath/LDAPCertStore.java
changeset 4091 82c116e2e288
parent 4090 3dd0ee516f2d
parent 4079 946518568340
child 4097 af3776a63c5e
--- a/jdk/src/share/classes/sun/security/provider/certpath/LDAPCertStore.java	Fri Oct 23 18:44:33 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1065 +0,0 @@
-/*
- * Copyright 2000-2006 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.ByteArrayInputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.net.URI;
-import java.util.*;
-import javax.naming.Context;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.NameNotFoundException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-
-import java.security.*;
-import java.security.cert.Certificate;
-import java.security.cert.*;
-import javax.security.auth.x500.X500Principal;
-
-import sun.misc.HexDumpEncoder;
-import sun.security.util.Cache;
-import sun.security.util.Debug;
-import sun.security.x509.X500Name;
-import sun.security.action.GetPropertyAction;
-
-/**
- * A <code>CertStore</code> that retrieves <code>Certificates</code> and
- * <code>CRL</code>s from an LDAP directory, using the PKIX LDAP V2 Schema
- * (RFC 2587):
- * <a href="http://www.ietf.org/rfc/rfc2587.txt">
- * http://www.ietf.org/rfc/rfc2587.txt</a>.
- * <p>
- * Before calling the {@link #engineGetCertificates engineGetCertificates} or
- * {@link #engineGetCRLs engineGetCRLs} methods, the
- * {@link #LDAPCertStore(CertStoreParameters)
- * LDAPCertStore(CertStoreParameters)} constructor is called to create the
- * <code>CertStore</code> and establish the DNS name and port of the LDAP
- * server from which <code>Certificate</code>s and <code>CRL</code>s will be
- * retrieved.
- * <p>
- * <b>Concurrent Access</b>
- * <p>
- * As described in the javadoc for <code>CertStoreSpi</code>, the
- * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
- * must be thread-safe. That is, multiple threads may concurrently
- * invoke these methods on a single <code>LDAPCertStore</code> object
- * (or more than one) with no ill effects. This allows a
- * <code>CertPathBuilder</code> to search for a CRL while simultaneously
- * searching for further certificates, for instance.
- * <p>
- * This is achieved by adding the <code>synchronized</code> keyword to the
- * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods.
- * <p>
- * This classes uses caching and requests multiple attributes at once to
- * minimize LDAP round trips. The cache is associated with the CertStore
- * instance. It uses soft references to hold the values to minimize impact
- * on footprint and currently has a maximum size of 750 attributes and a
- * 30 second default lifetime.
- * <p>
- * We always request CA certificates, cross certificate pairs, and ARLs in
- * a single LDAP request when any one of them is needed. The reason is that
- * we typically need all of them anyway and requesting them in one go can
- * reduce the number of requests to a third. Even if we don't need them,
- * these attributes are typically small enough not to cause a noticeable
- * overhead. In addition, when the prefetchCRLs flag is true, we also request
- * the full CRLs. It is currently false initially but set to true once any
- * request for an ARL to the server returns an null value. The reason is
- * that CRLs could be rather large but are rarely used. This implementation
- * should improve performance in most cases.
- *
- * @see java.security.cert.CertStore
- *
- * @since       1.4
- * @author      Steve Hanna
- * @author      Andreas Sterbenz
- */
-public class LDAPCertStore extends CertStoreSpi {
-
-    private static final Debug debug = Debug.getInstance("certpath");
-
-    private final static boolean DEBUG = false;
-
-    /**
-     * LDAP attribute identifiers.
-     */
-    private static final String USER_CERT = "userCertificate;binary";
-    private static final String CA_CERT = "cACertificate;binary";
-    private static final String CROSS_CERT = "crossCertificatePair;binary";
-    private static final String CRL = "certificateRevocationList;binary";
-    private static final String ARL = "authorityRevocationList;binary";
-    private static final String DELTA_CRL = "deltaRevocationList;binary";
-
-    // Constants for various empty values
-    private final static String[] STRING0 = new String[0];
-
-    private final static byte[][] BB0 = new byte[0][];
-
-    private final static Attributes EMPTY_ATTRIBUTES = new BasicAttributes();
-
-    // cache related constants
-    private final static int DEFAULT_CACHE_SIZE = 750;
-    private final static int DEFAULT_CACHE_LIFETIME = 30;
-
-    private final static int LIFETIME;
-
-    private final static String PROP_LIFETIME =
-                            "sun.security.certpath.ldap.cache.lifetime";
-
-    static {
-        String s = AccessController.doPrivileged(
-                                new GetPropertyAction(PROP_LIFETIME));
-        if (s != null) {
-            LIFETIME = Integer.parseInt(s); // throws NumberFormatException
-        } else {
-            LIFETIME = DEFAULT_CACHE_LIFETIME;
-        }
-    }
-
-    /**
-     * The CertificateFactory used to decode certificates from
-     * their binary stored form.
-     */
-    private CertificateFactory cf;
-    /**
-     * The JNDI directory context.
-     */
-    private DirContext ctx;
-
-    /**
-     * Flag indicating whether we should prefetch CRLs.
-     */
-    private boolean prefetchCRLs = false;
-
-    private final Cache valueCache;
-
-    private int cacheHits = 0;
-    private int cacheMisses = 0;
-    private int requests = 0;
-
-    /**
-     * Creates a <code>CertStore</code> with the specified parameters.
-     * For this class, the parameters object must be an instance of
-     * <code>LDAPCertStoreParameters</code>.
-     *
-     * @param params the algorithm parameters
-     * @exception InvalidAlgorithmParameterException if params is not an
-     *   instance of <code>LDAPCertStoreParameters</code>
-     */
-    public LDAPCertStore(CertStoreParameters params)
-            throws InvalidAlgorithmParameterException {
-        super(params);
-        if (!(params instanceof LDAPCertStoreParameters))
-          throw new InvalidAlgorithmParameterException(
-            "parameters must be LDAPCertStoreParameters");
-
-        LDAPCertStoreParameters lparams = (LDAPCertStoreParameters) params;
-
-        // Create InitialDirContext needed to communicate with the server
-        createInitialDirContext(lparams.getServerName(), lparams.getPort());
-
-        // Create CertificateFactory for use later on
-        try {
-            cf = CertificateFactory.getInstance("X.509");
-        } catch (CertificateException e) {
-            throw new InvalidAlgorithmParameterException(
-                "unable to create CertificateFactory for X.509");
-        }
-        if (LIFETIME == 0) {
-            valueCache = Cache.newNullCache();
-        } else if (LIFETIME < 0) {
-            valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE);
-        } else {
-            valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE, LIFETIME);
-        }
-    }
-
-    /**
-     * Returns an LDAP CertStore. This method consults a cache of
-     * CertStores (shared per JVM) using the LDAP server/port as a key.
-     */
-    private static final Cache certStoreCache = Cache.newSoftMemoryCache(185);
-    static synchronized CertStore getInstance(LDAPCertStoreParameters params)
-        throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
-        CertStore lcs = (CertStore) certStoreCache.get(params);
-        if (lcs == null) {
-            lcs = CertStore.getInstance("LDAP", params);
-            certStoreCache.put(params, lcs);
-        } else {
-            if (debug != null) {
-                debug.println("LDAPCertStore.getInstance: cache hit");
-            }
-        }
-        return lcs;
-    }
-
-    /**
-     * Create InitialDirContext.
-     *
-     * @param server Server DNS name hosting LDAP service
-     * @param port   Port at which server listens for requests
-     * @throws InvalidAlgorithmParameterException if creation fails
-     */
-    private void createInitialDirContext(String server, int port)
-            throws InvalidAlgorithmParameterException {
-        String url = "ldap://" + server + ":" + port;
-        Hashtable<String,Object> env = new Hashtable<String,Object>();
-        env.put(Context.INITIAL_CONTEXT_FACTORY,
-                "com.sun.jndi.ldap.LdapCtxFactory");
-        env.put(Context.PROVIDER_URL, url);
-        try {
-            ctx = new InitialDirContext(env);
-            /*
-             * By default, follow referrals unless application has
-             * overridden property in an application resource file.
-             */
-            Hashtable<?,?> currentEnv = ctx.getEnvironment();
-            if (currentEnv.get(Context.REFERRAL) == null) {
-                ctx.addToEnvironment(Context.REFERRAL, "follow");
-            }
-        } catch (NamingException e) {
-            if (debug != null) {
-                debug.println("LDAPCertStore.engineInit about to throw "
-                    + "InvalidAlgorithmParameterException");
-                e.printStackTrace();
-            }
-            Exception ee = new InvalidAlgorithmParameterException
-                ("unable to create InitialDirContext using supplied parameters");
-            ee.initCause(e);
-            throw (InvalidAlgorithmParameterException)ee;
-        }
-    }
-
-    /**
-     * Private class encapsulating the actual LDAP operations and cache
-     * handling. Use:
-     *
-     *   LDAPRequest request = new LDAPRequest(dn);
-     *   request.addRequestedAttribute(CROSS_CERT);
-     *   request.addRequestedAttribute(CA_CERT);
-     *   byte[][] crossValues = request.getValues(CROSS_CERT);
-     *   byte[][] caValues = request.getValues(CA_CERT);
-     *
-     * At most one LDAP request is sent for each instance created. If all
-     * getValues() calls can be satisfied from the cache, no request
-     * is sent at all. If a request is sent, all requested attributes
-     * are always added to the cache irrespective of whether the getValues()
-     * method is called.
-     */
-    private class LDAPRequest {
-
-        private final String name;
-        private Map<String, byte[][]> valueMap;
-        private final List<String> requestedAttributes;
-
-        LDAPRequest(String name) {
-            this.name = name;
-            requestedAttributes = new ArrayList<String>(5);
-        }
-
-        String getName() {
-            return name;
-        }
-
-        void addRequestedAttribute(String attrId) {
-            if (valueMap != null) {
-                throw new IllegalStateException("Request already sent");
-            }
-            requestedAttributes.add(attrId);
-        }
-
-        /**
-         * Gets one or more binary values from an attribute.
-         *
-         * @param name          the location holding the attribute
-         * @param attrId                the attribute identifier
-         * @return                      an array of binary values (byte arrays)
-         * @throws NamingException      if a naming exception occurs
-         */
-        byte[][] getValues(String attrId) throws NamingException {
-            if (DEBUG && ((cacheHits + cacheMisses) % 50 == 0)) {
-                System.out.println("Cache hits: " + cacheHits + "; misses: "
-                        + cacheMisses);
-            }
-            String cacheKey = name + "|" + attrId;
-            byte[][] values = (byte[][])valueCache.get(cacheKey);
-            if (values != null) {
-                cacheHits++;
-                return values;
-            }
-            cacheMisses++;
-            Map<String, byte[][]> attrs = getValueMap();
-            values = attrs.get(attrId);
-            return values;
-        }
-
-        /**
-         * Get a map containing the values for this request. The first time
-         * this method is called on an object, the LDAP request is sent,
-         * the results parsed and added to a private map and also to the
-         * cache of this LDAPCertStore. Subsequent calls return the private
-         * map immediately.
-         *
-         * The map contains an entry for each requested attribute. The
-         * attribute name is the key, values are byte[][]. If there are no
-         * values for that attribute, values are byte[0][].
-         *
-         * @return                      the value Map
-         * @throws NamingException      if a naming exception occurs
-         */
-        private Map<String, byte[][]> getValueMap() throws NamingException {
-            if (valueMap != null) {
-                return valueMap;
-            }
-            if (DEBUG) {
-                System.out.println("Request: " + name + ":" + requestedAttributes);
-                requests++;
-                if (requests % 5 == 0) {
-                    System.out.println("LDAP requests: " + requests);
-                }
-            }
-            valueMap = new HashMap<String, byte[][]>(8);
-            String[] attrIds = requestedAttributes.toArray(STRING0);
-            Attributes attrs;
-            try {
-                attrs = ctx.getAttributes(name, attrIds);
-            } catch (NameNotFoundException e) {
-                // name does not exist on this LDAP server
-                // treat same as not attributes found
-                attrs = EMPTY_ATTRIBUTES;
-            }
-            for (String attrId : requestedAttributes) {
-                Attribute attr = attrs.get(attrId);
-                byte[][] values = getAttributeValues(attr);
-                cacheAttribute(attrId, values);
-                valueMap.put(attrId, values);
-            }
-            return valueMap;
-        }
-
-        /**
-         * Add the values to the cache.
-         */
-        private void cacheAttribute(String attrId, byte[][] values) {
-            String cacheKey = name + "|" + attrId;
-            valueCache.put(cacheKey, values);
-        }
-
-        /**
-         * Get the values for the given attribute. If the attribute is null
-         * or does not contain any values, a zero length byte array is
-         * returned. NOTE that it is assumed that all values are byte arrays.
-         */
-        private byte[][] getAttributeValues(Attribute attr)
-                throws NamingException {
-            byte[][] values;
-            if (attr == null) {
-                values = BB0;
-            } else {
-                values = new byte[attr.size()][];
-                int i = 0;
-                NamingEnumeration<?> enum_ = attr.getAll();
-                while (enum_.hasMore()) {
-                    Object obj = enum_.next();
-                    if (debug != null) {
-                        if (obj instanceof String) {
-                            debug.println("LDAPCertStore.getAttrValues() "
-                                + "enum.next is a string!: " + obj);
-                        }
-                    }
-                    byte[] value = (byte[])obj;
-                    values[i++] = value;
-                }
-            }
-            return values;
-        }
-
-    }
-
-    /*
-     * Gets certificates from an attribute id and location in the LDAP
-     * directory. Returns a Collection containing only the Certificates that
-     * match the specified CertSelector.
-     *
-     * @param name the location holding the attribute
-     * @param id the attribute identifier
-     * @param sel a CertSelector that the Certificates must match
-     * @return a Collection of Certificates found
-     * @throws CertStoreException       if an exception occurs
-     */
-    private Collection<X509Certificate> getCertificates(LDAPRequest request,
-        String id, X509CertSelector sel) throws CertStoreException {
-
-        /* fetch encoded certs from storage */
-        byte[][] encodedCert;
-        try {
-            encodedCert = request.getValues(id);
-        } catch (NamingException namingEx) {
-            throw new CertStoreException(namingEx);
-        }
-
-        int n = encodedCert.length;
-        if (n == 0) {
-            return Collections.<X509Certificate>emptySet();
-        }
-
-        List<X509Certificate> certs = new ArrayList<X509Certificate>(n);
-        /* decode certs and check if they satisfy selector */
-        for (int i = 0; i < n; i++) {
-            ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]);
-            try {
-                Certificate cert = cf.generateCertificate(bais);
-                if (sel.match(cert)) {
-                  certs.add((X509Certificate)cert);
-                }
-            } catch (CertificateException e) {
-                if (debug != null) {
-                    debug.println("LDAPCertStore.getCertificates() encountered "
-                        + "exception while parsing cert, skipping the bad data: ");
-                    HexDumpEncoder encoder = new HexDumpEncoder();
-                    debug.println(
-                        "[ " + encoder.encodeBuffer(encodedCert[i]) + " ]");
-                }
-            }
-        }
-
-        return certs;
-    }
-
-    /*
-     * Gets certificate pairs from an attribute id and location in the LDAP
-     * directory.
-     *
-     * @param name the location holding the attribute
-     * @param id the attribute identifier
-     * @return a Collection of X509CertificatePairs found
-     * @throws CertStoreException       if an exception occurs
-     */
-    private Collection<X509CertificatePair> getCertPairs(
-        LDAPRequest request, String id) throws CertStoreException {
-
-        /* fetch the encoded cert pairs from storage */
-        byte[][] encodedCertPair;
-        try {
-            encodedCertPair = request.getValues(id);
-        } catch (NamingException namingEx) {
-            throw new CertStoreException(namingEx);
-        }
-
-        int n = encodedCertPair.length;
-        if (n == 0) {
-            return Collections.<X509CertificatePair>emptySet();
-        }
-
-        List<X509CertificatePair> certPairs =
-                                new ArrayList<X509CertificatePair>(n);
-        /* decode each cert pair and add it to the Collection */
-        for (int i = 0; i < n; i++) {
-            try {
-                X509CertificatePair certPair =
-                    X509CertificatePair.generateCertificatePair(encodedCertPair[i]);
-                certPairs.add(certPair);
-            } catch (CertificateException e) {
-                if (debug != null) {
-                    debug.println(
-                        "LDAPCertStore.getCertPairs() encountered exception "
-                        + "while parsing cert, skipping the bad data: ");
-                    HexDumpEncoder encoder = new HexDumpEncoder();
-                    debug.println(
-                        "[ " + encoder.encodeBuffer(encodedCertPair[i]) + " ]");
-                }
-            }
-        }
-
-        return certPairs;
-    }
-
-    /*
-     * Looks at certificate pairs stored in the crossCertificatePair attribute
-     * at the specified location in the LDAP directory. Returns a Collection
-     * containing all Certificates stored in the forward component that match
-     * the forward CertSelector and all Certificates stored in the reverse
-     * component that match the reverse CertSelector.
-     * <p>
-     * If either forward or reverse is null, all certificates from the
-     * corresponding component will be rejected.
-     *
-     * @param name the location to look in
-     * @param forward the forward CertSelector (or null)
-     * @param reverse the reverse CertSelector (or null)
-     * @return a Collection of Certificates found
-     * @throws CertStoreException       if an exception occurs
-     */
-    private Collection<X509Certificate> getMatchingCrossCerts(
-            LDAPRequest request, X509CertSelector forward,
-            X509CertSelector reverse)
-            throws CertStoreException {
-        // Get the cert pairs
-        Collection<X509CertificatePair> certPairs =
-                                getCertPairs(request, CROSS_CERT);
-
-        // Find Certificates that match and put them in a list
-        ArrayList<X509Certificate> matchingCerts =
-                                        new ArrayList<X509Certificate>();
-        for (X509CertificatePair certPair : certPairs) {
-            X509Certificate cert;
-            if (forward != null) {
-                cert = certPair.getForward();
-                if ((cert != null) && forward.match(cert)) {
-                    matchingCerts.add(cert);
-                }
-            }
-            if (reverse != null) {
-                cert = certPair.getReverse();
-                if ((cert != null) && reverse.match(cert)) {
-                    matchingCerts.add(cert);
-                }
-            }
-        }
-        return matchingCerts;
-    }
-
-    /**
-     * Returns a <code>Collection</code> of <code>Certificate</code>s that
-     * match the specified selector. If no <code>Certificate</code>s
-     * match the selector, an empty <code>Collection</code> will be returned.
-     * <p>
-     * It is not practical to search every entry in the LDAP database for
-     * matching <code>Certificate</code>s. Instead, the <code>CertSelector</code>
-     * is examined in order to determine where matching <code>Certificate</code>s
-     * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
-     * If the subject is specified, its directory entry is searched. If the
-     * issuer is specified, its directory entry is searched. If neither the
-     * subject nor the issuer are specified (or the selector is not an
-     * <code>X509CertSelector</code>), a <code>CertStoreException</code> is
-     * thrown.
-     *
-     * @param selector a <code>CertSelector</code> used to select which
-     *  <code>Certificate</code>s should be returned.
-     * @return a <code>Collection</code> of <code>Certificate</code>s that
-     *         match the specified selector
-     * @throws CertStoreException if an exception occurs
-     */
-    public synchronized Collection<X509Certificate> engineGetCertificates
-            (CertSelector selector) throws CertStoreException {
-        if (debug != null) {
-            debug.println("LDAPCertStore.engineGetCertificates() selector: "
-                + String.valueOf(selector));
-        }
-
-        if (selector == null) {
-            selector = new X509CertSelector();
-        }
-        if (!(selector instanceof X509CertSelector)) {
-            throw new CertStoreException("LDAPCertStore needs an X509CertSelector " +
-                                         "to find certs");
-        }
-        X509CertSelector xsel = (X509CertSelector) selector;
-        int basicConstraints = xsel.getBasicConstraints();
-        String subject = xsel.getSubjectAsString();
-        String issuer = xsel.getIssuerAsString();
-        HashSet<X509Certificate> certs = new HashSet<X509Certificate>();
-        if (debug != null) {
-            debug.println("LDAPCertStore.engineGetCertificates() basicConstraints: "
-                + basicConstraints);
-        }
-
-        // basicConstraints:
-        // -2: only EE certs accepted
-        // -1: no check is done
-        //  0: any CA certificate accepted
-        // >1: certificate's basicConstraints extension pathlen must match
-        if (subject != null) {
-            if (debug != null) {
-                debug.println("LDAPCertStore.engineGetCertificates() "
-                    + "subject is not null");
-            }
-            LDAPRequest request = new LDAPRequest(subject);
-            if (basicConstraints > -2) {
-                request.addRequestedAttribute(CROSS_CERT);
-                request.addRequestedAttribute(CA_CERT);
-                request.addRequestedAttribute(ARL);
-                if (prefetchCRLs) {
-                    request.addRequestedAttribute(CRL);
-                }
-            }
-            if (basicConstraints < 0) {
-                request.addRequestedAttribute(USER_CERT);
-            }
-
-            if (basicConstraints > -2) {
-                certs.addAll(getMatchingCrossCerts(request, xsel, null));
-                if (debug != null) {
-                    debug.println("LDAPCertStore.engineGetCertificates() after "
-                        + "getMatchingCrossCerts(subject,xsel,null),certs.size(): "
-                        + certs.size());
-                }
-                certs.addAll(getCertificates(request, CA_CERT, xsel));
-                if (debug != null) {
-                    debug.println("LDAPCertStore.engineGetCertificates() after "
-                        + "getCertificates(subject,CA_CERT,xsel),certs.size(): "
-                        + certs.size());
-                }
-            }
-            if (basicConstraints < 0) {
-                certs.addAll(getCertificates(request, USER_CERT, xsel));
-                if (debug != null) {
-                    debug.println("LDAPCertStore.engineGetCertificates() after "
-                        + "getCertificates(subject,USER_CERT, xsel),certs.size(): "
-                        + certs.size());
-                }
-            }
-        } else {
-            if (debug != null) {
-                debug.println
-                    ("LDAPCertStore.engineGetCertificates() subject is null");
-            }
-            if (basicConstraints == -2) {
-                throw new CertStoreException("need subject to find EE certs");
-            }
-            if (issuer == null) {
-                throw new CertStoreException("need subject or issuer to find certs");
-            }
-        }
-        if (debug != null) {
-            debug.println("LDAPCertStore.engineGetCertificates() about to "
-                + "getMatchingCrossCerts...");
-        }
-        if ((issuer != null) && (basicConstraints > -2)) {
-            LDAPRequest request = new LDAPRequest(issuer);
-            request.addRequestedAttribute(CROSS_CERT);
-            request.addRequestedAttribute(CA_CERT);
-            request.addRequestedAttribute(ARL);
-            if (prefetchCRLs) {
-                request.addRequestedAttribute(CRL);
-            }
-
-            certs.addAll(getMatchingCrossCerts(request, null, xsel));
-            if (debug != null) {
-                debug.println("LDAPCertStore.engineGetCertificates() after "
-                    + "getMatchingCrossCerts(issuer,null,xsel),certs.size(): "
-                    + certs.size());
-            }
-            certs.addAll(getCertificates(request, CA_CERT, xsel));
-            if (debug != null) {
-                debug.println("LDAPCertStore.engineGetCertificates() after "
-                    + "getCertificates(issuer,CA_CERT,xsel),certs.size(): "
-                    + certs.size());
-            }
-        }
-        if (debug != null) {
-            debug.println("LDAPCertStore.engineGetCertificates() returning certs");
-        }
-        return certs;
-    }
-
-    /*
-     * Gets CRLs from an attribute id and location in the LDAP directory.
-     * Returns a Collection containing only the CRLs that match the
-     * specified CRLSelector.
-     *
-     * @param name the location holding the attribute
-     * @param id the attribute identifier
-     * @param sel a CRLSelector that the CRLs must match
-     * @return a Collection of CRLs found
-     * @throws CertStoreException       if an exception occurs
-     */
-    private Collection<X509CRL> getCRLs(LDAPRequest request, String id,
-            X509CRLSelector sel) throws CertStoreException {
-
-        /* fetch the encoded crls from storage */
-        byte[][] encodedCRL;
-        try {
-            encodedCRL = request.getValues(id);
-        } catch (NamingException namingEx) {
-            throw new CertStoreException(namingEx);
-        }
-
-        int n = encodedCRL.length;
-        if (n == 0) {
-            return Collections.<X509CRL>emptySet();
-        }
-
-        List<X509CRL> crls = new ArrayList<X509CRL>(n);
-        /* decode each crl and check if it matches selector */
-        for (int i = 0; i < n; i++) {
-            try {
-                CRL crl = cf.generateCRL(new ByteArrayInputStream(encodedCRL[i]));
-                if (sel.match(crl)) {
-                    crls.add((X509CRL)crl);
-                }
-            } catch (CRLException e) {
-                if (debug != null) {
-                    debug.println("LDAPCertStore.getCRLs() encountered exception"
-                        + " while parsing CRL, skipping the bad data: ");
-                    HexDumpEncoder encoder = new HexDumpEncoder();
-                    debug.println("[ " + encoder.encodeBuffer(encodedCRL[i]) + " ]");
-                }
-            }
-        }
-
-        return crls;
-    }
-
-    /**
-     * Returns a <code>Collection</code> of <code>CRL</code>s that
-     * match the specified selector. If no <code>CRL</code>s
-     * match the selector, an empty <code>Collection</code> will be returned.
-     * <p>
-     * It is not practical to search every entry in the LDAP database for
-     * matching <code>CRL</code>s. Instead, the <code>CRLSelector</code>
-     * is examined in order to determine where matching <code>CRL</code>s
-     * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
-     * If issuerNames or certChecking are specified, the issuer's directory
-     * entry is searched. If neither issuerNames or certChecking are specified
-     * (or the selector is not an <code>X509CRLSelector</code>), a
-     * <code>CertStoreException</code> is thrown.
-     *
-     * @param selector A <code>CRLSelector</code> used to select which
-     *  <code>CRL</code>s should be returned. Specify <code>null</code>
-     *  to return all <code>CRL</code>s.
-     * @return A <code>Collection</code> of <code>CRL</code>s that
-     *         match the specified selector
-     * @throws CertStoreException if an exception occurs
-     */
-    public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector)
-            throws CertStoreException {
-        if (debug != null) {
-            debug.println("LDAPCertStore.engineGetCRLs() selector: "
-                + selector);
-        }
-        // Set up selector and collection to hold CRLs
-        if (selector == null) {
-            selector = new X509CRLSelector();
-        }
-        if (!(selector instanceof X509CRLSelector)) {
-            throw new CertStoreException("need X509CRLSelector to find CRLs");
-        }
-        X509CRLSelector xsel = (X509CRLSelector) selector;
-        HashSet<X509CRL> crls = new HashSet<X509CRL>();
-
-        // Look in directory entry for issuer of cert we're checking.
-        Collection<Object> issuerNames;
-        X509Certificate certChecking = xsel.getCertificateChecking();
-        if (certChecking != null) {
-            issuerNames = new HashSet<Object>();
-            X500Principal issuer = certChecking.getIssuerX500Principal();
-            issuerNames.add(issuer.getName(X500Principal.RFC2253));
-        } else {
-            // But if we don't know which cert we're checking, try the directory
-            // entries of all acceptable CRL issuers
-            issuerNames = xsel.getIssuerNames();
-            if (issuerNames == null) {
-                throw new CertStoreException("need issuerNames or certChecking to "
-                    + "find CRLs");
-            }
-        }
-        for (Object nameObject : issuerNames) {
-            String issuerName;
-            if (nameObject instanceof byte[]) {
-                try {
-                    X500Principal issuer = new X500Principal((byte[])nameObject);
-                    issuerName = issuer.getName(X500Principal.RFC2253);
-                } catch (IllegalArgumentException e) {
-                    continue;
-                }
-            } else {
-                issuerName = (String)nameObject;
-            }
-            // If all we want is CA certs, try to get the (probably shorter) ARL
-            Collection<X509CRL> entryCRLs = Collections.<X509CRL>emptySet();
-            if (certChecking == null || certChecking.getBasicConstraints() != -1) {
-                LDAPRequest request = new LDAPRequest(issuerName);
-                request.addRequestedAttribute(CROSS_CERT);
-                request.addRequestedAttribute(CA_CERT);
-                request.addRequestedAttribute(ARL);
-                if (prefetchCRLs) {
-                    request.addRequestedAttribute(CRL);
-                }
-                try {
-                    entryCRLs = getCRLs(request, ARL, xsel);
-                    if (entryCRLs.isEmpty()) {
-                        // no ARLs found. We assume that means that there are
-                        // no ARLs on this server at all and prefetch the CRLs.
-                        prefetchCRLs = true;
-                    } else {
-                        crls.addAll(entryCRLs);
-                    }
-                } catch (CertStoreException e) {
-                    if (debug != null) {
-                        debug.println("LDAPCertStore.engineGetCRLs non-fatal error "
-                            + "retrieving ARLs:" + e);
-                        e.printStackTrace();
-                    }
-                }
-            }
-            // Otherwise, get the CRL
-            // if certChecking is null, we don't know if we should look in ARL or CRL
-            // attribute, so check both for matching CRLs.
-            if (entryCRLs.isEmpty() || certChecking == null) {
-                LDAPRequest request = new LDAPRequest(issuerName);
-                request.addRequestedAttribute(CRL);
-                entryCRLs = getCRLs(request, CRL, xsel);
-                crls.addAll(entryCRLs);
-            }
-        }
-        return crls;
-    }
-
-    // converts an LDAP URI into LDAPCertStoreParameters
-    static LDAPCertStoreParameters getParameters(URI uri) {
-        String host = uri.getHost();
-        if (host == null) {
-            return new SunLDAPCertStoreParameters();
-        } else {
-            int port = uri.getPort();
-            return (port == -1
-                    ? new SunLDAPCertStoreParameters(host)
-                    : new SunLDAPCertStoreParameters(host, port));
-        }
-    }
-
-    /*
-     * Subclass of LDAPCertStoreParameters with overridden equals/hashCode
-     * methods. This is necessary because the parameters are used as
-     * keys in the LDAPCertStore cache.
-     */
-    private static class SunLDAPCertStoreParameters
-        extends LDAPCertStoreParameters {
-
-        private volatile int hashCode = 0;
-
-        SunLDAPCertStoreParameters(String serverName, int port) {
-            super(serverName, port);
-        }
-        SunLDAPCertStoreParameters(String serverName) {
-            super(serverName);
-        }
-        SunLDAPCertStoreParameters() {
-            super();
-        }
-        public boolean equals(Object obj) {
-            if (!(obj instanceof LDAPCertStoreParameters)) {
-                return false;
-            }
-            LDAPCertStoreParameters params = (LDAPCertStoreParameters) obj;
-            return (getPort() == params.getPort() &&
-                    getServerName().equalsIgnoreCase(params.getServerName()));
-        }
-        public int hashCode() {
-            if (hashCode == 0) {
-                int result = 17;
-                result = 37*result + getPort();
-                result = 37*result + getServerName().toLowerCase().hashCode();
-                hashCode = result;
-            }
-            return hashCode;
-        }
-    }
-
-    /*
-     * This inner class wraps an existing X509CertSelector and adds
-     * additional criteria to match on when the certificate's subject is
-     * different than the LDAP Distinguished Name entry. The LDAPCertStore
-     * implementation uses the subject DN as the directory entry for
-     * looking up certificates. This can be problematic if the certificates
-     * that you want to fetch have a different subject DN than the entry
-     * where they are stored. You could set the selector's subject to the
-     * LDAP DN entry, but then the resulting match would fail to find the
-     * desired certificates because the subject DNs would not match. This
-     * class avoids that problem by introducing a certSubject which should
-     * be set to the certificate's subject DN when it is different than
-     * the LDAP DN.
-     */
-    static class LDAPCertSelector extends X509CertSelector {
-
-        private X500Principal certSubject;
-        private X509CertSelector selector;
-        private X500Principal subject;
-
-        /**
-         * Creates an LDAPCertSelector.
-         *
-         * @param selector the X509CertSelector to wrap
-         * @param certSubject the subject DN of the certificate that you want
-         *      to retrieve via LDAP
-         * @param ldapDN the LDAP DN where the certificate is stored
-         */
-        LDAPCertSelector(X509CertSelector selector, X500Principal certSubject,
-            String ldapDN) throws IOException {
-            this.selector = selector == null ? new X509CertSelector() : selector;
-            this.certSubject = certSubject;
-            this.subject = new X500Name(ldapDN).asX500Principal();
-        }
-
-        // we only override the get (accessor methods) since the set methods
-        // will not be invoked by the code that uses this LDAPCertSelector.
-        public X509Certificate getCertificate() {
-            return selector.getCertificate();
-        }
-        public BigInteger getSerialNumber() {
-            return selector.getSerialNumber();
-        }
-        public X500Principal getIssuer() {
-            return selector.getIssuer();
-        }
-        public String getIssuerAsString() {
-            return selector.getIssuerAsString();
-        }
-        public byte[] getIssuerAsBytes() throws IOException {
-            return selector.getIssuerAsBytes();
-        }
-        public X500Principal getSubject() {
-            // return the ldap DN
-            return subject;
-        }
-        public String getSubjectAsString() {
-            // return the ldap DN
-            return subject.getName();
-        }
-        public byte[] getSubjectAsBytes() throws IOException {
-            // return the encoded ldap DN
-            return subject.getEncoded();
-        }
-        public byte[] getSubjectKeyIdentifier() {
-            return selector.getSubjectKeyIdentifier();
-        }
-        public byte[] getAuthorityKeyIdentifier() {
-            return selector.getAuthorityKeyIdentifier();
-        }
-        public Date getCertificateValid() {
-            return selector.getCertificateValid();
-        }
-        public Date getPrivateKeyValid() {
-            return selector.getPrivateKeyValid();
-        }
-        public String getSubjectPublicKeyAlgID() {
-            return selector.getSubjectPublicKeyAlgID();
-        }
-        public PublicKey getSubjectPublicKey() {
-            return selector.getSubjectPublicKey();
-        }
-        public boolean[] getKeyUsage() {
-            return selector.getKeyUsage();
-        }
-        public Set<String> getExtendedKeyUsage() {
-            return selector.getExtendedKeyUsage();
-        }
-        public boolean getMatchAllSubjectAltNames() {
-            return selector.getMatchAllSubjectAltNames();
-        }
-        public Collection<List<?>> getSubjectAlternativeNames() {
-            return selector.getSubjectAlternativeNames();
-        }
-        public byte[] getNameConstraints() {
-            return selector.getNameConstraints();
-        }
-        public int getBasicConstraints() {
-            return selector.getBasicConstraints();
-        }
-        public Set<String> getPolicy() {
-            return selector.getPolicy();
-        }
-        public Collection<List<?>> getPathToNames() {
-            return selector.getPathToNames();
-        }
-
-        public boolean match(Certificate cert) {
-            // temporarily set the subject criterion to the certSubject
-            // so that match will not reject the desired certificates
-            selector.setSubject(certSubject);
-            boolean match = selector.match(cert);
-            selector.setSubject(subject);
-            return match;
-        }
-    }
-
-    /**
-     * This class has the same purpose as LDAPCertSelector except it is for
-     * X.509 CRLs.
-     */
-    static class LDAPCRLSelector extends X509CRLSelector {
-
-        private X509CRLSelector selector;
-        private Collection<X500Principal> certIssuers;
-        private Collection<X500Principal> issuers;
-        private HashSet<Object> issuerNames;
-
-        /**
-         * Creates an LDAPCRLSelector.
-         *
-         * @param selector the X509CRLSelector to wrap
-         * @param certIssuers the issuer DNs of the CRLs that you want
-         *      to retrieve via LDAP
-         * @param ldapDN the LDAP DN where the CRL is stored
-         */
-        LDAPCRLSelector(X509CRLSelector selector,
-            Collection<X500Principal> certIssuers, String ldapDN)
-            throws IOException {
-            this.selector = selector == null ? new X509CRLSelector() : selector;
-            this.certIssuers = certIssuers;
-            issuerNames = new HashSet<Object>();
-            issuerNames.add(ldapDN);
-            issuers = new HashSet<X500Principal>();
-            issuers.add(new X500Name(ldapDN).asX500Principal());
-        }
-        // we only override the get (accessor methods) since the set methods
-        // will not be invoked by the code that uses this LDAPCRLSelector.
-        public Collection<X500Principal> getIssuers() {
-            // return the ldap DN
-            return Collections.unmodifiableCollection(issuers);
-        }
-        public Collection<Object> getIssuerNames() {
-            // return the ldap DN
-            return Collections.unmodifiableCollection(issuerNames);
-        }
-        public BigInteger getMinCRL() {
-            return selector.getMinCRL();
-        }
-        public BigInteger getMaxCRL() {
-            return selector.getMaxCRL();
-        }
-        public Date getDateAndTime() {
-            return selector.getDateAndTime();
-        }
-        public X509Certificate getCertificateChecking() {
-            return selector.getCertificateChecking();
-        }
-        public boolean match(CRL crl) {
-            // temporarily set the issuer criterion to the certIssuers
-            // so that match will not reject the desired CRL
-            selector.setIssuers(certIssuers);
-            boolean match = selector.match(crl);
-            selector.setIssuers(issuers);
-            return match;
-        }
-    }
-}