History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/security/Security.java (1 of 18352 files). Show all

Unified · Split

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