Add C++11 header <cuchar>.
[official-gcc.git] / libjava / classpath / java / security / Security.java
blob6cd98b0fb842680ef83de09b61f8b0c4c7f43b62
1 /* Security.java --- Java base security class implementation
2 Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package java.security;
42 import gnu.classpath.SystemProperties;
44 import gnu.classpath.Configuration;
45 import gnu.classpath.VMStackWalker;
47 import java.io.IOException;
48 import java.io.InputStream;
49 import java.net.URL;
50 import java.util.Collections;
51 import java.util.Enumeration;
52 import java.util.HashMap;
53 import java.util.HashSet;
54 import java.util.Iterator;
55 import java.util.LinkedHashSet;
56 import java.util.Map;
57 import java.util.Properties;
58 import java.util.Set;
59 import java.util.Vector;
61 /**
62 * This class centralizes all security properties and common security methods.
63 * One of its primary uses is to manage security providers.
65 * @author Mark Benvenuto (ivymccough@worldnet.att.net)
67 public final class Security
69 private static final String ALG_ALIAS = "Alg.Alias.";
71 private static Vector providers = new Vector();
72 private static Properties secprops = new Properties();
74 static
76 String base = SystemProperties.getProperty("gnu.classpath.home.url");
77 String vendor = SystemProperties.getProperty("gnu.classpath.vm.shortname");
79 // Try VM specific security file
80 boolean loaded = loadProviders (base, vendor);
82 // Append classpath standard provider if possible
83 if (!loadProviders (base, "classpath")
84 && !loaded
85 && providers.size() == 0)
87 if (Configuration.DEBUG)
89 /* No providers found and both security files failed to
90 * load properly. Give a warning in case of DEBUG is
91 * enabled. Could be done with java.util.logging later.
93 System.err.println
94 ("WARNING: could not properly read security provider files:");
95 System.err.println
96 (" " + base + "/security/" + vendor
97 + ".security");
98 System.err.println
99 (" " + base + "/security/" + "classpath"
100 + ".security");
101 System.err.println
102 (" Falling back to standard GNU security provider");
104 // Note that this matches our classpath.security file.
105 providers.addElement (new gnu.java.security.provider.Gnu());
106 providers.addElement(new gnu.javax.crypto.jce.GnuCrypto());
107 providers.addElement(new gnu.javax.crypto.jce.GnuSasl());
108 providers.addElement(new gnu.javax.net.ssl.provider.Jessie());
109 providers.addElement(new gnu.javax.security.auth.callback.GnuCallbacks());
112 // This class can't be instantiated.
113 private Security()
118 * Tries to load the vender specific security providers from the given base
119 * URL. Returns true if the resource could be read and completely parsed
120 * successfully, false otherwise.
122 private static boolean loadProviders(String baseUrl, String vendor)
124 if (baseUrl == null || vendor == null)
125 return false;
127 boolean result = true;
128 String secfilestr = baseUrl + "/security/" + vendor + ".security";
131 InputStream fin = new URL(secfilestr).openStream();
132 secprops.load(fin);
134 int i = 1;
135 String name;
136 while ((name = secprops.getProperty("security.provider." + i)) != null)
138 Exception exception = null;
141 ClassLoader sys = ClassLoader.getSystemClassLoader();
142 providers.addElement(Class.forName(name, true, sys).newInstance());
144 catch (ClassNotFoundException x)
146 exception = x;
148 catch (InstantiationException x)
150 exception = x;
152 catch (IllegalAccessException x)
154 exception = x;
157 if (exception != null)
159 System.err.println ("WARNING: Error loading security provider "
160 + name + ": " + exception);
161 result = false;
163 i++;
166 catch (IOException ignored)
168 result = false;
171 return result;
175 * Returns the value associated to a designated property name for a given
176 * algorithm.
178 * @param algName
179 * the algorithm name.
180 * @param propName
181 * the name of the property to return.
182 * @return the value of the specified property or <code>null</code> if none
183 * found.
184 * @deprecated Use the provider-based and algorithm-independent
185 * {@link AlgorithmParameters} and {@link KeyFactory} engine
186 * classes instead.
188 public static String getAlgorithmProperty(String algName, String propName)
190 if (algName == null || propName == null)
191 return null;
193 String property = String.valueOf(propName) + "." + String.valueOf(algName);
194 Provider p;
195 for (Iterator i = providers.iterator(); i.hasNext(); )
197 p = (Provider) i.next();
198 for (Iterator j = p.keySet().iterator(); j.hasNext(); )
200 String key = (String) j.next();
201 if (key.equalsIgnoreCase(property))
202 return p.getProperty(key);
205 return null;
209 * Inserts a new designated {@link Provider} at a designated (1-based)
210 * position in the current list of installed {@link Provider}s,
212 * @param provider
213 * the new {@link Provider} to add.
214 * @param position
215 * the position (starting from 1) of where to install
216 * <code>provider</code>.
217 * @return the actual position, in the list of installed Providers. Returns
218 * <code>-1</code> if <code>provider</code> was laready in the
219 * list. The actual position may be different than the desired
220 * <code>position</code>.
221 * @throws SecurityException
222 * if a {@link SecurityManager} is installed and it disallows this
223 * operation.
224 * @see #getProvider(String)
225 * @see #removeProvider(String)
226 * @see SecurityPermission
228 public static int insertProviderAt(Provider provider, int position)
230 SecurityManager sm = System.getSecurityManager();
231 if (sm != null)
232 sm.checkSecurityAccess("insertProvider." + provider.getName());
234 position--;
235 int max = providers.size ();
236 for (int i = 0; i < max; i++)
238 if (((Provider) providers.elementAt(i)).getName().equals(provider.getName()))
239 return -1;
242 if (position < 0)
243 position = 0;
244 if (position > max)
245 position = max;
247 providers.insertElementAt(provider, position);
249 return position + 1;
253 * Appends the designated new {@link Provider} to the current list of
254 * installed {@link Provider}s.
256 * @param provider
257 * the new {@link Provider} to append.
258 * @return the position (starting from 1) of <code>provider</code> in the
259 * current list of {@link Provider}s, or <code>-1</code> if
260 * <code>provider</code> was already there.
261 * @throws SecurityException
262 * if a {@link SecurityManager} is installed and it disallows this
263 * operation.
264 * @see #getProvider(String)
265 * @see #removeProvider(String)
266 * @see SecurityPermission
268 public static int addProvider(Provider provider)
270 return insertProviderAt (provider, providers.size () + 1);
274 * Removes an already installed {@link Provider}, given its name, from the
275 * current list of installed {@link Provider}s.
277 * @param name
278 * the name of an already installed {@link Provider} to remove.
279 * @throws SecurityException
280 * if a {@link SecurityManager} is installed and it disallows this
281 * operation.
282 * @see #getProvider(String)
283 * @see #addProvider(Provider)
285 public static void removeProvider(String name)
287 SecurityManager sm = System.getSecurityManager();
288 if (sm != null)
289 sm.checkSecurityAccess("removeProvider." + name);
291 int max = providers.size ();
292 for (int i = 0; i < max; i++)
294 if (((Provider) providers.elementAt(i)).getName().equals(name))
296 providers.remove(i);
297 break;
303 * Returns the current list of installed {@link Provider}s as an array
304 * ordered according to their installation preference order.
306 * @return an array of all the installed providers.
308 public static Provider[] getProviders()
310 Provider[] array = new Provider[providers.size ()];
311 providers.copyInto (array);
312 return array;
316 * Returns an already installed {@link Provider} given its name.
318 * @param name
319 * the name of an already installed {@link Provider}.
320 * @return the {@link Provider} known by <code>name</code>. Returns
321 * <code>null</code> if the current list of {@link Provider}s does
322 * not include one named <code>name</code>.
323 * @see #removeProvider(String)
324 * @see #addProvider(Provider)
326 public static Provider getProvider(String name)
328 if (name == null)
329 return null;
330 else
332 name = name.trim();
333 if (name.length() == 0)
334 return null;
336 Provider p;
337 int max = providers.size ();
338 for (int i = 0; i < max; i++)
340 p = (Provider) providers.elementAt(i);
341 if (p.getName().equals(name))
342 return p;
344 return null;
348 * Returns the value associated with a Security propery.
350 * @param key
351 * the key of the property to fetch.
352 * @return the value of the Security property associated with
353 * <code>key</code>. Returns <code>null</code> if no such property
354 * was found.
355 * @throws SecurityException
356 * if a {@link SecurityManager} is installed and it disallows this
357 * operation.
358 * @see #setProperty(String, String)
359 * @see SecurityPermission
361 public static String getProperty(String key)
363 // XXX To prevent infinite recursion when the SecurityManager calls us,
364 // don't do a security check if the caller is trusted (by virtue of having
365 // been loaded by the bootstrap class loader).
366 SecurityManager sm = System.getSecurityManager();
367 if (sm != null && VMStackWalker.getCallingClassLoader() != null)
368 sm.checkSecurityAccess("getProperty." + key);
370 return secprops.getProperty(key);
374 * Sets or changes a designated Security property to a designated value.
376 * @param key
377 * the name of the property to set.
378 * @param datum
379 * the new value of the property.
380 * @throws SecurityException
381 * if a {@link SecurityManager} is installed and it disallows this
382 * operation.
383 * @see #getProperty(String)
384 * @see SecurityPermission
386 public static void setProperty(String key, String datum)
388 SecurityManager sm = System.getSecurityManager();
389 if (sm != null)
390 sm.checkSecurityAccess("setProperty." + key);
392 if (datum == null)
393 secprops.remove(key);
394 else
395 secprops.put(key, datum);
399 * For a given <i>service</i> (e.g. Signature, MessageDigest, etc...) this
400 * method returns the {@link Set} of all available algorithm names (instances
401 * of {@link String}, from all currently installed {@link Provider}s.
403 * @param serviceName
404 * the case-insensitive name of a service (e.g. Signature,
405 * MessageDigest, etc).
406 * @return a {@link Set} of {@link String}s containing the names of all
407 * algorithm names provided by all of the currently installed
408 * {@link Provider}s.
409 * @since 1.4
411 public static Set<String> getAlgorithms(String serviceName)
413 HashSet<String> result = new HashSet<String>();
414 if (serviceName == null || serviceName.length() == 0)
415 return result;
417 serviceName = serviceName.trim();
418 if (serviceName.length() == 0)
419 return result;
421 serviceName = serviceName.toUpperCase()+".";
422 Provider[] providers = getProviders();
423 int ndx;
424 for (int i = 0; i < providers.length; i++)
425 for (Enumeration e = providers[i].propertyNames(); e.hasMoreElements(); )
427 String service = ((String) e.nextElement()).trim();
428 if (service.toUpperCase().startsWith(serviceName))
430 service = service.substring(serviceName.length()).trim();
431 ndx = service.indexOf(' '); // get rid of attributes
432 if (ndx != -1)
433 service = service.substring(0, ndx);
434 result.add(service);
437 return Collections.unmodifiableSet(result);
441 * Returns an array of currently installed {@link Provider}s, ordered
442 * according to their installation preference order, which satisfy a given
443 * <i>selection</i> criterion.
445 * <p>This implementation recognizes a <i>selection</i> criterion written in
446 * one of two following forms:</p>
448 * <ul>
449 * <li>&lt;crypto_service&gt;.&lt;algorithm_or_type&gt;: Where
450 * <i>crypto_service</i> is a case-insensitive string, similar to what has
451 * been described in the {@link #getAlgorithms(String)} method, and
452 * <i>algorithm_or_type</i> is a known case-insensitive name of an
453 * Algorithm, or one of its aliases.
455 * <p>For example, "CertificateFactory.X.509" would return all the installed
456 * {@link Provider}s which provide a <i>CertificateFactory</i>
457 * implementation of <i>X.509</i>.</p></li>
459 * <li>&lt;crypto_service&gt;.&lt;algorithm_or_type&gt; &lt;attribute_name&gt;:&lt;value&gt;:
460 * Where <i>crypto_service</i> is a case-insensitive string, similar to what
461 * has been described in the {@link #getAlgorithms(String)} method,
462 * <i>algorithm_or_type</i> is a case-insensitive known name of an Algorithm
463 * or one of its aliases, <i>attribute_name</i> is a case-insensitive
464 * property name with no whitespace characters, and no dots, in-between, and
465 * <i>value</i> is a {@link String} with no whitespace characters in-between.
467 * <p>For example, "Signature.Sha1WithDSS KeySize:1024" would return all the
468 * installed {@link Provider}s which declared their ability to provide
469 * <i>Signature</i> services, using the <i>Sha1WithDSS</i> algorithm with
470 * key sizes of <i>1024</i>.</p></li>
471 * </ul>
473 * @param filter
474 * the <i>selection</i> criterion for selecting among the installed
475 * {@link Provider}s.
476 * @return all the installed {@link Provider}s which satisfy the <i>selection</i>
477 * criterion. Returns <code>null</code> if no installed
478 * {@link Provider}s were found which satisfy the <i>selection</i>
479 * criterion. Returns ALL installed {@link Provider}s if
480 * <code>filter</code> is <code>null</code> or is an empty string.
481 * @throws InvalidParameterException
482 * if an exception occurs while parsing the <code>filter</code>.
483 * @see #getProviders(Map)
485 public static Provider[] getProviders(String filter)
487 if (providers == null || providers.isEmpty())
488 return null;
490 if (filter == null || filter.length() == 0)
491 return getProviders();
493 HashMap map = new HashMap(1);
494 int i = filter.indexOf(':');
495 if (i == -1) // <service>.<algorithm>
496 map.put(filter, "");
497 else // <service>.<algorithm> <attribute>:<value>
498 map.put(filter.substring(0, i), filter.substring(i+1));
500 return getProviders(map);
504 * Returns an array of currently installed {@link Provider}s which satisfy a
505 * set of <i>selection</i> criteria.
507 * <p>The <i>selection</i> criteria are defined in a {@link Map} where each
508 * element specifies a <i>selection</i> querry. The <i>Keys</i> in this
509 * {@link Map} must be in one of the two following forms:</p>
511 * <ul>
512 * <li>&lt;crypto_service&gt;.&lt;algorithm_or_type&gt;: Where
513 * <i>crypto_service</i> is a case-insensitive string, similar to what has
514 * been described in the {@link #getAlgorithms(String)} method, and
515 * <i>algorithm_or_type</i> is a case-insensitive known name of an
516 * Algorithm, or one of its aliases. The <i>value</i> of the entry in the
517 * {@link Map} for such a <i>Key</i> MUST be the empty string.
518 * {@link Provider}s which provide an implementation for the designated
519 * <i>service algorithm</i> are included in the result.</li>
521 * <li>&lt;crypto_service&gt;.&lt;algorithm_or_type&gt; &lt;attribute_name&gt;:
522 * Where <i>crypto_service</i> is a case-insensitive string, similar to what
523 * has been described in the {@link #getAlgorithms(String)} method,
524 * <i>algorithm_or_type</i> is a case-insensitive known name of an Algorithm
525 * or one of its aliases, and <i>attribute_name</i> is a case-insensitive
526 * property name with no whitespace characters, and no dots, in-between. The
527 * <i>value</i> of the entry in this {@link Map} for such a <i>Key</i> MUST
528 * NOT be <code>null</code> or an empty string. {@link Provider}s which
529 * declare the designated <i>attribute_name</i> and <i>value</i> for the
530 * designated <i>service algorithm</i> are included in the result.</li>
531 * </ul>
533 * @param filter
534 * a {@link Map} of <i>selection querries</i>.
535 * @return all currently installed {@link Provider}s which satisfy ALL the
536 * <i>selection</i> criteria defined in <code>filter</code>.
537 * Returns ALL installed {@link Provider}s if <code>filter</code>
538 * is <code>null</code> or empty.
539 * @throws InvalidParameterException
540 * if an exception is encountered while parsing the syntax of the
541 * {@link Map}'s <i>keys</i>.
542 * @see #getProviders(String)
544 public static Provider[] getProviders(Map<String,String> filter)
546 if (providers == null || providers.isEmpty())
547 return null;
549 if (filter == null)
550 return getProviders();
552 Set<String> querries = filter.keySet();
553 if (querries == null || querries.isEmpty())
554 return getProviders();
556 LinkedHashSet result = new LinkedHashSet(providers); // assume all
557 int dot, ws;
558 String querry, service, algorithm, attribute, value;
559 LinkedHashSet serviceProviders = new LinkedHashSet(); // preserve insertion order
560 for (Iterator i = querries.iterator(); i.hasNext(); )
562 querry = (String) i.next();
563 if (querry == null) // all providers
564 continue;
566 querry = querry.trim();
567 if (querry.length() == 0) // all providers
568 continue;
570 dot = querry.indexOf('.');
571 if (dot == -1) // syntax error
572 throw new InvalidParameterException(
573 "missing dot in '" + String.valueOf(querry)+"'");
575 value = filter.get(querry);
576 // deconstruct querry into [service, algorithm, attribute]
577 if (value == null || value.trim().length() == 0) // <service>.<algorithm>
579 value = null;
580 attribute = null;
581 service = querry.substring(0, dot).trim();
582 algorithm = querry.substring(dot+1).trim();
584 else // <service>.<algorithm> <attribute>
586 ws = querry.indexOf(' ');
587 if (ws == -1)
588 throw new InvalidParameterException(
589 "value (" + String.valueOf(value) +
590 ") is not empty, but querry (" + String.valueOf(querry) +
591 ") is missing at least one space character");
592 value = value.trim();
593 attribute = querry.substring(ws+1).trim();
594 // was the dot in the attribute?
595 if (attribute.indexOf('.') != -1)
596 throw new InvalidParameterException(
597 "attribute_name (" + String.valueOf(attribute) +
598 ") in querry (" + String.valueOf(querry) + ") contains a dot");
600 querry = querry.substring(0, ws).trim();
601 service = querry.substring(0, dot).trim();
602 algorithm = querry.substring(dot+1).trim();
605 // service and algorithm must not be empty
606 if (service.length() == 0)
607 throw new InvalidParameterException(
608 "<crypto_service> in querry (" + String.valueOf(querry) +
609 ") is empty");
611 if (algorithm.length() == 0)
612 throw new InvalidParameterException(
613 "<algorithm_or_type> in querry (" + String.valueOf(querry) +
614 ") is empty");
616 selectProviders(service, algorithm, attribute, value, result, serviceProviders);
617 result.retainAll(serviceProviders); // eval next retaining found providers
618 if (result.isEmpty()) // no point continuing
619 break;
622 if (result.isEmpty())
623 return null;
625 return (Provider[]) result.toArray(new Provider[result.size()]);
628 private static void selectProviders(String svc, String algo, String attr,
629 String val, LinkedHashSet providerSet,
630 LinkedHashSet result)
632 result.clear(); // ensure we start with an empty result set
633 for (Iterator i = providerSet.iterator(); i.hasNext(); )
635 Provider p = (Provider) i.next();
636 if (provides(p, svc, algo, attr, val))
637 result.add(p);
641 private static boolean provides(Provider p, String svc, String algo,
642 String attr, String val)
644 Iterator it;
645 String serviceDotAlgorithm = null;
646 String key = null;
647 String realVal;
648 boolean found = false;
649 // if <svc>.<algo> <attr> is in the set then so is <svc>.<algo>
650 // but it may be stored under an alias <algo>. resolve
651 outer: for (int r = 0; r < 3; r++) // guard against circularity
653 serviceDotAlgorithm = (svc+"."+String.valueOf(algo)).trim();
654 for (it = p.keySet().iterator(); it.hasNext(); )
656 key = (String) it.next();
657 if (key.equalsIgnoreCase(serviceDotAlgorithm)) // eureka
659 found = true;
660 break outer;
662 // it may be there but as an alias
663 if (key.equalsIgnoreCase(ALG_ALIAS + serviceDotAlgorithm))
665 algo = p.getProperty(key);
666 continue outer;
668 // else continue inner
672 if (!found)
673 return false;
675 // found a candidate for the querry. do we have an attr to match?
676 if (val == null) // <service>.<algorithm> querry
677 return true;
679 // <service>.<algorithm> <attribute>; find the key entry that match
680 String realAttr;
681 int limit = serviceDotAlgorithm.length() + 1;
682 for (it = p.keySet().iterator(); it.hasNext(); )
684 key = (String) it.next();
685 if (key.length() <= limit)
686 continue;
688 if (key.substring(0, limit).equalsIgnoreCase(serviceDotAlgorithm+" "))
690 realAttr = key.substring(limit).trim();
691 if (! realAttr.equalsIgnoreCase(attr))
692 continue;
694 // eveything matches so far. do the value
695 realVal = p.getProperty(key);
696 if (realVal == null)
697 return false;
699 realVal = realVal.trim();
700 // is it a string value?
701 if (val.equalsIgnoreCase(realVal))
702 return true;
704 // assume value is a number. cehck for greater-than-or-equal
705 return (Integer.parseInt(val) >= Integer.parseInt(realVal));
709 return false;