1. /*
  2. * @(#)Security.java 1.101 00/08/10
  3. *
  4. * Copyright 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.security;
  11. import java.lang.reflect.*;
  12. import java.util.*;
  13. import java.io.*;
  14. import java.security.InvalidParameterException;
  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.101, 08/10/00
  21. */
  22. public final class Security {
  23. // Do providers need to be reloaded?
  24. private static boolean reloadProviders = false;
  25. /* Are we debugging? -- for developers */
  26. static final boolean debug = false;
  27. /* Are we displaying errors? -- for users */
  28. static final boolean error = true;
  29. /* The java.security properties */
  30. private static Properties props;
  31. /* A vector of providers, in order of priority */
  32. private static Vector providers;
  33. // Where we cache provider properties
  34. private static Hashtable providerPropertiesCache;
  35. // Where we cache engine provider properties
  36. private static Hashtable engineCache;
  37. // Where we cache search results
  38. private static Hashtable searchResultsCache;
  39. // An element in the cache
  40. private static class ProviderProperty {
  41. String className;
  42. Provider provider;
  43. }
  44. static {
  45. // doPrivileged here because there are multiple
  46. // things in initialize that might require privs.
  47. // (the FileInputStream call and the File.exists call,
  48. // the securityPropFile call, etc)
  49. AccessController.doPrivileged(new PrivilegedAction() {
  50. public Object run() {
  51. initialize();
  52. return null;
  53. }
  54. });
  55. }
  56. private static void initialize() {
  57. props = new Properties();
  58. providers = new Vector();
  59. providerPropertiesCache = new Hashtable();
  60. engineCache = new Hashtable();
  61. searchResultsCache = new Hashtable(5);
  62. File propFile = securityPropFile("java.security");
  63. if (!propFile.exists()) {
  64. System.err.println
  65. ("security properties not found. using defaults.");
  66. initializeStatic();
  67. } else {
  68. try {
  69. FileInputStream is = new FileInputStream(propFile);
  70. // Inputstream has been buffered in Properties class
  71. props.load(is);
  72. is.close();
  73. } catch (IOException e) {
  74. error("could not load security properties file from " +
  75. propFile + ". using defaults.");
  76. initializeStatic();
  77. }
  78. }
  79. loadProviders();
  80. }
  81. /*
  82. * Initialize to default values, if <java.home>/lib/java.security
  83. * is not found.
  84. */
  85. private static void initializeStatic() {
  86. props.put("security.provider.1", "sun.security.provider.Sun");
  87. }
  88. /**
  89. * Don't let anyone instantiate this.
  90. */
  91. private Security() {
  92. }
  93. /**
  94. * Loops through provider declarations, which are expected to be
  95. * of the form:
  96. *
  97. * security.provider.1=sun.security.provider.Sun
  98. * security.provider.2=sun.security.jsafe.Jsafe
  99. * etc.
  100. *
  101. * The order determines the default search order when looking for
  102. * an algorithm.
  103. */
  104. private static synchronized void loadProviders() {
  105. int i = 1;
  106. sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
  107. while (true) {
  108. String name = props.getProperty("security.provider." + i++);
  109. if (name == null) {
  110. break;
  111. } else {
  112. Provider prov = Provider.loadProvider(name.trim());
  113. if (prov != null) {
  114. /* This must manipulate the datastructure
  115. directly, because going through addProviders
  116. causes a security check to happen, which
  117. sometimes will cause the security
  118. initialization to fail with bad
  119. consequences. */
  120. providers.addElement(prov);
  121. } else if (l == null) {
  122. reloadProviders = true;
  123. }
  124. }
  125. }
  126. }
  127. /*
  128. * Reload the providers (provided as extensions) that could not be loaded
  129. * (because there was no system class loader available).when this class
  130. * was initialized.
  131. */
  132. private static synchronized void reloadProviders() {
  133. if (reloadProviders) {
  134. sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
  135. if (l != null) {
  136. reloadProviders = false;
  137. providers.removeAllElements();
  138. int i = 1;
  139. while (true) {
  140. final String name =
  141. props.getProperty("security.provider." + i++);
  142. if (name == null) {
  143. break;
  144. } else {
  145. Provider prov =
  146. (Provider)AccessController.doPrivileged(
  147. new PrivilegedAction() {
  148. public Object run() {
  149. return Provider.loadProvider(name.trim());
  150. }
  151. });
  152. if (prov != null) {
  153. providers.addElement(prov);
  154. }
  155. }
  156. }
  157. // empty provider-property cache
  158. providerPropertiesCache.clear();
  159. engineCache.clear();
  160. searchResultsCache.clear();
  161. }
  162. }
  163. }
  164. private static File securityPropFile(String filename) {
  165. // maybe check for a system property which will specify where to
  166. // look. Someday.
  167. String sep = File.separator;
  168. return new File(System.getProperty("java.home") + sep + "lib" + sep +
  169. "security" + sep + filename);
  170. }
  171. /**
  172. * Looks up providers, and returns the property (and its associated
  173. * provider) mapping the key, if any.
  174. * The order in which the providers are looked up is the
  175. * provider-preference order, as specificed in the security
  176. * properties file.
  177. */
  178. private static ProviderProperty getProviderProperty(String key) {
  179. ProviderProperty entry
  180. = (ProviderProperty)providerPropertiesCache.get(key);
  181. if (entry != null) {
  182. return entry;
  183. }
  184. for (int i = 0; i < providers.size(); i++) {
  185. String matchKey = null;
  186. Provider prov = (Provider)providers.elementAt(i);
  187. String prop = prov.getProperty(key);
  188. if (prop == null) {
  189. // Is there a match if we do a case-insensitive property name
  190. // comparison? Let's try ...
  191. for (Enumeration enum = prov.keys();
  192. enum.hasMoreElements() && prop==null; ) {
  193. matchKey = (String)enum.nextElement();
  194. if (key.equalsIgnoreCase(matchKey)) {
  195. prop = prov.getProperty(matchKey);
  196. break;
  197. }
  198. }
  199. }
  200. if (prop != null) {
  201. ProviderProperty newEntry = new ProviderProperty();
  202. newEntry.className = prop;
  203. newEntry.provider = prov;
  204. providerPropertiesCache.put(key, newEntry);
  205. if (matchKey != null) {
  206. // Store the property value in the cache under the exact
  207. // property name, as specified by the provider
  208. providerPropertiesCache.put(matchKey, newEntry);
  209. }
  210. return newEntry;
  211. }
  212. }
  213. return entry;
  214. }
  215. /**
  216. * Returns the property (if any) mapping the key for the given provider.
  217. */
  218. private static String getProviderProperty(String key, Provider provider) {
  219. String prop = provider.getProperty(key);
  220. if (prop == null) {
  221. // Is there a match if we do a case-insensitive property name
  222. // comparison? Let's try ...
  223. for (Enumeration enum = provider.keys();
  224. enum.hasMoreElements() && prop==null; ) {
  225. String matchKey = (String)enum.nextElement();
  226. if (key.equalsIgnoreCase(matchKey)) {
  227. prop = provider.getProperty(matchKey);
  228. break;
  229. }
  230. }
  231. }
  232. return prop;
  233. }
  234. /**
  235. * We always map names to standard names
  236. */
  237. private static String getStandardName(String alias, String engineType,
  238. Provider prov) {
  239. return getProviderProperty("Alg.Alias." + engineType + "." + alias,
  240. prov);
  241. }
  242. /**
  243. * Gets a specified property for an algorithm. The algorithm name
  244. * should be a standard name. See Appendix A in the <a href=
  245. * "../../../guide/security/CryptoSpec.html#AppA">
  246. * Java Cryptography Architecture API Specification & Reference </a>
  247. * for information about standard algorithm names.
  248. * One possible use is by specialized algorithm parsers, which may map
  249. * classes to algorithms which they understand (much like Key parsers
  250. * do).
  251. *
  252. * @param algName the algorithm name.
  253. *
  254. * @param propName the name of the property to get.
  255. *
  256. * @return the value of the specified property.
  257. *
  258. * @deprecated This method used to return the value of a proprietary
  259. * property in the master file of the "SUN" Cryptographic Service
  260. * Provider in order to determine how to parse algorithm-specific
  261. * parameters. Use the new provider-based and algorithm-independent
  262. * <code>AlgorithmParameters</code> and <code>KeyFactory</code> engine
  263. * classes (introduced in the Java 2 platform) instead.
  264. */
  265. public static String getAlgorithmProperty(String algName,
  266. String propName) {
  267. reloadProviders();
  268. ProviderProperty entry = getProviderProperty("Alg." + propName
  269. + "." + algName);
  270. if (entry != null) {
  271. return entry.className;
  272. } else {
  273. return null;
  274. }
  275. }
  276. /*
  277. * Lookup the algorithm in our list of providers. Process
  278. * each provider in priority order one at a time looking for
  279. * either the direct engine property or a matching alias.
  280. */
  281. private static ProviderProperty getEngineClassName(String algName,
  282. String engineType)
  283. throws NoSuchAlgorithmException
  284. {
  285. ProviderProperty pp;
  286. String key = engineType;
  287. if (algName != null)
  288. key += "." + algName;
  289. pp = (ProviderProperty)engineCache.get(key);
  290. if (pp != null)
  291. return pp;
  292. synchronized (Security.class) {
  293. for (int i = 0; i < providers.size(); i++) {
  294. Provider prov = (Provider)providers.elementAt(i);
  295. try {
  296. pp = getEngineClassName(algName, prov.getName(),
  297. engineType);
  298. } catch (NoSuchAlgorithmException e) {
  299. continue;
  300. } catch (NoSuchProviderException e) {
  301. // can't happen except for sync failures
  302. continue;
  303. }
  304. /* Cache it */
  305. engineCache.put(key, pp);
  306. return pp;
  307. }
  308. }
  309. throw new NoSuchAlgorithmException(algName.toUpperCase() + " " +
  310. engineType + " not available");
  311. }
  312. private static ProviderProperty getEngineClassName(String algName,
  313. String provider,
  314. String engineType)
  315. throws NoSuchAlgorithmException, NoSuchProviderException
  316. {
  317. if (provider == null) {
  318. return getEngineClassName(algName, engineType);
  319. }
  320. // check if the provider is installed
  321. Provider prov = getProvider(provider);
  322. if (prov == null) {
  323. throw new NoSuchProviderException("no such provider: " +
  324. provider);
  325. }
  326. String key;
  327. if (engineType.equalsIgnoreCase("SecureRandom") && algName == null)
  328. key = engineType;
  329. else
  330. key = engineType + "." + algName;
  331. String className = getProviderProperty(key, prov);
  332. if (className == null) {
  333. if (engineType.equalsIgnoreCase("SecureRandom") &&
  334. algName == null)
  335. throw new NoSuchAlgorithmException
  336. ("SecureRandom not available for provider " + provider);
  337. else {
  338. // try algName as alias name
  339. String stdName = getStandardName(algName, engineType, prov);
  340. if (stdName != null) key = engineType + "." + stdName;
  341. if ((stdName == null)
  342. || (className = getProviderProperty(key, prov)) == null)
  343. throw new NoSuchAlgorithmException("no such algorithm: " +
  344. algName
  345. + " for provider " +
  346. provider);
  347. }
  348. }
  349. ProviderProperty entry = new ProviderProperty();
  350. entry.className = className;
  351. entry.provider = prov;
  352. return entry;
  353. }
  354. /**
  355. * Adds a new provider, at a specified position. The position is
  356. * the preference order in which providers are searched for
  357. * requested algorithms. Note that it is not guaranteed that this
  358. * preference will be respected. The position is 1-based, that is,
  359. * 1 is most preferred, followed by 2, and so on.
  360. *
  361. * <p>If the given provider is installed at the requested position,
  362. * the provider that used to be at that position, and all providers
  363. * with a position greater than <code>position</code>, are shifted up
  364. * one position (towards the end of the list of installed providers).
  365. *
  366. * <p>A provider cannot be added if it is already installed.
  367. *
  368. * <p>First, if there is a security manager, its
  369. * <code>checkSecurityAccess</code>
  370. * method is called with the string
  371. * <code>"insertProvider."+provider.getName()</code>
  372. * to see if it's ok to add a new provider.
  373. * If the default implementation of <code>checkSecurityAccess</code>
  374. * is used (i.e., that method is not overriden), then this will result in
  375. * a call to the security manager's <code>checkPermission</code> method
  376. * with a
  377. * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  378. * permission.
  379. *
  380. * @param provider the provider to be added.
  381. *
  382. * @param position the preference position that the caller would
  383. * like for this provider.
  384. *
  385. * @return the actual preference position in which the provider was
  386. * added, or -1 if the provider was not added because it is
  387. * already installed.
  388. *
  389. * @throws SecurityException
  390. * if a security manager exists and its <code>{@link
  391. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  392. * denies access to add a new provider
  393. *
  394. * @see #getProvider
  395. * @see #removeProvider
  396. * @see java.security.SecurityPermission
  397. */
  398. public static synchronized int insertProviderAt(Provider provider,
  399. int position) {
  400. reloadProviders();
  401. check("insertProvider."+provider.getName());
  402. /* First check if the provider is already installed */
  403. Provider already = getProvider(provider.getName());
  404. if (already != null) {
  405. return -1;
  406. }
  407. int size = providers.size();
  408. if (position > size || position <= 0) {
  409. position = size+1;
  410. }
  411. providers.insertElementAt(provider, position-1);
  412. // empty provider-property cache
  413. providerPropertiesCache.clear();
  414. engineCache.clear();
  415. searchResultsCache.clear();
  416. return position;
  417. }
  418. /**
  419. * Adds a provider to the next position available.
  420. *
  421. * <p>First, if there is a security manager, its
  422. * <code>checkSecurityAccess</code>
  423. * method is called with the string
  424. * <code>"insertProvider."+provider.getName()</code>
  425. * to see if it's ok to add a new provider.
  426. * If the default implementation of <code>checkSecurityAccess</code>
  427. * is used (i.e., that method is not overriden), then this will result in
  428. * a call to the security manager's <code>checkPermission</code> method
  429. * with a
  430. * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  431. * permission.
  432. *
  433. * @param provider the provider to be added.
  434. *
  435. * @return the preference position in which the provider was
  436. * added, or -1 if the provider was not added because it is
  437. * already installed.
  438. *
  439. * @throws SecurityException
  440. * if a security manager exists and its <code>{@link
  441. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  442. * denies access to add a new provider
  443. *
  444. * @see #getProvider
  445. * @see #removeProvider
  446. * @see java.security.SecurityPermission
  447. */
  448. public static int addProvider(Provider provider) {
  449. return insertProviderAt(provider, providers.size() + 1);
  450. }
  451. /**
  452. * Removes the provider with the specified name.
  453. *
  454. * <p>When the specified provider is removed, all providers located
  455. * at a position greater than where the specified provider was are shifted
  456. * down one position (towards the head of the list of installed
  457. * providers).
  458. *
  459. * <p>This method returns silently if the provider is not installed.
  460. *
  461. * <p>First, if there is a security manager, its
  462. * <code>checkSecurityAccess</code>
  463. * method is called with the string <code>"removeProvider."+name</code>
  464. * to see if it's ok to remove the provider.
  465. * If the default implementation of <code>checkSecurityAccess</code>
  466. * is used (i.e., that method is not overriden), then this will result in
  467. * a call to the security manager's <code>checkPermission</code> method
  468. * with a <code>SecurityPermission("removeProvider."+name)</code>
  469. * permission.
  470. *
  471. * @param name the name of the provider to remove.
  472. *
  473. * @throws SecurityException
  474. * if a security manager exists and its <code>{@link
  475. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  476. * denies
  477. * access to remove the provider
  478. *
  479. * @see #getProvider
  480. * @see #addProvider
  481. */
  482. public static synchronized void removeProvider(String name) {
  483. reloadProviders();
  484. check("removeProvider."+name);
  485. Provider provider = getProvider(name);
  486. if (provider != null) {
  487. for (Iterator i=providers.iterator(); i.hasNext(); )
  488. if (i.next()==provider)
  489. i.remove();
  490. // empty provider-property cache
  491. providerPropertiesCache.clear();
  492. engineCache.clear();
  493. searchResultsCache.clear();
  494. }
  495. }
  496. /**
  497. * Returns an array containing all the installed providers. The order of
  498. * the providers in the array is their preference order.
  499. *
  500. * @return an array of all the installed providers.
  501. */
  502. public static synchronized Provider[] getProviders() {
  503. reloadProviders();
  504. Provider[] result = new Provider[providers.size()];
  505. providers.copyInto(result);
  506. return result;
  507. }
  508. /**
  509. * Returns the provider installed with the specified name, if
  510. * any. Returns null if no provider with the speicified name is
  511. * installed.
  512. *
  513. * @param name the name of the provider to get.
  514. *
  515. * @return the provider of the specified name.
  516. *
  517. * @see #removeProvider
  518. * @see #addProvider
  519. */
  520. public static synchronized Provider getProvider(String name) {
  521. reloadProviders();
  522. Enumeration enum = providers.elements();
  523. while (enum.hasMoreElements()) {
  524. Provider prov = (Provider)enum.nextElement();
  525. if (prov.getName().equals(name)) {
  526. return prov;
  527. }
  528. }
  529. return null;
  530. }
  531. /**
  532. * Returns an array containing all installed providers that satisfy the
  533. * specified selection criterion, or null if no such providers have been
  534. * installed. The returned providers are ordered
  535. * according to their <a href=
  536. * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
  537. *
  538. * <p> A cryptographic service is always associated with a particular
  539. * algorithm or type. For example, a digital signature service is
  540. * always associated with a particular algorithm (e.g., DSA),
  541. * and a CertificateFactory service is always associated with
  542. * a particular certificate type (e.g., X.509).
  543. *
  544. * <p>The selection criterion must be specified in one of the following two formats:
  545. * <ul>
  546. * <li> <i><crypto_service>.<algorithm_or_type></i> <p> The
  547. * cryptographic service name must not contain any dots.
  548. * <p> A
  549. * provider satisfies the specified selection criterion iff the provider implements the
  550. * specified algorithm or type for the specified cryptographic service.
  551. * <p> For example, "CertificateFactory.X.509"
  552. * would be satisfied by any provider that supplied
  553. * a CertificateFactory implementation for X.509 certificates.
  554. * <li> <i><crypto_service>.<algorithm_or_type> <attribute_name>:< attribute_value></i>
  555. * <p> The cryptographic service name must not contain any dots. There
  556. * must be one or more space charaters between the the <i><algorithm_or_type></i>
  557. * and the <i><attribute_name></i>.
  558. * <p> A provider satisfies this selection criterion iff the
  559. * provider implements the specified algorithm or type for the specified
  560. * cryptographic service and its implementation meets the
  561. * constraint expressed by the specified attribute name/value pair.
  562. * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
  563. * satisfied by any provider that implemented
  564. * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
  565. *
  566. * </ul>
  567. *
  568. * <p> See Appendix A in the <a href=
  569. * "../../../guide/security/CryptoSpec.html#AppA">
  570. * Java Cryptogaphy Architecture API Specification & Reference </a>
  571. * for information about standard cryptographic service names, standard
  572. * algorithm names and standard attribute names.
  573. *
  574. * @param filter the criterion for selecting
  575. * providers. The filter is case-insensitive.
  576. *
  577. * @return all the installed providers that satisfy the selection
  578. * criterion, or null if no such providers have been installed.
  579. *
  580. * @throws InvalidParameterException
  581. * if the filter is not in the required format
  582. *
  583. * @ see #getProviders(java.util.Map)
  584. */
  585. public static Provider[] getProviders(String filter) {
  586. String key = null;
  587. String value = null;
  588. int index = filter.indexOf(':');
  589. if (index == -1) {
  590. key = new String(filter);
  591. value = "";
  592. } else {
  593. key = filter.substring(0, index);
  594. value = filter.substring(index + 1);
  595. }
  596. Hashtable hashtableFilter = new Hashtable(1);
  597. hashtableFilter.put(key, value);
  598. return (getProviders(hashtableFilter));
  599. }
  600. /**
  601. * Returns an array containing all installed providers that satisfy the specified
  602. * selection criteria, or null if no such providers have been installed.
  603. * The returned providers are ordered
  604. * according to their <a href=
  605. * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
  606. *
  607. * <p>The selection criteria are represented by a map.
  608. * Each map entry represents a selection criterion.
  609. * A provider is selected iff it satisfies all selection
  610. * criteria. The key for any entry in such a map must be in one of the
  611. * following two formats:
  612. * <ul>
  613. * <li> <i><crypto_service>.<algorithm_or_type></i>
  614. * <p> The cryptographic service name must not contain any dots.
  615. * <p> The value associated with the key must be an empty string.
  616. * <p> A provider
  617. * satisfies this selection criterion iff the provider implements the
  618. * specified algorithm or type for the specified cryptographic service.
  619. * <li> <i><crypto_service>.<algorithm_or_type> <attribute_name></i>
  620. * <p> The cryptographic service name must not contain any dots. There
  621. * must be one or more space charaters between the <i><algorithm_or_type></i>
  622. * and the <i><attribute_name></i>.
  623. * <p> The value associated with the key must be a non-empty string.
  624. * A provider satisfies this selection criterion iff the
  625. * provider implements the specified algorithm or type for the specified
  626. * cryptographic service and its implementation meets the
  627. * constraint expressed by the specified attribute name/value pair.
  628. * </ul>
  629. *
  630. * <p> See Appendix A in the <a href=
  631. * "../../../guide/security/CryptoSpec.html#AppA">
  632. * Java Cryptogaphy Architecture API Specification & Reference </a>
  633. * for information about standard cryptographic service names, standard
  634. * algorithm names and standard attribute names.
  635. *
  636. * @param filter the criteria for selecting
  637. * providers. The filter is case-insensitive.
  638. *
  639. * @return all the installed providers that satisfy the selection
  640. * criteria, or null if no such providers have been installed.
  641. *
  642. * @throws InvalidParameterException
  643. * if the filter is not in the required format
  644. *
  645. * @ see #getProviders(java.lang.String)
  646. */
  647. public static Provider[] getProviders(Map filter) {
  648. // Get all installed providers first.
  649. // Then only return those providers who satisfy the selection criteria.
  650. Provider[] allProviders = Security.getProviders();
  651. Set keySet = filter.keySet();
  652. HashSet candidates = new HashSet(5);
  653. // Returns all installed providers
  654. // if the selection criteria is null.
  655. if ((keySet == null) || (allProviders == null)) {
  656. return allProviders;
  657. }
  658. boolean firstSearch = true;
  659. // For each selection criterion, remove providers
  660. // which don't satisfy the criterion from the candidate set.
  661. for (Iterator ite = keySet.iterator(); ite.hasNext(); ) {
  662. String key = (String)ite.next();
  663. String value = (String)filter.get(key);
  664. HashSet newCandidates = getAllQualifyingCandidates(key, value,
  665. allProviders);
  666. if (firstSearch) {
  667. candidates = newCandidates;
  668. firstSearch = false;
  669. }
  670. if ((newCandidates != null) && !newCandidates.isEmpty()) {
  671. // For each provider in the candidates set, if it
  672. // isn't in the newCandidate set, we should remove
  673. // it from the candidate set.
  674. for (Iterator cansIte = candidates.iterator();
  675. cansIte.hasNext(); ) {
  676. Provider prov = (Provider)cansIte.next();
  677. if (!newCandidates.contains(prov)) {
  678. cansIte.remove();
  679. }
  680. }
  681. } else {
  682. candidates = null;
  683. break;
  684. }
  685. }
  686. if ((candidates == null) || (candidates.isEmpty()))
  687. return null;
  688. Object[] candidatesArray = candidates.toArray();
  689. Provider[] result = new Provider[candidatesArray.length];
  690. for (int i = 0; i < result.length; i++) {
  691. result[i] = (Provider)candidatesArray[i];
  692. }
  693. return result;
  694. }
  695. private static boolean checkSuperclass(Class subclass, Class superclass) {
  696. while(!subclass.equals(superclass)) {
  697. subclass = subclass.getSuperclass();
  698. if (subclass == null) {
  699. return false;
  700. }
  701. }
  702. return true;
  703. }
  704. /*
  705. * Returns an array of objects: the first object in the array is
  706. * an instance of an implementation of the requested algorithm
  707. * and type, and the second object in the array identifies the provider
  708. * of that implementation.
  709. * The <code>provider</code> argument can be null, in which case all
  710. * configured providers will be searched in order of preference.
  711. */
  712. static Object[] getImpl(String algorithm, String type, String provider)
  713. throws NoSuchAlgorithmException, NoSuchProviderException
  714. {
  715. reloadProviders();
  716. ProviderProperty pp = getEngineClassName(algorithm, provider, type);
  717. String className = pp.className;
  718. try {
  719. // java.security.<type>.Spi is a system class, therefore
  720. // Class.forName() always works
  721. Class typeClass;
  722. if (type.equals("CertificateFactory")) {
  723. typeClass = Class.forName("java.security.cert." + type
  724. + "Spi");
  725. } else {
  726. typeClass = Class.forName("java.security." + type + "Spi");
  727. }
  728. // Load the implementation class using the same class loader that
  729. // was used to load the associated provider.
  730. // In order to get the class loader of a class, the caller's class
  731. // loader must be the same as or an ancestor of the class loader
  732. // being returned.
  733. // Since java.security.Security is a system class, it can get the
  734. // class loader of any class (the system class loader is an
  735. // ancestor of all class loaders).
  736. ClassLoader cl = pp.provider.getClass().getClassLoader();
  737. Class implClass;
  738. if (cl != null) {
  739. implClass = cl.loadClass(className);
  740. } else {
  741. implClass = Class.forName(className);
  742. }
  743. if (checkSuperclass(implClass, typeClass)) {
  744. Object obj = implClass.newInstance();
  745. return new Object[] { obj, pp.provider };
  746. } else {
  747. throw new NoSuchAlgorithmException("class configured for " +
  748. type + ": " + className +
  749. " not a " + type);
  750. }
  751. } catch (ClassNotFoundException e) {
  752. throw new NoSuchAlgorithmException("class configured for " +
  753. type + "(provider: " +
  754. provider + ")" +
  755. "cannot be found.\n" +
  756. e.getMessage());
  757. } catch (InstantiationException e) {
  758. throw new NoSuchAlgorithmException("class " + className +
  759. " configured for " + type +
  760. "(provider: " + provider +
  761. ") cannot be instantiated.\n"+
  762. e.getMessage());
  763. } catch (IllegalAccessException e) {
  764. throw new NoSuchAlgorithmException("class " + className +
  765. " configured for " + type +
  766. "(provider: " + provider +
  767. ") cannot be accessed.\n" +
  768. e.getMessage());
  769. } catch (SecurityException e) {
  770. throw new NoSuchAlgorithmException("class " + className +
  771. " configured for " + type +
  772. "(provider: " + provider +
  773. ") cannot be accessed.\n" +
  774. e.getMessage());
  775. }
  776. }
  777. /**
  778. * Gets a security property value.
  779. *
  780. * <p>First, if there is a security manager, its
  781. * <code>checkPermission</code> method is called with a
  782. * <code>java.security.SecurityPermission("getProperty."+key)</code>
  783. * permission to see if it's ok to retrieve the specified
  784. * security property value..
  785. *
  786. * @param key the key of the property being retrieved.
  787. *
  788. * @return the value of the security property corresponding to key.
  789. *
  790. * @throws SecurityException
  791. * if a security manager exists and its <code>{@link
  792. * java.lang.SecurityManager#checkPermission}</code> method
  793. * denies
  794. * access to retrieve the specified security property value
  795. *
  796. * @see java.security.SecurityPermission
  797. */
  798. public static String getProperty(String key) {
  799. SecurityManager sm = System.getSecurityManager();
  800. if (sm != null) {
  801. sm.checkPermission(new SecurityPermission("getProperty."+
  802. key));
  803. }
  804. String name = props.getProperty(key);
  805. if (name != null)
  806. name = name.trim(); // could be a class name with trailing ws
  807. return name;
  808. }
  809. /**
  810. * Sets a security property value.
  811. *
  812. * <p>First, if there is a security manager, its
  813. * <code>checkPermission</code> method is called with a
  814. * <code>java.security.SecurityPermission("setProperty."+key)</code>
  815. * permission to see if it's ok to set the specified
  816. * security property value.
  817. *
  818. * @param key the name of the property to be set.
  819. *
  820. * @param datum the value of the property to be set.
  821. *
  822. * @throws SecurityException
  823. * if a security manager exists and its <code>{@link
  824. * java.lang.SecurityManager#checkPermission}</code> method
  825. * denies access to set the specified security property value
  826. *
  827. * @see java.security.SecurityPermission
  828. */
  829. public static void setProperty(String key, String datum) {
  830. check("setProperty."+key);
  831. props.put(key, datum);
  832. invalidateSMCache(key); /* See below. */
  833. }
  834. /*
  835. * Implementation detail: If the property we just set in
  836. * setProperty() was either "package.access" or
  837. * "package.definition", we need to signal to the SecurityManager
  838. * class that the value has just changed, and that it should
  839. * invalidate it's local cache values.
  840. *
  841. * Rather than create a new API entry for this function,
  842. * we use reflection to set a private variable.
  843. */
  844. private static void invalidateSMCache(String key) {
  845. final boolean pa = key.equals("package.access");
  846. final boolean pd = key.equals("package.definition");
  847. if (pa || pd) {
  848. AccessController.doPrivileged(new PrivilegedAction() {
  849. public Object run() {
  850. try {
  851. /* Get the class via the bootstrap class loader. */
  852. Class cl = Class.forName(
  853. "java.lang.SecurityManager", false, null);
  854. Field f = null;
  855. boolean accessible = false;
  856. if (pa) {
  857. f = cl.getDeclaredField("packageAccessValid");
  858. accessible = f.isAccessible();
  859. f.setAccessible(true);
  860. } else {
  861. f = cl.getDeclaredField("packageDefinitionValid");
  862. accessible = f.isAccessible();
  863. f.setAccessible(true);
  864. }
  865. f.setBoolean(f, false);
  866. f.setAccessible(accessible);
  867. }
  868. catch (Exception e1) {
  869. /* If we couldn't get the class, it hasn't
  870. * been loaded yet. If there is no such
  871. * field, we shouldn't try to set it. There
  872. * shouldn't be a security execption, as we
  873. * are loaded by boot class loader, and we
  874. * are inside a doPrivileged() here.
  875. *
  876. * NOOP: don't do anything...
  877. */
  878. }
  879. return null;
  880. } /* run */
  881. }); /* PrivilegedAction */
  882. } /* if */
  883. }
  884. private static void check(String directive) {
  885. SecurityManager security = System.getSecurityManager();
  886. if (security != null) {
  887. security.checkSecurityAccess(directive);
  888. }
  889. }
  890. /**
  891. * Print an error message that may be significant to a user.
  892. */
  893. static void error(String msg) {
  894. if (debug) {
  895. System.err.println(msg);
  896. }
  897. }
  898. /**
  899. * Print an error message that may be significant to a user.
  900. */
  901. static void error(String msg, Throwable t) {
  902. error(msg);
  903. if (debug) {
  904. t.printStackTrace();
  905. }
  906. }
  907. /**
  908. * Print an debugging message that may be significant to a developer.
  909. */
  910. static void debug(String msg) {
  911. if (debug) {
  912. System.err.println(msg);
  913. }
  914. }
  915. /**
  916. * Print an debugging message that may be significant to a developer.
  917. */
  918. static void debug(String msg, Throwable t) {
  919. if (debug) {
  920. t.printStackTrace();
  921. System.err.println(msg);
  922. }
  923. }
  924. /*
  925. * Returns all providers who satisfy the specified
  926. * criterion.
  927. */
  928. private static HashSet getAllQualifyingCandidates(String filterKey,
  929. String filterValue,
  930. Provider[] allProviders) {
  931. String[] filterComponents = getFilterComponents(filterKey,
  932. filterValue);
  933. // The first component is the service name.
  934. // The second is the algorithm name.
  935. // If the third isn't null, that is the attrinute name.
  936. String serviceName = filterComponents[0];
  937. String algName = filterComponents[1];
  938. String attrName = filterComponents[2];
  939. // Check whether we can find anything in the cache
  940. String cacheKey = serviceName + '.' + algName;
  941. HashSet candidates = (HashSet)searchResultsCache.get(cacheKey);
  942. // If there is no entry for the cacheKey in the cache,
  943. // let's build an entry for it first.
  944. HashSet forCache = getProvidersNotUsingCache(serviceName,
  945. algName,
  946. null,
  947. null,
  948. null,
  949. allProviders);
  950. if ((forCache == null) || (forCache.isEmpty())) {
  951. return null;
  952. } else {
  953. searchResultsCache.put(cacheKey, forCache);
  954. if (attrName == null) {
  955. return forCache;
  956. }
  957. return getProvidersNotUsingCache(serviceName, algName, attrName,
  958. filterValue, candidates,
  959. allProviders);
  960. }
  961. }
  962. private static HashSet getProvidersNotUsingCache(String serviceName,
  963. String algName,
  964. String attrName,
  965. String filterValue,
  966. HashSet candidates,
  967. Provider[] allProviders) {
  968. if ((attrName != null) && (candidates != null) &&
  969. (!candidates.isEmpty())) {
  970. for (Iterator cansIte = candidates.iterator();
  971. cansIte.hasNext(); ) {
  972. Provider prov = (Provider)cansIte.next();
  973. if (!isCriterionSatisfied(prov, serviceName, algName,
  974. attrName, filterValue)) {
  975. cansIte.remove();
  976. }
  977. }
  978. }
  979. if ((candidates == null) || (candidates.isEmpty())) {
  980. if (candidates == null)
  981. candidates = new HashSet(5);
  982. for (int i = 0; i < allProviders.length; i++) {
  983. if (isCriterionSatisfied(allProviders[i], serviceName,
  984. algName,
  985. attrName, filterValue)) {
  986. candidates.add(allProviders[i]);
  987. }
  988. }
  989. }
  990. return candidates;
  991. }
  992. /*
  993. * Returns true if the given provider satisfies
  994. * the selection criterion key:value.
  995. */
  996. private static boolean isCriterionSatisfied(Provider prov,
  997. String serviceName,
  998. String algName,
  999. String attrName,
  1000. String filterValue) {
  1001. String key = serviceName + '.' + algName;
  1002. if (attrName != null) {
  1003. key += ' ' + attrName;
  1004. }
  1005. // Check whether the provider has a property
  1006. // whose key is the same as the given key.
  1007. String propValue = getProviderProperty(key, prov);
  1008. if (propValue == null) {
  1009. // Check whether we have an alias instead
  1010. // of a standard name in the key.
  1011. String standardName = getProviderProperty("Alg.Alias." +
  1012. serviceName + "." +
  1013. algName,
  1014. prov);
  1015. if (standardName != null) {
  1016. key = serviceName + "." + standardName;
  1017. if (attrName != null) {
  1018. key += ' ' + attrName;
  1019. }
  1020. propValue = getProviderProperty(key, prov);
  1021. }
  1022. if (propValue == null) {
  1023. // The provider doesn't have the given
  1024. // key in its property list.
  1025. return false;
  1026. }
  1027. }
  1028. // If the key is in the format of:
  1029. // <crypto_service>.<algorithm_or_type>,
  1030. // there is no need to check the value.
  1031. if (attrName == null) {
  1032. return true;
  1033. }
  1034. // If we get here, the key must be in the
  1035. // format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
  1036. if (isStandardAttr(attrName)) {
  1037. return isConstraintSatisfied(attrName, filterValue, propValue);
  1038. } else {
  1039. return filterValue.equalsIgnoreCase(propValue);
  1040. }
  1041. }
  1042. /*
  1043. * Returns true if the attribute is a standard attribute;
  1044. * otherwise, returns false.
  1045. */
  1046. private static boolean isStandardAttr(String attribute) {
  1047. // For now, we just have two standard attributes: KeySize and ImplementedIn.
  1048. if (attribute.equalsIgnoreCase("KeySize"))
  1049. return true;
  1050. if (attribute.equalsIgnoreCase("ImplementedIn"))
  1051. return true;
  1052. return false;
  1053. }
  1054. /*
  1055. * Returns true if the requested attribute value is supported;
  1056. * otherwise, returns false.
  1057. */
  1058. private static boolean isConstraintSatisfied(String attribute,
  1059. String value,
  1060. String prop) {
  1061. // For KeySize, prop is the max key size the
  1062. // provider supports for a specific <crypto_service>.<algorithm>.
  1063. if (attribute.equalsIgnoreCase("KeySize")) {
  1064. int requestedSize = (new Integer(value)).intValue();
  1065. int maxSize = (new Integer(prop)).intValue();
  1066. if (requestedSize <= maxSize) {
  1067. return true;
  1068. } else {
  1069. return false;
  1070. }
  1071. }
  1072. // For Type, prop is the type of the implementation
  1073. // for a specific <crypto service>.<algorithm>.
  1074. if (attribute.equalsIgnoreCase("ImplementedIn")) {
  1075. return value.equalsIgnoreCase(prop);
  1076. }
  1077. return false;
  1078. }
  1079. static String[] getFilterComponents(String filterKey, String filterValue) {
  1080. int algIndex = filterKey.indexOf('.');
  1081. if (algIndex < 0) {
  1082. // There must be a dot in the filter, and the dot
  1083. // shouldn't be at the beginning of this string.
  1084. throw new InvalidParameterException("Invalid filter");
  1085. }
  1086. String serviceName = filterKey.substring(0, algIndex);
  1087. String algName = null;
  1088. String attrName = null;
  1089. if (filterValue.length() == 0) {
  1090. // The filterValue is an empty string. So the filterKey
  1091. // should be in the format of <crypto_service>.<algorithm_or_type>.
  1092. algName = filterKey.substring(algIndex + 1).trim();
  1093. if (algName.length() == 0) {
  1094. // There must be a algorithm or type name.
  1095. throw new InvalidParameterException("Invalid filter");
  1096. }
  1097. } else {
  1098. // The filterValue is a non-empty string. So the filterKey must be
  1099. // in the format of
  1100. // <crypto_service>.<algorithm_or_type> <attribute_name>
  1101. int attrIndex = filterKey.indexOf(' ');
  1102. if (attrIndex == -1) {
  1103. // There is no attribute name in the filter.
  1104. throw new InvalidParameterException("Invalid filter");
  1105. } else {
  1106. attrName = filterKey.substring(attrIndex + 1).trim();
  1107. if (attrName.length() == 0) {
  1108. // There is no attribute name in the filter.
  1109. throw new InvalidParameterException("Invalid filter");
  1110. }
  1111. }
  1112. // There must be an algorithm name in the filter.
  1113. if ((attrIndex < algIndex) ||
  1114. (algIndex == attrIndex - 1)) {
  1115. throw new InvalidParameterException("Invalid filter");
  1116. } else {
  1117. algName = filterKey.substring(algIndex + 1, attrIndex);
  1118. }
  1119. }
  1120. String[] result = new String[3];
  1121. result[0] = serviceName;
  1122. result[1] = algName;
  1123. result[2] = attrName;
  1124. return result;
  1125. }
  1126. }