|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
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; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
class URICertStore extends CertStoreSpi { |
|
|
|
private static final Debug debug = Debug.getInstance("certpath"); |
|
|
|
// interval between checks for update of cached Certificates/CRLs |
|
|
|
private final static int CHECK_INTERVAL = 30 * 1000; |
|
|
|
|
|
private final static int CACHE_SIZE = 185; |
|
|
|
|
|
private final CertificateFactory factory; |
|
|
|
|
|
private Collection<X509Certificate> certs = Collections.emptySet(); |
|
|
|
|
|
private X509CRL crl; |
|
|
|
|
|
private long lastChecked; |
|
|
|
// time server returned as last modified time stamp |
|
|
|
private long lastModified; |
|
|
|
|
|
private URI uri; |
|
|
|
|
|
private boolean ldap = false; |
|
private CertStoreHelper ldapHelper; |
|
private CertStore ldapCertStore; |
|
private String ldapPath; |
|
|
|
// Default maximum connect timeout in milliseconds (15 seconds) |
|
|
|
private static final int DEFAULT_CRL_CONNECT_TIMEOUT = 15000; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static final int CRL_CONNECT_TIMEOUT = initializeTimeout(); |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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 |
|
|
|
return tmp * 1000; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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 (uri.getScheme().toLowerCase(Locale.ENGLISH).equals("ldap")) { |
|
ldap = true; |
|
ldapHelper = CertStoreHelper.getInstance("LDAP"); |
|
ldapCertStore = ldapHelper.getCertStore(uri); |
|
ldapPath = uri.getPath(); |
|
|
|
if (ldapPath.charAt(0) == '/') { |
|
ldapPath = ldapPath.substring(1); |
|
} |
|
} |
|
try { |
|
factory = CertificateFactory.getInstance("X.509"); |
|
} catch (CertificateException e) { |
|
throw new RuntimeException(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
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; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
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; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
@SuppressWarnings("unchecked") |
|
public synchronized Collection<X509Certificate> engineGetCertificates |
|
(CertSelector selector) throws CertStoreException { |
|
|
|
// if ldap URI we wrap the CertSelector in an LDAPCertSelector to |
|
|
|
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. |
|
|
|
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. |
|
|
|
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) { |
|
|
|
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..."); |
|
} |
|
|
|
certs = (Collection<X509Certificate>) |
|
factory.generateCertificates(in); |
|
} |
|
return getMatchingCerts(certs, selector); |
|
} catch (IOException | CertificateException e) { |
|
if (debug != null) { |
|
debug.println("Exception fetching certificates:"); |
|
e.printStackTrace(); |
|
} |
|
} |
|
|
|
lastModified = 0; |
|
certs = Collections.emptySet(); |
|
return certs; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static Collection<X509Certificate> getMatchingCerts |
|
(Collection<X509Certificate> certs, CertSelector selector) { |
|
|
|
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; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
@SuppressWarnings("unchecked") |
|
public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector) |
|
throws CertStoreException { |
|
|
|
// if ldap URI we wrap the CRLSelector in an LDAPCRLSelector to |
|
|
|
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. |
|
|
|
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. |
|
|
|
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) { |
|
|
|
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(); |
|
} |
|
|
|
lastModified = 0; |
|
crl = null; |
|
throw new PKIX.CertStoreTypeException("URI", |
|
new CertStoreException(e)); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
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(); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
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) { |
|
|
|
throw new InternalError(e.toString(), e); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static class UCS extends CertStore { |
|
protected UCS(CertStoreSpi spi, Provider p, String type, |
|
CertStoreParameters params) { |
|
super(spi, p, type, params); |
|
} |
|
} |
|
} |