1 /*
   2  * Copyright (c) 1996, 2015, 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.util.*;
  29 import java.util.concurrent.ConcurrentHashMap;
  30 import java.io.*;
  31 import java.net.URL;
  32 
  33 import jdk.internal.misc.SharedSecrets;
  34 import sun.security.util.Debug;
  35 import sun.security.util.PropertyExpander;
  36 
  37 import sun.security.jca.*;
  38 
  39 /**
  40  * <p>This class centralizes all security properties and common security
  41  * methods. One of its primary uses is to manage providers.
  42  *
  43  * <p>The default values of security properties are read from an
  44  * implementation-specific location, which is typically the properties file
  45  * {@code conf/security/java.security} in the Java installation directory.
  46  *
  47  * @author Benjamin Renaud
  48  */
  49 
  50 public final class Security {
  51 
  52     /* Are we debugging? -- for developers */
  53     private static final Debug sdebug =
  54                         Debug.getInstance("properties");
  55 
  56     /* The java.security properties */
  57     private static Properties props;
  58 
  59     // An element in the cache
  60     private static class ProviderProperty {
  61         String className;
  62         Provider provider;
  63     }
  64 
  65     static {
  66         // doPrivileged here because there are multiple
  67         // things in initialize that might require privs.
  68         // (the FileInputStream call and the File.exists call,
  69         // the securityPropFile call, etc)
  70         AccessController.doPrivileged(new PrivilegedAction<>() {
  71             public Void run() {
  72                 initialize();
  73                 return null;
  74             }
  75         });
  76     }
  77 
  78     private static void initialize() {
  79         props = new Properties();
  80         boolean loadedProps = false;
  81         boolean overrideAll = false;
  82 
  83         // first load the system properties file
  84         // to determine the value of security.overridePropertiesFile
  85         File propFile = securityPropFile("java.security");
  86         if (propFile.exists()) {
  87             InputStream is = null;
  88             try {
  89                 FileInputStream fis = new FileInputStream(propFile);
  90                 is = new BufferedInputStream(fis);
  91                 props.load(is);
  92                 loadedProps = true;
  93 
  94                 if (sdebug != null) {
  95                     sdebug.println("reading security properties file: " +
  96                                 propFile);
  97                 }
  98             } catch (IOException e) {
  99                 if (sdebug != null) {
 100                     sdebug.println("unable to load security properties from " +
 101                                 propFile);
 102                     e.printStackTrace();
 103                 }
 104             } finally {
 105                 if (is != null) {
 106                     try {
 107                         is.close();
 108                     } catch (IOException ioe) {
 109                         if (sdebug != null) {
 110                             sdebug.println("unable to close input stream");
 111                         }
 112                     }
 113                 }
 114             }
 115         }
 116 
 117         if ("true".equalsIgnoreCase(props.getProperty
 118                 ("security.overridePropertiesFile"))) {
 119 
 120             String extraPropFile = System.getProperty
 121                                         ("java.security.properties");
 122             if (extraPropFile != null && extraPropFile.startsWith("=")) {
 123                 overrideAll = true;
 124                 extraPropFile = extraPropFile.substring(1);
 125             }
 126 
 127             if (overrideAll) {
 128                 props = new Properties();
 129                 if (sdebug != null) {
 130                     sdebug.println
 131                         ("overriding other security properties files!");
 132                 }
 133             }
 134 
 135             // now load the user-specified file so its values
 136             // will win if they conflict with the earlier values
 137             if (extraPropFile != null) {
 138                 BufferedInputStream bis = null;
 139                 try {
 140                     URL propURL;
 141 
 142                     extraPropFile = PropertyExpander.expand(extraPropFile);
 143                     propFile = new File(extraPropFile);
 144                     if (propFile.exists()) {
 145                         propURL = new URL
 146                                 ("file:" + propFile.getCanonicalPath());
 147                     } else {
 148                         propURL = new URL(extraPropFile);
 149                     }
 150                     bis = new BufferedInputStream(propURL.openStream());
 151                     props.load(bis);
 152                     loadedProps = true;
 153 
 154                     if (sdebug != null) {
 155                         sdebug.println("reading security properties file: " +
 156                                         propURL);
 157                         if (overrideAll) {
 158                             sdebug.println
 159                                 ("overriding other security properties files!");
 160                         }
 161                     }
 162                 } catch (Exception e) {
 163                     if (sdebug != null) {
 164                         sdebug.println
 165                                 ("unable to load security properties from " +
 166                                 extraPropFile);
 167                         e.printStackTrace();
 168                     }
 169                 } finally {
 170                     if (bis != null) {
 171                         try {
 172                             bis.close();
 173                         } catch (IOException ioe) {
 174                             if (sdebug != null) {
 175                                 sdebug.println("unable to close input stream");
 176                             }
 177                         }
 178                     }
 179                 }
 180             }
 181         }
 182 
 183         if (!loadedProps) {
 184             initializeStatic();
 185             if (sdebug != null) {
 186                 sdebug.println("unable to load security properties " +
 187                         "-- using defaults");
 188             }
 189         }
 190 
 191     }
 192 
 193     /*
 194      * Initialize to default values, if <java.home>/lib/java.security
 195      * is not found.
 196      */
 197     private static void initializeStatic() {
 198         props.put("security.provider.1", "sun.security.provider.Sun");
 199         props.put("security.provider.2", "sun.security.rsa.SunRsaSign");
 200         props.put("security.provider.3", "com.sun.net.ssl.internal.ssl.Provider");
 201         props.put("security.provider.4", "com.sun.crypto.provider.SunJCE");
 202         props.put("security.provider.5", "sun.security.jgss.SunProvider");
 203         props.put("security.provider.6", "com.sun.security.sasl.Provider");
 204     }
 205 
 206     /**
 207      * Don't let anyone instantiate this.
 208      */
 209     private Security() {
 210     }
 211 
 212     private static File securityPropFile(String filename) {
 213         // maybe check for a system property which will specify where to
 214         // look. Someday.
 215         String sep = File.separator;
 216         return new File(System.getProperty("java.home") + sep + "conf" + sep +
 217                         "security" + sep + filename);
 218     }
 219 
 220     /**
 221      * Looks up providers, and returns the property (and its associated
 222      * provider) mapping the key, if any.
 223      * The order in which the providers are looked up is the
 224      * provider-preference order, as specificed in the security
 225      * properties file.
 226      */
 227     private static ProviderProperty getProviderProperty(String key) {
 228         ProviderProperty entry = null;
 229 
 230         List<Provider> providers = Providers.getProviderList().providers();
 231         for (int i = 0; i < providers.size(); i++) {
 232 
 233             String matchKey = null;
 234             Provider prov = providers.get(i);
 235             String prop = prov.getProperty(key);
 236 
 237             if (prop == null) {
 238                 // Is there a match if we do a case-insensitive property name
 239                 // comparison? Let's try ...
 240                 for (Enumeration<Object> e = prov.keys();
 241                                 e.hasMoreElements() && prop == null; ) {
 242                     matchKey = (String)e.nextElement();
 243                     if (key.equalsIgnoreCase(matchKey)) {
 244                         prop = prov.getProperty(matchKey);
 245                         break;
 246                     }
 247                 }
 248             }
 249 
 250             if (prop != null) {
 251                 ProviderProperty newEntry = new ProviderProperty();
 252                 newEntry.className = prop;
 253                 newEntry.provider = prov;
 254                 return newEntry;
 255             }
 256         }
 257 
 258         return entry;
 259     }
 260 
 261     /**
 262      * Returns the property (if any) mapping the key for the given provider.
 263      */
 264     private static String getProviderProperty(String key, Provider provider) {
 265         String prop = provider.getProperty(key);
 266         if (prop == null) {
 267             // Is there a match if we do a case-insensitive property name
 268             // comparison? Let's try ...
 269             for (Enumeration<Object> e = provider.keys();
 270                                 e.hasMoreElements() && prop == null; ) {
 271                 String matchKey = (String)e.nextElement();
 272                 if (key.equalsIgnoreCase(matchKey)) {
 273                     prop = provider.getProperty(matchKey);
 274                     break;
 275                 }
 276             }
 277         }
 278         return prop;
 279     }
 280 
 281     /**
 282      * Gets a specified property for an algorithm. The algorithm name
 283      * should be a standard name. See the <a href=
 284      * "{@docRoot}/../technotes/guides/security/StandardNames.html">
 285      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
 286      * for information about standard algorithm names.
 287      *
 288      * One possible use is by specialized algorithm parsers, which may map
 289      * classes to algorithms which they understand (much like Key parsers
 290      * do).
 291      *
 292      * @param algName the algorithm name.
 293      *
 294      * @param propName the name of the property to get.
 295      *
 296      * @return the value of the specified property.
 297      *
 298      * @deprecated This method used to return the value of a proprietary
 299      * property in the master file of the "SUN" Cryptographic Service
 300      * Provider in order to determine how to parse algorithm-specific
 301      * parameters. Use the new provider-based and algorithm-independent
 302      * {@code AlgorithmParameters} and {@code KeyFactory} engine
 303      * classes (introduced in the J2SE version 1.2 platform) instead.
 304      */
 305     @Deprecated
 306     public static String getAlgorithmProperty(String algName,
 307                                               String propName) {
 308         ProviderProperty entry = getProviderProperty("Alg." + propName
 309                                                      + "." + algName);
 310         if (entry != null) {
 311             return entry.className;
 312         } else {
 313             return null;
 314         }
 315     }
 316 
 317     /**
 318      * Adds a new provider, at a specified position. The position is
 319      * the preference order in which providers are searched for
 320      * requested algorithms.  The position is 1-based, that is,
 321      * 1 is most preferred, followed by 2, and so on.
 322      *
 323      * <p>If the given provider is installed at the requested position,
 324      * the provider that used to be at that position, and all providers
 325      * with a position greater than {@code position}, are shifted up
 326      * one position (towards the end of the list of installed providers).
 327      *
 328      * <p>A provider cannot be added if it is already installed.
 329      *
 330      * <p>If there is a security manager, the
 331      * {@link java.lang.SecurityManager#checkSecurityAccess} method is called
 332      * with the {@code "insertProvider"} permission target name to see if
 333      * it's ok to add a new provider. If this permission check is denied,
 334      * {@code checkSecurityAccess} is called again with the
 335      * {@code "insertProvider."+provider.getName()} permission target name. If
 336      * both checks are denied, a {@code SecurityException} is thrown.
 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 {@link
 350      *          java.lang.SecurityManager#checkSecurityAccess} 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         checkInsertProvider(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>If there is a security manager, the
 374      * {@link java.lang.SecurityManager#checkSecurityAccess} method is called
 375      * with the {@code "insertProvider"} permission target name to see if
 376      * it's ok to add a new provider. If this permission check is denied,
 377      * {@code checkSecurityAccess} is called again with the
 378      * {@code "insertProvider."+provider.getName()} permission target name. If
 379      * both checks are denied, a {@code SecurityException} is thrown.
 380      *
 381      * @param provider the provider to be added.
 382      *
 383      * @return the preference position in which the provider was
 384      * added, or -1 if the provider was not added because it is
 385      * already installed.
 386      *
 387      * @throws  NullPointerException if provider is null
 388      * @throws  SecurityException
 389      *          if a security manager exists and its {@link
 390      *          java.lang.SecurityManager#checkSecurityAccess} method
 391      *          denies access to add a new provider
 392      *
 393      * @see #getProvider
 394      * @see #removeProvider
 395      * @see java.security.SecurityPermission
 396      */
 397     public static int addProvider(Provider provider) {
 398         /*
 399          * We can't assign a position here because the statically
 400          * registered providers may not have been installed yet.
 401          * insertProviderAt() will fix that value after it has
 402          * loaded the static providers.
 403          */
 404         return insertProviderAt(provider, 0);
 405     }
 406 
 407     /**
 408      * Removes the provider with the specified name.
 409      *
 410      * <p>When the specified provider is removed, all providers located
 411      * at a position greater than where the specified provider was are shifted
 412      * down one position (towards the head of the list of installed
 413      * providers).
 414      *
 415      * <p>This method returns silently if the provider is not installed or
 416      * if name is null.
 417      *
 418      * <p>First, if there is a security manager, its
 419      * {@code checkSecurityAccess}
 420      * method is called with the string {@code "removeProvider."+name}
 421      * to see if it's ok to remove the provider.
 422      * If the default implementation of {@code checkSecurityAccess}
 423      * is used (i.e., that method is not overriden), then this will result in
 424      * a call to the security manager's {@code checkPermission} method
 425      * with a {@code SecurityPermission("removeProvider."+name)}
 426      * permission.
 427      *
 428      * @param name the name of the provider to remove.
 429      *
 430      * @throws  SecurityException
 431      *          if a security manager exists and its {@link
 432      *          java.lang.SecurityManager#checkSecurityAccess} method
 433      *          denies
 434      *          access to remove the provider
 435      *
 436      * @see #getProvider
 437      * @see #addProvider
 438      */
 439     public static synchronized void removeProvider(String name) {
 440         check("removeProvider." + name);
 441         ProviderList list = Providers.getFullProviderList();
 442         ProviderList newList = ProviderList.remove(list, name);
 443         Providers.setProviderList(newList);
 444     }
 445 
 446     /**
 447      * Returns an array containing all the installed providers. The order of
 448      * the providers in the array is their preference order.
 449      *
 450      * @return an array of all the installed providers.
 451      */
 452     public static Provider[] getProviders() {
 453         return Providers.getFullProviderList().toArray();
 454     }
 455 
 456     /**
 457      * Returns the provider installed with the specified name, if
 458      * any. Returns null if no provider with the specified name is
 459      * installed or if name is null.
 460      *
 461      * @param name the name of the provider to get.
 462      *
 463      * @return the provider of the specified name.
 464      *
 465      * @see #removeProvider
 466      * @see #addProvider
 467      */
 468     public static Provider getProvider(String name) {
 469         return Providers.getProviderList().getProvider(name);
 470     }
 471 
 472     /**
 473      * Returns an array containing all installed providers that satisfy the
 474      * specified selection criterion, or null if no such providers have been
 475      * installed. The returned providers are ordered
 476      * according to their
 477      * {@linkplain #insertProviderAt(java.security.Provider, int) preference order}.
 478      *
 479      * <p> A cryptographic service is always associated with a particular
 480      * algorithm or type. For example, a digital signature service is
 481      * always associated with a particular algorithm (e.g., DSA),
 482      * and a CertificateFactory service is always associated with
 483      * a particular certificate type (e.g., X.509).
 484      *
 485      * <p>The selection criterion must be specified in one of the following two
 486      * formats:
 487      * <ul>
 488      * <li> <i>{@literal <crypto_service>.<algorithm_or_type>}</i>
 489      * <p> The cryptographic service name must not contain any dots.
 490      * <p> A
 491      * provider satisfies the specified selection criterion iff the provider
 492      * implements the
 493      * specified algorithm or type for the specified cryptographic service.
 494      * <p> For example, "CertificateFactory.X.509"
 495      * would be satisfied by any provider that supplied
 496      * a CertificateFactory implementation for X.509 certificates.
 497      * <li> <i>{@literal <crypto_service>.<algorithm_or_type>
 498      * <attribute_name>:<attribute_value>}</i>
 499      * <p> The cryptographic service name must not contain any dots. There
 500      * must be one or more space characters between the
 501      * <i>{@literal <algorithm_or_type>}</i> and the
 502      * <i>{@literal <attribute_name>}</i>.
 503      *  <p> A provider satisfies this selection criterion iff the
 504      * provider implements the specified algorithm or type for the specified
 505      * cryptographic service and its implementation meets the
 506      * constraint expressed by the specified attribute name/value pair.
 507      * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
 508      * satisfied by any provider that implemented
 509      * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
 510      *
 511      * </ul>
 512      *
 513      * <p> See the <a href=
 514      * "{@docRoot}/../technotes/guides/security/StandardNames.html">
 515      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
 516      * for information about standard cryptographic service names, standard
 517      * algorithm names and standard attribute names.
 518      *
 519      * @param filter the criterion for selecting
 520      * providers. The filter is case-insensitive.
 521      *
 522      * @return all the installed providers that satisfy the selection
 523      * criterion, or null if no such providers have been installed.
 524      *
 525      * @throws InvalidParameterException
 526      *         if the filter is not in the required format
 527      * @throws NullPointerException if filter is null
 528      *
 529      * @see #getProviders(java.util.Map)
 530      * @since 1.3
 531      */
 532     public static Provider[] getProviders(String filter) {
 533         String key = null;
 534         String value = null;
 535         int index = filter.indexOf(':');
 536 
 537         if (index == -1) {
 538             key = filter;
 539             value = "";
 540         } else {
 541             key = filter.substring(0, index);
 542             value = filter.substring(index + 1);
 543         }
 544 
 545         Hashtable<String, String> hashtableFilter = new Hashtable<>(1);
 546         hashtableFilter.put(key, value);
 547 
 548         return (getProviders(hashtableFilter));
 549     }
 550 
 551     /**
 552      * Returns an array containing all installed providers that satisfy the
 553      * specified selection criteria, or null if no such providers have been
 554      * installed. The returned providers are ordered
 555      * according to their
 556      * {@linkplain #insertProviderAt(java.security.Provider, int)
 557      * preference order}.
 558      *
 559      * <p>The selection criteria are represented by a map.
 560      * Each map entry represents a selection criterion.
 561      * A provider is selected iff it satisfies all selection
 562      * criteria. The key for any entry in such a map must be in one of the
 563      * following two formats:
 564      * <ul>
 565      * <li> <i>{@literal <crypto_service>.<algorithm_or_type>}</i>
 566      * <p> The cryptographic service name must not contain any dots.
 567      * <p> The value associated with the key must be an empty string.
 568      * <p> A provider
 569      * satisfies this selection criterion iff the provider implements the
 570      * specified algorithm or type for the specified cryptographic service.
 571      * <li>  <i>{@literal <crypto_service>}.
 572      * {@literal <algorithm_or_type> <attribute_name>}</i>
 573      * <p> The cryptographic service name must not contain any dots. There
 574      * must be one or more space characters between the
 575      * <i>{@literal <algorithm_or_type>}</i>
 576      * and the <i>{@literal <attribute_name>}</i>.
 577      * <p> The value associated with the key must be a non-empty string.
 578      * A provider satisfies this selection criterion iff the
 579      * provider implements the specified algorithm or type for the specified
 580      * cryptographic service and its implementation meets the
 581      * constraint expressed by the specified attribute name/value pair.
 582      * </ul>
 583      *
 584      * <p> See the <a href=
 585      * "../../../technotes/guides/security/StandardNames.html">
 586      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
 587      * for information about standard cryptographic service names, standard
 588      * algorithm names and standard attribute names.
 589      *
 590      * @param filter the criteria for selecting
 591      * providers. The filter is case-insensitive.
 592      *
 593      * @return all the installed providers that satisfy the selection
 594      * criteria, or null if no such providers have been installed.
 595      *
 596      * @throws InvalidParameterException
 597      *         if the filter is not in the required format
 598      * @throws NullPointerException if filter is null
 599      *
 600      * @see #getProviders(java.lang.String)
 601      * @since 1.3
 602      */
 603     public static Provider[] getProviders(Map<String,String> filter) {
 604         // Get all installed providers first.
 605         // Then only return those providers who satisfy the selection criteria.
 606         Provider[] allProviders = Security.getProviders();
 607         Set<String> keySet = filter.keySet();
 608         LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
 609 
 610         // Returns all installed providers
 611         // if the selection criteria is null.
 612         if ((keySet == null) || (allProviders == null)) {
 613             return allProviders;
 614         }
 615 
 616         boolean firstSearch = true;
 617 
 618         // For each selection criterion, remove providers
 619         // which don't satisfy the criterion from the candidate set.
 620         for (Iterator<String> ite = keySet.iterator(); ite.hasNext(); ) {
 621             String key = ite.next();
 622             String value = filter.get(key);
 623 
 624             LinkedHashSet<Provider> newCandidates = getAllQualifyingCandidates(key, value,
 625                                                                allProviders);
 626             if (firstSearch) {
 627                 candidates = newCandidates;
 628                 firstSearch = false;
 629             }
 630 
 631             if ((newCandidates != null) && !newCandidates.isEmpty()) {
 632                 // For each provider in the candidates set, if it
 633                 // isn't in the newCandidate set, we should remove
 634                 // it from the candidate set.
 635                 for (Iterator<Provider> cansIte = candidates.iterator();
 636                      cansIte.hasNext(); ) {
 637                     Provider prov = cansIte.next();
 638                     if (!newCandidates.contains(prov)) {
 639                         cansIte.remove();
 640                     }
 641                 }
 642             } else {
 643                 candidates = null;
 644                 break;
 645             }
 646         }
 647 
 648         if ((candidates == null) || (candidates.isEmpty()))
 649             return null;
 650 
 651         Object[] candidatesArray = candidates.toArray();
 652         Provider[] result = new Provider[candidatesArray.length];
 653 
 654         for (int i = 0; i < result.length; i++) {
 655             result[i] = (Provider)candidatesArray[i];
 656         }
 657 
 658         return result;
 659     }
 660 
 661     // Map containing cached Spi Class objects of the specified type
 662     private static final Map<String, Class<?>> spiMap =
 663             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} 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} 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}  method is called with a
 740      * {@code java.security.SecurityPermission("getProperty."+key)}
 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 {@link
 750      *          java.lang.SecurityManager#checkPermission} 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} method is called with a
 775      * {@code java.security.SecurityPermission("setProperty."+key)}
 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 {@link
 785      *          java.lang.SecurityManager#checkPermission} 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     private static void invalidateSMCache(String key) {
 806 
 807         final boolean pa = key.equals("package.access");
 808         final boolean pd = key.equals("package.definition");
 809 
 810         if (pa || pd) {
 811             SharedSecrets.getJavaLangAccess().invalidatePackageAccessCache();
 812         }
 813     }
 814 
 815     private static void check(String directive) {
 816         SecurityManager security = System.getSecurityManager();
 817         if (security != null) {
 818             security.checkSecurityAccess(directive);
 819         }
 820     }
 821 
 822     private static void checkInsertProvider(String name) {
 823         SecurityManager security = System.getSecurityManager();
 824         if (security != null) {
 825             try {
 826                 security.checkSecurityAccess("insertProvider");
 827             } catch (SecurityException se1) {
 828                 try {
 829                     security.checkSecurityAccess("insertProvider." + name);
 830                 } catch (SecurityException se2) {
 831                     // throw first exception, but add second to suppressed
 832                     se1.addSuppressed(se2);
 833                     throw se1;
 834                 }
 835             }
 836         }
 837     }
 838 
 839     /*
 840     * Returns all providers who satisfy the specified
 841     * criterion.
 842     */
 843     private static LinkedHashSet<Provider> getAllQualifyingCandidates(
 844                                                 String filterKey,
 845                                                 String filterValue,
 846                                                 Provider[] allProviders) {
 847         String[] filterComponents = getFilterComponents(filterKey,
 848                                                         filterValue);
 849 
 850         // The first component is the service name.
 851         // The second is the algorithm name.
 852         // If the third isn't null, that is the attrinute name.
 853         String serviceName = filterComponents[0];
 854         String algName = filterComponents[1];
 855         String attrName = filterComponents[2];
 856 
 857         return getProvidersNotUsingCache(serviceName, algName, attrName,
 858                                          filterValue, allProviders);
 859     }
 860 
 861     private static LinkedHashSet<Provider> getProvidersNotUsingCache(
 862                                                 String serviceName,
 863                                                 String algName,
 864                                                 String attrName,
 865                                                 String filterValue,
 866                                                 Provider[] allProviders) {
 867         LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
 868         for (int i = 0; i < allProviders.length; i++) {
 869             if (isCriterionSatisfied(allProviders[i], serviceName,
 870                                      algName,
 871                                      attrName, filterValue)) {
 872                 candidates.add(allProviders[i]);
 873             }
 874         }
 875         return candidates;
 876     }
 877 
 878     /*
 879      * Returns true if the given provider satisfies
 880      * the selection criterion key:value.
 881      */
 882     private static boolean isCriterionSatisfied(Provider prov,
 883                                                 String serviceName,
 884                                                 String algName,
 885                                                 String attrName,
 886                                                 String filterValue) {
 887         String key = serviceName + '.' + algName;
 888 
 889         if (attrName != null) {
 890             key += ' ' + attrName;
 891         }
 892         // Check whether the provider has a property
 893         // whose key is the same as the given key.
 894         String propValue = getProviderProperty(key, prov);
 895 
 896         if (propValue == null) {
 897             // Check whether we have an alias instead
 898             // of a standard name in the key.
 899             String standardName = getProviderProperty("Alg.Alias." +
 900                                                       serviceName + "." +
 901                                                       algName,
 902                                                       prov);
 903             if (standardName != null) {
 904                 key = serviceName + "." + standardName;
 905 
 906                 if (attrName != null) {
 907                     key += ' ' + attrName;
 908                 }
 909 
 910                 propValue = getProviderProperty(key, prov);
 911             }
 912 
 913             if (propValue == null) {
 914                 // The provider doesn't have the given
 915                 // key in its property list.
 916                 return false;
 917             }
 918         }
 919 
 920         // If the key is in the format of:
 921         // <crypto_service>.<algorithm_or_type>,
 922         // there is no need to check the value.
 923 
 924         if (attrName == null) {
 925             return true;
 926         }
 927 
 928         // If we get here, the key must be in the
 929         // format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
 930         if (isStandardAttr(attrName)) {
 931             return isConstraintSatisfied(attrName, filterValue, propValue);
 932         } else {
 933             return filterValue.equalsIgnoreCase(propValue);
 934         }
 935     }
 936 
 937     /*
 938      * Returns true if the attribute is a standard attribute;
 939      * otherwise, returns false.
 940      */
 941     private static boolean isStandardAttr(String attribute) {
 942         // For now, we just have two standard attributes:
 943         // KeySize and ImplementedIn.
 944         if (attribute.equalsIgnoreCase("KeySize"))
 945             return true;
 946 
 947         if (attribute.equalsIgnoreCase("ImplementedIn"))
 948             return true;
 949 
 950         return false;
 951     }
 952 
 953     /*
 954      * Returns true if the requested attribute value is supported;
 955      * otherwise, returns false.
 956      */
 957     private static boolean isConstraintSatisfied(String attribute,
 958                                                  String value,
 959                                                  String prop) {
 960         // For KeySize, prop is the max key size the
 961         // provider supports for a specific <crypto_service>.<algorithm>.
 962         if (attribute.equalsIgnoreCase("KeySize")) {
 963             int requestedSize = Integer.parseInt(value);
 964             int maxSize = Integer.parseInt(prop);
 965             if (requestedSize <= maxSize) {
 966                 return true;
 967             } else {
 968                 return false;
 969             }
 970         }
 971 
 972         // For Type, prop is the type of the implementation
 973         // for a specific <crypto service>.<algorithm>.
 974         if (attribute.equalsIgnoreCase("ImplementedIn")) {
 975             return value.equalsIgnoreCase(prop);
 976         }
 977 
 978         return false;
 979     }
 980 
 981     static String[] getFilterComponents(String filterKey, String filterValue) {
 982         int algIndex = filterKey.indexOf('.');
 983 
 984         if (algIndex < 0) {
 985             // There must be a dot in the filter, and the dot
 986             // shouldn't be at the beginning of this string.
 987             throw new InvalidParameterException("Invalid filter");
 988         }
 989 
 990         String serviceName = filterKey.substring(0, algIndex);
 991         String algName = null;
 992         String attrName = null;
 993 
 994         if (filterValue.length() == 0) {
 995             // The filterValue is an empty string. So the filterKey
 996             // should be in the format of <crypto_service>.<algorithm_or_type>.
 997             algName = filterKey.substring(algIndex + 1).trim();
 998             if (algName.length() == 0) {
 999                 // There must be a algorithm or type name.
1000                 throw new InvalidParameterException("Invalid filter");
1001             }
1002         } else {
1003             // The filterValue is a non-empty string. So the filterKey must be
1004             // in the format of
1005             // <crypto_service>.<algorithm_or_type> <attribute_name>
1006             int attrIndex = filterKey.indexOf(' ');
1007 
1008             if (attrIndex == -1) {
1009                 // There is no attribute name in the filter.
1010                 throw new InvalidParameterException("Invalid filter");
1011             } else {
1012                 attrName = filterKey.substring(attrIndex + 1).trim();
1013                 if (attrName.length() == 0) {
1014                     // There is no attribute name in the filter.
1015                     throw new InvalidParameterException("Invalid filter");
1016                 }
1017             }
1018 
1019             // There must be an algorithm name in the filter.
1020             if ((attrIndex < algIndex) ||
1021                 (algIndex == attrIndex - 1)) {
1022                 throw new InvalidParameterException("Invalid filter");
1023             } else {
1024                 algName = filterKey.substring(algIndex + 1, attrIndex);
1025             }
1026         }
1027 
1028         String[] result = new String[3];
1029         result[0] = serviceName;
1030         result[1] = algName;
1031         result[2] = attrName;
1032 
1033         return result;
1034     }
1035 
1036     /**
1037      * Returns a Set of Strings containing the names of all available
1038      * algorithms or types for the specified Java cryptographic service
1039      * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns
1040      * an empty Set if there is no provider that supports the
1041      * specified service or if serviceName is null. For a complete list
1042      * of Java cryptographic services, please see the
1043      * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">Java
1044      * Cryptography Architecture API Specification &amp; Reference</a>.
1045      * Note: the returned set is immutable.
1046      *
1047      * @param serviceName the name of the Java cryptographic
1048      * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
1049      * Note: this parameter is case-insensitive.
1050      *
1051      * @return a Set of Strings containing the names of all available
1052      * algorithms or types for the specified Java cryptographic service
1053      * or an empty set if no provider supports the specified service.
1054      *
1055      * @since 1.4
1056      **/
1057     public static Set<String> getAlgorithms(String serviceName) {
1058 
1059         if ((serviceName == null) || (serviceName.length() == 0) ||
1060             (serviceName.endsWith("."))) {
1061             return Collections.emptySet();
1062         }
1063 
1064         HashSet<String> result = new HashSet<>();
1065         Provider[] providers = Security.getProviders();
1066 
1067         for (int i = 0; i < providers.length; i++) {
1068             // Check the keys for each provider.
1069             for (Enumeration<Object> e = providers[i].keys();
1070                                                 e.hasMoreElements(); ) {
1071                 String currentKey =
1072                         ((String)e.nextElement()).toUpperCase(Locale.ENGLISH);
1073                 if (currentKey.startsWith(
1074                         serviceName.toUpperCase(Locale.ENGLISH))) {
1075                     // We should skip the currentKey if it contains a
1076                     // whitespace. The reason is: such an entry in the
1077                     // provider property contains attributes for the
1078                     // implementation of an algorithm. We are only interested
1079                     // in entries which lead to the implementation
1080                     // classes.
1081                     if (currentKey.indexOf(' ') < 0) {
1082                         result.add(currentKey.substring(
1083                                                 serviceName.length() + 1));
1084                     }
1085                 }
1086             }
1087         }
1088         return Collections.unmodifiableSet(result);
1089     }
1090 }