1. /*
  2. * @(#)Security.java 1.126 04/05/18
  3. *
  4. * Copyright 2004 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.util.concurrent.ConcurrentHashMap;
  11. import java.io.*;
  12. import java.net.URL;
  13. import sun.security.util.Debug;
  14. import sun.security.util.PropertyExpander;
  15. import java.security.Provider.Service;
  16. import sun.security.jca.*;
  17. /**
  18. * <p>This class centralizes all security properties and common security
  19. * methods. One of its primary uses is to manage providers.
  20. *
  21. * @author Benjamin Renaud
  22. * @version 1.126, 05/18/04
  23. */
  24. public final class Security {
  25. /* Are we debugging? -- for developers */
  26. private static final Debug sdebug =
  27. Debug.getInstance("properties");
  28. /* The java.security properties */
  29. private static Properties props;
  30. // An element in the cache
  31. private static class ProviderProperty {
  32. String className;
  33. Provider provider;
  34. }
  35. static {
  36. // doPrivileged here because there are multiple
  37. // things in initialize that might require privs.
  38. // (the FileInputStream call and the File.exists call,
  39. // the securityPropFile call, etc)
  40. AccessController.doPrivileged(new PrivilegedAction() {
  41. public Object run() {
  42. initialize();
  43. return null;
  44. }
  45. });
  46. }
  47. private static void initialize() {
  48. props = new Properties();
  49. boolean loadedProps = false;
  50. boolean overrideAll = false;
  51. // first load the system properties file
  52. // to determine the value of security.overridePropertiesFile
  53. File propFile = securityPropFile("java.security");
  54. if (propFile.exists()) {
  55. try {
  56. FileInputStream fis = new FileInputStream(propFile);
  57. InputStream is = new BufferedInputStream(fis);
  58. props.load(is);
  59. is.close();
  60. loadedProps = true;
  61. if (sdebug != null) {
  62. sdebug.println("reading security properties file: " +
  63. propFile);
  64. }
  65. } catch (IOException e) {
  66. if (sdebug != null) {
  67. sdebug.println("unable to load security properties from " +
  68. propFile);
  69. e.printStackTrace();
  70. }
  71. }
  72. }
  73. if ("true".equalsIgnoreCase(props.getProperty
  74. ("security.overridePropertiesFile"))) {
  75. String extraPropFile = System.getProperty
  76. ("java.security.properties");
  77. if (extraPropFile != null && extraPropFile.startsWith("=")) {
  78. overrideAll = true;
  79. extraPropFile = extraPropFile.substring(1);
  80. }
  81. if (overrideAll) {
  82. props = new Properties();
  83. if (sdebug != null) {
  84. sdebug.println
  85. ("overriding other security properties files!");
  86. }
  87. }
  88. // now load the user-specified file so its values
  89. // will win if they conflict with the earlier values
  90. if (extraPropFile != null) {
  91. try {
  92. URL propURL;
  93. extraPropFile = PropertyExpander.expand(extraPropFile);
  94. propFile = new File(extraPropFile);
  95. if (propFile.exists()) {
  96. propURL = new URL
  97. ("file:" + propFile.getCanonicalPath());
  98. } else {
  99. propURL = new URL(extraPropFile);
  100. }
  101. BufferedInputStream bis = new BufferedInputStream
  102. (propURL.openStream());
  103. props.load(bis);
  104. bis.close();
  105. loadedProps = true;
  106. if (sdebug != null) {
  107. sdebug.println("reading security properties file: " +
  108. propURL);
  109. if (overrideAll) {
  110. sdebug.println
  111. ("overriding other security properties files!");
  112. }
  113. }
  114. } catch (Exception e) {
  115. if (sdebug != null) {
  116. sdebug.println
  117. ("unable to load security properties from " +
  118. extraPropFile);
  119. e.printStackTrace();
  120. }
  121. }
  122. }
  123. }
  124. if (!loadedProps) {
  125. initializeStatic();
  126. if (sdebug != null) {
  127. sdebug.println("unable to load security properties " +
  128. "-- using defaults");
  129. }
  130. }
  131. }
  132. /*
  133. * Initialize to default values, if <java.home>/lib/java.security
  134. * is not found.
  135. */
  136. private static void initializeStatic() {
  137. props.put("security.provider.1", "sun.security.provider.Sun");
  138. props.put("security.provider.2", "sun.security.rsa.SunRsaSign");
  139. props.put("security.provider.3", "com.sun.net.ssl.internal.ssl.Provider");
  140. props.put("security.provider.4", "com.sun.crypto.provider.SunJCE");
  141. props.put("security.provider.5", "sun.security.jgss.SunProvider");
  142. props.put("security.provider.6", "com.sun.security.sasl.Provider");
  143. }
  144. /**
  145. * Don't let anyone instantiate this.
  146. */
  147. private Security() {
  148. }
  149. private static File securityPropFile(String filename) {
  150. // maybe check for a system property which will specify where to
  151. // look. Someday.
  152. String sep = File.separator;
  153. return new File(System.getProperty("java.home") + sep + "lib" + sep +
  154. "security" + sep + filename);
  155. }
  156. /**
  157. * Looks up providers, and returns the property (and its associated
  158. * provider) mapping the key, if any.
  159. * The order in which the providers are looked up is the
  160. * provider-preference order, as specificed in the security
  161. * properties file.
  162. */
  163. private static ProviderProperty getProviderProperty(String key) {
  164. ProviderProperty entry = null;
  165. List providers = Providers.getProviderList().providers();
  166. for (int i = 0; i < providers.size(); i++) {
  167. String matchKey = null;
  168. Provider prov = (Provider)providers.get(i);
  169. String prop = prov.getProperty(key);
  170. if (prop == null) {
  171. // Is there a match if we do a case-insensitive property name
  172. // comparison? Let's try ...
  173. for (Enumeration e = prov.keys();
  174. e.hasMoreElements() && prop == null; ) {
  175. matchKey = (String)e.nextElement();
  176. if (key.equalsIgnoreCase(matchKey)) {
  177. prop = prov.getProperty(matchKey);
  178. break;
  179. }
  180. }
  181. }
  182. if (prop != null) {
  183. ProviderProperty newEntry = new ProviderProperty();
  184. newEntry.className = prop;
  185. newEntry.provider = prov;
  186. return newEntry;
  187. }
  188. }
  189. return entry;
  190. }
  191. /**
  192. * Returns the property (if any) mapping the key for the given provider.
  193. */
  194. private static String getProviderProperty(String key, Provider provider) {
  195. String prop = provider.getProperty(key);
  196. if (prop == null) {
  197. // Is there a match if we do a case-insensitive property name
  198. // comparison? Let's try ...
  199. for (Enumeration e = provider.keys();
  200. e.hasMoreElements() && prop == null; ) {
  201. String matchKey = (String)e.nextElement();
  202. if (key.equalsIgnoreCase(matchKey)) {
  203. prop = provider.getProperty(matchKey);
  204. break;
  205. }
  206. }
  207. }
  208. return prop;
  209. }
  210. /**
  211. * Gets a specified property for an algorithm. The algorithm name
  212. * should be a standard name. See Appendix A in the <a href=
  213. * "../../../guide/security/CryptoSpec.html#AppA">
  214. * Java Cryptography Architecture API Specification & Reference </a>
  215. * for information about standard algorithm names.
  216. * One possible use is by specialized algorithm parsers, which may map
  217. * classes to algorithms which they understand (much like Key parsers
  218. * do).
  219. *
  220. * @param algName the algorithm name.
  221. *
  222. * @param propName the name of the property to get.
  223. *
  224. * @return the value of the specified property.
  225. *
  226. * @deprecated This method used to return the value of a proprietary
  227. * property in the master file of the "SUN" Cryptographic Service
  228. * Provider in order to determine how to parse algorithm-specific
  229. * parameters. Use the new provider-based and algorithm-independent
  230. * <code>AlgorithmParameters</code> and <code>KeyFactory</code> engine
  231. * classes (introduced in the Java 2 platform) instead.
  232. */
  233. @Deprecated
  234. public static String getAlgorithmProperty(String algName,
  235. String propName) {
  236. ProviderProperty entry = getProviderProperty("Alg." + propName
  237. + "." + algName);
  238. if (entry != null) {
  239. return entry.className;
  240. } else {
  241. return null;
  242. }
  243. }
  244. /**
  245. * Adds a new provider, at a specified position. The position is
  246. * the preference order in which providers are searched for
  247. * requested algorithms. Note that it is not guaranteed that this
  248. * preference will be respected. The position is 1-based, that is,
  249. * 1 is most preferred, followed by 2, and so on.
  250. *
  251. * <p>If the given provider is installed at the requested position,
  252. * the provider that used to be at that position, and all providers
  253. * with a position greater than <code>position</code>, are shifted up
  254. * one position (towards the end of the list of installed providers).
  255. *
  256. * <p>A provider cannot be added if it is already installed.
  257. *
  258. * <p>First, if there is a security manager, its
  259. * <code>checkSecurityAccess</code>
  260. * method is called with the string
  261. * <code>"insertProvider."+provider.getName()</code>
  262. * to see if it's ok to add a new provider.
  263. * If the default implementation of <code>checkSecurityAccess</code>
  264. * is used (i.e., that method is not overriden), then this will result in
  265. * a call to the security manager's <code>checkPermission</code> method
  266. * with a
  267. * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  268. * permission.
  269. *
  270. * @param provider the provider to be added.
  271. *
  272. * @param position the preference position that the caller would
  273. * like for this provider.
  274. *
  275. * @return the actual preference position in which the provider was
  276. * added, or -1 if the provider was not added because it is
  277. * already installed.
  278. *
  279. * @throws NullPointerException if provider is null
  280. * @throws SecurityException
  281. * if a security manager exists and its <code>{@link
  282. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  283. * denies access to add a new provider
  284. *
  285. * @see #getProvider
  286. * @see #removeProvider
  287. * @see java.security.SecurityPermission
  288. */
  289. public static synchronized int insertProviderAt(Provider provider,
  290. int position) {
  291. String providerName = provider.getName();
  292. check("insertProvider." + providerName);
  293. ProviderList list = Providers.getFullProviderList();
  294. ProviderList newList = ProviderList.insertAt(list, provider, position - 1);
  295. if (list == newList) {
  296. return -1;
  297. }
  298. Providers.setProviderList(newList);
  299. return newList.getIndex(providerName) + 1;
  300. }
  301. /**
  302. * Adds a provider to the next position available.
  303. *
  304. * <p>First, if there is a security manager, its
  305. * <code>checkSecurityAccess</code>
  306. * method is called with the string
  307. * <code>"insertProvider."+provider.getName()</code>
  308. * to see if it's ok to add a new provider.
  309. * If the default implementation of <code>checkSecurityAccess</code>
  310. * is used (i.e., that method is not overriden), then this will result in
  311. * a call to the security manager's <code>checkPermission</code> method
  312. * with a
  313. * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  314. * permission.
  315. *
  316. * @param provider the provider to be added.
  317. *
  318. * @return the preference position in which the provider was
  319. * added, or -1 if the provider was not added because it is
  320. * already installed.
  321. *
  322. * @throws NullPointerException if provider is null
  323. * @throws SecurityException
  324. * if a security manager exists and its <code>{@link
  325. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  326. * denies access to add a new provider
  327. *
  328. * @see #getProvider
  329. * @see #removeProvider
  330. * @see java.security.SecurityPermission
  331. */
  332. public static int addProvider(Provider provider) {
  333. /*
  334. * We can't assign a position here because the statically
  335. * registered providers may not have been installed yet.
  336. * insertProviderAt() will fix that value after it has
  337. * loaded the static providers.
  338. */
  339. return insertProviderAt(provider, 0);
  340. }
  341. /**
  342. * Removes the provider with the specified name.
  343. *
  344. * <p>When the specified provider is removed, all providers located
  345. * at a position greater than where the specified provider was are shifted
  346. * down one position (towards the head of the list of installed
  347. * providers).
  348. *
  349. * <p>This method returns silently if the provider is not installed or
  350. * if name is null.
  351. *
  352. * <p>First, if there is a security manager, its
  353. * <code>checkSecurityAccess</code>
  354. * method is called with the string <code>"removeProvider."+name</code>
  355. * to see if it's ok to remove the provider.
  356. * If the default implementation of <code>checkSecurityAccess</code>
  357. * is used (i.e., that method is not overriden), then this will result in
  358. * a call to the security manager's <code>checkPermission</code> method
  359. * with a <code>SecurityPermission("removeProvider."+name)</code>
  360. * permission.
  361. *
  362. * @param name the name of the provider to remove.
  363. *
  364. * @throws SecurityException
  365. * if a security manager exists and its <code>{@link
  366. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  367. * denies
  368. * access to remove the provider
  369. *
  370. * @see #getProvider
  371. * @see #addProvider
  372. */
  373. public static synchronized void removeProvider(String name) {
  374. check("removeProvider." + name);
  375. ProviderList list = Providers.getFullProviderList();
  376. ProviderList newList = ProviderList.remove(list, name);
  377. Providers.setProviderList(newList);
  378. }
  379. /**
  380. * Returns an array containing all the installed providers. The order of
  381. * the providers in the array is their preference order.
  382. *
  383. * @return an array of all the installed providers.
  384. */
  385. public static Provider[] getProviders() {
  386. return Providers.getFullProviderList().toArray();
  387. }
  388. /**
  389. * Returns the provider installed with the specified name, if
  390. * any. Returns null if no provider with the specified name is
  391. * installed or if name is null.
  392. *
  393. * @param name the name of the provider to get.
  394. *
  395. * @return the provider of the specified name.
  396. *
  397. * @see #removeProvider
  398. * @see #addProvider
  399. */
  400. public static Provider getProvider(String name) {
  401. return Providers.getProviderList().getProvider(name);
  402. }
  403. /**
  404. * Returns an array containing all installed providers that satisfy the
  405. * specified selection criterion, or null if no such providers have been
  406. * installed. The returned providers are ordered
  407. * according to their <a href=
  408. * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
  409. *
  410. * <p> A cryptographic service is always associated with a particular
  411. * algorithm or type. For example, a digital signature service is
  412. * always associated with a particular algorithm (e.g., DSA),
  413. * and a CertificateFactory service is always associated with
  414. * a particular certificate type (e.g., X.509).
  415. *
  416. * <p>The selection criterion must be specified in one of the following two
  417. * formats:
  418. * <ul>
  419. * <li> <i><crypto_service>.<algorithm_or_type></i> <p> The
  420. * cryptographic service name must not contain any dots.
  421. * <p> A
  422. * provider satisfies the specified selection criterion iff the provider
  423. * implements the
  424. * specified algorithm or type for the specified cryptographic service.
  425. * <p> For example, "CertificateFactory.X.509"
  426. * would be satisfied by any provider that supplied
  427. * a CertificateFactory implementation for X.509 certificates.
  428. * <li> <i><crypto_service>.<algorithm_or_type>
  429. * <attribute_name>:< attribute_value></i>
  430. * <p> The cryptographic service name must not contain any dots. There
  431. * must be one or more space charaters between the the
  432. * <i><algorithm_or_type></i> and the <i><attribute_name></i>.
  433. * <p> A provider satisfies this selection criterion iff the
  434. * provider implements the specified algorithm or type for the specified
  435. * cryptographic service and its implementation meets the
  436. * constraint expressed by the specified attribute name/value pair.
  437. * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
  438. * satisfied by any provider that implemented
  439. * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
  440. *
  441. * </ul>
  442. *
  443. * <p> See Appendix A in the <a href=
  444. * "../../../guide/security/CryptoSpec.html#AppA">
  445. * Java Cryptogaphy Architecture API Specification & Reference </a>
  446. * for information about standard cryptographic service names, standard
  447. * algorithm names and standard attribute names.
  448. *
  449. * @param filter the criterion for selecting
  450. * providers. The filter is case-insensitive.
  451. *
  452. * @return all the installed providers that satisfy the selection
  453. * criterion, or null if no such providers have been installed.
  454. *
  455. * @throws InvalidParameterException
  456. * if the filter is not in the required format
  457. * @throws NullPointerException if filter is null
  458. *
  459. * @see #getProviders(java.util.Map)
  460. */
  461. public static Provider[] getProviders(String filter) {
  462. String key = null;
  463. String value = null;
  464. int index = filter.indexOf(':');
  465. if (index == -1) {
  466. key = filter;
  467. value = "";
  468. } else {
  469. key = filter.substring(0, index);
  470. value = filter.substring(index + 1);
  471. }
  472. Hashtable hashtableFilter = new Hashtable(1);
  473. hashtableFilter.put(key, value);
  474. return (getProviders(hashtableFilter));
  475. }
  476. /**
  477. * Returns an array containing all installed providers that satisfy the
  478. * specified* selection criteria, or null if no such providers have been
  479. * installed. The returned providers are ordered
  480. * according to their <a href=
  481. * "#insertProviderAt(java.security.Provider, int)">preference order</a>.
  482. *
  483. * <p>The selection criteria are represented by a map.
  484. * Each map entry represents a selection criterion.
  485. * A provider is selected iff it satisfies all selection
  486. * criteria. The key for any entry in such a map must be in one of the
  487. * following two formats:
  488. * <ul>
  489. * <li> <i><crypto_service>.<algorithm_or_type></i>
  490. * <p> The cryptographic service name must not contain any dots.
  491. * <p> The value associated with the key must be an empty string.
  492. * <p> A provider
  493. * satisfies this selection criterion iff the provider implements the
  494. * specified algorithm or type for the specified cryptographic service.
  495. * <li> <i><crypto_service>.<algorithm_or_type> <attribute_name></i>
  496. * <p> The cryptographic service name must not contain any dots. There
  497. * must be one or more space charaters between the <i><algorithm_or_type></i>
  498. * and the <i><attribute_name></i>.
  499. * <p> The value associated with the key must be a non-empty string.
  500. * A provider satisfies this selection criterion iff the
  501. * provider implements the specified algorithm or type for the specified
  502. * cryptographic service and its implementation meets the
  503. * constraint expressed by the specified attribute name/value pair.
  504. * </ul>
  505. *
  506. * <p> See Appendix A in the <a href=
  507. * "../../../guide/security/CryptoSpec.html#AppA">
  508. * Java Cryptogaphy Architecture API Specification & Reference </a>
  509. * for information about standard cryptographic service names, standard
  510. * algorithm names and standard attribute names.
  511. *
  512. * @param filter the criteria for selecting
  513. * providers. The filter is case-insensitive.
  514. *
  515. * @return all the installed providers that satisfy the selection
  516. * criteria, or null if no such providers have been installed.
  517. *
  518. * @throws InvalidParameterException
  519. * if the filter is not in the required format
  520. * @throws NullPointerException if filter is null
  521. *
  522. * @see #getProviders(java.lang.String)
  523. */
  524. public static Provider[] getProviders(Map<String,String> filter) {
  525. // Get all installed providers first.
  526. // Then only return those providers who satisfy the selection criteria.
  527. Provider[] allProviders = Security.getProviders();
  528. Set keySet = filter.keySet();
  529. LinkedHashSet candidates = new LinkedHashSet(5);
  530. // Returns all installed providers
  531. // if the selection criteria is null.
  532. if ((keySet == null) || (allProviders == null)) {
  533. return allProviders;
  534. }
  535. boolean firstSearch = true;
  536. // For each selection criterion, remove providers
  537. // which don't satisfy the criterion from the candidate set.
  538. for (Iterator ite = keySet.iterator(); ite.hasNext(); ) {
  539. String key = (String)ite.next();
  540. String value = (String)filter.get(key);
  541. LinkedHashSet newCandidates = getAllQualifyingCandidates(key, value,
  542. allProviders);
  543. if (firstSearch) {
  544. candidates = newCandidates;
  545. firstSearch = false;
  546. }
  547. if ((newCandidates != null) && !newCandidates.isEmpty()) {
  548. // For each provider in the candidates set, if it
  549. // isn't in the newCandidate set, we should remove
  550. // it from the candidate set.
  551. for (Iterator cansIte = candidates.iterator();
  552. cansIte.hasNext(); ) {
  553. Provider prov = (Provider)cansIte.next();
  554. if (!newCandidates.contains(prov)) {
  555. cansIte.remove();
  556. }
  557. }
  558. } else {
  559. candidates = null;
  560. break;
  561. }
  562. }
  563. if ((candidates == null) || (candidates.isEmpty()))
  564. return null;
  565. Object[] candidatesArray = candidates.toArray();
  566. Provider[] result = new Provider[candidatesArray.length];
  567. for (int i = 0; i < result.length; i++) {
  568. result[i] = (Provider)candidatesArray[i];
  569. }
  570. return result;
  571. }
  572. // Map containing cached Spi Class objects of the specified type
  573. private static final Map<String,Class> spiMap =
  574. new ConcurrentHashMap<String,Class>();
  575. /**
  576. * Return the Class object for the given engine type
  577. * (e.g. "MessageDigest"). Works for Spis in the java.security package
  578. * only.
  579. */
  580. private static Class getSpiClass(String type) {
  581. Class clazz = spiMap.get(type);
  582. if (clazz != null) {
  583. return clazz;
  584. }
  585. try {
  586. clazz = Class.forName("java.security." + type + "Spi");
  587. spiMap.put(type, clazz);
  588. return clazz;
  589. } catch (ClassNotFoundException e) {
  590. throw (Error)new AssertionError("Spi class not found").initCause(e);
  591. }
  592. }
  593. /*
  594. * Returns an array of objects: the first object in the array is
  595. * an instance of an implementation of the requested algorithm
  596. * and type, and the second object in the array identifies the provider
  597. * of that implementation.
  598. * The <code>provider</code> argument can be null, in which case all
  599. * configured providers will be searched in order of preference.
  600. */
  601. static Object[] getImpl(String algorithm, String type, String provider)
  602. throws NoSuchAlgorithmException, NoSuchProviderException {
  603. if (provider == null) {
  604. return GetInstance.getInstance
  605. (type, getSpiClass(type), algorithm).toArray();
  606. } else {
  607. return GetInstance.getInstance
  608. (type, getSpiClass(type), algorithm, provider).toArray();
  609. }
  610. }
  611. static Object[] getImpl(String algorithm, String type, String provider,
  612. Object params) throws NoSuchAlgorithmException,
  613. NoSuchProviderException, InvalidAlgorithmParameterException {
  614. if (provider == null) {
  615. return GetInstance.getInstance
  616. (type, getSpiClass(type), algorithm, params).toArray();
  617. } else {
  618. return GetInstance.getInstance
  619. (type, getSpiClass(type), algorithm, params, provider).toArray();
  620. }
  621. }
  622. /*
  623. * Returns an array of objects: the first object in the array is
  624. * an instance of an implementation of the requested algorithm
  625. * and type, and the second object in the array identifies the provider
  626. * of that implementation.
  627. * The <code>provider</code> argument cannot be null.
  628. */
  629. static Object[] getImpl(String algorithm, String type, Provider provider)
  630. throws NoSuchAlgorithmException {
  631. return GetInstance.getInstance
  632. (type, getSpiClass(type), algorithm, provider).toArray();
  633. }
  634. static Object[] getImpl(String algorithm, String type, Provider provider,
  635. Object params) throws NoSuchAlgorithmException,
  636. InvalidAlgorithmParameterException {
  637. return GetInstance.getInstance
  638. (type, getSpiClass(type), algorithm, params, provider).toArray();
  639. }
  640. /**
  641. * Gets a security property value.
  642. *
  643. * <p>First, if there is a security manager, its
  644. * <code>checkPermission</code> method is called with a
  645. * <code>java.security.SecurityPermission("getProperty."+key)</code>
  646. * permission to see if it's ok to retrieve the specified
  647. * security property value..
  648. *
  649. * @param key the key of the property being retrieved.
  650. *
  651. * @return the value of the security property corresponding to key.
  652. *
  653. * @throws SecurityException
  654. * if a security manager exists and its <code>{@link
  655. * java.lang.SecurityManager#checkPermission}</code> method
  656. * denies
  657. * access to retrieve the specified security property value
  658. * @throws NullPointerException is key is null
  659. *
  660. * @see #setProperty
  661. * @see java.security.SecurityPermission
  662. */
  663. public static String getProperty(String key) {
  664. SecurityManager sm = System.getSecurityManager();
  665. if (sm != null) {
  666. sm.checkPermission(new SecurityPermission("getProperty."+
  667. key));
  668. }
  669. String name = props.getProperty(key);
  670. if (name != null)
  671. name = name.trim(); // could be a class name with trailing ws
  672. return name;
  673. }
  674. /**
  675. * Sets a security property value.
  676. *
  677. * <p>First, if there is a security manager, its
  678. * <code>checkPermission</code> method is called with a
  679. * <code>java.security.SecurityPermission("setProperty."+key)</code>
  680. * permission to see if it's ok to set the specified
  681. * security property value.
  682. *
  683. * @param key the name of the property to be set.
  684. *
  685. * @param datum the value of the property to be set.
  686. *
  687. * @throws SecurityException
  688. * if a security manager exists and its <code>{@link
  689. * java.lang.SecurityManager#checkPermission}</code> method
  690. * denies access to set the specified security property value
  691. * @throws NullPointerException if key or datum is null
  692. *
  693. * @see #getProperty
  694. * @see java.security.SecurityPermission
  695. */
  696. public static void setProperty(String key, String datum) {
  697. check("setProperty."+key);
  698. props.put(key, datum);
  699. invalidateSMCache(key); /* See below. */
  700. }
  701. /*
  702. * Implementation detail: If the property we just set in
  703. * setProperty() was either "package.access" or
  704. * "package.definition", we need to signal to the SecurityManager
  705. * class that the value has just changed, and that it should
  706. * invalidate it's local cache values.
  707. *
  708. * Rather than create a new API entry for this function,
  709. * we use reflection to set a private variable.
  710. */
  711. private static void invalidateSMCache(String key) {
  712. final boolean pa = key.equals("package.access");
  713. final boolean pd = key.equals("package.definition");
  714. if (pa || pd) {
  715. AccessController.doPrivileged(new PrivilegedAction() {
  716. public Object run() {
  717. try {
  718. /* Get the class via the bootstrap class loader. */
  719. Class cl = Class.forName(
  720. "java.lang.SecurityManager", false, null);
  721. Field f = null;
  722. boolean accessible = false;
  723. if (pa) {
  724. f = cl.getDeclaredField("packageAccessValid");
  725. accessible = f.isAccessible();
  726. f.setAccessible(true);
  727. } else {
  728. f = cl.getDeclaredField("packageDefinitionValid");
  729. accessible = f.isAccessible();
  730. f.setAccessible(true);
  731. }
  732. f.setBoolean(f, false);
  733. f.setAccessible(accessible);
  734. }
  735. catch (Exception e1) {
  736. /* If we couldn't get the class, it hasn't
  737. * been loaded yet. If there is no such
  738. * field, we shouldn't try to set it. There
  739. * shouldn't be a security execption, as we
  740. * are loaded by boot class loader, and we
  741. * are inside a doPrivileged() here.
  742. *
  743. * NOOP: don't do anything...
  744. */
  745. }
  746. return null;
  747. } /* run */
  748. }); /* PrivilegedAction */
  749. } /* if */
  750. }
  751. private static void check(String directive) {
  752. SecurityManager security = System.getSecurityManager();
  753. if (security != null) {
  754. security.checkSecurityAccess(directive);
  755. }
  756. }
  757. /*
  758. * Returns all providers who satisfy the specified
  759. * criterion.
  760. */
  761. private static LinkedHashSet getAllQualifyingCandidates(String filterKey,
  762. String filterValue,
  763. Provider[] allProviders) {
  764. String[] filterComponents = getFilterComponents(filterKey,
  765. filterValue);
  766. // The first component is the service name.
  767. // The second is the algorithm name.
  768. // If the third isn't null, that is the attrinute name.
  769. String serviceName = filterComponents[0];
  770. String algName = filterComponents[1];
  771. String attrName = filterComponents[2];
  772. return getProvidersNotUsingCache(serviceName, algName, attrName,
  773. filterValue, allProviders);
  774. }
  775. private static LinkedHashSet getProvidersNotUsingCache(String serviceName,
  776. String algName,
  777. String attrName,
  778. String filterValue,
  779. Provider[] allProviders) {
  780. LinkedHashSet candidates = new LinkedHashSet(5);
  781. for (int i = 0; i < allProviders.length; i++) {
  782. if (isCriterionSatisfied(allProviders[i], serviceName,
  783. algName,
  784. attrName, filterValue)) {
  785. candidates.add(allProviders[i]);
  786. }
  787. }
  788. return candidates;
  789. }
  790. /*
  791. * Returns true if the given provider satisfies
  792. * the selection criterion key:value.
  793. */
  794. private static boolean isCriterionSatisfied(Provider prov,
  795. String serviceName,
  796. String algName,
  797. String attrName,
  798. String filterValue) {
  799. String key = serviceName + '.' + algName;
  800. if (attrName != null) {
  801. key += ' ' + attrName;
  802. }
  803. // Check whether the provider has a property
  804. // whose key is the same as the given key.
  805. String propValue = getProviderProperty(key, prov);
  806. if (propValue == null) {
  807. // Check whether we have an alias instead
  808. // of a standard name in the key.
  809. String standardName = getProviderProperty("Alg.Alias." +
  810. serviceName + "." +
  811. algName,
  812. prov);
  813. if (standardName != null) {
  814. key = serviceName + "." + standardName;
  815. if (attrName != null) {
  816. key += ' ' + attrName;
  817. }
  818. propValue = getProviderProperty(key, prov);
  819. }
  820. if (propValue == null) {
  821. // The provider doesn't have the given
  822. // key in its property list.
  823. return false;
  824. }
  825. }
  826. // If the key is in the format of:
  827. // <crypto_service>.<algorithm_or_type>,
  828. // there is no need to check the value.
  829. if (attrName == null) {
  830. return true;
  831. }
  832. // If we get here, the key must be in the
  833. // format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
  834. if (isStandardAttr(attrName)) {
  835. return isConstraintSatisfied(attrName, filterValue, propValue);
  836. } else {
  837. return filterValue.equalsIgnoreCase(propValue);
  838. }
  839. }
  840. /*
  841. * Returns true if the attribute is a standard attribute;
  842. * otherwise, returns false.
  843. */
  844. private static boolean isStandardAttr(String attribute) {
  845. // For now, we just have two standard attributes:
  846. // KeySize and ImplementedIn.
  847. if (attribute.equalsIgnoreCase("KeySize"))
  848. return true;
  849. if (attribute.equalsIgnoreCase("ImplementedIn"))
  850. return true;
  851. return false;
  852. }
  853. /*
  854. * Returns true if the requested attribute value is supported;
  855. * otherwise, returns false.
  856. */
  857. private static boolean isConstraintSatisfied(String attribute,
  858. String value,
  859. String prop) {
  860. // For KeySize, prop is the max key size the
  861. // provider supports for a specific <crypto_service>.<algorithm>.
  862. if (attribute.equalsIgnoreCase("KeySize")) {
  863. int requestedSize = Integer.parseInt(value);
  864. int maxSize = Integer.parseInt(prop);
  865. if (requestedSize <= maxSize) {
  866. return true;
  867. } else {
  868. return false;
  869. }
  870. }
  871. // For Type, prop is the type of the implementation
  872. // for a specific <crypto service>.<algorithm>.
  873. if (attribute.equalsIgnoreCase("ImplementedIn")) {
  874. return value.equalsIgnoreCase(prop);
  875. }
  876. return false;
  877. }
  878. static String[] getFilterComponents(String filterKey, String filterValue) {
  879. int algIndex = filterKey.indexOf('.');
  880. if (algIndex < 0) {
  881. // There must be a dot in the filter, and the dot
  882. // shouldn't be at the beginning of this string.
  883. throw new InvalidParameterException("Invalid filter");
  884. }
  885. String serviceName = filterKey.substring(0, algIndex);
  886. String algName = null;
  887. String attrName = null;
  888. if (filterValue.length() == 0) {
  889. // The filterValue is an empty string. So the filterKey
  890. // should be in the format of <crypto_service>.<algorithm_or_type>.
  891. algName = filterKey.substring(algIndex + 1).trim();
  892. if (algName.length() == 0) {
  893. // There must be a algorithm or type name.
  894. throw new InvalidParameterException("Invalid filter");
  895. }
  896. } else {
  897. // The filterValue is a non-empty string. So the filterKey must be
  898. // in the format of
  899. // <crypto_service>.<algorithm_or_type> <attribute_name>
  900. int attrIndex = filterKey.indexOf(' ');
  901. if (attrIndex == -1) {
  902. // There is no attribute name in the filter.
  903. throw new InvalidParameterException("Invalid filter");
  904. } else {
  905. attrName = filterKey.substring(attrIndex + 1).trim();
  906. if (attrName.length() == 0) {
  907. // There is no attribute name in the filter.
  908. throw new InvalidParameterException("Invalid filter");
  909. }
  910. }
  911. // There must be an algorithm name in the filter.
  912. if ((attrIndex < algIndex) ||
  913. (algIndex == attrIndex - 1)) {
  914. throw new InvalidParameterException("Invalid filter");
  915. } else {
  916. algName = filterKey.substring(algIndex + 1, attrIndex);
  917. }
  918. }
  919. String[] result = new String[3];
  920. result[0] = serviceName;
  921. result[1] = algName;
  922. result[2] = attrName;
  923. return result;
  924. }
  925. /**
  926. * Returns a Set of Strings containing the names of all available
  927. * algorithms or types for the specified Java cryptographic service
  928. * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns
  929. * an empty Set if there is no provider that supports the
  930. * specified service or if serviceName is null. For a complete list
  931. * of Java cryptographic services, please see the
  932. * <a href="../../../guide/security/CryptoSpec.html">Java
  933. * Cryptography Architecture API Specification & Reference</a>.
  934. * Note: the returned set is immutable.
  935. *
  936. * @param serviceName the name of the Java cryptographic
  937. * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
  938. * Note: this parameter is case-insensitive.
  939. *
  940. * @return a Set of Strings containing the names of all available
  941. * algorithms or types for the specified Java cryptographic service
  942. * or an empty set if no provider supports the specified service.
  943. *
  944. * @since 1.4
  945. **/
  946. public static Set<String> getAlgorithms(String serviceName) {
  947. if ((serviceName == null) || (serviceName.length() == 0) ||
  948. (serviceName.endsWith("."))) {
  949. return Collections.EMPTY_SET;
  950. }
  951. HashSet result = new HashSet();
  952. Provider[] providers = Security.getProviders();
  953. for (int i = 0; i < providers.length; i++) {
  954. // Check the keys for each provider.
  955. for (Enumeration e = providers[i].keys(); e.hasMoreElements(); ) {
  956. String currentKey = ((String)e.nextElement()).toUpperCase();
  957. if (currentKey.startsWith(serviceName.toUpperCase())) {
  958. // We should skip the currentKey if it contains a
  959. // whitespace. The reason is: such an entry in the
  960. // provider property contains attributes for the
  961. // implementation of an algorithm. We are only interested
  962. // in entries which lead to the implementation
  963. // classes.
  964. if (currentKey.indexOf(" ") < 0) {
  965. result.add(currentKey.substring(serviceName.length() + 1));
  966. }
  967. }
  968. }
  969. }
  970. return Collections.unmodifiableSet(result);
  971. }
  972. }