0N/A/*
3909N/A * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.security;
0N/A
0N/Aimport java.lang.reflect.*;
0N/Aimport java.util.*;
0N/Aimport java.util.concurrent.ConcurrentHashMap;
0N/Aimport java.io.*;
0N/Aimport java.net.URL;
0N/Aimport sun.security.util.Debug;
0N/Aimport sun.security.util.PropertyExpander;
0N/A
0N/Aimport java.security.Provider.Service;
0N/A
0N/Aimport sun.security.jca.*;
0N/A
0N/A/**
0N/A * <p>This class centralizes all security properties and common security
0N/A * methods. One of its primary uses is to manage providers.
0N/A *
0N/A * @author Benjamin Renaud
0N/A */
0N/A
0N/Apublic final class Security {
0N/A
0N/A /* Are we debugging? -- for developers */
0N/A private static final Debug sdebug =
0N/A Debug.getInstance("properties");
0N/A
0N/A /* The java.security properties */
0N/A private static Properties props;
0N/A
0N/A // An element in the cache
0N/A private static class ProviderProperty {
0N/A String className;
0N/A Provider provider;
0N/A }
0N/A
0N/A static {
0N/A // doPrivileged here because there are multiple
0N/A // things in initialize that might require privs.
0N/A // (the FileInputStream call and the File.exists call,
0N/A // the securityPropFile call, etc)
0N/A AccessController.doPrivileged(new PrivilegedAction<Void>() {
0N/A public Void run() {
0N/A initialize();
0N/A return null;
0N/A }
0N/A });
0N/A }
0N/A
0N/A private static void initialize() {
0N/A props = new Properties();
0N/A boolean loadedProps = false;
0N/A boolean overrideAll = false;
0N/A
0N/A // first load the system properties file
0N/A // to determine the value of security.overridePropertiesFile
0N/A File propFile = securityPropFile("java.security");
0N/A if (propFile.exists()) {
0N/A InputStream is = null;
0N/A try {
0N/A FileInputStream fis = new FileInputStream(propFile);
0N/A is = new BufferedInputStream(fis);
0N/A props.load(is);
0N/A loadedProps = true;
0N/A
0N/A if (sdebug != null) {
0N/A sdebug.println("reading security properties file: " +
0N/A propFile);
0N/A }
0N/A } catch (IOException e) {
0N/A if (sdebug != null) {
0N/A sdebug.println("unable to load security properties from " +
0N/A propFile);
0N/A e.printStackTrace();
0N/A }
0N/A } finally {
0N/A if (is != null) {
0N/A try {
0N/A is.close();
0N/A } catch (IOException ioe) {
0N/A if (sdebug != null) {
0N/A sdebug.println("unable to close input stream");
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A if ("true".equalsIgnoreCase(props.getProperty
0N/A ("security.overridePropertiesFile"))) {
0N/A
0N/A String extraPropFile = System.getProperty
0N/A ("java.security.properties");
0N/A if (extraPropFile != null && extraPropFile.startsWith("=")) {
0N/A overrideAll = true;
0N/A extraPropFile = extraPropFile.substring(1);
0N/A }
0N/A
0N/A if (overrideAll) {
0N/A props = new Properties();
0N/A if (sdebug != null) {
0N/A sdebug.println
0N/A ("overriding other security properties files!");
0N/A }
0N/A }
0N/A
0N/A // now load the user-specified file so its values
0N/A // will win if they conflict with the earlier values
0N/A if (extraPropFile != null) {
0N/A BufferedInputStream bis = null;
0N/A try {
0N/A URL propURL;
0N/A
0N/A extraPropFile = PropertyExpander.expand(extraPropFile);
0N/A propFile = new File(extraPropFile);
0N/A if (propFile.exists()) {
0N/A propURL = new URL
0N/A ("file:" + propFile.getCanonicalPath());
0N/A } else {
0N/A propURL = new URL(extraPropFile);
0N/A }
0N/A bis = new BufferedInputStream(propURL.openStream());
0N/A props.load(bis);
0N/A loadedProps = true;
0N/A
0N/A if (sdebug != null) {
0N/A sdebug.println("reading security properties file: " +
0N/A propURL);
0N/A if (overrideAll) {
0N/A sdebug.println
0N/A ("overriding other security properties files!");
0N/A }
0N/A }
0N/A } catch (Exception e) {
0N/A if (sdebug != null) {
0N/A sdebug.println
0N/A ("unable to load security properties from " +
0N/A extraPropFile);
0N/A e.printStackTrace();
0N/A }
0N/A } finally {
0N/A if (bis != null) {
0N/A try {
0N/A bis.close();
0N/A } catch (IOException ioe) {
0N/A if (sdebug != null) {
0N/A sdebug.println("unable to close input stream");
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A if (!loadedProps) {
0N/A initializeStatic();
0N/A if (sdebug != null) {
0N/A sdebug.println("unable to load security properties " +
0N/A "-- using defaults");
0N/A }
0N/A }
0N/A
0N/A }
0N/A
0N/A /*
0N/A * Initialize to default values, if <java.home>/lib/java.security
0N/A * is not found.
0N/A */
0N/A private static void initializeStatic() {
0N/A props.put("security.provider.1", "sun.security.provider.Sun");
0N/A props.put("security.provider.2", "sun.security.rsa.SunRsaSign");
0N/A props.put("security.provider.3", "com.sun.net.ssl.internal.ssl.Provider");
0N/A props.put("security.provider.4", "com.sun.crypto.provider.SunJCE");
0N/A props.put("security.provider.5", "sun.security.jgss.SunProvider");
0N/A props.put("security.provider.6", "com.sun.security.sasl.Provider");
0N/A }
0N/A
0N/A /**
0N/A * Don't let anyone instantiate this.
0N/A */
0N/A private Security() {
0N/A }
0N/A
0N/A private static File securityPropFile(String filename) {
0N/A // maybe check for a system property which will specify where to
0N/A // look. Someday.
0N/A String sep = File.separator;
0N/A return new File(System.getProperty("java.home") + sep + "lib" + sep +
0N/A "security" + sep + filename);
0N/A }
0N/A
0N/A /**
0N/A * Looks up providers, and returns the property (and its associated
0N/A * provider) mapping the key, if any.
0N/A * The order in which the providers are looked up is the
0N/A * provider-preference order, as specificed in the security
0N/A * properties file.
0N/A */
0N/A private static ProviderProperty getProviderProperty(String key) {
0N/A ProviderProperty entry = null;
0N/A
0N/A List<Provider> providers = Providers.getProviderList().providers();
0N/A for (int i = 0; i < providers.size(); i++) {
0N/A
0N/A String matchKey = null;
0N/A Provider prov = providers.get(i);
0N/A String prop = prov.getProperty(key);
0N/A
0N/A if (prop == null) {
0N/A // Is there a match if we do a case-insensitive property name
0N/A // comparison? Let's try ...
0N/A for (Enumeration<Object> e = prov.keys();
0N/A e.hasMoreElements() && prop == null; ) {
0N/A matchKey = (String)e.nextElement();
0N/A if (key.equalsIgnoreCase(matchKey)) {
0N/A prop = prov.getProperty(matchKey);
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A
0N/A if (prop != null) {
0N/A ProviderProperty newEntry = new ProviderProperty();
0N/A newEntry.className = prop;
0N/A newEntry.provider = prov;
0N/A return newEntry;
0N/A }
0N/A }
0N/A
0N/A return entry;
0N/A }
0N/A
0N/A /**
0N/A * Returns the property (if any) mapping the key for the given provider.
0N/A */
0N/A private static String getProviderProperty(String key, Provider provider) {
0N/A String prop = provider.getProperty(key);
0N/A if (prop == null) {
0N/A // Is there a match if we do a case-insensitive property name
0N/A // comparison? Let's try ...
0N/A for (Enumeration<Object> e = provider.keys();
0N/A e.hasMoreElements() && prop == null; ) {
0N/A String matchKey = (String)e.nextElement();
0N/A if (key.equalsIgnoreCase(matchKey)) {
0N/A prop = provider.getProperty(matchKey);
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A return prop;
0N/A }
0N/A
0N/A /**
0N/A * Gets a specified property for an algorithm. The algorithm name
3465N/A * should be a standard name. See the <a href=
3465N/A * "{@docRoot}/../technotes/guides/security/StandardNames.html">
3465N/A * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
0N/A * for information about standard algorithm names.
3465N/A *
0N/A * One possible use is by specialized algorithm parsers, which may map
0N/A * classes to algorithms which they understand (much like Key parsers
0N/A * do).
0N/A *
0N/A * @param algName the algorithm name.
0N/A *
0N/A * @param propName the name of the property to get.
0N/A *
0N/A * @return the value of the specified property.
0N/A *
0N/A * @deprecated This method used to return the value of a proprietary
0N/A * property in the master file of the "SUN" Cryptographic Service
0N/A * Provider in order to determine how to parse algorithm-specific
0N/A * parameters. Use the new provider-based and algorithm-independent
0N/A * <code>AlgorithmParameters</code> and <code>KeyFactory</code> engine
0N/A * classes (introduced in the J2SE version 1.2 platform) instead.
0N/A */
0N/A @Deprecated
0N/A public static String getAlgorithmProperty(String algName,
0N/A String propName) {
0N/A ProviderProperty entry = getProviderProperty("Alg." + propName
0N/A + "." + algName);
0N/A if (entry != null) {
0N/A return entry.className;
0N/A } else {
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Adds a new provider, at a specified position. The position is
0N/A * the preference order in which providers are searched for
0N/A * requested algorithms. The position is 1-based, that is,
0N/A * 1 is most preferred, followed by 2, and so on.
0N/A *
0N/A * <p>If the given provider is installed at the requested position,
0N/A * the provider that used to be at that position, and all providers
0N/A * with a position greater than <code>position</code>, are shifted up
0N/A * one position (towards the end of the list of installed providers).
0N/A *
0N/A * <p>A provider cannot be added if it is already installed.
0N/A *
0N/A * <p>First, if there is a security manager, its
0N/A * <code>checkSecurityAccess</code>
0N/A * method is called with the string
0N/A * <code>"insertProvider."+provider.getName()</code>
0N/A * to see if it's ok to add a new provider.
0N/A * If the default implementation of <code>checkSecurityAccess</code>
0N/A * is used (i.e., that method is not overriden), then this will result in
0N/A * a call to the security manager's <code>checkPermission</code> method
0N/A * with a
0N/A * <code>SecurityPermission("insertProvider."+provider.getName())</code>
0N/A * permission.
0N/A *
0N/A * @param provider the provider to be added.
0N/A *
0N/A * @param position the preference position that the caller would
0N/A * like for this provider.
0N/A *
0N/A * @return the actual preference position in which the provider was
0N/A * added, or -1 if the provider was not added because it is
0N/A * already installed.
0N/A *
0N/A * @throws NullPointerException if provider is null
0N/A * @throws SecurityException
0N/A * if a security manager exists and its <code>{@link
0N/A * java.lang.SecurityManager#checkSecurityAccess}</code> method
0N/A * denies access to add a new provider
0N/A *
0N/A * @see #getProvider
0N/A * @see #removeProvider
0N/A * @see java.security.SecurityPermission
0N/A */
0N/A public static synchronized int insertProviderAt(Provider provider,
0N/A int position) {
0N/A String providerName = provider.getName();
0N/A check("insertProvider." + providerName);
0N/A ProviderList list = Providers.getFullProviderList();
0N/A ProviderList newList = ProviderList.insertAt(list, provider, position - 1);
0N/A if (list == newList) {
0N/A return -1;
0N/A }
0N/A Providers.setProviderList(newList);
0N/A return newList.getIndex(providerName) + 1;
0N/A }
0N/A
0N/A /**
0N/A * Adds a provider to the next position available.
0N/A *
0N/A * <p>First, if there is a security manager, its
0N/A * <code>checkSecurityAccess</code>
0N/A * method is called with the string
0N/A * <code>"insertProvider."+provider.getName()</code>
0N/A * to see if it's ok to add a new provider.
0N/A * If the default implementation of <code>checkSecurityAccess</code>
0N/A * is used (i.e., that method is not overriden), then this will result in
0N/A * a call to the security manager's <code>checkPermission</code> method
0N/A * with a
0N/A * <code>SecurityPermission("insertProvider."+provider.getName())</code>
0N/A * permission.
0N/A *
0N/A * @param provider the provider to be added.
0N/A *
0N/A * @return the preference position in which the provider was
0N/A * added, or -1 if the provider was not added because it is
0N/A * already installed.
0N/A *
0N/A * @throws NullPointerException if provider is null
0N/A * @throws SecurityException
0N/A * if a security manager exists and its <code>{@link
0N/A * java.lang.SecurityManager#checkSecurityAccess}</code> method
0N/A * denies access to add a new provider
0N/A *
0N/A * @see #getProvider
0N/A * @see #removeProvider
0N/A * @see java.security.SecurityPermission
0N/A */
0N/A public static int addProvider(Provider provider) {
0N/A /*
0N/A * We can't assign a position here because the statically
0N/A * registered providers may not have been installed yet.
0N/A * insertProviderAt() will fix that value after it has
0N/A * loaded the static providers.
0N/A */
0N/A return insertProviderAt(provider, 0);
0N/A }
0N/A
0N/A /**
0N/A * Removes the provider with the specified name.
0N/A *
0N/A * <p>When the specified provider is removed, all providers located
0N/A * at a position greater than where the specified provider was are shifted
0N/A * down one position (towards the head of the list of installed
0N/A * providers).
0N/A *
0N/A * <p>This method returns silently if the provider is not installed or
0N/A * if name is null.
0N/A *
0N/A * <p>First, if there is a security manager, its
0N/A * <code>checkSecurityAccess</code>
0N/A * method is called with the string <code>"removeProvider."+name</code>
0N/A * to see if it's ok to remove the provider.
0N/A * If the default implementation of <code>checkSecurityAccess</code>
0N/A * is used (i.e., that method is not overriden), then this will result in
0N/A * a call to the security manager's <code>checkPermission</code> method
0N/A * with a <code>SecurityPermission("removeProvider."+name)</code>
0N/A * permission.
0N/A *
0N/A * @param name the name of the provider to remove.
0N/A *
0N/A * @throws SecurityException
0N/A * if a security manager exists and its <code>{@link
0N/A * java.lang.SecurityManager#checkSecurityAccess}</code> method
0N/A * denies
0N/A * access to remove the provider
0N/A *
0N/A * @see #getProvider
0N/A * @see #addProvider
0N/A */
0N/A public static synchronized void removeProvider(String name) {
0N/A check("removeProvider." + name);
0N/A ProviderList list = Providers.getFullProviderList();
0N/A ProviderList newList = ProviderList.remove(list, name);
0N/A Providers.setProviderList(newList);
0N/A }
0N/A
0N/A /**
0N/A * Returns an array containing all the installed providers. The order of
0N/A * the providers in the array is their preference order.
0N/A *
0N/A * @return an array of all the installed providers.
0N/A */
0N/A public static Provider[] getProviders() {
0N/A return Providers.getFullProviderList().toArray();
0N/A }
0N/A
0N/A /**
0N/A * Returns the provider installed with the specified name, if
0N/A * any. Returns null if no provider with the specified name is
0N/A * installed or if name is null.
0N/A *
0N/A * @param name the name of the provider to get.
0N/A *
0N/A * @return the provider of the specified name.
0N/A *
0N/A * @see #removeProvider
0N/A * @see #addProvider
0N/A */
0N/A public static Provider getProvider(String name) {
0N/A return Providers.getProviderList().getProvider(name);
0N/A }
0N/A
0N/A /**
0N/A * Returns an array containing all installed providers that satisfy the
0N/A * specified selection criterion, or null if no such providers have been
0N/A * installed. The returned providers are ordered
0N/A * according to their <a href=
0N/A * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
0N/A *
0N/A * <p> A cryptographic service is always associated with a particular
0N/A * algorithm or type. For example, a digital signature service is
0N/A * always associated with a particular algorithm (e.g., DSA),
0N/A * and a CertificateFactory service is always associated with
0N/A * a particular certificate type (e.g., X.509).
0N/A *
0N/A * <p>The selection criterion must be specified in one of the following two
0N/A * formats:
0N/A * <ul>
0N/A * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type></i> <p> The
0N/A * cryptographic service name must not contain any dots.
0N/A * <p> A
0N/A * provider satisfies the specified selection criterion iff the provider
0N/A * implements the
0N/A * specified algorithm or type for the specified cryptographic service.
0N/A * <p> For example, "CertificateFactory.X.509"
0N/A * would be satisfied by any provider that supplied
0N/A * a CertificateFactory implementation for X.509 certificates.
0N/A * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type>
0N/A * &lt;attribute_name>:&lt attribute_value></i>
0N/A * <p> The cryptographic service name must not contain any dots. There
1104N/A * must be one or more space charaters between the
0N/A * <i>&lt;algorithm_or_type></i> and the <i>&lt;attribute_name></i>.
0N/A * <p> A provider satisfies this selection criterion iff the
0N/A * provider implements the specified algorithm or type for the specified
0N/A * cryptographic service and its implementation meets the
0N/A * constraint expressed by the specified attribute name/value pair.
0N/A * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
0N/A * satisfied by any provider that implemented
0N/A * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
0N/A *
0N/A * </ul>
0N/A *
3465N/A * <p> See the <a href=
3465N/A * "{@docRoot}/../technotes/guides/security/StandardNames.html">
3465N/A * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
0N/A * for information about standard cryptographic service names, standard
0N/A * algorithm names and standard attribute names.
0N/A *
0N/A * @param filter the criterion for selecting
0N/A * providers. The filter is case-insensitive.
0N/A *
0N/A * @return all the installed providers that satisfy the selection
0N/A * criterion, or null if no such providers have been installed.
0N/A *
0N/A * @throws InvalidParameterException
0N/A * if the filter is not in the required format
0N/A * @throws NullPointerException if filter is null
0N/A *
0N/A * @see #getProviders(java.util.Map)
0N/A * @since 1.3
0N/A */
0N/A public static Provider[] getProviders(String filter) {
0N/A String key = null;
0N/A String value = null;
0N/A int index = filter.indexOf(':');
0N/A
0N/A if (index == -1) {
0N/A key = filter;
0N/A value = "";
0N/A } else {
0N/A key = filter.substring(0, index);
0N/A value = filter.substring(index + 1);
0N/A }
0N/A
3381N/A Hashtable<String, String> hashtableFilter = new Hashtable<>(1);
0N/A hashtableFilter.put(key, value);
0N/A
0N/A return (getProviders(hashtableFilter));
0N/A }
0N/A
0N/A /**
0N/A * Returns an array containing all installed providers that satisfy the
0N/A * specified* selection criteria, or null if no such providers have been
0N/A * installed. The returned providers are ordered
0N/A * according to their <a href=
0N/A * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
0N/A *
0N/A * <p>The selection criteria are represented by a map.
0N/A * Each map entry represents a selection criterion.
0N/A * A provider is selected iff it satisfies all selection
0N/A * criteria. The key for any entry in such a map must be in one of the
0N/A * following two formats:
0N/A * <ul>
0N/A * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type></i>
0N/A * <p> The cryptographic service name must not contain any dots.
0N/A * <p> The value associated with the key must be an empty string.
0N/A * <p> A provider
0N/A * satisfies this selection criterion iff the provider implements the
0N/A * specified algorithm or type for the specified cryptographic service.
0N/A * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type> &lt;attribute_name></i>
0N/A * <p> The cryptographic service name must not contain any dots. There
0N/A * must be one or more space charaters between the <i>&lt;algorithm_or_type></i>
0N/A * and the <i>&lt;attribute_name></i>.
0N/A * <p> The value associated with the key must be a non-empty string.
0N/A * A provider satisfies this selection criterion iff the
0N/A * provider implements the specified algorithm or type for the specified
0N/A * cryptographic service and its implementation meets the
0N/A * constraint expressed by the specified attribute name/value pair.
0N/A * </ul>
0N/A *
3465N/A * <p> See the <a href=
3465N/A * "../../../technotes/guides/security/StandardNames.html">
3465N/A * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
0N/A * for information about standard cryptographic service names, standard
0N/A * algorithm names and standard attribute names.
0N/A *
0N/A * @param filter the criteria for selecting
0N/A * providers. The filter is case-insensitive.
0N/A *
0N/A * @return all the installed providers that satisfy the selection
0N/A * criteria, or null if no such providers have been installed.
0N/A *
0N/A * @throws InvalidParameterException
0N/A * if the filter is not in the required format
0N/A * @throws NullPointerException if filter is null
0N/A *
0N/A * @see #getProviders(java.lang.String)
0N/A * @since 1.3
0N/A */
0N/A public static Provider[] getProviders(Map<String,String> filter) {
0N/A // Get all installed providers first.
0N/A // Then only return those providers who satisfy the selection criteria.
0N/A Provider[] allProviders = Security.getProviders();
0N/A Set<String> keySet = filter.keySet();
3381N/A LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
0N/A
0N/A // Returns all installed providers
0N/A // if the selection criteria is null.
0N/A if ((keySet == null) || (allProviders == null)) {
0N/A return allProviders;
0N/A }
0N/A
0N/A boolean firstSearch = true;
0N/A
0N/A // For each selection criterion, remove providers
0N/A // which don't satisfy the criterion from the candidate set.
0N/A for (Iterator<String> ite = keySet.iterator(); ite.hasNext(); ) {
0N/A String key = ite.next();
0N/A String value = filter.get(key);
0N/A
0N/A LinkedHashSet<Provider> newCandidates = getAllQualifyingCandidates(key, value,
0N/A allProviders);
0N/A if (firstSearch) {
0N/A candidates = newCandidates;
0N/A firstSearch = false;
0N/A }
0N/A
0N/A if ((newCandidates != null) && !newCandidates.isEmpty()) {
0N/A // For each provider in the candidates set, if it
0N/A // isn't in the newCandidate set, we should remove
0N/A // it from the candidate set.
0N/A for (Iterator<Provider> cansIte = candidates.iterator();
0N/A cansIte.hasNext(); ) {
0N/A Provider prov = cansIte.next();
0N/A if (!newCandidates.contains(prov)) {
0N/A cansIte.remove();
0N/A }
0N/A }
0N/A } else {
0N/A candidates = null;
0N/A break;
0N/A }
0N/A }
0N/A
0N/A if ((candidates == null) || (candidates.isEmpty()))
0N/A return null;
0N/A
0N/A Object[] candidatesArray = candidates.toArray();
0N/A Provider[] result = new Provider[candidatesArray.length];
0N/A
0N/A for (int i = 0; i < result.length; i++) {
0N/A result[i] = (Provider)candidatesArray[i];
0N/A }
0N/A
0N/A return result;
0N/A }
0N/A
0N/A // Map containing cached Spi Class objects of the specified type
3384N/A private static final Map<String, Class> spiMap = new ConcurrentHashMap<>();
0N/A
0N/A /**
0N/A * Return the Class object for the given engine type
0N/A * (e.g. "MessageDigest"). Works for Spis in the java.security package
0N/A * only.
0N/A */
0N/A private static Class getSpiClass(String type) {
0N/A Class clazz = spiMap.get(type);
0N/A if (clazz != null) {
0N/A return clazz;
0N/A }
0N/A try {
0N/A clazz = Class.forName("java.security." + type + "Spi");
0N/A spiMap.put(type, clazz);
0N/A return clazz;
0N/A } catch (ClassNotFoundException e) {
2463N/A throw new AssertionError("Spi class not found", e);
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Returns an array of objects: the first object in the array is
0N/A * an instance of an implementation of the requested algorithm
0N/A * and type, and the second object in the array identifies the provider
0N/A * of that implementation.
0N/A * The <code>provider</code> argument can be null, in which case all
0N/A * configured providers will be searched in order of preference.
0N/A */
0N/A static Object[] getImpl(String algorithm, String type, String provider)
0N/A throws NoSuchAlgorithmException, NoSuchProviderException {
0N/A if (provider == null) {
0N/A return GetInstance.getInstance
0N/A (type, getSpiClass(type), algorithm).toArray();
0N/A } else {
0N/A return GetInstance.getInstance
0N/A (type, getSpiClass(type), algorithm, provider).toArray();
0N/A }
0N/A }
0N/A
0N/A static Object[] getImpl(String algorithm, String type, String provider,
0N/A Object params) throws NoSuchAlgorithmException,
0N/A NoSuchProviderException, InvalidAlgorithmParameterException {
0N/A if (provider == null) {
0N/A return GetInstance.getInstance
0N/A (type, getSpiClass(type), algorithm, params).toArray();
0N/A } else {
0N/A return GetInstance.getInstance
0N/A (type, getSpiClass(type), algorithm, params, provider).toArray();
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Returns an array of objects: the first object in the array is
0N/A * an instance of an implementation of the requested algorithm
0N/A * and type, and the second object in the array identifies the provider
0N/A * of that implementation.
0N/A * The <code>provider</code> argument cannot be null.
0N/A */
0N/A static Object[] getImpl(String algorithm, String type, Provider provider)
0N/A throws NoSuchAlgorithmException {
0N/A return GetInstance.getInstance
0N/A (type, getSpiClass(type), algorithm, provider).toArray();
0N/A }
0N/A
0N/A static Object[] getImpl(String algorithm, String type, Provider provider,
0N/A Object params) throws NoSuchAlgorithmException,
0N/A InvalidAlgorithmParameterException {
0N/A return GetInstance.getInstance
0N/A (type, getSpiClass(type), algorithm, params, provider).toArray();
0N/A }
0N/A
0N/A /**
0N/A * Gets a security property value.
0N/A *
0N/A * <p>First, if there is a security manager, its
0N/A * <code>checkPermission</code> method is called with a
0N/A * <code>java.security.SecurityPermission("getProperty."+key)</code>
0N/A * permission to see if it's ok to retrieve the specified
0N/A * security property value..
0N/A *
0N/A * @param key the key of the property being retrieved.
0N/A *
0N/A * @return the value of the security property corresponding to key.
0N/A *
0N/A * @throws SecurityException
0N/A * if a security manager exists and its <code>{@link
0N/A * java.lang.SecurityManager#checkPermission}</code> method
0N/A * denies
0N/A * access to retrieve the specified security property value
0N/A * @throws NullPointerException is key is null
0N/A *
0N/A * @see #setProperty
0N/A * @see java.security.SecurityPermission
0N/A */
0N/A public static String getProperty(String key) {
0N/A SecurityManager sm = System.getSecurityManager();
0N/A if (sm != null) {
0N/A sm.checkPermission(new SecurityPermission("getProperty."+
0N/A key));
0N/A }
0N/A String name = props.getProperty(key);
0N/A if (name != null)
0N/A name = name.trim(); // could be a class name with trailing ws
0N/A return name;
0N/A }
0N/A
0N/A /**
0N/A * Sets a security property value.
0N/A *
0N/A * <p>First, if there is a security manager, its
0N/A * <code>checkPermission</code> method is called with a
0N/A * <code>java.security.SecurityPermission("setProperty."+key)</code>
0N/A * permission to see if it's ok to set the specified
0N/A * security property value.
0N/A *
0N/A * @param key the name of the property to be set.
0N/A *
0N/A * @param datum the value of the property to be set.
0N/A *
0N/A * @throws SecurityException
0N/A * if a security manager exists and its <code>{@link
0N/A * java.lang.SecurityManager#checkPermission}</code> method
0N/A * denies access to set the specified security property value
0N/A * @throws NullPointerException if key or datum is null
0N/A *
0N/A * @see #getProperty
0N/A * @see java.security.SecurityPermission
0N/A */
0N/A public static void setProperty(String key, String datum) {
0N/A check("setProperty."+key);
0N/A props.put(key, datum);
0N/A invalidateSMCache(key); /* See below. */
0N/A }
0N/A
0N/A /*
0N/A * Implementation detail: If the property we just set in
0N/A * setProperty() was either "package.access" or
0N/A * "package.definition", we need to signal to the SecurityManager
0N/A * class that the value has just changed, and that it should
0N/A * invalidate it's local cache values.
0N/A *
0N/A * Rather than create a new API entry for this function,
0N/A * we use reflection to set a private variable.
0N/A */
0N/A private static void invalidateSMCache(String key) {
0N/A
0N/A final boolean pa = key.equals("package.access");
0N/A final boolean pd = key.equals("package.definition");
0N/A
0N/A if (pa || pd) {
0N/A AccessController.doPrivileged(new PrivilegedAction<Void>() {
0N/A public Void run() {
0N/A try {
0N/A /* Get the class via the bootstrap class loader. */
0N/A Class cl = Class.forName(
0N/A "java.lang.SecurityManager", false, null);
0N/A Field f = null;
0N/A boolean accessible = false;
0N/A
0N/A if (pa) {
0N/A f = cl.getDeclaredField("packageAccessValid");
0N/A accessible = f.isAccessible();
0N/A f.setAccessible(true);
0N/A } else {
0N/A f = cl.getDeclaredField("packageDefinitionValid");
0N/A accessible = f.isAccessible();
0N/A f.setAccessible(true);
0N/A }
0N/A f.setBoolean(f, false);
0N/A f.setAccessible(accessible);
0N/A }
0N/A catch (Exception e1) {
0N/A /* If we couldn't get the class, it hasn't
0N/A * been loaded yet. If there is no such
0N/A * field, we shouldn't try to set it. There
0N/A * shouldn't be a security execption, as we
0N/A * are loaded by boot class loader, and we
0N/A * are inside a doPrivileged() here.
0N/A *
0N/A * NOOP: don't do anything...
0N/A */
0N/A }
0N/A return null;
0N/A } /* run */
0N/A }); /* PrivilegedAction */
0N/A } /* if */
0N/A }
0N/A
0N/A private static void check(String directive) {
0N/A SecurityManager security = System.getSecurityManager();
0N/A if (security != null) {
0N/A security.checkSecurityAccess(directive);
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Returns all providers who satisfy the specified
0N/A * criterion.
0N/A */
0N/A private static LinkedHashSet<Provider> getAllQualifyingCandidates(
0N/A String filterKey,
0N/A String filterValue,
0N/A Provider[] allProviders) {
0N/A String[] filterComponents = getFilterComponents(filterKey,
0N/A filterValue);
0N/A
0N/A // The first component is the service name.
0N/A // The second is the algorithm name.
0N/A // If the third isn't null, that is the attrinute name.
0N/A String serviceName = filterComponents[0];
0N/A String algName = filterComponents[1];
0N/A String attrName = filterComponents[2];
0N/A
0N/A return getProvidersNotUsingCache(serviceName, algName, attrName,
0N/A filterValue, allProviders);
0N/A }
0N/A
0N/A private static LinkedHashSet<Provider> getProvidersNotUsingCache(
0N/A String serviceName,
0N/A String algName,
0N/A String attrName,
0N/A String filterValue,
0N/A Provider[] allProviders) {
3381N/A LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
0N/A for (int i = 0; i < allProviders.length; i++) {
0N/A if (isCriterionSatisfied(allProviders[i], serviceName,
0N/A algName,
0N/A attrName, filterValue)) {
0N/A candidates.add(allProviders[i]);
0N/A }
0N/A }
0N/A return candidates;
0N/A }
0N/A
0N/A /*
0N/A * Returns true if the given provider satisfies
0N/A * the selection criterion key:value.
0N/A */
0N/A private static boolean isCriterionSatisfied(Provider prov,
0N/A String serviceName,
0N/A String algName,
0N/A String attrName,
0N/A String filterValue) {
0N/A String key = serviceName + '.' + algName;
0N/A
0N/A if (attrName != null) {
0N/A key += ' ' + attrName;
0N/A }
0N/A // Check whether the provider has a property
0N/A // whose key is the same as the given key.
0N/A String propValue = getProviderProperty(key, prov);
0N/A
0N/A if (propValue == null) {
0N/A // Check whether we have an alias instead
0N/A // of a standard name in the key.
0N/A String standardName = getProviderProperty("Alg.Alias." +
0N/A serviceName + "." +
0N/A algName,
0N/A prov);
0N/A if (standardName != null) {
0N/A key = serviceName + "." + standardName;
0N/A
0N/A if (attrName != null) {
0N/A key += ' ' + attrName;
0N/A }
0N/A
0N/A propValue = getProviderProperty(key, prov);
0N/A }
0N/A
0N/A if (propValue == null) {
0N/A // The provider doesn't have the given
0N/A // key in its property list.
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A // If the key is in the format of:
0N/A // <crypto_service>.<algorithm_or_type>,
0N/A // there is no need to check the value.
0N/A
0N/A if (attrName == null) {
0N/A return true;
0N/A }
0N/A
0N/A // If we get here, the key must be in the
0N/A // format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
0N/A if (isStandardAttr(attrName)) {
0N/A return isConstraintSatisfied(attrName, filterValue, propValue);
0N/A } else {
0N/A return filterValue.equalsIgnoreCase(propValue);
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Returns true if the attribute is a standard attribute;
0N/A * otherwise, returns false.
0N/A */
0N/A private static boolean isStandardAttr(String attribute) {
0N/A // For now, we just have two standard attributes:
0N/A // KeySize and ImplementedIn.
0N/A if (attribute.equalsIgnoreCase("KeySize"))
0N/A return true;
0N/A
0N/A if (attribute.equalsIgnoreCase("ImplementedIn"))
0N/A return true;
0N/A
0N/A return false;
0N/A }
0N/A
0N/A /*
0N/A * Returns true if the requested attribute value is supported;
0N/A * otherwise, returns false.
0N/A */
0N/A private static boolean isConstraintSatisfied(String attribute,
0N/A String value,
0N/A String prop) {
0N/A // For KeySize, prop is the max key size the
0N/A // provider supports for a specific <crypto_service>.<algorithm>.
0N/A if (attribute.equalsIgnoreCase("KeySize")) {
0N/A int requestedSize = Integer.parseInt(value);
0N/A int maxSize = Integer.parseInt(prop);
0N/A if (requestedSize <= maxSize) {
0N/A return true;
0N/A } else {
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A // For Type, prop is the type of the implementation
0N/A // for a specific <crypto service>.<algorithm>.
0N/A if (attribute.equalsIgnoreCase("ImplementedIn")) {
0N/A return value.equalsIgnoreCase(prop);
0N/A }
0N/A
0N/A return false;
0N/A }
0N/A
0N/A static String[] getFilterComponents(String filterKey, String filterValue) {
0N/A int algIndex = filterKey.indexOf('.');
0N/A
0N/A if (algIndex < 0) {
0N/A // There must be a dot in the filter, and the dot
0N/A // shouldn't be at the beginning of this string.
0N/A throw new InvalidParameterException("Invalid filter");
0N/A }
0N/A
0N/A String serviceName = filterKey.substring(0, algIndex);
0N/A String algName = null;
0N/A String attrName = null;
0N/A
0N/A if (filterValue.length() == 0) {
0N/A // The filterValue is an empty string. So the filterKey
0N/A // should be in the format of <crypto_service>.<algorithm_or_type>.
0N/A algName = filterKey.substring(algIndex + 1).trim();
0N/A if (algName.length() == 0) {
0N/A // There must be a algorithm or type name.
0N/A throw new InvalidParameterException("Invalid filter");
0N/A }
0N/A } else {
0N/A // The filterValue is a non-empty string. So the filterKey must be
0N/A // in the format of
0N/A // <crypto_service>.<algorithm_or_type> <attribute_name>
0N/A int attrIndex = filterKey.indexOf(' ');
0N/A
0N/A if (attrIndex == -1) {
0N/A // There is no attribute name in the filter.
0N/A throw new InvalidParameterException("Invalid filter");
0N/A } else {
0N/A attrName = filterKey.substring(attrIndex + 1).trim();
0N/A if (attrName.length() == 0) {
0N/A // There is no attribute name in the filter.
0N/A throw new InvalidParameterException("Invalid filter");
0N/A }
0N/A }
0N/A
0N/A // There must be an algorithm name in the filter.
0N/A if ((attrIndex < algIndex) ||
0N/A (algIndex == attrIndex - 1)) {
0N/A throw new InvalidParameterException("Invalid filter");
0N/A } else {
0N/A algName = filterKey.substring(algIndex + 1, attrIndex);
0N/A }
0N/A }
0N/A
0N/A String[] result = new String[3];
0N/A result[0] = serviceName;
0N/A result[1] = algName;
0N/A result[2] = attrName;
0N/A
0N/A return result;
0N/A }
0N/A
0N/A /**
0N/A * Returns a Set of Strings containing the names of all available
0N/A * algorithms or types for the specified Java cryptographic service
0N/A * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns
0N/A * an empty Set if there is no provider that supports the
0N/A * specified service or if serviceName is null. For a complete list
0N/A * of Java cryptographic services, please see the
0N/A * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">Java
0N/A * Cryptography Architecture API Specification &amp; Reference</a>.
0N/A * Note: the returned set is immutable.
0N/A *
0N/A * @param serviceName the name of the Java cryptographic
0N/A * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
0N/A * Note: this parameter is case-insensitive.
0N/A *
0N/A * @return a Set of Strings containing the names of all available
0N/A * algorithms or types for the specified Java cryptographic service
0N/A * or an empty set if no provider supports the specified service.
0N/A *
0N/A * @since 1.4
0N/A **/
0N/A public static Set<String> getAlgorithms(String serviceName) {
0N/A
0N/A if ((serviceName == null) || (serviceName.length() == 0) ||
0N/A (serviceName.endsWith("."))) {
0N/A return Collections.EMPTY_SET;
0N/A }
0N/A
3381N/A HashSet<String> result = new HashSet<>();
0N/A Provider[] providers = Security.getProviders();
0N/A
0N/A for (int i = 0; i < providers.length; i++) {
0N/A // Check the keys for each provider.
0N/A for (Enumeration<Object> e = providers[i].keys();
0N/A e.hasMoreElements(); ) {
0N/A String currentKey = ((String)e.nextElement()).toUpperCase();
0N/A if (currentKey.startsWith(serviceName.toUpperCase())) {
0N/A // We should skip the currentKey if it contains a
0N/A // whitespace. The reason is: such an entry in the
0N/A // provider property contains attributes for the
0N/A // implementation of an algorithm. We are only interested
0N/A // in entries which lead to the implementation
0N/A // classes.
0N/A if (currentKey.indexOf(" ") < 0) {
0N/A result.add(currentKey.substring(serviceName.length() + 1));
0N/A }
0N/A }
0N/A }
0N/A }
0N/A return Collections.unmodifiableSet(result);
0N/A }
0N/A}