Save This Page
Home » openjdk-7 » java » security » [javadoc | source]
    1   /*
    2    * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package java.security;
   27   
   28   import java.lang.reflect;
   29   import java.util;
   30   import java.util.concurrent.ConcurrentHashMap;
   31   import java.io;
   32   import java.net.URL;
   33   import sun.security.util.Debug;
   34   import sun.security.util.PropertyExpander;
   35   
   36   import java.security.Provider.Service;
   37   
   38   import sun.security.jca;
   39   
   40   /**
   41    * <p>This class centralizes all security properties and common security
   42    * methods. One of its primary uses is to manage providers.
   43    *
   44    * @author Benjamin Renaud
   45    */
   46   
   47   public final class Security {
   48   
   49       /* Are we debugging? -- for developers */
   50       private static final Debug sdebug =
   51                           Debug.getInstance("properties");
   52   
   53       /* The java.security properties */
   54       private static Properties props;
   55   
   56       // An element in the cache
   57       private static class ProviderProperty {
   58           String className;
   59           Provider provider;
   60       }
   61   
   62       static {
   63           // doPrivileged here because there are multiple
   64           // things in initialize that might require privs.
   65           // (the FileInputStream call and the File.exists call,
   66           // the securityPropFile call, etc)
   67           AccessController.doPrivileged(new PrivilegedAction<Void>() {
   68               public Void run() {
   69                   initialize();
   70                   return null;
   71               }
   72           });
   73       }
   74   
   75       private static void initialize() {
   76           props = new Properties();
   77           boolean loadedProps = false;
   78           boolean overrideAll = false;
   79   
   80           // first load the system properties file
   81           // to determine the value of security.overridePropertiesFile
   82           File propFile = securityPropFile("java.security");
   83           if (propFile.exists()) {
   84               InputStream is = null;
   85               try {
   86                   FileInputStream fis = new FileInputStream(propFile);
   87                   is = new BufferedInputStream(fis);
   88                   props.load(is);
   89                   loadedProps = true;
   90   
   91                   if (sdebug != null) {
   92                       sdebug.println("reading security properties file: " +
   93                                   propFile);
   94                   }
   95               } catch (IOException e) {
   96                   if (sdebug != null) {
   97                       sdebug.println("unable to load security properties from " +
   98                                   propFile);
   99                       e.printStackTrace();
  100                   }
  101               } finally {
  102                   if (is != null) {
  103                       try {
  104                           is.close();
  105                       } catch (IOException ioe) {
  106                           if (sdebug != null) {
  107                               sdebug.println("unable to close input stream");
  108                           }
  109                       }
  110                   }
  111               }
  112           }
  113   
  114           if ("true".equalsIgnoreCase(props.getProperty
  115                   ("security.overridePropertiesFile"))) {
  116   
  117               String extraPropFile = System.getProperty
  118                                           ("java.security.properties");
  119               if (extraPropFile != null && extraPropFile.startsWith("=")) {
  120                   overrideAll = true;
  121                   extraPropFile = extraPropFile.substring(1);
  122               }
  123   
  124               if (overrideAll) {
  125                   props = new Properties();
  126                   if (sdebug != null) {
  127                       sdebug.println
  128                           ("overriding other security properties files!");
  129                   }
  130               }
  131   
  132               // now load the user-specified file so its values
  133               // will win if they conflict with the earlier values
  134               if (extraPropFile != null) {
  135                   BufferedInputStream bis = null;
  136                   try {
  137                       URL propURL;
  138   
  139                       extraPropFile = PropertyExpander.expand(extraPropFile);
  140                       propFile = new File(extraPropFile);
  141                       if (propFile.exists()) {
  142                           propURL = new URL
  143                                   ("file:" + propFile.getCanonicalPath());
  144                       } else {
  145                           propURL = new URL(extraPropFile);
  146                       }
  147                       bis = new BufferedInputStream(propURL.openStream());
  148                       props.load(bis);
  149                       loadedProps = true;
  150   
  151                       if (sdebug != null) {
  152                           sdebug.println("reading security properties file: " +
  153                                           propURL);
  154                           if (overrideAll) {
  155                               sdebug.println
  156                                   ("overriding other security properties files!");
  157                           }
  158                       }
  159                   } catch (Exception e) {
  160                       if (sdebug != null) {
  161                           sdebug.println
  162                                   ("unable to load security properties from " +
  163                                   extraPropFile);
  164                           e.printStackTrace();
  165                       }
  166                   } finally {
  167                       if (bis != null) {
  168                           try {
  169                               bis.close();
  170                           } catch (IOException ioe) {
  171                               if (sdebug != null) {
  172                                   sdebug.println("unable to close input stream");
  173                               }
  174                           }
  175                       }
  176                   }
  177               }
  178           }
  179   
  180           if (!loadedProps) {
  181               initializeStatic();
  182               if (sdebug != null) {
  183                   sdebug.println("unable to load security properties " +
  184                           "-- using defaults");
  185               }
  186           }
  187   
  188       }
  189   
  190       /*
  191        * Initialize to default values, if <java.home>/lib/java.security
  192        * is not found.
  193        */
  194       private static void initializeStatic() {
  195           props.put("security.provider.1", "sun.security.provider.Sun");
  196           props.put("security.provider.2", "sun.security.rsa.SunRsaSign");
  197           props.put("security.provider.3", "com.sun.net.ssl.internal.ssl.Provider");
  198           props.put("security.provider.4", "com.sun.crypto.provider.SunJCE");
  199           props.put("security.provider.5", "sun.security.jgss.SunProvider");
  200           props.put("security.provider.6", "com.sun.security.sasl.Provider");
  201       }
  202   
  203       /**
  204        * Don't let anyone instantiate this.
  205        */
  206       private Security() {
  207       }
  208   
  209       private static File securityPropFile(String filename) {
  210           // maybe check for a system property which will specify where to
  211           // look. Someday.
  212           String sep = File.separator;
  213           return new File(System.getProperty("java.home") + sep + "lib" + sep +
  214                           "security" + sep + filename);
  215       }
  216   
  217       /**
  218        * Looks up providers, and returns the property (and its associated
  219        * provider) mapping the key, if any.
  220        * The order in which the providers are looked up is the
  221        * provider-preference order, as specificed in the security
  222        * properties file.
  223        */
  224       private static ProviderProperty getProviderProperty(String key) {
  225           ProviderProperty entry = null;
  226   
  227           List<Provider> providers = Providers.getProviderList().providers();
  228           for (int i = 0; i < providers.size(); i++) {
  229   
  230               String matchKey = null;
  231               Provider prov = providers.get(i);
  232               String prop = prov.getProperty(key);
  233   
  234               if (prop == null) {
  235                   // Is there a match if we do a case-insensitive property name
  236                   // comparison? Let's try ...
  237                   for (Enumeration<Object> e = prov.keys();
  238                                   e.hasMoreElements() && prop == null; ) {
  239                       matchKey = (String)e.nextElement();
  240                       if (key.equalsIgnoreCase(matchKey)) {
  241                           prop = prov.getProperty(matchKey);
  242                           break;
  243                       }
  244                   }
  245               }
  246   
  247               if (prop != null) {
  248                   ProviderProperty newEntry = new ProviderProperty();
  249                   newEntry.className = prop;
  250                   newEntry.provider = prov;
  251                   return newEntry;
  252               }
  253           }
  254   
  255           return entry;
  256       }
  257   
  258       /**
  259        * Returns the property (if any) mapping the key for the given provider.
  260        */
  261       private static String getProviderProperty(String key, Provider provider) {
  262           String prop = provider.getProperty(key);
  263           if (prop == null) {
  264               // Is there a match if we do a case-insensitive property name
  265               // comparison? Let's try ...
  266               for (Enumeration<Object> e = provider.keys();
  267                                   e.hasMoreElements() && prop == null; ) {
  268                   String matchKey = (String)e.nextElement();
  269                   if (key.equalsIgnoreCase(matchKey)) {
  270                       prop = provider.getProperty(matchKey);
  271                       break;
  272                   }
  273               }
  274           }
  275           return prop;
  276       }
  277   
  278       /**
  279        * Gets a specified property for an algorithm. The algorithm name
  280        * should be a standard name. See the <a href=
  281        * "{@docRoot}/../technotes/guides/security/StandardNames.html">
  282        * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
  283        * for information about standard algorithm names.
  284        *
  285        * One possible use is by specialized algorithm parsers, which may map
  286        * classes to algorithms which they understand (much like Key parsers
  287        * do).
  288        *
  289        * @param algName the algorithm name.
  290        *
  291        * @param propName the name of the property to get.
  292        *
  293        * @return the value of the specified property.
  294        *
  295        * @deprecated This method used to return the value of a proprietary
  296        * property in the master file of the "SUN" Cryptographic Service
  297        * Provider in order to determine how to parse algorithm-specific
  298        * parameters. Use the new provider-based and algorithm-independent
  299        * <code>AlgorithmParameters</code> and <code>KeyFactory</code> engine
  300        * classes (introduced in the J2SE version 1.2 platform) instead.
  301        */
  302       @Deprecated
  303       public static String getAlgorithmProperty(String algName,
  304                                                 String propName) {
  305           ProviderProperty entry = getProviderProperty("Alg." + propName
  306                                                        + "." + algName);
  307           if (entry != null) {
  308               return entry.className;
  309           } else {
  310               return null;
  311           }
  312       }
  313   
  314       /**
  315        * Adds a new provider, at a specified position. The position is
  316        * the preference order in which providers are searched for
  317        * requested algorithms.  The position is 1-based, that is,
  318        * 1 is most preferred, followed by 2, and so on.
  319        *
  320        * <p>If the given provider is installed at the requested position,
  321        * the provider that used to be at that position, and all providers
  322        * with a position greater than <code>position</code>, are shifted up
  323        * one position (towards the end of the list of installed providers).
  324        *
  325        * <p>A provider cannot be added if it is already installed.
  326        *
  327        * <p>First, if there is a security manager, its
  328        * <code>checkSecurityAccess</code>
  329        * method is called with the string
  330        * <code>"insertProvider."+provider.getName()</code>
  331        * to see if it's ok to add a new provider.
  332        * If the default implementation of <code>checkSecurityAccess</code>
  333        * is used (i.e., that method is not overriden), then this will result in
  334        * a call to the security manager's <code>checkPermission</code> method
  335        * with a
  336        * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  337        * permission.
  338        *
  339        * @param provider the provider to be added.
  340        *
  341        * @param position the preference position that the caller would
  342        * like for this provider.
  343        *
  344        * @return the actual preference position in which the provider was
  345        * added, or -1 if the provider was not added because it is
  346        * already installed.
  347        *
  348        * @throws  NullPointerException if provider is null
  349        * @throws  SecurityException
  350        *          if a security manager exists and its <code>{@link
  351        *          java.lang.SecurityManager#checkSecurityAccess}</code> method
  352        *          denies access to add a new provider
  353        *
  354        * @see #getProvider
  355        * @see #removeProvider
  356        * @see java.security.SecurityPermission
  357        */
  358       public static synchronized int insertProviderAt(Provider provider,
  359               int position) {
  360           String providerName = provider.getName();
  361           check("insertProvider." + providerName);
  362           ProviderList list = Providers.getFullProviderList();
  363           ProviderList newList = ProviderList.insertAt(list, provider, position - 1);
  364           if (list == newList) {
  365               return -1;
  366           }
  367           Providers.setProviderList(newList);
  368           return newList.getIndex(providerName) + 1;
  369       }
  370   
  371       /**
  372        * Adds a provider to the next position available.
  373        *
  374        * <p>First, if there is a security manager, its
  375        * <code>checkSecurityAccess</code>
  376        * method is called with the string
  377        * <code>"insertProvider."+provider.getName()</code>
  378        * to see if it's ok to add a new provider.
  379        * If the default implementation of <code>checkSecurityAccess</code>
  380        * is used (i.e., that method is not overriden), then this will result in
  381        * a call to the security manager's <code>checkPermission</code> method
  382        * with a
  383        * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  384        * permission.
  385        *
  386        * @param provider the provider to be added.
  387        *
  388        * @return the preference position in which the provider was
  389        * added, or -1 if the provider was not added because it is
  390        * already installed.
  391        *
  392        * @throws  NullPointerException if provider is null
  393        * @throws  SecurityException
  394        *          if a security manager exists and its <code>{@link
  395        *          java.lang.SecurityManager#checkSecurityAccess}</code> method
  396        *          denies access to add a new provider
  397        *
  398        * @see #getProvider
  399        * @see #removeProvider
  400        * @see java.security.SecurityPermission
  401        */
  402       public static int addProvider(Provider provider) {
  403           /*
  404            * We can't assign a position here because the statically
  405            * registered providers may not have been installed yet.
  406            * insertProviderAt() will fix that value after it has
  407            * loaded the static providers.
  408            */
  409           return insertProviderAt(provider, 0);
  410       }
  411   
  412       /**
  413        * Removes the provider with the specified name.
  414        *
  415        * <p>When the specified provider is removed, all providers located
  416        * at a position greater than where the specified provider was are shifted
  417        * down one position (towards the head of the list of installed
  418        * providers).
  419        *
  420        * <p>This method returns silently if the provider is not installed or
  421        * if name is null.
  422        *
  423        * <p>First, if there is a security manager, its
  424        * <code>checkSecurityAccess</code>
  425        * method is called with the string <code>"removeProvider."+name</code>
  426        * to see if it's ok to remove the provider.
  427        * If the default implementation of <code>checkSecurityAccess</code>
  428        * is used (i.e., that method is not overriden), then this will result in
  429        * a call to the security manager's <code>checkPermission</code> method
  430        * with a <code>SecurityPermission("removeProvider."+name)</code>
  431        * permission.
  432        *
  433        * @param name the name of the provider to remove.
  434        *
  435        * @throws  SecurityException
  436        *          if a security manager exists and its <code>{@link
  437        *          java.lang.SecurityManager#checkSecurityAccess}</code> method
  438        *          denies
  439        *          access to remove the provider
  440        *
  441        * @see #getProvider
  442        * @see #addProvider
  443        */
  444       public static synchronized void removeProvider(String name) {
  445           check("removeProvider." + name);
  446           ProviderList list = Providers.getFullProviderList();
  447           ProviderList newList = ProviderList.remove(list, name);
  448           Providers.setProviderList(newList);
  449       }
  450   
  451       /**
  452        * Returns an array containing all the installed providers. The order of
  453        * the providers in the array is their preference order.
  454        *
  455        * @return an array of all the installed providers.
  456        */
  457       public static Provider[] getProviders() {
  458           return Providers.getFullProviderList().toArray();
  459       }
  460   
  461       /**
  462        * Returns the provider installed with the specified name, if
  463        * any. Returns null if no provider with the specified name is
  464        * installed or if name is null.
  465        *
  466        * @param name the name of the provider to get.
  467        *
  468        * @return the provider of the specified name.
  469        *
  470        * @see #removeProvider
  471        * @see #addProvider
  472        */
  473       public static Provider getProvider(String name) {
  474           return Providers.getProviderList().getProvider(name);
  475       }
  476   
  477       /**
  478        * Returns an array containing all installed providers that satisfy the
  479        * specified selection criterion, or null if no such providers have been
  480        * installed. The returned providers are ordered
  481        * according to their <a href=
  482        * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
  483        *
  484        * <p> A cryptographic service is always associated with a particular
  485        * algorithm or type. For example, a digital signature service is
  486        * always associated with a particular algorithm (e.g., DSA),
  487        * and a CertificateFactory service is always associated with
  488        * a particular certificate type (e.g., X.509).
  489        *
  490        * <p>The selection criterion must be specified in one of the following two
  491        * formats:
  492        * <ul>
  493        * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type></i> <p> The
  494        * cryptographic service name must not contain any dots.
  495        * <p> A
  496        * provider satisfies the specified selection criterion iff the provider
  497        * implements the
  498        * specified algorithm or type for the specified cryptographic service.
  499        * <p> For example, "CertificateFactory.X.509"
  500        * would be satisfied by any provider that supplied
  501        * a CertificateFactory implementation for X.509 certificates.
  502        * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type>
  503        * &lt;attribute_name>:&lt attribute_value></i>
  504        * <p> The cryptographic service name must not contain any dots. There
  505        * must be one or more space charaters between the
  506        * <i>&lt;algorithm_or_type></i> and the <i>&lt;attribute_name></i>.
  507        *  <p> A provider satisfies this selection criterion iff the
  508        * provider implements the specified algorithm or type for the specified
  509        * cryptographic service and its implementation meets the
  510        * constraint expressed by the specified attribute name/value pair.
  511        * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
  512        * satisfied by any provider that implemented
  513        * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
  514        *
  515        * </ul>
  516        *
  517        * <p> See the <a href=
  518        * "{@docRoot}/../technotes/guides/security/StandardNames.html">
  519        * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
  520        * for information about standard cryptographic service names, standard
  521        * algorithm names and standard attribute names.
  522        *
  523        * @param filter the criterion for selecting
  524        * providers. The filter is case-insensitive.
  525        *
  526        * @return all the installed providers that satisfy the selection
  527        * criterion, or null if no such providers have been installed.
  528        *
  529        * @throws InvalidParameterException
  530        *         if the filter is not in the required format
  531        * @throws NullPointerException if filter is null
  532        *
  533        * @see #getProviders(java.util.Map)
  534        * @since 1.3
  535        */
  536       public static Provider[] getProviders(String filter) {
  537           String key = null;
  538           String value = null;
  539           int index = filter.indexOf(':');
  540   
  541           if (index == -1) {
  542               key = filter;
  543               value = "";
  544           } else {
  545               key = filter.substring(0, index);
  546               value = filter.substring(index + 1);
  547           }
  548   
  549           Hashtable<String, String> hashtableFilter = new Hashtable<>(1);
  550           hashtableFilter.put(key, value);
  551   
  552           return (getProviders(hashtableFilter));
  553       }
  554   
  555       /**
  556        * Returns an array containing all installed providers that satisfy the
  557        * specified* selection criteria, or null if no such providers have been
  558        * installed. The returned providers are ordered
  559        * according to their <a href=
  560        * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
  561        *
  562        * <p>The selection criteria are represented by a map.
  563        * Each map entry represents a selection criterion.
  564        * A provider is selected iff it satisfies all selection
  565        * criteria. The key for any entry in such a map must be in one of the
  566        * following two formats:
  567        * <ul>
  568        * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type></i>
  569        * <p> The cryptographic service name must not contain any dots.
  570        * <p> The value associated with the key must be an empty string.
  571        * <p> A provider
  572        * satisfies this selection criterion iff the provider implements the
  573        * specified algorithm or type for the specified cryptographic service.
  574        * <li>  <i>&lt;crypto_service>.&lt;algorithm_or_type> &lt;attribute_name></i>
  575        * <p> The cryptographic service name must not contain any dots. There
  576        * must be one or more space charaters between the <i>&lt;algorithm_or_type></i>
  577        * and the <i>&lt;attribute_name></i>.
  578        * <p> The value associated with the key must be a non-empty string.
  579        * A provider satisfies this selection criterion iff the
  580        * provider implements the specified algorithm or type for the specified
  581        * cryptographic service and its implementation meets the
  582        * constraint expressed by the specified attribute name/value pair.
  583        * </ul>
  584        *
  585        * <p> See the <a href=
  586        * "../../../technotes/guides/security/StandardNames.html">
  587        * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
  588        * for information about standard cryptographic service names, standard
  589        * algorithm names and standard attribute names.
  590        *
  591        * @param filter the criteria for selecting
  592        * providers. The filter is case-insensitive.
  593        *
  594        * @return all the installed providers that satisfy the selection
  595        * criteria, or null if no such providers have been installed.
  596        *
  597        * @throws InvalidParameterException
  598        *         if the filter is not in the required format
  599        * @throws NullPointerException if filter is null
  600        *
  601        * @see #getProviders(java.lang.String)
  602        * @since 1.3
  603        */
  604       public static Provider[] getProviders(Map<String,String> filter) {
  605           // Get all installed providers first.
  606           // Then only return those providers who satisfy the selection criteria.
  607           Provider[] allProviders = Security.getProviders();
  608           Set<String> keySet = filter.keySet();
  609           LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
  610   
  611           // Returns all installed providers
  612           // if the selection criteria is null.
  613           if ((keySet == null) || (allProviders == null)) {
  614               return allProviders;
  615           }
  616   
  617           boolean firstSearch = true;
  618   
  619           // For each selection criterion, remove providers
  620           // which don't satisfy the criterion from the candidate set.
  621           for (Iterator<String> ite = keySet.iterator(); ite.hasNext(); ) {
  622               String key = ite.next();
  623               String value = filter.get(key);
  624   
  625               LinkedHashSet<Provider> newCandidates = getAllQualifyingCandidates(key, value,
  626                                                                  allProviders);
  627               if (firstSearch) {
  628                   candidates = newCandidates;
  629                   firstSearch = false;
  630               }
  631   
  632               if ((newCandidates != null) && !newCandidates.isEmpty()) {
  633                   // For each provider in the candidates set, if it
  634                   // isn't in the newCandidate set, we should remove
  635                   // it from the candidate set.
  636                   for (Iterator<Provider> cansIte = candidates.iterator();
  637                        cansIte.hasNext(); ) {
  638                       Provider prov = cansIte.next();
  639                       if (!newCandidates.contains(prov)) {
  640                           cansIte.remove();
  641                       }
  642                   }
  643               } else {
  644                   candidates = null;
  645                   break;
  646               }
  647           }
  648   
  649           if ((candidates == null) || (candidates.isEmpty()))
  650               return null;
  651   
  652           Object[] candidatesArray = candidates.toArray();
  653           Provider[] result = new Provider[candidatesArray.length];
  654   
  655           for (int i = 0; i < result.length; i++) {
  656               result[i] = (Provider)candidatesArray[i];
  657           }
  658   
  659           return result;
  660       }
  661   
  662       // Map containing cached Spi Class objects of the specified type
  663       private static final Map<String, Class> spiMap = new ConcurrentHashMap<>();
  664   
  665       /**
  666        * Return the Class object for the given engine type
  667        * (e.g. "MessageDigest"). Works for Spis in the java.security package
  668        * only.
  669        */
  670       private static Class getSpiClass(String type) {
  671           Class clazz = spiMap.get(type);
  672           if (clazz != null) {
  673               return clazz;
  674           }
  675           try {
  676               clazz = Class.forName("java.security." + type + "Spi");
  677               spiMap.put(type, clazz);
  678               return clazz;
  679           } catch (ClassNotFoundException e) {
  680               throw new AssertionError("Spi class not found", e);
  681           }
  682       }
  683   
  684       /*
  685        * Returns an array of objects: the first object in the array is
  686        * an instance of an implementation of the requested algorithm
  687        * and type, and the second object in the array identifies the provider
  688        * of that implementation.
  689        * The <code>provider</code> argument can be null, in which case all
  690        * configured providers will be searched in order of preference.
  691        */
  692       static Object[] getImpl(String algorithm, String type, String provider)
  693               throws NoSuchAlgorithmException, NoSuchProviderException {
  694           if (provider == null) {
  695               return GetInstance.getInstance
  696                   (type, getSpiClass(type), algorithm).toArray();
  697           } else {
  698               return GetInstance.getInstance
  699                   (type, getSpiClass(type), algorithm, provider).toArray();
  700           }
  701       }
  702   
  703       static Object[] getImpl(String algorithm, String type, String provider,
  704               Object params) throws NoSuchAlgorithmException,
  705               NoSuchProviderException, InvalidAlgorithmParameterException {
  706           if (provider == null) {
  707               return GetInstance.getInstance
  708                   (type, getSpiClass(type), algorithm, params).toArray();
  709           } else {
  710               return GetInstance.getInstance
  711                   (type, getSpiClass(type), algorithm, params, provider).toArray();
  712           }
  713       }
  714   
  715       /*
  716        * Returns an array of objects: the first object in the array is
  717        * an instance of an implementation of the requested algorithm
  718        * and type, and the second object in the array identifies the provider
  719        * of that implementation.
  720        * The <code>provider</code> argument cannot be null.
  721        */
  722       static Object[] getImpl(String algorithm, String type, Provider provider)
  723               throws NoSuchAlgorithmException {
  724           return GetInstance.getInstance
  725               (type, getSpiClass(type), algorithm, provider).toArray();
  726       }
  727   
  728       static Object[] getImpl(String algorithm, String type, Provider provider,
  729               Object params) throws NoSuchAlgorithmException,
  730               InvalidAlgorithmParameterException {
  731           return GetInstance.getInstance
  732               (type, getSpiClass(type), algorithm, params, provider).toArray();
  733       }
  734   
  735       /**
  736        * Gets a security property value.
  737        *
  738        * <p>First, if there is a security manager, its
  739        * <code>checkPermission</code>  method is called with a
  740        * <code>java.security.SecurityPermission("getProperty."+key)</code>
  741        * permission to see if it's ok to retrieve the specified
  742        * security property value..
  743        *
  744        * @param key the key of the property being retrieved.
  745        *
  746        * @return the value of the security property corresponding to key.
  747        *
  748        * @throws  SecurityException
  749        *          if a security manager exists and its <code>{@link
  750        *          java.lang.SecurityManager#checkPermission}</code> method
  751        *          denies
  752        *          access to retrieve the specified security property value
  753        * @throws  NullPointerException is key is null
  754        *
  755        * @see #setProperty
  756        * @see java.security.SecurityPermission
  757        */
  758       public static String getProperty(String key) {
  759           SecurityManager sm = System.getSecurityManager();
  760           if (sm != null) {
  761               sm.checkPermission(new SecurityPermission("getProperty."+
  762                                                         key));
  763           }
  764           String name = props.getProperty(key);
  765           if (name != null)
  766               name = name.trim(); // could be a class name with trailing ws
  767           return name;
  768       }
  769   
  770       /**
  771        * Sets a security property value.
  772        *
  773        * <p>First, if there is a security manager, its
  774        * <code>checkPermission</code> method is called with a
  775        * <code>java.security.SecurityPermission("setProperty."+key)</code>
  776        * permission to see if it's ok to set the specified
  777        * security property value.
  778        *
  779        * @param key the name of the property to be set.
  780        *
  781        * @param datum the value of the property to be set.
  782        *
  783        * @throws  SecurityException
  784        *          if a security manager exists and its <code>{@link
  785        *          java.lang.SecurityManager#checkPermission}</code> method
  786        *          denies access to set the specified security property value
  787        * @throws  NullPointerException if key or datum is null
  788        *
  789        * @see #getProperty
  790        * @see java.security.SecurityPermission
  791        */
  792       public static void setProperty(String key, String datum) {
  793           check("setProperty."+key);
  794           props.put(key, datum);
  795           invalidateSMCache(key);  /* See below. */
  796       }
  797   
  798       /*
  799        * Implementation detail:  If the property we just set in
  800        * setProperty() was either "package.access" or
  801        * "package.definition", we need to signal to the SecurityManager
  802        * class that the value has just changed, and that it should
  803        * invalidate it's local cache values.
  804        *
  805        * Rather than create a new API entry for this function,
  806        * we use reflection to set a private variable.
  807        */
  808       private static void invalidateSMCache(String key) {
  809   
  810           final boolean pa = key.equals("package.access");
  811           final boolean pd = key.equals("package.definition");
  812   
  813           if (pa || pd) {
  814               AccessController.doPrivileged(new PrivilegedAction<Void>() {
  815                   public Void run() {
  816                       try {
  817                           /* Get the class via the bootstrap class loader. */
  818                           Class cl = Class.forName(
  819                               "java.lang.SecurityManager", false, null);
  820                           Field f = null;
  821                           boolean accessible = false;
  822   
  823                           if (pa) {
  824                               f = cl.getDeclaredField("packageAccessValid");
  825                               accessible = f.isAccessible();
  826                               f.setAccessible(true);
  827                           } else {
  828                               f = cl.getDeclaredField("packageDefinitionValid");
  829                               accessible = f.isAccessible();
  830                               f.setAccessible(true);
  831                           }
  832                           f.setBoolean(f, false);
  833                           f.setAccessible(accessible);
  834                       }
  835                       catch (Exception e1) {
  836                           /* If we couldn't get the class, it hasn't
  837                            * been loaded yet.  If there is no such
  838                            * field, we shouldn't try to set it.  There
  839                            * shouldn't be a security execption, as we
  840                            * are loaded by boot class loader, and we
  841                            * are inside a doPrivileged() here.
  842                            *
  843                            * NOOP: don't do anything...
  844                            */
  845                       }
  846                       return null;
  847                   }  /* run */
  848               });  /* PrivilegedAction */
  849           }  /* if */
  850       }
  851   
  852       private static void check(String directive) {
  853           SecurityManager security = System.getSecurityManager();
  854           if (security != null) {
  855               security.checkSecurityAccess(directive);
  856           }
  857       }
  858   
  859       /*
  860       * Returns all providers who satisfy the specified
  861       * criterion.
  862       */
  863       private static LinkedHashSet<Provider> getAllQualifyingCandidates(
  864                                                   String filterKey,
  865                                                   String filterValue,
  866                                                   Provider[] allProviders) {
  867           String[] filterComponents = getFilterComponents(filterKey,
  868                                                           filterValue);
  869   
  870           // The first component is the service name.
  871           // The second is the algorithm name.
  872           // If the third isn't null, that is the attrinute name.
  873           String serviceName = filterComponents[0];
  874           String algName = filterComponents[1];
  875           String attrName = filterComponents[2];
  876   
  877           return getProvidersNotUsingCache(serviceName, algName, attrName,
  878                                            filterValue, allProviders);
  879       }
  880   
  881       private static LinkedHashSet<Provider> getProvidersNotUsingCache(
  882                                                   String serviceName,
  883                                                   String algName,
  884                                                   String attrName,
  885                                                   String filterValue,
  886                                                   Provider[] allProviders) {
  887           LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
  888           for (int i = 0; i < allProviders.length; i++) {
  889               if (isCriterionSatisfied(allProviders[i], serviceName,
  890                                        algName,
  891                                        attrName, filterValue)) {
  892                   candidates.add(allProviders[i]);
  893               }
  894           }
  895           return candidates;
  896       }
  897   
  898       /*
  899        * Returns true if the given provider satisfies
  900        * the selection criterion key:value.
  901        */
  902       private static boolean isCriterionSatisfied(Provider prov,
  903                                                   String serviceName,
  904                                                   String algName,
  905                                                   String attrName,
  906                                                   String filterValue) {
  907           String key = serviceName + '.' + algName;
  908   
  909           if (attrName != null) {
  910               key += ' ' + attrName;
  911           }
  912           // Check whether the provider has a property
  913           // whose key is the same as the given key.
  914           String propValue = getProviderProperty(key, prov);
  915   
  916           if (propValue == null) {
  917               // Check whether we have an alias instead
  918               // of a standard name in the key.
  919               String standardName = getProviderProperty("Alg.Alias." +
  920                                                         serviceName + "." +
  921                                                         algName,
  922                                                         prov);
  923               if (standardName != null) {
  924                   key = serviceName + "." + standardName;
  925   
  926                   if (attrName != null) {
  927                       key += ' ' + attrName;
  928                   }
  929   
  930                   propValue = getProviderProperty(key, prov);
  931               }
  932   
  933               if (propValue == null) {
  934                   // The provider doesn't have the given
  935                   // key in its property list.
  936                   return false;
  937               }
  938           }
  939   
  940           // If the key is in the format of:
  941           // <crypto_service>.<algorithm_or_type>,
  942           // there is no need to check the value.
  943   
  944           if (attrName == null) {
  945               return true;
  946           }
  947   
  948           // If we get here, the key must be in the
  949           // format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
  950           if (isStandardAttr(attrName)) {
  951               return isConstraintSatisfied(attrName, filterValue, propValue);
  952           } else {
  953               return filterValue.equalsIgnoreCase(propValue);
  954           }
  955       }
  956   
  957       /*
  958        * Returns true if the attribute is a standard attribute;
  959        * otherwise, returns false.
  960        */
  961       private static boolean isStandardAttr(String attribute) {
  962           // For now, we just have two standard attributes:
  963           // KeySize and ImplementedIn.
  964           if (attribute.equalsIgnoreCase("KeySize"))
  965               return true;
  966   
  967           if (attribute.equalsIgnoreCase("ImplementedIn"))
  968               return true;
  969   
  970           return false;
  971       }
  972   
  973       /*
  974        * Returns true if the requested attribute value is supported;
  975        * otherwise, returns false.
  976        */
  977       private static boolean isConstraintSatisfied(String attribute,
  978                                                    String value,
  979                                                    String prop) {
  980           // For KeySize, prop is the max key size the
  981           // provider supports for a specific <crypto_service>.<algorithm>.
  982           if (attribute.equalsIgnoreCase("KeySize")) {
  983               int requestedSize = Integer.parseInt(value);
  984               int maxSize = Integer.parseInt(prop);
  985               if (requestedSize <= maxSize) {
  986                   return true;
  987               } else {
  988                   return false;
  989               }
  990           }
  991   
  992           // For Type, prop is the type of the implementation
  993           // for a specific <crypto service>.<algorithm>.
  994           if (attribute.equalsIgnoreCase("ImplementedIn")) {
  995               return value.equalsIgnoreCase(prop);
  996           }
  997   
  998           return false;
  999       }
 1000   
 1001       static String[] getFilterComponents(String filterKey, String filterValue) {
 1002           int algIndex = filterKey.indexOf('.');
 1003   
 1004           if (algIndex < 0) {
 1005               // There must be a dot in the filter, and the dot
 1006               // shouldn't be at the beginning of this string.
 1007               throw new InvalidParameterException("Invalid filter");
 1008           }
 1009   
 1010           String serviceName = filterKey.substring(0, algIndex);
 1011           String algName = null;
 1012           String attrName = null;
 1013   
 1014           if (filterValue.length() == 0) {
 1015               // The filterValue is an empty string. So the filterKey
 1016               // should be in the format of <crypto_service>.<algorithm_or_type>.
 1017               algName = filterKey.substring(algIndex + 1).trim();
 1018               if (algName.length() == 0) {
 1019                   // There must be a algorithm or type name.
 1020                   throw new InvalidParameterException("Invalid filter");
 1021               }
 1022           } else {
 1023               // The filterValue is a non-empty string. So the filterKey must be
 1024               // in the format of
 1025               // <crypto_service>.<algorithm_or_type> <attribute_name>
 1026               int attrIndex = filterKey.indexOf(' ');
 1027   
 1028               if (attrIndex == -1) {
 1029                   // There is no attribute name in the filter.
 1030                   throw new InvalidParameterException("Invalid filter");
 1031               } else {
 1032                   attrName = filterKey.substring(attrIndex + 1).trim();
 1033                   if (attrName.length() == 0) {
 1034                       // There is no attribute name in the filter.
 1035                       throw new InvalidParameterException("Invalid filter");
 1036                   }
 1037               }
 1038   
 1039               // There must be an algorithm name in the filter.
 1040               if ((attrIndex < algIndex) ||
 1041                   (algIndex == attrIndex - 1)) {
 1042                   throw new InvalidParameterException("Invalid filter");
 1043               } else {
 1044                   algName = filterKey.substring(algIndex + 1, attrIndex);
 1045               }
 1046           }
 1047   
 1048           String[] result = new String[3];
 1049           result[0] = serviceName;
 1050           result[1] = algName;
 1051           result[2] = attrName;
 1052   
 1053           return result;
 1054       }
 1055   
 1056       /**
 1057        * Returns a Set of Strings containing the names of all available
 1058        * algorithms or types for the specified Java cryptographic service
 1059        * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns
 1060        * an empty Set if there is no provider that supports the
 1061        * specified service or if serviceName is null. For a complete list
 1062        * of Java cryptographic services, please see the
 1063        * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">Java
 1064        * Cryptography Architecture API Specification &amp; Reference</a>.
 1065        * Note: the returned set is immutable.
 1066        *
 1067        * @param serviceName the name of the Java cryptographic
 1068        * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
 1069        * Note: this parameter is case-insensitive.
 1070        *
 1071        * @return a Set of Strings containing the names of all available
 1072        * algorithms or types for the specified Java cryptographic service
 1073        * or an empty set if no provider supports the specified service.
 1074        *
 1075        * @since 1.4
 1076        **/
 1077       public static Set<String> getAlgorithms(String serviceName) {
 1078   
 1079           if ((serviceName == null) || (serviceName.length() == 0) ||
 1080               (serviceName.endsWith("."))) {
 1081               return Collections.EMPTY_SET;
 1082           }
 1083   
 1084           HashSet<String> result = new HashSet<>();
 1085           Provider[] providers = Security.getProviders();
 1086   
 1087           for (int i = 0; i < providers.length; i++) {
 1088               // Check the keys for each provider.
 1089               for (Enumeration<Object> e = providers[i].keys();
 1090                                                   e.hasMoreElements(); ) {
 1091                   String currentKey = ((String)e.nextElement()).toUpperCase();
 1092                   if (currentKey.startsWith(serviceName.toUpperCase())) {
 1093                       // We should skip the currentKey if it contains a
 1094                       // whitespace. The reason is: such an entry in the
 1095                       // provider property contains attributes for the
 1096                       // implementation of an algorithm. We are only interested
 1097                       // in entries which lead to the implementation
 1098                       // classes.
 1099                       if (currentKey.indexOf(" ") < 0) {
 1100                           result.add(currentKey.substring(serviceName.length() + 1));
 1101                       }
 1102                   }
 1103               }
 1104           }
 1105           return Collections.unmodifiableSet(result);
 1106       }
 1107   }

Save This Page
Home » openjdk-7 » java » security » [javadoc | source]