Home | History | Annotate | Download | only in security
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package java.security;
     28 
     29 import java.io.*;
     30 import java.util.*;
     31 import java.util.concurrent.atomic.AtomicBoolean;
     32 
     33 import static java.util.Locale.ENGLISH;
     34 
     35 import java.lang.ref.*;
     36 import java.lang.reflect.*;
     37 import java.security.Security;
     38 import java.util.function.BiConsumer;
     39 import java.util.function.BiFunction;
     40 import java.util.function.Function;
     41 
     42 /**
     43  * This class represents a "provider" for the
     44  * Java Security API, where a provider implements some or all parts of
     45  * Java Security. Services that a provider may implement include:
     46  *
     47  * <ul>
     48  *
     49  * <li>Algorithms (such as DSA, RSA, MD5 or SHA-1).
     50  *
     51  * <li>Key generation, conversion, and management facilities (such as for
     52  * algorithm-specific keys).
     53  *
     54  *</ul>
     55  *
     56  * <p>Each provider has a name and a version number, and is configured
     57  * in each runtime it is installed in.
     58  *
     59  * <p>See <a href =
     60  * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html#Provider">The Provider Class</a>
     61  * in the "Java Cryptography Architecture API Specification &amp; Reference"
     62  * for information about how a particular type of provider, the
     63  * cryptographic service provider, works and is installed. However,
     64  * please note that a provider can be used to implement any security
     65  * service in Java that uses a pluggable architecture with a choice
     66  * of implementations that fit underneath.
     67  *
     68  * <p>Some provider implementations may encounter unrecoverable internal
     69  * errors during their operation, for example a failure to communicate with a
     70  * security token. A {@link ProviderException} should be used to indicate
     71  * such errors.
     72  *
     73  * <p>The service type {@code Provider} is reserved for use by the
     74  * security framework. Services of this type cannot be added, removed,
     75  * or modified by applications.
     76  * The following attributes are automatically placed in each Provider object:
     77  * <table cellspacing=4>
     78  * <caption><b>Attributes Automatically Placed in a Provider Object</b></caption>
     79  * <tr><th>Name</th><th>Value</th>
     80  * <tr><td>{@code Provider.id name}</td>
     81   *    <td>{@code String.valueOf(provider.getName())}</td>
     82  * <tr><td>{@code Provider.id version}</td>
     83  *     <td>{@code String.valueOf(provider.getVersion())}</td>
     84  * <tr><td>{@code Provider.id info}</td>
     85        <td>{@code String.valueOf(provider.getInfo())}</td>
     86  * <tr><td>{@code Provider.id className}</td>
     87  *     <td>{@code provider.getClass().getName()}</td>
     88  * </table>
     89  *
     90  * @author Benjamin Renaud
     91  * @author Andreas Sterbenz
     92  */
     93 public abstract class Provider extends Properties {
     94 
     95     // Declare serialVersionUID to be compatible with JDK1.1
     96     static final long serialVersionUID = -4298000515446427739L;
     97 
     98     // Android-added: Provider registration
     99     // Marking a provider as "registered" makes it change the security version when
    100     // changes to it are made.  As of 2017-05-22 this is only used in ProviderTest.
    101     // TODO: Change ProviderTest to no longer require this mechanism
    102     private volatile boolean registered = false;
    103 
    104     private static final sun.security.util.Debug debug =
    105         sun.security.util.Debug.getInstance
    106         ("provider", "Provider");
    107 
    108     /**
    109      * The provider name.
    110      *
    111      * @serial
    112      */
    113     private String name;
    114 
    115     /**
    116      * A description of the provider and its services.
    117      *
    118      * @serial
    119      */
    120     private String info;
    121 
    122     /**
    123      * The provider version number.
    124      *
    125      * @serial
    126      */
    127     private double version;
    128 
    129 
    130     private transient Set<Map.Entry<Object,Object>> entrySet = null;
    131     private transient int entrySetCallCount = 0;
    132 
    133     private transient boolean initialized;
    134 
    135     /**
    136      * Constructs a provider with the specified name, version number,
    137      * and information.
    138      *
    139      * @param name the provider name.
    140      *
    141      * @param version the provider version number.
    142      *
    143      * @param info a description of the provider and its services.
    144      */
    145     protected Provider(String name, double version, String info) {
    146         this.name = name;
    147         this.version = version;
    148         this.info = info;
    149         putId();
    150         initialized = true;
    151     }
    152 
    153     /**
    154      * Returns the name of this provider.
    155      *
    156      * @return the name of this provider.
    157      */
    158     public String getName() {
    159         return name;
    160     }
    161 
    162     /**
    163      * Returns the version number for this provider.
    164      *
    165      * @return the version number for this provider.
    166      */
    167     public double getVersion() {
    168         return version;
    169     }
    170 
    171     /**
    172      * Returns a human-readable description of the provider and its
    173      * services.  This may return an HTML page, with relevant links.
    174      *
    175      * @return a description of the provider and its services.
    176      */
    177     public String getInfo() {
    178         return info;
    179     }
    180 
    181     /**
    182      * Returns a string with the name and the version number
    183      * of this provider.
    184      *
    185      * @return the string with the name and the version number
    186      * for this provider.
    187      */
    188     public String toString() {
    189         return name + " version " + version;
    190     }
    191 
    192     /*
    193      * override the following methods to ensure that provider
    194      * information can only be changed if the caller has the appropriate
    195      * permissions.
    196      */
    197 
    198     /**
    199      * Clears this provider so that it no longer contains the properties
    200      * used to look up facilities implemented by the provider.
    201      *
    202      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    203      * method is called with the string {@code "clearProviderProperties."+name}
    204      * (where {@code name} is the provider name) to see if it's ok to clear
    205      * this provider.
    206      *
    207      * @throws  SecurityException
    208      *          if a security manager exists and its {@link
    209      *          java.lang.SecurityManager#checkSecurityAccess} method
    210      *          denies access to clear this provider
    211      *
    212      * @since 1.2
    213      */
    214     @Override
    215     public synchronized void clear() {
    216         check("clearProviderProperties."+name);
    217         if (debug != null) {
    218             debug.println("Remove " + name + " provider properties");
    219         }
    220         implClear();
    221     }
    222 
    223     /**
    224      * Reads a property list (key and element pairs) from the input stream.
    225      *
    226      * @param inStream   the input stream.
    227      * @exception  IOException  if an error occurred when reading from the
    228      *               input stream.
    229      * @see java.util.Properties#load
    230      */
    231     @Override
    232     public synchronized void load(InputStream inStream) throws IOException {
    233         check("putProviderProperty."+name);
    234         if (debug != null) {
    235             debug.println("Load " + name + " provider properties");
    236         }
    237         Properties tempProperties = new Properties();
    238         tempProperties.load(inStream);
    239         implPutAll(tempProperties);
    240     }
    241 
    242     /**
    243      * Copies all of the mappings from the specified Map to this provider.
    244      * These mappings will replace any properties that this provider had
    245      * for any of the keys currently in the specified Map.
    246      *
    247      * @since 1.2
    248      */
    249     @Override
    250     public synchronized void putAll(Map<?,?> t) {
    251         check("putProviderProperty."+name);
    252         if (debug != null) {
    253             debug.println("Put all " + name + " provider properties");
    254         }
    255         implPutAll(t);
    256     }
    257 
    258     /**
    259      * Returns an unmodifiable Set view of the property entries contained
    260      * in this Provider.
    261      *
    262      * @see   java.util.Map.Entry
    263      * @since 1.2
    264      */
    265     @Override
    266     public synchronized Set<Map.Entry<Object,Object>> entrySet() {
    267         checkInitialized();
    268         if (entrySet == null) {
    269             if (entrySetCallCount++ == 0)  // Initial call
    270                 entrySet = Collections.unmodifiableMap(this).entrySet();
    271             else
    272                 return super.entrySet();   // Recursive call
    273         }
    274 
    275         // This exception will be thrown if the implementation of
    276         // Collections.unmodifiableMap.entrySet() is changed such that it
    277         // no longer calls entrySet() on the backing Map.  (Provider's
    278         // entrySet implementation depends on this "implementation detail",
    279         // which is unlikely to change.
    280         if (entrySetCallCount != 2)
    281             throw new RuntimeException("Internal error.");
    282 
    283         return entrySet;
    284     }
    285 
    286     /**
    287      * Returns an unmodifiable Set view of the property keys contained in
    288      * this provider.
    289      *
    290      * @since 1.2
    291      */
    292     @Override
    293     public Set<Object> keySet() {
    294         checkInitialized();
    295         return Collections.unmodifiableSet(super.keySet());
    296     }
    297 
    298     /**
    299      * Returns an unmodifiable Collection view of the property values
    300      * contained in this provider.
    301      *
    302      * @since 1.2
    303      */
    304     @Override
    305     public Collection<Object> values() {
    306         checkInitialized();
    307         return Collections.unmodifiableCollection(super.values());
    308     }
    309 
    310     /**
    311      * Sets the {@code key} property to have the specified
    312      * {@code value}.
    313      *
    314      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    315      * method is called with the string {@code "putProviderProperty."+name},
    316      * where {@code name} is the provider name, to see if it's ok to set this
    317      * provider's property values.
    318      *
    319      * @throws  SecurityException
    320      *          if a security manager exists and its {@link
    321      *          java.lang.SecurityManager#checkSecurityAccess} method
    322      *          denies access to set property values.
    323      *
    324      * @since 1.2
    325      */
    326     @Override
    327     public synchronized Object put(Object key, Object value) {
    328         check("putProviderProperty."+name);
    329         if (debug != null) {
    330             debug.println("Set " + name + " provider property [" +
    331                           key + "/" + value +"]");
    332         }
    333         return implPut(key, value);
    334     }
    335 
    336     /**
    337      * If the specified key is not already associated with a value (or is mapped
    338      * to {@code null}) associates it with the given value and returns
    339      * {@code null}, else returns the current value.
    340      *
    341      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    342      * method is called with the string {@code "putProviderProperty."+name},
    343      * where {@code name} is the provider name, to see if it's ok to set this
    344      * provider's property values.
    345      *
    346      * @throws  SecurityException
    347      *          if a security manager exists and its {@link
    348      *          java.lang.SecurityManager#checkSecurityAccess} method
    349      *          denies access to set property values.
    350      *
    351      * @since 1.8
    352      */
    353     @Override
    354     public synchronized Object putIfAbsent(Object key, Object value) {
    355         check("putProviderProperty."+name);
    356         if (debug != null) {
    357             debug.println("Set " + name + " provider property [" +
    358                           key + "/" + value +"]");
    359         }
    360         return implPutIfAbsent(key, value);
    361     }
    362 
    363     /**
    364      * Removes the {@code key} property (and its corresponding
    365      * {@code value}).
    366      *
    367      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    368      * method is called with the string {@code "removeProviderProperty."+name},
    369      * where {@code name} is the provider name, to see if it's ok to remove this
    370      * provider's properties.
    371      *
    372      * @throws  SecurityException
    373      *          if a security manager exists and its {@link
    374      *          java.lang.SecurityManager#checkSecurityAccess} method
    375      *          denies access to remove this provider's properties.
    376      *
    377      * @since 1.2
    378      */
    379     @Override
    380     public synchronized Object remove(Object key) {
    381         check("removeProviderProperty."+name);
    382         if (debug != null) {
    383             debug.println("Remove " + name + " provider property " + key);
    384         }
    385         return implRemove(key);
    386     }
    387 
    388     /**
    389      * Removes the entry for the specified key only if it is currently
    390      * mapped to the specified value.
    391      *
    392      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    393      * method is called with the string {@code "removeProviderProperty."+name},
    394      * where {@code name} is the provider name, to see if it's ok to remove this
    395      * provider's properties.
    396      *
    397      * @throws  SecurityException
    398      *          if a security manager exists and its {@link
    399      *          java.lang.SecurityManager#checkSecurityAccess} method
    400      *          denies access to remove this provider's properties.
    401      *
    402      * @since 1.8
    403      */
    404     @Override
    405     public synchronized boolean remove(Object key, Object value) {
    406         check("removeProviderProperty."+name);
    407         if (debug != null) {
    408             debug.println("Remove " + name + " provider property " + key);
    409         }
    410         return implRemove(key, value);
    411     }
    412 
    413     /**
    414      * Replaces the entry for the specified key only if currently
    415      * mapped to the specified value.
    416      *
    417      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    418      * method is called with the string {@code "putProviderProperty."+name},
    419      * where {@code name} is the provider name, to see if it's ok to set this
    420      * provider's property values.
    421      *
    422      * @throws  SecurityException
    423      *          if a security manager exists and its {@link
    424      *          java.lang.SecurityManager#checkSecurityAccess} method
    425      *          denies access to set property values.
    426      *
    427      * @since 1.8
    428      */
    429     @Override
    430     public synchronized boolean replace(Object key, Object oldValue,
    431             Object newValue) {
    432         check("putProviderProperty." + name);
    433 
    434         if (debug != null) {
    435             debug.println("Replace " + name + " provider property " + key);
    436         }
    437         return implReplace(key, oldValue, newValue);
    438     }
    439 
    440     /**
    441      * Replaces the entry for the specified key only if it is
    442      * currently mapped to some value.
    443      *
    444      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    445      * method is called with the string {@code "putProviderProperty."+name},
    446      * where {@code name} is the provider name, to see if it's ok to set this
    447      * provider's property values.
    448      *
    449      * @throws  SecurityException
    450      *          if a security manager exists and its {@link
    451      *          java.lang.SecurityManager#checkSecurityAccess} method
    452      *          denies access to set property values.
    453      *
    454      * @since 1.8
    455      */
    456     @Override
    457     public synchronized Object replace(Object key, Object value) {
    458         check("putProviderProperty." + name);
    459 
    460         if (debug != null) {
    461             debug.println("Replace " + name + " provider property " + key);
    462         }
    463         return implReplace(key, value);
    464     }
    465 
    466     /**
    467      * Replaces each entry's value with the result of invoking the given
    468      * function on that entry, in the order entries are returned by an entry
    469      * set iterator, until all entries have been processed or the function
    470      * throws an exception.
    471      *
    472      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    473      * method is called with the string {@code "putProviderProperty."+name},
    474      * where {@code name} is the provider name, to see if it's ok to set this
    475      * provider's property values.
    476      *
    477      * @throws  SecurityException
    478      *          if a security manager exists and its {@link
    479      *          java.lang.SecurityManager#checkSecurityAccess} method
    480      *          denies access to set property values.
    481      *
    482      * @since 1.8
    483      */
    484     @Override
    485     public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function) {
    486         check("putProviderProperty." + name);
    487 
    488         if (debug != null) {
    489             debug.println("ReplaceAll " + name + " provider property ");
    490         }
    491         implReplaceAll(function);
    492     }
    493 
    494     /**
    495      * Attempts to compute a mapping for the specified key and its
    496      * current mapped value (or {@code null} if there is no current
    497      * mapping).
    498      *
    499      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    500      * method is called with the strings {@code "putProviderProperty."+name}
    501      * and {@code "removeProviderProperty."+name}, where {@code name} is the
    502      * provider name, to see if it's ok to set this provider's property values
    503      * and remove this provider's properties.
    504      *
    505      * @throws  SecurityException
    506      *          if a security manager exists and its {@link
    507      *          java.lang.SecurityManager#checkSecurityAccess} method
    508      *          denies access to set property values or remove properties.
    509      *
    510      * @since 1.8
    511      */
    512     @Override
    513     public synchronized Object compute(Object key,
    514         BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
    515         check("putProviderProperty." + name);
    516         check("removeProviderProperty" + name);
    517 
    518         if (debug != null) {
    519             debug.println("Compute " + name + " provider property " + key);
    520         }
    521         return implCompute(key, remappingFunction);
    522     }
    523 
    524     /**
    525      * If the specified key is not already associated with a value (or
    526      * is mapped to {@code null}), attempts to compute its value using
    527      * the given mapping function and enters it into this map unless
    528      * {@code null}.
    529      *
    530      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    531      * method is called with the strings {@code "putProviderProperty."+name}
    532      * and {@code "removeProviderProperty."+name}, where {@code name} is the
    533      * provider name, to see if it's ok to set this provider's property values
    534      * and remove this provider's properties.
    535      *
    536      * @throws  SecurityException
    537      *          if a security manager exists and its {@link
    538      *          java.lang.SecurityManager#checkSecurityAccess} method
    539      *          denies access to set property values and remove properties.
    540      *
    541      * @since 1.8
    542      */
    543     @Override
    544     public synchronized Object computeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction) {
    545         check("putProviderProperty." + name);
    546         check("removeProviderProperty" + name);
    547 
    548         if (debug != null) {
    549             debug.println("ComputeIfAbsent " + name + " provider property " +
    550                     key);
    551         }
    552         return implComputeIfAbsent(key, mappingFunction);
    553     }
    554 
    555     /**
    556      * If the value for the specified key is present and non-null, attempts to
    557      * compute a new mapping given the key and its current mapped value.
    558      *
    559      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    560      * method is called with the strings {@code "putProviderProperty."+name}
    561      * and {@code "removeProviderProperty."+name}, where {@code name} is the
    562      * provider name, to see if it's ok to set this provider's property values
    563      * and remove this provider's properties.
    564      *
    565      * @throws  SecurityException
    566      *          if a security manager exists and its {@link
    567      *          java.lang.SecurityManager#checkSecurityAccess} method
    568      *          denies access to set property values or remove properties.
    569      *
    570      * @since 1.8
    571      */
    572     @Override
    573     public synchronized Object computeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
    574         check("putProviderProperty." + name);
    575         check("removeProviderProperty" + name);
    576 
    577         if (debug != null) {
    578             debug.println("ComputeIfPresent " + name + " provider property " +
    579                     key);
    580         }
    581         return implComputeIfPresent(key, remappingFunction);
    582     }
    583 
    584     /**
    585      * If the specified key is not already associated with a value or is
    586      * associated with null, associates it with the given value. Otherwise,
    587      * replaces the value with the results of the given remapping function,
    588      * or removes if the result is null. This method may be of use when
    589      * combining multiple mapped values for a key.
    590      *
    591      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    592      * method is called with the strings {@code "putProviderProperty."+name}
    593      * and {@code "removeProviderProperty."+name}, where {@code name} is the
    594      * provider name, to see if it's ok to set this provider's property values
    595      * and remove this provider's properties.
    596      *
    597      * @throws  SecurityException
    598      *          if a security manager exists and its {@link
    599      *          java.lang.SecurityManager#checkSecurityAccess} method
    600      *          denies access to set property values or remove properties.
    601      *
    602      * @since 1.8
    603      */
    604     @Override
    605     public synchronized Object merge(Object key, Object value,  BiFunction<? super Object, ? super Object, ? extends Object>  remappingFunction) {
    606         check("putProviderProperty." + name);
    607         check("removeProviderProperty" + name);
    608 
    609         if (debug != null) {
    610             debug.println("Merge " + name + " provider property " + key);
    611         }
    612         return implMerge(key, value, remappingFunction);
    613     }
    614 
    615     // let javadoc show doc from superclass
    616     @Override
    617     public Object get(Object key) {
    618         checkInitialized();
    619         return super.get(key);
    620     }
    621     /**
    622      * @since 1.8
    623      */
    624     @Override
    625     public synchronized Object getOrDefault(Object key, Object defaultValue) {
    626         checkInitialized();
    627         return super.getOrDefault(key, defaultValue);
    628     }
    629 
    630     /**
    631      * @since 1.8
    632      */
    633     @Override
    634     public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
    635         checkInitialized();
    636         super.forEach(action);
    637     }
    638 
    639     // let javadoc show doc from superclass
    640     @Override
    641     public Enumeration<Object> keys() {
    642         checkInitialized();
    643         return super.keys();
    644     }
    645 
    646     // let javadoc show doc from superclass
    647     @Override
    648     public Enumeration<Object> elements() {
    649         checkInitialized();
    650         return super.elements();
    651     }
    652 
    653     // let javadoc show doc from superclass
    654     public String getProperty(String key) {
    655         checkInitialized();
    656         return super.getProperty(key);
    657     }
    658 
    659     private void checkInitialized() {
    660         if (!initialized) {
    661             throw new IllegalStateException();
    662         }
    663     }
    664 
    665     private void check(String directive) {
    666         checkInitialized();
    667         SecurityManager security = System.getSecurityManager();
    668         if (security != null) {
    669             security.checkSecurityAccess(directive);
    670         }
    671     }
    672 
    673     // legacy properties changed since last call to any services method?
    674     private transient boolean legacyChanged;
    675     // serviceMap changed since last call to getServices()
    676     private transient boolean servicesChanged;
    677 
    678     // Map<String,String>
    679     private transient Map<String,String> legacyStrings;
    680 
    681     // Map<ServiceKey,Service>
    682     // used for services added via putService(), initialized on demand
    683     private transient Map<ServiceKey,Service> serviceMap;
    684 
    685     // Map<ServiceKey,Service>
    686     // used for services added via legacy methods, init on demand
    687     private transient Map<ServiceKey,Service> legacyMap;
    688 
    689     // Set<Service>
    690     // Unmodifiable set of all services. Initialized on demand.
    691     private transient Set<Service> serviceSet;
    692 
    693     // register the id attributes for this provider
    694     // this is to ensure that equals() and hashCode() do not incorrectly
    695     // report to different provider objects as the same
    696     private void putId() {
    697         // note: name and info may be null
    698         super.put("Provider.id name", String.valueOf(name));
    699         super.put("Provider.id version", String.valueOf(version));
    700         super.put("Provider.id info", String.valueOf(info));
    701         super.put("Provider.id className", this.getClass().getName());
    702     }
    703 
    704     private void readObject(ObjectInputStream in)
    705                 throws IOException, ClassNotFoundException {
    706         // Android-added: Provider registration
    707         registered = false;
    708         Map<Object,Object> copy = new HashMap<>();
    709         for (Map.Entry<Object,Object> entry : super.entrySet()) {
    710             copy.put(entry.getKey(), entry.getValue());
    711         }
    712         defaults = null;
    713         in.defaultReadObject();
    714         implClear();
    715         initialized = true;
    716         putAll(copy);
    717     }
    718 
    719     private boolean checkLegacy(Object key) {
    720         // Android-added: Provider registration
    721         if (registered) {
    722             Security.increaseVersion();
    723         }
    724         String keyString = (String)key;
    725         if (keyString.startsWith("Provider.")) {
    726             return false;
    727         }
    728 
    729         legacyChanged = true;
    730         if (legacyStrings == null) {
    731             legacyStrings = new LinkedHashMap<String,String>();
    732         }
    733         return true;
    734     }
    735 
    736     /**
    737      * Copies all of the mappings from the specified Map to this provider.
    738      * Internal method to be called AFTER the security check has been
    739      * performed.
    740      */
    741     private void implPutAll(Map<?,?> t) {
    742         for (Map.Entry<?,?> e : t.entrySet()) {
    743             implPut(e.getKey(), e.getValue());
    744         }
    745         // Android-added: Provider registration
    746         if (registered) {
    747             Security.increaseVersion();
    748         }
    749     }
    750 
    751     private Object implRemove(Object key) {
    752         if (key instanceof String) {
    753             if (!checkLegacy(key)) {
    754                 return null;
    755             }
    756             legacyStrings.remove((String)key);
    757         }
    758         return super.remove(key);
    759     }
    760 
    761     private boolean implRemove(Object key, Object value) {
    762         if (key instanceof String && value instanceof String) {
    763             if (!checkLegacy(key)) {
    764                 return false;
    765             }
    766             legacyStrings.remove((String)key, value);
    767         }
    768         return super.remove(key, value);
    769     }
    770 
    771     private boolean implReplace(Object key, Object oldValue, Object newValue) {
    772         if ((key instanceof String) && (oldValue instanceof String) &&
    773                 (newValue instanceof String)) {
    774             if (!checkLegacy(key)) {
    775                 return false;
    776             }
    777             legacyStrings.replace((String)key, (String)oldValue,
    778                     (String)newValue);
    779         }
    780         return super.replace(key, oldValue, newValue);
    781     }
    782 
    783     private Object implReplace(Object key, Object value) {
    784         if ((key instanceof String) && (value instanceof String)) {
    785             if (!checkLegacy(key)) {
    786                 return null;
    787             }
    788             legacyStrings.replace((String)key, (String)value);
    789         }
    790         return super.replace(key, value);
    791     }
    792 
    793     private void implReplaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function) {
    794         legacyChanged = true;
    795         if (legacyStrings == null) {
    796             legacyStrings = new LinkedHashMap<String,String>();
    797         } else {
    798             legacyStrings.replaceAll((BiFunction<? super String, ? super String, ? extends String>) function);
    799         }
    800         super.replaceAll(function);
    801     }
    802 
    803 
    804     private Object implMerge(Object key, Object value, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
    805         if ((key instanceof String) && (value instanceof String)) {
    806             if (!checkLegacy(key)) {
    807                 return null;
    808             }
    809             legacyStrings.merge((String)key, (String)value,
    810                     (BiFunction<? super String, ? super String, ? extends String>) remappingFunction);
    811         }
    812         return super.merge(key, value, remappingFunction);
    813     }
    814 
    815     private Object implCompute(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
    816         if (key instanceof String) {
    817             if (!checkLegacy(key)) {
    818                 return null;
    819             }
    820             // BEGIN Android-changed: was
    821             // legacyStrings.computeIfAbsent((String) key,
    822             //         (Function<? super String, ? extends String>) remappingFunction);
    823             // which cannot ever succeed as the cast from BiFunction to Function always fails
    824             legacyStrings.compute((String) key,
    825                     (BiFunction<? super String, ? super String, ? extends String>)
    826                             remappingFunction);
    827             // END Android-changed
    828         }
    829         return super.compute(key, remappingFunction);
    830     }
    831 
    832     private Object implComputeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction) {
    833         if (key instanceof String) {
    834             if (!checkLegacy(key)) {
    835                 return null;
    836             }
    837             legacyStrings.computeIfAbsent((String) key,
    838                     (Function<? super String, ? extends String>) mappingFunction);
    839         }
    840         return super.computeIfAbsent(key, mappingFunction);
    841     }
    842 
    843     private Object implComputeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
    844         if (key instanceof String) {
    845             if (!checkLegacy(key)) {
    846                 return null;
    847             }
    848             legacyStrings.computeIfPresent((String) key,
    849                     (BiFunction<? super String, ? super String, ? extends String>) remappingFunction);
    850         }
    851         return super.computeIfPresent(key, remappingFunction);
    852     }
    853 
    854     private Object implPut(Object key, Object value) {
    855         if ((key instanceof String) && (value instanceof String)) {
    856             if (!checkLegacy(key)) {
    857                 return null;
    858             }
    859             legacyStrings.put((String)key, (String)value);
    860         }
    861         return super.put(key, value);
    862     }
    863 
    864     private Object implPutIfAbsent(Object key, Object value) {
    865         if ((key instanceof String) && (value instanceof String)) {
    866             if (!checkLegacy(key)) {
    867                 return null;
    868             }
    869             legacyStrings.putIfAbsent((String)key, (String)value);
    870         }
    871         return super.putIfAbsent(key, value);
    872     }
    873 
    874     private void implClear() {
    875         if (legacyStrings != null) {
    876             legacyStrings.clear();
    877         }
    878         if (legacyMap != null) {
    879             legacyMap.clear();
    880         }
    881         if (serviceMap != null) {
    882             serviceMap.clear();
    883         }
    884         legacyChanged = false;
    885         servicesChanged = false;
    886         serviceSet = null;
    887         super.clear();
    888         putId();
    889         // Android-added: Provider registration
    890         if (registered) {
    891           Security.increaseVersion();
    892         }
    893     }
    894 
    895     // used as key in the serviceMap and legacyMap HashMaps
    896     private static class ServiceKey {
    897         private final String type;
    898         private final String algorithm;
    899         private final String originalAlgorithm;
    900         private ServiceKey(String type, String algorithm, boolean intern) {
    901             this.type = type;
    902             this.originalAlgorithm = algorithm;
    903             algorithm = algorithm.toUpperCase(ENGLISH);
    904             this.algorithm = intern ? algorithm.intern() : algorithm;
    905         }
    906         public int hashCode() {
    907             return type.hashCode() + algorithm.hashCode();
    908         }
    909         public boolean equals(Object obj) {
    910             if (this == obj) {
    911                 return true;
    912             }
    913             if (obj instanceof ServiceKey == false) {
    914                 return false;
    915             }
    916             ServiceKey other = (ServiceKey)obj;
    917             return this.type.equals(other.type)
    918                 && this.algorithm.equals(other.algorithm);
    919         }
    920         boolean matches(String type, String algorithm) {
    921             return (this.type == type) && (this.originalAlgorithm == algorithm);
    922         }
    923     }
    924 
    925     /**
    926      * Ensure all the legacy String properties are fully parsed into
    927      * service objects.
    928      */
    929     private void ensureLegacyParsed() {
    930         if ((legacyChanged == false) || (legacyStrings == null)) {
    931             return;
    932         }
    933         serviceSet = null;
    934         if (legacyMap == null) {
    935             legacyMap = new LinkedHashMap<ServiceKey,Service>();
    936         } else {
    937             legacyMap.clear();
    938         }
    939         for (Map.Entry<String,String> entry : legacyStrings.entrySet()) {
    940             parseLegacyPut(entry.getKey(), entry.getValue());
    941         }
    942         removeInvalidServices(legacyMap);
    943         legacyChanged = false;
    944     }
    945 
    946     /**
    947      * Remove all invalid services from the Map. Invalid services can only
    948      * occur if the legacy properties are inconsistent or incomplete.
    949      */
    950     private void removeInvalidServices(Map<ServiceKey,Service> map) {
    951         for (Iterator<Map.Entry<ServiceKey, Service>> t =
    952                 map.entrySet().iterator(); t.hasNext(); ) {
    953             Service s = t.next().getValue();
    954             if (s.isValid() == false) {
    955                 t.remove();
    956             }
    957         }
    958     }
    959 
    960     private String[] getTypeAndAlgorithm(String key) {
    961         int i = key.indexOf(".");
    962         if (i < 1) {
    963             if (debug != null) {
    964                 debug.println("Ignoring invalid entry in provider "
    965                         + name + ":" + key);
    966             }
    967             return null;
    968         }
    969         String type = key.substring(0, i);
    970         String alg = key.substring(i + 1);
    971         return new String[] {type, alg};
    972     }
    973 
    974     private final static String ALIAS_PREFIX = "Alg.Alias.";
    975     private final static String ALIAS_PREFIX_LOWER = "alg.alias.";
    976     private final static int ALIAS_LENGTH = ALIAS_PREFIX.length();
    977 
    978     private void parseLegacyPut(String name, String value) {
    979         if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
    980             // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
    981             // aliasKey ~ MessageDigest.SHA
    982             String stdAlg = value;
    983             String aliasKey = name.substring(ALIAS_LENGTH);
    984             String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
    985             if (typeAndAlg == null) {
    986                 return;
    987             }
    988             String type = getEngineName(typeAndAlg[0]);
    989             String aliasAlg = typeAndAlg[1].intern();
    990             ServiceKey key = new ServiceKey(type, stdAlg, true);
    991             Service s = legacyMap.get(key);
    992             if (s == null) {
    993                 s = new Service(this);
    994                 s.type = type;
    995                 s.algorithm = stdAlg;
    996                 legacyMap.put(key, s);
    997             }
    998             legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
    999             s.addAlias(aliasAlg);
   1000         } else {
   1001             String[] typeAndAlg = getTypeAndAlgorithm(name);
   1002             if (typeAndAlg == null) {
   1003                 return;
   1004             }
   1005             int i = typeAndAlg[1].indexOf(' ');
   1006             if (i == -1) {
   1007                 // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
   1008                 String type = getEngineName(typeAndAlg[0]);
   1009                 String stdAlg = typeAndAlg[1].intern();
   1010                 String className = value;
   1011                 ServiceKey key = new ServiceKey(type, stdAlg, true);
   1012                 Service s = legacyMap.get(key);
   1013                 if (s == null) {
   1014                     s = new Service(this);
   1015                     s.type = type;
   1016                     s.algorithm = stdAlg;
   1017                     legacyMap.put(key, s);
   1018                 }
   1019                 s.className = className;
   1020             } else { // attribute
   1021                 // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
   1022                 String attributeValue = value;
   1023                 String type = getEngineName(typeAndAlg[0]);
   1024                 String attributeString = typeAndAlg[1];
   1025                 String stdAlg = attributeString.substring(0, i).intern();
   1026                 String attributeName = attributeString.substring(i + 1);
   1027                 // kill additional spaces
   1028                 while (attributeName.startsWith(" ")) {
   1029                     attributeName = attributeName.substring(1);
   1030                 }
   1031                 attributeName = attributeName.intern();
   1032                 ServiceKey key = new ServiceKey(type, stdAlg, true);
   1033                 Service s = legacyMap.get(key);
   1034                 if (s == null) {
   1035                     s = new Service(this);
   1036                     s.type = type;
   1037                     s.algorithm = stdAlg;
   1038                     legacyMap.put(key, s);
   1039                 }
   1040                 s.addAttribute(attributeName, attributeValue);
   1041             }
   1042         }
   1043     }
   1044 
   1045     /**
   1046      * Get the service describing this Provider's implementation of the
   1047      * specified type of this algorithm or alias. If no such
   1048      * implementation exists, this method returns null. If there are two
   1049      * matching services, one added to this provider using
   1050      * {@link #putService putService()} and one added via {@link #put put()},
   1051      * the service added via {@link #putService putService()} is returned.
   1052      *
   1053      * @param type the type of {@link Service service} requested
   1054      * (for example, {@code MessageDigest})
   1055      * @param algorithm the case insensitive algorithm name (or alternate
   1056      * alias) of the service requested (for example, {@code SHA-1})
   1057      *
   1058      * @return the service describing this Provider's matching service
   1059      * or null if no such service exists
   1060      *
   1061      * @throws NullPointerException if type or algorithm is null
   1062      *
   1063      * @since 1.5
   1064      */
   1065     public synchronized Service getService(String type, String algorithm) {
   1066         checkInitialized();
   1067         // avoid allocating a new key object if possible
   1068         ServiceKey key = previousKey;
   1069         if (key.matches(type, algorithm) == false) {
   1070             key = new ServiceKey(type, algorithm, false);
   1071             previousKey = key;
   1072         }
   1073         if (serviceMap != null) {
   1074             Service service = serviceMap.get(key);
   1075             if (service != null) {
   1076                 return service;
   1077             }
   1078         }
   1079         ensureLegacyParsed();
   1080         return (legacyMap != null) ? legacyMap.get(key) : null;
   1081     }
   1082 
   1083     // ServiceKey from previous getService() call
   1084     // by re-using it if possible we avoid allocating a new object
   1085     // and the toUpperCase() call.
   1086     // re-use will occur e.g. as the framework traverses the provider
   1087     // list and queries each provider with the same values until it finds
   1088     // a matching service
   1089     private static volatile ServiceKey previousKey =
   1090                                             new ServiceKey("", "", false);
   1091 
   1092     /**
   1093      * Get an unmodifiable Set of all services supported by
   1094      * this Provider.
   1095      *
   1096      * @return an unmodifiable Set of all services supported by
   1097      * this Provider
   1098      *
   1099      * @since 1.5
   1100      */
   1101     public synchronized Set<Service> getServices() {
   1102         checkInitialized();
   1103         if (legacyChanged || servicesChanged) {
   1104             serviceSet = null;
   1105         }
   1106         if (serviceSet == null) {
   1107             ensureLegacyParsed();
   1108             Set<Service> set = new LinkedHashSet<>();
   1109             if (serviceMap != null) {
   1110                 set.addAll(serviceMap.values());
   1111             }
   1112             if (legacyMap != null) {
   1113                 set.addAll(legacyMap.values());
   1114             }
   1115             serviceSet = Collections.unmodifiableSet(set);
   1116             servicesChanged = false;
   1117         }
   1118         return serviceSet;
   1119     }
   1120 
   1121     /**
   1122      * Add a service. If a service of the same type with the same algorithm
   1123      * name exists and it was added using {@link #putService putService()},
   1124      * it is replaced by the new service.
   1125      * This method also places information about this service
   1126      * in the provider's Hashtable values in the format described in the
   1127      * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html">
   1128      * Java Cryptography Architecture API Specification &amp; Reference </a>.
   1129      *
   1130      * <p>Also, if there is a security manager, its
   1131      * {@code checkSecurityAccess} method is called with the string
   1132      * {@code "putProviderProperty."+name}, where {@code name} is
   1133      * the provider name, to see if it's ok to set this provider's property
   1134      * values. If the default implementation of {@code checkSecurityAccess}
   1135      * is used (that is, that method is not overriden), then this results in
   1136      * a call to the security manager's {@code checkPermission} method with
   1137      * a {@code SecurityPermission("putProviderProperty."+name)}
   1138      * permission.
   1139      *
   1140      * @param s the Service to add
   1141      *
   1142      * @throws SecurityException
   1143      *      if a security manager exists and its {@link
   1144      *      java.lang.SecurityManager#checkSecurityAccess} method denies
   1145      *      access to set property values.
   1146      * @throws NullPointerException if s is null
   1147      *
   1148      * @since 1.5
   1149      */
   1150     protected synchronized void putService(Service s) {
   1151         check("putProviderProperty." + name);
   1152         if (debug != null) {
   1153             debug.println(name + ".putService(): " + s);
   1154         }
   1155         if (s == null) {
   1156             throw new NullPointerException();
   1157         }
   1158         if (s.getProvider() != this) {
   1159             throw new IllegalArgumentException
   1160                     ("service.getProvider() must match this Provider object");
   1161         }
   1162         if (serviceMap == null) {
   1163             serviceMap = new LinkedHashMap<ServiceKey,Service>();
   1164         }
   1165         servicesChanged = true;
   1166         String type = s.getType();
   1167         String algorithm = s.getAlgorithm();
   1168         ServiceKey key = new ServiceKey(type, algorithm, true);
   1169         // remove existing service
   1170         implRemoveService(serviceMap.get(key));
   1171         serviceMap.put(key, s);
   1172         for (String alias : s.getAliases()) {
   1173             serviceMap.put(new ServiceKey(type, alias, true), s);
   1174         }
   1175         putPropertyStrings(s);
   1176     }
   1177 
   1178     /**
   1179      * Put the string properties for this Service in this Provider's
   1180      * Hashtable.
   1181      */
   1182     private void putPropertyStrings(Service s) {
   1183         String type = s.getType();
   1184         String algorithm = s.getAlgorithm();
   1185         // use super() to avoid permission check and other processing
   1186         super.put(type + "." + algorithm, s.getClassName());
   1187         for (String alias : s.getAliases()) {
   1188             super.put(ALIAS_PREFIX + type + "." + alias, algorithm);
   1189         }
   1190         for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
   1191             String key = type + "." + algorithm + " " + entry.getKey();
   1192             super.put(key, entry.getValue());
   1193         }
   1194         // Android-added: Provider registration
   1195         if (registered) {
   1196             Security.increaseVersion();
   1197         }
   1198     }
   1199 
   1200     /**
   1201      * Remove the string properties for this Service from this Provider's
   1202      * Hashtable.
   1203      */
   1204     private void removePropertyStrings(Service s) {
   1205         String type = s.getType();
   1206         String algorithm = s.getAlgorithm();
   1207         // use super() to avoid permission check and other processing
   1208         super.remove(type + "." + algorithm);
   1209         for (String alias : s.getAliases()) {
   1210             super.remove(ALIAS_PREFIX + type + "." + alias);
   1211         }
   1212         for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
   1213             String key = type + "." + algorithm + " " + entry.getKey();
   1214             super.remove(key);
   1215         }
   1216         // Android-added: Provider registration
   1217         if (registered) {
   1218           Security.increaseVersion();
   1219         }
   1220     }
   1221 
   1222     /**
   1223      * Remove a service previously added using
   1224      * {@link #putService putService()}. The specified service is removed from
   1225      * this provider. It will no longer be returned by
   1226      * {@link #getService getService()} and its information will be removed
   1227      * from this provider's Hashtable.
   1228      *
   1229      * <p>Also, if there is a security manager, its
   1230      * {@code checkSecurityAccess} method is called with the string
   1231      * {@code "removeProviderProperty."+name}, where {@code name} is
   1232      * the provider name, to see if it's ok to remove this provider's
   1233      * properties. If the default implementation of
   1234      * {@code checkSecurityAccess} is used (that is, that method is not
   1235      * overriden), then this results in a call to the security manager's
   1236      * {@code checkPermission} method with a
   1237      * {@code SecurityPermission("removeProviderProperty."+name)}
   1238      * permission.
   1239      *
   1240      * @param s the Service to be removed
   1241      *
   1242      * @throws  SecurityException
   1243      *          if a security manager exists and its {@link
   1244      *          java.lang.SecurityManager#checkSecurityAccess} method denies
   1245      *          access to remove this provider's properties.
   1246      * @throws NullPointerException if s is null
   1247      *
   1248      * @since 1.5
   1249      */
   1250     protected synchronized void removeService(Service s) {
   1251         check("removeProviderProperty." + name);
   1252         if (debug != null) {
   1253             debug.println(name + ".removeService(): " + s);
   1254         }
   1255         if (s == null) {
   1256             throw new NullPointerException();
   1257         }
   1258         implRemoveService(s);
   1259     }
   1260 
   1261     private void implRemoveService(Service s) {
   1262         if ((s == null) || (serviceMap == null)) {
   1263             return;
   1264         }
   1265         String type = s.getType();
   1266         String algorithm = s.getAlgorithm();
   1267         ServiceKey key = new ServiceKey(type, algorithm, false);
   1268         Service oldService = serviceMap.get(key);
   1269         if (s != oldService) {
   1270             return;
   1271         }
   1272         servicesChanged = true;
   1273         serviceMap.remove(key);
   1274         for (String alias : s.getAliases()) {
   1275             serviceMap.remove(new ServiceKey(type, alias, false));
   1276         }
   1277         removePropertyStrings(s);
   1278     }
   1279 
   1280     // Wrapped String that behaves in a case insensitive way for equals/hashCode
   1281     private static class UString {
   1282         final String string;
   1283         final String lowerString;
   1284 
   1285         UString(String s) {
   1286             this.string = s;
   1287             this.lowerString = s.toLowerCase(ENGLISH);
   1288         }
   1289 
   1290         public int hashCode() {
   1291             return lowerString.hashCode();
   1292         }
   1293 
   1294         public boolean equals(Object obj) {
   1295             if (this == obj) {
   1296                 return true;
   1297             }
   1298             if (obj instanceof UString == false) {
   1299                 return false;
   1300             }
   1301             UString other = (UString)obj;
   1302             return lowerString.equals(other.lowerString);
   1303         }
   1304 
   1305         public String toString() {
   1306             return string;
   1307         }
   1308     }
   1309 
   1310     // describe relevant properties of a type of engine
   1311     private static class EngineDescription {
   1312         final String name;
   1313         final boolean supportsParameter;
   1314         final String constructorParameterClassName;
   1315         private volatile Class<?> constructorParameterClass;
   1316 
   1317         EngineDescription(String name, boolean sp, String paramName) {
   1318             this.name = name;
   1319             this.supportsParameter = sp;
   1320             this.constructorParameterClassName = paramName;
   1321         }
   1322         Class<?> getConstructorParameterClass() throws ClassNotFoundException {
   1323             Class<?> clazz = constructorParameterClass;
   1324             if (clazz == null) {
   1325                 clazz = Class.forName(constructorParameterClassName);
   1326                 constructorParameterClass = clazz;
   1327             }
   1328             return clazz;
   1329         }
   1330     }
   1331 
   1332     // built in knowledge of the engine types shipped as part of the JDK
   1333     private static final Map<String,EngineDescription> knownEngines;
   1334 
   1335     private static void addEngine(String name, boolean sp, String paramName) {
   1336         EngineDescription ed = new EngineDescription(name, sp, paramName);
   1337         // also index by canonical name to avoid toLowerCase() for some lookups
   1338         knownEngines.put(name.toLowerCase(ENGLISH), ed);
   1339         knownEngines.put(name, ed);
   1340     }
   1341 
   1342     static {
   1343         knownEngines = new HashMap<String,EngineDescription>();
   1344         // JCA
   1345         addEngine("AlgorithmParameterGenerator",        false, null);
   1346         addEngine("AlgorithmParameters",                false, null);
   1347         addEngine("KeyFactory",                         false, null);
   1348         addEngine("KeyPairGenerator",                   false, null);
   1349         addEngine("KeyStore",                           false, null);
   1350         addEngine("MessageDigest",                      false, null);
   1351         addEngine("SecureRandom",                       false, null);
   1352         addEngine("Signature",                          true,  null);
   1353         addEngine("CertificateFactory",                 false, null);
   1354         addEngine("CertPathBuilder",                    false, null);
   1355         addEngine("CertPathValidator",                  false, null);
   1356         addEngine("CertStore",                          false,
   1357                             "java.security.cert.CertStoreParameters");
   1358         // JCE
   1359         addEngine("Cipher",                             true,  null);
   1360         addEngine("ExemptionMechanism",                 false, null);
   1361         addEngine("Mac",                                true,  null);
   1362         addEngine("KeyAgreement",                       true,  null);
   1363         addEngine("KeyGenerator",                       false, null);
   1364         addEngine("SecretKeyFactory",                   false, null);
   1365         // JSSE
   1366         addEngine("KeyManagerFactory",                  false, null);
   1367         addEngine("SSLContext",                         false, null);
   1368         addEngine("TrustManagerFactory",                false, null);
   1369         // JGSS
   1370         addEngine("GssApiMechanism",                    false, null);
   1371         // SASL
   1372         addEngine("SaslClientFactory",                  false, null);
   1373         addEngine("SaslServerFactory",                  false, null);
   1374         // POLICY
   1375         addEngine("Policy",                             false,
   1376                             "java.security.Policy$Parameters");
   1377         // CONFIGURATION
   1378         addEngine("Configuration",                      false,
   1379                             "javax.security.auth.login.Configuration$Parameters");
   1380         // XML DSig
   1381         addEngine("XMLSignatureFactory",                false, null);
   1382         addEngine("KeyInfoFactory",                     false, null);
   1383         addEngine("TransformService",                   false, null);
   1384         // Smart Card I/O
   1385         addEngine("TerminalFactory",                    false,
   1386                             "java.lang.Object");
   1387     }
   1388 
   1389     // get the "standard" (mixed-case) engine name for arbitary case engine name
   1390     // if there is no known engine by that name, return s
   1391     private static String getEngineName(String s) {
   1392         // try original case first, usually correct
   1393         EngineDescription e = knownEngines.get(s);
   1394         if (e == null) {
   1395             e = knownEngines.get(s.toLowerCase(ENGLISH));
   1396         }
   1397         return (e == null) ? s : e.name;
   1398     }
   1399 
   1400     /**
   1401      * The description of a security service. It encapsulates the properties
   1402      * of a service and contains a factory method to obtain new implementation
   1403      * instances of this service.
   1404      *
   1405      * <p>Each service has a provider that offers the service, a type,
   1406      * an algorithm name, and the name of the class that implements the
   1407      * service. Optionally, it also includes a list of alternate algorithm
   1408      * names for this service (aliases) and attributes, which are a map of
   1409      * (name, value) String pairs.
   1410      *
   1411      * <p>This class defines the methods {@link #supportsParameter
   1412      * supportsParameter()} and {@link #newInstance newInstance()}
   1413      * which are used by the Java security framework when it searches for
   1414      * suitable services and instantiates them. The valid arguments to those
   1415      * methods depend on the type of service. For the service types defined
   1416      * within Java SE, see the
   1417      * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html">
   1418      * Java Cryptography Architecture API Specification &amp; Reference </a>
   1419      * for the valid values.
   1420      * Note that components outside of Java SE can define additional types of
   1421      * services and their behavior.
   1422      *
   1423      * <p>Instances of this class are immutable.
   1424      *
   1425      * @since 1.5
   1426      */
   1427     public static class Service {
   1428 
   1429         private String type, algorithm, className;
   1430         private final Provider provider;
   1431         private List<String> aliases;
   1432         private Map<UString,String> attributes;
   1433 
   1434         // Reference to the cached implementation Class object
   1435         private volatile Reference<Class<?>> classRef;
   1436 
   1437         // flag indicating whether this service has its attributes for
   1438         // supportedKeyFormats or supportedKeyClasses set
   1439         // if null, the values have not been initialized
   1440         // if TRUE, at least one of supportedFormats/Classes is non null
   1441         private volatile Boolean hasKeyAttributes;
   1442 
   1443         // supported encoding formats
   1444         private String[] supportedFormats;
   1445 
   1446         // names of the supported key (super) classes
   1447         private Class[] supportedClasses;
   1448 
   1449         // whether this service has been registered with the Provider
   1450         private boolean registered;
   1451 
   1452         private static final Class<?>[] CLASS0 = new Class<?>[0];
   1453 
   1454         // this constructor and these methods are used for parsing
   1455         // the legacy string properties.
   1456 
   1457         private Service(Provider provider) {
   1458             this.provider = provider;
   1459             aliases = Collections.<String>emptyList();
   1460             attributes = Collections.<UString,String>emptyMap();
   1461         }
   1462 
   1463         private boolean isValid() {
   1464             return (type != null) && (algorithm != null) && (className != null);
   1465         }
   1466 
   1467         private void addAlias(String alias) {
   1468             if (aliases.isEmpty()) {
   1469                 aliases = new ArrayList<String>(2);
   1470             }
   1471             aliases.add(alias);
   1472         }
   1473 
   1474         void addAttribute(String type, String value) {
   1475             if (attributes.isEmpty()) {
   1476                 attributes = new HashMap<UString,String>(8);
   1477             }
   1478             attributes.put(new UString(type), value);
   1479         }
   1480 
   1481         /**
   1482          * Construct a new service.
   1483          *
   1484          * @param provider the provider that offers this service
   1485          * @param type the type of this service
   1486          * @param algorithm the algorithm name
   1487          * @param className the name of the class implementing this service
   1488          * @param aliases List of aliases or null if algorithm has no aliases
   1489          * @param attributes Map of attributes or null if this implementation
   1490          *                   has no attributes
   1491          *
   1492          * @throws NullPointerException if provider, type, algorithm, or
   1493          * className is null
   1494          */
   1495         public Service(Provider provider, String type, String algorithm,
   1496                 String className, List<String> aliases,
   1497                 Map<String,String> attributes) {
   1498             if ((provider == null) || (type == null) ||
   1499                     (algorithm == null) || (className == null)) {
   1500                 throw new NullPointerException();
   1501             }
   1502             this.provider = provider;
   1503             this.type = getEngineName(type);
   1504             this.algorithm = algorithm;
   1505             this.className = className;
   1506             if (aliases == null) {
   1507                 this.aliases = Collections.<String>emptyList();
   1508             } else {
   1509                 this.aliases = new ArrayList<String>(aliases);
   1510             }
   1511             if (attributes == null) {
   1512                 this.attributes = Collections.<UString,String>emptyMap();
   1513             } else {
   1514                 this.attributes = new HashMap<UString,String>();
   1515                 for (Map.Entry<String,String> entry : attributes.entrySet()) {
   1516                     this.attributes.put(new UString(entry.getKey()), entry.getValue());
   1517                 }
   1518             }
   1519         }
   1520 
   1521         /**
   1522          * Get the type of this service. For example, {@code MessageDigest}.
   1523          *
   1524          * @return the type of this service
   1525          */
   1526         public final String getType() {
   1527             return type;
   1528         }
   1529 
   1530         /**
   1531          * Return the name of the algorithm of this service. For example,
   1532          * {@code SHA-1}.
   1533          *
   1534          * @return the algorithm of this service
   1535          */
   1536         public final String getAlgorithm() {
   1537             return algorithm;
   1538         }
   1539 
   1540         /**
   1541          * Return the Provider of this service.
   1542          *
   1543          * @return the Provider of this service
   1544          */
   1545         public final Provider getProvider() {
   1546             return provider;
   1547         }
   1548 
   1549         /**
   1550          * Return the name of the class implementing this service.
   1551          *
   1552          * @return the name of the class implementing this service
   1553          */
   1554         public final String getClassName() {
   1555             return className;
   1556         }
   1557 
   1558         // internal only
   1559         private final List<String> getAliases() {
   1560             return aliases;
   1561         }
   1562 
   1563         /**
   1564          * Return the value of the specified attribute or null if this
   1565          * attribute is not set for this Service.
   1566          *
   1567          * @param name the name of the requested attribute
   1568          *
   1569          * @return the value of the specified attribute or null if the
   1570          *         attribute is not present
   1571          *
   1572          * @throws NullPointerException if name is null
   1573          */
   1574         public final String getAttribute(String name) {
   1575             if (name == null) {
   1576                 throw new NullPointerException();
   1577             }
   1578             return attributes.get(new UString(name));
   1579         }
   1580 
   1581         /**
   1582          * Return a new instance of the implementation described by this
   1583          * service. The security provider framework uses this method to
   1584          * construct implementations. Applications will typically not need
   1585          * to call it.
   1586          *
   1587          * <p>The default implementation uses reflection to invoke the
   1588          * standard constructor for this type of service.
   1589          * Security providers can override this method to implement
   1590          * instantiation in a different way.
   1591          * For details and the values of constructorParameter that are
   1592          * valid for the various types of services see the
   1593          * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html">
   1594          * Java Cryptography Architecture API Specification &amp;
   1595          * Reference</a>.
   1596          *
   1597          * @param constructorParameter the value to pass to the constructor,
   1598          * or null if this type of service does not use a constructorParameter.
   1599          *
   1600          * @return a new implementation of this service
   1601          *
   1602          * @throws InvalidParameterException if the value of
   1603          * constructorParameter is invalid for this type of service.
   1604          * @throws NoSuchAlgorithmException if instantiation failed for
   1605          * any other reason.
   1606          */
   1607         public Object newInstance(Object constructorParameter)
   1608                 throws NoSuchAlgorithmException {
   1609             if (registered == false) {
   1610                 if (provider.getService(type, algorithm) != this) {
   1611                     throw new NoSuchAlgorithmException
   1612                         ("Service not registered with Provider "
   1613                         + provider.getName() + ": " + this);
   1614                 }
   1615                 registered = true;
   1616             }
   1617             try {
   1618                 EngineDescription cap = knownEngines.get(type);
   1619                 if (cap == null) {
   1620                     // unknown engine type, use generic code
   1621                     // this is the code path future for non-core
   1622                     // optional packages
   1623                     return newInstanceGeneric(constructorParameter);
   1624                 }
   1625                 if (cap.constructorParameterClassName == null) {
   1626                     if (constructorParameter != null) {
   1627                         throw new InvalidParameterException
   1628                             ("constructorParameter not used with " + type
   1629                             + " engines");
   1630                     }
   1631                     Class<?> clazz = getImplClass();
   1632                     Class<?>[] empty = {};
   1633                     Constructor<?> con = clazz.getConstructor(empty);
   1634                     return con.newInstance();
   1635                 } else {
   1636                     Class<?> paramClass = cap.getConstructorParameterClass();
   1637                     if (constructorParameter != null) {
   1638                         Class<?> argClass = constructorParameter.getClass();
   1639                         if (paramClass.isAssignableFrom(argClass) == false) {
   1640                             throw new InvalidParameterException
   1641                             ("constructorParameter must be instanceof "
   1642                             + cap.constructorParameterClassName.replace('$', '.')
   1643                             + " for engine type " + type);
   1644                         }
   1645                     }
   1646                     Class<?> clazz = getImplClass();
   1647                     Constructor<?> cons = clazz.getConstructor(paramClass);
   1648                     return cons.newInstance(constructorParameter);
   1649                 }
   1650             } catch (NoSuchAlgorithmException e) {
   1651                 throw e;
   1652             } catch (InvocationTargetException e) {
   1653                 throw new NoSuchAlgorithmException
   1654                     ("Error constructing implementation (algorithm: "
   1655                     + algorithm + ", provider: " + provider.getName()
   1656                     + ", class: " + className + ")", e.getCause());
   1657             } catch (Exception e) {
   1658                 throw new NoSuchAlgorithmException
   1659                     ("Error constructing implementation (algorithm: "
   1660                     + algorithm + ", provider: " + provider.getName()
   1661                     + ", class: " + className + ")", e);
   1662             }
   1663         }
   1664 
   1665         // return the implementation Class object for this service
   1666         private Class<?> getImplClass() throws NoSuchAlgorithmException {
   1667             try {
   1668                 Reference<Class<?>> ref = classRef;
   1669                 Class<?> clazz = (ref == null) ? null : ref.get();
   1670                 if (clazz == null) {
   1671                     ClassLoader cl = provider.getClass().getClassLoader();
   1672                     if (cl == null) {
   1673                         clazz = Class.forName(className);
   1674                     } else {
   1675                         clazz = cl.loadClass(className);
   1676                     }
   1677                     if (!Modifier.isPublic(clazz.getModifiers())) {
   1678                         throw new NoSuchAlgorithmException
   1679                             ("class configured for " + type + " (provider: " +
   1680                             provider.getName() + ") is not public.");
   1681                     }
   1682                     classRef = new WeakReference<Class<?>>(clazz);
   1683                 }
   1684                 return clazz;
   1685             } catch (ClassNotFoundException e) {
   1686                 throw new NoSuchAlgorithmException
   1687                     ("class configured for " + type + " (provider: " +
   1688                     provider.getName() + ") cannot be found.", e);
   1689             }
   1690         }
   1691 
   1692         /**
   1693          * Generic code path for unknown engine types. Call the
   1694          * no-args constructor if constructorParameter is null, otherwise
   1695          * use the first matching constructor.
   1696          */
   1697         private Object newInstanceGeneric(Object constructorParameter)
   1698                 throws Exception {
   1699             Class<?> clazz = getImplClass();
   1700             if (constructorParameter == null) {
   1701                 // create instance with public no-arg constructor if it exists
   1702                 try {
   1703                     Class<?>[] empty = {};
   1704                     Constructor<?> con = clazz.getConstructor(empty);
   1705                     return con.newInstance();
   1706                 } catch (NoSuchMethodException e) {
   1707                     throw new NoSuchAlgorithmException("No public no-arg "
   1708                         + "constructor found in class " + className);
   1709                 }
   1710             }
   1711             Class<?> argClass = constructorParameter.getClass();
   1712             Constructor[] cons = clazz.getConstructors();
   1713             // find first public constructor that can take the
   1714             // argument as parameter
   1715             for (Constructor<?> con : cons) {
   1716                 Class<?>[] paramTypes = con.getParameterTypes();
   1717                 if (paramTypes.length != 1) {
   1718                     continue;
   1719                 }
   1720                 if (paramTypes[0].isAssignableFrom(argClass) == false) {
   1721                     continue;
   1722                 }
   1723                 return con.newInstance(constructorParameter);
   1724             }
   1725             throw new NoSuchAlgorithmException("No public constructor matching "
   1726                 + argClass.getName() + " found in class " + className);
   1727         }
   1728 
   1729         /**
   1730          * Test whether this Service can use the specified parameter.
   1731          * Returns false if this service cannot use the parameter. Returns
   1732          * true if this service can use the parameter, if a fast test is
   1733          * infeasible, or if the status is unknown.
   1734          *
   1735          * <p>The security provider framework uses this method with
   1736          * some types of services to quickly exclude non-matching
   1737          * implementations for consideration.
   1738          * Applications will typically not need to call it.
   1739          *
   1740          * <p>For details and the values of parameter that are valid for the
   1741          * various types of services see the top of this class and the
   1742          * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html">
   1743          * Java Cryptography Architecture API Specification &amp;
   1744          * Reference</a>.
   1745          * Security providers can override it to implement their own test.
   1746          *
   1747          * @param parameter the parameter to test
   1748          *
   1749          * @return false if this this service cannot use the specified
   1750          * parameter; true if it can possibly use the parameter
   1751          *
   1752          * @throws InvalidParameterException if the value of parameter is
   1753          * invalid for this type of service or if this method cannot be
   1754          * used with this type of service
   1755          */
   1756         public boolean supportsParameter(Object parameter) {
   1757             EngineDescription cap = knownEngines.get(type);
   1758             if (cap == null) {
   1759                 // unknown engine type, return true by default
   1760                 return true;
   1761             }
   1762             if (cap.supportsParameter == false) {
   1763                 throw new InvalidParameterException("supportsParameter() not "
   1764                     + "used with " + type + " engines");
   1765             }
   1766             // allow null for keys without attributes for compatibility
   1767             if ((parameter != null) && (parameter instanceof Key == false)) {
   1768                 throw new InvalidParameterException
   1769                     ("Parameter must be instanceof Key for engine " + type);
   1770             }
   1771             if (hasKeyAttributes() == false) {
   1772                 return true;
   1773             }
   1774             if (parameter == null) {
   1775                 return false;
   1776             }
   1777             Key key = (Key)parameter;
   1778             if (supportsKeyFormat(key)) {
   1779                 return true;
   1780             }
   1781             if (supportsKeyClass(key)) {
   1782                 return true;
   1783             }
   1784             return false;
   1785         }
   1786 
   1787         /**
   1788          * Return whether this service has its Supported* properties for
   1789          * keys defined. Parses the attributes if not yet initialized.
   1790          */
   1791         private boolean hasKeyAttributes() {
   1792             Boolean b = hasKeyAttributes;
   1793             if (b == null) {
   1794                 synchronized (this) {
   1795                     String s;
   1796                     s = getAttribute("SupportedKeyFormats");
   1797                     if (s != null) {
   1798                         supportedFormats = s.split("\\|");
   1799                     }
   1800                     s = getAttribute("SupportedKeyClasses");
   1801                     if (s != null) {
   1802                         String[] classNames = s.split("\\|");
   1803                         List<Class<?>> classList =
   1804                             new ArrayList<>(classNames.length);
   1805                         for (String className : classNames) {
   1806                             Class<?> clazz = getKeyClass(className);
   1807                             if (clazz != null) {
   1808                                 classList.add(clazz);
   1809                             }
   1810                         }
   1811                         supportedClasses = classList.toArray(CLASS0);
   1812                     }
   1813                     boolean bool = (supportedFormats != null)
   1814                         || (supportedClasses != null);
   1815                     b = Boolean.valueOf(bool);
   1816                     hasKeyAttributes = b;
   1817                 }
   1818             }
   1819             return b.booleanValue();
   1820         }
   1821 
   1822         // get the key class object of the specified name
   1823         private Class<?> getKeyClass(String name) {
   1824             try {
   1825                 return Class.forName(name);
   1826             } catch (ClassNotFoundException e) {
   1827                 // ignore
   1828             }
   1829             try {
   1830                 ClassLoader cl = provider.getClass().getClassLoader();
   1831                 if (cl != null) {
   1832                     return cl.loadClass(name);
   1833                 }
   1834             } catch (ClassNotFoundException e) {
   1835                 // ignore
   1836             }
   1837             return null;
   1838         }
   1839 
   1840         private boolean supportsKeyFormat(Key key) {
   1841             if (supportedFormats == null) {
   1842                 return false;
   1843             }
   1844             String format = key.getFormat();
   1845             if (format == null) {
   1846                 return false;
   1847             }
   1848             for (String supportedFormat : supportedFormats) {
   1849                 if (supportedFormat.equals(format)) {
   1850                     return true;
   1851                 }
   1852             }
   1853             return false;
   1854         }
   1855 
   1856         private boolean supportsKeyClass(Key key) {
   1857             if (supportedClasses == null) {
   1858                 return false;
   1859             }
   1860             Class<?> keyClass = key.getClass();
   1861             for (Class<?> clazz : supportedClasses) {
   1862                 if (clazz.isAssignableFrom(keyClass)) {
   1863                     return true;
   1864                 }
   1865             }
   1866             return false;
   1867         }
   1868 
   1869         /**
   1870          * Return a String representation of this service.
   1871          *
   1872          * @return a String representation of this service.
   1873          */
   1874         public String toString() {
   1875             String aString = aliases.isEmpty()
   1876                 ? "" : "\r\n  aliases: " + aliases.toString();
   1877             String attrs = attributes.isEmpty()
   1878                 ? "" : "\r\n  attributes: " + attributes.toString();
   1879             return provider.getName() + ": " + type + "." + algorithm
   1880                 + " -> " + className + aString + attrs + "\r\n";
   1881         }
   1882 
   1883     }
   1884 
   1885     // BEGIN Android-added: Provider registration
   1886     /**
   1887      * @hide
   1888      */
   1889     public void setRegistered() {
   1890         registered = true;
   1891     }
   1892 
   1893     /**
   1894      * @hide
   1895      */
   1896     public void setUnregistered() {
   1897         registered = false;
   1898     }
   1899 
   1900     /**
   1901      * @hide
   1902      */
   1903     public boolean isRegistered() {
   1904         return registered;
   1905     }
   1906 
   1907     /**
   1908      * Ensure the values cached by {@link #getServices} and {@link #getService} are already computed
   1909      *
   1910      * Used by the zygote so that initialization is performed during preload for the providers
   1911      * available at that point.
   1912      *
   1913      * @hide
   1914      */
   1915     public synchronized void warmUpServiceProvision() {
   1916         checkInitialized();
   1917         // Further calls do nothing if the services didn't change. If not called here, it would
   1918         // parse legacy strings the first time that a service is requested.
   1919         ensureLegacyParsed();
   1920         // This call to getServices will update fields so that further calls will just return a
   1921         // stored field, if the services didn't change in the meantime.
   1922         getServices();
   1923     }
   1924     // END Android-added: Provider registration
   1925 }
   1926