173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root/*
273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This code is free software; you can redistribute it and/or modify it
673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * under the terms of the GNU General Public License version 2 only, as
773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * published by the Free Software Foundation.  Oracle designates this
873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * particular file as subject to the "Classpath" exception as provided
973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * by Oracle in the LICENSE file that accompanied this code.
1073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
1173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This code is distributed in the hope that it will be useful, but WITHOUT
1273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * version 2 for more details (a copy is included in the LICENSE file that
1573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * accompanied this code).
1673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
1773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * You should have received a copy of the GNU General Public License version
1873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * 2 along with this work; if not, write to the Free Software Foundation,
1973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
2173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * or visit www.oracle.com if you need additional information or have any
2373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * questions.
2473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root */
2573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
2673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootpackage sun.security.provider.certpath;
2773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
2873405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.io.InputStream;
2973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.io.IOException;
3073405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.net.HttpURLConnection;
3173405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.net.URI;
3273405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.net.URLConnection;
3373405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.InvalidAlgorithmParameterException;
3473405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.NoSuchAlgorithmException;
3573405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.Provider;
3673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertificateException;
3773405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertificateFactory;
3873405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertSelector;
3973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertStore;
4073405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertStoreException;
4173405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertStoreParameters;
4273405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertStoreSpi;
4373405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CRLException;
4473405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CRLSelector;
4573405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.X509Certificate;
4673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.X509CertSelector;
4773405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.X509CRL;
4873405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.X509CRLSelector;
4973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.ArrayList;
5073405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Collection;
5173405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Collections;
5273405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.List;
5373405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Locale;
5473405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.action.GetIntegerAction;
5573405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.x509.AccessDescription;
5673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.x509.GeneralNameInterface;
5773405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.x509.URIName;
5873405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.util.Cache;
5973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.util.Debug;
6073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
6173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root/**
6273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * A <code>CertStore</code> that retrieves <code>Certificates</code> or
6373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <code>CRL</code>s from a URI, for example, as specified in an X.509
6473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * AuthorityInformationAccess or CRLDistributionPoint extension.
6573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <p>
6673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * For CRLs, this implementation retrieves a single DER encoded CRL per URI.
6773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * For Certificates, this implementation retrieves a single DER encoded CRL or
6873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * a collection of Certificates encoded as a PKCS#7 "certs-only" CMS message.
6973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <p>
7073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This <code>CertStore</code> also implements Certificate/CRL caching.
7173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Currently, the cache is shared between all applications in the VM and uses a
7273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * hardcoded policy. The cache has a maximum size of 185 entries, which are held
7373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * by SoftReferences. A request will be satisfied from the cache if we last
7473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * checked for an update within CHECK_INTERVAL (last 30 seconds). Otherwise,
7573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * we open an URLConnection to download the Certificate(s)/CRL using an
7673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * If-Modified-Since request (HTTP) if possible. Note that both positive and
7773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * negative responses are cached, i.e. if we are unable to open the connection
7873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * or the Certificate(s)/CRL cannot be parsed, we remember this result and
7973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * additional calls during the CHECK_INTERVAL period do not try to open another
8073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * connection.
8173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <p>
8273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * The URICertStore is not currently a standard CertStore type. We should
8373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * consider adding a standard "URI" CertStore type.
8473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
8573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @author Andreas Sterbenz
8673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @author Sean Mullan
8773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @since 7.0
8873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root */
8973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootclass URICertStore extends CertStoreSpi {
9073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
9173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final Debug debug = Debug.getInstance("certpath");
9273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
9373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // interval between checks for update of cached Certificates/CRLs
9473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // (30 seconds)
9573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private final static int CHECK_INTERVAL = 30 * 1000;
9673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
9773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // size of the cache (see Cache class for sizing recommendations)
9873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private final static int CACHE_SIZE = 185;
9973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
10073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // X.509 certificate factory instance
10173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private final CertificateFactory factory;
10273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
10373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // cached Collection of X509Certificates (may be empty, never null)
10473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private Collection<X509Certificate> certs = Collections.emptySet();
10573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
10673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // cached X509CRL (may be null)
10773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private X509CRL crl;
10873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
10973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // time we last checked for an update
11073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private long lastChecked;
11173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
11273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // time server returned as last modified time stamp
11373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // or 0 if not available
11473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private long lastModified;
11573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
11673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // the URI of this CertStore
11773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private URI uri;
11873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
11973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // true if URI is ldap
12073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private boolean ldap = false;
12173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private CertStoreHelper ldapHelper;
12273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private CertStore ldapCertStore;
12373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private String ldapPath;
12473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
12573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // Default maximum connect timeout in milliseconds (15 seconds)
12673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // allowed when downloading CRLs
12773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int DEFAULT_CRL_CONNECT_TIMEOUT = 15000;
12873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
12973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
13073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Integer value indicating the connect timeout, in seconds, to be
13173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * used for the CRL download. A timeout of zero is interpreted as
13273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * an infinite timeout.
13373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
13473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int CRL_CONNECT_TIMEOUT = initializeTimeout();
13573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
13673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
13773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Initialize the timeout length by getting the CRL timeout
13873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * system property. If the property has not been set, or if its
13973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * value is negative, set the timeout length to the default.
14073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
14173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static int initializeTimeout() {
14273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Integer tmp = java.security.AccessController.doPrivileged(
14373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                new GetIntegerAction("com.sun.security.crl.timeout"));
14473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (tmp == null || tmp < 0) {
14573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return DEFAULT_CRL_CONNECT_TIMEOUT;
14673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
14773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // Convert to milliseconds, as the system property will be
14873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // specified in seconds
14973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return tmp * 1000;
15073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
15173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
15273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
15373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Creates a URICertStore.
15473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
15573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param parameters specifying the URI
15673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
15773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    URICertStore(CertStoreParameters params)
15873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
15973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        super(params);
16073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (!(params instanceof URICertStoreParameters)) {
16173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new InvalidAlgorithmParameterException
16273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                ("params must be instanceof URICertStoreParameters");
16373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
16473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        this.uri = ((URICertStoreParameters) params).uri;
16573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // if ldap URI, use an LDAPCertStore to fetch certs and CRLs
16673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (uri.getScheme().toLowerCase(Locale.ENGLISH).equals("ldap")) {
16773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            ldap = true;
16873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            ldapHelper = CertStoreHelper.getInstance("LDAP");
16973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            ldapCertStore = ldapHelper.getCertStore(uri);
17073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            ldapPath = uri.getPath();
17173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // strip off leading '/'
17273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (ldapPath.charAt(0) == '/') {
17373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                ldapPath = ldapPath.substring(1);
17473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
17573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
17673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        try {
17773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            factory = CertificateFactory.getInstance("X.509");
17873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } catch (CertificateException e) {
17973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new RuntimeException();
18073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
18173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
18273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
18373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
18473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Returns a URI CertStore. This method consults a cache of
18573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * CertStores (shared per JVM) using the URI as a key.
18673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
18773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final Cache<URICertStoreParameters, CertStore>
18873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        certStoreCache = Cache.newSoftMemoryCache(CACHE_SIZE);
18973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    static synchronized CertStore getInstance(URICertStoreParameters params)
19073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
19173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (debug != null) {
19273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            debug.println("CertStore URI:" + params.uri);
19373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
19473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        CertStore ucs = certStoreCache.get(params);
19573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (ucs == null) {
19673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            ucs = new UCS(new URICertStore(params), null, "URI", params);
19773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            certStoreCache.put(params, ucs);
19873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } else {
19973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
20073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("URICertStore.getInstance: cache hit");
20173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
20273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
20373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return ucs;
20473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
20573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
20673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
20773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Creates a CertStore from information included in the AccessDescription
20873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * object of a certificate's Authority Information Access Extension.
20973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
21073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    static CertStore getInstance(AccessDescription ad) {
21173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (!ad.getAccessMethod().equals((Object)
21273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                AccessDescription.Ad_CAISSUERS_Id)) {
21373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return null;
21473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
21573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        GeneralNameInterface gn = ad.getAccessLocation().getName();
21673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (!(gn instanceof URIName)) {
21773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return null;
21873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
21973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        URI uri = ((URIName) gn).getURI();
22073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        try {
22173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return URICertStore.getInstance
22273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                (new URICertStore.URICertStoreParameters(uri));
22373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } catch (Exception ex) {
22473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
22573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("exception creating CertStore: " + ex);
22673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                ex.printStackTrace();
22773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
22873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return null;
22973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
23073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
23173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
23273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
23373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Returns a <code>Collection</code> of <code>X509Certificate</code>s that
23473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * match the specified selector. If no <code>X509Certificate</code>s
23573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * match the selector, an empty <code>Collection</code> will be returned.
23673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
23773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param selector a <code>CertSelector</code> used to select which
23873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *  <code>X509Certificate</code>s should be returned. Specify
23973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *  <code>null</code> to return all <code>X509Certificate</code>s.
24073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @return a <code>Collection</code> of <code>X509Certificate</code>s that
24173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *         match the specified selector
24273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws CertStoreException if an exception occurs
24373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
24473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    @Override
24573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    @SuppressWarnings("unchecked")
24673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public synchronized Collection<X509Certificate> engineGetCertificates
24773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        (CertSelector selector) throws CertStoreException {
24873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
24973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // if ldap URI we wrap the CertSelector in an LDAPCertSelector to
25073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // avoid LDAP DN matching issues (see LDAPCertSelector for more info)
25173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (ldap) {
25273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            X509CertSelector xsel = (X509CertSelector) selector;
25373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            try {
25473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                xsel = ldapHelper.wrap(xsel, xsel.getSubject(), ldapPath);
25573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } catch (IOException ioe) {
25673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertStoreException(ioe);
25773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
25873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // Fetch the certificates via LDAP. LDAPCertStore has its own
25973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // caching mechanism, see the class description for more info.
26073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // Safe cast since xsel is an X509 certificate selector.
26173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return (Collection<X509Certificate>)
26273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                ldapCertStore.getCertificates(xsel);
26373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
26473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
26573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // Return the Certificates for this entry. It returns the cached value
26673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // if it is still current and fetches the Certificates otherwise.
26773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // For the caching details, see the top of this class.
26873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        long time = System.currentTimeMillis();
26973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (time - lastChecked < CHECK_INTERVAL) {
27073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
27173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("Returning certificates from cache");
27273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
27373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return getMatchingCerts(certs, selector);
27473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
27573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        lastChecked = time;
27673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        try {
27773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            URLConnection connection = uri.toURL().openConnection();
27873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (lastModified != 0) {
27973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                connection.setIfModifiedSince(lastModified);
28073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
28173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            long oldLastModified = lastModified;
28273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            try (InputStream in = connection.getInputStream()) {
28373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                lastModified = connection.getLastModified();
28473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (oldLastModified != 0) {
28573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (oldLastModified == lastModified) {
28673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        if (debug != null) {
28773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            debug.println("Not modified, using cached copy");
28873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        }
28973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        return getMatchingCerts(certs, selector);
29073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    } else if (connection instanceof HttpURLConnection) {
29173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // some proxy servers omit last modified
29273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        HttpURLConnection hconn = (HttpURLConnection)connection;
29373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        if (hconn.getResponseCode()
29473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                    == HttpURLConnection.HTTP_NOT_MODIFIED) {
29573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            if (debug != null) {
29673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                debug.println("Not modified, using cached copy");
29773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            }
29873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            return getMatchingCerts(certs, selector);
29973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        }
30073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
30173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
30273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (debug != null) {
30373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    debug.println("Downloading new certificates...");
30473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
30573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // Safe cast since factory is an X.509 certificate factory
30673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                certs = (Collection<X509Certificate>)
30773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    factory.generateCertificates(in);
30873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
30973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return getMatchingCerts(certs, selector);
31073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } catch (IOException | CertificateException e) {
31173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
31273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("Exception fetching certificates:");
31373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                e.printStackTrace();
31473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
31573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
31673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // exception, forget previous values
31773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        lastModified = 0;
31873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        certs = Collections.emptySet();
31973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return certs;
32073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
32173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
32273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
32373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Iterates over the specified Collection of X509Certificates and
32473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * returns only those that match the criteria specified in the
32573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * CertSelector.
32673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
32773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static Collection<X509Certificate> getMatchingCerts
32873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        (Collection<X509Certificate> certs, CertSelector selector) {
32973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // if selector not specified, all certs match
33073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (selector == null) {
33173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return certs;
33273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
33373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        List<X509Certificate> matchedCerts = new ArrayList<>(certs.size());
33473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        for (X509Certificate cert : certs) {
33573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (selector.match(cert)) {
33673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                matchedCerts.add(cert);
33773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
33873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
33973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return matchedCerts;
34073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
34173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
34273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
34373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Returns a <code>Collection</code> of <code>X509CRL</code>s that
34473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * match the specified selector. If no <code>X509CRL</code>s
34573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * match the selector, an empty <code>Collection</code> will be returned.
34673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
34773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param selector A <code>CRLSelector</code> used to select which
34873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *  <code>X509CRL</code>s should be returned. Specify <code>null</code>
34973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *  to return all <code>X509CRL</code>s.
35073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @return A <code>Collection</code> of <code>X509CRL</code>s that
35173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *         match the specified selector
35273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws CertStoreException if an exception occurs
35373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
35473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    @Override
35573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    @SuppressWarnings("unchecked")
35673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector)
35773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        throws CertStoreException {
35873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
35973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // if ldap URI we wrap the CRLSelector in an LDAPCRLSelector to
36073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // avoid LDAP DN matching issues (see LDAPCRLSelector for more info)
36173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (ldap) {
36273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            X509CRLSelector xsel = (X509CRLSelector) selector;
36373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            try {
36473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                xsel = ldapHelper.wrap(xsel, null, ldapPath);
36573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } catch (IOException ioe) {
36673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertStoreException(ioe);
36773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
36873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // Fetch the CRLs via LDAP. LDAPCertStore has its own
36973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // caching mechanism, see the class description for more info.
37073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // Safe cast since xsel is an X509 certificate selector.
37173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            try {
37273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                return (Collection<X509CRL>) ldapCertStore.getCRLs(xsel);
37373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } catch (CertStoreException cse) {
37473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new PKIX.CertStoreTypeException("LDAP", cse);
37573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
37673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
37773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
37873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // Return the CRLs for this entry. It returns the cached value
37973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // if it is still current and fetches the CRLs otherwise.
38073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // For the caching details, see the top of this class.
38173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        long time = System.currentTimeMillis();
38273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (time - lastChecked < CHECK_INTERVAL) {
38373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
38473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("Returning CRL from cache");
38573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
38673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return getMatchingCRLs(crl, selector);
38773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
38873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        lastChecked = time;
38973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        try {
39073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            URLConnection connection = uri.toURL().openConnection();
39173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (lastModified != 0) {
39273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                connection.setIfModifiedSince(lastModified);
39373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
39473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            long oldLastModified = lastModified;
39573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            connection.setConnectTimeout(CRL_CONNECT_TIMEOUT);
39673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            try (InputStream in = connection.getInputStream()) {
39773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                lastModified = connection.getLastModified();
39873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (oldLastModified != 0) {
39973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (oldLastModified == lastModified) {
40073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        if (debug != null) {
40173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            debug.println("Not modified, using cached copy");
40273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        }
40373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        return getMatchingCRLs(crl, selector);
40473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    } else if (connection instanceof HttpURLConnection) {
40573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // some proxy servers omit last modified
40673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        HttpURLConnection hconn = (HttpURLConnection)connection;
40773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        if (hconn.getResponseCode()
40873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                    == HttpURLConnection.HTTP_NOT_MODIFIED) {
40973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            if (debug != null) {
41073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                debug.println("Not modified, using cached copy");
41173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            }
41273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            return getMatchingCRLs(crl, selector);
41373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        }
41473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
41573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
41673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (debug != null) {
41773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    debug.println("Downloading new CRL...");
41873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
41973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                crl = (X509CRL) factory.generateCRL(in);
42073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
42173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return getMatchingCRLs(crl, selector);
42273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } catch (IOException | CRLException e) {
42373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
42473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("Exception fetching CRL:");
42573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                e.printStackTrace();
42673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
42773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // exception, forget previous values
42873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            lastModified = 0;
42973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            crl = null;
43073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new PKIX.CertStoreTypeException("URI",
43173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                                  new CertStoreException(e));
43273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
43373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
43473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
43573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
43673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Checks if the specified X509CRL matches the criteria specified in the
43773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * CRLSelector.
43873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
43973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static Collection<X509CRL> getMatchingCRLs
44073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        (X509CRL crl, CRLSelector selector) {
44173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (selector == null || (crl != null && selector.match(crl))) {
44273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return Collections.singletonList(crl);
44373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } else {
44473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return Collections.emptyList();
44573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
44673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
44773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
44873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
44973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * CertStoreParameters for the URICertStore.
45073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
45173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    static class URICertStoreParameters implements CertStoreParameters {
45273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        private final URI uri;
45373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        private volatile int hashCode = 0;
45473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        URICertStoreParameters(URI uri) {
45573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            this.uri = uri;
45673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
45773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        @Override public boolean equals(Object obj) {
45873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (!(obj instanceof URICertStoreParameters)) {
45973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                return false;
46073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
46173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            URICertStoreParameters params = (URICertStoreParameters) obj;
46273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return uri.equals(params.uri);
46373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
46473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        @Override public int hashCode() {
46573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (hashCode == 0) {
46673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                int result = 17;
46773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                result = 37*result + uri.hashCode();
46873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                hashCode = result;
46973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
47073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return hashCode;
47173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
47273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        @Override public Object clone() {
47373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            try {
47473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                return super.clone();
47573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } catch (CloneNotSupportedException e) {
47673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                /* Cannot happen */
47773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new InternalError(e.toString(), e);
47873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
47973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
48073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
48173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
48273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
48373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * This class allows the URICertStore to be accessed as a CertStore.
48473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
48573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static class UCS extends CertStore {
48673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        protected UCS(CertStoreSpi spi, Provider p, String type,
48773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            CertStoreParameters params) {
48873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            super(spi, p, type, params);
48973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
49073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
49173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root}
492