Save This Page
Home » openjdk-7 » java » security » [javadoc | source]
    1   /*
    2    * Copyright 1996-2006 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any 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 Appendix A in the <a href=
  281        * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  282        * Java Cryptography Architecture API Specification &amp; Reference </a>
  283        * for information about standard algorithm names.
  284        * One possible use is by specialized algorithm parsers, which may map
  285        * classes to algorithms which they understand (much like Key parsers
  286        * do).
  287        *
  288        * @param algName the algorithm name.
  289        *
  290        * @param propName the name of the property to get.
  291        *
  292        * @return the value of the specified property.
  293        *
  294        * @deprecated This method used to return the value of a proprietary
  295        * property in the master file of the "SUN" Cryptographic Service
  296        * Provider in order to determine how to parse algorithm-specific
  297        * parameters. Use the new provider-based and algorithm-independent
  298        * <code>AlgorithmParameters</code> and <code>KeyFactory</code> engine
  299        * classes (introduced in the J2SE version 1.2 platform) instead.
  300        */
  301       @Deprecated
  302       public static String getAlgorithmProperty(String algName,
  303                                                 String propName) {
  304           ProviderProperty entry = getProviderProperty("Alg." + propName
  305                                                        + "." + algName);
  306           if (entry != null) {
  307               return entry.className;
  308           } else {
  309               return null;
  310           }
  311       }
  312   
  313       /**
  314        * Adds a new provider, at a specified position. The position is
  315        * the preference order in which providers are searched for
  316        * requested algorithms.  The position is 1-based, that is,
  317        * 1 is most preferred, followed by 2, and so on.
  318        *
  319        * <p>If the given provider is installed at the requested position,
  320        * the provider that used to be at that position, and all providers
  321        * with a position greater than <code>position</code>, are shifted up
  322        * one position (towards the end of the list of installed providers).
  323        *
  324        * <p>A provider cannot be added if it is already installed.
  325        *
  326        * <p>First, if there is a security manager, its
  327        * <code>checkSecurityAccess</code>
  328        * method is called with the string
  329        * <code>"insertProvider."+provider.getName()</code>
  330        * to see if it's ok to add a new provider.
  331        * If the default implementation of <code>checkSecurityAccess</code>
  332        * is used (i.e., that method is not overriden), then this will result in
  333        * a call to the security manager's <code>checkPermission</code> method
  334        * with a
  335        * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  336        * permission.
  337        *
  338        * @param provider the provider to be added.
  339        *
  340        * @param position the preference position that the caller would
  341        * like for this provider.
  342        *
  343        * @return the actual preference position in which the provider was
  344        * added, or -1 if the provider was not added because it is
  345        * already installed.
  346        *
  347        * @throws  NullPointerException if provider is null
  348        * @throws  SecurityException
  349        *          if a security manager exists and its <code>{@link
  350        *          java.lang.SecurityManager#checkSecurityAccess}</code> method
  351        *          denies access to add a new provider
  352        *
  353        * @see #getProvider
  354        * @see #removeProvider
  355        * @see java.security.SecurityPermission
  356        */
  357       public static synchronized int insertProviderAt(Provider provider,
  358               int position) {
  359           String providerName = provider.getName();
  360           check("insertProvider." + providerName);
  361           ProviderList list = Providers.getFullProviderList();
  362           ProviderList newList = ProviderList.insertAt(list, provider, position - 1);
  363           if (list == newList) {
  364               return -1;
  365           }
  366           Providers.setProviderList(newList);
  367           return newList.getIndex(providerName) + 1;
  368       }
  369   
  370       /**
  371        * Adds a provider to the next position available.
  372        *
  373        * <p>First, if there is a security manager, its
  374        * <code>checkSecurityAccess</code>
  375        * method is called with the string
  376        * <code>"insertProvider."+provider.getName()</code>
  377        * to see if it's ok to add a new provider.
  378        * If the default implementation of <code>checkSecurityAccess</code>
  379        * is used (i.e., that method is not overriden), then this will result in
  380        * a call to the security manager's <code>checkPermission</code> method
  381        * with a
  382        * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  383        * permission.
  384        *
  385        * @param provider the provider to be added.
  386        *
  387        * @return the preference position in which the provider was
  388        * added, or -1 if the provider was not added because it is
  389        * already installed.
  390        *
  391        * @throws  NullPointerException if provider is null
  392        * @throws  SecurityException
  393        *          if a security manager exists and its <code>{@link
  394        *          java.lang.SecurityManager#checkSecurityAccess}</code> method
  395        *          denies access to add a new provider
  396        *
  397        * @see #getProvider
  398        * @see #removeProvider
  399        * @see java.security.SecurityPermission
  400        */
  401       public static int addProvider(Provider provider) {
  402           /*
  403            * We can't assign a position here because the statically
  404            * registered providers may not have been installed yet.
  405            * insertProviderAt() will fix that value after it has
  406            * loaded the static providers.
  407            */
  408           return insertProviderAt(provider, 0);
  409       }
  410   
  411       /**
  412        * Removes the provider with the specified name.
  413        *
  414        * <p>When the specified provider is removed, all providers located
  415        * at a position greater than where the specified provider was are shifted
  416        * down one position (towards the head of the list of installed
  417        * providers).
  418        *
  419        * <p>This method returns silently if the provider is not installed or
  420        * if name is null.
  421        *
  422        * <p>First, if there is a security manager, its
  423        * <code>checkSecurityAccess</code>
  424        * method is called with the string <code>"removeProvider."+name</code>
  425        * to see if it's ok to remove the provider.
  426        * If the default implementation of <code>checkSecurityAccess</code>
  427        * is used (i.e., that method is not overriden), then this will result in
  428        * a call to the security manager's <code>checkPermission</code> method
  429        * with a <code>SecurityPermission("removeProvider."+name)</code>
  430        * permission.
  431        *
  432        * @param name the name of the provider to remove.
  433        *
  434        * @throws  SecurityException
  435        *          if a security manager exists and its <code>{@link
  436        *          java.lang.SecurityManager#checkSecurityAccess}</code> method
  437        *          denies
  438        *          access to remove the provider
  439        *
  440        * @see #getProvider
  441        * @see #addProvider
  442        */
  443       public static synchronized void removeProvider(String name) {
  444           check("removeProvider." + name);
  445           ProviderList list = Providers.getFullProviderList();
  446           ProviderList newList = ProviderList.remove(list, name);
  447           Providers.setProviderList(newList);
  448       }
  449   
  450       /**
  451        * Returns an array containing all the installed providers. The order of
  452        * the providers in the array is their preference order.
  453        *
  454        * @return an array of all the installed providers.
  455        */
  456       public static Provider[] getProviders() {
  457           return Providers.getFullProviderList().toArray();
  458       }
  459   
  460       /**
  461        * Returns the provider installed with the specified name, if
  462        * any. Returns null if no provider with the specified name is
  463        * installed or if name is null.
  464        *
  465        * @param name the name of the provider to get.
  466        *
  467        * @return the provider of the specified name.
  468        *
  469        * @see #removeProvider
  470        * @see #addProvider
  471        */
  472       public static Provider getProvider(String name) {
  473           return Providers.getProviderList().getProvider(name);
  474       }
  475   
  476       /**
  477        * Returns an array containing all installed providers that satisfy the
  478        * specified selection criterion, or null if no such providers have been
  479        * installed. The returned providers are ordered
  480        * according to their <a href=
  481        * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
  482        *
  483        * <p> A cryptographic service is always associated with a particular
  484        * algorithm or type. For example, a digital signature service is
  485        * always associated with a particular algorithm (e.g., DSA),
  486        * and a CertificateFactory service is always associated with
  487        * a particular certificate type (e.g., X.509).
  488        *
  489        * <p>The selection criterion must be specified in one of the following two
  490        * formats:
  491        * <ul>
  492        * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type></i> <p> The
  493        * cryptographic service name must not contain any dots.
  494        * <p> A
  495        * provider satisfies the specified selection criterion iff the provider
  496        * implements the
  497        * specified algorithm or type for the specified cryptographic service.
  498        * <p> For example, "CertificateFactory.X.509"
  499        * would be satisfied by any provider that supplied
  500        * a CertificateFactory implementation for X.509 certificates.
  501        * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type>
  502        * &lt;attribute_name>:&lt attribute_value></i>
  503        * <p> The cryptographic service name must not contain any dots. There
  504        * must be one or more space charaters between the the
  505        * <i>&lt;algorithm_or_type></i> and the <i>&lt;attribute_name></i>.
  506        *  <p> A provider satisfies this selection criterion iff the
  507        * provider implements the specified algorithm or type for the specified
  508        * cryptographic service and its implementation meets the
  509        * constraint expressed by the specified attribute name/value pair.
  510        * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
  511        * satisfied by any provider that implemented
  512        * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
  513        *
  514        * </ul>
  515        *
  516        * <p> See Appendix A in the <a href=
  517        * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  518        * Java Cryptography Architecture API Specification &amp; Reference </a>
  519        * for information about standard cryptographic service names, standard
  520        * algorithm names and standard attribute names.
  521        *
  522        * @param filter the criterion for selecting
  523        * providers. The filter is case-insensitive.
  524        *
  525        * @return all the installed providers that satisfy the selection
  526        * criterion, or null if no such providers have been installed.
  527        *
  528        * @throws InvalidParameterException
  529        *         if the filter is not in the required format
  530        * @throws NullPointerException if filter is null
  531        *
  532        * @see #getProviders(java.util.Map)
  533        * @since 1.3
  534        */
  535       public static Provider[] getProviders(String filter) {
  536           String key = null;
  537           String value = null;
  538           int index = filter.indexOf(':');
  539   
  540           if (index == -1) {
  541               key = filter;
  542               value = "";
  543           } else {
  544               key = filter.substring(0, index);
  545               value = filter.substring(index + 1);
  546           }
  547   
  548           Hashtable<String, String> hashtableFilter =
  549                   new Hashtable<String, String>(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 Appendix A in the <a href=
  586        * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  587        * Java Cryptography Architecture API Specification &amp; Reference </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<Provider>(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 =
  664                                   new ConcurrentHashMap<String,Class>();
  665   
  666       /**
  667        * Return the Class object for the given engine type
  668        * (e.g. "MessageDigest"). Works for Spis in the java.security package
  669        * only.
  670        */
  671       private static Class getSpiClass(String type) {
  672           Class clazz = spiMap.get(type);
  673           if (clazz != null) {
  674               return clazz;
  675           }
  676           try {
  677               clazz = Class.forName("java.security." + type + "Spi");
  678               spiMap.put(type, clazz);
  679               return clazz;
  680           } catch (ClassNotFoundException e) {
  681               throw (Error)new AssertionError("Spi class not found").initCause(e);
  682           }
  683       }
  684   
  685       /*
  686        * Returns an array of objects: the first object in the array is
  687        * an instance of an implementation of the requested algorithm
  688        * and type, and the second object in the array identifies the provider
  689        * of that implementation.
  690        * The <code>provider</code> argument can be null, in which case all
  691        * configured providers will be searched in order of preference.
  692        */
  693       static Object[] getImpl(String algorithm, String type, String provider)
  694               throws NoSuchAlgorithmException, NoSuchProviderException {
  695           if (provider == null) {
  696               return GetInstance.getInstance
  697                   (type, getSpiClass(type), algorithm).toArray();
  698           } else {
  699               return GetInstance.getInstance
  700                   (type, getSpiClass(type), algorithm, provider).toArray();
  701           }
  702       }
  703   
  704       static Object[] getImpl(String algorithm, String type, String provider,
  705               Object params) throws NoSuchAlgorithmException,
  706               NoSuchProviderException, InvalidAlgorithmParameterException {
  707           if (provider == null) {
  708               return GetInstance.getInstance
  709                   (type, getSpiClass(type), algorithm, params).toArray();
  710           } else {
  711               return GetInstance.getInstance
  712                   (type, getSpiClass(type), algorithm, params, provider).toArray();
  713           }
  714       }
  715   
  716       /*
  717        * Returns an array of objects: the first object in the array is
  718        * an instance of an implementation of the requested algorithm
  719        * and type, and the second object in the array identifies the provider
  720        * of that implementation.
  721        * The <code>provider</code> argument cannot be null.
  722        */
  723       static Object[] getImpl(String algorithm, String type, Provider provider)
  724               throws NoSuchAlgorithmException {
  725           return GetInstance.getInstance
  726               (type, getSpiClass(type), algorithm, provider).toArray();
  727       }
  728   
  729       static Object[] getImpl(String algorithm, String type, Provider provider,
  730               Object params) throws NoSuchAlgorithmException,
  731               InvalidAlgorithmParameterException {
  732           return GetInstance.getInstance
  733               (type, getSpiClass(type), algorithm, params, provider).toArray();
  734       }
  735   
  736       /**
  737        * Gets a security property value.
  738        *
  739        * <p>First, if there is a security manager, its
  740        * <code>checkPermission</code>  method is called with a
  741        * <code>java.security.SecurityPermission("getProperty."+key)</code>
  742        * permission to see if it's ok to retrieve the specified
  743        * security property value..
  744        *
  745        * @param key the key of the property being retrieved.
  746        *
  747        * @return the value of the security property corresponding to key.
  748        *
  749        * @throws  SecurityException
  750        *          if a security manager exists and its <code>{@link
  751        *          java.lang.SecurityManager#checkPermission}</code> method
  752        *          denies
  753        *          access to retrieve the specified security property value
  754        * @throws  NullPointerException is key is null
  755        *
  756        * @see #setProperty
  757        * @see java.security.SecurityPermission
  758        */
  759       public static String getProperty(String key) {
  760           SecurityManager sm = System.getSecurityManager();
  761           if (sm != null) {
  762               sm.checkPermission(new SecurityPermission("getProperty."+
  763                                                         key));
  764           }
  765           String name = props.getProperty(key);
  766           if (name != null)
  767               name = name.trim(); // could be a class name with trailing ws
  768           return name;
  769       }
  770   
  771       /**
  772        * Sets a security property value.
  773        *
  774        * <p>First, if there is a security manager, its
  775        * <code>checkPermission</code> method is called with a
  776        * <code>java.security.SecurityPermission("setProperty."+key)</code>
  777        * permission to see if it's ok to set the specified
  778        * security property value.
  779        *
  780        * @param key the name of the property to be set.
  781        *
  782        * @param datum the value of the property to be set.
  783        *
  784        * @throws  SecurityException
  785        *          if a security manager exists and its <code>{@link
  786        *          java.lang.SecurityManager#checkPermission}</code> method
  787        *          denies access to set the specified security property value
  788        * @throws  NullPointerException if key or datum is null
  789        *
  790        * @see #getProperty
  791        * @see java.security.SecurityPermission
  792        */
  793       public static void setProperty(String key, String datum) {
  794           check("setProperty."+key);
  795           props.put(key, datum);
  796           invalidateSMCache(key);  /* See below. */
  797       }
  798   
  799       /*
  800        * Implementation detail:  If the property we just set in
  801        * setProperty() was either "package.access" or
  802        * "package.definition", we need to signal to the SecurityManager
  803        * class that the value has just changed, and that it should
  804        * invalidate it's local cache values.
  805        *
  806        * Rather than create a new API entry for this function,
  807        * we use reflection to set a private variable.
  808        */
  809       private static void invalidateSMCache(String key) {
  810   
  811           final boolean pa = key.equals("package.access");
  812           final boolean pd = key.equals("package.definition");
  813   
  814           if (pa || pd) {
  815               AccessController.doPrivileged(new PrivilegedAction<Void>() {
  816                   public Void run() {
  817                       try {
  818                           /* Get the class via the bootstrap class loader. */
  819                           Class cl = Class.forName(
  820                               "java.lang.SecurityManager", false, null);
  821                           Field f = null;
  822                           boolean accessible = false;
  823   
  824                           if (pa) {
  825                               f = cl.getDeclaredField("packageAccessValid");
  826                               accessible = f.isAccessible();
  827                               f.setAccessible(true);
  828                           } else {
  829                               f = cl.getDeclaredField("packageDefinitionValid");
  830                               accessible = f.isAccessible();
  831                               f.setAccessible(true);
  832                           }
  833                           f.setBoolean(f, false);
  834                           f.setAccessible(accessible);
  835                       }
  836                       catch (Exception e1) {
  837                           /* If we couldn't get the class, it hasn't
  838                            * been loaded yet.  If there is no such
  839                            * field, we shouldn't try to set it.  There
  840                            * shouldn't be a security execption, as we
  841                            * are loaded by boot class loader, and we
  842                            * are inside a doPrivileged() here.
  843                            *
  844                            * NOOP: don't do anything...
  845                            */
  846                       }
  847                       return null;
  848                   }  /* run */
  849               });  /* PrivilegedAction */
  850           }  /* if */
  851       }
  852   
  853       private static void check(String directive) {
  854           SecurityManager security = System.getSecurityManager();
  855           if (security != null) {
  856               security.checkSecurityAccess(directive);
  857           }
  858       }
  859   
  860       /*
  861       * Returns all providers who satisfy the specified
  862       * criterion.
  863       */
  864       private static LinkedHashSet<Provider> getAllQualifyingCandidates(
  865                                                   String filterKey,
  866                                                   String filterValue,
  867                                                   Provider[] allProviders) {
  868           String[] filterComponents = getFilterComponents(filterKey,
  869                                                           filterValue);
  870   
  871           // The first component is the service name.
  872           // The second is the algorithm name.
  873           // If the third isn't null, that is the attrinute name.
  874           String serviceName = filterComponents[0];
  875           String algName = filterComponents[1];
  876           String attrName = filterComponents[2];
  877   
  878           return getProvidersNotUsingCache(serviceName, algName, attrName,
  879                                            filterValue, allProviders);
  880       }
  881   
  882       private static LinkedHashSet<Provider> getProvidersNotUsingCache(
  883                                                   String serviceName,
  884                                                   String algName,
  885                                                   String attrName,
  886                                                   String filterValue,
  887                                                   Provider[] allProviders) {
  888           LinkedHashSet<Provider> candidates = new LinkedHashSet<Provider>(5);
  889           for (int i = 0; i < allProviders.length; i++) {
  890               if (isCriterionSatisfied(allProviders[i], serviceName,
  891                                        algName,
  892                                        attrName, filterValue)) {
  893                   candidates.add(allProviders[i]);
  894               }
  895           }
  896           return candidates;
  897       }
  898   
  899       /*
  900        * Returns true if the given provider satisfies
  901        * the selection criterion key:value.
  902        */
  903       private static boolean isCriterionSatisfied(Provider prov,
  904                                                   String serviceName,
  905                                                   String algName,
  906                                                   String attrName,
  907                                                   String filterValue) {
  908           String key = serviceName + '.' + algName;
  909   
  910           if (attrName != null) {
  911               key += ' ' + attrName;
  912           }
  913           // Check whether the provider has a property
  914           // whose key is the same as the given key.
  915           String propValue = getProviderProperty(key, prov);
  916   
  917           if (propValue == null) {
  918               // Check whether we have an alias instead
  919               // of a standard name in the key.
  920               String standardName = getProviderProperty("Alg.Alias." +
  921                                                         serviceName + "." +
  922                                                         algName,
  923                                                         prov);
  924               if (standardName != null) {
  925                   key = serviceName + "." + standardName;
  926   
  927                   if (attrName != null) {
  928                       key += ' ' + attrName;
  929                   }
  930   
  931                   propValue = getProviderProperty(key, prov);
  932               }
  933   
  934               if (propValue == null) {
  935                   // The provider doesn't have the given
  936                   // key in its property list.
  937                   return false;
  938               }
  939           }
  940   
  941           // If the key is in the format of:
  942           // <crypto_service>.<algorithm_or_type>,
  943           // there is no need to check the value.
  944   
  945           if (attrName == null) {
  946               return true;
  947           }
  948   
  949           // If we get here, the key must be in the
  950           // format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
  951           if (isStandardAttr(attrName)) {
  952               return isConstraintSatisfied(attrName, filterValue, propValue);
  953           } else {
  954               return filterValue.equalsIgnoreCase(propValue);
  955           }
  956       }
  957   
  958       /*
  959        * Returns true if the attribute is a standard attribute;
  960        * otherwise, returns false.
  961        */
  962       private static boolean isStandardAttr(String attribute) {
  963           // For now, we just have two standard attributes:
  964           // KeySize and ImplementedIn.
  965           if (attribute.equalsIgnoreCase("KeySize"))
  966               return true;
  967   
  968           if (attribute.equalsIgnoreCase("ImplementedIn"))
  969               return true;
  970   
  971           return false;
  972       }
  973   
  974       /*
  975        * Returns true if the requested attribute value is supported;
  976        * otherwise, returns false.
  977        */
  978       private static boolean isConstraintSatisfied(String attribute,
  979                                                    String value,
  980                                                    String prop) {
  981           // For KeySize, prop is the max key size the
  982           // provider supports for a specific <crypto_service>.<algorithm>.
  983           if (attribute.equalsIgnoreCase("KeySize")) {
  984               int requestedSize = Integer.parseInt(value);
  985               int maxSize = Integer.parseInt(prop);
  986               if (requestedSize <= maxSize) {
  987                   return true;
  988               } else {
  989                   return false;
  990               }
  991           }
  992   
  993           // For Type, prop is the type of the implementation
  994           // for a specific <crypto service>.<algorithm>.
  995           if (attribute.equalsIgnoreCase("ImplementedIn")) {
  996               return value.equalsIgnoreCase(prop);
  997           }
  998   
  999           return false;
 1000       }
 1001   
 1002       static String[] getFilterComponents(String filterKey, String filterValue) {
 1003           int algIndex = filterKey.indexOf('.');
 1004   
 1005           if (algIndex < 0) {
 1006               // There must be a dot in the filter, and the dot
 1007               // shouldn't be at the beginning of this string.
 1008               throw new InvalidParameterException("Invalid filter");
 1009           }
 1010   
 1011           String serviceName = filterKey.substring(0, algIndex);
 1012           String algName = null;
 1013           String attrName = null;
 1014   
 1015           if (filterValue.length() == 0) {
 1016               // The filterValue is an empty string. So the filterKey
 1017               // should be in the format of <crypto_service>.<algorithm_or_type>.
 1018               algName = filterKey.substring(algIndex + 1).trim();
 1019               if (algName.length() == 0) {
 1020                   // There must be a algorithm or type name.
 1021                   throw new InvalidParameterException("Invalid filter");
 1022               }
 1023           } else {
 1024               // The filterValue is a non-empty string. So the filterKey must be
 1025               // in the format of
 1026               // <crypto_service>.<algorithm_or_type> <attribute_name>
 1027               int attrIndex = filterKey.indexOf(' ');
 1028   
 1029               if (attrIndex == -1) {
 1030                   // There is no attribute name in the filter.
 1031                   throw new InvalidParameterException("Invalid filter");
 1032               } else {
 1033                   attrName = filterKey.substring(attrIndex + 1).trim();
 1034                   if (attrName.length() == 0) {
 1035                       // There is no attribute name in the filter.
 1036                       throw new InvalidParameterException("Invalid filter");
 1037                   }
 1038               }
 1039   
 1040               // There must be an algorithm name in the filter.
 1041               if ((attrIndex < algIndex) ||
 1042                   (algIndex == attrIndex - 1)) {
 1043                   throw new InvalidParameterException("Invalid filter");
 1044               } else {
 1045                   algName = filterKey.substring(algIndex + 1, attrIndex);
 1046               }
 1047           }
 1048   
 1049           String[] result = new String[3];
 1050           result[0] = serviceName;
 1051           result[1] = algName;
 1052           result[2] = attrName;
 1053   
 1054           return result;
 1055       }
 1056   
 1057       /**
 1058        * Returns a Set of Strings containing the names of all available
 1059        * algorithms or types for the specified Java cryptographic service
 1060        * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns
 1061        * an empty Set if there is no provider that supports the
 1062        * specified service or if serviceName is null. For a complete list
 1063        * of Java cryptographic services, please see the
 1064        * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">Java
 1065        * Cryptography Architecture API Specification &amp; Reference</a>.
 1066        * Note: the returned set is immutable.
 1067        *
 1068        * @param serviceName the name of the Java cryptographic
 1069        * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
 1070        * Note: this parameter is case-insensitive.
 1071        *
 1072        * @return a Set of Strings containing the names of all available
 1073        * algorithms or types for the specified Java cryptographic service
 1074        * or an empty set if no provider supports the specified service.
 1075        *
 1076        * @since 1.4
 1077        **/
 1078       public static Set<String> getAlgorithms(String serviceName) {
 1079   
 1080           if ((serviceName == null) || (serviceName.length() == 0) ||
 1081               (serviceName.endsWith("."))) {
 1082               return Collections.EMPTY_SET;
 1083           }
 1084   
 1085           HashSet<String> result = new HashSet<String>();
 1086           Provider[] providers = Security.getProviders();
 1087   
 1088           for (int i = 0; i < providers.length; i++) {
 1089               // Check the keys for each provider.
 1090               for (Enumeration<Object> e = providers[i].keys();
 1091                                                   e.hasMoreElements(); ) {
 1092                   String currentKey = ((String)e.nextElement()).toUpperCase();
 1093                   if (currentKey.startsWith(serviceName.toUpperCase())) {
 1094                       // We should skip the currentKey if it contains a
 1095                       // whitespace. The reason is: such an entry in the
 1096                       // provider property contains attributes for the
 1097                       // implementation of an algorithm. We are only interested
 1098                       // in entries which lead to the implementation
 1099                       // classes.
 1100                       if (currentKey.indexOf(" ") < 0) {
 1101                           result.add(currentKey.substring(serviceName.length() + 1));
 1102                       }
 1103                   }
 1104               }
 1105           }
 1106           return Collections.unmodifiableSet(result);
 1107       }
 1108   }

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