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