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