OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / java / security / Security.java
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17
18 package java.security;
19
20
21 import java.io.BufferedInputStream;
22 import java.io.InputStream;
23 import java.util.Enumeration;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Map.Entry;
30 import java.util.Properties;
31 import java.util.Set;
32 import java.util.logging.Level;
33 import java.util.logging.Logger;
34 import org.apache.harmony.security.Util;
35 import org.apache.harmony.security.fortress.Engine;
36 import org.apache.harmony.security.fortress.SecurityAccess;
37 import org.apache.harmony.security.fortress.Services;
38
39 /**
40  * {@code Security} is the central class in the Java Security API. It manages
41  * the list of security {@code Provider} that have been installed into this
42  * runtime environment.
43  */
44 public final class Security {
45
46     // Security properties
47     private static Properties secprops = new Properties();
48
49     // static initialization
50     // - load security properties files
51     // - load statically registered providers
52     // - if no provider description file found then load default providers
53     static {
54         AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {
55             public Void run() {
56                 boolean loaded = false;
57
58                 // BEGIN android-added
59                 /*
60                  * Android only uses a local "security.properties" resource
61                  * for configuration. TODO: Reevaluate this decision.
62                  */
63                 try {
64                     InputStream configStream =
65                         getClass().getResourceAsStream("security.properties");
66                     InputStream input = new BufferedInputStream(configStream);
67                     secprops.load(input);
68                     loaded = true;
69                     configStream.close();
70                 } catch (Exception ex) {
71                     Logger.global.log(Level.SEVERE,
72                             "Could not load Security properties.", ex);
73                 }
74                 // END android-added
75
76                 // BEGIN android-removed
77 //                if (Util.equalsIgnoreCase("true", secprops.getProperty("security.allowCustomPropertiesFile", "true"))) {
78 //                    String securityFile = System.getProperty("java.security.properties");
79 //                    if (securityFile != null) {
80 //                        if (securityFile.startsWith("=")) { // overwrite
81 //                            secprops = new Properties();
82 //                            loaded = false;
83 //                            securityFile = securityFile.substring(1);
84 //                        }
85 //                        try {
86 //                            securityFile = PolicyUtils.expand(securityFile, System.getProperties());
87 //                        } catch (PolicyUtils.ExpansionFailedException e) {
88 ////                            System.err.println("Could not load custom Security properties file "
89 ////                                    + securityFile +": " + e);
90 //                        }
91 //                        f = new File(securityFile);
92 //                        InputStream is;
93 //                        try {
94 //                            if (f.exists()) {
95 //                                FileInputStream fis = new FileInputStream(f);
96 //                                is = new BufferedInputStream(fis);
97 //                            } else {
98 //                                URL url = new URL(securityFile);
99 //                                is = new BufferedInputStream(url.openStream());
100 //                            }
101 //                            secprops.load(is);
102 //                            loaded = true;
103 //                            is.close();
104 //                        } catch (IOException e) {
105 // //                           System.err.println("Could not load custom Security properties file "
106 // //                                   + securityFile +": " + e);
107 //                        }
108 //                    }
109 //                }
110                 // END android-removed
111                 if (!loaded) {
112                     registerDefaultProviders();
113                 }
114                 Engine.door = new SecurityDoor();
115                 return null;
116             }
117         });
118     }
119
120     /**
121      * This class can't be instantiated.
122      */
123     private Security() {
124     }
125
126     // Register default providers
127     private static void registerDefaultProviders() {
128         secprops.put("security.provider.1", "org.apache.harmony.xnet.provider.jsse.OpenSSLProvider");
129         secprops.put("security.provider.2", "org.apache.harmony.security.provider.cert.DRLCertFactory");
130         secprops.put("security.provider.3", "org.bouncycastle.jce.provider.BouncyCastleProvider");
131         secprops.put("security.provider.4", "org.apache.harmony.security.provider.crypto.CryptoProvider");
132         secprops.put("security.provider.5", "org.apache.harmony.xnet.provider.jsse.JSSEProvider");
133     }
134
135     /**
136      * Returns value for the specified algorithm with the specified name.
137      *
138      * @param algName
139      *            the name of the algorithm.
140      * @param propName
141      *            the name of the property.
142      * @return value of the property.
143      * @deprecated Use {@link AlgorithmParameters} and {@link KeyFactory}
144      *             instead.
145      */
146     @Deprecated
147     public static String getAlgorithmProperty(String algName, String propName) {
148         if (algName == null || propName == null) {
149             return null;
150         }
151         // BEGIN android-changed
152         String prop = "Alg." + propName + "." + algName;
153         // END android-changed
154         Provider[] providers = getProviders();
155         for (int i = 0; i < providers.length; i++) {
156             for (Enumeration e = providers[i].propertyNames(); e
157                     .hasMoreElements();) {
158                 String pname = (String) e.nextElement();
159                 if (Util.equalsIgnoreCase(prop, pname)) {
160                     return providers[i].getProperty(pname);
161                 }
162             }
163         }
164         return null;
165     }
166
167     /**
168      * Insert the given {@code Provider} at the specified {@code position}. The
169      * positions define the preference order in which providers are searched for
170      * requested algorithms.
171      * <p>
172      * If a {@code SecurityManager} is installed, code calling this method needs
173      * the {@code SecurityPermission} {@code insertProvider.NAME} (where NAME is
174      * the provider name) to be granted, otherwise a {@code SecurityException}
175      * will be thrown.
176      *
177      * @param provider
178      *            the provider to insert.
179      * @param position
180      *            the position (starting from 1).
181      * @return the actual position or {@code -1} if the given {@code provider}
182      *         was already in the list. The actual position may be different
183      *         from the desired position.
184      * @throws SecurityException
185      *             if a {@code SecurityManager} is installed and the caller does
186      *             not have permission to invoke this method.
187      */
188     public static synchronized int insertProviderAt(Provider provider,
189             int position) {
190         // check security access; check that provider is not already
191         // installed, else return -1; if (position <1) or (position > max
192         // position) position = max position + 1; insert provider, shift up
193         // one position for next providers; Note: The position is 1-based
194         SecurityManager sm = System.getSecurityManager();
195         if (sm != null) {
196             sm.checkSecurityAccess("insertProvider." + provider.getName());
197         }
198         if (getProvider(provider.getName()) != null) {
199             return -1;
200         }
201         int result = Services.insertProviderAt(provider, position);
202         renumProviders();
203         return result;
204     }
205
206     /**
207      * Adds the given {@code provider} to the collection of providers at the
208      * next available position.
209      * <p>
210      * If a {@code SecurityManager} is installed, code calling this method needs
211      * the {@code SecurityPermission} {@code insertProvider.NAME} (where NAME is
212      * the provider name) to be granted, otherwise a {@code SecurityException}
213      * will be thrown.
214      *
215      * @param provider
216      *            the provider to be added.
217      * @return the actual position or {@code -1} if the given {@code provider}
218      *         was already in the list.
219      * @throws SecurityException
220      *             if a {@code SecurityManager} is installed and the caller does
221      *             not have permission to invoke this method.
222      */
223     public static int addProvider(Provider provider) {
224         return insertProviderAt(provider, 0);
225     }
226
227     /**
228      * Removes the {@code Provider} with the specified name form the collection
229      * of providers. If the the {@code Provider} with the specified name is
230      * removed, all provider at a greater position are shifted down one
231      * position.
232      * <p>
233      * Returns silently if {@code name} is {@code null} or no provider with the
234      * specified name is installed.
235      * <p>
236      * If a {@code SecurityManager} is installed, code calling this method needs
237      * the {@code SecurityPermission} {@code removeProvider.NAME} (where NAME is
238      * the provider name) to be granted, otherwise a {@code SecurityException}
239      * will be thrown.
240      *
241      * @param name
242      *            the name of the provider to remove.
243      * @throws SecurityException
244      *             if a {@code SecurityManager} is installed and the caller does
245      *             not have permission to invoke this method.
246      */
247     public static synchronized void removeProvider(String name) {
248         // It is not clear from spec.:
249         // 1. if name is null, should we checkSecurityAccess or not?
250         //    throw SecurityException or not?
251         // 2. as 1 but provider is not installed
252         // 3. behavior if name is empty string?
253
254         Provider p;
255         if ((name == null) || (name.length() == 0)) {
256             return;
257         }
258         p = getProvider(name);
259         if (p == null) {
260             return;
261         }
262         SecurityManager sm = System.getSecurityManager();
263         if (sm != null) {
264             sm.checkSecurityAccess("removeProvider." + name);
265         }
266         Services.removeProvider(p.getProviderNumber());
267         renumProviders();
268         p.setProviderNumber(-1);
269     }
270
271     /**
272      * Returns an array containing all installed providers. The providers are
273      * ordered according their preference order.
274      *
275      * @return an array containing all installed providers.
276      */
277     public static synchronized Provider[] getProviders() {
278         return Services.getProviders();
279     }
280
281     /**
282      * Returns the {@code Provider} with the specified name. Returns {@code
283      * null} if name is {@code null} or no provider with the specified name is
284      * installed.
285      *
286      * @param name
287      *            the name of the requested provider.
288      * @return the provider with the specified name, maybe {@code null}.
289      */
290     public static synchronized Provider getProvider(String name) {
291         return Services.getProvider(name);
292     }
293
294     /**
295      * Returns the array of providers which meet the user supplied string
296      * filter. The specified filter must be supplied in one of two formats:
297      * <nl>
298      * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE
299      * <p>
300      * (for example: "MessageDigest.SHA")
301      * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE
302      * ATTR_NAME:ATTR_VALUE
303      * <p>
304      * (for example: "Signature.MD2withRSA KeySize:512")
305      * </nl>
306      *
307      * @param filter
308      *            case-insensitive filter.
309      * @return the providers which meet the user supplied string filter {@code
310      *         filter}. A {@code null} value signifies that none of the
311      *         installed providers meets the filter specification.
312      * @throws InvalidParameterException
313      *             if an unusable filter is supplied.
314      * @throws NullPointerException
315      *             if {@code filter} is {@code null}.
316      */
317     public static Provider[] getProviders(String filter) {
318         if (filter == null) {
319             throw new NullPointerException();
320         }
321         if (filter.length() == 0) {
322             throw new InvalidParameterException();
323         }
324         HashMap<String, String> hm = new HashMap<String, String>();
325         int i = filter.indexOf(':');
326         if ((i == filter.length() - 1) || (i == 0)) {
327             throw new InvalidParameterException();
328         }
329         if (i < 1) {
330             hm.put(filter, "");
331         } else {
332             hm.put(filter.substring(0, i), filter.substring(i + 1));
333         }
334         return getProviders(hm);
335     }
336
337     /**
338      * Returns the array of providers which meet the user supplied set of
339      * filters. The filter must be supplied in one of two formats:
340      * <nl>
341      * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE
342      * <p>
343      * for example: "MessageDigest.SHA" The value associated with the key must
344      * be an empty string. <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE
345      * ATTR_NAME:ATTR_VALUE
346      * <p>
347      * for example: "Signature.MD2withRSA KeySize:512" where "KeySize:512" is
348      * the value of the filter map entry.
349      * </nl>
350      *
351      * @param filter
352      *            case-insensitive filter.
353      * @return the providers which meet the user supplied string filter {@code
354      *         filter}. A {@code null} value signifies that none of the
355      *         installed providers meets the filter specification.
356      * @throws InvalidParameterException
357      *             if an unusable filter is supplied.
358      * @throws NullPointerException
359      *             if {@code filter} is {@code null}.
360      */
361     public static synchronized Provider[] getProviders(Map<String,String> filter) {
362         if (filter == null) {
363             throw new NullPointerException();
364         }
365         if (filter.isEmpty()) {
366             return null;
367         }
368         java.util.List<Provider> result = Services.getProvidersList();
369         Set<Entry<String, String>> keys = filter.entrySet();
370         Map.Entry<String, String> entry;
371         for (Iterator<Entry<String, String>> it = keys.iterator(); it.hasNext();) {
372             entry = it.next();
373             String key = entry.getKey();
374             String val = entry.getValue();
375             String attribute = null;
376             int i = key.indexOf(' ');
377             int j = key.indexOf('.');
378             if (j == -1) {
379                 throw new InvalidParameterException();
380             }
381             if (i == -1) { // <crypto_service>.<algorithm_or_type>
382                 if (val.length() != 0) {
383                     throw new InvalidParameterException();
384                 }
385             } else { // <crypto_service>.<algorithm_or_type> <attribute_name>
386                 if (val.length() == 0) {
387                     throw new InvalidParameterException();
388                 }
389                 attribute = key.substring(i + 1);
390                 if (attribute.trim().length() == 0) {
391                     throw new InvalidParameterException();
392                 }
393                 key = key.substring(0, i);
394             }
395             String serv = key.substring(0, j);
396             String alg = key.substring(j + 1);
397             if (serv.length() == 0 || alg.length() == 0) {
398                 throw new InvalidParameterException();
399             }
400             Provider p;
401             for (int k = 0; k < result.size(); k++) {
402                 try {
403                     p = result.get(k);
404                 } catch (IndexOutOfBoundsException e) {
405                     break;
406                 }
407                 if (!p.implementsAlg(serv, alg, attribute, val)) {
408                     result.remove(p);
409                     k--;
410                 }
411             }
412         }
413         if (result.size() > 0) {
414             return result.toArray(new Provider[result.size()]);
415         }
416         return null;
417     }
418
419     /**
420      * Returns the value of the security property named by the argument.
421      * <p>
422      * If a {@code SecurityManager} is installed, code calling this method needs
423      * the {@code SecurityPermission} {@code getProperty.KEY} (where KEY is the
424      * specified {@code key}) to be granted, otherwise a {@code
425      * SecurityException} will be thrown.
426      *
427      * @param key
428      *            the name of the requested security property.
429      * @return the value of the security property.
430      * @throws SecurityException
431      *             if a {@code SecurityManager} is installed and the caller does
432      *             not have permission to invoke this method.
433      */
434     public static String getProperty(String key) {
435         if (key == null) {
436             throw new NullPointerException("key == null");
437         }
438         SecurityManager sm = System.getSecurityManager();
439         if (sm != null) {
440             sm.checkSecurityAccess("getProperty." + key);
441         }
442         String property = secprops.getProperty(key);
443         if (property != null) {
444             property = property.trim();
445         }
446         return property;
447     }
448
449     /**
450      * Sets the value of the specified security property.
451      * <p>
452      * If a {@code SecurityManager} is installed, code calling this method needs
453      * the {@code SecurityPermission} {@code setProperty.KEY} (where KEY is the
454      * specified {@code key}) to be granted, otherwise a {@code
455      * SecurityException} will be thrown.
456      *
457      * @param key
458      *            the name of the security property.
459      * @param datnum
460      *            the value of the security property.
461      * @throws SecurityException
462      *             if a {@code SecurityManager} is installed and the caller does
463      *             not have permission to invoke this method.
464      */
465     public static void setProperty(String key, String datnum) {
466         SecurityManager sm = System.getSecurityManager();
467         if (sm != null) {
468             sm.checkSecurityAccess("setProperty." + key);
469         }
470         secprops.put(key, datnum);
471     }
472
473     /**
474      * Returns a {@code Set} of all registered algorithms for the specified
475      * cryptographic service. {@code "Signature"}, {@code "Cipher"} and {@code
476      * "KeyStore"} are examples for such kind of services.
477      *
478      * @param serviceName
479      *            the case-insensitive name of the service.
480      * @return a {@code Set} of all registered algorithms for the specified
481      *         cryptographic service, or an empty {@code Set} if {@code
482      *         serviceName} is {@code null} or if no registered provider
483      *         provides the requested service.
484      */
485     public static Set<String> getAlgorithms(String serviceName) {
486         Set<String> result = new HashSet<String>();
487         // BEGIN android-added
488         // compatibility with RI
489         if (serviceName == null) {
490             return result;
491         }
492         // END android-added
493         Provider[] p = getProviders();
494         for (int i = 0; i < p.length; i++) {
495             for (Iterator it = p[i].getServices().iterator(); it.hasNext();) {
496                 Provider.Service s = (Provider.Service) it.next();
497                 if (Util.equalsIgnoreCase(s.getType(),serviceName)) {
498                     result.add(s.getAlgorithm());
499                 }
500             }
501         }
502         return result;
503     }
504
505     /**
506      *
507      * Update sequence numbers of all providers.
508      *
509      */
510     private static void renumProviders() {
511         Provider[] p = Services.getProviders();
512         for (int i = 0; i < p.length; i++) {
513             p[i].setProviderNumber(i + 1);
514         }
515     }
516
517     private static class SecurityDoor implements SecurityAccess {
518         // Access to Security.renumProviders()
519         public void renumProviders() {
520             Security.renumProviders();
521         }
522
523         //  Access to Security.getAliases()
524         public List<String> getAliases(Provider.Service s) {
525             return s.getAliases();
526         }
527
528         // Access to Provider.getService()
529         public Provider.Service getService(Provider p, String type) {
530             return p.getService(type);
531         }
532     }
533 }