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