KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > security > Security


1 /*
2  * @(#)Security.java 1.126 04/05/18
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.security;
9
10 import java.lang.reflect.*;
11 import java.util.*;
12 import java.util.concurrent.ConcurrentHashMap JavaDoc;
13 import java.io.*;
14 import java.net.URL JavaDoc;
15 import sun.security.util.Debug;
16 import sun.security.util.PropertyExpander;
17
18 import java.security.Provider.Service;
19
20 import sun.security.jca.*;
21
22 /**
23  * <p>This class centralizes all security properties and common security
24  * methods. One of its primary uses is to manage providers.
25  *
26  * @author Benjamin Renaud
27  * @version 1.126, 05/18/04
28  */

29
30 public final class Security {
31     
32     /* Are we debugging? -- for developers */
33     private static final Debug sdebug =
34             Debug.getInstance("properties");
35
36     /* The java.security properties */
37     private static Properties props;
38
39     // An element in the cache
40
private static class ProviderProperty {
41     String JavaDoc className;
42     Provider JavaDoc provider;
43     }
44
45     static {
46     // doPrivileged here because there are multiple
47
// things in initialize that might require privs.
48
// (the FileInputStream call and the File.exists call,
49
// the securityPropFile call, etc)
50
AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
51         public Object JavaDoc run() {
52         initialize();
53         return null;
54         }
55     });
56     }
57     
58     private static void initialize() {
59     props = new Properties();
60     boolean loadedProps = false;
61     boolean overrideAll = false;
62
63     // first load the system properties file
64
// to determine the value of security.overridePropertiesFile
65
File propFile = securityPropFile("java.security");
66     if (propFile.exists()) {
67         try {
68         FileInputStream fis = new FileInputStream(propFile);
69         InputStream is = new BufferedInputStream(fis);
70         props.load(is);
71         is.close();
72         loadedProps = true;
73
74         if (sdebug != null) {
75             sdebug.println("reading security properties file: " +
76                 propFile);
77         }
78         } catch (IOException e) {
79         if (sdebug != null) {
80             sdebug.println("unable to load security properties from " +
81                 propFile);
82             e.printStackTrace();
83         }
84         }
85     }
86
87     if ("true".equalsIgnoreCase(props.getProperty
88         ("security.overridePropertiesFile"))) {
89
90         String JavaDoc extraPropFile = System.getProperty
91                     ("java.security.properties");
92         if (extraPropFile != null && extraPropFile.startsWith("=")) {
93         overrideAll = true;
94         extraPropFile = extraPropFile.substring(1);
95         }
96
97         if (overrideAll) {
98         props = new Properties();
99         if (sdebug != null) {
100             sdebug.println
101             ("overriding other security properties files!");
102         }
103         }
104
105         // now load the user-specified file so its values
106
// will win if they conflict with the earlier values
107
if (extraPropFile != null) {
108         try {
109             URL JavaDoc propURL;
110
111             extraPropFile = PropertyExpander.expand(extraPropFile);
112             propFile = new File(extraPropFile);
113             if (propFile.exists()) {
114             propURL = new URL JavaDoc
115                 ("file:" + propFile.getCanonicalPath());
116             } else {
117             propURL = new URL JavaDoc(extraPropFile);
118             }
119             BufferedInputStream bis = new BufferedInputStream
120                     (propURL.openStream());
121             props.load(bis);
122             bis.close();
123             loadedProps = true;
124
125             if (sdebug != null) {
126             sdebug.println("reading security properties file: " +
127                     propURL);
128             if (overrideAll) {
129                 sdebug.println
130                 ("overriding other security properties files!");
131             }
132             }
133         } catch (Exception JavaDoc e) {
134             if (sdebug != null) {
135             sdebug.println
136                 ("unable to load security properties from " +
137                 extraPropFile);
138             e.printStackTrace();
139             }
140         }
141         }
142     }
143
144     if (!loadedProps) {
145         initializeStatic();
146         if (sdebug != null) {
147         sdebug.println("unable to load security properties " +
148             "-- using defaults");
149         }
150     }
151
152     }
153     
154     /*
155      * Initialize to default values, if <java.home>/lib/java.security
156      * is not found.
157      */

158     private static void initializeStatic() {
159     props.put("security.provider.1", "sun.security.provider.Sun");
160     props.put("security.provider.2", "sun.security.rsa.SunRsaSign");
161     props.put("security.provider.3", "com.sun.net.ssl.internal.ssl.Provider");
162     props.put("security.provider.4", "com.sun.crypto.provider.SunJCE");
163     props.put("security.provider.5", "sun.security.jgss.SunProvider");
164     props.put("security.provider.6", "com.sun.security.sasl.Provider");
165     }
166
167     /**
168      * Don't let anyone instantiate this.
169      */

170     private Security() {
171     }
172
173     private static File securityPropFile(String JavaDoc filename) {
174     // maybe check for a system property which will specify where to
175
// look. Someday.
176
String JavaDoc sep = File.separator;
177     return new File(System.getProperty("java.home") + sep + "lib" + sep +
178             "security" + sep + filename);
179     }
180
181     /**
182      * Looks up providers, and returns the property (and its associated
183      * provider) mapping the key, if any.
184      * The order in which the providers are looked up is the
185      * provider-preference order, as specificed in the security
186      * properties file.
187      */

188     private static ProviderProperty getProviderProperty(String JavaDoc key) {
189     ProviderProperty entry = null;
190
191     List providers = Providers.getProviderList().providers();
192     for (int i = 0; i < providers.size(); i++) {
193
194         String JavaDoc matchKey = null;
195         Provider JavaDoc prov = (Provider JavaDoc)providers.get(i);
196         String JavaDoc prop = prov.getProperty(key);
197
198         if (prop == null) {
199         // Is there a match if we do a case-insensitive property name
200
// comparison? Let's try ...
201
for (Enumeration e = prov.keys();
202              e.hasMoreElements() && prop == null; ) {
203             matchKey = (String JavaDoc)e.nextElement();
204             if (key.equalsIgnoreCase(matchKey)) {
205             prop = prov.getProperty(matchKey);
206             break;
207             }
208         }
209         }
210
211         if (prop != null) {
212         ProviderProperty newEntry = new ProviderProperty();
213         newEntry.className = prop;
214         newEntry.provider = prov;
215         return newEntry;
216         }
217     }
218
219     return entry;
220     }
221
222     /**
223      * Returns the property (if any) mapping the key for the given provider.
224      */

225     private static String JavaDoc getProviderProperty(String JavaDoc key, Provider JavaDoc provider) {
226     String JavaDoc prop = provider.getProperty(key);
227     if (prop == null) {
228         // Is there a match if we do a case-insensitive property name
229
// comparison? Let's try ...
230
for (Enumeration e = provider.keys();
231          e.hasMoreElements() && prop == null; ) {
232         String JavaDoc matchKey = (String JavaDoc)e.nextElement();
233         if (key.equalsIgnoreCase(matchKey)) {
234             prop = provider.getProperty(matchKey);
235             break;
236         }
237         }
238     }
239     return prop;
240     }
241
242     /**
243      * Gets a specified property for an algorithm. The algorithm name
244      * should be a standard name. See Appendix A in the <a HREF=
245      * "../../../guide/security/CryptoSpec.html#AppA">
246      * Java Cryptography Architecture API Specification &amp; Reference </a>
247      * for information about standard algorithm names.
248      * One possible use is by specialized algorithm parsers, which may map
249      * classes to algorithms which they understand (much like Key parsers
250      * do).
251      *
252      * @param algName the algorithm name.
253      *
254      * @param propName the name of the property to get.
255      *
256      * @return the value of the specified property.
257      *
258      * @deprecated This method used to return the value of a proprietary
259      * property in the master file of the "SUN" Cryptographic Service
260      * Provider in order to determine how to parse algorithm-specific
261      * parameters. Use the new provider-based and algorithm-independent
262      * <code>AlgorithmParameters</code> and <code>KeyFactory</code> engine
263      * classes (introduced in the Java 2 platform) instead.
264      */

265     @Deprecated JavaDoc
266     public static String JavaDoc getAlgorithmProperty(String JavaDoc algName,
267                           String JavaDoc propName) {
268     ProviderProperty entry = getProviderProperty("Alg." + propName
269                              + "." + algName);
270     if (entry != null) {
271         return entry.className;
272     } else {
273         return null;
274     }
275     }
276
277     /**
278      * Adds a new provider, at a specified position. The position is
279      * the preference order in which providers are searched for
280      * requested algorithms. Note that it is not guaranteed that this
281      * preference will be respected. The position is 1-based, that is,
282      * 1 is most preferred, followed by 2, and so on.
283      *
284      * <p>If the given provider is installed at the requested position,
285      * the provider that used to be at that position, and all providers
286      * with a position greater than <code>position</code>, are shifted up
287      * one position (towards the end of the list of installed providers).
288      *
289      * <p>A provider cannot be added if it is already installed.
290      *
291      * <p>First, if there is a security manager, its
292      * <code>checkSecurityAccess</code>
293      * method is called with the string
294      * <code>"insertProvider."+provider.getName()</code>
295      * to see if it's ok to add a new provider.
296      * If the default implementation of <code>checkSecurityAccess</code>
297      * is used (i.e., that method is not overriden), then this will result in
298      * a call to the security manager's <code>checkPermission</code> method
299      * with a
300      * <code>SecurityPermission("insertProvider."+provider.getName())</code>
301      * permission.
302      *
303      * @param provider the provider to be added.
304      *
305      * @param position the preference position that the caller would
306      * like for this provider.
307      *
308      * @return the actual preference position in which the provider was
309      * added, or -1 if the provider was not added because it is
310      * already installed.
311      *
312      * @throws NullPointerException if provider is null
313      * @throws SecurityException
314      * if a security manager exists and its <code>{@link
315      * java.lang.SecurityManager#checkSecurityAccess}</code> method
316      * denies access to add a new provider
317      *
318      * @see #getProvider
319      * @see #removeProvider
320      * @see java.security.SecurityPermission
321      */

322     public static synchronized int insertProviderAt(Provider JavaDoc provider,
323         int position) {
324     String JavaDoc providerName = provider.getName();
325     check("insertProvider." + providerName);
326     ProviderList list = Providers.getFullProviderList();
327     ProviderList newList = ProviderList.insertAt(list, provider, position - 1);
328     if (list == newList) {
329         return -1;
330     }
331     Providers.setProviderList(newList);
332     return newList.getIndex(providerName) + 1;
333     }
334
335     /**
336      * Adds a provider to the next position available.
337      *
338      * <p>First, if there is a security manager, its
339      * <code>checkSecurityAccess</code>
340      * method is called with the string
341      * <code>"insertProvider."+provider.getName()</code>
342      * to see if it's ok to add a new provider.
343      * If the default implementation of <code>checkSecurityAccess</code>
344      * is used (i.e., that method is not overriden), then this will result in
345      * a call to the security manager's <code>checkPermission</code> method
346      * with a
347      * <code>SecurityPermission("insertProvider."+provider.getName())</code>
348      * permission.
349      *
350      * @param provider the provider to be added.
351      *
352      * @return the preference position in which the provider was
353      * added, or -1 if the provider was not added because it is
354      * already installed.
355      *
356      * @throws NullPointerException if provider is null
357      * @throws SecurityException
358      * if a security manager exists and its <code>{@link
359      * java.lang.SecurityManager#checkSecurityAccess}</code> method
360      * denies access to add a new provider
361      *
362      * @see #getProvider
363      * @see #removeProvider
364      * @see java.security.SecurityPermission
365      */

366     public static int addProvider(Provider JavaDoc provider) {
367     /*
368      * We can't assign a position here because the statically
369      * registered providers may not have been installed yet.
370      * insertProviderAt() will fix that value after it has
371      * loaded the static providers.
372      */

373     return insertProviderAt(provider, 0);
374     }
375
376     /**
377      * Removes the provider with the specified name.
378      *
379      * <p>When the specified provider is removed, all providers located
380      * at a position greater than where the specified provider was are shifted
381      * down one position (towards the head of the list of installed
382      * providers).
383      *
384      * <p>This method returns silently if the provider is not installed or
385      * if name is null.
386      *
387      * <p>First, if there is a security manager, its
388      * <code>checkSecurityAccess</code>
389      * method is called with the string <code>"removeProvider."+name</code>
390      * to see if it's ok to remove the provider.
391      * If the default implementation of <code>checkSecurityAccess</code>
392      * is used (i.e., that method is not overriden), then this will result in
393      * a call to the security manager's <code>checkPermission</code> method
394      * with a <code>SecurityPermission("removeProvider."+name)</code>
395      * permission.
396      *
397      * @param name the name of the provider to remove.
398      *
399      * @throws SecurityException
400      * if a security manager exists and its <code>{@link
401      * java.lang.SecurityManager#checkSecurityAccess}</code> method
402      * denies
403      * access to remove the provider
404      *
405      * @see #getProvider
406      * @see #addProvider
407      */

408     public static synchronized void removeProvider(String JavaDoc name) {
409     check("removeProvider." + name);
410     ProviderList list = Providers.getFullProviderList();
411     ProviderList newList = ProviderList.remove(list, name);
412     Providers.setProviderList(newList);
413     }
414
415     /**
416      * Returns an array containing all the installed providers. The order of
417      * the providers in the array is their preference order.
418      *
419      * @return an array of all the installed providers.
420      */

421     public static Provider JavaDoc[] getProviders() {
422     return Providers.getFullProviderList().toArray();
423     }
424
425     /**
426      * Returns the provider installed with the specified name, if
427      * any. Returns null if no provider with the specified name is
428      * installed or if name is null.
429      *
430      * @param name the name of the provider to get.
431      *
432      * @return the provider of the specified name.
433      *
434      * @see #removeProvider
435      * @see #addProvider
436      */

437     public static Provider JavaDoc getProvider(String JavaDoc name) {
438     return Providers.getProviderList().getProvider(name);
439     }
440
441     /**
442      * Returns an array containing all installed providers that satisfy the
443      * specified selection criterion, or null if no such providers have been
444      * installed. The returned providers are ordered
445      * according to their <a HREF=
446      * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
447      *
448      * <p> A cryptographic service is always associated with a particular
449      * algorithm or type. For example, a digital signature service is
450      * always associated with a particular algorithm (e.g., DSA),
451      * and a CertificateFactory service is always associated with
452      * a particular certificate type (e.g., X.509).
453      *
454      * <p>The selection criterion must be specified in one of the following two
455      * formats:
456      * <ul>
457      * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type></i> <p> The
458      * cryptographic service name must not contain any dots.
459      * <p> A
460      * provider satisfies the specified selection criterion iff the provider
461      * implements the
462      * specified algorithm or type for the specified cryptographic service.
463      * <p> For example, "CertificateFactory.X.509"
464      * would be satisfied by any provider that supplied
465      * a CertificateFactory implementation for X.509 certificates.
466      * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type>
467      * &lt;attribute_name>:&lt attribute_value></i>
468      * <p> The cryptographic service name must not contain any dots. There
469      * must be one or more space charaters between the the
470      * <i>&lt;algorithm_or_type></i> and the <i>&lt;attribute_name></i>.
471      * <p> A provider satisfies this selection criterion iff the
472      * provider implements the specified algorithm or type for the specified
473      * cryptographic service and its implementation meets the
474      * constraint expressed by the specified attribute name/value pair.
475      * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
476      * satisfied by any provider that implemented
477      * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
478      *
479      * </ul>
480      *
481      * <p> See Appendix A in the <a HREF=
482      * "../../../guide/security/CryptoSpec.html#AppA">
483      * Java Cryptogaphy Architecture API Specification &amp; Reference </a>
484      * for information about standard cryptographic service names, standard
485      * algorithm names and standard attribute names.
486      *
487      * @param filter the criterion for selecting
488      * providers. The filter is case-insensitive.
489      *
490      * @return all the installed providers that satisfy the selection
491      * criterion, or null if no such providers have been installed.
492      *
493      * @throws InvalidParameterException
494      * if the filter is not in the required format
495      * @throws NullPointerException if filter is null
496      *
497      * @see #getProviders(java.util.Map)
498      */

499     public static Provider JavaDoc[] getProviders(String JavaDoc filter) {
500     String JavaDoc key = null;
501     String JavaDoc value = null;
502     int index = filter.indexOf(':');
503
504     if (index == -1) {
505         key = filter;
506         value = "";
507     } else {
508         key = filter.substring(0, index);
509         value = filter.substring(index + 1);
510     }
511
512     Hashtable hashtableFilter = new Hashtable(1);
513     hashtableFilter.put(key, value);
514
515     return (getProviders(hashtableFilter));
516     }
517
518     /**
519      * Returns an array containing all installed providers that satisfy the
520      * specified* selection criteria, or null if no such providers have been
521      * installed. The returned providers are ordered
522      * according to their <a HREF=
523      * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
524      *
525      * <p>The selection criteria are represented by a map.
526      * Each map entry represents a selection criterion.
527      * A provider is selected iff it satisfies all selection
528      * criteria. The key for any entry in such a map must be in one of the
529      * following two formats:
530      * <ul>
531      * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type></i>
532      * <p> The cryptographic service name must not contain any dots.
533      * <p> The value associated with the key must be an empty string.
534      * <p> A provider
535      * satisfies this selection criterion iff the provider implements the
536      * specified algorithm or type for the specified cryptographic service.
537      * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type> &lt;attribute_name></i>
538      * <p> The cryptographic service name must not contain any dots. There
539      * must be one or more space charaters between the <i>&lt;algorithm_or_type></i>
540      * and the <i>&lt;attribute_name></i>.
541      * <p> The value associated with the key must be a non-empty string.
542      * A provider satisfies this selection criterion iff the
543      * provider implements the specified algorithm or type for the specified
544      * cryptographic service and its implementation meets the
545      * constraint expressed by the specified attribute name/value pair.
546      * </ul>
547      *
548      * <p> See Appendix A in the <a HREF=
549      * "../../../guide/security/CryptoSpec.html#AppA">
550      * Java Cryptogaphy Architecture API Specification &amp; Reference </a>
551      * for information about standard cryptographic service names, standard
552      * algorithm names and standard attribute names.
553      *
554      * @param filter the criteria for selecting
555      * providers. The filter is case-insensitive.
556      *
557      * @return all the installed providers that satisfy the selection
558      * criteria, or null if no such providers have been installed.
559      *
560      * @throws InvalidParameterException
561      * if the filter is not in the required format
562      * @throws NullPointerException if filter is null
563      *
564      * @see #getProviders(java.lang.String)
565      */

566     public static Provider JavaDoc[] getProviders(Map JavaDoc<String JavaDoc,String JavaDoc> filter) {
567     // Get all installed providers first.
568
// Then only return those providers who satisfy the selection criteria.
569
Provider JavaDoc[] allProviders = Security.getProviders();
570     Set keySet = filter.keySet();
571     LinkedHashSet candidates = new LinkedHashSet(5);
572
573     // Returns all installed providers
574
// if the selection criteria is null.
575
if ((keySet == null) || (allProviders == null)) {
576         return allProviders;
577     }
578     
579     boolean firstSearch = true;
580
581     // For each selection criterion, remove providers
582
// which don't satisfy the criterion from the candidate set.
583
for (Iterator ite = keySet.iterator(); ite.hasNext(); ) {
584         String JavaDoc key = (String JavaDoc)ite.next();
585         String JavaDoc value = (String JavaDoc)filter.get(key);
586         
587         LinkedHashSet newCandidates = getAllQualifyingCandidates(key, value,
588                                    allProviders);
589         if (firstSearch) {
590         candidates = newCandidates;
591         firstSearch = false;
592         }
593
594         if ((newCandidates != null) && !newCandidates.isEmpty()) {
595         // For each provider in the candidates set, if it
596
// isn't in the newCandidate set, we should remove
597
// it from the candidate set.
598
for (Iterator cansIte = candidates.iterator();
599              cansIte.hasNext(); ) {
600             Provider JavaDoc prov = (Provider JavaDoc)cansIte.next();
601             if (!newCandidates.contains(prov)) {
602             cansIte.remove();
603             }
604         }
605         } else {
606         candidates = null;
607         break;
608         }
609     }
610
611     if ((candidates == null) || (candidates.isEmpty()))
612         return null;
613
614     Object JavaDoc[] candidatesArray = candidates.toArray();
615     Provider JavaDoc[] result = new Provider JavaDoc[candidatesArray.length];
616
617     for (int i = 0; i < result.length; i++) {
618         result[i] = (Provider JavaDoc)candidatesArray[i];
619     }
620     
621     return result;
622     }
623     
624     // Map containing cached Spi Class objects of the specified type
625
private static final Map JavaDoc<String JavaDoc,Class JavaDoc> spiMap =
626                 new ConcurrentHashMap JavaDoc<String JavaDoc,Class JavaDoc>();
627     
628     /**
629      * Return the Class object for the given engine type
630      * (e.g. "MessageDigest"). Works for Spis in the java.security package
631      * only.
632      */

633     private static Class JavaDoc getSpiClass(String JavaDoc type) {
634     Class JavaDoc clazz = spiMap.get(type);
635     if (clazz != null) {
636         return clazz;
637     }
638     try {
639         clazz = Class.forName("java.security." + type + "Spi");
640         spiMap.put(type, clazz);
641         return clazz;
642     } catch (ClassNotFoundException JavaDoc e) {
643         throw (Error JavaDoc)new AssertionError JavaDoc("Spi class not found").initCause(e);
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</code> argument can be null, in which case all
653      * configured providers will be searched in order of preference.
654      */

655     static Object JavaDoc[] getImpl(String JavaDoc algorithm, String JavaDoc type, String JavaDoc provider)
656         throws NoSuchAlgorithmException JavaDoc, NoSuchProviderException JavaDoc {
657     if (provider == null) {
658         return GetInstance.getInstance
659             (type, getSpiClass(type), algorithm).toArray();
660     } else {
661         return GetInstance.getInstance
662             (type, getSpiClass(type), algorithm, provider).toArray();
663     }
664     }
665
666     static Object JavaDoc[] getImpl(String JavaDoc algorithm, String JavaDoc type, String JavaDoc provider,
667         Object JavaDoc params) throws NoSuchAlgorithmException JavaDoc,
668         NoSuchProviderException JavaDoc, InvalidAlgorithmParameterException JavaDoc {
669     if (provider == null) {
670         return GetInstance.getInstance
671             (type, getSpiClass(type), algorithm, params).toArray();
672     } else {
673         return GetInstance.getInstance
674             (type, getSpiClass(type), algorithm, params, provider).toArray();
675     }
676     }
677
678     /*
679      * Returns an array of objects: the first object in the array is
680      * an instance of an implementation of the requested algorithm
681      * and type, and the second object in the array identifies the provider
682      * of that implementation.
683      * The <code>provider</code> argument cannot be null.
684      */

685     static Object JavaDoc[] getImpl(String JavaDoc algorithm, String JavaDoc type, Provider JavaDoc provider)
686         throws NoSuchAlgorithmException JavaDoc {
687     return GetInstance.getInstance
688         (type, getSpiClass(type), algorithm, provider).toArray();
689     }
690
691     static Object JavaDoc[] getImpl(String JavaDoc algorithm, String JavaDoc type, Provider JavaDoc provider,
692         Object JavaDoc params) throws NoSuchAlgorithmException JavaDoc,
693         InvalidAlgorithmParameterException JavaDoc {
694     return GetInstance.getInstance
695         (type, getSpiClass(type), algorithm, params, provider).toArray();
696     }
697
698     /**
699      * Gets a security property value.
700      *
701      * <p>First, if there is a security manager, its
702      * <code>checkPermission</code> method is called with a
703      * <code>java.security.SecurityPermission("getProperty."+key)</code>
704      * permission to see if it's ok to retrieve the specified
705      * security property value..
706      *
707      * @param key the key of the property being retrieved.
708      *
709      * @return the value of the security property corresponding to key.
710      *
711      * @throws SecurityException
712      * if a security manager exists and its <code>{@link
713      * java.lang.SecurityManager#checkPermission}</code> method
714      * denies
715      * access to retrieve the specified security property value
716      * @throws NullPointerException is key is null
717      *
718      * @see #setProperty
719      * @see java.security.SecurityPermission
720      */

721     public static String JavaDoc getProperty(String JavaDoc key) {
722     SecurityManager JavaDoc sm = System.getSecurityManager();
723     if (sm != null) {
724         sm.checkPermission(new SecurityPermission JavaDoc("getProperty."+
725                               key));
726     }
727     String JavaDoc name = props.getProperty(key);
728     if (name != null)
729         name = name.trim(); // could be a class name with trailing ws
730
return name;
731     }
732
733     /**
734      * Sets a security property value.
735      *
736      * <p>First, if there is a security manager, its
737      * <code>checkPermission</code> method is called with a
738      * <code>java.security.SecurityPermission("setProperty."+key)</code>
739      * permission to see if it's ok to set the specified
740      * security property value.
741      *
742      * @param key the name of the property to be set.
743      *
744      * @param datum the value of the property to be set.
745      *
746      * @throws SecurityException
747      * if a security manager exists and its <code>{@link
748      * java.lang.SecurityManager#checkPermission}</code> method
749      * denies access to set the specified security property value
750      * @throws NullPointerException if key or datum is null
751      *
752      * @see #getProperty
753      * @see java.security.SecurityPermission
754      */

755     public static void setProperty(String JavaDoc key, String JavaDoc datum) {
756     check("setProperty."+key);
757     props.put(key, datum);
758     invalidateSMCache(key); /* See below. */
759     }
760
761     /*
762      * Implementation detail: If the property we just set in
763      * setProperty() was either "package.access" or
764      * "package.definition", we need to signal to the SecurityManager
765      * class that the value has just changed, and that it should
766      * invalidate it's local cache values.
767      *
768      * Rather than create a new API entry for this function,
769      * we use reflection to set a private variable.
770      */

771     private static void invalidateSMCache(String JavaDoc key) {
772     
773     final boolean pa = key.equals("package.access");
774     final boolean pd = key.equals("package.definition");
775
776     if (pa || pd) {
777         AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
778         public Object JavaDoc run() {
779             try {
780             /* Get the class via the bootstrap class loader. */
781             Class JavaDoc cl = Class.forName(
782                 "java.lang.SecurityManager", false, null);
783             Field f = null;
784             boolean accessible = false;
785
786             if (pa) {
787                 f = cl.getDeclaredField("packageAccessValid");
788                 accessible = f.isAccessible();
789                 f.setAccessible(true);
790             } else {
791                 f = cl.getDeclaredField("packageDefinitionValid");
792                 accessible = f.isAccessible();
793                 f.setAccessible(true);
794             }
795             f.setBoolean(f, false);
796             f.setAccessible(accessible);
797             }
798             catch (Exception JavaDoc e1) {
799             /* If we couldn't get the class, it hasn't
800              * been loaded yet. If there is no such
801              * field, we shouldn't try to set it. There
802              * shouldn't be a security execption, as we
803              * are loaded by boot class loader, and we
804              * are inside a doPrivileged() here.
805              *
806              * NOOP: don't do anything...
807              */

808             }
809             return null;
810         } /* run */
811         }); /* PrivilegedAction */
812     } /* if */
813     }
814
815     private static void check(String JavaDoc directive) {
816     SecurityManager JavaDoc security = System.getSecurityManager();
817     if (security != null) {
818         security.checkSecurityAccess(directive);
819     }
820     }
821     
822     /*
823     * Returns all providers who satisfy the specified
824     * criterion.
825     */

826     private static LinkedHashSet getAllQualifyingCandidates(String JavaDoc filterKey,
827                          String JavaDoc filterValue,
828                          Provider JavaDoc[] allProviders) {
829     String JavaDoc[] filterComponents = getFilterComponents(filterKey,
830                             filterValue);
831
832     // The first component is the service name.
833
// The second is the algorithm name.
834
// If the third isn't null, that is the attrinute name.
835
String JavaDoc serviceName = filterComponents[0];
836     String JavaDoc algName = filterComponents[1];
837     String JavaDoc attrName = filterComponents[2];
838
839     return getProvidersNotUsingCache(serviceName, algName, attrName,
840                      filterValue, allProviders);
841     }
842     
843     private static LinkedHashSet getProvidersNotUsingCache(String JavaDoc serviceName,
844                              String JavaDoc algName,
845                              String JavaDoc attrName,
846                              String JavaDoc filterValue,
847                              Provider JavaDoc[] allProviders) {
848     LinkedHashSet candidates = new LinkedHashSet(5);
849     for (int i = 0; i < allProviders.length; i++) {
850         if (isCriterionSatisfied(allProviders[i], serviceName,
851                      algName,
852                      attrName, filterValue)) {
853         candidates.add(allProviders[i]);
854         }
855     }
856     return candidates;
857     }
858
859     /*
860      * Returns true if the given provider satisfies
861      * the selection criterion key:value.
862      */

863     private static boolean isCriterionSatisfied(Provider JavaDoc prov,
864                         String JavaDoc serviceName,
865                         String JavaDoc algName,
866                         String JavaDoc attrName,
867                         String JavaDoc filterValue) {
868     String JavaDoc key = serviceName + '.' + algName;
869
870     if (attrName != null) {
871         key += ' ' + attrName;
872     }
873         // Check whether the provider has a property
874
// whose key is the same as the given key.
875
String JavaDoc propValue = getProviderProperty(key, prov);
876
877     if (propValue == null) {
878         // Check whether we have an alias instead
879
// of a standard name in the key.
880
String JavaDoc standardName = getProviderProperty("Alg.Alias." +
881                               serviceName + "." +
882                               algName,
883                               prov);
884         if (standardName != null) {
885         key = serviceName + "." + standardName;
886
887         if (attrName != null) {
888             key += ' ' + attrName;
889         }
890
891         propValue = getProviderProperty(key, prov);
892         }
893         
894         if (propValue == null) {
895         // The provider doesn't have the given
896
// key in its property list.
897
return false;
898         }
899     }
900
901     // If the key is in the format of:
902
// <crypto_service>.<algorithm_or_type>,
903
// there is no need to check the value.
904

905     if (attrName == null) {
906         return true;
907     }
908
909     // If we get here, the key must be in the
910
// format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
911
if (isStandardAttr(attrName)) {
912         return isConstraintSatisfied(attrName, filterValue, propValue);
913     } else {
914         return filterValue.equalsIgnoreCase(propValue);
915     }
916     }
917         
918     /*
919      * Returns true if the attribute is a standard attribute;
920      * otherwise, returns false.
921      */

922     private static boolean isStandardAttr(String JavaDoc attribute) {
923     // For now, we just have two standard attributes:
924
// KeySize and ImplementedIn.
925
if (attribute.equalsIgnoreCase("KeySize"))
926         return true;
927     
928     if (attribute.equalsIgnoreCase("ImplementedIn"))
929         return true;
930
931     return false;
932     }
933
934     /*
935      * Returns true if the requested attribute value is supported;
936      * otherwise, returns false.
937      */

938     private static boolean isConstraintSatisfied(String JavaDoc attribute,
939                          String JavaDoc value,
940                          String JavaDoc prop) {
941     // For KeySize, prop is the max key size the
942
// provider supports for a specific <crypto_service>.<algorithm>.
943
if (attribute.equalsIgnoreCase("KeySize")) {
944         int requestedSize = Integer.parseInt(value);
945         int maxSize = Integer.parseInt(prop);
946         if (requestedSize <= maxSize) {
947         return true;
948         } else {
949         return false;
950         }
951     }
952
953     // For Type, prop is the type of the implementation
954
// for a specific <crypto service>.<algorithm>.
955
if (attribute.equalsIgnoreCase("ImplementedIn")) {
956         return value.equalsIgnoreCase(prop);
957     }
958
959     return false;
960     }
961
962     static String JavaDoc[] getFilterComponents(String JavaDoc filterKey, String JavaDoc filterValue) {
963     int algIndex = filterKey.indexOf('.');
964
965     if (algIndex < 0) {
966         // There must be a dot in the filter, and the dot
967
// shouldn't be at the beginning of this string.
968
throw new InvalidParameterException JavaDoc("Invalid filter");
969     }
970
971     String JavaDoc serviceName = filterKey.substring(0, algIndex);
972     String JavaDoc algName = null;
973     String JavaDoc attrName = null;
974
975     if (filterValue.length() == 0) {
976         // The filterValue is an empty string. So the filterKey
977
// should be in the format of <crypto_service>.<algorithm_or_type>.
978
algName = filterKey.substring(algIndex + 1).trim();
979         if (algName.length() == 0) {
980         // There must be a algorithm or type name.
981
throw new InvalidParameterException JavaDoc("Invalid filter");
982         }
983     } else {
984         // The filterValue is a non-empty string. So the filterKey must be
985
// in the format of
986
// <crypto_service>.<algorithm_or_type> <attribute_name>
987
int attrIndex = filterKey.indexOf(' ');
988
989         if (attrIndex == -1) {
990         // There is no attribute name in the filter.
991
throw new InvalidParameterException JavaDoc("Invalid filter");
992         } else {
993         attrName = filterKey.substring(attrIndex + 1).trim();
994         if (attrName.length() == 0) {
995             // There is no attribute name in the filter.
996
throw new InvalidParameterException JavaDoc("Invalid filter");
997         }
998         }
999     
1000        // There must be an algorithm name in the filter.
1001
if ((attrIndex < algIndex) ||
1002        (algIndex == attrIndex - 1)) {
1003        throw new InvalidParameterException JavaDoc("Invalid filter");
1004        } else {
1005        algName = filterKey.substring(algIndex + 1, attrIndex);
1006        }
1007    }
1008
1009    String JavaDoc[] result = new String JavaDoc[3];
1010    result[0] = serviceName;
1011    result[1] = algName;
1012    result[2] = attrName;
1013
1014    return result;
1015    }
1016
1017    /**
1018     * Returns a Set of Strings containing the names of all available
1019     * algorithms or types for the specified Java cryptographic service
1020     * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns
1021     * an empty Set if there is no provider that supports the
1022     * specified service or if serviceName is null. For a complete list
1023     * of Java cryptographic services, please see the
1024     * <a HREF="../../../guide/security/CryptoSpec.html">Java
1025     * Cryptography Architecture API Specification &amp; Reference</a>.
1026     * Note: the returned set is immutable.
1027     *
1028     * @param serviceName the name of the Java cryptographic
1029     * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
1030     * Note: this parameter is case-insensitive.
1031     *
1032     * @return a Set of Strings containing the names of all available
1033     * algorithms or types for the specified Java cryptographic service
1034     * or an empty set if no provider supports the specified service.
1035     *
1036     * @since 1.4
1037     **/

1038    public static Set<String JavaDoc> getAlgorithms(String JavaDoc serviceName) {
1039
1040    if ((serviceName == null) || (serviceName.length() == 0) ||
1041        (serviceName.endsWith("."))) {
1042        return Collections.EMPTY_SET;
1043    }
1044
1045    HashSet result = new HashSet();
1046    Provider JavaDoc[] providers = Security.getProviders();
1047
1048    for (int i = 0; i < providers.length; i++) {
1049        // Check the keys for each provider.
1050
for (Enumeration e = providers[i].keys(); e.hasMoreElements(); ) {
1051        String JavaDoc currentKey = ((String JavaDoc)e.nextElement()).toUpperCase();
1052        if (currentKey.startsWith(serviceName.toUpperCase())) {
1053            // We should skip the currentKey if it contains a
1054
// whitespace. The reason is: such an entry in the
1055
// provider property contains attributes for the
1056
// implementation of an algorithm. We are only interested
1057
// in entries which lead to the implementation
1058
// classes.
1059
if (currentKey.indexOf(" ") < 0) {
1060            result.add(currentKey.substring(serviceName.length() + 1));
1061            }
1062        }
1063        }
1064    }
1065    return Collections.unmodifiableSet(result);
1066    }
1067}
1068
1069
Popular Tags