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