|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.jca; |
|
|
|
import java.util.*; |
|
|
|
import java.security.AccessController; |
|
import java.security.PrivilegedAction; |
|
import java.security.Provider; |
|
import java.security.Provider.Service; |
|
import java.security.Security; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final class ProviderList { |
|
|
|
static final sun.security.util.Debug debug = |
|
sun.security.util.Debug.getInstance("jca", "ProviderList"); |
|
|
|
private static final ProviderConfig[] PC0 = new ProviderConfig[0]; |
|
|
|
private static final Provider[] P0 = new Provider[0]; |
|
|
|
|
|
static final ProviderList EMPTY = new ProviderList(PC0, true); |
|
|
|
|
|
static private PreferredList preferredPropList = null; |
|
|
|
// dummy provider object to use during initialization |
|
|
|
private static final Provider EMPTY_PROVIDER = |
|
new Provider("##Empty##", "1.0", "initialization in progress") { |
|
private static final long serialVersionUID = 1151354171352296389L; |
|
|
|
public Service getService(String type, String algorithm) { |
|
return null; |
|
} |
|
}; |
|
|
|
// construct a ProviderList from the security properties |
|
|
|
static ProviderList fromSecurityProperties() { |
|
|
|
return AccessController.doPrivileged( |
|
new PrivilegedAction<ProviderList>() { |
|
public ProviderList run() { |
|
return new ProviderList(); |
|
} |
|
}); |
|
} |
|
|
|
public static ProviderList add(ProviderList providerList, Provider p) { |
|
return insertAt(providerList, p, -1); |
|
} |
|
|
|
public static ProviderList insertAt(ProviderList providerList, Provider p, |
|
int position) { |
|
if (providerList.getProvider(p.getName()) != null) { |
|
return providerList; |
|
} |
|
List<ProviderConfig> list = new ArrayList<> |
|
(Arrays.asList(providerList.configs)); |
|
int n = list.size(); |
|
if ((position < 0) || (position > n)) { |
|
position = n; |
|
} |
|
list.add(position, new ProviderConfig(p)); |
|
return new ProviderList(list.toArray(PC0), true); |
|
} |
|
|
|
public static ProviderList remove(ProviderList providerList, String name) { |
|
|
|
if (providerList.getProvider(name) == null) { |
|
return providerList; |
|
} |
|
|
|
ProviderConfig[] configs = new ProviderConfig[providerList.size() - 1]; |
|
int j = 0; |
|
for (ProviderConfig config : providerList.configs) { |
|
if (config.getProvider().getName().equals(name) == false) { |
|
configs[j++] = config; |
|
} |
|
} |
|
return new ProviderList(configs, true); |
|
} |
|
|
|
// Create a new ProviderList from the specified Providers. |
|
|
|
public static ProviderList newList(Provider ... providers) { |
|
ProviderConfig[] configs = new ProviderConfig[providers.length]; |
|
for (int i = 0; i < providers.length; i++) { |
|
configs[i] = new ProviderConfig(providers[i]); |
|
} |
|
return new ProviderList(configs, true); |
|
} |
|
|
|
|
|
private final ProviderConfig[] configs; |
|
|
|
|
|
private volatile boolean allLoaded; |
|
|
|
|
|
private final List<Provider> userList = new AbstractList<Provider>() { |
|
public int size() { |
|
return configs.length; |
|
} |
|
public Provider get(int index) { |
|
return getProvider(index); |
|
} |
|
}; |
|
|
|
|
|
|
|
*/ |
|
private ProviderList(ProviderConfig[] configs, boolean allLoaded) { |
|
this.configs = configs; |
|
this.allLoaded = allLoaded; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private ProviderList() { |
|
List<ProviderConfig> configList = new ArrayList<>(); |
|
String entry; |
|
int i = 1; |
|
|
|
while ((entry = Security.getProperty("security.provider." + i)) != null) { |
|
entry = entry.trim(); |
|
if (entry.length() == 0) { |
|
System.err.println("invalid entry for " + |
|
"security.provider." + i); |
|
break; |
|
} |
|
int k = entry.indexOf(' '); |
|
ProviderConfig config; |
|
if (k == -1) { |
|
config = new ProviderConfig(entry); |
|
} else { |
|
String provName = entry.substring(0, k); |
|
String argument = entry.substring(k + 1).trim(); |
|
config = new ProviderConfig(provName, argument); |
|
} |
|
|
|
|
|
if (configList.contains(config) == false) { |
|
configList.add(config); |
|
} |
|
i++; |
|
} |
|
configs = configList.toArray(PC0); |
|
|
|
|
|
entry = Security.getProperty("jdk.security.provider.preferred"); |
|
if (entry != null && (entry = entry.trim()).length() > 0) { |
|
String[] entries = entry.split(","); |
|
if (ProviderList.preferredPropList == null) { |
|
ProviderList.preferredPropList = new PreferredList(); |
|
} |
|
|
|
for (String e : entries) { |
|
i = e.indexOf(':'); |
|
if (i < 0) { |
|
if (debug != null) { |
|
debug.println("invalid preferred entry skipped. " + |
|
"Missing colon delimiter \"" + e + "\""); |
|
} |
|
continue; |
|
} |
|
ProviderList.preferredPropList.add(new PreferredEntry( |
|
e.substring(0, i).trim(), e.substring(i + 1).trim())); |
|
} |
|
} |
|
|
|
if (debug != null) { |
|
debug.println("provider configuration: " + configList); |
|
debug.println("config configuration: " + |
|
ProviderList.preferredPropList); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
ProviderList getJarList(String[] jarProvNames) { |
|
List<ProviderConfig> newConfigs = new ArrayList<>(); |
|
for (String provName : jarProvNames) { |
|
ProviderConfig newConfig = new ProviderConfig(provName); |
|
for (ProviderConfig config : configs) { |
|
// if the equivalent object is present in this provider list, |
|
// use the old object rather than the new object. |
|
// this ensures that when the provider is loaded in the |
|
// new thread local list, it will also become available |
|
|
|
if (config.equals(newConfig)) { |
|
newConfig = config; |
|
break; |
|
} |
|
} |
|
newConfigs.add(newConfig); |
|
} |
|
ProviderConfig[] configArray = newConfigs.toArray(PC0); |
|
return new ProviderList(configArray, false); |
|
} |
|
|
|
public int size() { |
|
return configs.length; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
Provider getProvider(int index) { |
|
Provider p = configs[index].getProvider(); |
|
return (p != null) ? p : EMPTY_PROVIDER; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public List<Provider> providers() { |
|
return userList; |
|
} |
|
|
|
private ProviderConfig getProviderConfig(String name) { |
|
int index = getIndex(name); |
|
return (index != -1) ? configs[index] : null; |
|
} |
|
|
|
|
|
public Provider getProvider(String name) { |
|
ProviderConfig config = getProviderConfig(name); |
|
return (config == null) ? null : config.getProvider(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public int getIndex(String name) { |
|
for (int i = 0; i < configs.length; i++) { |
|
Provider p = getProvider(i); |
|
if (p.getName().equals(name)) { |
|
return i; |
|
} |
|
} |
|
return -1; |
|
} |
|
|
|
|
|
private int loadAll() { |
|
if (allLoaded) { |
|
return configs.length; |
|
} |
|
if (debug != null) { |
|
debug.println("Loading all providers"); |
|
new Exception("Debug Info. Call trace:").printStackTrace(); |
|
} |
|
int n = 0; |
|
for (int i = 0; i < configs.length; i++) { |
|
Provider p = configs[i].getProvider(); |
|
if (p != null) { |
|
n++; |
|
} |
|
} |
|
if (n == configs.length) { |
|
allLoaded = true; |
|
} |
|
return n; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
ProviderList removeInvalid() { |
|
int n = loadAll(); |
|
if (n == configs.length) { |
|
return this; |
|
} |
|
ProviderConfig[] newConfigs = new ProviderConfig[n]; |
|
for (int i = 0, j = 0; i < configs.length; i++) { |
|
ProviderConfig config = configs[i]; |
|
if (config.isLoaded()) { |
|
newConfigs[j++] = config; |
|
} |
|
} |
|
return new ProviderList(newConfigs, true); |
|
} |
|
|
|
|
|
public Provider[] toArray() { |
|
return providers().toArray(P0); |
|
} |
|
|
|
|
|
public String toString() { |
|
return Arrays.asList(configs).toString(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Service getService(String type, String name) { |
|
ArrayList<PreferredEntry> pList = null; |
|
int i; |
|
|
|
|
|
if (preferredPropList != null && |
|
(pList = preferredPropList.getAll(type, name)) != null) { |
|
for (i = 0; i < pList.size(); i++) { |
|
Provider p = getProvider(pList.get(i).provider); |
|
Service s = p.getService(type, name); |
|
if (s != null) { |
|
return s; |
|
} |
|
} |
|
} |
|
|
|
for (i = 0; i < configs.length; i++) { |
|
Provider p = getProvider(i); |
|
Service s = p.getService(type, name); |
|
if (s != null) { |
|
return s; |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public List<Service> getServices(String type, String algorithm) { |
|
return new ServiceList(type, algorithm); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Deprecated |
|
public List<Service> getServices(String type, List<String> algorithms) { |
|
List<ServiceId> ids = new ArrayList<>(); |
|
for (String alg : algorithms) { |
|
ids.add(new ServiceId(type, alg)); |
|
} |
|
return getServices(ids); |
|
} |
|
|
|
public List<Service> getServices(List<ServiceId> ids) { |
|
return new ServiceList(ids); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private final class ServiceList extends AbstractList<Service> { |
|
|
|
// type and algorithm for simple lookup |
|
|
|
private final String type; |
|
private final String algorithm; |
|
|
|
// list of ids for parallel lookup |
|
|
|
private final List<ServiceId> ids; |
|
|
|
// first service we have found |
|
// it is stored in a separate variable so that we can avoid |
|
// allocating the services list if we do not need the second service. |
|
|
|
private Service firstService; |
|
|
|
|
|
private List<Service> services; |
|
|
|
|
|
private int providerIndex = 0; |
|
|
|
|
|
ArrayList<PreferredEntry> preferredList = null; |
|
private int preferredIndex = 0; |
|
|
|
ServiceList(String type, String algorithm) { |
|
this.type = type; |
|
this.algorithm = algorithm; |
|
this.ids = null; |
|
} |
|
|
|
ServiceList(List<ServiceId> ids) { |
|
this.type = null; |
|
this.algorithm = null; |
|
this.ids = ids; |
|
} |
|
|
|
private void addService(Service s) { |
|
if (firstService == null) { |
|
firstService = s; |
|
} else { |
|
if (services == null) { |
|
services = new ArrayList<Service>(4); |
|
services.add(firstService); |
|
} |
|
services.add(s); |
|
} |
|
} |
|
|
|
private Service tryGet(int index) { |
|
Provider p; |
|
|
|
// If preferred providers are configured, check for matches with |
|
|
|
if (preferredPropList != null && preferredList == null) { |
|
preferredList = preferredPropList.getAll(this); |
|
} |
|
|
|
while (true) { |
|
if ((index == 0) && (firstService != null)) { |
|
return firstService; |
|
} else if ((services != null) && (services.size() > index)) { |
|
return services.get(index); |
|
} |
|
if (providerIndex >= configs.length) { |
|
return null; |
|
} |
|
|
|
// If there were matches with a preferred provider, iterate |
|
// through the list first before going through the |
|
|
|
if (preferredList != null && |
|
preferredIndex < preferredList.size()) { |
|
PreferredEntry entry = preferredList.get(preferredIndex++); |
|
|
|
p = getProvider(entry.provider); |
|
if (p == null) { |
|
if (debug != null) { |
|
debug.println("No provider found with name: " + |
|
entry.provider); |
|
} |
|
continue; |
|
} |
|
} else { |
|
|
|
p = getProvider(providerIndex++); |
|
} |
|
|
|
if (type != null) { |
|
|
|
Service s = p.getService(type, algorithm); |
|
if (s != null) { |
|
addService(s); |
|
} |
|
} else { |
|
|
|
for (ServiceId id : ids) { |
|
Service s = p.getService(id.type, id.algorithm); |
|
if (s != null) { |
|
addService(s); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
public Service get(int index) { |
|
Service s = tryGet(index); |
|
if (s == null) { |
|
throw new IndexOutOfBoundsException(); |
|
} |
|
return s; |
|
} |
|
|
|
public int size() { |
|
int n; |
|
if (services != null) { |
|
n = services.size(); |
|
} else { |
|
n = (firstService != null) ? 1 : 0; |
|
} |
|
while (tryGet(n) != null) { |
|
n++; |
|
} |
|
return n; |
|
} |
|
|
|
// override isEmpty() and iterator() to not call size() |
|
// this avoids loading + checking all Providers |
|
|
|
public boolean isEmpty() { |
|
return (tryGet(0) == null); |
|
} |
|
|
|
public Iterator<Service> iterator() { |
|
return new Iterator<Service>() { |
|
int index; |
|
|
|
public boolean hasNext() { |
|
return tryGet(index) != null; |
|
} |
|
|
|
public Service next() { |
|
Service s = tryGet(index); |
|
if (s == null) { |
|
throw new NoSuchElementException(); |
|
} |
|
index++; |
|
return s; |
|
} |
|
|
|
public void remove() { |
|
throw new UnsupportedOperationException(); |
|
} |
|
}; |
|
} |
|
} |
|
|
|
|
|
static final class PreferredList { |
|
ArrayList<PreferredEntry> list = new ArrayList<PreferredEntry>(); |
|
|
|
|
|
|
|
|
|
*/ |
|
ArrayList<PreferredEntry> getAll(ServiceList s) { |
|
if (s.ids == null) { |
|
return getAll(s.type, s.algorithm); |
|
|
|
} |
|
|
|
ArrayList<PreferredEntry> l = new ArrayList<PreferredEntry>(); |
|
for (ServiceId id : s.ids) { |
|
implGetAll(l, id.type, id.algorithm); |
|
} |
|
|
|
return l; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
ArrayList<PreferredEntry> getAll(String type, String algorithm) { |
|
ArrayList<PreferredEntry> l = new ArrayList<PreferredEntry>(); |
|
implGetAll(l, type, algorithm); |
|
return l; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private void implGetAll(ArrayList<PreferredEntry> l, String type, |
|
String algorithm) { |
|
PreferredEntry e; |
|
|
|
for (int i = 0; i < size(); i++) { |
|
e = list.get(i); |
|
if (e.match(type, algorithm)) { |
|
l.add(e); |
|
} |
|
} |
|
} |
|
|
|
public PreferredEntry get(int i) { |
|
return list.get(i); |
|
} |
|
|
|
public int size() { |
|
return list.size(); |
|
} |
|
|
|
public boolean add(PreferredEntry e) { |
|
return list.add(e); |
|
} |
|
|
|
public String toString() { |
|
String s = ""; |
|
for (PreferredEntry e: list) { |
|
s += e.toString(); |
|
} |
|
return s; |
|
} |
|
} |
|
|
|
|
|
private static final String SHA2Group[] = { "SHA-224", "SHA-256", |
|
"SHA-384", "SHA-512", "SHA-512/224", "SHA-512/256" }; |
|
private static final String HmacSHA2Group[] = { "HmacSHA224", |
|
"HmacSHA256", "HmacSHA384", "HmacSHA512"}; |
|
private static final String SHA2RSAGroup[] = { "SHA224withRSA", |
|
"SHA256withRSA", "SHA384withRSA", "SHA512withRSA"}; |
|
private static final String SHA2DSAGroup[] = { "SHA224withDSA", |
|
"SHA256withDSA", "SHA384withDSA", "SHA512withDSA"}; |
|
private static final String SHA2ECDSAGroup[] = { "SHA224withECDSA", |
|
"SHA256withECDSA", "SHA384withECDSA", "SHA512withECDSA"}; |
|
private static final String SHA3Group[] = { "SHA3-224", "SHA3-256", |
|
"SHA3-384", "SHA3-512" }; |
|
private static final String HmacSHA3Group[] = { "HmacSHA3-224", |
|
"HmacSHA3-256", "HmacSHA3-384", "HmacSHA3-512"}; |
|
|
|
|
|
private static class PreferredEntry { |
|
private String type = null; |
|
private String algorithm; |
|
private String provider; |
|
private String alternateNames[] = null; |
|
private boolean group = false; |
|
|
|
PreferredEntry(String t, String p) { |
|
int i = t.indexOf('.'); |
|
if (i > 0) { |
|
type = t.substring(0, i); |
|
algorithm = t.substring(i + 1); |
|
} else { |
|
algorithm = t; |
|
} |
|
|
|
provider = p; |
|
|
|
if (type != null && type.compareToIgnoreCase("Group") == 0) { |
|
|
|
if (algorithm.compareToIgnoreCase("SHA2") == 0) { |
|
alternateNames = SHA2Group; |
|
} else if (algorithm.compareToIgnoreCase("HmacSHA2") == 0) { |
|
alternateNames = HmacSHA2Group; |
|
} else if (algorithm.compareToIgnoreCase("SHA2RSA") == 0) { |
|
alternateNames = SHA2RSAGroup; |
|
} else if (algorithm.compareToIgnoreCase("SHA2DSA") == 0) { |
|
alternateNames = SHA2DSAGroup; |
|
} else if (algorithm.compareToIgnoreCase("SHA2ECDSA") == 0) { |
|
alternateNames = SHA2ECDSAGroup; |
|
} else if (algorithm.compareToIgnoreCase("SHA3") == 0) { |
|
alternateNames = SHA3Group; |
|
} else if (algorithm.compareToIgnoreCase("HmacSHA3") == 0) { |
|
alternateNames = HmacSHA3Group; |
|
} |
|
if (alternateNames != null) { |
|
group = true; |
|
} |
|
|
|
// If the algorithm name given is SHA1 |
|
} else if (algorithm.compareToIgnoreCase("SHA1") == 0) { |
|
alternateNames = new String[] { "SHA-1" }; |
|
} else if (algorithm.compareToIgnoreCase("SHA-1") == 0) { |
|
alternateNames = new String[] { "SHA1" }; |
|
} |
|
} |
|
|
|
boolean match(String t, String a) { |
|
if (debug != null) { |
|
debug.println("Config check: " + toString() + " == " + |
|
print(t, a, null)); |
|
} |
|
|
|
|
|
if (type != null && !group && type.compareToIgnoreCase(t) != 0) { |
|
return false; |
|
} |
|
|
|
|
|
if (!group && a.compareToIgnoreCase(algorithm) == 0) { |
|
if (debug != null) { |
|
debug.println("Config entry matched: " + toString()); |
|
} |
|
return true; |
|
} |
|
|
|
if (alternateNames != null) { |
|
for (String alt : alternateNames) { |
|
if (debug != null) { |
|
debug.println("AltName check: " + print(type, alt, |
|
provider)); |
|
} |
|
if (a.compareToIgnoreCase(alt) == 0) { |
|
if (debug != null) { |
|
debug.println("AltName entry matched: " + |
|
provider); |
|
} |
|
return true; |
|
} |
|
} |
|
} |
|
|
|
|
|
return false; |
|
} |
|
|
|
|
|
private String print(String t, String a, String p) { |
|
return "[" + ((t != null) ? t : "" ) + ", " + a + |
|
((p != null) ? " : " + p : "" ) + "] "; |
|
} |
|
|
|
public String toString() { |
|
return print(type, algorithm, provider); |
|
} |
|
} |
|
|
|
} |