0001 /*
0002 * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package java.security;
0027
0028 import java.lang.reflect.*;
0029 import java.util.*;
0030 import java.util.concurrent.ConcurrentHashMap;
0031 import java.io.*;
0032 import java.net.URL;
0033 import sun.security.util.Debug;
0034 import sun.security.util.PropertyExpander;
0035
0036 import java.security.Provider.Service;
0037
0038 import sun.security.jca.*;
0039
0040 /**
0041 * <p>This class centralizes all security properties and common security
0042 * methods. One of its primary uses is to manage providers.
0043 *
0044 * @author Benjamin Renaud
0045 * @version 1.140, 05/05/07
0046 */
0047
0048 public final class Security {
0049
0050 /* Are we debugging? -- for developers */
0051 private static final Debug sdebug = Debug.getInstance("properties");
0052
0053 /* The java.security properties */
0054 private static Properties props;
0055
0056 // An element in the cache
0057 private static class ProviderProperty {
0058 String className;
0059 Provider provider;
0060 }
0061
0062 static {
0063 // doPrivileged here because there are multiple
0064 // things in initialize that might require privs.
0065 // (the FileInputStream call and the File.exists call,
0066 // the securityPropFile call, etc)
0067 AccessController.doPrivileged(new PrivilegedAction<Void>() {
0068 public Void run() {
0069 initialize();
0070 return null;
0071 }
0072 });
0073 }
0074
0075 private static void initialize() {
0076 props = new Properties();
0077 boolean loadedProps = false;
0078 boolean overrideAll = false;
0079
0080 // first load the system properties file
0081 // to determine the value of security.overridePropertiesFile
0082 File propFile = securityPropFile("java.security");
0083 if (propFile.exists()) {
0084 InputStream is = null;
0085 try {
0086 FileInputStream fis = new FileInputStream(propFile);
0087 is = new BufferedInputStream(fis);
0088 props.load(is);
0089 loadedProps = true;
0090
0091 if (sdebug != null) {
0092 sdebug.println("reading security properties file: "
0093 + propFile);
0094 }
0095 } catch (IOException e) {
0096 if (sdebug != null) {
0097 sdebug
0098 .println("unable to load security properties from "
0099 + propFile);
0100 e.printStackTrace();
0101 }
0102 } finally {
0103 if (is != null) {
0104 try {
0105 is.close();
0106 } catch (IOException ioe) {
0107 if (sdebug != null) {
0108 sdebug
0109 .println("unable to close input stream");
0110 }
0111 }
0112 }
0113 }
0114 }
0115
0116 if ("true".equalsIgnoreCase(props
0117 .getProperty("security.overridePropertiesFile"))) {
0118
0119 String extraPropFile = System
0120 .getProperty("java.security.properties");
0121 if (extraPropFile != null && extraPropFile.startsWith("=")) {
0122 overrideAll = true;
0123 extraPropFile = extraPropFile.substring(1);
0124 }
0125
0126 if (overrideAll) {
0127 props = new Properties();
0128 if (sdebug != null) {
0129 sdebug
0130 .println("overriding other security properties files!");
0131 }
0132 }
0133
0134 // now load the user-specified file so its values
0135 // will win if they conflict with the earlier values
0136 if (extraPropFile != null) {
0137 BufferedInputStream bis = null;
0138 try {
0139 URL propURL;
0140
0141 extraPropFile = PropertyExpander
0142 .expand(extraPropFile);
0143 propFile = new File(extraPropFile);
0144 if (propFile.exists()) {
0145 propURL = new URL("file:"
0146 + propFile.getCanonicalPath());
0147 } else {
0148 propURL = new URL(extraPropFile);
0149 }
0150 bis = new BufferedInputStream(propURL.openStream());
0151 props.load(bis);
0152 loadedProps = true;
0153
0154 if (sdebug != null) {
0155 sdebug
0156 .println("reading security properties file: "
0157 + propURL);
0158 if (overrideAll) {
0159 sdebug
0160 .println("overriding other security properties files!");
0161 }
0162 }
0163 } catch (Exception e) {
0164 if (sdebug != null) {
0165 sdebug
0166 .println("unable to load security properties from "
0167 + extraPropFile);
0168 e.printStackTrace();
0169 }
0170 } finally {
0171 if (bis != null) {
0172 try {
0173 bis.close();
0174 } catch (IOException ioe) {
0175 if (sdebug != null) {
0176 sdebug
0177 .println("unable to close input stream");
0178 }
0179 }
0180 }
0181 }
0182 }
0183 }
0184
0185 if (!loadedProps) {
0186 initializeStatic();
0187 if (sdebug != null) {
0188 sdebug.println("unable to load security properties "
0189 + "-- using defaults");
0190 }
0191 }
0192
0193 }
0194
0195 /*
0196 * Initialize to default values, if <java.home>/lib/java.security
0197 * is not found.
0198 */
0199 private static void initializeStatic() {
0200 props.put("security.provider.1", "sun.security.provider.Sun");
0201 props.put("security.provider.2", "sun.security.rsa.SunRsaSign");
0202 props.put("security.provider.3",
0203 "com.sun.net.ssl.internal.ssl.Provider");
0204 props.put("security.provider.4",
0205 "com.sun.crypto.provider.SunJCE");
0206 props.put("security.provider.5",
0207 "sun.security.jgss.SunProvider");
0208 props.put("security.provider.6",
0209 "com.sun.security.sasl.Provider");
0210 }
0211
0212 /**
0213 * Don't let anyone instantiate this.
0214 */
0215 private Security() {
0216 }
0217
0218 private static File securityPropFile(String filename) {
0219 // maybe check for a system property which will specify where to
0220 // look. Someday.
0221 String sep = File.separator;
0222 return new File(System.getProperty("java.home") + sep + "lib"
0223 + sep + "security" + sep + filename);
0224 }
0225
0226 /**
0227 * Looks up providers, and returns the property (and its associated
0228 * provider) mapping the key, if any.
0229 * The order in which the providers are looked up is the
0230 * provider-preference order, as specificed in the security
0231 * properties file.
0232 */
0233 private static ProviderProperty getProviderProperty(String key) {
0234 ProviderProperty entry = null;
0235
0236 List<Provider> providers = Providers.getProviderList()
0237 .providers();
0238 for (int i = 0; i < providers.size(); i++) {
0239
0240 String matchKey = null;
0241 Provider prov = providers.get(i);
0242 String prop = prov.getProperty(key);
0243
0244 if (prop == null) {
0245 // Is there a match if we do a case-insensitive property name
0246 // comparison? Let's try ...
0247 for (Enumeration<Object> e = prov.keys(); e
0248 .hasMoreElements()
0249 && prop == null;) {
0250 matchKey = (String) e.nextElement();
0251 if (key.equalsIgnoreCase(matchKey)) {
0252 prop = prov.getProperty(matchKey);
0253 break;
0254 }
0255 }
0256 }
0257
0258 if (prop != null) {
0259 ProviderProperty newEntry = new ProviderProperty();
0260 newEntry.className = prop;
0261 newEntry.provider = prov;
0262 return newEntry;
0263 }
0264 }
0265
0266 return entry;
0267 }
0268
0269 /**
0270 * Returns the property (if any) mapping the key for the given provider.
0271 */
0272 private static String getProviderProperty(String key,
0273 Provider provider) {
0274 String prop = provider.getProperty(key);
0275 if (prop == null) {
0276 // Is there a match if we do a case-insensitive property name
0277 // comparison? Let's try ...
0278 for (Enumeration<Object> e = provider.keys(); e
0279 .hasMoreElements()
0280 && prop == null;) {
0281 String matchKey = (String) e.nextElement();
0282 if (key.equalsIgnoreCase(matchKey)) {
0283 prop = provider.getProperty(matchKey);
0284 break;
0285 }
0286 }
0287 }
0288 return prop;
0289 }
0290
0291 /**
0292 * Gets a specified property for an algorithm. The algorithm name
0293 * should be a standard name. See Appendix A in the <a href=
0294 * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
0295 * Java Cryptography Architecture API Specification & Reference </a>
0296 * for information about standard algorithm names.
0297 * One possible use is by specialized algorithm parsers, which may map
0298 * classes to algorithms which they understand (much like Key parsers
0299 * do).
0300 *
0301 * @param algName the algorithm name.
0302 *
0303 * @param propName the name of the property to get.
0304 *
0305 * @return the value of the specified property.
0306 *
0307 * @deprecated This method used to return the value of a proprietary
0308 * property in the master file of the "SUN" Cryptographic Service
0309 * Provider in order to determine how to parse algorithm-specific
0310 * parameters. Use the new provider-based and algorithm-independent
0311 * <code>AlgorithmParameters</code> and <code>KeyFactory</code> engine
0312 * classes (introduced in the J2SE version 1.2 platform) instead.
0313 */
0314 @Deprecated
0315 public static String getAlgorithmProperty(String algName,
0316 String propName) {
0317 ProviderProperty entry = getProviderProperty("Alg." + propName
0318 + "." + algName);
0319 if (entry != null) {
0320 return entry.className;
0321 } else {
0322 return null;
0323 }
0324 }
0325
0326 /**
0327 * Adds a new provider, at a specified position. The position is
0328 * the preference order in which providers are searched for
0329 * requested algorithms. The position is 1-based, that is,
0330 * 1 is most preferred, followed by 2, and so on.
0331 *
0332 * <p>If the given provider is installed at the requested position,
0333 * the provider that used to be at that position, and all providers
0334 * with a position greater than <code>position</code>, are shifted up
0335 * one position (towards the end of the list of installed providers).
0336 *
0337 * <p>A provider cannot be added if it is already installed.
0338 *
0339 * <p>First, if there is a security manager, its
0340 * <code>checkSecurityAccess</code>
0341 * method is called with the string
0342 * <code>"insertProvider."+provider.getName()</code>
0343 * to see if it's ok to add a new provider.
0344 * If the default implementation of <code>checkSecurityAccess</code>
0345 * is used (i.e., that method is not overriden), then this will result in
0346 * a call to the security manager's <code>checkPermission</code> method
0347 * with a
0348 * <code>SecurityPermission("insertProvider."+provider.getName())</code>
0349 * permission.
0350 *
0351 * @param provider the provider to be added.
0352 *
0353 * @param position the preference position that the caller would
0354 * like for this provider.
0355 *
0356 * @return the actual preference position in which the provider was
0357 * added, or -1 if the provider was not added because it is
0358 * already installed.
0359 *
0360 * @throws NullPointerException if provider is null
0361 * @throws SecurityException
0362 * if a security manager exists and its <code>{@link
0363 * java.lang.SecurityManager#checkSecurityAccess}</code> method
0364 * denies access to add a new provider
0365 *
0366 * @see #getProvider
0367 * @see #removeProvider
0368 * @see java.security.SecurityPermission
0369 */
0370 public static synchronized int insertProviderAt(Provider provider,
0371 int position) {
0372 String providerName = provider.getName();
0373 check("insertProvider." + providerName);
0374 ProviderList list = Providers.getFullProviderList();
0375 ProviderList newList = ProviderList.insertAt(list, provider,
0376 position - 1);
0377 if (list == newList) {
0378 return -1;
0379 }
0380 Providers.setProviderList(newList);
0381 return newList.getIndex(providerName) + 1;
0382 }
0383
0384 /**
0385 * Adds a provider to the next position available.
0386 *
0387 * <p>First, if there is a security manager, its
0388 * <code>checkSecurityAccess</code>
0389 * method is called with the string
0390 * <code>"insertProvider."+provider.getName()</code>
0391 * to see if it's ok to add a new provider.
0392 * If the default implementation of <code>checkSecurityAccess</code>
0393 * is used (i.e., that method is not overriden), then this will result in
0394 * a call to the security manager's <code>checkPermission</code> method
0395 * with a
0396 * <code>SecurityPermission("insertProvider."+provider.getName())</code>
0397 * permission.
0398 *
0399 * @param provider the provider to be added.
0400 *
0401 * @return the preference position in which the provider was
0402 * added, or -1 if the provider was not added because it is
0403 * already installed.
0404 *
0405 * @throws NullPointerException if provider is null
0406 * @throws SecurityException
0407 * if a security manager exists and its <code>{@link
0408 * java.lang.SecurityManager#checkSecurityAccess}</code> method
0409 * denies access to add a new provider
0410 *
0411 * @see #getProvider
0412 * @see #removeProvider
0413 * @see java.security.SecurityPermission
0414 */
0415 public static int addProvider(Provider provider) {
0416 /*
0417 * We can't assign a position here because the statically
0418 * registered providers may not have been installed yet.
0419 * insertProviderAt() will fix that value after it has
0420 * loaded the static providers.
0421 */
0422 return insertProviderAt(provider, 0);
0423 }
0424
0425 /**
0426 * Removes the provider with the specified name.
0427 *
0428 * <p>When the specified provider is removed, all providers located
0429 * at a position greater than where the specified provider was are shifted
0430 * down one position (towards the head of the list of installed
0431 * providers).
0432 *
0433 * <p>This method returns silently if the provider is not installed or
0434 * if name is null.
0435 *
0436 * <p>First, if there is a security manager, its
0437 * <code>checkSecurityAccess</code>
0438 * method is called with the string <code>"removeProvider."+name</code>
0439 * to see if it's ok to remove the provider.
0440 * If the default implementation of <code>checkSecurityAccess</code>
0441 * is used (i.e., that method is not overriden), then this will result in
0442 * a call to the security manager's <code>checkPermission</code> method
0443 * with a <code>SecurityPermission("removeProvider."+name)</code>
0444 * permission.
0445 *
0446 * @param name the name of the provider to remove.
0447 *
0448 * @throws SecurityException
0449 * if a security manager exists and its <code>{@link
0450 * java.lang.SecurityManager#checkSecurityAccess}</code> method
0451 * denies
0452 * access to remove the provider
0453 *
0454 * @see #getProvider
0455 * @see #addProvider
0456 */
0457 public static synchronized void removeProvider(String name) {
0458 check("removeProvider." + name);
0459 ProviderList list = Providers.getFullProviderList();
0460 ProviderList newList = ProviderList.remove(list, name);
0461 Providers.setProviderList(newList);
0462 }
0463
0464 /**
0465 * Returns an array containing all the installed providers. The order of
0466 * the providers in the array is their preference order.
0467 *
0468 * @return an array of all the installed providers.
0469 */
0470 public static Provider[] getProviders() {
0471 return Providers.getFullProviderList().toArray();
0472 }
0473
0474 /**
0475 * Returns the provider installed with the specified name, if
0476 * any. Returns null if no provider with the specified name is
0477 * installed or if name is null.
0478 *
0479 * @param name the name of the provider to get.
0480 *
0481 * @return the provider of the specified name.
0482 *
0483 * @see #removeProvider
0484 * @see #addProvider
0485 */
0486 public static Provider getProvider(String name) {
0487 return Providers.getProviderList().getProvider(name);
0488 }
0489
0490 /**
0491 * Returns an array containing all installed providers that satisfy the
0492 * specified selection criterion, or null if no such providers have been
0493 * installed. The returned providers are ordered
0494 * according to their <a href=
0495 * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
0496 *
0497 * <p> A cryptographic service is always associated with a particular
0498 * algorithm or type. For example, a digital signature service is
0499 * always associated with a particular algorithm (e.g., DSA),
0500 * and a CertificateFactory service is always associated with
0501 * a particular certificate type (e.g., X.509).
0502 *
0503 * <p>The selection criterion must be specified in one of the following two
0504 * formats:
0505 * <ul>
0506 * <li> <i><crypto_service>.<algorithm_or_type></i> <p> The
0507 * cryptographic service name must not contain any dots.
0508 * <p> A
0509 * provider satisfies the specified selection criterion iff the provider
0510 * implements the
0511 * specified algorithm or type for the specified cryptographic service.
0512 * <p> For example, "CertificateFactory.X.509"
0513 * would be satisfied by any provider that supplied
0514 * a CertificateFactory implementation for X.509 certificates.
0515 * <li> <i><crypto_service>.<algorithm_or_type>
0516 * <attribute_name>:< attribute_value></i>
0517 * <p> The cryptographic service name must not contain any dots. There
0518 * must be one or more space charaters between the the
0519 * <i><algorithm_or_type></i> and the <i><attribute_name></i>.
0520 * <p> A provider satisfies this selection criterion iff the
0521 * provider implements the specified algorithm or type for the specified
0522 * cryptographic service and its implementation meets the
0523 * constraint expressed by the specified attribute name/value pair.
0524 * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
0525 * satisfied by any provider that implemented
0526 * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
0527 *
0528 * </ul>
0529 *
0530 * <p> See Appendix A in the <a href=
0531 * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
0532 * Java Cryptography Architecture API Specification & Reference </a>
0533 * for information about standard cryptographic service names, standard
0534 * algorithm names and standard attribute names.
0535 *
0536 * @param filter the criterion for selecting
0537 * providers. The filter is case-insensitive.
0538 *
0539 * @return all the installed providers that satisfy the selection
0540 * criterion, or null if no such providers have been installed.
0541 *
0542 * @throws InvalidParameterException
0543 * if the filter is not in the required format
0544 * @throws NullPointerException if filter is null
0545 *
0546 * @see #getProviders(java.util.Map)
0547 * @since 1.3
0548 */
0549 public static Provider[] getProviders(String filter) {
0550 String key = null;
0551 String value = null;
0552 int index = filter.indexOf(':');
0553
0554 if (index == -1) {
0555 key = filter;
0556 value = "";
0557 } else {
0558 key = filter.substring(0, index);
0559 value = filter.substring(index + 1);
0560 }
0561
0562 Hashtable<String, String> hashtableFilter = new Hashtable<String, String>(
0563 1);
0564 hashtableFilter.put(key, value);
0565
0566 return (getProviders(hashtableFilter));
0567 }
0568
0569 /**
0570 * Returns an array containing all installed providers that satisfy the
0571 * specified* selection criteria, or null if no such providers have been
0572 * installed. The returned providers are ordered
0573 * according to their <a href=
0574 * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
0575 *
0576 * <p>The selection criteria are represented by a map.
0577 * Each map entry represents a selection criterion.
0578 * A provider is selected iff it satisfies all selection
0579 * criteria. The key for any entry in such a map must be in one of the
0580 * following two formats:
0581 * <ul>
0582 * <li> <i><crypto_service>.<algorithm_or_type></i>
0583 * <p> The cryptographic service name must not contain any dots.
0584 * <p> The value associated with the key must be an empty string.
0585 * <p> A provider
0586 * satisfies this selection criterion iff the provider implements the
0587 * specified algorithm or type for the specified cryptographic service.
0588 * <li> <i><crypto_service>.<algorithm_or_type> <attribute_name></i>
0589 * <p> The cryptographic service name must not contain any dots. There
0590 * must be one or more space charaters between the <i><algorithm_or_type></i>
0591 * and the <i><attribute_name></i>.
0592 * <p> The value associated with the key must be a non-empty string.
0593 * A provider satisfies this selection criterion iff the
0594 * provider implements the specified algorithm or type for the specified
0595 * cryptographic service and its implementation meets the
0596 * constraint expressed by the specified attribute name/value pair.
0597 * </ul>
0598 *
0599 * <p> See Appendix A in the <a href=
0600 * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
0601 * Java Cryptography Architecture API Specification & Reference </a>
0602 * for information about standard cryptographic service names, standard
0603 * algorithm names and standard attribute names.
0604 *
0605 * @param filter the criteria for selecting
0606 * providers. The filter is case-insensitive.
0607 *
0608 * @return all the installed providers that satisfy the selection
0609 * criteria, or null if no such providers have been installed.
0610 *
0611 * @throws InvalidParameterException
0612 * if the filter is not in the required format
0613 * @throws NullPointerException if filter is null
0614 *
0615 * @see #getProviders(java.lang.String)
0616 * @since 1.3
0617 */
0618 public static Provider[] getProviders(Map<String, String> filter) {
0619 // Get all installed providers first.
0620 // Then only return those providers who satisfy the selection criteria.
0621 Provider[] allProviders = Security.getProviders();
0622 Set<String> keySet = filter.keySet();
0623 LinkedHashSet<Provider> candidates = new LinkedHashSet<Provider>(
0624 5);
0625
0626 // Returns all installed providers
0627 // if the selection criteria is null.
0628 if ((keySet == null) || (allProviders == null)) {
0629 return allProviders;
0630 }
0631
0632 boolean firstSearch = true;
0633
0634 // For each selection criterion, remove providers
0635 // which don't satisfy the criterion from the candidate set.
0636 for (Iterator<String> ite = keySet.iterator(); ite.hasNext();) {
0637 String key = ite.next();
0638 String value = filter.get(key);
0639
0640 LinkedHashSet<Provider> newCandidates = getAllQualifyingCandidates(
0641 key, value, allProviders);
0642 if (firstSearch) {
0643 candidates = newCandidates;
0644 firstSearch = false;
0645 }
0646
0647 if ((newCandidates != null) && !newCandidates.isEmpty()) {
0648 // For each provider in the candidates set, if it
0649 // isn't in the newCandidate set, we should remove
0650 // it from the candidate set.
0651 for (Iterator<Provider> cansIte = candidates.iterator(); cansIte
0652 .hasNext();) {
0653 Provider prov = cansIte.next();
0654 if (!newCandidates.contains(prov)) {
0655 cansIte.remove();
0656 }
0657 }
0658 } else {
0659 candidates = null;
0660 break;
0661 }
0662 }
0663
0664 if ((candidates == null) || (candidates.isEmpty()))
0665 return null;
0666
0667 Object[] candidatesArray = candidates.toArray();
0668 Provider[] result = new Provider[candidatesArray.length];
0669
0670 for (int i = 0; i < result.length; i++) {
0671 result[i] = (Provider) candidatesArray[i];
0672 }
0673
0674 return result;
0675 }
0676
0677 // Map containing cached Spi Class objects of the specified type
0678 private static final Map<String, Class> spiMap = new ConcurrentHashMap<String, Class>();
0679
0680 /**
0681 * Return the Class object for the given engine type
0682 * (e.g. "MessageDigest"). Works for Spis in the java.security package
0683 * only.
0684 */
0685 private static Class getSpiClass(String type) {
0686 Class clazz = spiMap.get(type);
0687 if (clazz != null) {
0688 return clazz;
0689 }
0690 try {
0691 clazz = Class.forName("java.security." + type + "Spi");
0692 spiMap.put(type, clazz);
0693 return clazz;
0694 } catch (ClassNotFoundException e) {
0695 throw (Error) new AssertionError("Spi class not found")
0696 .initCause(e);
0697 }
0698 }
0699
0700 /*
0701 * Returns an array of objects: the first object in the array is
0702 * an instance of an implementation of the requested algorithm
0703 * and type, and the second object in the array identifies the provider
0704 * of that implementation.
0705 * The <code>provider</code> argument can be null, in which case all
0706 * configured providers will be searched in order of preference.
0707 */
0708 static Object[] getImpl(String algorithm, String type,
0709 String provider) throws NoSuchAlgorithmException,
0710 NoSuchProviderException {
0711 if (provider == null) {
0712 return GetInstance.getInstance(type, getSpiClass(type),
0713 algorithm).toArray();
0714 } else {
0715 return GetInstance.getInstance(type, getSpiClass(type),
0716 algorithm, provider).toArray();
0717 }
0718 }
0719
0720 static Object[] getImpl(String algorithm, String type,
0721 String provider, Object params)
0722 throws NoSuchAlgorithmException, NoSuchProviderException,
0723 InvalidAlgorithmParameterException {
0724 if (provider == null) {
0725 return GetInstance.getInstance(type, getSpiClass(type),
0726 algorithm, params).toArray();
0727 } else {
0728 return GetInstance.getInstance(type, getSpiClass(type),
0729 algorithm, params, provider).toArray();
0730 }
0731 }
0732
0733 /*
0734 * Returns an array of objects: the first object in the array is
0735 * an instance of an implementation of the requested algorithm
0736 * and type, and the second object in the array identifies the provider
0737 * of that implementation.
0738 * The <code>provider</code> argument cannot be null.
0739 */
0740 static Object[] getImpl(String algorithm, String type,
0741 Provider provider) throws NoSuchAlgorithmException {
0742 return GetInstance.getInstance(type, getSpiClass(type),
0743 algorithm, provider).toArray();
0744 }
0745
0746 static Object[] getImpl(String algorithm, String type,
0747 Provider provider, Object params)
0748 throws NoSuchAlgorithmException,
0749 InvalidAlgorithmParameterException {
0750 return GetInstance.getInstance(type, getSpiClass(type),
0751 algorithm, params, provider).toArray();
0752 }
0753
0754 /**
0755 * Gets a security property value.
0756 *
0757 * <p>First, if there is a security manager, its
0758 * <code>checkPermission</code> method is called with a
0759 * <code>java.security.SecurityPermission("getProperty."+key)</code>
0760 * permission to see if it's ok to retrieve the specified
0761 * security property value..
0762 *
0763 * @param key the key of the property being retrieved.
0764 *
0765 * @return the value of the security property corresponding to key.
0766 *
0767 * @throws SecurityException
0768 * if a security manager exists and its <code>{@link
0769 * java.lang.SecurityManager#checkPermission}</code> method
0770 * denies
0771 * access to retrieve the specified security property value
0772 * @throws NullPointerException is key is null
0773 *
0774 * @see #setProperty
0775 * @see java.security.SecurityPermission
0776 */
0777 public static String getProperty(String key) {
0778 SecurityManager sm = System.getSecurityManager();
0779 if (sm != null) {
0780 sm.checkPermission(new SecurityPermission("getProperty."
0781 + key));
0782 }
0783 String name = props.getProperty(key);
0784 if (name != null)
0785 name = name.trim(); // could be a class name with trailing ws
0786 return name;
0787 }
0788
0789 /**
0790 * Sets a security property value.
0791 *
0792 * <p>First, if there is a security manager, its
0793 * <code>checkPermission</code> method is called with a
0794 * <code>java.security.SecurityPermission("setProperty."+key)</code>
0795 * permission to see if it's ok to set the specified
0796 * security property value.
0797 *
0798 * @param key the name of the property to be set.
0799 *
0800 * @param datum the value of the property to be set.
0801 *
0802 * @throws SecurityException
0803 * if a security manager exists and its <code>{@link
0804 * java.lang.SecurityManager#checkPermission}</code> method
0805 * denies access to set the specified security property value
0806 * @throws NullPointerException if key or datum is null
0807 *
0808 * @see #getProperty
0809 * @see java.security.SecurityPermission
0810 */
0811 public static void setProperty(String key, String datum) {
0812 check("setProperty." + key);
0813 props.put(key, datum);
0814 invalidateSMCache(key); /* See below. */
0815 }
0816
0817 /*
0818 * Implementation detail: If the property we just set in
0819 * setProperty() was either "package.access" or
0820 * "package.definition", we need to signal to the SecurityManager
0821 * class that the value has just changed, and that it should
0822 * invalidate it's local cache values.
0823 *
0824 * Rather than create a new API entry for this function,
0825 * we use reflection to set a private variable.
0826 */
0827 private static void invalidateSMCache(String key) {
0828
0829 final boolean pa = key.equals("package.access");
0830 final boolean pd = key.equals("package.definition");
0831
0832 if (pa || pd) {
0833 AccessController.doPrivileged(new PrivilegedAction<Void>() {
0834 public Void run() {
0835 try {
0836 /* Get the class via the bootstrap class loader. */
0837 Class cl = Class.forName(
0838 "java.lang.SecurityManager", false,
0839 null);
0840 Field f = null;
0841 boolean accessible = false;
0842
0843 if (pa) {
0844 f = cl
0845 .getDeclaredField("packageAccessValid");
0846 accessible = f.isAccessible();
0847 f.setAccessible(true);
0848 } else {
0849 f = cl
0850 .getDeclaredField("packageDefinitionValid");
0851 accessible = f.isAccessible();
0852 f.setAccessible(true);
0853 }
0854 f.setBoolean(f, false);
0855 f.setAccessible(accessible);
0856 } catch (Exception e1) {
0857 /* If we couldn't get the class, it hasn't
0858 * been loaded yet. If there is no such
0859 * field, we shouldn't try to set it. There
0860 * shouldn't be a security execption, as we
0861 * are loaded by boot class loader, and we
0862 * are inside a doPrivileged() here.
0863 *
0864 * NOOP: don't do anything...
0865 */
0866 }
0867 return null;
0868 } /* run */
0869 }); /* PrivilegedAction */
0870 } /* if */
0871 }
0872
0873 private static void check(String directive) {
0874 SecurityManager security = System.getSecurityManager();
0875 if (security != null) {
0876 security.checkSecurityAccess(directive);
0877 }
0878 }
0879
0880 /*
0881 * Returns all providers who satisfy the specified
0882 * criterion.
0883 */
0884 private static LinkedHashSet<Provider> getAllQualifyingCandidates(
0885 String filterKey, String filterValue,
0886 Provider[] allProviders) {
0887 String[] filterComponents = getFilterComponents(filterKey,
0888 filterValue);
0889
0890 // The first component is the service name.
0891 // The second is the algorithm name.
0892 // If the third isn't null, that is the attrinute name.
0893 String serviceName = filterComponents[0];
0894 String algName = filterComponents[1];
0895 String attrName = filterComponents[2];
0896
0897 return getProvidersNotUsingCache(serviceName, algName,
0898 attrName, filterValue, allProviders);
0899 }
0900
0901 private static LinkedHashSet<Provider> getProvidersNotUsingCache(
0902 String serviceName, String algName, String attrName,
0903 String filterValue, Provider[] allProviders) {
0904 LinkedHashSet<Provider> candidates = new LinkedHashSet<Provider>(
0905 5);
0906 for (int i = 0; i < allProviders.length; i++) {
0907 if (isCriterionSatisfied(allProviders[i], serviceName,
0908 algName, attrName, filterValue)) {
0909 candidates.add(allProviders[i]);
0910 }
0911 }
0912 return candidates;
0913 }
0914
0915 /*
0916 * Returns true if the given provider satisfies
0917 * the selection criterion key:value.
0918 */
0919 private static boolean isCriterionSatisfied(Provider prov,
0920 String serviceName, String algName, String attrName,
0921 String filterValue) {
0922 String key = serviceName + '.' + algName;
0923
0924 if (attrName != null) {
0925 key += ' ' + attrName;
0926 }
0927 // Check whether the provider has a property
0928 // whose key is the same as the given key.
0929 String propValue = getProviderProperty(key, prov);
0930
0931 if (propValue == null) {
0932 // Check whether we have an alias instead
0933 // of a standard name in the key.
0934 String standardName = getProviderProperty("Alg.Alias."
0935 + serviceName + "." + algName, prov);
0936 if (standardName != null) {
0937 key = serviceName + "." + standardName;
0938
0939 if (attrName != null) {
0940 key += ' ' + attrName;
0941 }
0942
0943 propValue = getProviderProperty(key, prov);
0944 }
0945
0946 if (propValue == null) {
0947 // The provider doesn't have the given
0948 // key in its property list.
0949 return false;
0950 }
0951 }
0952
0953 // If the key is in the format of:
0954 // <crypto_service>.<algorithm_or_type>,
0955 // there is no need to check the value.
0956
0957 if (attrName == null) {
0958 return true;
0959 }
0960
0961 // If we get here, the key must be in the
0962 // format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
0963 if (isStandardAttr(attrName)) {
0964 return isConstraintSatisfied(attrName, filterValue,
0965 propValue);
0966 } else {
0967 return filterValue.equalsIgnoreCase(propValue);
0968 }
0969 }
0970
0971 /*
0972 * Returns true if the attribute is a standard attribute;
0973 * otherwise, returns false.
0974 */
0975 private static boolean isStandardAttr(String attribute) {
0976 // For now, we just have two standard attributes:
0977 // KeySize and ImplementedIn.
0978 if (attribute.equalsIgnoreCase("KeySize"))
0979 return true;
0980
0981 if (attribute.equalsIgnoreCase("ImplementedIn"))
0982 return true;
0983
0984 return false;
0985 }
0986
0987 /*
0988 * Returns true if the requested attribute value is supported;
0989 * otherwise, returns false.
0990 */
0991 private static boolean isConstraintSatisfied(String attribute,
0992 String value, String prop) {
0993 // For KeySize, prop is the max key size the
0994 // provider supports for a specific <crypto_service>.<algorithm>.
0995 if (attribute.equalsIgnoreCase("KeySize")) {
0996 int requestedSize = Integer.parseInt(value);
0997 int maxSize = Integer.parseInt(prop);
0998 if (requestedSize <= maxSize) {
0999 return true;
1000 } else {
1001 return false;
1002 }
1003 }
1004
1005 // For Type, prop is the type of the implementation
1006 // for a specific <crypto service>.<algorithm>.
1007 if (attribute.equalsIgnoreCase("ImplementedIn")) {
1008 return value.equalsIgnoreCase(prop);
1009 }
1010
1011 return false;
1012 }
1013
1014 static String[] getFilterComponents(String filterKey,
1015 String filterValue) {
1016 int algIndex = filterKey.indexOf('.');
1017
1018 if (algIndex < 0) {
1019 // There must be a dot in the filter, and the dot
1020 // shouldn't be at the beginning of this string.
1021 throw new InvalidParameterException("Invalid filter");
1022 }
1023
1024 String serviceName = filterKey.substring(0, algIndex);
1025 String algName = null;
1026 String attrName = null;
1027
1028 if (filterValue.length() == 0) {
1029 // The filterValue is an empty string. So the filterKey
1030 // should be in the format of <crypto_service>.<algorithm_or_type>.
1031 algName = filterKey.substring(algIndex + 1).trim();
1032 if (algName.length() == 0) {
1033 // There must be a algorithm or type name.
1034 throw new InvalidParameterException("Invalid filter");
1035 }
1036 } else {
1037 // The filterValue is a non-empty string. So the filterKey must be
1038 // in the format of
1039 // <crypto_service>.<algorithm_or_type> <attribute_name>
1040 int attrIndex = filterKey.indexOf(' ');
1041
1042 if (attrIndex == -1) {
1043 // There is no attribute name in the filter.
1044 throw new InvalidParameterException("Invalid filter");
1045 } else {
1046 attrName = filterKey.substring(attrIndex + 1).trim();
1047 if (attrName.length() == 0) {
1048 // There is no attribute name in the filter.
1049 throw new InvalidParameterException(
1050 "Invalid filter");
1051 }
1052 }
1053
1054 // There must be an algorithm name in the filter.
1055 if ((attrIndex < algIndex) || (algIndex == attrIndex - 1)) {
1056 throw new InvalidParameterException("Invalid filter");
1057 } else {
1058 algName = filterKey.substring(algIndex + 1, attrIndex);
1059 }
1060 }
1061
1062 String[] result = new String[3];
1063 result[0] = serviceName;
1064 result[1] = algName;
1065 result[2] = attrName;
1066
1067 return result;
1068 }
1069
1070 /**
1071 * Returns a Set of Strings containing the names of all available
1072 * algorithms or types for the specified Java cryptographic service
1073 * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns
1074 * an empty Set if there is no provider that supports the
1075 * specified service or if serviceName is null. For a complete list
1076 * of Java cryptographic services, please see the
1077 * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">Java
1078 * Cryptography Architecture API Specification & Reference</a>.
1079 * Note: the returned set is immutable.
1080 *
1081 * @param serviceName the name of the Java cryptographic
1082 * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
1083 * Note: this parameter is case-insensitive.
1084 *
1085 * @return a Set of Strings containing the names of all available
1086 * algorithms or types for the specified Java cryptographic service
1087 * or an empty set if no provider supports the specified service.
1088 *
1089 * @since 1.4
1090 **/
1091 public static Set<String> getAlgorithms(String serviceName) {
1092
1093 if ((serviceName == null) || (serviceName.length() == 0)
1094 || (serviceName.endsWith("."))) {
1095 return Collections.EMPTY_SET;
1096 }
1097
1098 HashSet<String> result = new HashSet<String>();
1099 Provider[] providers = Security.getProviders();
1100
1101 for (int i = 0; i < providers.length; i++) {
1102 // Check the keys for each provider.
1103 for (Enumeration<Object> e = providers[i].keys(); e
1104 .hasMoreElements();) {
1105 String currentKey = ((String) e.nextElement())
1106 .toUpperCase();
1107 if (currentKey.startsWith(serviceName.toUpperCase())) {
1108 // We should skip the currentKey if it contains a
1109 // whitespace. The reason is: such an entry in the
1110 // provider property contains attributes for the
1111 // implementation of an algorithm. We are only interested
1112 // in entries which lead to the implementation
1113 // classes.
1114 if (currentKey.indexOf(" ") < 0) {
1115 result.add(currentKey.substring(serviceName
1116 .length() + 1));
1117 }
1118 }
1119 }
1120 }
1121 return Collections.unmodifiableSet(result);
1122 }
1123 }
|