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  * "https://docs.oracle.com/javase/8/docs/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      */
Provider(String name, double version, String info)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      */
getName()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      */
getVersion()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      */
getInfo()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      */
toString()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
clear()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
load(InputStream inStream)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
putAll(Map<?,?> t)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
entrySet()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
keySet()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
values()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
put(Object key, Object value)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
putIfAbsent(Object key, Object value)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
remove(Object key)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
remove(Object key, Object value)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
replace(Object key, Object oldValue, Object newValue)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
replace(Object key, Object value)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
replaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function)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
compute(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction)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
computeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction)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
computeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction)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
merge(Object key, Object value, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction)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
get(Object key)617     public Object get(Object key) {
618         checkInitialized();
619         return super.get(key);
620     }
621     /**
622      * @since 1.8
623      */
624     @Override
getOrDefault(Object key, Object defaultValue)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
forEach(BiConsumer<? super Object, ? super Object> action)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
keys()641     public Enumeration<Object> keys() {
642         checkInitialized();
643         return super.keys();
644     }
645 
646     // let javadoc show doc from superclass
647     @Override
elements()648     public Enumeration<Object> elements() {
649         checkInitialized();
650         return super.elements();
651     }
652 
653     // let javadoc show doc from superclass
getProperty(String key)654     public String getProperty(String key) {
655         checkInitialized();
656         return super.getProperty(key);
657     }
658 
checkInitialized()659     private void checkInitialized() {
660         if (!initialized) {
661             throw new IllegalStateException();
662         }
663     }
664 
check(String directive)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
putId()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 
readObject(ObjectInputStream in)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 
checkLegacy(Object key)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      */
implPutAll(Map<?,?> t)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 
implRemove(Object key)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 
implRemove(Object key, Object value)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 
implReplace(Object key, Object oldValue, Object newValue)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 
implReplace(Object key, Object value)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 
implReplaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function)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 
implMerge(Object key, Object value, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction)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 
implCompute(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction)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: use compute() instead of computeIfAbsent() to avoid cast fails
821             // The upstream code cannot ever succeed as the cast from BiFunction to Function
822             // always fails.
823             // legacyStrings.computeIfAbsent((String) key,
824             //         (Function<? super String, ? extends String>) remappingFunction);
825             legacyStrings.compute((String) key,
826                     (BiFunction<? super String, ? super String, ? extends String>)
827                             remappingFunction);
828             // END Android-changed: use compute() instead of computeIfAbsent() to avoid cast fails
829         }
830         return super.compute(key, remappingFunction);
831     }
832 
implComputeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction)833     private Object implComputeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction) {
834         if (key instanceof String) {
835             if (!checkLegacy(key)) {
836                 return null;
837             }
838             legacyStrings.computeIfAbsent((String) key,
839                     (Function<? super String, ? extends String>) mappingFunction);
840         }
841         return super.computeIfAbsent(key, mappingFunction);
842     }
843 
implComputeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction)844     private Object implComputeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
845         if (key instanceof String) {
846             if (!checkLegacy(key)) {
847                 return null;
848             }
849             legacyStrings.computeIfPresent((String) key,
850                     (BiFunction<? super String, ? super String, ? extends String>) remappingFunction);
851         }
852         return super.computeIfPresent(key, remappingFunction);
853     }
854 
implPut(Object key, Object value)855     private Object implPut(Object key, Object value) {
856         if ((key instanceof String) && (value instanceof String)) {
857             if (!checkLegacy(key)) {
858                 return null;
859             }
860             legacyStrings.put((String)key, (String)value);
861         }
862         return super.put(key, value);
863     }
864 
implPutIfAbsent(Object key, Object value)865     private Object implPutIfAbsent(Object key, Object value) {
866         if ((key instanceof String) && (value instanceof String)) {
867             if (!checkLegacy(key)) {
868                 return null;
869             }
870             legacyStrings.putIfAbsent((String)key, (String)value);
871         }
872         return super.putIfAbsent(key, value);
873     }
874 
implClear()875     private void implClear() {
876         if (legacyStrings != null) {
877             legacyStrings.clear();
878         }
879         if (legacyMap != null) {
880             legacyMap.clear();
881         }
882         if (serviceMap != null) {
883             serviceMap.clear();
884         }
885         legacyChanged = false;
886         servicesChanged = false;
887         serviceSet = null;
888         super.clear();
889         putId();
890         // Android-added: Provider registration
891         if (registered) {
892           Security.increaseVersion();
893         }
894     }
895 
896     // used as key in the serviceMap and legacyMap HashMaps
897     private static class ServiceKey {
898         private final String type;
899         private final String algorithm;
900         private final String originalAlgorithm;
ServiceKey(String type, String algorithm, boolean intern)901         private ServiceKey(String type, String algorithm, boolean intern) {
902             this.type = type;
903             this.originalAlgorithm = algorithm;
904             algorithm = algorithm.toUpperCase(ENGLISH);
905             this.algorithm = intern ? algorithm.intern() : algorithm;
906         }
hashCode()907         public int hashCode() {
908             return type.hashCode() + algorithm.hashCode();
909         }
equals(Object obj)910         public boolean equals(Object obj) {
911             if (this == obj) {
912                 return true;
913             }
914             if (obj instanceof ServiceKey == false) {
915                 return false;
916             }
917             ServiceKey other = (ServiceKey)obj;
918             return this.type.equals(other.type)
919                 && this.algorithm.equals(other.algorithm);
920         }
matches(String type, String algorithm)921         boolean matches(String type, String algorithm) {
922             return (this.type == type) && (this.originalAlgorithm == algorithm);
923         }
924     }
925 
926     /**
927      * Ensure all the legacy String properties are fully parsed into
928      * service objects.
929      */
ensureLegacyParsed()930     private void ensureLegacyParsed() {
931         if ((legacyChanged == false) || (legacyStrings == null)) {
932             return;
933         }
934         serviceSet = null;
935         if (legacyMap == null) {
936             legacyMap = new LinkedHashMap<ServiceKey,Service>();
937         } else {
938             legacyMap.clear();
939         }
940         for (Map.Entry<String,String> entry : legacyStrings.entrySet()) {
941             parseLegacyPut(entry.getKey(), entry.getValue());
942         }
943         removeInvalidServices(legacyMap);
944         legacyChanged = false;
945     }
946 
947     /**
948      * Remove all invalid services from the Map. Invalid services can only
949      * occur if the legacy properties are inconsistent or incomplete.
950      */
removeInvalidServices(Map<ServiceKey,Service> map)951     private void removeInvalidServices(Map<ServiceKey,Service> map) {
952         for (Iterator<Map.Entry<ServiceKey, Service>> t =
953                 map.entrySet().iterator(); t.hasNext(); ) {
954             Service s = t.next().getValue();
955             if (s.isValid() == false) {
956                 t.remove();
957             }
958         }
959     }
960 
getTypeAndAlgorithm(String key)961     private String[] getTypeAndAlgorithm(String key) {
962         int i = key.indexOf(".");
963         if (i < 1) {
964             if (debug != null) {
965                 debug.println("Ignoring invalid entry in provider "
966                         + name + ":" + key);
967             }
968             return null;
969         }
970         String type = key.substring(0, i);
971         String alg = key.substring(i + 1);
972         return new String[] {type, alg};
973     }
974 
975     private final static String ALIAS_PREFIX = "Alg.Alias.";
976     private final static String ALIAS_PREFIX_LOWER = "alg.alias.";
977     private final static int ALIAS_LENGTH = ALIAS_PREFIX.length();
978 
parseLegacyPut(String name, String value)979     private void parseLegacyPut(String name, String value) {
980         if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
981             // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
982             // aliasKey ~ MessageDigest.SHA
983             String stdAlg = value;
984             String aliasKey = name.substring(ALIAS_LENGTH);
985             String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
986             if (typeAndAlg == null) {
987                 return;
988             }
989             String type = getEngineName(typeAndAlg[0]);
990             String aliasAlg = typeAndAlg[1].intern();
991             ServiceKey key = new ServiceKey(type, stdAlg, true);
992             Service s = legacyMap.get(key);
993             if (s == null) {
994                 s = new Service(this);
995                 s.type = type;
996                 s.algorithm = stdAlg;
997                 legacyMap.put(key, s);
998             }
999             legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
1000             s.addAlias(aliasAlg);
1001         } else {
1002             String[] typeAndAlg = getTypeAndAlgorithm(name);
1003             if (typeAndAlg == null) {
1004                 return;
1005             }
1006             int i = typeAndAlg[1].indexOf(' ');
1007             if (i == -1) {
1008                 // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
1009                 String type = getEngineName(typeAndAlg[0]);
1010                 String stdAlg = typeAndAlg[1].intern();
1011                 String className = value;
1012                 ServiceKey key = new ServiceKey(type, stdAlg, true);
1013                 Service s = legacyMap.get(key);
1014                 if (s == null) {
1015                     s = new Service(this);
1016                     s.type = type;
1017                     s.algorithm = stdAlg;
1018                     legacyMap.put(key, s);
1019                 }
1020                 s.className = className;
1021             } else { // attribute
1022                 // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
1023                 String attributeValue = value;
1024                 String type = getEngineName(typeAndAlg[0]);
1025                 String attributeString = typeAndAlg[1];
1026                 String stdAlg = attributeString.substring(0, i).intern();
1027                 String attributeName = attributeString.substring(i + 1);
1028                 // kill additional spaces
1029                 while (attributeName.startsWith(" ")) {
1030                     attributeName = attributeName.substring(1);
1031                 }
1032                 attributeName = attributeName.intern();
1033                 ServiceKey key = new ServiceKey(type, stdAlg, true);
1034                 Service s = legacyMap.get(key);
1035                 if (s == null) {
1036                     s = new Service(this);
1037                     s.type = type;
1038                     s.algorithm = stdAlg;
1039                     legacyMap.put(key, s);
1040                 }
1041                 s.addAttribute(attributeName, attributeValue);
1042             }
1043         }
1044     }
1045 
1046     /**
1047      * Get the service describing this Provider's implementation of the
1048      * specified type of this algorithm or alias. If no such
1049      * implementation exists, this method returns null. If there are two
1050      * matching services, one added to this provider using
1051      * {@link #putService putService()} and one added via {@link #put put()},
1052      * the service added via {@link #putService putService()} is returned.
1053      *
1054      * @param type the type of {@link Service service} requested
1055      * (for example, {@code MessageDigest})
1056      * @param algorithm the case insensitive algorithm name (or alternate
1057      * alias) of the service requested (for example, {@code SHA-1})
1058      *
1059      * @return the service describing this Provider's matching service
1060      * or null if no such service exists
1061      *
1062      * @throws NullPointerException if type or algorithm is null
1063      *
1064      * @since 1.5
1065      */
getService(String type, String algorithm)1066     public synchronized Service getService(String type, String algorithm) {
1067         checkInitialized();
1068         // avoid allocating a new key object if possible
1069         ServiceKey key = previousKey;
1070         if (key.matches(type, algorithm) == false) {
1071             key = new ServiceKey(type, algorithm, false);
1072             previousKey = key;
1073         }
1074         if (serviceMap != null) {
1075             Service service = serviceMap.get(key);
1076             if (service != null) {
1077                 return service;
1078             }
1079         }
1080         ensureLegacyParsed();
1081         return (legacyMap != null) ? legacyMap.get(key) : null;
1082     }
1083 
1084     // ServiceKey from previous getService() call
1085     // by re-using it if possible we avoid allocating a new object
1086     // and the toUpperCase() call.
1087     // re-use will occur e.g. as the framework traverses the provider
1088     // list and queries each provider with the same values until it finds
1089     // a matching service
1090     private static volatile ServiceKey previousKey =
1091                                             new ServiceKey("", "", false);
1092 
1093     /**
1094      * Get an unmodifiable Set of all services supported by
1095      * this Provider.
1096      *
1097      * @return an unmodifiable Set of all services supported by
1098      * this Provider
1099      *
1100      * @since 1.5
1101      */
getServices()1102     public synchronized Set<Service> getServices() {
1103         checkInitialized();
1104         if (legacyChanged || servicesChanged) {
1105             serviceSet = null;
1106         }
1107         if (serviceSet == null) {
1108             ensureLegacyParsed();
1109             Set<Service> set = new LinkedHashSet<>();
1110             if (serviceMap != null) {
1111                 set.addAll(serviceMap.values());
1112             }
1113             if (legacyMap != null) {
1114                 set.addAll(legacyMap.values());
1115             }
1116             serviceSet = Collections.unmodifiableSet(set);
1117             servicesChanged = false;
1118         }
1119         return serviceSet;
1120     }
1121 
1122     /**
1123      * Add a service. If a service of the same type with the same algorithm
1124      * name exists and it was added using {@link #putService putService()},
1125      * it is replaced by the new service.
1126      * This method also places information about this service
1127      * in the provider's Hashtable values in the format described in the
1128      * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
1129      * Java Cryptography Architecture API Specification &amp; Reference </a>.
1130      *
1131      * <p>Also, if there is a security manager, its
1132      * {@code checkSecurityAccess} method is called with the string
1133      * {@code "putProviderProperty."+name}, where {@code name} is
1134      * the provider name, to see if it's ok to set this provider's property
1135      * values. If the default implementation of {@code checkSecurityAccess}
1136      * is used (that is, that method is not overriden), then this results in
1137      * a call to the security manager's {@code checkPermission} method with
1138      * a {@code SecurityPermission("putProviderProperty."+name)}
1139      * permission.
1140      *
1141      * @param s the Service to add
1142      *
1143      * @throws SecurityException
1144      *      if a security manager exists and its {@link
1145      *      java.lang.SecurityManager#checkSecurityAccess} method denies
1146      *      access to set property values.
1147      * @throws NullPointerException if s is null
1148      *
1149      * @since 1.5
1150      */
putService(Service s)1151     protected synchronized void putService(Service s) {
1152         check("putProviderProperty." + name);
1153         if (debug != null) {
1154             debug.println(name + ".putService(): " + s);
1155         }
1156         if (s == null) {
1157             throw new NullPointerException();
1158         }
1159         if (s.getProvider() != this) {
1160             throw new IllegalArgumentException
1161                     ("service.getProvider() must match this Provider object");
1162         }
1163         if (serviceMap == null) {
1164             serviceMap = new LinkedHashMap<ServiceKey,Service>();
1165         }
1166         servicesChanged = true;
1167         String type = s.getType();
1168         String algorithm = s.getAlgorithm();
1169         ServiceKey key = new ServiceKey(type, algorithm, true);
1170         // remove existing service
1171         implRemoveService(serviceMap.get(key));
1172         serviceMap.put(key, s);
1173         for (String alias : s.getAliases()) {
1174             serviceMap.put(new ServiceKey(type, alias, true), s);
1175         }
1176         putPropertyStrings(s);
1177     }
1178 
1179     /**
1180      * Put the string properties for this Service in this Provider's
1181      * Hashtable.
1182      */
putPropertyStrings(Service s)1183     private void putPropertyStrings(Service s) {
1184         String type = s.getType();
1185         String algorithm = s.getAlgorithm();
1186         // use super() to avoid permission check and other processing
1187         super.put(type + "." + algorithm, s.getClassName());
1188         for (String alias : s.getAliases()) {
1189             super.put(ALIAS_PREFIX + type + "." + alias, algorithm);
1190         }
1191         for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
1192             String key = type + "." + algorithm + " " + entry.getKey();
1193             super.put(key, entry.getValue());
1194         }
1195         // Android-added: Provider registration
1196         if (registered) {
1197             Security.increaseVersion();
1198         }
1199     }
1200 
1201     /**
1202      * Remove the string properties for this Service from this Provider's
1203      * Hashtable.
1204      */
removePropertyStrings(Service s)1205     private void removePropertyStrings(Service s) {
1206         String type = s.getType();
1207         String algorithm = s.getAlgorithm();
1208         // use super() to avoid permission check and other processing
1209         super.remove(type + "." + algorithm);
1210         for (String alias : s.getAliases()) {
1211             super.remove(ALIAS_PREFIX + type + "." + alias);
1212         }
1213         for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
1214             String key = type + "." + algorithm + " " + entry.getKey();
1215             super.remove(key);
1216         }
1217         // Android-added: Provider registration
1218         if (registered) {
1219           Security.increaseVersion();
1220         }
1221     }
1222 
1223     /**
1224      * Remove a service previously added using
1225      * {@link #putService putService()}. The specified service is removed from
1226      * this provider. It will no longer be returned by
1227      * {@link #getService getService()} and its information will be removed
1228      * from this provider's Hashtable.
1229      *
1230      * <p>Also, if there is a security manager, its
1231      * {@code checkSecurityAccess} method is called with the string
1232      * {@code "removeProviderProperty."+name}, where {@code name} is
1233      * the provider name, to see if it's ok to remove this provider's
1234      * properties. If the default implementation of
1235      * {@code checkSecurityAccess} is used (that is, that method is not
1236      * overriden), then this results in a call to the security manager's
1237      * {@code checkPermission} method with a
1238      * {@code SecurityPermission("removeProviderProperty."+name)}
1239      * permission.
1240      *
1241      * @param s the Service to be removed
1242      *
1243      * @throws  SecurityException
1244      *          if a security manager exists and its {@link
1245      *          java.lang.SecurityManager#checkSecurityAccess} method denies
1246      *          access to remove this provider's properties.
1247      * @throws NullPointerException if s is null
1248      *
1249      * @since 1.5
1250      */
removeService(Service s)1251     protected synchronized void removeService(Service s) {
1252         check("removeProviderProperty." + name);
1253         if (debug != null) {
1254             debug.println(name + ".removeService(): " + s);
1255         }
1256         if (s == null) {
1257             throw new NullPointerException();
1258         }
1259         implRemoveService(s);
1260     }
1261 
implRemoveService(Service s)1262     private void implRemoveService(Service s) {
1263         if ((s == null) || (serviceMap == null)) {
1264             return;
1265         }
1266         String type = s.getType();
1267         String algorithm = s.getAlgorithm();
1268         ServiceKey key = new ServiceKey(type, algorithm, false);
1269         Service oldService = serviceMap.get(key);
1270         if (s != oldService) {
1271             return;
1272         }
1273         servicesChanged = true;
1274         serviceMap.remove(key);
1275         for (String alias : s.getAliases()) {
1276             serviceMap.remove(new ServiceKey(type, alias, false));
1277         }
1278         removePropertyStrings(s);
1279     }
1280 
1281     // Wrapped String that behaves in a case insensitive way for equals/hashCode
1282     private static class UString {
1283         final String string;
1284         final String lowerString;
1285 
UString(String s)1286         UString(String s) {
1287             this.string = s;
1288             this.lowerString = s.toLowerCase(ENGLISH);
1289         }
1290 
hashCode()1291         public int hashCode() {
1292             return lowerString.hashCode();
1293         }
1294 
equals(Object obj)1295         public boolean equals(Object obj) {
1296             if (this == obj) {
1297                 return true;
1298             }
1299             if (obj instanceof UString == false) {
1300                 return false;
1301             }
1302             UString other = (UString)obj;
1303             return lowerString.equals(other.lowerString);
1304         }
1305 
toString()1306         public String toString() {
1307             return string;
1308         }
1309     }
1310 
1311     // describe relevant properties of a type of engine
1312     private static class EngineDescription {
1313         final String name;
1314         final boolean supportsParameter;
1315         final String constructorParameterClassName;
1316         private volatile Class<?> constructorParameterClass;
1317 
EngineDescription(String name, boolean sp, String paramName)1318         EngineDescription(String name, boolean sp, String paramName) {
1319             this.name = name;
1320             this.supportsParameter = sp;
1321             this.constructorParameterClassName = paramName;
1322         }
getConstructorParameterClass()1323         Class<?> getConstructorParameterClass() throws ClassNotFoundException {
1324             Class<?> clazz = constructorParameterClass;
1325             if (clazz == null) {
1326                 clazz = Class.forName(constructorParameterClassName);
1327                 constructorParameterClass = clazz;
1328             }
1329             return clazz;
1330         }
1331     }
1332 
1333     // built in knowledge of the engine types shipped as part of the JDK
1334     private static final Map<String,EngineDescription> knownEngines;
1335 
addEngine(String name, boolean sp, String paramName)1336     private static void addEngine(String name, boolean sp, String paramName) {
1337         EngineDescription ed = new EngineDescription(name, sp, paramName);
1338         // also index by canonical name to avoid toLowerCase() for some lookups
1339         knownEngines.put(name.toLowerCase(ENGLISH), ed);
1340         knownEngines.put(name, ed);
1341     }
1342 
1343     static {
1344         knownEngines = new HashMap<String,EngineDescription>();
1345         // JCA
1346         addEngine("AlgorithmParameterGenerator",        false, null);
1347         addEngine("AlgorithmParameters",                false, null);
1348         addEngine("KeyFactory",                         false, null);
1349         addEngine("KeyPairGenerator",                   false, null);
1350         addEngine("KeyStore",                           false, null);
1351         addEngine("MessageDigest",                      false, null);
1352         addEngine("SecureRandom",                       false, null);
1353         addEngine("Signature",                          true,  null);
1354         addEngine("CertificateFactory",                 false, null);
1355         addEngine("CertPathBuilder",                    false, null);
1356         addEngine("CertPathValidator",                  false, null);
1357         addEngine("CertStore",                          false,
1358                             "java.security.cert.CertStoreParameters");
1359         // JCE
1360         addEngine("Cipher",                             true,  null);
1361         addEngine("ExemptionMechanism",                 false, null);
1362         addEngine("Mac",                                true,  null);
1363         addEngine("KeyAgreement",                       true,  null);
1364         addEngine("KeyGenerator",                       false, null);
1365         addEngine("SecretKeyFactory",                   false, null);
1366         // JSSE
1367         addEngine("KeyManagerFactory",                  false, null);
1368         addEngine("SSLContext",                         false, null);
1369         addEngine("TrustManagerFactory",                false, null);
1370         // JGSS
1371         addEngine("GssApiMechanism",                    false, null);
1372         // SASL
1373         addEngine("SaslClientFactory",                  false, null);
1374         addEngine("SaslServerFactory",                  false, null);
1375         // POLICY
1376         addEngine("Policy",                             false,
1377                             "java.security.Policy$Parameters");
1378         // CONFIGURATION
1379         addEngine("Configuration",                      false,
1380                             "javax.security.auth.login.Configuration$Parameters");
1381         // XML DSig
1382         addEngine("XMLSignatureFactory",                false, null);
1383         addEngine("KeyInfoFactory",                     false, null);
1384         addEngine("TransformService",                   false, null);
1385         // Smart Card I/O
1386         addEngine("TerminalFactory",                    false,
1387                             "java.lang.Object");
1388     }
1389 
1390     // get the "standard" (mixed-case) engine name for arbitary case engine name
1391     // if there is no known engine by that name, return s
getEngineName(String s)1392     private static String getEngineName(String s) {
1393         // try original case first, usually correct
1394         EngineDescription e = knownEngines.get(s);
1395         if (e == null) {
1396             e = knownEngines.get(s.toLowerCase(ENGLISH));
1397         }
1398         return (e == null) ? s : e.name;
1399     }
1400 
1401     /**
1402      * The description of a security service. It encapsulates the properties
1403      * of a service and contains a factory method to obtain new implementation
1404      * instances of this service.
1405      *
1406      * <p>Each service has a provider that offers the service, a type,
1407      * an algorithm name, and the name of the class that implements the
1408      * service. Optionally, it also includes a list of alternate algorithm
1409      * names for this service (aliases) and attributes, which are a map of
1410      * (name, value) String pairs.
1411      *
1412      * <p>This class defines the methods {@link #supportsParameter
1413      * supportsParameter()} and {@link #newInstance newInstance()}
1414      * which are used by the Java security framework when it searches for
1415      * suitable services and instantiates them. The valid arguments to those
1416      * methods depend on the type of service. For the service types defined
1417      * within Java SE, see the
1418      * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
1419      * Java Cryptography Architecture API Specification &amp; Reference </a>
1420      * for the valid values.
1421      * Note that components outside of Java SE can define additional types of
1422      * services and their behavior.
1423      *
1424      * <p>Instances of this class are immutable.
1425      *
1426      * @since 1.5
1427      */
1428     public static class Service {
1429 
1430         private String type, algorithm, className;
1431         private final Provider provider;
1432         private List<String> aliases;
1433         private Map<UString,String> attributes;
1434 
1435         // Reference to the cached implementation Class object
1436         private volatile Reference<Class<?>> classRef;
1437 
1438         // flag indicating whether this service has its attributes for
1439         // supportedKeyFormats or supportedKeyClasses set
1440         // if null, the values have not been initialized
1441         // if TRUE, at least one of supportedFormats/Classes is non null
1442         private volatile Boolean hasKeyAttributes;
1443 
1444         // supported encoding formats
1445         private String[] supportedFormats;
1446 
1447         // names of the supported key (super) classes
1448         private Class[] supportedClasses;
1449 
1450         // whether this service has been registered with the Provider
1451         private boolean registered;
1452 
1453         private static final Class<?>[] CLASS0 = new Class<?>[0];
1454 
1455         // this constructor and these methods are used for parsing
1456         // the legacy string properties.
1457 
Service(Provider provider)1458         private Service(Provider provider) {
1459             this.provider = provider;
1460             aliases = Collections.<String>emptyList();
1461             attributes = Collections.<UString,String>emptyMap();
1462         }
1463 
isValid()1464         private boolean isValid() {
1465             return (type != null) && (algorithm != null) && (className != null);
1466         }
1467 
addAlias(String alias)1468         private void addAlias(String alias) {
1469             if (aliases.isEmpty()) {
1470                 aliases = new ArrayList<String>(2);
1471             }
1472             aliases.add(alias);
1473         }
1474 
addAttribute(String type, String value)1475         void addAttribute(String type, String value) {
1476             if (attributes.isEmpty()) {
1477                 attributes = new HashMap<UString,String>(8);
1478             }
1479             attributes.put(new UString(type), value);
1480         }
1481 
1482         /**
1483          * Construct a new service.
1484          *
1485          * @param provider the provider that offers this service
1486          * @param type the type of this service
1487          * @param algorithm the algorithm name
1488          * @param className the name of the class implementing this service
1489          * @param aliases List of aliases or null if algorithm has no aliases
1490          * @param attributes Map of attributes or null if this implementation
1491          *                   has no attributes
1492          *
1493          * @throws NullPointerException if provider, type, algorithm, or
1494          * className is null
1495          */
Service(Provider provider, String type, String algorithm, String className, List<String> aliases, Map<String,String> attributes)1496         public Service(Provider provider, String type, String algorithm,
1497                 String className, List<String> aliases,
1498                 Map<String,String> attributes) {
1499             if ((provider == null) || (type == null) ||
1500                     (algorithm == null) || (className == null)) {
1501                 throw new NullPointerException();
1502             }
1503             this.provider = provider;
1504             this.type = getEngineName(type);
1505             this.algorithm = algorithm;
1506             this.className = className;
1507             if (aliases == null) {
1508                 this.aliases = Collections.<String>emptyList();
1509             } else {
1510                 this.aliases = new ArrayList<String>(aliases);
1511             }
1512             if (attributes == null) {
1513                 this.attributes = Collections.<UString,String>emptyMap();
1514             } else {
1515                 this.attributes = new HashMap<UString,String>();
1516                 for (Map.Entry<String,String> entry : attributes.entrySet()) {
1517                     this.attributes.put(new UString(entry.getKey()), entry.getValue());
1518                 }
1519             }
1520         }
1521 
1522         /**
1523          * Get the type of this service. For example, {@code MessageDigest}.
1524          *
1525          * @return the type of this service
1526          */
getType()1527         public final String getType() {
1528             return type;
1529         }
1530 
1531         /**
1532          * Return the name of the algorithm of this service. For example,
1533          * {@code SHA-1}.
1534          *
1535          * @return the algorithm of this service
1536          */
getAlgorithm()1537         public final String getAlgorithm() {
1538             return algorithm;
1539         }
1540 
1541         /**
1542          * Return the Provider of this service.
1543          *
1544          * @return the Provider of this service
1545          */
getProvider()1546         public final Provider getProvider() {
1547             return provider;
1548         }
1549 
1550         /**
1551          * Return the name of the class implementing this service.
1552          *
1553          * @return the name of the class implementing this service
1554          */
getClassName()1555         public final String getClassName() {
1556             return className;
1557         }
1558 
1559         // internal only
getAliases()1560         private final List<String> getAliases() {
1561             return aliases;
1562         }
1563 
1564         /**
1565          * Return the value of the specified attribute or null if this
1566          * attribute is not set for this Service.
1567          *
1568          * @param name the name of the requested attribute
1569          *
1570          * @return the value of the specified attribute or null if the
1571          *         attribute is not present
1572          *
1573          * @throws NullPointerException if name is null
1574          */
getAttribute(String name)1575         public final String getAttribute(String name) {
1576             if (name == null) {
1577                 throw new NullPointerException();
1578             }
1579             return attributes.get(new UString(name));
1580         }
1581 
1582         /**
1583          * Return a new instance of the implementation described by this
1584          * service. The security provider framework uses this method to
1585          * construct implementations. Applications will typically not need
1586          * to call it.
1587          *
1588          * <p>The default implementation uses reflection to invoke the
1589          * standard constructor for this type of service.
1590          * Security providers can override this method to implement
1591          * instantiation in a different way.
1592          * For details and the values of constructorParameter that are
1593          * valid for the various types of services see the
1594          * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
1595          * Java Cryptography Architecture API Specification &amp;
1596          * Reference</a>.
1597          *
1598          * @param constructorParameter the value to pass to the constructor,
1599          * or null if this type of service does not use a constructorParameter.
1600          *
1601          * @return a new implementation of this service
1602          *
1603          * @throws InvalidParameterException if the value of
1604          * constructorParameter is invalid for this type of service.
1605          * @throws NoSuchAlgorithmException if instantiation failed for
1606          * any other reason.
1607          */
newInstance(Object constructorParameter)1608         public Object newInstance(Object constructorParameter)
1609                 throws NoSuchAlgorithmException {
1610             if (registered == false) {
1611                 if (provider.getService(type, algorithm) != this) {
1612                     throw new NoSuchAlgorithmException
1613                         ("Service not registered with Provider "
1614                         + provider.getName() + ": " + this);
1615                 }
1616                 registered = true;
1617             }
1618             try {
1619                 EngineDescription cap = knownEngines.get(type);
1620                 if (cap == null) {
1621                     // unknown engine type, use generic code
1622                     // this is the code path future for non-core
1623                     // optional packages
1624                     return newInstanceGeneric(constructorParameter);
1625                 }
1626                 if (cap.constructorParameterClassName == null) {
1627                     if (constructorParameter != null) {
1628                         throw new InvalidParameterException
1629                             ("constructorParameter not used with " + type
1630                             + " engines");
1631                     }
1632                     Class<?> clazz = getImplClass();
1633                     Class<?>[] empty = {};
1634                     Constructor<?> con = clazz.getConstructor(empty);
1635                     return con.newInstance();
1636                 } else {
1637                     Class<?> paramClass = cap.getConstructorParameterClass();
1638                     if (constructorParameter != null) {
1639                         Class<?> argClass = constructorParameter.getClass();
1640                         if (paramClass.isAssignableFrom(argClass) == false) {
1641                             throw new InvalidParameterException
1642                             ("constructorParameter must be instanceof "
1643                             + cap.constructorParameterClassName.replace('$', '.')
1644                             + " for engine type " + type);
1645                         }
1646                     }
1647                     Class<?> clazz = getImplClass();
1648                     Constructor<?> cons = clazz.getConstructor(paramClass);
1649                     return cons.newInstance(constructorParameter);
1650                 }
1651             } catch (NoSuchAlgorithmException e) {
1652                 throw e;
1653             } catch (InvocationTargetException e) {
1654                 throw new NoSuchAlgorithmException
1655                     ("Error constructing implementation (algorithm: "
1656                     + algorithm + ", provider: " + provider.getName()
1657                     + ", class: " + className + ")", e.getCause());
1658             } catch (Exception e) {
1659                 throw new NoSuchAlgorithmException
1660                     ("Error constructing implementation (algorithm: "
1661                     + algorithm + ", provider: " + provider.getName()
1662                     + ", class: " + className + ")", e);
1663             }
1664         }
1665 
1666         // return the implementation Class object for this service
getImplClass()1667         private Class<?> getImplClass() throws NoSuchAlgorithmException {
1668             try {
1669                 Reference<Class<?>> ref = classRef;
1670                 Class<?> clazz = (ref == null) ? null : ref.get();
1671                 if (clazz == null) {
1672                     ClassLoader cl = provider.getClass().getClassLoader();
1673                     if (cl == null) {
1674                         clazz = Class.forName(className);
1675                     } else {
1676                         clazz = cl.loadClass(className);
1677                     }
1678                     if (!Modifier.isPublic(clazz.getModifiers())) {
1679                         throw new NoSuchAlgorithmException
1680                             ("class configured for " + type + " (provider: " +
1681                             provider.getName() + ") is not public.");
1682                     }
1683                     classRef = new WeakReference<Class<?>>(clazz);
1684                 }
1685                 return clazz;
1686             } catch (ClassNotFoundException e) {
1687                 throw new NoSuchAlgorithmException
1688                     ("class configured for " + type + " (provider: " +
1689                     provider.getName() + ") cannot be found.", e);
1690             }
1691         }
1692 
1693         /**
1694          * Generic code path for unknown engine types. Call the
1695          * no-args constructor if constructorParameter is null, otherwise
1696          * use the first matching constructor.
1697          */
newInstanceGeneric(Object constructorParameter)1698         private Object newInstanceGeneric(Object constructorParameter)
1699                 throws Exception {
1700             Class<?> clazz = getImplClass();
1701             if (constructorParameter == null) {
1702                 // create instance with public no-arg constructor if it exists
1703                 try {
1704                     Class<?>[] empty = {};
1705                     Constructor<?> con = clazz.getConstructor(empty);
1706                     return con.newInstance();
1707                 } catch (NoSuchMethodException e) {
1708                     throw new NoSuchAlgorithmException("No public no-arg "
1709                         + "constructor found in class " + className);
1710                 }
1711             }
1712             Class<?> argClass = constructorParameter.getClass();
1713             Constructor[] cons = clazz.getConstructors();
1714             // find first public constructor that can take the
1715             // argument as parameter
1716             for (Constructor<?> con : cons) {
1717                 Class<?>[] paramTypes = con.getParameterTypes();
1718                 if (paramTypes.length != 1) {
1719                     continue;
1720                 }
1721                 if (paramTypes[0].isAssignableFrom(argClass) == false) {
1722                     continue;
1723                 }
1724                 return con.newInstance(constructorParameter);
1725             }
1726             throw new NoSuchAlgorithmException("No public constructor matching "
1727                 + argClass.getName() + " found in class " + className);
1728         }
1729 
1730         /**
1731          * Test whether this Service can use the specified parameter.
1732          * Returns false if this service cannot use the parameter. Returns
1733          * true if this service can use the parameter, if a fast test is
1734          * infeasible, or if the status is unknown.
1735          *
1736          * <p>The security provider framework uses this method with
1737          * some types of services to quickly exclude non-matching
1738          * implementations for consideration.
1739          * Applications will typically not need to call it.
1740          *
1741          * <p>For details and the values of parameter that are valid for the
1742          * various types of services see the top of this class and the
1743          * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
1744          * Java Cryptography Architecture API Specification &amp;
1745          * Reference</a>.
1746          * Security providers can override it to implement their own test.
1747          *
1748          * @param parameter the parameter to test
1749          *
1750          * @return false if this this service cannot use the specified
1751          * parameter; true if it can possibly use the parameter
1752          *
1753          * @throws InvalidParameterException if the value of parameter is
1754          * invalid for this type of service or if this method cannot be
1755          * used with this type of service
1756          */
supportsParameter(Object parameter)1757         public boolean supportsParameter(Object parameter) {
1758             EngineDescription cap = knownEngines.get(type);
1759             if (cap == null) {
1760                 // unknown engine type, return true by default
1761                 return true;
1762             }
1763             if (cap.supportsParameter == false) {
1764                 throw new InvalidParameterException("supportsParameter() not "
1765                     + "used with " + type + " engines");
1766             }
1767             // allow null for keys without attributes for compatibility
1768             if ((parameter != null) && (parameter instanceof Key == false)) {
1769                 throw new InvalidParameterException
1770                     ("Parameter must be instanceof Key for engine " + type);
1771             }
1772             if (hasKeyAttributes() == false) {
1773                 return true;
1774             }
1775             if (parameter == null) {
1776                 return false;
1777             }
1778             Key key = (Key)parameter;
1779             if (supportsKeyFormat(key)) {
1780                 return true;
1781             }
1782             if (supportsKeyClass(key)) {
1783                 return true;
1784             }
1785             return false;
1786         }
1787 
1788         /**
1789          * Return whether this service has its Supported* properties for
1790          * keys defined. Parses the attributes if not yet initialized.
1791          */
hasKeyAttributes()1792         private boolean hasKeyAttributes() {
1793             Boolean b = hasKeyAttributes;
1794             if (b == null) {
1795                 synchronized (this) {
1796                     String s;
1797                     s = getAttribute("SupportedKeyFormats");
1798                     if (s != null) {
1799                         supportedFormats = s.split("\\|");
1800                     }
1801                     s = getAttribute("SupportedKeyClasses");
1802                     if (s != null) {
1803                         String[] classNames = s.split("\\|");
1804                         List<Class<?>> classList =
1805                             new ArrayList<>(classNames.length);
1806                         for (String className : classNames) {
1807                             Class<?> clazz = getKeyClass(className);
1808                             if (clazz != null) {
1809                                 classList.add(clazz);
1810                             }
1811                         }
1812                         supportedClasses = classList.toArray(CLASS0);
1813                     }
1814                     boolean bool = (supportedFormats != null)
1815                         || (supportedClasses != null);
1816                     b = Boolean.valueOf(bool);
1817                     hasKeyAttributes = b;
1818                 }
1819             }
1820             return b.booleanValue();
1821         }
1822 
1823         // get the key class object of the specified name
getKeyClass(String name)1824         private Class<?> getKeyClass(String name) {
1825             try {
1826                 return Class.forName(name);
1827             } catch (ClassNotFoundException e) {
1828                 // ignore
1829             }
1830             try {
1831                 ClassLoader cl = provider.getClass().getClassLoader();
1832                 if (cl != null) {
1833                     return cl.loadClass(name);
1834                 }
1835             } catch (ClassNotFoundException e) {
1836                 // ignore
1837             }
1838             return null;
1839         }
1840 
supportsKeyFormat(Key key)1841         private boolean supportsKeyFormat(Key key) {
1842             if (supportedFormats == null) {
1843                 return false;
1844             }
1845             String format = key.getFormat();
1846             if (format == null) {
1847                 return false;
1848             }
1849             for (String supportedFormat : supportedFormats) {
1850                 if (supportedFormat.equals(format)) {
1851                     return true;
1852                 }
1853             }
1854             return false;
1855         }
1856 
supportsKeyClass(Key key)1857         private boolean supportsKeyClass(Key key) {
1858             if (supportedClasses == null) {
1859                 return false;
1860             }
1861             Class<?> keyClass = key.getClass();
1862             for (Class<?> clazz : supportedClasses) {
1863                 if (clazz.isAssignableFrom(keyClass)) {
1864                     return true;
1865                 }
1866             }
1867             return false;
1868         }
1869 
1870         /**
1871          * Return a String representation of this service.
1872          *
1873          * @return a String representation of this service.
1874          */
toString()1875         public String toString() {
1876             String aString = aliases.isEmpty()
1877                 ? "" : "\r\n  aliases: " + aliases.toString();
1878             String attrs = attributes.isEmpty()
1879                 ? "" : "\r\n  attributes: " + attributes.toString();
1880             return provider.getName() + ": " + type + "." + algorithm
1881                 + " -> " + className + aString + attrs + "\r\n";
1882         }
1883 
1884     }
1885 
1886     // BEGIN Android-added: Provider registration
1887     /**
1888      * @hide
1889      */
setRegistered()1890     public void setRegistered() {
1891         registered = true;
1892     }
1893 
1894     /**
1895      * @hide
1896      */
setUnregistered()1897     public void setUnregistered() {
1898         registered = false;
1899     }
1900 
1901     /**
1902      * @hide
1903      */
isRegistered()1904     public boolean isRegistered() {
1905         return registered;
1906     }
1907 
1908     /**
1909      * Ensure the values cached by {@link #getServices} and {@link #getService} are already computed
1910      *
1911      * Used by the zygote so that initialization is performed during preload for the providers
1912      * available at that point.
1913      *
1914      * @hide
1915      */
warmUpServiceProvision()1916     public synchronized void warmUpServiceProvision() {
1917         checkInitialized();
1918         // Further calls do nothing if the services didn't change. If not called here, it would
1919         // parse legacy strings the first time that a service is requested.
1920         ensureLegacyParsed();
1921         // This call to getServices will update fields so that further calls will just return a
1922         // stored field, if the services didn't change in the meantime.
1923         getServices();
1924     }
1925     // END Android-added: Provider registration
1926 }
1927