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