|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.jca; |
|
|
|
import java.io.File; |
|
import java.lang.reflect.*; |
|
import java.util.*; |
|
|
|
import java.security.*; |
|
|
|
import sun.security.util.PropertyExpander; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final class ProviderConfig { |
|
|
|
private static final sun.security.util.Debug debug = |
|
sun.security.util.Debug.getInstance("jca", "ProviderConfig"); |
|
|
|
|
|
private static final String P11_SOL_NAME = "SunPKCS11"; |
|
|
|
|
|
private static final String P11_SOL_ARG = |
|
"${java.home}/conf/security/sunpkcs11-solaris.cfg"; |
|
|
|
|
|
private static final int MAX_LOAD_TRIES = 30; |
|
|
|
|
|
private final String provName; |
|
|
|
|
|
private final String argument; |
|
|
|
|
|
private int tries; |
|
|
|
|
|
private volatile Provider provider; |
|
|
|
// flag indicating if we are currently trying to load the provider |
|
|
|
private boolean isLoading; |
|
|
|
ProviderConfig(String provName, String argument) { |
|
if (provName.endsWith(P11_SOL_NAME) && argument.equals(P11_SOL_ARG)) { |
|
checkSunPKCS11Solaris(); |
|
} |
|
this.provName = provName; |
|
this.argument = expand(argument); |
|
} |
|
|
|
ProviderConfig(String provName) { |
|
this(provName, ""); |
|
} |
|
|
|
ProviderConfig(Provider provider) { |
|
this.provName = provider.getName(); |
|
this.argument = ""; |
|
this.provider = provider; |
|
} |
|
|
|
// check if we should try to load the SunPKCS11-Solaris provider |
|
// avoid if not available (pre Solaris 10) to reduce startup time |
|
|
|
private void checkSunPKCS11Solaris() { |
|
Boolean o = AccessController.doPrivileged( |
|
new PrivilegedAction<Boolean>() { |
|
public Boolean run() { |
|
File file = new File("/usr/lib/libpkcs11.so"); |
|
if (file.exists() == false) { |
|
return Boolean.FALSE; |
|
} |
|
if ("false".equalsIgnoreCase(System.getProperty |
|
("sun.security.pkcs11.enable-solaris"))) { |
|
return Boolean.FALSE; |
|
} |
|
return Boolean.TRUE; |
|
} |
|
}); |
|
if (o == Boolean.FALSE) { |
|
tries = MAX_LOAD_TRIES; |
|
} |
|
} |
|
|
|
private boolean hasArgument() { |
|
return argument.length() != 0; |
|
} |
|
|
|
|
|
private boolean shouldLoad() { |
|
return (tries < MAX_LOAD_TRIES); |
|
} |
|
|
|
|
|
private void disableLoad() { |
|
tries = MAX_LOAD_TRIES; |
|
} |
|
|
|
boolean isLoaded() { |
|
return (provider != null); |
|
} |
|
|
|
public boolean equals(Object obj) { |
|
if (this == obj) { |
|
return true; |
|
} |
|
if (obj instanceof ProviderConfig == false) { |
|
return false; |
|
} |
|
ProviderConfig other = (ProviderConfig)obj; |
|
return this.provName.equals(other.provName) |
|
&& this.argument.equals(other.argument); |
|
|
|
} |
|
|
|
public int hashCode() { |
|
return provName.hashCode() + argument.hashCode(); |
|
} |
|
|
|
public String toString() { |
|
if (hasArgument()) { |
|
return provName + "('" + argument + "')"; |
|
} else { |
|
return provName; |
|
} |
|
} |
|
|
|
/** |
|
* Get the provider object. Loads the provider if it is not already loaded. |
|
*/ |
|
|
|
@SuppressWarnings("deprecation") |
|
synchronized Provider getProvider() { |
|
|
|
Provider p = provider; |
|
if (p != null) { |
|
return p; |
|
} |
|
if (shouldLoad() == false) { |
|
return null; |
|
} |
|
|
|
|
|
if (provName.equals("SUN") || provName.equals("sun.security.provider.Sun")) { |
|
p = new sun.security.provider.Sun(); |
|
} else if (provName.equals("SunRsaSign") || provName.equals("sun.security.rsa.SunRsaSign")) { |
|
p = new sun.security.rsa.SunRsaSign(); |
|
} else if (provName.equals("SunJCE") || provName.equals("com.sun.crypto.provider.SunJCE")) { |
|
p = new com.sun.crypto.provider.SunJCE(); |
|
} else if (provName.equals("SunJSSE") || provName.equals("com.sun.net.ssl.internal.ssl.Provider")) { |
|
p = new com.sun.net.ssl.internal.ssl.Provider(); |
|
} else if (provName.equals("Apple") || provName.equals("apple.security.AppleProvider")) { |
|
|
|
p = AccessController.doPrivileged(new PrivilegedAction<Provider>() { |
|
public Provider run() { |
|
try { |
|
Class<?> c = Class.forName("apple.security.AppleProvider"); |
|
if (Provider.class.isAssignableFrom(c)) { |
|
@SuppressWarnings("deprecation") |
|
Object tmp = c.newInstance(); |
|
return (Provider) tmp; |
|
} else { |
|
return null; |
|
} |
|
} catch (Exception ex) { |
|
if (debug != null) { |
|
debug.println("Error loading provider Apple"); |
|
ex.printStackTrace(); |
|
} |
|
return null; |
|
} |
|
} |
|
}); |
|
} else { |
|
if (isLoading) { |
|
// because this method is synchronized, this can only |
|
|
|
if (debug != null) { |
|
debug.println("Recursion loading provider: " + this); |
|
new Exception("Call trace").printStackTrace(); |
|
} |
|
return null; |
|
} |
|
try { |
|
isLoading = true; |
|
tries++; |
|
p = doLoadProvider(); |
|
} finally { |
|
isLoading = false; |
|
} |
|
} |
|
provider = p; |
|
return p; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private Provider doLoadProvider() { |
|
return AccessController.doPrivileged(new PrivilegedAction<Provider>() { |
|
public Provider run() { |
|
if (debug != null) { |
|
debug.println("Loading provider " + ProviderConfig.this); |
|
} |
|
try { |
|
Provider p = ProviderLoader.INSTANCE.load(provName); |
|
if (p != null) { |
|
if (hasArgument()) { |
|
p = p.configure(argument); |
|
} |
|
if (debug != null) { |
|
debug.println("Loaded provider " + p.getName()); |
|
} |
|
} else { |
|
if (debug != null) { |
|
debug.println("Error loading provider " + |
|
ProviderConfig.this); |
|
} |
|
disableLoad(); |
|
} |
|
return p; |
|
} catch (Exception e) { |
|
if (e instanceof ProviderException) { |
|
|
|
throw e; |
|
} else { |
|
if (debug != null) { |
|
debug.println("Error loading provider " + |
|
ProviderConfig.this); |
|
e.printStackTrace(); |
|
} |
|
disableLoad(); |
|
return null; |
|
} |
|
} catch (ExceptionInInitializerError err) { |
|
|
|
if (debug != null) { |
|
debug.println("Error loading provider " + ProviderConfig.this); |
|
err.printStackTrace(); |
|
} |
|
disableLoad(); |
|
return null; |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static String expand(final String value) { |
|
|
|
if (value.contains("${") == false) { |
|
return value; |
|
} |
|
return AccessController.doPrivileged(new PrivilegedAction<String>() { |
|
public String run() { |
|
try { |
|
return PropertyExpander.expand(value); |
|
} catch (GeneralSecurityException e) { |
|
throw new ProviderException(e); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
private static final class ProviderLoader { |
|
static final ProviderLoader INSTANCE = new ProviderLoader(); |
|
|
|
private final ServiceLoader<Provider> services; |
|
|
|
private ProviderLoader() { |
|
// VM should already been booted at this point, if not |
|
// - Only providers in java.base should be loaded, don't use |
|
// ServiceLoader |
|
|
|
services = ServiceLoader.load(java.security.Provider.class, |
|
ClassLoader.getSystemClassLoader()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Provider load(String pn) { |
|
if (debug != null) { |
|
debug.println("Attempt to load " + pn + " using SL"); |
|
} |
|
Iterator<Provider> iter = services.iterator(); |
|
while (iter.hasNext()) { |
|
try { |
|
Provider p = iter.next(); |
|
String pName = p.getName(); |
|
if (debug != null) { |
|
debug.println("Found SL Provider named " + pName); |
|
} |
|
if (pName.equals(pn)) { |
|
return p; |
|
} |
|
} catch (SecurityException | ServiceConfigurationError | |
|
InvalidParameterException ex) { |
|
// if provider loading fail due to security permission, |
|
|
|
if (debug != null) { |
|
debug.println("Encountered " + ex + |
|
" while iterating through SL, ignore and move on"); |
|
ex.printStackTrace(); |
|
} |
|
} |
|
} |
|
// No success with ServiceLoader. Try loading provider the legacy, |
|
|
|
try { |
|
return legacyLoad(pn); |
|
} catch (ProviderException pe) { |
|
|
|
throw pe; |
|
} catch (Exception ex) { |
|
|
|
if (debug != null) { |
|
debug.println("Encountered " + ex + |
|
" during legacy load of " + pn); |
|
ex.printStackTrace(); |
|
} |
|
return null; |
|
} |
|
} |
|
|
|
private Provider legacyLoad(String classname) { |
|
|
|
if (debug != null) { |
|
debug.println("Loading legacy provider: " + classname); |
|
} |
|
|
|
try { |
|
Class<?> provClass = |
|
ClassLoader.getSystemClassLoader().loadClass(classname); |
|
|
|
|
|
if (!Provider.class.isAssignableFrom(provClass)) { |
|
if (debug != null) { |
|
debug.println(classname + " is not a provider"); |
|
} |
|
return null; |
|
} |
|
|
|
Provider p = AccessController.doPrivileged |
|
(new PrivilegedExceptionAction<Provider>() { |
|
@SuppressWarnings("deprecation") |
|
public Provider run() throws Exception { |
|
return (Provider) provClass.newInstance(); |
|
} |
|
}); |
|
return p; |
|
} catch (Exception e) { |
|
Throwable t; |
|
if (e instanceof InvocationTargetException) { |
|
t = ((InvocationTargetException)e).getCause(); |
|
} else { |
|
t = e; |
|
} |
|
if (debug != null) { |
|
debug.println("Error loading legacy provider " + classname); |
|
t.printStackTrace(); |
|
} |
|
|
|
if (t instanceof ProviderException) { |
|
throw (ProviderException) t; |
|
} |
|
return null; |
|
} catch (ExceptionInInitializerError | NoClassDefFoundError err) { |
|
|
|
if (debug != null) { |
|
debug.println("Error loading legacy provider " + classname); |
|
err.printStackTrace(); |
|
} |
|
return null; |
|
} |
|
} |
|
} |
|
} |