0001: /*
0002: * @(#)Security.java 1.110 06/10/11
0003: *
0004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: *
0026: */
0027:
0028: package java.security;
0029:
0030: import java.lang.reflect.*;
0031: import java.util.*;
0032: import java.io.*;
0033: import java.net.URL;
0034: import java.security.InvalidParameterException;
0035: import sun.security.util.Debug;
0036: import sun.security.util.PropertyExpander;
0037:
0038: /**
0039: * <p>This class centralizes all security properties and common security
0040: * methods. One of its primary uses is to manage providers.
0041: *
0042: * @author Benjamin Renaud
0043: * @version 1.101 10/17/00
0044: */
0045:
0046: public final class Security {
0047:
0048: // Do providers need to be reloaded?
0049: private static boolean reloadProviders = true;
0050:
0051: /* Are we debugging? -- for developers */
0052: static final boolean debug = false;
0053: private static final Debug sdebug = Debug.getInstance("properties");
0054:
0055: /* Are we displaying errors? -- for users */
0056: static final boolean error = true;
0057:
0058: /* The java.security properties */
0059: private static Properties props;
0060:
0061: /* A vector of providers, in order of priority */
0062: private static Vector providers;
0063:
0064: // Where we cache provider properties
0065: private static Hashtable providerPropertiesCache;
0066:
0067: // Where we cache engine provider properties
0068: private static Hashtable engineCache;
0069:
0070: // Where we cache search results
0071: private static Hashtable searchResultsCache;
0072:
0073: // providers currently attempting to be loaded
0074: private static Hashtable providerLoads;
0075:
0076: // An element in the cache
0077: private static class ProviderProperty {
0078: String className;
0079: Provider provider;
0080: }
0081:
0082: // Number of statically registered security providers. No duplicates.
0083: private static int numOfStaticProviders = 0;
0084:
0085: /* A vector of statically registered providers' master class names,
0086: * in order of priority. No duplicates.
0087: */
0088: private static Vector providerMasterClassNames = new Vector(6);
0089:
0090: // Index for the vector providerMasterClassNames.
0091: // It points to the next provider which we should try to load.
0092: private static int indexStaticProviders = 0;
0093:
0094: // Does the indexStaticProviders need to be reset?
0095: private static boolean resetProviderIndex = false;
0096:
0097: static {
0098: // doPrivileged here because there are multiple
0099: // things in initialize that might require privs.
0100: // (the FileInputStream call and the File.exists call,
0101: // the securityPropFile call, etc)
0102: AccessController.doPrivileged(new PrivilegedAction() {
0103: public Object run() {
0104: initialize();
0105: return null;
0106: }
0107: });
0108: }
0109:
0110: private static void initialize() {
0111: props = new Properties();
0112: providers = new Vector();
0113: providerPropertiesCache = new Hashtable();
0114: engineCache = new Hashtable();
0115: searchResultsCache = new Hashtable(5);
0116: providerLoads = new Hashtable(1);
0117: boolean loadedProps = false;
0118: boolean overrideAll = false;
0119:
0120: // first load the system properties file
0121: // to determine the value of security.overridePropertiesFile
0122: File propFile = securityPropFile("java.security");
0123: if (propFile.exists()) {
0124: try {
0125: FileInputStream is = new FileInputStream(propFile);
0126: // Inputstream has been buffered in Properties class
0127: props.load(is);
0128: is.close();
0129: loadedProps = true;
0130:
0131: if (sdebug != null) {
0132: sdebug.println("reading security properties file: "
0133: + propFile);
0134: }
0135: } catch (IOException e) {
0136: if (sdebug != null) {
0137: sdebug
0138: .println("unable to load security properties from "
0139: + propFile);
0140: e.printStackTrace();
0141: }
0142: }
0143: }
0144:
0145: if ("true".equalsIgnoreCase(props
0146: .getProperty("security.overridePropertiesFile"))) {
0147:
0148: String extraPropFile = System
0149: .getProperty("java.security.properties");
0150: if (extraPropFile != null && extraPropFile.startsWith("=")) {
0151: overrideAll = true;
0152: extraPropFile = extraPropFile.substring(1);
0153: }
0154:
0155: if (overrideAll) {
0156: props = new Properties();
0157: if (sdebug != null) {
0158: sdebug
0159: .println("overriding other security properties files!");
0160: }
0161: }
0162:
0163: // now load the user-specified file so its values
0164: // will win if they conflict with the earlier values
0165: if (extraPropFile != null) {
0166: try {
0167: URL propURL;
0168:
0169: extraPropFile = PropertyExpander
0170: .expand(extraPropFile);
0171: propFile = new File(extraPropFile);
0172: if (propFile.exists()) {
0173: propURL = new URL("file:"
0174: + propFile.getCanonicalPath());
0175: } else {
0176: propURL = new URL(extraPropFile);
0177: }
0178: BufferedInputStream bis = new BufferedInputStream(
0179: propURL.openStream());
0180: props.load(bis);
0181: bis.close();
0182: loadedProps = true;
0183:
0184: if (sdebug != null) {
0185: sdebug
0186: .println("reading security properties file: "
0187: + propURL);
0188: if (overrideAll) {
0189: sdebug
0190: .println("overriding other security properties files!");
0191: }
0192: }
0193: } catch (Exception e) {
0194: if (sdebug != null) {
0195: sdebug
0196: .println("unable to load security properties from "
0197: + extraPropFile);
0198: e.printStackTrace();
0199: }
0200: }
0201: }
0202: }
0203:
0204: if (!loadedProps) {
0205: initializeStatic();
0206: if (sdebug != null) {
0207: sdebug.println("unable to load security properties "
0208: + "-- using defaults");
0209: }
0210: }
0211:
0212: // Not loading providers here. Just counts how many providers
0213: // are statically registered. This reduces the startup
0214: // footprint.
0215: countProviders();
0216: }
0217:
0218: /*
0219: * Initialize to default values, if <java.home>/lib/java.security
0220: * is not found.
0221: */
0222: private static void initializeStatic() {
0223: props.put("security.provider.1", "sun.security.provider.Sun");
0224: }
0225:
0226: /**
0227: * Don't let anyone instantiate this.
0228: */
0229: private Security() {
0230: }
0231:
0232: /**
0233: * Loops through provider declarations, which are expected to be
0234: * of the form:
0235: *
0236: * security.provider.1=sun.security.provider.Sun
0237: * security.provider.2=sun.security.jsafe.Jsafe
0238: * etc.
0239: *
0240: * The order determines the default search order when looking for
0241: * an algorithm.
0242: */
0243: private static synchronized void countProviders() {
0244:
0245: int i = 1;
0246:
0247: while (true) {
0248: String name = props.getProperty("security.provider." + i);
0249: if (name == null) {
0250: break;
0251: } else {
0252: String fullClassName = name.trim();
0253: if (fullClassName.length() == 0) {
0254: System.err.println("invalid entry for "
0255: + "security.provider." + i);
0256: break;
0257: } else {
0258: // Get rid of duplicate providers.
0259: if (!providerMasterClassNames
0260: .contains(fullClassName)) {
0261: providerMasterClassNames.add(fullClassName);
0262: }
0263: i++;
0264: }
0265: }
0266: }
0267:
0268: // Get the number of statically registered providers.
0269: numOfStaticProviders = providerMasterClassNames.size();
0270:
0271: }
0272:
0273: /*
0274: * Reload the providers (provided as extensions) that could not be loaded
0275: * (because there was no system class loader available) when this class
0276: * was initialized.
0277: */
0278: private static synchronized void reloadProviders() {
0279: if (reloadProviders) {
0280: sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
0281: if (l != null) {
0282: synchronized (Security.class) {
0283: reloadProviders = false;
0284: // We don't want loadOneMoreProvider() to do
0285: // anything from now on since this method will
0286: // load all static providers.
0287: indexStaticProviders = numOfStaticProviders;
0288: resetProviderIndex = false;
0289: providers.removeAllElements();
0290: // i is an index for the vector
0291: // providerMasterClassNames. So it starts from 0.
0292: int i = 0;
0293: while (i < numOfStaticProviders) {
0294: final String name = (String) providerMasterClassNames
0295: .elementAt(i);
0296: i++;
0297: Provider prov = (Provider) AccessController
0298: .doPrivileged(new PrivilegedAction() {
0299: public Object run() {
0300: return Provider
0301: .loadProvider(name);
0302: }
0303: });
0304: if (prov != null) {
0305: providers.addElement(prov);
0306: }
0307: }
0308: // empty provider-property cache
0309: providerPropertiesCache.clear();
0310: engineCache.clear();
0311: searchResultsCache.clear();
0312: }
0313: }
0314: }
0315: }
0316:
0317: /**
0318: * Try our best to load one more statically registered provider.
0319: * This is used by getEngineClassName(String algName, String engineType).
0320: */
0321: private static synchronized void loadOneMoreProvider() {
0322: // suspend provider reloading inside this method
0323: boolean restore = false;
0324: if (reloadProviders) {
0325: restore = true;
0326: reloadProviders = false;
0327: }
0328: try {
0329: sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
0330: /*
0331: * Even if the launcher l is null, we still want to
0332: * load providers if we can. See bug 4418903.
0333: * When we first see that the launcher isn't null, we
0334: * could be in one of the following situations:
0335: * a) some providers were loaded out of the priority order.
0336: * For example, 6 providers are statically configured, and
0337: * provider 2 and 4 are loaded. The field resetProviderIndex
0338: * should be "true". So we can try to load providers
0339: * according to the priority order when the launcher isn't null.
0340: * b) some providers were loaded, but not out of order.
0341: * For example, 6 providers are statically configured, and
0342: * provider 1 and 2 are loaded. The field resetProviderIndex
0343: * should be "false". So we just try to load the next
0344: * provider whose index is indexStaticProviders.
0345: * c) no providers were loaded. The field resetProviderIndex
0346: * should be "false". So we just try to load the first
0347: * provider. Note: indexStaticProviders is 0 in this case.
0348: */
0349:
0350: if (indexStaticProviders >= numOfStaticProviders) {
0351: return;
0352: }
0353:
0354: Provider prov = null;
0355:
0356: while (indexStaticProviders < numOfStaticProviders) {
0357: final String name = (String) providerMasterClassNames
0358: .elementAt(indexStaticProviders);
0359:
0360: // determine if the loadProvider call below is looping.
0361: // this may occur if the provider to be loaded is signed.
0362: // if looping, continue
0363: if (providerLoads.get(name) != null) {
0364: indexStaticProviders++;
0365: continue;
0366: } else {
0367: providerLoads.put(name, name);
0368: }
0369:
0370: prov = (Provider) AccessController
0371: .doPrivileged(new PrivilegedAction() {
0372: public Object run() {
0373: return Provider.loadProvider(name);
0374: }
0375: });
0376:
0377: // indexStaticProviders points to the next provider we
0378: // should try to load.
0379: indexStaticProviders++;
0380: providerLoads.remove(name);
0381:
0382: if (prov != null) {
0383: /* This must manipulate the datastructure
0384: directly, because going through addProviders
0385: causes a security check to happen, which
0386: sometimes will cause the security
0387: initialization to fail with bad
0388: consequences. */
0389: providers.addElement(prov);
0390: // empty provider-property cache
0391: providerPropertiesCache.clear();
0392: engineCache.clear();
0393: searchResultsCache.clear();
0394: break;
0395: } else {
0396: if (l == null) {
0397: // Set resetProviderIndex to true since we may load
0398: // providers out of the priority order.
0399: resetProviderIndex = true;
0400: }
0401: }
0402: }
0403: } finally {
0404: // resume provider reloading if necessary
0405: if (restore) {
0406: reloadProviders = true;
0407: }
0408: }
0409: }
0410:
0411: private static File securityPropFile(String filename) {
0412: // maybe check for a system property which will specify where to
0413: // look. Someday.
0414: String sep = File.separator;
0415: return new File(System.getProperty("java.home") + sep + "lib"
0416: + sep + "security" + sep + filename);
0417: }
0418:
0419: /**
0420: * Looks up providers, and returns the property (and its associated
0421: * provider) mapping the key, if any.
0422: * The order in which the providers are looked up is the
0423: * provider-preference order, as specificed in the security
0424: * properties file.
0425: */
0426: private static ProviderProperty getProviderProperty(String key) {
0427: ProviderProperty entry = (ProviderProperty) providerPropertiesCache
0428: .get(key);
0429: if (entry != null) {
0430: return entry;
0431: }
0432:
0433: for (int i = 0; i < providers.size(); i++) {
0434:
0435: String matchKey = null;
0436: Provider prov = (Provider) providers.elementAt(i);
0437: String prop = prov.getProperty(key);
0438:
0439: if (prop == null) {
0440: // Is there a match if we do a case-insensitive property name
0441: // comparison? Let's try ...
0442: for (Enumeration enum_ = prov.keys(); enum_
0443: .hasMoreElements()
0444: && prop == null;) {
0445: matchKey = (String) enum_.nextElement();
0446: if (key.equalsIgnoreCase(matchKey)) {
0447: prop = prov.getProperty(matchKey);
0448: break;
0449: }
0450: }
0451: }
0452:
0453: if (prop != null) {
0454: ProviderProperty newEntry = new ProviderProperty();
0455: newEntry.className = prop;
0456: newEntry.provider = prov;
0457: providerPropertiesCache.put(key, newEntry);
0458: if (matchKey != null) {
0459: // Store the property value in the cache under the exact
0460: // property name, as specified by the provider
0461: providerPropertiesCache.put(matchKey, newEntry);
0462: }
0463: return newEntry;
0464: }
0465: }
0466:
0467: return entry;
0468: }
0469:
0470: /**
0471: * Returns the property (if any) mapping the key for the given provider.
0472: */
0473: private static String getProviderProperty(String key,
0474: Provider provider) {
0475: String prop = provider.getProperty(key);
0476: if (prop == null) {
0477: // Is there a match if we do a case-insensitive property name
0478: // comparison? Let's try ...
0479: for (Enumeration enum_ = provider.keys(); enum_
0480: .hasMoreElements()
0481: && prop == null;) {
0482: String matchKey = (String) enum_.nextElement();
0483: if (key.equalsIgnoreCase(matchKey)) {
0484: prop = provider.getProperty(matchKey);
0485: break;
0486: }
0487: }
0488: }
0489: return prop;
0490: }
0491:
0492: /**
0493: * We always map names to standard names
0494: */
0495: private static String getStandardName(String alias,
0496: String engineType, Provider prov) {
0497: return getProviderProperty("Alg.Alias." + engineType + "."
0498: + alias, prov);
0499: }
0500:
0501: /**
0502: * Gets a specified property for an algorithm. The algorithm name
0503: * should be a standard name. See Appendix A in the <a href=
0504: * "../../../guide/security/CryptoSpec.html#AppA">
0505: * Java Cryptography Architecture API Specification & Reference </a>
0506: * for information about standard algorithm names.
0507: * One possible use is by specialized algorithm parsers, which may map
0508: * classes to algorithms which they understand (much like Key parsers
0509: * do).
0510: *
0511: * param algName the algorithm name.
0512: *
0513: * param propName the name of the property to get.
0514: *
0515: * return the value of the specified property.
0516: *
0517: * deprecated This method used to return the value of a proprietary
0518: * property in the master file of the "SUN" Cryptographic Service
0519: * Provider in order to determine how to parse algorithm-specific
0520: * parameters. Use the new provider-based and algorithm-independent
0521: * <code>AlgorithmParameters</code> and <code>KeyFactory</code> engine
0522: * classes (introduced in the Java 2 platform) instead.
0523: *
0524: public static String getAlgorithmProperty(String algName,
0525: String propName) {
0526: reloadProviders();
0527: ProviderProperty entry = getProviderProperty("Alg." + propName
0528: + "." + algName);
0529: if (entry != null) {
0530: return entry.className;
0531: } else {
0532: return null;
0533: }
0534: }
0535: */
0536:
0537: /*
0538: * Lookup the algorithm in our list of providers. Process
0539: * each provider in priority order one at a time looking for
0540: * either the direct engine property or a matching alias.
0541: */
0542: private static ProviderProperty getEngineClassName(String algName,
0543: String engineType) throws NoSuchAlgorithmException {
0544: ProviderProperty pp;
0545: String key = engineType;
0546:
0547: if (algName != null)
0548: key += "." + algName;
0549: pp = (ProviderProperty) engineCache.get(key);
0550: if (pp != null)
0551: return pp;
0552:
0553: synchronized (Security.class) {
0554: sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
0555: /*
0556: * In case some providers have been loaded out of the
0557: * priority order when the launcher l is null, we should
0558: * clear the vector "providers" and reset the indexStaticProviders
0559: * to zero when the launcher l isn't null.
0560: *
0561: * We should only do the above if the "reloadProviders" is true
0562: * which means that the method reloadProviders() hasn't
0563: * load all statically registered providers yet.
0564: * Once the reloadProviders() method has loaded all statically
0565: * registered providers, we shouldn't clear the vector
0566: * "providers" in this getEngineClassName() method.
0567: */
0568: if ((reloadProviders == true) && (l != null)
0569: && (resetProviderIndex == true)) {
0570: resetProviderIndex = false;
0571: indexStaticProviders = 0;
0572: providers.removeAllElements();
0573: providerPropertiesCache.clear();
0574: engineCache.clear();
0575: searchResultsCache.clear();
0576: providerLoads.clear();
0577: }
0578:
0579: // We should call loadOneMoreProvider() if no provider
0580: // has been loaded yet. Otherwise, we may not be able to
0581: // get in the following "for" loop.
0582: if (providers.size() == 0) {
0583: loadOneMoreProvider();
0584: }
0585: for (int i = 0; i < providers.size(); i++) {
0586: Provider prov = (Provider) providers.elementAt(i);
0587: try {
0588: pp = getEngineClassName(algName, prov, engineType);
0589: } catch (NoSuchAlgorithmException e) {
0590: if (i == providers.size() - 1) {
0591: // The requested algorithm may be available in
0592: // a registered provider which hasn't been loaded
0593: // yet. Let's try to load one more registered
0594: // provider. The method loadOneMoreProvider()
0595: // won't do anything if we have tried to load all
0596: // registered providers.
0597: loadOneMoreProvider();
0598: }
0599: continue;
0600: }
0601:
0602: /* Cache it */
0603: engineCache.put(key, pp);
0604: return pp;
0605: }
0606: }
0607:
0608: throw new NoSuchAlgorithmException(algName.toUpperCase() + " "
0609: + engineType + " not available");
0610: }
0611:
0612: private static ProviderProperty getEngineClassName(String algName,
0613: String provider, String engineType)
0614: throws NoSuchAlgorithmException, NoSuchProviderException {
0615: if (provider == null) {
0616: return getEngineClassName(algName, engineType);
0617: }
0618:
0619: // check if the provider is installed
0620: Provider prov = getProvider(provider);
0621: if (prov == null) {
0622: throw new NoSuchProviderException("no such provider: "
0623: + provider);
0624: }
0625:
0626: return getEngineClassName(algName, prov, engineType);
0627: }
0628:
0629: /**
0630: * The parameter provider cannot be null.
0631: */
0632: private static ProviderProperty getEngineClassName(String algName,
0633: Provider provider, String engineType)
0634: throws NoSuchAlgorithmException {
0635: String key;
0636: if (engineType.equalsIgnoreCase("SecureRandom")
0637: && algName == null)
0638: key = engineType;
0639: else
0640: key = engineType + "." + algName;
0641:
0642: String className = getProviderProperty(key, provider);
0643: if (className == null) {
0644: if (engineType.equalsIgnoreCase("SecureRandom")
0645: && algName == null)
0646: throw new NoSuchAlgorithmException(
0647: "SecureRandom not available for provider "
0648: + provider.getName());
0649: else {
0650: // try algName as alias name
0651: String stdName = getStandardName(algName, engineType,
0652: provider);
0653: if (stdName != null)
0654: key = engineType + "." + stdName;
0655: if ((stdName == null)
0656: || (className = getProviderProperty(key,
0657: provider)) == null)
0658: throw new NoSuchAlgorithmException(
0659: "no such algorithm: " + algName
0660: + " for provider "
0661: + provider.getName());
0662: }
0663: }
0664:
0665: ProviderProperty entry = new ProviderProperty();
0666: entry.className = className;
0667: entry.provider = provider;
0668:
0669: return entry;
0670: }
0671:
0672: /**
0673: * Adds a new provider, at a specified position. The position is
0674: * the preference order in which providers are searched for
0675: * requested algorithms. Note that it is not guaranteed that this
0676: * preference will be respected. The position is 1-based, that is,
0677: * 1 is most preferred, followed by 2, and so on.
0678: *
0679: * <p>If the given provider is installed at the requested position,
0680: * the provider that used to be at that position, and all providers
0681: * with a position greater than <code>position</code>, are shifted up
0682: * one position (towards the end of the list of installed providers).
0683: *
0684: * <p>A provider cannot be added if it is already installed.
0685: *
0686: * <p>First, if there is a security manager, its
0687: * <code>checkSecurityAccess</code>
0688: * method is called with the string
0689: * <code>"insertProvider."+provider.getName()</code>
0690: * to see if it's ok to add a new provider.
0691: * If the default implementation of <code>checkSecurityAccess</code>
0692: * is used (i.e., that method is not overriden), then this will result in
0693: * a call to the security manager's <code>checkPermission</code> method
0694: * with a
0695: * <code>SecurityPermission("insertProvider."+provider.getName())</code>
0696: * permission.
0697: *
0698: * @param provider the provider to be added.
0699: *
0700: * @param position the preference position that the caller would
0701: * like for this provider.
0702: *
0703: * @return the actual preference position in which the provider was
0704: * added, or -1 if the provider was not added because it is
0705: * already installed.
0706: *
0707: * @throws SecurityException
0708: * if a security manager exists and its <code>{@link
0709: * java.lang.SecurityManager#checkSecurityAccess}</code> method
0710: * denies access to add a new provider
0711: *
0712: * @see #getProvider
0713: * @see #removeProvider
0714: * @see java.security.SecurityPermission
0715: */
0716: public static synchronized int insertProviderAt(Provider provider,
0717: int position) {
0718: reloadProviders();
0719:
0720: check("insertProvider." + provider.getName());
0721:
0722: /* First check if the provider is already installed */
0723: Provider already = getProvider(provider.getName());
0724: if (already != null) {
0725: return -1;
0726: }
0727:
0728: int size = providers.size();
0729: if (position > size || position <= 0) {
0730: position = size + 1;
0731: }
0732:
0733: providers.insertElementAt(provider, position - 1);
0734:
0735: // empty provider-property cache
0736: providerPropertiesCache.clear();
0737: engineCache.clear();
0738: searchResultsCache.clear();
0739:
0740: return position;
0741: }
0742:
0743: /**
0744: * Adds a provider to the next position available.
0745: *
0746: * <p>First, if there is a security manager, its
0747: * <code>checkSecurityAccess</code>
0748: * method is called with the string
0749: * <code>"insertProvider."+provider.getName()</code>
0750: * to see if it's ok to add a new provider.
0751: * If the default implementation of <code>checkSecurityAccess</code>
0752: * is used (i.e., that method is not overriden), then this will result in
0753: * a call to the security manager's <code>checkPermission</code> method
0754: * with a
0755: * <code>SecurityPermission("insertProvider."+provider.getName())</code>
0756: * permission.
0757: *
0758: * @param provider the provider to be added.
0759: *
0760: * @return the preference position in which the provider was
0761: * added, or -1 if the provider was not added because it is
0762: * already installed.
0763: *
0764: * @throws SecurityException
0765: * if a security manager exists and its <code>{@link
0766: * java.lang.SecurityManager#checkSecurityAccess}</code> method
0767: * denies access to add a new provider
0768: *
0769: * @see #getProvider
0770: * @see #removeProvider
0771: * @see java.security.SecurityPermission
0772: */
0773: public static int addProvider(Provider provider) {
0774: /*
0775: * We can't assign a position here because the statically
0776: * registered providers may not have been installed yet.
0777: * insertProviderAt() will fix that value after it has
0778: * loaded the static providers.
0779: */
0780: return insertProviderAt(provider, 0);
0781: }
0782:
0783: /**
0784: * Removes the provider with the specified name.
0785: *
0786: * <p>When the specified provider is removed, all providers located
0787: * at a position greater than where the specified provider was are shifted
0788: * down one position (towards the head of the list of installed
0789: * providers).
0790: *
0791: * <p>This method returns silently if the provider is not installed.
0792: *
0793: * <p>First, if there is a security manager, its
0794: * <code>checkSecurityAccess</code>
0795: * method is called with the string <code>"removeProvider."+name</code>
0796: * to see if it's ok to remove the provider.
0797: * If the default implementation of <code>checkSecurityAccess</code>
0798: * is used (i.e., that method is not overriden), then this will result in
0799: * a call to the security manager's <code>checkPermission</code> method
0800: * with a <code>SecurityPermission("removeProvider."+name)</code>
0801: * permission.
0802: *
0803: * @param name the name of the provider to remove.
0804: *
0805: * @throws SecurityException
0806: * if a security manager exists and its <code>{@link
0807: * java.lang.SecurityManager#checkSecurityAccess}</code> method
0808: * denies
0809: * access to remove the provider
0810: *
0811: * @see #getProvider
0812: * @see #addProvider
0813: */
0814: public static synchronized void removeProvider(String name) {
0815: reloadProviders();
0816: check("removeProvider." + name);
0817: Provider provider = getProvider(name);
0818: if (provider != null) {
0819: for (Iterator i = providers.iterator(); i.hasNext();)
0820: if (i.next() == provider)
0821: i.remove();
0822:
0823: // empty provider-property cache
0824: providerPropertiesCache.clear();
0825: engineCache.clear();
0826: searchResultsCache.clear();
0827: }
0828: }
0829:
0830: /**
0831: * Returns an array containing all the installed providers. The order of
0832: * the providers in the array is their preference order.
0833: *
0834: * @return an array of all the installed providers.
0835: */
0836: public static synchronized Provider[] getProviders() {
0837: reloadProviders();
0838: Provider[] result = new Provider[providers.size()];
0839: providers.copyInto(result);
0840:
0841: return result;
0842: }
0843:
0844: /**
0845: * Returns the provider installed with the specified name, if
0846: * any. Returns null if no provider with the specified name is
0847: * installed.
0848: *
0849: * @param name the name of the provider to get.
0850: *
0851: * @return the provider of the specified name.
0852: *
0853: * @see #removeProvider
0854: * @see #addProvider
0855: */
0856: public static synchronized Provider getProvider(String name) {
0857: reloadProviders();
0858: Enumeration enum_ = providers.elements();
0859: while (enum_.hasMoreElements()) {
0860: Provider prov = (Provider) enum_.nextElement();
0861: if (prov.getName().equals(name)) {
0862: return prov;
0863: }
0864: }
0865: return null;
0866: }
0867:
0868: /**
0869: * Returns an array containing all installed providers that satisfy the
0870: * specified selection criterion, or null if no such providers have been
0871: * installed. The returned providers are ordered
0872: * according to their <a href=
0873: * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
0874: *
0875: * <p> A cryptographic service is always associated with a particular
0876: * algorithm or type. For example, a digital signature service is
0877: * always associated with a particular algorithm (e.g., DSA),
0878: * and a CertificateFactory service is always associated with
0879: * a particular certificate type (e.g., X.509).
0880: * NOTE: <B>java.security.cert.CertificateFactory</B> is found in J2ME CDC
0881: * profiles such as J2ME Foundation Profile.
0882: *
0883: * <p>The selection criterion must be specified in one of the following two formats:
0884: * <ul>
0885: * <li> <i><crypto_service>.<algorithm_or_type></i> <p> The
0886: * cryptographic service name must not contain any dots.
0887: * <p> A
0888: * provider satisfies the specified selection criterion iff the provider implements the
0889: * specified algorithm or type for the specified cryptographic service.
0890: * <p> For example, "CertificateFactory.X.509"
0891: * would be satisfied by any provider that supplied
0892: * a CertificateFactory implementation for X.509 certificates.
0893: * NOTE: <B>java.security.cert.CertificateFactory</B> is found in J2ME CDC
0894: * profiles such as J2ME Foundation Profile.
0895: * <li> <i><crypto_service>.<algorithm_or_type> <attribute_name>:< attribute_value></i>
0896: * <p> The cryptographic service name must not contain any dots. There
0897: * must be one or more space charaters between the the <i><algorithm_or_type></i>
0898: * and the <i><attribute_name></i>.
0899: * <p> A provider satisfies this selection criterion iff the
0900: * provider implements the specified algorithm or type for the specified
0901: * cryptographic service and its implementation meets the
0902: * constraint expressed by the specified attribute name/value pair.
0903: * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
0904: * satisfied by any provider that implemented
0905: * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
0906: * NOTE: <B>java.security.Signature</B> is found in J2ME CDC profiles such as
0907: * J2ME Foundation Profile.
0908: *
0909: * </ul>
0910: *
0911: * <p> See Appendix A in the <a href=
0912: * "../../../guide/security/CryptoSpec.html#AppA">
0913: * Java Cryptogaphy Architecture API Specification & Reference </a>
0914: * for information about standard cryptographic service names, standard
0915: * algorithm names and standard attribute names.
0916: *
0917: * @param filter the criterion for selecting
0918: * providers. The filter is case-insensitive.
0919: *
0920: * @return all the installed providers that satisfy the selection
0921: * criterion, or null if no such providers have been installed.
0922: *
0923: * @throws InvalidParameterException
0924: * if the filter is not in the required format
0925: *
0926: * @see #getProviders(java.util.Map)
0927: */
0928: public static Provider[] getProviders(String filter) {
0929: String key = null;
0930: String value = null;
0931: int index = filter.indexOf(':');
0932:
0933: if (index == -1) {
0934: key = new String(filter);
0935: value = "";
0936: } else {
0937: key = filter.substring(0, index);
0938: value = filter.substring(index + 1);
0939: }
0940:
0941: Hashtable hashtableFilter = new Hashtable(1);
0942: hashtableFilter.put(key, value);
0943:
0944: return (getProviders(hashtableFilter));
0945: }
0946:
0947: /**
0948: * Returns an array containing all installed providers that satisfy the specified
0949: * selection criteria, or null if no such providers have been installed.
0950: * The returned providers are ordered
0951: * according to their <a href=
0952: * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
0953: *
0954: * <p>The selection criteria are represented by a map.
0955: * Each map entry represents a selection criterion.
0956: * A provider is selected iff it satisfies all selection
0957: * criteria. The key for any entry in such a map must be in one of the
0958: * following two formats:
0959: * <ul>
0960: * <li> <i><crypto_service>.<algorithm_or_type></i>
0961: * <p> The cryptographic service name must not contain any dots.
0962: * <p> The value associated with the key must be an empty string.
0963: * <p> A provider
0964: * satisfies this selection criterion iff the provider implements the
0965: * specified algorithm or type for the specified cryptographic service.
0966: * <li> <i><crypto_service>.<algorithm_or_type> <attribute_name></i>
0967: * <p> The cryptographic service name must not contain any dots. There
0968: * must be one or more space charaters between the <i><algorithm_or_type></i>
0969: * and the <i><attribute_name></i>.
0970: * <p> The value associated with the key must be a non-empty string.
0971: * A provider satisfies this selection criterion iff the
0972: * provider implements the specified algorithm or type for the specified
0973: * cryptographic service and its implementation meets the
0974: * constraint expressed by the specified attribute name/value pair.
0975: * </ul>
0976: *
0977: * <p> See Appendix A in the <a href=
0978: * "../../../guide/security/CryptoSpec.html#AppA">
0979: * Java Cryptogaphy Architecture API Specification & Reference </a>
0980: * for information about standard cryptographic service names, standard
0981: * algorithm names and standard attribute names.
0982: *
0983: * @param filter the criteria for selecting
0984: * providers. The filter is case-insensitive.
0985: *
0986: * @return all the installed providers that satisfy the selection
0987: * criteria, or null if no such providers have been installed.
0988: *
0989: * @throws InvalidParameterException
0990: * if the filter is not in the required format
0991: *
0992: * @see #getProviders(java.lang.String)
0993: */
0994: public static Provider[] getProviders(Map filter) {
0995: // Get all installed providers first.
0996: // Then only return those providers who satisfy the selection criteria.
0997: Provider[] allProviders = Security.getProviders();
0998: Set keySet = filter.keySet();
0999: LinkedHashSet candidates = new LinkedHashSet(5);
1000:
1001: // Returns all installed providers
1002: // if the selection criteria is null.
1003: if ((keySet == null) || (allProviders == null)) {
1004: return allProviders;
1005: }
1006:
1007: boolean firstSearch = true;
1008:
1009: // For each selection criterion, remove providers
1010: // which don't satisfy the criterion from the candidate set.
1011: for (Iterator ite = keySet.iterator(); ite.hasNext();) {
1012: String key = (String) ite.next();
1013: String value = (String) filter.get(key);
1014:
1015: LinkedHashSet newCandidates = getAllQualifyingCandidates(
1016: key, value, allProviders);
1017: if (firstSearch) {
1018: candidates = newCandidates;
1019: firstSearch = false;
1020: }
1021:
1022: if ((newCandidates != null) && !newCandidates.isEmpty()) {
1023: // For each provider in the candidates set, if it
1024: // isn't in the newCandidate set, we should remove
1025: // it from the candidate set.
1026: for (Iterator cansIte = candidates.iterator(); cansIte
1027: .hasNext();) {
1028: Provider prov = (Provider) cansIte.next();
1029: if (!newCandidates.contains(prov)) {
1030: cansIte.remove();
1031: }
1032: }
1033: } else {
1034: candidates = null;
1035: break;
1036: }
1037: }
1038:
1039: if ((candidates == null) || (candidates.isEmpty()))
1040: return null;
1041:
1042: Object[] candidatesArray = candidates.toArray();
1043: Provider[] result = new Provider[candidatesArray.length];
1044:
1045: for (int i = 0; i < result.length; i++) {
1046: result[i] = (Provider) candidatesArray[i];
1047: }
1048:
1049: return result;
1050: }
1051:
1052: private static boolean checkSuperclass(Class subclass,
1053: Class super class) {
1054: while (!subclass.equals(super class)) {
1055: subclass = subclass.getSuperclass();
1056: if (subclass == null) {
1057: return false;
1058: }
1059: }
1060: return true;
1061: }
1062:
1063: /*
1064: * Returns an array of objects: the first object in the array is
1065: * an instance of an implementation of the requested algorithm
1066: * and type, and the second object in the array identifies the provider
1067: * of that implementation.
1068: * The <code>provider</code> argument can be null, in which case all
1069: * configured providers will be searched in order of preference.
1070: */
1071: static Object[] getImpl(String algorithm, String type,
1072: String provider) throws NoSuchAlgorithmException,
1073: NoSuchProviderException {
1074: ProviderProperty pp = getEngineClassName(algorithm, provider,
1075: type);
1076: return doGetImpl(algorithm, type, pp);
1077: }
1078:
1079: static Object[] getImpl(String algorithm, String type,
1080: String provider, Object params)
1081: throws NoSuchAlgorithmException, NoSuchProviderException,
1082: InvalidAlgorithmParameterException {
1083: ProviderProperty pp = getEngineClassName(algorithm, provider,
1084: type);
1085: return doGetImpl(algorithm, type, pp, params);
1086: }
1087:
1088: /*
1089: * Returns an array of objects: the first object in the array is
1090: * an instance of an implementation of the requested algorithm
1091: * and type, and the second object in the array identifies the provider
1092: * of that implementation.
1093: * The <code>provider</code> argument cannot be null.
1094: */
1095: static Object[] getImpl(String algorithm, String type,
1096: Provider provider) throws NoSuchAlgorithmException {
1097: ProviderProperty pp = getEngineClassName(algorithm, provider,
1098: type);
1099: return doGetImpl(algorithm, type, pp);
1100: }
1101:
1102: static Object[] getImpl(String algorithm, String type,
1103: Provider provider, Object params)
1104: throws NoSuchAlgorithmException,
1105: InvalidAlgorithmParameterException {
1106: ProviderProperty pp = getEngineClassName(algorithm, provider,
1107: type);
1108: return doGetImpl(algorithm, type, pp, params);
1109: }
1110:
1111: private static Object[] doGetImpl(String algorithm, String type,
1112: ProviderProperty pp) throws NoSuchAlgorithmException {
1113: try {
1114: return doGetImpl(algorithm, type, pp, null);
1115: } catch (InvalidAlgorithmParameterException e) {
1116: // should not occur
1117: throw new NoSuchAlgorithmException(e.getMessage());
1118: }
1119: }
1120:
1121: private static Object[] doGetImpl(String algorithm, String type,
1122: ProviderProperty pp, Object params)
1123: throws NoSuchAlgorithmException,
1124: InvalidAlgorithmParameterException {
1125: String className = pp.className;
1126: String providerName = pp.provider.getName();
1127:
1128: try {
1129: // java.security.<type>.Spi is a system class, therefore
1130: // Class.forName() always works
1131: Class typeClass;
1132: if (type.equals("CertificateFactory")
1133: || type.equals("CertPathBuilder")
1134: || type.equals("CertPathValidator")
1135: || type.equals("CertStore")) {
1136: typeClass = Class.forName("java.security.cert." + type
1137: + "Spi");
1138: } else {
1139: typeClass = Class.forName("java.security." + type
1140: + "Spi");
1141: }
1142:
1143: // Load the implementation class using the same class loader that
1144: // was used to load the associated provider.
1145: // In order to get the class loader of a class, the caller's class
1146: // loader must be the same as or an ancestor of the class loader
1147: // being returned.
1148: // Since java.security.Security is a system class, it can get the
1149: // class loader of any class (the system class loader is an
1150: // ancestor of all class loaders).
1151: ClassLoader cl = pp.provider.getClass().getClassLoader();
1152: Class implClass;
1153: if (cl != null) {
1154: implClass = cl.loadClass(className);
1155: } else {
1156: implClass = Class.forName(className);
1157: }
1158:
1159: if (checkSuperclass(implClass, typeClass)) {
1160: Object obj;
1161: if (type.equals("CertStore")) {
1162: Constructor cons = implClass
1163: .getConstructor(new Class[] { Class
1164: .forName("java.security.cert.CertStoreParameters") });
1165: obj = cons.newInstance(new Object[] { params });
1166: } else
1167: obj = implClass.newInstance();
1168: return new Object[] { obj, pp.provider };
1169: } else {
1170: throw new NoSuchAlgorithmException(
1171: "class configured for " + type + ": "
1172: + className + " not a " + type);
1173: }
1174: } catch (ClassNotFoundException e) {
1175: throw new NoSuchAlgorithmException("class configured for "
1176: + type + "(provider: " + providerName + ")"
1177: + "cannot be found.\n" + e.getMessage());
1178: } catch (InstantiationException e) {
1179: throw (NoSuchAlgorithmException) new NoSuchAlgorithmException(
1180: "class " + className + " configured for " + type
1181: + "(provider: " + providerName
1182: + ") cannot be " + "instantiated.\n")
1183: .initCause(e);
1184: } catch (IllegalAccessException e) {
1185: throw new NoSuchAlgorithmException("class " + className
1186: + " configured for " + type + "(provider: "
1187: + providerName + ") cannot be accessed.\n"
1188: + e.getMessage());
1189: } catch (SecurityException e) {
1190: throw new NoSuchAlgorithmException("class " + className
1191: + " configured for " + type + "(provider: "
1192: + providerName + ") cannot be accessed.\n"
1193: + e.getMessage());
1194: } catch (NoSuchMethodException e) {
1195: throw new NoSuchAlgorithmException("constructor for "
1196: + "class " + className + " configured for " + type
1197: + "(provider: " + providerName
1198: + ") cannot be instantiated.\n" + e.getMessage());
1199: } catch (InvocationTargetException e) {
1200: Throwable t = e.getCause();
1201: if (t != null
1202: && t instanceof InvalidAlgorithmParameterException)
1203: throw (InvalidAlgorithmParameterException) t;
1204: else
1205: throw new InvalidAlgorithmParameterException(
1206: "constructor " + "for class " + className
1207: + " configured for " + type
1208: + "(provider: " + providerName
1209: + ") cannot be instantiated.\n"
1210: + e.getMessage());
1211: }
1212: }
1213:
1214: /**
1215: * Gets a security property value.
1216: *
1217: * <p>First, if there is a security manager, its
1218: * <code>checkPermission</code> method is called with a
1219: * <code>java.security.SecurityPermission("getProperty."+key)</code>
1220: * permission to see if it's ok to retrieve the specified
1221: * security property value..
1222: *
1223: * @param key the key of the property being retrieved.
1224: *
1225: * @return the value of the security property corresponding to key.
1226: *
1227: * @throws SecurityException
1228: * if a security manager exists and its <code>{@link
1229: * java.lang.SecurityManager#checkPermission}</code> method
1230: * denies
1231: * access to retrieve the specified security property value
1232: *
1233: * @see #setProperty
1234: * @see java.security.SecurityPermission
1235: */
1236: public static String getProperty(String key) {
1237: SecurityManager sm = System.getSecurityManager();
1238: if (sm != null) {
1239: sm.checkPermission(new SecurityPermission("getProperty."
1240: + key));
1241: }
1242: String name = props.getProperty(key);
1243: if (name != null)
1244: name = name.trim(); // could be a class name with trailing ws
1245: return name;
1246: }
1247:
1248: /**
1249: * Sets a security property value.
1250: *
1251: * <p>First, if there is a security manager, its
1252: * <code>checkPermission</code> method is called with a
1253: * <code>java.security.SecurityPermission("setProperty."+key)</code>
1254: * permission to see if it's ok to set the specified
1255: * security property value.
1256: *
1257: * @param key the name of the property to be set.
1258: *
1259: * @param datum the value of the property to be set.
1260: *
1261: * @throws SecurityException
1262: * if a security manager exists and its <code>{@link
1263: * java.lang.SecurityManager#checkPermission}</code> method
1264: * denies access to set the specified security property value
1265: *
1266: * @see #getProperty
1267: * @see java.security.SecurityPermission
1268: */
1269: public static void setProperty(String key, String datum) {
1270: check("setProperty." + key);
1271: props.put(key, datum);
1272: invalidateSMCache(key); /* See below. */
1273: }
1274:
1275: /*
1276: * Implementation detail: If the property we just set in
1277: * setProperty() was either "package.access" or
1278: * "package.definition", we need to signal to the SecurityManager
1279: * class that the value has just changed, and that it should
1280: * invalidate it's local cache values.
1281: *
1282: * Rather than create a new API entry for this function,
1283: * we use reflection to set a private variable.
1284: */
1285: private static void invalidateSMCache(String key) {
1286:
1287: final boolean pa = key.equals("package.access");
1288: final boolean pd = key.equals("package.definition");
1289:
1290: if (pa || pd) {
1291: AccessController.doPrivileged(new PrivilegedAction() {
1292: public Object run() {
1293: try {
1294: /* Get the class via the bootstrap class loader. */
1295: Class cl = Class.forName(
1296: "java.lang.SecurityManager", false,
1297: null);
1298: Field f = null;
1299: boolean accessible = false;
1300:
1301: if (pa) {
1302: f = cl
1303: .getDeclaredField("packageAccessValid");
1304: accessible = f.isAccessible();
1305: f.setAccessible(true);
1306: } else {
1307: f = cl
1308: .getDeclaredField("packageDefinitionValid");
1309: accessible = f.isAccessible();
1310: f.setAccessible(true);
1311: }
1312: f.setBoolean(f, false);
1313: f.setAccessible(accessible);
1314: } catch (Exception e1) {
1315: /* If we couldn't get the class, it hasn't
1316: * been loaded yet. If there is no such
1317: * field, we shouldn't try to set it. There
1318: * shouldn't be a security execption, as we
1319: * are loaded by boot class loader, and we
1320: * are inside a doPrivileged() here.
1321: *
1322: * NOOP: don't do anything...
1323: */
1324: }
1325: return null;
1326: } /* run */
1327: }); /* PrivilegedAction */
1328: } /* if */
1329: }
1330:
1331: private static void check(String directive) {
1332: SecurityManager security = System.getSecurityManager();
1333: if (security != null) {
1334: security.checkSecurityAccess(directive);
1335: }
1336: }
1337:
1338: /**
1339: * Print an error message that may be significant to a user.
1340: */
1341: static void error(String msg) {
1342: if (debug) {
1343: System.err.println(msg);
1344: }
1345: }
1346:
1347: /**
1348: * Print an error message that may be significant to a user.
1349: */
1350: static void error(String msg, Throwable t) {
1351: error(msg);
1352: if (debug) {
1353: t.printStackTrace();
1354: }
1355: }
1356:
1357: /**
1358: * Print an debugging message that may be significant to a developer.
1359: */
1360: static void debug(String msg) {
1361: if (debug) {
1362: System.err.println(msg);
1363: }
1364: }
1365:
1366: /**
1367: * Print an debugging message that may be significant to a developer.
1368: */
1369: static void debug(String msg, Throwable t) {
1370: if (debug) {
1371: t.printStackTrace();
1372: System.err.println(msg);
1373: }
1374: }
1375:
1376: /*
1377: * Returns all providers who satisfy the specified
1378: * criterion.
1379: */
1380: private static LinkedHashSet getAllQualifyingCandidates(
1381: String filterKey, String filterValue,
1382: Provider[] allProviders) {
1383: String[] filterComponents = getFilterComponents(filterKey,
1384: filterValue);
1385:
1386: // The first component is the service name.
1387: // The second is the algorithm name.
1388: // If the third isn't null, that is the attrinute name.
1389: String serviceName = filterComponents[0];
1390: String algName = filterComponents[1];
1391: String attrName = filterComponents[2];
1392:
1393: // Check whether we can find anything in the cache
1394: String cacheKey = serviceName + '.' + algName;
1395: LinkedHashSet candidates = (LinkedHashSet) searchResultsCache
1396: .get(cacheKey);
1397:
1398: // If there is no entry for the cacheKey in the cache,
1399: // let's build an entry for it first.
1400: LinkedHashSet forCache = getProvidersNotUsingCache(serviceName,
1401: algName, null, null, null, allProviders);
1402:
1403: if ((forCache == null) || (forCache.isEmpty())) {
1404: return null;
1405: } else {
1406: searchResultsCache.put(cacheKey, forCache);
1407: if (attrName == null) {
1408: return forCache;
1409: }
1410: return getProvidersNotUsingCache(serviceName, algName,
1411: attrName, filterValue, candidates, allProviders);
1412: }
1413: }
1414:
1415: private static LinkedHashSet getProvidersNotUsingCache(
1416: String serviceName, String algName, String attrName,
1417: String filterValue, LinkedHashSet candidates,
1418: Provider[] allProviders) {
1419: if ((attrName != null) && (candidates != null)
1420: && (!candidates.isEmpty())) {
1421: for (Iterator cansIte = candidates.iterator(); cansIte
1422: .hasNext();) {
1423: Provider prov = (Provider) cansIte.next();
1424: if (!isCriterionSatisfied(prov, serviceName, algName,
1425: attrName, filterValue)) {
1426: cansIte.remove();
1427: }
1428: }
1429: }
1430:
1431: if ((candidates == null) || (candidates.isEmpty())) {
1432: if (candidates == null)
1433: candidates = new LinkedHashSet(5);
1434: for (int i = 0; i < allProviders.length; i++) {
1435: if (isCriterionSatisfied(allProviders[i], serviceName,
1436: algName, attrName, filterValue)) {
1437: candidates.add(allProviders[i]);
1438: }
1439: }
1440: }
1441:
1442: return candidates;
1443: }
1444:
1445: /*
1446: * Returns true if the given provider satisfies
1447: * the selection criterion key:value.
1448: */
1449: private static boolean isCriterionSatisfied(Provider prov,
1450: String serviceName, String algName, String attrName,
1451: String filterValue) {
1452: String key = serviceName + '.' + algName;
1453:
1454: if (attrName != null) {
1455: key += ' ' + attrName;
1456: }
1457: // Check whether the provider has a property
1458: // whose key is the same as the given key.
1459: String propValue = getProviderProperty(key, prov);
1460:
1461: if (propValue == null) {
1462: // Check whether we have an alias instead
1463: // of a standard name in the key.
1464: String standardName = getProviderProperty("Alg.Alias."
1465: + serviceName + "." + algName, prov);
1466: if (standardName != null) {
1467: key = serviceName + "." + standardName;
1468:
1469: if (attrName != null) {
1470: key += ' ' + attrName;
1471: }
1472:
1473: propValue = getProviderProperty(key, prov);
1474: }
1475:
1476: if (propValue == null) {
1477: // The provider doesn't have the given
1478: // key in its property list.
1479: return false;
1480: }
1481: }
1482:
1483: // If the key is in the format of:
1484: // <crypto_service>.<algorithm_or_type>,
1485: // there is no need to check the value.
1486:
1487: if (attrName == null) {
1488: return true;
1489: }
1490:
1491: // If we get here, the key must be in the
1492: // format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
1493: if (isStandardAttr(attrName)) {
1494: return isConstraintSatisfied(attrName, filterValue,
1495: propValue);
1496: } else {
1497: return filterValue.equalsIgnoreCase(propValue);
1498: }
1499: }
1500:
1501: /*
1502: * Returns true if the attribute is a standard attribute;
1503: * otherwise, returns false.
1504: */
1505: private static boolean isStandardAttr(String attribute) {
1506: // For now, we just have two standard attributes: KeySize and ImplementedIn.
1507: if (attribute.equalsIgnoreCase("KeySize"))
1508: return true;
1509:
1510: if (attribute.equalsIgnoreCase("ImplementedIn"))
1511: return true;
1512:
1513: return false;
1514: }
1515:
1516: /*
1517: * Returns true if the requested attribute value is supported;
1518: * otherwise, returns false.
1519: */
1520: private static boolean isConstraintSatisfied(String attribute,
1521: String value, String prop) {
1522: // For KeySize, prop is the max key size the
1523: // provider supports for a specific <crypto_service>.<algorithm>.
1524: if (attribute.equalsIgnoreCase("KeySize")) {
1525: int requestedSize = (new Integer(value)).intValue();
1526: int maxSize = (new Integer(prop)).intValue();
1527: if (requestedSize <= maxSize) {
1528: return true;
1529: } else {
1530: return false;
1531: }
1532: }
1533:
1534: // For Type, prop is the type of the implementation
1535: // for a specific <crypto service>.<algorithm>.
1536: if (attribute.equalsIgnoreCase("ImplementedIn")) {
1537: return value.equalsIgnoreCase(prop);
1538: }
1539:
1540: return false;
1541: }
1542:
1543: static String[] getFilterComponents(String filterKey,
1544: String filterValue) {
1545: int algIndex = filterKey.indexOf('.');
1546:
1547: if (algIndex < 0) {
1548: // There must be a dot in the filter, and the dot
1549: // shouldn't be at the beginning of this string.
1550: throw new InvalidParameterException("Invalid filter");
1551: }
1552:
1553: String serviceName = filterKey.substring(0, algIndex);
1554: String algName = null;
1555: String attrName = null;
1556:
1557: if (filterValue.length() == 0) {
1558: // The filterValue is an empty string. So the filterKey
1559: // should be in the format of <crypto_service>.<algorithm_or_type>.
1560: algName = filterKey.substring(algIndex + 1).trim();
1561: if (algName.length() == 0) {
1562: // There must be a algorithm or type name.
1563: throw new InvalidParameterException("Invalid filter");
1564: }
1565: } else {
1566: // The filterValue is a non-empty string. So the filterKey must be
1567: // in the format of
1568: // <crypto_service>.<algorithm_or_type> <attribute_name>
1569: int attrIndex = filterKey.indexOf(' ');
1570:
1571: if (attrIndex == -1) {
1572: // There is no attribute name in the filter.
1573: throw new InvalidParameterException("Invalid filter");
1574: } else {
1575: attrName = filterKey.substring(attrIndex + 1).trim();
1576: if (attrName.length() == 0) {
1577: // There is no attribute name in the filter.
1578: throw new InvalidParameterException(
1579: "Invalid filter");
1580: }
1581: }
1582:
1583: // There must be an algorithm name in the filter.
1584: if ((attrIndex < algIndex) || (algIndex == attrIndex - 1)) {
1585: throw new InvalidParameterException("Invalid filter");
1586: } else {
1587: algName = filterKey.substring(algIndex + 1, attrIndex);
1588: }
1589: }
1590:
1591: String[] result = new String[3];
1592: result[0] = serviceName;
1593: result[1] = algName;
1594: result[2] = attrName;
1595:
1596: return result;
1597: }
1598:
1599: /**
1600: * Returns a Set of Strings containing the names of all available
1601: * algorithms or types for the specified Java cryptographic service
1602: * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns
1603: * an empty Set if there is no provider that supports the
1604: * specified service. For a complete list of Java cryptographic
1605: * services, please see the
1606: * <a href="../../../guide/security/CryptoSpec.html">Java
1607: * Cryptography Architecture API Specification & Reference</a>.
1608: * Note: the returned set is immutable.
1609: *
1610: * @param serviceName the name of the Java cryptographic
1611: * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
1612: * Note: this parameter is case-insensitive.
1613: *
1614: * NOTE: <B>java.security.Signature, java.security.KeyStore</B> are found
1615: * in J2ME CDC profiles such as J2ME Foundation Profile. <B> Cipher,
1616: * Mac </B> are found in J2ME CDC optional packages such as J2ME Security
1617: * Optional Package.
1618: *
1619: * @return a Set of Strings containing the names of all available
1620: * algorithms or types for the specified Java cryptographic service
1621: * or an empty set if no provider supports the specified service.
1622: *
1623: * @since 1.4
1624: **/
1625: public static Set getAlgorithms(String serviceName) {
1626: HashSet result = new HashSet();
1627:
1628: if ((serviceName == null) || (serviceName.length() == 0)
1629: || (serviceName.endsWith("."))) {
1630: return result;
1631: }
1632:
1633: Provider[] providers = Security.getProviders();
1634:
1635: for (int i = 0; i < providers.length; i++) {
1636: // Check the keys for each provider.
1637: for (Enumeration e = providers[i].keys(); e
1638: .hasMoreElements();) {
1639: String currentKey = ((String) e.nextElement())
1640: .toUpperCase();
1641: if (currentKey.startsWith(serviceName.toUpperCase())) {
1642: // We should skip the currentKey if it contains a
1643: // whitespace. The reason is: such an entry in the
1644: // provider property contains attributes for the
1645: // implementation of an algorithm. We are only interested
1646: // in entries which lead to the implementation
1647: // classes.
1648: if (currentKey.indexOf(" ") < 0) {
1649: result.add(currentKey.substring(serviceName
1650: .length() + 1));
1651: }
1652: }
1653: }
1654: }
1655: return Collections.unmodifiableSet(result);
1656: }
1657: }
|