* config/i386/i386.md (*sinxf2): Rename to *sinxf2_i387.
[official-gcc.git] / libjava / java / security / Security.java
blob630a55412db1528fe756fc9d0da07c1615847c45
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 // GCJ LOCAL - We don't have VMStackWalker yet.
46 // import gnu.classpath.VMStackWalker;
48 import java.io.IOException;
49 import java.io.InputStream;
50 import java.net.URL;
51 import java.util.Collections;
52 import java.util.Enumeration;
53 import java.util.HashMap;
54 import java.util.HashSet;
55 import java.util.Iterator;
56 import java.util.LinkedHashSet;
57 import java.util.Map;
58 import java.util.Properties;
59 import java.util.Set;
60 import java.util.Vector;
62 /**
63 * This class centralizes all security properties and common security methods.
64 * One of its primary uses is to manage security providers.
66 * @author Mark Benvenuto (ivymccough@worldnet.att.net)
68 public final class Security
70 private static final String ALG_ALIAS = "Alg.Alias.";
72 private static Vector providers = new Vector();
73 private static Properties secprops = new Properties();
75 static
77 String base = SystemProperties.getProperty("gnu.classpath.home.url");
78 String vendor = SystemProperties.getProperty("gnu.classpath.vm.shortname");
80 // Try VM specific security file
81 boolean loaded = loadProviders (base, vendor);
83 // Append classpath standard provider if possible
84 if (!loadProviders (base, "classpath")
85 && !loaded
86 && providers.size() == 0)
88 if (Configuration.DEBUG)
90 /* No providers found and both security files failed to
91 * load properly. Give a warning in case of DEBUG is
92 * enabled. Could be done with java.util.logging later.
94 System.err.println
95 ("WARNING: could not properly read security provider files:");
96 System.err.println
97 (" " + base + "/security/" + vendor
98 + ".security");
99 System.err.println
100 (" " + base + "/security/" + "classpath"
101 + ".security");
102 System.err.println
103 (" Falling back to standard GNU security provider");
105 // Note that this matches our classpath.security file.
106 providers.addElement (new gnu.java.security.provider.Gnu());
107 providers.addElement(new gnu.javax.crypto.jce.GnuCrypto());
108 providers.addElement(new gnu.javax.crypto.jce.GnuSasl());
109 providers.addElement(new gnu.javax.net.ssl.provider.Jessie());
110 providers.addElement(new gnu.javax.security.auth.callback.GnuCallbacks());
113 // This class can't be instantiated.
114 private Security()
119 * Tries to load the vender specific security providers from the given base
120 * URL. Returns true if the resource could be read and completely parsed
121 * successfully, false otherwise.
123 private static boolean loadProviders(String baseUrl, String vendor)
125 if (baseUrl == null || vendor == null)
126 return false;
128 boolean result = true;
129 String secfilestr = baseUrl + "/security/" + vendor + ".security";
132 InputStream fin = new URL(secfilestr).openStream();
133 secprops.load(fin);
135 int i = 1;
136 String name;
137 while ((name = secprops.getProperty("security.provider." + i)) != null)
139 Exception exception = null;
142 ClassLoader sys = ClassLoader.getSystemClassLoader();
143 providers.addElement(Class.forName(name, true, sys).newInstance());
145 catch (ClassNotFoundException x)
147 exception = x;
149 catch (InstantiationException x)
151 exception = x;
153 catch (IllegalAccessException x)
155 exception = x;
158 if (exception != null)
160 System.err.println ("WARNING: Error loading security provider "
161 + name + ": " + exception);
162 result = false;
164 i++;
167 catch (IOException ignored)
169 result = false;
172 return result;
176 * Returns the value associated to a designated property name for a given
177 * algorithm.
179 * @param algName
180 * the algorithm name.
181 * @param propName
182 * the name of the property to return.
183 * @return the value of the specified property or <code>null</code> if none
184 * found.
185 * @deprecated Use the provider-based and algorithm-independent
186 * {@link AlgorithmParameters} and {@link KeyFactory} engine
187 * classes instead.
189 public static String getAlgorithmProperty(String algName, String propName)
191 if (algName == null || propName == null)
192 return null;
194 String property = String.valueOf(propName) + "." + String.valueOf(algName);
195 Provider p;
196 for (Iterator i = providers.iterator(); i.hasNext(); )
198 p = (Provider) i.next();
199 for (Iterator j = p.keySet().iterator(); j.hasNext(); )
201 String key = (String) j.next();
202 if (key.equalsIgnoreCase(property))
203 return p.getProperty(key);
206 return null;
210 * Inserts a new designated {@link Provider} at a designated (1-based)
211 * position in the current list of installed {@link Provider}s,
213 * @param provider
214 * the new {@link Provider} to add.
215 * @param position
216 * the position (starting from 1) of where to install
217 * <code>provider</code>.
218 * @return the actual position, in the list of installed Providers. Returns
219 * <code>-1</code> if <code>provider</code> was laready in the
220 * list. The actual position may be different than the desired
221 * <code>position</code>.
222 * @throws SecurityException
223 * if a {@link SecurityManager} is installed and it disallows this
224 * operation.
225 * @see #getProvider(String)
226 * @see #removeProvider(String)
227 * @see SecurityPermission
229 public static int insertProviderAt(Provider provider, int position)
231 SecurityManager sm = System.getSecurityManager();
232 if (sm != null)
233 sm.checkSecurityAccess("insertProvider." + provider.getName());
235 position--;
236 int max = providers.size ();
237 for (int i = 0; i < max; i++)
239 if (((Provider) providers.elementAt(i)).getName().equals(provider.getName()))
240 return -1;
243 if (position < 0)
244 position = 0;
245 if (position > max)
246 position = max;
248 providers.insertElementAt(provider, position);
250 return position + 1;
254 * Appends the designated new {@link Provider} to the current list of
255 * installed {@link Provider}s.
257 * @param provider
258 * the new {@link Provider} to append.
259 * @return the position (starting from 1) of <code>provider</code> in the
260 * current list of {@link Provider}s, or <code>-1</code> if
261 * <code>provider</code> was already there.
262 * @throws SecurityException
263 * if a {@link SecurityManager} is installed and it disallows this
264 * operation.
265 * @see #getProvider(String)
266 * @see #removeProvider(String)
267 * @see SecurityPermission
269 public static int addProvider(Provider provider)
271 return insertProviderAt (provider, providers.size () + 1);
275 * Removes an already installed {@link Provider}, given its name, from the
276 * current list of installed {@link Provider}s.
278 * @param name
279 * the name of an already installed {@link Provider} to remove.
280 * @throws SecurityException
281 * if a {@link SecurityManager} is installed and it disallows this
282 * operation.
283 * @see #getProvider(String)
284 * @see #addProvider(Provider)
286 public static void removeProvider(String name)
288 SecurityManager sm = System.getSecurityManager();
289 if (sm != null)
290 sm.checkSecurityAccess("removeProvider." + name);
292 int max = providers.size ();
293 for (int i = 0; i < max; i++)
295 if (((Provider) providers.elementAt(i)).getName().equals(name))
297 providers.remove(i);
298 break;
304 * Returns the current list of installed {@link Provider}s as an array
305 * ordered according to their installation preference order.
307 * @return an array of all the installed providers.
309 public static Provider[] getProviders()
311 Provider[] array = new Provider[providers.size ()];
312 providers.copyInto (array);
313 return array;
317 * Returns an already installed {@link Provider} given its name.
319 * @param name
320 * the name of an already installed {@link Provider}.
321 * @return the {@link Provider} known by <code>name</code>. Returns
322 * <code>null</code> if the current list of {@link Provider}s does
323 * not include one named <code>name</code>.
324 * @see #removeProvider(String)
325 * @see #addProvider(Provider)
327 public static Provider getProvider(String name)
329 if (name == null)
330 return null;
331 else
333 name = name.trim();
334 if (name.length() == 0)
335 return null;
337 Provider p;
338 int max = providers.size ();
339 for (int i = 0; i < max; i++)
341 p = (Provider) providers.elementAt(i);
342 if (p.getName().equals(name))
343 return p;
345 return null;
349 * Returns the value associated with a Security propery.
351 * @param key
352 * the key of the property to fetch.
353 * @return the value of the Security property associated with
354 * <code>key</code>. Returns <code>null</code> if no such property
355 * was found.
356 * @throws SecurityException
357 * if a {@link SecurityManager} is installed and it disallows this
358 * operation.
359 * @see #setProperty(String, String)
360 * @see SecurityPermission
362 public static String getProperty(String key)
364 // GCJ LOCAL - We don't have VMStackWalker yet.
365 // XXX To prevent infinite recursion when the SecurityManager calls us,
366 // don't do a security check if the caller is trusted (by virtue of having
367 // been loaded by the bootstrap class loader).
368 SecurityManager sm = System.getSecurityManager();
369 // if (sm != null && VMStackWalker.getCallingClassLoader() != null)
370 if (sm != null)
371 sm.checkSecurityAccess("getProperty." + key);
373 return secprops.getProperty(key);
377 * Sets or changes a designated Security property to a designated value.
379 * @param key
380 * the name of the property to set.
381 * @param datum
382 * the new value of the property.
383 * @throws SecurityException
384 * if a {@link SecurityManager} is installed and it disallows this
385 * operation.
386 * @see #getProperty(String)
387 * @see SecurityPermission
389 public static void setProperty(String key, String datum)
391 SecurityManager sm = System.getSecurityManager();
392 if (sm != null)
393 sm.checkSecurityAccess("setProperty." + key);
395 if (datum == null)
396 secprops.remove(key);
397 else
398 secprops.put(key, datum);
402 * For a given <i>service</i> (e.g. Signature, MessageDigest, etc...) this
403 * method returns the {@link Set} of all available algorithm names (instances
404 * of {@link String}, from all currently installed {@link Provider}s.
406 * @param serviceName
407 * the case-insensitive name of a service (e.g. Signature,
408 * MessageDigest, etc).
409 * @return a {@link Set} of {@link String}s containing the names of all
410 * algorithm names provided by all of the currently installed
411 * {@link Provider}s.
412 * @since 1.4
414 public static Set getAlgorithms(String serviceName)
416 HashSet result = new HashSet();
417 if (serviceName == null || serviceName.length() == 0)
418 return result;
420 serviceName = serviceName.trim();
421 if (serviceName.length() == 0)
422 return result;
424 serviceName = serviceName.toUpperCase()+".";
425 Provider[] providers = getProviders();
426 int ndx;
427 for (int i = 0; i < providers.length; i++)
428 for (Enumeration e = providers[i].propertyNames(); e.hasMoreElements(); )
430 String service = ((String) e.nextElement()).trim();
431 if (service.toUpperCase().startsWith(serviceName))
433 service = service.substring(serviceName.length()).trim();
434 ndx = service.indexOf(' '); // get rid of attributes
435 if (ndx != -1)
436 service = service.substring(0, ndx);
437 result.add(service);
440 return Collections.unmodifiableSet(result);
444 * Returns an array of currently installed {@link Provider}s, ordered
445 * according to their installation preference order, which satisfy a given
446 * <i>selection</i> criterion.
448 * <p>This implementation recognizes a <i>selection</i> criterion written in
449 * one of two following forms:</p>
451 * <ul>
452 * <li>&lt;crypto_service&gt;.&lt;algorithm_or_type&gt;: Where
453 * <i>crypto_service</i> is a case-insensitive string, similar to what has
454 * been described in the {@link #getAlgorithms(String)} method, and
455 * <i>algorithm_or_type</i> is a known case-insensitive name of an
456 * Algorithm, or one of its aliases.
458 * <p>For example, "CertificateFactory.X.509" would return all the installed
459 * {@link Provider}s which provide a <i>CertificateFactory</i>
460 * implementation of <i>X.509</i>.</p></li>
462 * <li>&lt;crypto_service&gt;.&lt;algorithm_or_type&gt; &lt;attribute_name&gt;:&lt;value&gt;:
463 * Where <i>crypto_service</i> is a case-insensitive string, similar to what
464 * has been described in the {@link #getAlgorithms(String)} method,
465 * <i>algorithm_or_type</i> is a case-insensitive known name of an Algorithm
466 * or one of its aliases, <i>attribute_name</i> is a case-insensitive
467 * property name with no whitespace characters, and no dots, in-between, and
468 * <i>value</i> is a {@link String} with no whitespace characters in-between.
470 * <p>For example, "Signature.Sha1WithDSS KeySize:1024" would return all the
471 * installed {@link Provider}s which declared their ability to provide
472 * <i>Signature</i> services, using the <i>Sha1WithDSS</i> algorithm with
473 * key sizes of <i>1024</i>.</p></li>
474 * </ul>
476 * @param filter
477 * the <i>selection</i> criterion for selecting among the installed
478 * {@link Provider}s.
479 * @return all the installed {@link Provider}s which satisfy the <i>selection</i>
480 * criterion. Returns <code>null</code> if no installed
481 * {@link Provider}s were found which satisfy the <i>selection</i>
482 * criterion. Returns ALL installed {@link Provider}s if
483 * <code>filter</code> is <code>null</code> or is an empty string.
484 * @throws InvalidParameterException
485 * if an exception occurs while parsing the <code>filter</code>.
486 * @see #getProviders(Map)
488 public static Provider[] getProviders(String filter)
490 if (providers == null || providers.isEmpty())
491 return null;
493 if (filter == null || filter.length() == 0)
494 return getProviders();
496 HashMap map = new HashMap(1);
497 int i = filter.indexOf(':');
498 if (i == -1) // <service>.<algorithm>
499 map.put(filter, "");
500 else // <service>.<algorithm> <attribute>:<value>
501 map.put(filter.substring(0, i), filter.substring(i+1));
503 return getProviders(map);
507 * Returns an array of currently installed {@link Provider}s which satisfy a
508 * set of <i>selection</i> criteria.
510 * <p>The <i>selection</i> criteria are defined in a {@link Map} where each
511 * element specifies a <i>selection</i> querry. The <i>Keys</i> in this
512 * {@link Map} must be in one of the two following forms:</p>
514 * <ul>
515 * <li>&lt;crypto_service&gt;.&lt;algorithm_or_type&gt;: Where
516 * <i>crypto_service</i> is a case-insensitive string, similar to what has
517 * been described in the {@link #getAlgorithms(String)} method, and
518 * <i>algorithm_or_type</i> is a case-insensitive known name of an
519 * Algorithm, or one of its aliases. The <i>value</i> of the entry in the
520 * {@link Map} for such a <i>Key</i> MUST be the empty string.
521 * {@link Provider}s which provide an implementation for the designated
522 * <i>service algorithm</i> are included in the result.</li>
524 * <li>&lt;crypto_service&gt;.&lt;algorithm_or_type&gt; &lt;attribute_name&gt;:
525 * Where <i>crypto_service</i> is a case-insensitive string, similar to what
526 * has been described in the {@link #getAlgorithms(String)} method,
527 * <i>algorithm_or_type</i> is a case-insensitive known name of an Algorithm
528 * or one of its aliases, and <i>attribute_name</i> is a case-insensitive
529 * property name with no whitespace characters, and no dots, in-between. The
530 * <i>value</i> of the entry in this {@link Map} for such a <i>Key</i> MUST
531 * NOT be <code>null</code> or an empty string. {@link Provider}s which
532 * declare the designated <i>attribute_name</i> and <i>value</i> for the
533 * designated <i>service algorithm</i> are included in the result.</li>
534 * </ul>
536 * @param filter
537 * a {@link Map} of <i>selection querries</i>.
538 * @return all currently installed {@link Provider}s which satisfy ALL the
539 * <i>selection</i> criteria defined in <code>filter</code>.
540 * Returns ALL installed {@link Provider}s if <code>filter</code>
541 * is <code>null</code> or empty.
542 * @throws InvalidParameterException
543 * if an exception is encountered while parsing the syntax of the
544 * {@link Map}'s <i>keys</i>.
545 * @see #getProviders(String)
547 public static Provider[] getProviders(Map filter)
549 if (providers == null || providers.isEmpty())
550 return null;
552 if (filter == null)
553 return getProviders();
555 Set querries = filter.keySet();
556 if (querries == null || querries.isEmpty())
557 return getProviders();
559 LinkedHashSet result = new LinkedHashSet(providers); // assume all
560 int dot, ws;
561 String querry, service, algorithm, attribute, value;
562 LinkedHashSet serviceProviders = new LinkedHashSet(); // preserve insertion order
563 for (Iterator i = querries.iterator(); i.hasNext(); )
565 querry = (String) i.next();
566 if (querry == null) // all providers
567 continue;
569 querry = querry.trim();
570 if (querry.length() == 0) // all providers
571 continue;
573 dot = querry.indexOf('.');
574 if (dot == -1) // syntax error
575 throw new InvalidParameterException(
576 "missing dot in '" + String.valueOf(querry)+"'");
578 value = (String) filter.get(querry);
579 // deconstruct querry into [service, algorithm, attribute]
580 if (value == null || value.trim().length() == 0) // <service>.<algorithm>
582 value = null;
583 attribute = null;
584 service = querry.substring(0, dot).trim();
585 algorithm = querry.substring(dot+1).trim();
587 else // <service>.<algorithm> <attribute>
589 ws = querry.indexOf(' ');
590 if (ws == -1)
591 throw new InvalidParameterException(
592 "value (" + String.valueOf(value) +
593 ") is not empty, but querry (" + String.valueOf(querry) +
594 ") is missing at least one space character");
595 value = value.trim();
596 attribute = querry.substring(ws+1).trim();
597 // was the dot in the attribute?
598 if (attribute.indexOf('.') != -1)
599 throw new InvalidParameterException(
600 "attribute_name (" + String.valueOf(attribute) +
601 ") in querry (" + String.valueOf(querry) + ") contains a dot");
603 querry = querry.substring(0, ws).trim();
604 service = querry.substring(0, dot).trim();
605 algorithm = querry.substring(dot+1).trim();
608 // service and algorithm must not be empty
609 if (service.length() == 0)
610 throw new InvalidParameterException(
611 "<crypto_service> in querry (" + String.valueOf(querry) +
612 ") is empty");
614 if (algorithm.length() == 0)
615 throw new InvalidParameterException(
616 "<algorithm_or_type> in querry (" + String.valueOf(querry) +
617 ") is empty");
619 selectProviders(service, algorithm, attribute, value, result, serviceProviders);
620 result.retainAll(serviceProviders); // eval next retaining found providers
621 if (result.isEmpty()) // no point continuing
622 break;
625 if (result.isEmpty())
626 return null;
628 return (Provider[]) result.toArray(new Provider[result.size()]);
631 private static void selectProviders(String svc, String algo, String attr,
632 String val, LinkedHashSet providerSet,
633 LinkedHashSet result)
635 result.clear(); // ensure we start with an empty result set
636 for (Iterator i = providerSet.iterator(); i.hasNext(); )
638 Provider p = (Provider) i.next();
639 if (provides(p, svc, algo, attr, val))
640 result.add(p);
644 private static boolean provides(Provider p, String svc, String algo,
645 String attr, String val)
647 Iterator it;
648 String serviceDotAlgorithm = null;
649 String key = null;
650 String realVal;
651 boolean found = false;
652 // if <svc>.<algo> <attr> is in the set then so is <svc>.<algo>
653 // but it may be stored under an alias <algo>. resolve
654 outer: for (int r = 0; r < 3; r++) // guard against circularity
656 serviceDotAlgorithm = (svc+"."+String.valueOf(algo)).trim();
657 for (it = p.keySet().iterator(); it.hasNext(); )
659 key = (String) it.next();
660 if (key.equalsIgnoreCase(serviceDotAlgorithm)) // eureka
662 found = true;
663 break outer;
665 // it may be there but as an alias
666 if (key.equalsIgnoreCase(ALG_ALIAS + serviceDotAlgorithm))
668 algo = p.getProperty(key);
669 continue outer;
671 // else continue inner
675 if (!found)
676 return false;
678 // found a candidate for the querry. do we have an attr to match?
679 if (val == null) // <service>.<algorithm> querry
680 return true;
682 // <service>.<algorithm> <attribute>; find the key entry that match
683 String realAttr;
684 int limit = serviceDotAlgorithm.length() + 1;
685 for (it = p.keySet().iterator(); it.hasNext(); )
687 key = (String) it.next();
688 if (key.length() <= limit)
689 continue;
691 if (key.substring(0, limit).equalsIgnoreCase(serviceDotAlgorithm+" "))
693 realAttr = key.substring(limit).trim();
694 if (! realAttr.equalsIgnoreCase(attr))
695 continue;
697 // eveything matches so far. do the value
698 realVal = p.getProperty(key);
699 if (realVal == null)
700 return false;
702 realVal = realVal.trim();
703 // is it a string value?
704 if (val.equalsIgnoreCase(realVal))
705 return true;
707 // assume value is a number. cehck for greater-than-or-equal
708 return (new Integer(val).intValue() >= new Integer(realVal).intValue());
712 return false;