1. /*
  2. * @(#)Security.java 1.119 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.security;
  8. import java.lang.reflect.*;
  9. import java.util.*;
  10. import java.io.*;
  11. import java.net.URL;
  12. import java.security.InvalidParameterException;
  13. import sun.security.util.Debug;
  14. import sun.security.util.PropertyExpander;
  15. /**
  16. * <p>This class centralizes all security properties and common security
  17. * methods. One of its primary uses is to manage providers.
  18. *
  19. * @author Benjamin Renaud
  20. * @version 1.119, 01/23/03
  21. */
  22. public final class Security {
  23. // Do providers need to be reloaded?
  24. private static boolean reloadProviders = true;
  25. /* Are we debugging? -- for developers */
  26. static final boolean debug = false;
  27. private static final Debug sdebug =
  28. Debug.getInstance("properties");
  29. /* Are we displaying errors? -- for users */
  30. static final boolean error = true;
  31. /* The java.security properties */
  32. private static Properties props;
  33. /* A vector of providers, in order of priority */
  34. private static Vector providers;
  35. // Where we cache provider properties
  36. private static Hashtable providerPropertiesCache;
  37. // Where we cache engine provider properties
  38. private static Hashtable engineCache;
  39. // Where we cache search results
  40. private static Hashtable searchResultsCache;
  41. // providers currently attempting to be loaded
  42. private static Hashtable providerLoads;
  43. // An element in the cache
  44. private static class ProviderProperty {
  45. String className;
  46. Provider provider;
  47. }
  48. // Number of statically registered security providers. No duplicates.
  49. private static int numOfStaticProviders = 0;
  50. /* A vector of statically registered providers' master class names,
  51. * in order of priority. No duplicates.
  52. */
  53. private static Vector providerMasterClassNames = new Vector(6);
  54. // Index for the vector providerMasterClassNames.
  55. // It points to the next provider which we should try to load.
  56. private static int indexStaticProviders = 0;
  57. // Does the indexStaticProviders need to be reset?
  58. private static boolean resetProviderIndex = false;
  59. static {
  60. // doPrivileged here because there are multiple
  61. // things in initialize that might require privs.
  62. // (the FileInputStream call and the File.exists call,
  63. // the securityPropFile call, etc)
  64. AccessController.doPrivileged(new PrivilegedAction() {
  65. public Object run() {
  66. initialize();
  67. return null;
  68. }
  69. });
  70. }
  71. private static void initialize() {
  72. props = new Properties();
  73. providers = new Vector();
  74. providerPropertiesCache = new Hashtable();
  75. engineCache = new Hashtable();
  76. searchResultsCache = new Hashtable(5);
  77. providerLoads = new Hashtable(1);
  78. boolean loadedProps = false;
  79. boolean overrideAll = false;
  80. // first load the system properties file
  81. // to determine the value of security.overridePropertiesFile
  82. File propFile = securityPropFile("java.security");
  83. if (propFile.exists()) {
  84. try {
  85. FileInputStream fis = new FileInputStream(propFile);
  86. InputStream is = new BufferedInputStream(fis);
  87. props.load(is);
  88. is.close();
  89. loadedProps = true;
  90. if (sdebug != null) {
  91. sdebug.println("reading security properties file: " +
  92. propFile);
  93. }
  94. } catch (IOException e) {
  95. if (sdebug != null) {
  96. sdebug.println("unable to load security properties from " +
  97. propFile);
  98. e.printStackTrace();
  99. }
  100. }
  101. }
  102. if ("true".equalsIgnoreCase(props.getProperty
  103. ("security.overridePropertiesFile"))) {
  104. String extraPropFile = System.getProperty
  105. ("java.security.properties");
  106. if (extraPropFile != null && extraPropFile.startsWith("=")) {
  107. overrideAll = true;
  108. extraPropFile = extraPropFile.substring(1);
  109. }
  110. if (overrideAll) {
  111. props = new Properties();
  112. if (sdebug != null) {
  113. sdebug.println
  114. ("overriding other security properties files!");
  115. }
  116. }
  117. // now load the user-specified file so its values
  118. // will win if they conflict with the earlier values
  119. if (extraPropFile != null) {
  120. try {
  121. URL propURL;
  122. extraPropFile = PropertyExpander.expand(extraPropFile);
  123. propFile = new File(extraPropFile);
  124. if (propFile.exists()) {
  125. propURL = new URL
  126. ("file:" + propFile.getCanonicalPath());
  127. } else {
  128. propURL = new URL(extraPropFile);
  129. }
  130. BufferedInputStream bis = new BufferedInputStream
  131. (propURL.openStream());
  132. props.load(bis);
  133. bis.close();
  134. loadedProps = true;
  135. if (sdebug != null) {
  136. sdebug.println("reading security properties file: " +
  137. propURL);
  138. if (overrideAll) {
  139. sdebug.println
  140. ("overriding other security properties files!");
  141. }
  142. }
  143. } catch (Exception e) {
  144. if (sdebug != null) {
  145. sdebug.println
  146. ("unable to load security properties from " +
  147. extraPropFile);
  148. e.printStackTrace();
  149. }
  150. }
  151. }
  152. }
  153. if (!loadedProps) {
  154. initializeStatic();
  155. if (sdebug != null) {
  156. sdebug.println("unable to load security properties " +
  157. "-- using defaults");
  158. }
  159. }
  160. // Not loading providers here. Just counts how many providers
  161. // are statically registered. This reduces the startup
  162. // footprint.
  163. countProviders();
  164. }
  165. /*
  166. * Initialize to default values, if <java.home>/lib/java.security
  167. * is not found.
  168. */
  169. private static void initializeStatic() {
  170. props.put("security.provider.1", "sun.security.provider.Sun");
  171. }
  172. /**
  173. * Don't let anyone instantiate this.
  174. */
  175. private Security() {
  176. }
  177. /**
  178. * Loops through provider declarations, which are expected to be
  179. * of the form:
  180. *
  181. * security.provider.1=sun.security.provider.Sun
  182. * security.provider.2=sun.security.jsafe.Jsafe
  183. * etc.
  184. *
  185. * The order determines the default search order when looking for
  186. * an algorithm.
  187. */
  188. private static synchronized void countProviders() {
  189. int i = 1;
  190. while (true) {
  191. String name = props.getProperty("security.provider." + i);
  192. if (name == null) {
  193. break;
  194. } else {
  195. String fullClassName = name.trim();
  196. if (fullClassName.length() == 0) {
  197. System.err.println("invalid entry for " +
  198. "security.provider." + i);
  199. break;
  200. } else {
  201. // Get rid of duplicate providers.
  202. if (!providerMasterClassNames.contains(fullClassName)) {
  203. providerMasterClassNames.add(fullClassName);
  204. }
  205. i++;
  206. }
  207. }
  208. }
  209. // Get the number of statically registered providers.
  210. numOfStaticProviders = providerMasterClassNames.size();
  211. }
  212. /*
  213. * Reload the providers (provided as extensions) that could not be loaded
  214. * (because there was no system class loader available) when this class
  215. * was initialized.
  216. */
  217. private static synchronized void reloadProviders() {
  218. if (reloadProviders) {
  219. sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
  220. if (l != null) {
  221. synchronized (Security.class) {
  222. reloadProviders = false;
  223. // We don't want loadOneMoreProvider() to do
  224. // anything from now on since this method will
  225. // load all static providers.
  226. indexStaticProviders = numOfStaticProviders;
  227. resetProviderIndex = false;
  228. providers.removeAllElements();
  229. // i is an index for the vector
  230. // providerMasterClassNames. So it starts from 0.
  231. int i = 0;
  232. while (i < numOfStaticProviders) {
  233. final String name =
  234. (String)providerMasterClassNames.elementAt(i);
  235. i++;
  236. Provider prov =
  237. (Provider)AccessController.doPrivileged(
  238. new PrivilegedAction() {
  239. public Object run() {
  240. return Provider.loadProvider(name);
  241. }
  242. });
  243. if (prov != null) {
  244. providers.addElement(prov);
  245. }
  246. }
  247. // empty provider-property cache
  248. providerPropertiesCache.clear();
  249. engineCache.clear();
  250. searchResultsCache.clear();
  251. }
  252. }
  253. }
  254. }
  255. /**
  256. * Try our best to load one more statically registered provider.
  257. * This is used by getEngineClassName(String algName, String engineType).
  258. */
  259. private static synchronized void loadOneMoreProvider() {
  260. // suspend provider reloading inside this method
  261. boolean restore = false;
  262. if (reloadProviders) {
  263. restore = true;
  264. reloadProviders = false;
  265. }
  266. try {
  267. sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
  268. /*
  269. * Even if the launcher l is null, we still want to
  270. * load providers if we can. See bug 4418903.
  271. * When we first see that the launcher isn't null, we
  272. * could be in one of the following situations:
  273. * a) some providers were loaded out of the priority order.
  274. * For example, 6 providers are statically configured, and
  275. * provider 2 and 4 are loaded. The field resetProviderIndex
  276. * should be "true". So we can try to load providers
  277. * according to the priority order when the launcher isn't null.
  278. * b) some providers were loaded, but not out of order.
  279. * For example, 6 providers are statically configured, and
  280. * provider 1 and 2 are loaded. The field resetProviderIndex
  281. * should be "false". So we just try to load the next
  282. * provider whose index is indexStaticProviders.
  283. * c) no providers were loaded. The field resetProviderIndex
  284. * should be "false". So we just try to load the first
  285. * provider. Note: indexStaticProviders is 0 in this case.
  286. */
  287. if (indexStaticProviders >= numOfStaticProviders) {
  288. return;
  289. }
  290. Provider prov = null;
  291. while (indexStaticProviders < numOfStaticProviders) {
  292. final String name = (String)providerMasterClassNames.elementAt(
  293. indexStaticProviders);
  294. // determine if the loadProvider call below is looping.
  295. // this may occur if the provider to be loaded is signed.
  296. // if looping, continue
  297. if (providerLoads.get(name) != null) {
  298. indexStaticProviders++;
  299. continue;
  300. } else {
  301. providerLoads.put(name, name);
  302. }
  303. prov = (Provider)AccessController.doPrivileged(
  304. new PrivilegedAction() {
  305. public Object run() {
  306. return Provider.loadProvider(name);
  307. }
  308. });
  309. // indexStaticProviders points to the next provider we
  310. // should try to load.
  311. indexStaticProviders++;
  312. providerLoads.remove(name);
  313. if (prov != null) {
  314. /* This must manipulate the datastructure
  315. directly, because going through addProviders
  316. causes a security check to happen, which
  317. sometimes will cause the security
  318. initialization to fail with bad
  319. consequences. */
  320. providers.addElement(prov);
  321. // empty provider-property cache
  322. providerPropertiesCache.clear();
  323. engineCache.clear();
  324. searchResultsCache.clear();
  325. break;
  326. } else {
  327. if (l == null) {
  328. // Set resetProviderIndex to true since we may load
  329. // providers out of the priority order.
  330. resetProviderIndex = true;
  331. }
  332. }
  333. }
  334. } finally {
  335. // resume provider reloading if necessary
  336. if (restore) {
  337. reloadProviders = true;
  338. }
  339. }
  340. }
  341. private static File securityPropFile(String filename) {
  342. // maybe check for a system property which will specify where to
  343. // look. Someday.
  344. String sep = File.separator;
  345. return new File(System.getProperty("java.home") + sep + "lib" + sep +
  346. "security" + sep + filename);
  347. }
  348. /**
  349. * Looks up providers, and returns the property (and its associated
  350. * provider) mapping the key, if any.
  351. * The order in which the providers are looked up is the
  352. * provider-preference order, as specificed in the security
  353. * properties file.
  354. */
  355. private static ProviderProperty getProviderProperty(String key) {
  356. ProviderProperty entry
  357. = (ProviderProperty)providerPropertiesCache.get(key);
  358. if (entry != null) {
  359. return entry;
  360. }
  361. for (int i = 0; i < providers.size(); i++) {
  362. String matchKey = null;
  363. Provider prov = (Provider)providers.elementAt(i);
  364. String prop = prov.getProperty(key);
  365. if (prop == null) {
  366. // Is there a match if we do a case-insensitive property name
  367. // comparison? Let's try ...
  368. for (Enumeration enum = prov.keys();
  369. enum.hasMoreElements() && prop==null; ) {
  370. matchKey = (String)enum.nextElement();
  371. if (key.equalsIgnoreCase(matchKey)) {
  372. prop = prov.getProperty(matchKey);
  373. break;
  374. }
  375. }
  376. }
  377. if (prop != null) {
  378. ProviderProperty newEntry = new ProviderProperty();
  379. newEntry.className = prop;
  380. newEntry.provider = prov;
  381. providerPropertiesCache.put(key, newEntry);
  382. if (matchKey != null) {
  383. // Store the property value in the cache under the exact
  384. // property name, as specified by the provider
  385. providerPropertiesCache.put(matchKey, newEntry);
  386. }
  387. return newEntry;
  388. }
  389. }
  390. return entry;
  391. }
  392. /**
  393. * Returns the property (if any) mapping the key for the given provider.
  394. */
  395. private static String getProviderProperty(String key, Provider provider) {
  396. String prop = provider.getProperty(key);
  397. if (prop == null) {
  398. // Is there a match if we do a case-insensitive property name
  399. // comparison? Let's try ...
  400. for (Enumeration enum = provider.keys();
  401. enum.hasMoreElements() && prop==null; ) {
  402. String matchKey = (String)enum.nextElement();
  403. if (key.equalsIgnoreCase(matchKey)) {
  404. prop = provider.getProperty(matchKey);
  405. break;
  406. }
  407. }
  408. }
  409. return prop;
  410. }
  411. /**
  412. * We always map names to standard names
  413. */
  414. private static String getStandardName(String alias, String engineType,
  415. Provider prov) {
  416. return getProviderProperty("Alg.Alias." + engineType + "." + alias,
  417. prov);
  418. }
  419. /**
  420. * Gets a specified property for an algorithm. The algorithm name
  421. * should be a standard name. See Appendix A in the <a href=
  422. * "../../../guide/security/CryptoSpec.html#AppA">
  423. * Java Cryptography Architecture API Specification & Reference </a>
  424. * for information about standard algorithm names.
  425. * One possible use is by specialized algorithm parsers, which may map
  426. * classes to algorithms which they understand (much like Key parsers
  427. * do).
  428. *
  429. * @param algName the algorithm name.
  430. *
  431. * @param propName the name of the property to get.
  432. *
  433. * @return the value of the specified property.
  434. *
  435. * @deprecated This method used to return the value of a proprietary
  436. * property in the master file of the "SUN" Cryptographic Service
  437. * Provider in order to determine how to parse algorithm-specific
  438. * parameters. Use the new provider-based and algorithm-independent
  439. * <code>AlgorithmParameters</code> and <code>KeyFactory</code> engine
  440. * classes (introduced in the Java 2 platform) instead.
  441. */
  442. public static String getAlgorithmProperty(String algName,
  443. String propName) {
  444. reloadProviders();
  445. ProviderProperty entry = getProviderProperty("Alg." + propName
  446. + "." + algName);
  447. if (entry != null) {
  448. return entry.className;
  449. } else {
  450. return null;
  451. }
  452. }
  453. /*
  454. * Lookup the algorithm in our list of providers. Process
  455. * each provider in priority order one at a time looking for
  456. * either the direct engine property or a matching alias.
  457. */
  458. private static ProviderProperty getEngineClassName(String algName,
  459. String engineType)
  460. throws NoSuchAlgorithmException
  461. {
  462. ProviderProperty pp;
  463. String key = engineType;
  464. if (algName != null)
  465. key += "." + algName;
  466. pp = (ProviderProperty)engineCache.get(key);
  467. if (pp != null)
  468. return pp;
  469. synchronized (Security.class) {
  470. sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
  471. /*
  472. * In case some providers have been loaded out of the
  473. * priority order when the launcher l is null, we should
  474. * clear the vector "providers" and reset the indexStaticProviders
  475. * to zero when the launcher l isn't null.
  476. *
  477. * We should only do the above if the "reloadProviders" is true
  478. * which means that the method reloadProviders() hasn't
  479. * load all statically registered providers yet.
  480. * Once the reloadProviders() method has loaded all statically
  481. * registered providers, we shouldn't clear the vector
  482. * "providers" in this getEngineClassName() method.
  483. */
  484. if ((reloadProviders == true) &&
  485. (l != null) && (resetProviderIndex == true)) {
  486. resetProviderIndex = false;
  487. indexStaticProviders = 0;
  488. providers.removeAllElements();
  489. providerPropertiesCache.clear();
  490. engineCache.clear();
  491. searchResultsCache.clear();
  492. providerLoads.clear();
  493. }
  494. // We should call loadOneMoreProvider() if no provider
  495. // has been loaded yet. Otherwise, we may not be able to
  496. // get in the following "for" loop.
  497. if (providers.size() == 0) {
  498. loadOneMoreProvider();
  499. }
  500. for (int i = 0; i < providers.size(); i++) {
  501. Provider prov = (Provider)providers.elementAt(i);
  502. try {
  503. pp = getEngineClassName(algName, prov,
  504. engineType);
  505. } catch (NoSuchAlgorithmException e) {
  506. if (i == providers.size() - 1) {
  507. // The requested algorithm may be available in
  508. // a registered provider which hasn't been loaded
  509. // yet. Let's try to load one more registered
  510. // provider. The method loadOneMoreProvider()
  511. // won't do anything if we have tried to load all
  512. // registered providers.
  513. loadOneMoreProvider();
  514. }
  515. continue;
  516. }
  517. /* Cache it */
  518. engineCache.put(key, pp);
  519. return pp;
  520. }
  521. }
  522. throw new NoSuchAlgorithmException(algName.toUpperCase() + " " +
  523. engineType + " not available");
  524. }
  525. private static ProviderProperty getEngineClassName(String algName,
  526. String provider,
  527. String engineType)
  528. throws NoSuchAlgorithmException, NoSuchProviderException
  529. {
  530. if (provider == null) {
  531. return getEngineClassName(algName, engineType);
  532. }
  533. // check if the provider is installed
  534. Provider prov = getProvider(provider);
  535. if (prov == null) {
  536. throw new NoSuchProviderException("no such provider: " +
  537. provider);
  538. }
  539. return getEngineClassName(algName, prov, engineType);
  540. }
  541. /**
  542. * The parameter provider cannot be null.
  543. */
  544. private static ProviderProperty getEngineClassName(String algName,
  545. Provider provider,
  546. String engineType)
  547. throws NoSuchAlgorithmException
  548. {
  549. String key;
  550. if (engineType.equalsIgnoreCase("SecureRandom") && algName == null)
  551. key = engineType;
  552. else
  553. key = engineType + "." + algName;
  554. String className = getProviderProperty(key, provider);
  555. if (className == null) {
  556. if (engineType.equalsIgnoreCase("SecureRandom") &&
  557. algName == null)
  558. throw new NoSuchAlgorithmException
  559. ("SecureRandom not available for provider " +
  560. provider.getName());
  561. else {
  562. // try algName as alias name
  563. String stdName = getStandardName(algName, engineType, provider);
  564. if (stdName != null) key = engineType + "." + stdName;
  565. if ((stdName == null)
  566. || (className = getProviderProperty(key, provider)) == null)
  567. throw new NoSuchAlgorithmException("no such algorithm: " +
  568. algName
  569. + " for provider " +
  570. provider.getName());
  571. }
  572. }
  573. ProviderProperty entry = new ProviderProperty();
  574. entry.className = className;
  575. entry.provider = provider;
  576. return entry;
  577. }
  578. /**
  579. * Adds a new provider, at a specified position. The position is
  580. * the preference order in which providers are searched for
  581. * requested algorithms. Note that it is not guaranteed that this
  582. * preference will be respected. The position is 1-based, that is,
  583. * 1 is most preferred, followed by 2, and so on.
  584. *
  585. * <p>If the given provider is installed at the requested position,
  586. * the provider that used to be at that position, and all providers
  587. * with a position greater than <code>position</code>, are shifted up
  588. * one position (towards the end of the list of installed providers).
  589. *
  590. * <p>A provider cannot be added if it is already installed.
  591. *
  592. * <p>First, if there is a security manager, its
  593. * <code>checkSecurityAccess</code>
  594. * method is called with the string
  595. * <code>"insertProvider."+provider.getName()</code>
  596. * to see if it's ok to add a new provider.
  597. * If the default implementation of <code>checkSecurityAccess</code>
  598. * is used (i.e., that method is not overriden), then this will result in
  599. * a call to the security manager's <code>checkPermission</code> method
  600. * with a
  601. * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  602. * permission.
  603. *
  604. * @param provider the provider to be added.
  605. *
  606. * @param position the preference position that the caller would
  607. * like for this provider.
  608. *
  609. * @return the actual preference position in which the provider was
  610. * added, or -1 if the provider was not added because it is
  611. * already installed.
  612. *
  613. * @throws SecurityException
  614. * if a security manager exists and its <code>{@link
  615. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  616. * denies access to add a new provider
  617. *
  618. * @see #getProvider
  619. * @see #removeProvider
  620. * @see java.security.SecurityPermission
  621. */
  622. public static synchronized int insertProviderAt(Provider provider,
  623. int position) {
  624. reloadProviders();
  625. check("insertProvider."+provider.getName());
  626. /* First check if the provider is already installed */
  627. Provider already = getProvider(provider.getName());
  628. if (already != null) {
  629. return -1;
  630. }
  631. int size = providers.size();
  632. if (position > size || position <= 0) {
  633. position = size+1;
  634. }
  635. providers.insertElementAt(provider, position-1);
  636. // empty provider-property cache
  637. providerPropertiesCache.clear();
  638. engineCache.clear();
  639. searchResultsCache.clear();
  640. return position;
  641. }
  642. /**
  643. * Adds a provider to the next position available.
  644. *
  645. * <p>First, if there is a security manager, its
  646. * <code>checkSecurityAccess</code>
  647. * method is called with the string
  648. * <code>"insertProvider."+provider.getName()</code>
  649. * to see if it's ok to add a new provider.
  650. * If the default implementation of <code>checkSecurityAccess</code>
  651. * is used (i.e., that method is not overriden), then this will result in
  652. * a call to the security manager's <code>checkPermission</code> method
  653. * with a
  654. * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  655. * permission.
  656. *
  657. * @param provider the provider to be added.
  658. *
  659. * @return the preference position in which the provider was
  660. * added, or -1 if the provider was not added because it is
  661. * already installed.
  662. *
  663. * @throws SecurityException
  664. * if a security manager exists and its <code>{@link
  665. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  666. * denies access to add a new provider
  667. *
  668. * @see #getProvider
  669. * @see #removeProvider
  670. * @see java.security.SecurityPermission
  671. */
  672. public static int addProvider(Provider provider) {
  673. /*
  674. * We can't assign a position here because the statically
  675. * registered providers may not have been installed yet.
  676. * insertProviderAt() will fix that value after it has
  677. * loaded the static providers.
  678. */
  679. return insertProviderAt(provider, 0);
  680. }
  681. /**
  682. * Removes the provider with the specified name.
  683. *
  684. * <p>When the specified provider is removed, all providers located
  685. * at a position greater than where the specified provider was are shifted
  686. * down one position (towards the head of the list of installed
  687. * providers).
  688. *
  689. * <p>This method returns silently if the provider is not installed.
  690. *
  691. * <p>First, if there is a security manager, its
  692. * <code>checkSecurityAccess</code>
  693. * method is called with the string <code>"removeProvider."+name</code>
  694. * to see if it's ok to remove the provider.
  695. * If the default implementation of <code>checkSecurityAccess</code>
  696. * is used (i.e., that method is not overriden), then this will result in
  697. * a call to the security manager's <code>checkPermission</code> method
  698. * with a <code>SecurityPermission("removeProvider."+name)</code>
  699. * permission.
  700. *
  701. * @param name the name of the provider to remove.
  702. *
  703. * @throws SecurityException
  704. * if a security manager exists and its <code>{@link
  705. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  706. * denies
  707. * access to remove the provider
  708. *
  709. * @see #getProvider
  710. * @see #addProvider
  711. */
  712. public static synchronized void removeProvider(String name) {
  713. reloadProviders();
  714. check("removeProvider."+name);
  715. Provider provider = getProvider(name);
  716. if (provider != null) {
  717. for (Iterator i=providers.iterator(); i.hasNext(); )
  718. if (i.next()==provider)
  719. i.remove();
  720. // empty provider-property cache
  721. providerPropertiesCache.clear();
  722. engineCache.clear();
  723. searchResultsCache.clear();
  724. }
  725. }
  726. /**
  727. * Returns an array containing all the installed providers. The order of
  728. * the providers in the array is their preference order.
  729. *
  730. * @return an array of all the installed providers.
  731. */
  732. public static synchronized Provider[] getProviders() {
  733. reloadProviders();
  734. Provider[] result = new Provider[providers.size()];
  735. providers.copyInto(result);
  736. return result;
  737. }
  738. /**
  739. * Returns the provider installed with the specified name, if
  740. * any. Returns null if no provider with the specified name is
  741. * installed.
  742. *
  743. * @param name the name of the provider to get.
  744. *
  745. * @return the provider of the specified name.
  746. *
  747. * @see #removeProvider
  748. * @see #addProvider
  749. */
  750. public static synchronized Provider getProvider(String name) {
  751. reloadProviders();
  752. Enumeration enum = providers.elements();
  753. while (enum.hasMoreElements()) {
  754. Provider prov = (Provider)enum.nextElement();
  755. if (prov.getName().equals(name)) {
  756. return prov;
  757. }
  758. }
  759. return null;
  760. }
  761. /**
  762. * Returns an array containing all installed providers that satisfy the
  763. * specified selection criterion, or null if no such providers have been
  764. * installed. The returned providers are ordered
  765. * according to their <a href=
  766. * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
  767. *
  768. * <p> A cryptographic service is always associated with a particular
  769. * algorithm or type. For example, a digital signature service is
  770. * always associated with a particular algorithm (e.g., DSA),
  771. * and a CertificateFactory service is always associated with
  772. * a particular certificate type (e.g., X.509).
  773. *
  774. * <p>The selection criterion must be specified in one of the following two formats:
  775. * <ul>
  776. * <li> <i><crypto_service>.<algorithm_or_type></i> <p> The
  777. * cryptographic service name must not contain any dots.
  778. * <p> A
  779. * provider satisfies the specified selection criterion iff the provider implements the
  780. * specified algorithm or type for the specified cryptographic service.
  781. * <p> For example, "CertificateFactory.X.509"
  782. * would be satisfied by any provider that supplied
  783. * a CertificateFactory implementation for X.509 certificates.
  784. * <li> <i><crypto_service>.<algorithm_or_type> <attribute_name>:< attribute_value></i>
  785. * <p> The cryptographic service name must not contain any dots. There
  786. * must be one or more space charaters between the the <i><algorithm_or_type></i>
  787. * and the <i><attribute_name></i>.
  788. * <p> A provider satisfies this selection criterion iff the
  789. * provider implements the specified algorithm or type for the specified
  790. * cryptographic service and its implementation meets the
  791. * constraint expressed by the specified attribute name/value pair.
  792. * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
  793. * satisfied by any provider that implemented
  794. * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
  795. *
  796. * </ul>
  797. *
  798. * <p> See Appendix A in the <a href=
  799. * "../../../guide/security/CryptoSpec.html#AppA">
  800. * Java Cryptogaphy Architecture API Specification & Reference </a>
  801. * for information about standard cryptographic service names, standard
  802. * algorithm names and standard attribute names.
  803. *
  804. * @param filter the criterion for selecting
  805. * providers. The filter is case-insensitive.
  806. *
  807. * @return all the installed providers that satisfy the selection
  808. * criterion, or null if no such providers have been installed.
  809. *
  810. * @throws InvalidParameterException
  811. * if the filter is not in the required format
  812. *
  813. * @see #getProviders(java.util.Map)
  814. */
  815. public static Provider[] getProviders(String filter) {
  816. String key = null;
  817. String value = null;
  818. int index = filter.indexOf(':');
  819. if (index == -1) {
  820. key = new String(filter);
  821. value = "";
  822. } else {
  823. key = filter.substring(0, index);
  824. value = filter.substring(index + 1);
  825. }
  826. Hashtable hashtableFilter = new Hashtable(1);
  827. hashtableFilter.put(key, value);
  828. return (getProviders(hashtableFilter));
  829. }
  830. /**
  831. * Returns an array containing all installed providers that satisfy the specified
  832. * selection criteria, or null if no such providers have been installed.
  833. * The returned providers are ordered
  834. * according to their <a href=
  835. * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
  836. *
  837. * <p>The selection criteria are represented by a map.
  838. * Each map entry represents a selection criterion.
  839. * A provider is selected iff it satisfies all selection
  840. * criteria. The key for any entry in such a map must be in one of the
  841. * following two formats:
  842. * <ul>
  843. * <li> <i><crypto_service>.<algorithm_or_type></i>
  844. * <p> The cryptographic service name must not contain any dots.
  845. * <p> The value associated with the key must be an empty string.
  846. * <p> A provider
  847. * satisfies this selection criterion iff the provider implements the
  848. * specified algorithm or type for the specified cryptographic service.
  849. * <li> <i><crypto_service>.<algorithm_or_type> <attribute_name></i>
  850. * <p> The cryptographic service name must not contain any dots. There
  851. * must be one or more space charaters between the <i><algorithm_or_type></i>
  852. * and the <i><attribute_name></i>.
  853. * <p> The value associated with the key must be a non-empty string.
  854. * A provider satisfies this selection criterion iff the
  855. * provider implements the specified algorithm or type for the specified
  856. * cryptographic service and its implementation meets the
  857. * constraint expressed by the specified attribute name/value pair.
  858. * </ul>
  859. *
  860. * <p> See Appendix A in the <a href=
  861. * "../../../guide/security/CryptoSpec.html#AppA">
  862. * Java Cryptogaphy Architecture API Specification & Reference </a>
  863. * for information about standard cryptographic service names, standard
  864. * algorithm names and standard attribute names.
  865. *
  866. * @param filter the criteria for selecting
  867. * providers. The filter is case-insensitive.
  868. *
  869. * @return all the installed providers that satisfy the selection
  870. * criteria, or null if no such providers have been installed.
  871. *
  872. * @throws InvalidParameterException
  873. * if the filter is not in the required format
  874. *
  875. * @see #getProviders(java.lang.String)
  876. */
  877. public static Provider[] getProviders(Map filter) {
  878. // Get all installed providers first.
  879. // Then only return those providers who satisfy the selection criteria.
  880. Provider[] allProviders = Security.getProviders();
  881. Set keySet = filter.keySet();
  882. LinkedHashSet candidates = new LinkedHashSet(5);
  883. // Returns all installed providers
  884. // if the selection criteria is null.
  885. if ((keySet == null) || (allProviders == null)) {
  886. return allProviders;
  887. }
  888. boolean firstSearch = true;
  889. // For each selection criterion, remove providers
  890. // which don't satisfy the criterion from the candidate set.
  891. for (Iterator ite = keySet.iterator(); ite.hasNext(); ) {
  892. String key = (String)ite.next();
  893. String value = (String)filter.get(key);
  894. LinkedHashSet newCandidates = getAllQualifyingCandidates(key, value,
  895. allProviders);
  896. if (firstSearch) {
  897. candidates = newCandidates;
  898. firstSearch = false;
  899. }
  900. if ((newCandidates != null) && !newCandidates.isEmpty()) {
  901. // For each provider in the candidates set, if it
  902. // isn't in the newCandidate set, we should remove
  903. // it from the candidate set.
  904. for (Iterator cansIte = candidates.iterator();
  905. cansIte.hasNext(); ) {
  906. Provider prov = (Provider)cansIte.next();
  907. if (!newCandidates.contains(prov)) {
  908. cansIte.remove();
  909. }
  910. }
  911. } else {
  912. candidates = null;
  913. break;
  914. }
  915. }
  916. if ((candidates == null) || (candidates.isEmpty()))
  917. return null;
  918. Object[] candidatesArray = candidates.toArray();
  919. Provider[] result = new Provider[candidatesArray.length];
  920. for (int i = 0; i < result.length; i++) {
  921. result[i] = (Provider)candidatesArray[i];
  922. }
  923. return result;
  924. }
  925. private static boolean checkSuperclass(Class subclass, Class superclass) {
  926. while(!subclass.equals(superclass)) {
  927. subclass = subclass.getSuperclass();
  928. if (subclass == null) {
  929. return false;
  930. }
  931. }
  932. return true;
  933. }
  934. /*
  935. * Returns an array of objects: the first object in the array is
  936. * an instance of an implementation of the requested algorithm
  937. * and type, and the second object in the array identifies the provider
  938. * of that implementation.
  939. * The <code>provider</code> argument can be null, in which case all
  940. * configured providers will be searched in order of preference.
  941. */
  942. static Object[] getImpl(String algorithm, String type, String provider)
  943. throws NoSuchAlgorithmException, NoSuchProviderException
  944. {
  945. ProviderProperty pp = getEngineClassName(algorithm, provider, type);
  946. return doGetImpl(algorithm, type, pp);
  947. }
  948. static Object[] getImpl(String algorithm, String type, String provider,
  949. Object params)
  950. throws NoSuchAlgorithmException, NoSuchProviderException,
  951. InvalidAlgorithmParameterException
  952. {
  953. ProviderProperty pp = getEngineClassName(algorithm, provider, type);
  954. return doGetImpl(algorithm, type, pp, params);
  955. }
  956. /*
  957. * Returns an array of objects: the first object in the array is
  958. * an instance of an implementation of the requested algorithm
  959. * and type, and the second object in the array identifies the provider
  960. * of that implementation.
  961. * The <code>provider</code> argument cannot be null.
  962. */
  963. static Object[] getImpl(String algorithm, String type, Provider provider)
  964. throws NoSuchAlgorithmException
  965. {
  966. ProviderProperty pp = getEngineClassName(algorithm, provider, type);
  967. return doGetImpl(algorithm, type, pp);
  968. }
  969. static Object[] getImpl(String algorithm, String type, Provider provider,
  970. Object params)
  971. throws NoSuchAlgorithmException, InvalidAlgorithmParameterException
  972. {
  973. ProviderProperty pp = getEngineClassName(algorithm, provider, type);
  974. return doGetImpl(algorithm, type, pp, params);
  975. }
  976. private static Object[] doGetImpl(String algorithm, String type,
  977. ProviderProperty pp)
  978. throws NoSuchAlgorithmException
  979. {
  980. try {
  981. return doGetImpl(algorithm, type, pp, null);
  982. } catch (InvalidAlgorithmParameterException e) {
  983. // should not occur
  984. throw new NoSuchAlgorithmException(e.getMessage());
  985. }
  986. }
  987. private static Object[] doGetImpl(String algorithm, String type,
  988. ProviderProperty pp, Object params)
  989. throws NoSuchAlgorithmException, InvalidAlgorithmParameterException
  990. {
  991. String className = pp.className;
  992. String providerName = pp.provider.getName();
  993. try {
  994. // java.security.<type>.Spi is a system class, therefore
  995. // Class.forName() always works
  996. Class typeClass;
  997. if (type.equals("CertificateFactory") ||
  998. type.equals("CertPathBuilder") ||
  999. type.equals("CertPathValidator") ||
  1000. type.equals("CertStore")) {
  1001. typeClass = Class.forName("java.security.cert." + type
  1002. + "Spi");
  1003. } else {
  1004. typeClass = Class.forName("java.security." + type + "Spi");
  1005. }
  1006. // Load the implementation class using the same class loader that
  1007. // was used to load the associated provider.
  1008. // In order to get the class loader of a class, the caller's class
  1009. // loader must be the same as or an ancestor of the class loader
  1010. // being returned.
  1011. // Since java.security.Security is a system class, it can get the
  1012. // class loader of any class (the system class loader is an
  1013. // ancestor of all class loaders).
  1014. ClassLoader cl = pp.provider.getClass().getClassLoader();
  1015. Class implClass;
  1016. if (cl != null) {
  1017. implClass = cl.loadClass(className);
  1018. } else {
  1019. implClass = Class.forName(className);
  1020. }
  1021. if (checkSuperclass(implClass, typeClass)) {
  1022. Object obj;
  1023. if (type.equals("CertStore")) {
  1024. Constructor cons =
  1025. implClass.getConstructor(new Class[]
  1026. { Class.forName
  1027. ("java.security.cert.CertStoreParameters") });
  1028. obj = cons.newInstance(new Object[] {params});
  1029. } else
  1030. obj = implClass.newInstance();
  1031. return new Object[] { obj, pp.provider };
  1032. } else {
  1033. throw new NoSuchAlgorithmException("class configured for " +
  1034. type + ": " + className +
  1035. " not a " + type);
  1036. }
  1037. } catch (ClassNotFoundException e) {
  1038. throw new NoSuchAlgorithmException("class configured for " +
  1039. type + "(provider: " +
  1040. providerName + ")" +
  1041. "cannot be found.\n" +
  1042. e.getMessage());
  1043. } catch (InstantiationException e) {
  1044. throw (NoSuchAlgorithmException) new NoSuchAlgorithmException("class " + className +
  1045. " configured for " + type +
  1046. "(provider: " + providerName +
  1047. ") cannot be " +
  1048. "instantiated.\n").initCause(e);
  1049. } catch (IllegalAccessException e) {
  1050. throw new NoSuchAlgorithmException("class " + className +
  1051. " configured for " + type +
  1052. "(provider: " + providerName +
  1053. ") cannot be accessed.\n" +
  1054. e.getMessage());
  1055. } catch (SecurityException e) {
  1056. throw new NoSuchAlgorithmException("class " + className +
  1057. " configured for " + type +
  1058. "(provider: " + providerName +
  1059. ") cannot be accessed.\n" +
  1060. e.getMessage());
  1061. } catch (NoSuchMethodException e) {
  1062. throw new NoSuchAlgorithmException("constructor for " +
  1063. "class " + className +
  1064. " configured for " + type +
  1065. "(provider: " + providerName +
  1066. ") cannot be instantiated.\n" +
  1067. e.getMessage());
  1068. } catch (InvocationTargetException e) {
  1069. Throwable t = e.getCause();
  1070. if (t != null && t instanceof InvalidAlgorithmParameterException)
  1071. throw (InvalidAlgorithmParameterException) t;
  1072. else
  1073. throw new InvalidAlgorithmParameterException("constructor " +
  1074. "for class " + className +
  1075. " configured for " + type +
  1076. "(provider: " + providerName +
  1077. ") cannot be instantiated.\n" +
  1078. e.getMessage());
  1079. }
  1080. }
  1081. /**
  1082. * Gets a security property value.
  1083. *
  1084. * <p>First, if there is a security manager, its
  1085. * <code>checkPermission</code> method is called with a
  1086. * <code>java.security.SecurityPermission("getProperty."+key)</code>
  1087. * permission to see if it's ok to retrieve the specified
  1088. * security property value..
  1089. *
  1090. * @param key the key of the property being retrieved.
  1091. *
  1092. * @return the value of the security property corresponding to key.
  1093. *
  1094. * @throws SecurityException
  1095. * if a security manager exists and its <code>{@link
  1096. * java.lang.SecurityManager#checkPermission}</code> method
  1097. * denies
  1098. * access to retrieve the specified security property value
  1099. *
  1100. * @see #setProperty
  1101. * @see java.security.SecurityPermission
  1102. */
  1103. public static String getProperty(String key) {
  1104. SecurityManager sm = System.getSecurityManager();
  1105. if (sm != null) {
  1106. sm.checkPermission(new SecurityPermission("getProperty."+
  1107. key));
  1108. }
  1109. String name = props.getProperty(key);
  1110. if (name != null)
  1111. name = name.trim(); // could be a class name with trailing ws
  1112. return name;
  1113. }
  1114. /**
  1115. * Sets a security property value.
  1116. *
  1117. * <p>First, if there is a security manager, its
  1118. * <code>checkPermission</code> method is called with a
  1119. * <code>java.security.SecurityPermission("setProperty."+key)</code>
  1120. * permission to see if it's ok to set the specified
  1121. * security property value.
  1122. *
  1123. * @param key the name of the property to be set.
  1124. *
  1125. * @param datum the value of the property to be set.
  1126. *
  1127. * @throws SecurityException
  1128. * if a security manager exists and its <code>{@link
  1129. * java.lang.SecurityManager#checkPermission}</code> method
  1130. * denies access to set the specified security property value
  1131. *
  1132. * @see #getProperty
  1133. * @see java.security.SecurityPermission
  1134. */
  1135. public static void setProperty(String key, String datum) {
  1136. check("setProperty."+key);
  1137. props.put(key, datum);
  1138. invalidateSMCache(key); /* See below. */
  1139. }
  1140. /*
  1141. * Implementation detail: If the property we just set in
  1142. * setProperty() was either "package.access" or
  1143. * "package.definition", we need to signal to the SecurityManager
  1144. * class that the value has just changed, and that it should
  1145. * invalidate it's local cache values.
  1146. *
  1147. * Rather than create a new API entry for this function,
  1148. * we use reflection to set a private variable.
  1149. */
  1150. private static void invalidateSMCache(String key) {
  1151. final boolean pa = key.equals("package.access");
  1152. final boolean pd = key.equals("package.definition");
  1153. if (pa || pd) {
  1154. AccessController.doPrivileged(new PrivilegedAction() {
  1155. public Object run() {
  1156. try {
  1157. /* Get the class via the bootstrap class loader. */
  1158. Class cl = Class.forName(
  1159. "java.lang.SecurityManager", false, null);
  1160. Field f = null;
  1161. boolean accessible = false;
  1162. if (pa) {
  1163. f = cl.getDeclaredField("packageAccessValid");
  1164. accessible = f.isAccessible();
  1165. f.setAccessible(true);
  1166. } else {
  1167. f = cl.getDeclaredField("packageDefinitionValid");
  1168. accessible = f.isAccessible();
  1169. f.setAccessible(true);
  1170. }
  1171. f.setBoolean(f, false);
  1172. f.setAccessible(accessible);
  1173. }
  1174. catch (Exception e1) {
  1175. /* If we couldn't get the class, it hasn't
  1176. * been loaded yet. If there is no such
  1177. * field, we shouldn't try to set it. There
  1178. * shouldn't be a security execption, as we
  1179. * are loaded by boot class loader, and we
  1180. * are inside a doPrivileged() here.
  1181. *
  1182. * NOOP: don't do anything...
  1183. */
  1184. }
  1185. return null;
  1186. } /* run */
  1187. }); /* PrivilegedAction */
  1188. } /* if */
  1189. }
  1190. private static void check(String directive) {
  1191. SecurityManager security = System.getSecurityManager();
  1192. if (security != null) {
  1193. security.checkSecurityAccess(directive);
  1194. }
  1195. }
  1196. /**
  1197. * Print an error message that may be significant to a user.
  1198. */
  1199. static void error(String msg) {
  1200. if (debug) {
  1201. System.err.println(msg);
  1202. }
  1203. }
  1204. /**
  1205. * Print an error message that may be significant to a user.
  1206. */
  1207. static void error(String msg, Throwable t) {
  1208. error(msg);
  1209. if (debug) {
  1210. t.printStackTrace();
  1211. }
  1212. }
  1213. /**
  1214. * Print an debugging message that may be significant to a developer.
  1215. */
  1216. static void debug(String msg) {
  1217. if (debug) {
  1218. System.err.println(msg);
  1219. }
  1220. }
  1221. /**
  1222. * Print an debugging message that may be significant to a developer.
  1223. */
  1224. static void debug(String msg, Throwable t) {
  1225. if (debug) {
  1226. t.printStackTrace();
  1227. System.err.println(msg);
  1228. }
  1229. }
  1230. /*
  1231. * Returns all providers who satisfy the specified
  1232. * criterion.
  1233. */
  1234. private static LinkedHashSet getAllQualifyingCandidates(String filterKey,
  1235. String filterValue,
  1236. Provider[] allProviders) {
  1237. String[] filterComponents = getFilterComponents(filterKey,
  1238. filterValue);
  1239. // The first component is the service name.
  1240. // The second is the algorithm name.
  1241. // If the third isn't null, that is the attrinute name.
  1242. String serviceName = filterComponents[0];
  1243. String algName = filterComponents[1];
  1244. String attrName = filterComponents[2];
  1245. // Check whether we can find anything in the cache
  1246. String cacheKey = serviceName + '.' + algName;
  1247. LinkedHashSet candidates = (LinkedHashSet)searchResultsCache.get(cacheKey);
  1248. // If there is no entry for the cacheKey in the cache,
  1249. // let's build an entry for it first.
  1250. LinkedHashSet forCache = getProvidersNotUsingCache(serviceName,
  1251. algName,
  1252. null,
  1253. null,
  1254. null,
  1255. allProviders);
  1256. if ((forCache == null) || (forCache.isEmpty())) {
  1257. return null;
  1258. } else {
  1259. searchResultsCache.put(cacheKey, forCache);
  1260. if (attrName == null) {
  1261. return forCache;
  1262. }
  1263. return getProvidersNotUsingCache(serviceName, algName, attrName,
  1264. filterValue, candidates,
  1265. allProviders);
  1266. }
  1267. }
  1268. private static LinkedHashSet getProvidersNotUsingCache(String serviceName,
  1269. String algName,
  1270. String attrName,
  1271. String filterValue,
  1272. LinkedHashSet candidates,
  1273. Provider[] allProviders) {
  1274. if ((attrName != null) && (candidates != null) &&
  1275. (!candidates.isEmpty())) {
  1276. for (Iterator cansIte = candidates.iterator();
  1277. cansIte.hasNext(); ) {
  1278. Provider prov = (Provider)cansIte.next();
  1279. if (!isCriterionSatisfied(prov, serviceName, algName,
  1280. attrName, filterValue)) {
  1281. cansIte.remove();
  1282. }
  1283. }
  1284. }
  1285. if ((candidates == null) || (candidates.isEmpty())) {
  1286. if (candidates == null)
  1287. candidates = new LinkedHashSet(5);
  1288. for (int i = 0; i < allProviders.length; i++) {
  1289. if (isCriterionSatisfied(allProviders[i], serviceName,
  1290. algName,
  1291. attrName, filterValue)) {
  1292. candidates.add(allProviders[i]);
  1293. }
  1294. }
  1295. }
  1296. return candidates;
  1297. }
  1298. /*
  1299. * Returns true if the given provider satisfies
  1300. * the selection criterion key:value.
  1301. */
  1302. private static boolean isCriterionSatisfied(Provider prov,
  1303. String serviceName,
  1304. String algName,
  1305. String attrName,
  1306. String filterValue) {
  1307. String key = serviceName + '.' + algName;
  1308. if (attrName != null) {
  1309. key += ' ' + attrName;
  1310. }
  1311. // Check whether the provider has a property
  1312. // whose key is the same as the given key.
  1313. String propValue = getProviderProperty(key, prov);
  1314. if (propValue == null) {
  1315. // Check whether we have an alias instead
  1316. // of a standard name in the key.
  1317. String standardName = getProviderProperty("Alg.Alias." +
  1318. serviceName + "." +
  1319. algName,
  1320. prov);
  1321. if (standardName != null) {
  1322. key = serviceName + "." + standardName;
  1323. if (attrName != null) {
  1324. key += ' ' + attrName;
  1325. }
  1326. propValue = getProviderProperty(key, prov);
  1327. }
  1328. if (propValue == null) {
  1329. // The provider doesn't have the given
  1330. // key in its property list.
  1331. return false;
  1332. }
  1333. }
  1334. // If the key is in the format of:
  1335. // <crypto_service>.<algorithm_or_type>,
  1336. // there is no need to check the value.
  1337. if (attrName == null) {
  1338. return true;
  1339. }
  1340. // If we get here, the key must be in the
  1341. // format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
  1342. if (isStandardAttr(attrName)) {
  1343. return isConstraintSatisfied(attrName, filterValue, propValue);
  1344. } else {
  1345. return filterValue.equalsIgnoreCase(propValue);
  1346. }
  1347. }
  1348. /*
  1349. * Returns true if the attribute is a standard attribute;
  1350. * otherwise, returns false.
  1351. */
  1352. private static boolean isStandardAttr(String attribute) {
  1353. // For now, we just have two standard attributes: KeySize and ImplementedIn.
  1354. if (attribute.equalsIgnoreCase("KeySize"))
  1355. return true;
  1356. if (attribute.equalsIgnoreCase("ImplementedIn"))
  1357. return true;
  1358. return false;
  1359. }
  1360. /*
  1361. * Returns true if the requested attribute value is supported;
  1362. * otherwise, returns false.
  1363. */
  1364. private static boolean isConstraintSatisfied(String attribute,
  1365. String value,
  1366. String prop) {
  1367. // For KeySize, prop is the max key size the
  1368. // provider supports for a specific <crypto_service>.<algorithm>.
  1369. if (attribute.equalsIgnoreCase("KeySize")) {
  1370. int requestedSize = (new Integer(value)).intValue();
  1371. int maxSize = (new Integer(prop)).intValue();
  1372. if (requestedSize <= maxSize) {
  1373. return true;
  1374. } else {
  1375. return false;
  1376. }
  1377. }
  1378. // For Type, prop is the type of the implementation
  1379. // for a specific <crypto service>.<algorithm>.
  1380. if (attribute.equalsIgnoreCase("ImplementedIn")) {
  1381. return value.equalsIgnoreCase(prop);
  1382. }
  1383. return false;
  1384. }
  1385. static String[] getFilterComponents(String filterKey, String filterValue) {
  1386. int algIndex = filterKey.indexOf('.');
  1387. if (algIndex < 0) {
  1388. // There must be a dot in the filter, and the dot
  1389. // shouldn't be at the beginning of this string.
  1390. throw new InvalidParameterException("Invalid filter");
  1391. }
  1392. String serviceName = filterKey.substring(0, algIndex);
  1393. String algName = null;
  1394. String attrName = null;
  1395. if (filterValue.length() == 0) {
  1396. // The filterValue is an empty string. So the filterKey
  1397. // should be in the format of <crypto_service>.<algorithm_or_type>.
  1398. algName = filterKey.substring(algIndex + 1).trim();
  1399. if (algName.length() == 0) {
  1400. // There must be a algorithm or type name.
  1401. throw new InvalidParameterException("Invalid filter");
  1402. }
  1403. } else {
  1404. // The filterValue is a non-empty string. So the filterKey must be
  1405. // in the format of
  1406. // <crypto_service>.<algorithm_or_type> <attribute_name>
  1407. int attrIndex = filterKey.indexOf(' ');
  1408. if (attrIndex == -1) {
  1409. // There is no attribute name in the filter.
  1410. throw new InvalidParameterException("Invalid filter");
  1411. } else {
  1412. attrName = filterKey.substring(attrIndex + 1).trim();
  1413. if (attrName.length() == 0) {
  1414. // There is no attribute name in the filter.
  1415. throw new InvalidParameterException("Invalid filter");
  1416. }
  1417. }
  1418. // There must be an algorithm name in the filter.
  1419. if ((attrIndex < algIndex) ||
  1420. (algIndex == attrIndex - 1)) {
  1421. throw new InvalidParameterException("Invalid filter");
  1422. } else {
  1423. algName = filterKey.substring(algIndex + 1, attrIndex);
  1424. }
  1425. }
  1426. String[] result = new String[3];
  1427. result[0] = serviceName;
  1428. result[1] = algName;
  1429. result[2] = attrName;
  1430. return result;
  1431. }
  1432. /**
  1433. * Returns a Set of Strings containing the names of all available
  1434. * algorithms or types for the specified Java cryptographic service
  1435. * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns
  1436. * an empty Set if there is no provider that supports the
  1437. * specified service. For a complete list of Java cryptographic
  1438. * services, please see the
  1439. * <a href="../../../guide/security/CryptoSpec.html">Java
  1440. * Cryptography Architecture API Specification & Reference</a>.
  1441. * Note: the returned set is immutable.
  1442. *
  1443. * @param serviceName the name of the Java cryptographic
  1444. * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
  1445. * Note: this parameter is case-insensitive.
  1446. *
  1447. * @return a Set of Strings containing the names of all available
  1448. * algorithms or types for the specified Java cryptographic service
  1449. * or an empty set if no provider supports the specified service.
  1450. *
  1451. * @since 1.4
  1452. **/
  1453. public static Set getAlgorithms(String serviceName) {
  1454. HashSet result = new HashSet();
  1455. if ((serviceName == null) || (serviceName.length() == 0) ||
  1456. (serviceName.endsWith("."))) {
  1457. return result;
  1458. }
  1459. Provider[] providers = Security.getProviders();
  1460. for (int i = 0; i < providers.length; i++) {
  1461. // Check the keys for each provider.
  1462. for (Enumeration e = providers[i].keys(); e.hasMoreElements(); ) {
  1463. String currentKey = ((String)e.nextElement()).toUpperCase();
  1464. if (currentKey.startsWith(serviceName.toUpperCase())) {
  1465. // We should skip the currentKey if it contains a
  1466. // whitespace. The reason is: such an entry in the
  1467. // provider property contains attributes for the
  1468. // implementation of an algorithm. We are only interested
  1469. // in entries which lead to the implementation
  1470. // classes.
  1471. if (currentKey.indexOf(" ") < 0) {
  1472. result.add(currentKey.substring(serviceName.length() + 1));
  1473. }
  1474. }
  1475. }
  1476. }
  1477. return Collections.unmodifiableSet(result);
  1478. }
  1479. }