173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root/*
273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Copyright (c) 2002, 2012, 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.util.*;
2973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
3073405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.InvalidAlgorithmParameterException;
3173405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.*;
3273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
3373405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport javax.security.auth.x500.X500Principal;
3473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
3573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root/**
3673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * A <code>CertStore</code> that retrieves <code>Certificates</code> and
3773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <code>CRL</code>s from a <code>Collection</code>.
3873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <p>
3973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This implementation is functionally equivalent to CollectionCertStore
4073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * with two differences:
4173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <ol>
4273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <li>Upon construction, the elements in the specified Collection are
4373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * partially indexed. X509Certificates are indexed by subject, X509CRLs
4473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * by issuer, non-X509 Certificates and CRLs are copied without indexing,
4573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * other objects are ignored. This increases CertStore construction time
4673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * but allows significant speedups for searches which specify the indexed
4773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * attributes, in particular for large Collections (reduction from linear
4873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * time to effectively constant time). Searches for non-indexed queries
4973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * are as fast (or marginally faster) than for the standard
5073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * CollectionCertStore. Certificate subjects and CRL issuers
5173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * were found to be specified in most searches used internally by the
5273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * CertPath provider. Additional attributes could indexed if there are
5373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * queries that justify the effort.
5473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
5573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <li>Changes to the specified Collection after construction time are
5673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * not detected and ignored. This is because there is no way to efficiently
5773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * detect if a Collection has been modified, a full traversal would be
5873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * required. That would degrade lookup performance to linear time and
5973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * eliminated the benefit of indexing. We may fix this via the introduction
6073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * of new public APIs in the future.
6173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * </ol>
6273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <p>
6373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Before calling the {@link #engineGetCertificates engineGetCertificates} or
6473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * {@link #engineGetCRLs engineGetCRLs} methods, the
6573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * {@link #CollectionCertStore(CertStoreParameters)
6673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * CollectionCertStore(CertStoreParameters)} constructor is called to
6773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * create the <code>CertStore</code> and establish the
6873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <code>Collection</code> from which <code>Certificate</code>s and
6973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <code>CRL</code>s will be retrieved. If the specified
7073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <code>Collection</code> contains an object that is not a
7173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <code>Certificate</code> or <code>CRL</code>, that object will be
7273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * ignored.
7373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <p>
7473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <b>Concurrent Access</b>
7573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <p>
7673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * As described in the javadoc for <code>CertStoreSpi</code>, the
7773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
7873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * must be thread-safe. That is, multiple threads may concurrently
7973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * invoke these methods on a single <code>CollectionCertStore</code>
8073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * object (or more than one) with no ill effects.
8173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <p>
8273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This is achieved by requiring that the <code>Collection</code> passed to
8373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * the {@link #CollectionCertStore(CertStoreParameters)
8473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * CollectionCertStore(CertStoreParameters)} constructor (via the
8573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <code>CollectionCertStoreParameters</code> object) must have fail-fast
8673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * iterators. Simultaneous modifications to the <code>Collection</code> can thus be
8773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * detected and certificate or CRL retrieval can be retried. The fact that
8873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <code>Certificate</code>s and <code>CRL</code>s must be thread-safe is also
8973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * essential.
9073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
9173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @see java.security.cert.CertStore
9273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @see CollectionCertStore
9373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
9473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @author Andreas Sterbenz
9573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root */
9673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootpublic class IndexedCollectionCertStore extends CertStoreSpi {
9773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
9873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
9973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Map X500Principal(subject) -> X509Certificate | List of X509Certificate
10073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
10173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private Map<X500Principal, Object> certSubjects;
10273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
10373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Map X500Principal(issuer) -> X509CRL | List of X509CRL
10473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
10573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private Map<X500Principal, Object> crlIssuers;
10673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
10773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Sets of non-X509 certificates and CRLs
10873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
10973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private Set<Certificate> otherCertificates;
11073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private Set<CRL> otherCRLs;
11173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
11273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
11373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Creates a <code>CertStore</code> with the specified parameters.
11473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * For this class, the parameters object must be an instance of
11573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * <code>CollectionCertStoreParameters</code>.
11673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
11773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param params the algorithm parameters
11873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @exception InvalidAlgorithmParameterException if params is not an
11973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *   instance of <code>CollectionCertStoreParameters</code>
12073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
12173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public IndexedCollectionCertStore(CertStoreParameters params)
12273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throws InvalidAlgorithmParameterException {
12373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        super(params);
12473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (!(params instanceof CollectionCertStoreParameters)) {
12573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new InvalidAlgorithmParameterException(
12673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                "parameters must be CollectionCertStoreParameters");
12773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
12873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Collection<?> coll = ((CollectionCertStoreParameters)params).getCollection();
12973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (coll == null) {
13073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new InvalidAlgorithmParameterException
13173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                        ("Collection must not be null");
13273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
13373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        buildIndex(coll);
13473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
13573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
13673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
13773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Index the specified Collection copying all references to Certificates
13873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * and CRLs.
13973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
14073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private void buildIndex(Collection<?> coll) {
14173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        certSubjects = new HashMap<X500Principal, Object>();
14273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        crlIssuers = new HashMap<X500Principal, Object>();
14373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        otherCertificates = null;
14473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        otherCRLs = null;
14573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        for (Object obj : coll) {
14673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (obj instanceof X509Certificate) {
14773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                indexCertificate((X509Certificate)obj);
14873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else if (obj instanceof X509CRL) {
14973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                indexCRL((X509CRL)obj);
15073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else if (obj instanceof Certificate) {
15173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (otherCertificates == null) {
15273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    otherCertificates = new HashSet<Certificate>();
15373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
15473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                otherCertificates.add((Certificate)obj);
15573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else if (obj instanceof CRL) {
15673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (otherCRLs == null) {
15773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    otherCRLs = new HashSet<CRL>();
15873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
15973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                otherCRLs.add((CRL)obj);
16073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else {
16173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // ignore
16273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
16373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
16473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (otherCertificates == null) {
16573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            otherCertificates = Collections.<Certificate>emptySet();
16673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
16773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (otherCRLs == null) {
16873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            otherCRLs = Collections.<CRL>emptySet();
16973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
17073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
17173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
17273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
17373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Add an X509Certificate to the index.
17473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
17573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private void indexCertificate(X509Certificate cert) {
17673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        X500Principal subject = cert.getSubjectX500Principal();
17773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Object oldEntry = certSubjects.put(subject, cert);
17873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (oldEntry != null) { // assume this is unlikely
17973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (oldEntry instanceof X509Certificate) {
18073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (cert.equals(oldEntry)) {
18173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    return;
18273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
18373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                List<X509Certificate> list = new ArrayList<>(2);
18473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                list.add(cert);
18573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                list.add((X509Certificate)oldEntry);
18673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                certSubjects.put(subject, list);
18773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else {
18873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                @SuppressWarnings("unchecked") // See certSubjects javadoc.
18973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                List<X509Certificate> list = (List<X509Certificate>)oldEntry;
19073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (list.contains(cert) == false) {
19173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    list.add(cert);
19273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
19373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                certSubjects.put(subject, list);
19473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
19573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
19673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
19773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
19873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
19973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Add an X509CRL to the index.
20073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
20173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private void indexCRL(X509CRL crl) {
20273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        X500Principal issuer = crl.getIssuerX500Principal();
20373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Object oldEntry = crlIssuers.put(issuer, crl);
20473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (oldEntry != null) { // assume this is unlikely
20573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (oldEntry instanceof X509CRL) {
20673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (crl.equals(oldEntry)) {
20773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    return;
20873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
20973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                List<X509CRL> list = new ArrayList<>(2);
21073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                list.add(crl);
21173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                list.add((X509CRL)oldEntry);
21273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                crlIssuers.put(issuer, list);
21373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else {
21473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // See crlIssuers javadoc.
21573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                @SuppressWarnings("unchecked")
21673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                List<X509CRL> list = (List<X509CRL>)oldEntry;
21773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (list.contains(crl) == false) {
21873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    list.add(crl);
21973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
22073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                crlIssuers.put(issuer, list);
22173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
22273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
22373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
22473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
22573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
22673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Returns a <code>Collection</code> of <code>Certificate</code>s that
22773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * match the specified selector. If no <code>Certificate</code>s
22873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * match the selector, an empty <code>Collection</code> will be returned.
22973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
23073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param selector a <code>CertSelector</code> used to select which
23173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *  <code>Certificate</code>s should be returned. Specify <code>null</code>
23273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *  to return all <code>Certificate</code>s.
23373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @return a <code>Collection</code> of <code>Certificate</code>s that
23473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *         match the specified selector
23573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws CertStoreException if an exception occurs
23673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
23773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    @Override
23873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public Collection<? extends Certificate> engineGetCertificates(CertSelector selector)
23973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throws CertStoreException {
24073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
24173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // no selector means match all
24273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (selector == null) {
24373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            Set<Certificate> matches = new HashSet<>();
24473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            matchX509Certs(new X509CertSelector(), matches);
24573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            matches.addAll(otherCertificates);
24673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return matches;
24773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
24873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
24973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (selector instanceof X509CertSelector == false) {
25073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            Set<Certificate> matches = new HashSet<>();
25173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            matchX509Certs(selector, matches);
25273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            for (Certificate cert : otherCertificates) {
25373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (selector.match(cert)) {
25473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    matches.add(cert);
25573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
25673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
25773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return matches;
25873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
25973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
26073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (certSubjects.isEmpty()) {
26173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return Collections.<X509Certificate>emptySet();
26273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
26373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        X509CertSelector x509Selector = (X509CertSelector)selector;
26473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // see if the subject is specified
26573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        X500Principal subject;
26673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        X509Certificate matchCert = x509Selector.getCertificate();
26773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (matchCert != null) {
26873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            subject = matchCert.getSubjectX500Principal();
26973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } else {
27073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            subject = x509Selector.getSubject();
27173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
27273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (subject != null) {
27373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // yes, narrow down candidates to indexed possibilities
27473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            Object entry = certSubjects.get(subject);
27573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (entry == null) {
27673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                return Collections.<X509Certificate>emptySet();
27773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
27873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (entry instanceof X509Certificate) {
27973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                X509Certificate x509Entry = (X509Certificate)entry;
28073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (x509Selector.match(x509Entry)) {
28173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    return Collections.singleton(x509Entry);
28273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } else {
28373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    return Collections.<X509Certificate>emptySet();
28473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
28573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else {
28673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // See certSubjects javadoc.
28773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                @SuppressWarnings("unchecked")
28873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                List<X509Certificate> list = (List<X509Certificate>)entry;
28973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                Set<X509Certificate> matches = new HashSet<>(16);
29073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                for (X509Certificate cert : list) {
29173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (x509Selector.match(cert)) {
29273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        matches.add(cert);
29373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
29473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
29573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                return matches;
29673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
29773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
29873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // cannot use index, iterate all
29973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Set<Certificate> matches = new HashSet<>(16);
30073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        matchX509Certs(x509Selector, matches);
30173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return matches;
30273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
30373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
30473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
30573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Iterate through all the X509Certificates and add matches to the
30673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * collection.
30773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
30873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private void matchX509Certs(CertSelector selector,
30973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Collection<Certificate> matches) {
31073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
31173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        for (Object obj : certSubjects.values()) {
31273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (obj instanceof X509Certificate) {
31373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                X509Certificate cert = (X509Certificate)obj;
31473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (selector.match(cert)) {
31573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    matches.add(cert);
31673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
31773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else {
31873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // See certSubjects javadoc.
31973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                @SuppressWarnings("unchecked")
32073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                List<X509Certificate> list = (List<X509Certificate>)obj;
32173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                for (X509Certificate cert : list) {
32273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (selector.match(cert)) {
32373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        matches.add(cert);
32473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
32573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
32673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
32773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
32873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
32973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
33073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
33173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Returns a <code>Collection</code> of <code>CRL</code>s that
33273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * match the specified selector. If no <code>CRL</code>s
33373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * match the selector, an empty <code>Collection</code> will be returned.
33473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
33573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param selector a <code>CRLSelector</code> used to select which
33673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *  <code>CRL</code>s should be returned. Specify <code>null</code>
33773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *  to return all <code>CRL</code>s.
33873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @return a <code>Collection</code> of <code>CRL</code>s that
33973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *         match the specified selector
34073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws CertStoreException if an exception occurs
34173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
34273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    @Override
34373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public Collection<CRL> engineGetCRLs(CRLSelector selector)
34473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throws CertStoreException {
34573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
34673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (selector == null) {
34773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            Set<CRL> matches = new HashSet<>();
34873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            matchX509CRLs(new X509CRLSelector(), matches);
34973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            matches.addAll(otherCRLs);
35073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return matches;
35173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
35273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
35373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (selector instanceof X509CRLSelector == false) {
35473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            Set<CRL> matches = new HashSet<>();
35573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            matchX509CRLs(selector, matches);
35673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            for (CRL crl : otherCRLs) {
35773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (selector.match(crl)) {
35873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    matches.add(crl);
35973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
36073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
36173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return matches;
36273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
36373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
36473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (crlIssuers.isEmpty()) {
36573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return Collections.<CRL>emptySet();
36673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
36773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        X509CRLSelector x509Selector = (X509CRLSelector)selector;
36873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // see if the issuer is specified
36973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Collection<X500Principal> issuers = x509Selector.getIssuers();
37073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (issuers != null) {
37173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            HashSet<CRL> matches = new HashSet<>(16);
37273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            for (X500Principal issuer : issuers) {
37373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                Object entry = crlIssuers.get(issuer);
37473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (entry == null) {
37573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    // empty
37673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } else if (entry instanceof X509CRL) {
37773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    X509CRL crl = (X509CRL)entry;
37873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (x509Selector.match(crl)) {
37973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        matches.add(crl);
38073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
38173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } else { // List
38273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    // See crlIssuers javadoc.
38373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    @SuppressWarnings("unchecked")
38473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    List<X509CRL> list = (List<X509CRL>)entry;
38573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    for (X509CRL crl : list) {
38673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        if (x509Selector.match(crl)) {
38773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            matches.add(crl);
38873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        }
38973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
39073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
39173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
39273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return matches;
39373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
39473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // cannot use index, iterate all
39573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Set<CRL> matches = new HashSet<>(16);
39673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        matchX509CRLs(x509Selector, matches);
39773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return matches;
39873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
39973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
40073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
40173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Iterate through all the X509CRLs and add matches to the
40273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * collection.
40373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
40473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private void matchX509CRLs(CRLSelector selector, Collection<CRL> matches) {
40573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        for (Object obj : crlIssuers.values()) {
40673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (obj instanceof X509CRL) {
40773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                X509CRL crl = (X509CRL)obj;
40873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (selector.match(crl)) {
40973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    matches.add(crl);
41073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
41173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else {
41273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // See crlIssuers javadoc.
41373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                @SuppressWarnings("unchecked")
41473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                List<X509CRL> list = (List<X509CRL>)obj;
41573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                for (X509CRL crl : list) {
41673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (selector.match(crl)) {
41773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        matches.add(crl);
41873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
41973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
42073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
42173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
42273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
42373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
42473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root}
425