alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (URICertStore.java)

This example Java source code file (URICertStore.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

certstore, certstoreexception, check_interval, collection, crl, httpurlconnection, invalidalgorithmparameterexception, ioexception, net, network, not, override, security, ucs, uri, uricertstoreparameters, util, x509crl

The URICertStore.java Java example source code

/*
 * Copyright (c) 2006, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.security.provider.certpath;

import java.io.InputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URLConnection;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertSelector;
import java.security.cert.CertStore;
import java.security.cert.CertStoreException;
import java.security.cert.CertStoreParameters;
import java.security.cert.CertStoreSpi;
import java.security.cert.CRLException;
import java.security.cert.CRLSelector;
import java.security.cert.X509Certificate;
import java.security.cert.X509CertSelector;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLSelector;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import sun.security.action.GetIntegerAction;
import sun.security.x509.AccessDescription;
import sun.security.x509.GeneralNameInterface;
import sun.security.x509.URIName;
import sun.security.util.Cache;
import sun.security.util.Debug;

/**
 * A <code>CertStore that retrieves Certificates or
 * <code>CRLs from a URI, for example, as specified in an X.509
 * AuthorityInformationAccess or CRLDistributionPoint extension.
 * <p>
 * For CRLs, this implementation retrieves a single DER encoded CRL per URI.
 * For Certificates, this implementation retrieves a single DER encoded CRL or
 * a collection of Certificates encoded as a PKCS#7 "certs-only" CMS message.
 * <p>
 * This <code>CertStore also implements Certificate/CRL caching.
 * Currently, the cache is shared between all applications in the VM and uses a
 * hardcoded policy. The cache has a maximum size of 185 entries, which are held
 * by SoftReferences. A request will be satisfied from the cache if we last
 * checked for an update within CHECK_INTERVAL (last 30 seconds). Otherwise,
 * we open an URLConnection to download the Certificate(s)/CRL using an
 * If-Modified-Since request (HTTP) if possible. Note that both positive and
 * negative responses are cached, i.e. if we are unable to open the connection
 * or the Certificate(s)/CRL cannot be parsed, we remember this result and
 * additional calls during the CHECK_INTERVAL period do not try to open another
 * connection.
 * <p>
 * The URICertStore is not currently a standard CertStore type. We should
 * consider adding a standard "URI" CertStore type.
 *
 * @author Andreas Sterbenz
 * @author Sean Mullan
 * @since 7.0
 */
class URICertStore extends CertStoreSpi {

    private static final Debug debug = Debug.getInstance("certpath");

    // interval between checks for update of cached Certificates/CRLs
    // (30 seconds)
    private final static int CHECK_INTERVAL = 30 * 1000;

    // size of the cache (see Cache class for sizing recommendations)
    private final static int CACHE_SIZE = 185;

    // X.509 certificate factory instance
    private final CertificateFactory factory;

    // cached Collection of X509Certificates (may be empty, never null)
    private Collection<X509Certificate> certs = Collections.emptySet();

    // cached X509CRL (may be null)
    private X509CRL crl;

    // time we last checked for an update
    private long lastChecked;

    // time server returned as last modified time stamp
    // or 0 if not available
    private long lastModified;

    // the URI of this CertStore
    private URI uri;

    // true if URI is ldap
    private boolean ldap = false;
    private CertStoreHelper ldapHelper;
    private CertStore ldapCertStore;
    private String ldapPath;

    // Default maximum connect timeout in milliseconds (15 seconds)
    // allowed when downloading CRLs
    private static final int DEFAULT_CRL_CONNECT_TIMEOUT = 15000;

    /**
     * Integer value indicating the connect timeout, in seconds, to be
     * used for the CRL download. A timeout of zero is interpreted as
     * an infinite timeout.
     */
    private static final int CRL_CONNECT_TIMEOUT = initializeTimeout();

    /**
     * Initialize the timeout length by getting the CRL timeout
     * system property. If the property has not been set, or if its
     * value is negative, set the timeout length to the default.
     */
    private static int initializeTimeout() {
        Integer tmp = java.security.AccessController.doPrivileged(
                new GetIntegerAction("com.sun.security.crl.timeout"));
        if (tmp == null || tmp < 0) {
            return DEFAULT_CRL_CONNECT_TIMEOUT;
        }
        // Convert to milliseconds, as the system property will be
        // specified in seconds
        return tmp * 1000;
    }

    /**
     * Creates a URICertStore.
     *
     * @param parameters specifying the URI
     */
    URICertStore(CertStoreParameters params)
        throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
        super(params);
        if (!(params instanceof URICertStoreParameters)) {
            throw new InvalidAlgorithmParameterException
                ("params must be instanceof URICertStoreParameters");
        }
        this.uri = ((URICertStoreParameters) params).uri;
        // if ldap URI, use an LDAPCertStore to fetch certs and CRLs
        if (uri.getScheme().toLowerCase(Locale.ENGLISH).equals("ldap")) {
            ldap = true;
            ldapHelper = CertStoreHelper.getInstance("LDAP");
            ldapCertStore = ldapHelper.getCertStore(uri);
            ldapPath = uri.getPath();
            // strip off leading '/'
            if (ldapPath.charAt(0) == '/') {
                ldapPath = ldapPath.substring(1);
            }
        }
        try {
            factory = CertificateFactory.getInstance("X.509");
        } catch (CertificateException e) {
            throw new RuntimeException();
        }
    }

    /**
     * Returns a URI CertStore. This method consults a cache of
     * CertStores (shared per JVM) using the URI as a key.
     */
    private static final Cache<URICertStoreParameters, CertStore>
        certStoreCache = Cache.newSoftMemoryCache(CACHE_SIZE);
    static synchronized CertStore getInstance(URICertStoreParameters params)
        throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        if (debug != null) {
            debug.println("CertStore URI:" + params.uri);
        }
        CertStore ucs = certStoreCache.get(params);
        if (ucs == null) {
            ucs = new UCS(new URICertStore(params), null, "URI", params);
            certStoreCache.put(params, ucs);
        } else {
            if (debug != null) {
                debug.println("URICertStore.getInstance: cache hit");
            }
        }
        return ucs;
    }

    /**
     * Creates a CertStore from information included in the AccessDescription
     * object of a certificate's Authority Information Access Extension.
     */
    static CertStore getInstance(AccessDescription ad) {
        if (!ad.getAccessMethod().equals((Object)
                AccessDescription.Ad_CAISSUERS_Id)) {
            return null;
        }
        GeneralNameInterface gn = ad.getAccessLocation().getName();
        if (!(gn instanceof URIName)) {
            return null;
        }
        URI uri = ((URIName) gn).getURI();
        try {
            return URICertStore.getInstance
                (new URICertStore.URICertStoreParameters(uri));
        } catch (Exception ex) {
            if (debug != null) {
                debug.println("exception creating CertStore: " + ex);
                ex.printStackTrace();
            }
            return null;
        }
    }

    /**
     * Returns a <code>Collection of X509Certificates that
     * match the specified selector. If no <code>X509Certificates
     * match the selector, an empty <code>Collection will be returned.
     *
     * @param selector a <code>CertSelector used to select which
     *  <code>X509Certificates should be returned. Specify
     *  <code>null to return all X509Certificates.
     * @return a <code>Collection of X509Certificates that
     *         match the specified selector
     * @throws CertStoreException if an exception occurs
     */
    @Override
    @SuppressWarnings("unchecked")
    public synchronized Collection<X509Certificate> engineGetCertificates
        (CertSelector selector) throws CertStoreException {

        // if ldap URI we wrap the CertSelector in an LDAPCertSelector to
        // avoid LDAP DN matching issues (see LDAPCertSelector for more info)
        if (ldap) {
            X509CertSelector xsel = (X509CertSelector) selector;
            try {
                xsel = ldapHelper.wrap(xsel, xsel.getSubject(), ldapPath);
            } catch (IOException ioe) {
                throw new CertStoreException(ioe);
            }
            // Fetch the certificates via LDAP. LDAPCertStore has its own
            // caching mechanism, see the class description for more info.
            // Safe cast since xsel is an X509 certificate selector.
            return (Collection<X509Certificate>)
                ldapCertStore.getCertificates(xsel);
        }

        // Return the Certificates for this entry. It returns the cached value
        // if it is still current and fetches the Certificates otherwise.
        // For the caching details, see the top of this class.
        long time = System.currentTimeMillis();
        if (time - lastChecked < CHECK_INTERVAL) {
            if (debug != null) {
                debug.println("Returning certificates from cache");
            }
            return getMatchingCerts(certs, selector);
        }
        lastChecked = time;
        try {
            URLConnection connection = uri.toURL().openConnection();
            if (lastModified != 0) {
                connection.setIfModifiedSince(lastModified);
            }
            long oldLastModified = lastModified;
            try (InputStream in = connection.getInputStream()) {
                lastModified = connection.getLastModified();
                if (oldLastModified != 0) {
                    if (oldLastModified == lastModified) {
                        if (debug != null) {
                            debug.println("Not modified, using cached copy");
                        }
                        return getMatchingCerts(certs, selector);
                    } else if (connection instanceof HttpURLConnection) {
                        // some proxy servers omit last modified
                        HttpURLConnection hconn = (HttpURLConnection)connection;
                        if (hconn.getResponseCode()
                                    == HttpURLConnection.HTTP_NOT_MODIFIED) {
                            if (debug != null) {
                                debug.println("Not modified, using cached copy");
                            }
                            return getMatchingCerts(certs, selector);
                        }
                    }
                }
                if (debug != null) {
                    debug.println("Downloading new certificates...");
                }
                // Safe cast since factory is an X.509 certificate factory
                certs = (Collection<X509Certificate>)
                    factory.generateCertificates(in);
            }
            return getMatchingCerts(certs, selector);
        } catch (IOException | CertificateException e) {
            if (debug != null) {
                debug.println("Exception fetching certificates:");
                e.printStackTrace();
            }
        }
        // exception, forget previous values
        lastModified = 0;
        certs = Collections.emptySet();
        return certs;
    }

    /**
     * Iterates over the specified Collection of X509Certificates and
     * returns only those that match the criteria specified in the
     * CertSelector.
     */
    private static Collection<X509Certificate> getMatchingCerts
        (Collection<X509Certificate> certs, CertSelector selector) {
        // if selector not specified, all certs match
        if (selector == null) {
            return certs;
        }
        List<X509Certificate> matchedCerts = new ArrayList<>(certs.size());
        for (X509Certificate cert : certs) {
            if (selector.match(cert)) {
                matchedCerts.add(cert);
            }
        }
        return matchedCerts;
    }

    /**
     * Returns a <code>Collection of X509CRLs that
     * match the specified selector. If no <code>X509CRLs
     * match the selector, an empty <code>Collection will be returned.
     *
     * @param selector A <code>CRLSelector used to select which
     *  <code>X509CRLs should be returned. Specify null
     *  to return all <code>X509CRLs.
     * @return A <code>Collection of X509CRLs that
     *         match the specified selector
     * @throws CertStoreException if an exception occurs
     */
    @Override
    @SuppressWarnings("unchecked")
    public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector)
        throws CertStoreException {

        // if ldap URI we wrap the CRLSelector in an LDAPCRLSelector to
        // avoid LDAP DN matching issues (see LDAPCRLSelector for more info)
        if (ldap) {
            X509CRLSelector xsel = (X509CRLSelector) selector;
            try {
                xsel = ldapHelper.wrap(xsel, null, ldapPath);
            } catch (IOException ioe) {
                throw new CertStoreException(ioe);
            }
            // Fetch the CRLs via LDAP. LDAPCertStore has its own
            // caching mechanism, see the class description for more info.
            // Safe cast since xsel is an X509 certificate selector.
            try {
                return (Collection<X509CRL>) ldapCertStore.getCRLs(xsel);
            } catch (CertStoreException cse) {
                throw new PKIX.CertStoreTypeException("LDAP", cse);
            }
        }

        // Return the CRLs for this entry. It returns the cached value
        // if it is still current and fetches the CRLs otherwise.
        // For the caching details, see the top of this class.
        long time = System.currentTimeMillis();
        if (time - lastChecked < CHECK_INTERVAL) {
            if (debug != null) {
                debug.println("Returning CRL from cache");
            }
            return getMatchingCRLs(crl, selector);
        }
        lastChecked = time;
        try {
            URLConnection connection = uri.toURL().openConnection();
            if (lastModified != 0) {
                connection.setIfModifiedSince(lastModified);
            }
            long oldLastModified = lastModified;
            connection.setConnectTimeout(CRL_CONNECT_TIMEOUT);
            try (InputStream in = connection.getInputStream()) {
                lastModified = connection.getLastModified();
                if (oldLastModified != 0) {
                    if (oldLastModified == lastModified) {
                        if (debug != null) {
                            debug.println("Not modified, using cached copy");
                        }
                        return getMatchingCRLs(crl, selector);
                    } else if (connection instanceof HttpURLConnection) {
                        // some proxy servers omit last modified
                        HttpURLConnection hconn = (HttpURLConnection)connection;
                        if (hconn.getResponseCode()
                                    == HttpURLConnection.HTTP_NOT_MODIFIED) {
                            if (debug != null) {
                                debug.println("Not modified, using cached copy");
                            }
                            return getMatchingCRLs(crl, selector);
                        }
                    }
                }
                if (debug != null) {
                    debug.println("Downloading new CRL...");
                }
                crl = (X509CRL) factory.generateCRL(in);
            }
            return getMatchingCRLs(crl, selector);
        } catch (IOException | CRLException e) {
            if (debug != null) {
                debug.println("Exception fetching CRL:");
                e.printStackTrace();
            }
            // exception, forget previous values
            lastModified = 0;
            crl = null;
            throw new PKIX.CertStoreTypeException("URI",
                                                  new CertStoreException(e));
        }
    }

    /**
     * Checks if the specified X509CRL matches the criteria specified in the
     * CRLSelector.
     */
    private static Collection<X509CRL> getMatchingCRLs
        (X509CRL crl, CRLSelector selector) {
        if (selector == null || (crl != null && selector.match(crl))) {
            return Collections.singletonList(crl);
        } else {
            return Collections.emptyList();
        }
    }

    /**
     * CertStoreParameters for the URICertStore.
     */
    static class URICertStoreParameters implements CertStoreParameters {
        private final URI uri;
        private volatile int hashCode = 0;
        URICertStoreParameters(URI uri) {
            this.uri = uri;
        }
        @Override public boolean equals(Object obj) {
            if (!(obj instanceof URICertStoreParameters)) {
                return false;
            }
            URICertStoreParameters params = (URICertStoreParameters) obj;
            return uri.equals(params.uri);
        }
        @Override public int hashCode() {
            if (hashCode == 0) {
                int result = 17;
                result = 37*result + uri.hashCode();
                hashCode = result;
            }
            return hashCode;
        }
        @Override public Object clone() {
            try {
                return super.clone();
            } catch (CloneNotSupportedException e) {
                /* Cannot happen */
                throw new InternalError(e.toString(), e);
            }
        }
    }

    /**
     * This class allows the URICertStore to be accessed as a CertStore.
     */
    private static class UCS extends CertStore {
        protected UCS(CertStoreSpi spi, Provider p, String type,
            CertStoreParameters params) {
            super(spi, p, type, params);
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java URICertStore.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.