1. /*
  2. * @(#)Security.java 1.90 01/11/29
  3. *
  4. * Copyright 2002 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. /**
  12. * <p>This class centralizes all security properties and common security
  13. * methods. One of its primary uses is to manage providers.
  14. *
  15. * @author Benjamin Renaud
  16. * @version 1.90, 01/11/29
  17. */
  18. public final class Security {
  19. // Do providers need to be reloaded?
  20. private static boolean reloadProviders = false;
  21. /* Are we debugging? -- for developers */
  22. static final boolean debug = false;
  23. /* Are we displaying errors? -- for users */
  24. static final boolean error = true;
  25. /* The java.security properties */
  26. private static Properties props;
  27. /* A vector of providers, in order of priority */
  28. private static Vector providers;
  29. // Where we cache provider properties
  30. private static Hashtable providerPropertiesCache;
  31. // Where we cache engine provider properties
  32. private static Hashtable engineCache;
  33. // An element in the cache
  34. private static class ProviderProperty {
  35. String className;
  36. Provider provider;
  37. }
  38. static {
  39. // doPrivileged here because there are multiple
  40. // things in initialize that might require privs.
  41. // (the FileInputStream call and the File.exists call,
  42. // the securityPropFile call, etc)
  43. AccessController.doPrivileged(new PrivilegedAction() {
  44. public Object run() {
  45. initialize();
  46. return null;
  47. }
  48. });
  49. }
  50. private static void initialize() {
  51. props = new Properties();
  52. providers = new Vector();
  53. providerPropertiesCache = new Hashtable();
  54. engineCache = new Hashtable();
  55. File propFile = securityPropFile("java.security");
  56. if (!propFile.exists()) {
  57. System.err.println
  58. ("security properties not found. using defaults.");
  59. initializeStatic();
  60. } else {
  61. try {
  62. FileInputStream fis = new FileInputStream(propFile);
  63. InputStream is = new BufferedInputStream(fis);
  64. props.load(is);
  65. is.close();
  66. } catch (IOException e) {
  67. error("could not load security properties file from " +
  68. propFile + ". using defaults.");
  69. initializeStatic();
  70. }
  71. }
  72. loadProviders();
  73. }
  74. /*
  75. * Initialize to default values, if <java.home>/lib/java.security
  76. * is not found.
  77. */
  78. private static void initializeStatic() {
  79. props.put("security.provider.1", "sun.security.provider.Sun");
  80. }
  81. /**
  82. * Don't let anyone instantiate this.
  83. */
  84. private Security() {
  85. }
  86. /**
  87. * Loops through provider declarations, which are expected to be
  88. * of the form:
  89. *
  90. * security.provider.1=sun.security.provider.Sun
  91. * security.provider.2=sun.security.jsafe.Jsafe
  92. * etc.
  93. *
  94. * The order determines the default search order when looking for
  95. * an algorithm.
  96. */
  97. private static synchronized void loadProviders() {
  98. int i = 1;
  99. sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
  100. while (true) {
  101. String name = props.getProperty("security.provider." + i++);
  102. if (name == null) {
  103. break;
  104. } else {
  105. Provider prov = Provider.loadProvider(name);
  106. if (prov != null) {
  107. /* This must manipulate the datastructure
  108. directly, because going through addProviders
  109. causes a security check to happen, which
  110. sometimes will cause the security
  111. initialization to fail with bad
  112. consequences. */
  113. providers.addElement(prov);
  114. } else if (l == null) {
  115. reloadProviders = true;
  116. }
  117. }
  118. }
  119. }
  120. /*
  121. * Reload the providers (provided as extensions) that could not be loaded
  122. * (because there was no system class loader available).when this class
  123. * was initialized.
  124. */
  125. private static synchronized void reloadProviders() {
  126. if (reloadProviders) {
  127. sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
  128. if (l != null) {
  129. reloadProviders = false;
  130. providers.removeAllElements();
  131. int i = 1;
  132. while (true) {
  133. final String name =
  134. props.getProperty("security.provider." + i++);
  135. if (name == null) {
  136. break;
  137. } else {
  138. Provider prov =
  139. (Provider)AccessController.doPrivileged(
  140. new PrivilegedAction() {
  141. public Object run() {
  142. return Provider.loadProvider(name);
  143. }
  144. });
  145. if (prov != null) {
  146. providers.addElement(prov);
  147. }
  148. }
  149. }
  150. // empty provider-property cache
  151. providerPropertiesCache.clear();
  152. engineCache.clear();
  153. }
  154. }
  155. }
  156. private static File securityPropFile(String filename) {
  157. // maybe check for a system property which will specify where to
  158. // look. Someday.
  159. String sep = File.separator;
  160. return new File(System.getProperty("java.home") + sep + "lib" + sep +
  161. "security" + sep + filename);
  162. }
  163. /**
  164. * Looks up providers, and returns the property (and its associated
  165. * provider) mapping the key, if any.
  166. * The order in which the providers are looked up is the
  167. * provider-preference order, as specificed in the security
  168. * properties file.
  169. */
  170. private static ProviderProperty getProviderProperty(String key) {
  171. ProviderProperty entry
  172. = (ProviderProperty)providerPropertiesCache.get(key);
  173. if (entry != null) {
  174. return entry;
  175. }
  176. for (int i = 0; i < providers.size(); i++) {
  177. String matchKey = null;
  178. Provider prov = (Provider)providers.elementAt(i);
  179. String prop = prov.getProperty(key);
  180. if (prop == null) {
  181. // Is there a match if we do a case-insensitive property name
  182. // comparison? Let's try ...
  183. for (Enumeration enum = prov.keys();
  184. enum.hasMoreElements() && prop==null; ) {
  185. matchKey = (String)enum.nextElement();
  186. if (key.equalsIgnoreCase(matchKey)) {
  187. prop = prov.getProperty(matchKey);
  188. break;
  189. }
  190. }
  191. }
  192. if (prop != null) {
  193. ProviderProperty newEntry = new ProviderProperty();
  194. newEntry.className = prop;
  195. newEntry.provider = prov;
  196. providerPropertiesCache.put(key, newEntry);
  197. if (matchKey != null) {
  198. // Store the property value in the cache under the exact
  199. // property name, as specified by the provider
  200. providerPropertiesCache.put(matchKey, newEntry);
  201. }
  202. return newEntry;
  203. }
  204. }
  205. return entry;
  206. }
  207. /**
  208. * Returns the property (if any) mapping the key for the given provider.
  209. */
  210. private static String getProviderProperty(String key, Provider provider) {
  211. String prop = provider.getProperty(key);
  212. if (prop == null) {
  213. // Is there a match if we do a case-insensitive property name
  214. // comparison? Let's try ...
  215. for (Enumeration enum = provider.keys();
  216. enum.hasMoreElements() && prop==null; ) {
  217. String matchKey = (String)enum.nextElement();
  218. if (key.equalsIgnoreCase(matchKey)) {
  219. prop = provider.getProperty(matchKey);
  220. break;
  221. }
  222. }
  223. }
  224. return prop;
  225. }
  226. /**
  227. * We always map names to standard names
  228. */
  229. private static String getStandardName(String alias, String engineType,
  230. Provider prov) {
  231. return getProviderProperty("Alg.Alias." + engineType + "." + alias,
  232. prov);
  233. }
  234. /**
  235. * Gets a specified property for an algorithm. The algorithm name
  236. * should be a standard name. See Appendix A in the <a href=
  237. * "../../../guide/security/CryptoSpec.html#AppA">
  238. * Java Cryptography Architecture API Specification & Reference </a>
  239. * for information about standard algorithm names.
  240. * One possible use is by specialized algorithm parsers, which may map
  241. * classes to algorithms which they understand (much like Key parsers
  242. * do).
  243. *
  244. * @param algName the algorithm name.
  245. *
  246. * @param propName the name of the property to get.
  247. *
  248. * @return the value of the specified property.
  249. *
  250. * @deprecated This method used to return the value of a proprietary
  251. * property in the master file of the "SUN" Cryptographic Service
  252. * Provider in order to determine how to parse algorithm-specific
  253. * parameters. Use the new provider-based and algorithm-independent
  254. * <code>AlgorithmParameters</code> and <code>KeyFactory</code> engine
  255. * classes (introduced in JDK 1.2) instead.
  256. */
  257. public static String getAlgorithmProperty(String algName,
  258. String propName) {
  259. reloadProviders();
  260. ProviderProperty entry = getProviderProperty("Alg." + propName
  261. + "." + algName);
  262. if (entry != null) {
  263. return entry.className;
  264. } else {
  265. return null;
  266. }
  267. }
  268. /*
  269. * Lookup the algorithm in our list of providers. Process
  270. * each provider in priority order one at a time looking for
  271. * either the direct engine property or a matching alias.
  272. */
  273. private static ProviderProperty getEngineClassName(String algName,
  274. String engineType)
  275. throws NoSuchAlgorithmException
  276. {
  277. ProviderProperty pp;
  278. String key = engineType;
  279. if (algName != null)
  280. key += "." + algName;
  281. pp = (ProviderProperty)engineCache.get(key);
  282. if (pp != null)
  283. return pp;
  284. synchronized (Security.class) {
  285. for (int i = 0; i < providers.size(); i++) {
  286. Provider prov = (Provider)providers.elementAt(i);
  287. try {
  288. pp = getEngineClassName(algName, prov.getName(),
  289. engineType);
  290. } catch (NoSuchAlgorithmException e) {
  291. continue;
  292. } catch (NoSuchProviderException e) {
  293. // can't happen except for sync failures
  294. continue;
  295. }
  296. /* Cache it */
  297. engineCache.put(key, pp);
  298. return pp;
  299. }
  300. }
  301. throw new NoSuchAlgorithmException(engineType + " not available");
  302. }
  303. private static ProviderProperty getEngineClassName(String algName,
  304. String provider,
  305. String engineType)
  306. throws NoSuchAlgorithmException, NoSuchProviderException
  307. {
  308. if (provider == null) {
  309. return getEngineClassName(algName, engineType);
  310. }
  311. // check if the provider is installed
  312. Provider prov = getProvider(provider);
  313. if (prov == null) {
  314. throw new NoSuchProviderException("no such provider: " +
  315. provider);
  316. }
  317. String key;
  318. if (engineType.equalsIgnoreCase("SecureRandom") && algName == null)
  319. key = engineType;
  320. else
  321. key = engineType + "." + algName;
  322. String className = getProviderProperty(key, prov);
  323. if (className == null) {
  324. if (engineType.equalsIgnoreCase("SecureRandom") &&
  325. algName == null)
  326. throw new NoSuchAlgorithmException
  327. ("SecureRandom not available for provider " + provider);
  328. else {
  329. // try algName as alias name
  330. String stdName = getStandardName(algName, engineType, prov);
  331. if (stdName != null) key = engineType + "." + stdName;
  332. if ((stdName == null)
  333. || (className = getProviderProperty(key, prov)) == null)
  334. throw new NoSuchAlgorithmException("no such algorithm: " +
  335. algName
  336. + " for provider " +
  337. provider);
  338. }
  339. }
  340. ProviderProperty entry = new ProviderProperty();
  341. entry.className = className;
  342. entry.provider = prov;
  343. return entry;
  344. }
  345. /**
  346. * Adds a new provider, at a specified position. The position is
  347. * the preference order in which providers are searched for
  348. * requested algorithms. Note that it is not guaranteed that this
  349. * preference will be respected. The position is 1-based, that is,
  350. * 1 is most preferred, followed by 2, and so on.
  351. *
  352. * <p>If the given provider is installed at the requested position,
  353. * the provider that used to be at that position, and all providers
  354. * with a position greater than <code>position</code>, are shifted up
  355. * one position (towards the end of the list of installed providers).
  356. *
  357. * <p>A provider cannot be added if it is already installed.
  358. *
  359. * <p>First, if there is a security manager, its
  360. * <code>checkSecurityAccess</code>
  361. * method is called with the string
  362. * <code>"insertProvider."+provider.getName()</code>
  363. * to see if it's ok to add a new provider.
  364. * If the default implementation of <code>checkSecurityAccess</code>
  365. * is used (i.e., that method is not overriden), then this will result in
  366. * a call to the security manager's <code>checkPermission</code> method
  367. * with a
  368. * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  369. * permission.
  370. *
  371. * @param provider the provider to be added.
  372. *
  373. * @param position the preference position that the caller would
  374. * like for this provider.
  375. *
  376. * @return the actual preference position in which the provider was
  377. * added, or -1 if the provider was not added because it is
  378. * already installed.
  379. *
  380. * @throws SecurityException
  381. * if a security manager exists and its <code>{@link
  382. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  383. * denies access to add a new provider
  384. *
  385. * @see #getProvider
  386. * @see #removeProvider
  387. * @see java.security.SecurityPermission
  388. */
  389. public static synchronized int insertProviderAt(Provider provider,
  390. int position) {
  391. reloadProviders();
  392. check("insertProvider."+provider.getName());
  393. /* First check if the provider is already installed */
  394. Provider already = getProvider(provider.getName());
  395. if (already != null) {
  396. return -1;
  397. }
  398. int size = providers.size();
  399. if (position > size || position <= 0) {
  400. position = size+1;
  401. }
  402. providers.insertElementAt(provider, position-1);
  403. // empty provider-property cache
  404. providerPropertiesCache.clear();
  405. engineCache.clear();
  406. return position;
  407. }
  408. /**
  409. * Adds a provider to the next position available.
  410. *
  411. * <p>First, if there is a security manager, its
  412. * <code>checkSecurityAccess</code>
  413. * method is called with the string
  414. * <code>"insertProvider."+provider.getName()</code>
  415. * to see if it's ok to add a new provider.
  416. * If the default implementation of <code>checkSecurityAccess</code>
  417. * is used (i.e., that method is not overriden), then this will result in
  418. * a call to the security manager's <code>checkPermission</code> method
  419. * with a
  420. * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  421. * permission.
  422. *
  423. * @param provider the provider to be added.
  424. *
  425. * @return the preference position in which the provider was
  426. * added, or -1 if the provider was not added because it is
  427. * already installed.
  428. *
  429. * @throws SecurityException
  430. * if a security manager exists and its <code>{@link
  431. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  432. * denies access to add a new provider
  433. *
  434. * @see #getProvider
  435. * @see #removeProvider
  436. * @see java.security.SecurityPermission
  437. */
  438. public static int addProvider(Provider provider) {
  439. return insertProviderAt(provider, providers.size() + 1);
  440. }
  441. /**
  442. * Removes the provider with the specified name.
  443. *
  444. * <p>When the specified provider is removed, all providers located
  445. * at a position greater than where the specified provider was are shifted
  446. * down one position (towards the head of the list of installed
  447. * providers).
  448. *
  449. * <p>This method returns silently if the provider is not installed.
  450. *
  451. * <p>First, if there is a security manager, its
  452. * <code>checkSecurityAccess</code>
  453. * method is called with the string <code>"removeProvider."+name</code>
  454. * to see if it's ok to remove the provider.
  455. * If the default implementation of <code>checkSecurityAccess</code>
  456. * is used (i.e., that method is not overriden), then this will result in
  457. * a call to the security manager's <code>checkPermission</code> method
  458. * with a <code>SecurityPermission("removeProvider."+name)</code>
  459. * permission.
  460. *
  461. * @param name the name of the provider to remove.
  462. *
  463. * @throws SecurityException
  464. * if a security manager exists and its <code>{@link
  465. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  466. * denies
  467. * access to remove the provider
  468. *
  469. * @see #getProvider
  470. * @see #addProvider
  471. */
  472. public static synchronized void removeProvider(String name) {
  473. reloadProviders();
  474. check("removeProvider."+name);
  475. Provider provider = getProvider(name);
  476. if (provider != null) {
  477. for (Iterator i=providers.iterator(); i.hasNext(); )
  478. if (i.next()==provider)
  479. i.remove();
  480. // empty provider-property cache
  481. providerPropertiesCache.clear();
  482. engineCache.clear();
  483. }
  484. }
  485. /**
  486. * Returns an array containing all the installed providers. The order of
  487. * the providers in the array is their preference order.
  488. *
  489. * @return an array of all the installed providers.
  490. */
  491. public static synchronized Provider[] getProviders() {
  492. reloadProviders();
  493. Provider[] result = new Provider[providers.size()];
  494. providers.copyInto(result);
  495. return result;
  496. }
  497. /**
  498. * Returns the provider installed with the specified name, if
  499. * any. Returns null if no provider with the speicified name is
  500. * installed.
  501. *
  502. * @param name the name of the provider to get.
  503. *
  504. * @return the provider of the specified name.
  505. *
  506. * @see #removeProvider
  507. * @see #addProvider
  508. */
  509. public static synchronized Provider getProvider(String name) {
  510. reloadProviders();
  511. Enumeration enum = providers.elements();
  512. while (enum.hasMoreElements()) {
  513. Provider prov = (Provider)enum.nextElement();
  514. if (prov.getName().equals(name)) {
  515. return prov;
  516. }
  517. }
  518. return null;
  519. }
  520. private static boolean checkSuperclass(Class subclass, Class superclass) {
  521. while(!subclass.equals(superclass)) {
  522. subclass = subclass.getSuperclass();
  523. if (subclass == null) {
  524. return false;
  525. }
  526. }
  527. return true;
  528. }
  529. /*
  530. * Returns an array of objects: the first object in the array is
  531. * an instance of an implementation of the requested algorithm
  532. * and type, and the second object in the array identifies the provider
  533. * of that implementation.
  534. * The <code>provider</code> argument can be null, in which case all
  535. * configured providers will be searched in order of preference.
  536. */
  537. static Object[] getImpl(String algorithm, String type, String provider)
  538. throws NoSuchAlgorithmException, NoSuchProviderException
  539. {
  540. reloadProviders();
  541. ProviderProperty pp = getEngineClassName(algorithm, provider, type);
  542. String className = pp.className;
  543. try {
  544. // java.security.<type>.Spi is a system class, therefore
  545. // Class.forName() always works
  546. Class typeClass;
  547. if (type.equals("CertificateFactory")) {
  548. typeClass = Class.forName("java.security.cert." + type
  549. + "Spi");
  550. } else {
  551. typeClass = Class.forName("java.security." + type + "Spi");
  552. }
  553. // Load the implementation class using the same class loader that
  554. // was used to load the associated provider.
  555. // In order to get the class loader of a class, the caller's class
  556. // loader must be the same as or an ancestor of the class loader
  557. // being returned.
  558. // Since java.security.Security is a system class, it can get the
  559. // class loader of any class (the system class loader is an
  560. // ancestor of all class loaders).
  561. ClassLoader cl = pp.provider.getClass().getClassLoader();
  562. Class implClass;
  563. if (cl != null) {
  564. implClass = cl.loadClass(className);
  565. } else {
  566. implClass = Class.forName(className);
  567. }
  568. if (checkSuperclass(implClass, typeClass)) {
  569. Object obj = implClass.newInstance();
  570. return new Object[] { obj, pp.provider };
  571. } else {
  572. throw new NoSuchAlgorithmException("class configured for " +
  573. type + ": " + className +
  574. " not a " + type);
  575. }
  576. } catch (ClassNotFoundException e) {
  577. throw new NoSuchAlgorithmException("class configured for " +
  578. type + "(provider: " +
  579. provider + ")" +
  580. "cannot be found.\n" +
  581. e.getMessage());
  582. } catch (InstantiationException e) {
  583. throw new NoSuchAlgorithmException("class " + className +
  584. " configured for " + type +
  585. "(provider: " + provider +
  586. ") cannot be instantiated.\n"+
  587. e.getMessage());
  588. } catch (IllegalAccessException e) {
  589. throw new NoSuchAlgorithmException("class " + className +
  590. " configured for " + type +
  591. "(provider: " + provider +
  592. ") cannot be accessed.\n" +
  593. e.getMessage());
  594. } catch (SecurityException e) {
  595. throw new NoSuchAlgorithmException("class " + className +
  596. " configured for " + type +
  597. "(provider: " + provider +
  598. ") cannot be accessed.\n" +
  599. e.getMessage());
  600. }
  601. }
  602. /**
  603. * Gets a security property value.
  604. *
  605. * <p>First, if there is a security manager, its
  606. * <code>checkPermission</code> method is called with a
  607. * <code>java.security.SecurityPermission("getProperty."+key)</code>
  608. * permission to see if it's ok to retrieve the specified
  609. * security property value..
  610. *
  611. * @param key the key of the property being retrieved.
  612. *
  613. * @return the value of the security property corresponding to key.
  614. *
  615. * @throws SecurityException
  616. * if a security manager exists and its <code>{@link
  617. * java.lang.SecurityManager#checkPermission}</code> method
  618. * denies
  619. * access to retrieve the specified security property value
  620. *
  621. * @see java.security.SecurityPermission
  622. */
  623. public static String getProperty(String key) {
  624. SecurityManager sm = System.getSecurityManager();
  625. if (sm != null) {
  626. sm.checkPermission(new SecurityPermission("getProperty."+
  627. key));
  628. }
  629. return props.getProperty(key);
  630. }
  631. /**
  632. * Sets a security property value.
  633. *
  634. * <p>First, if there is a security manager, its
  635. * <code>checkPermission</code> method is called with a
  636. * <code>java.security.SecurityPermission("setProperty."+key)</code>
  637. * permission to see if it's ok to set the specified
  638. * security property value.
  639. *
  640. * @param key the name of the property to be set.
  641. *
  642. * @param datum the value of the property to be set.
  643. *
  644. * @throws SecurityException
  645. * if a security manager exists and its <code>{@link
  646. * java.lang.SecurityManager#checkPermission}</code> method
  647. * denies access to set the specified security property value
  648. *
  649. * @see java.security.SecurityPermission
  650. */
  651. public static void setProperty(String key, String datum) {
  652. check("setProperty."+key);
  653. props.put(key, datum);
  654. }
  655. private static void check(String directive) {
  656. SecurityManager security = System.getSecurityManager();
  657. if (security != null) {
  658. security.checkSecurityAccess(directive);
  659. }
  660. }
  661. /**
  662. * Print an error message that may be significant to a user.
  663. */
  664. static void error(String msg) {
  665. if (debug) {
  666. System.err.println(msg);
  667. }
  668. }
  669. /**
  670. * Print an error message that may be significant to a user.
  671. */
  672. static void error(String msg, Throwable t) {
  673. error(msg);
  674. if (debug) {
  675. t.printStackTrace();
  676. }
  677. }
  678. /**
  679. * Print an debugging message that may be significant to a developer.
  680. */
  681. static void debug(String msg) {
  682. if (debug) {
  683. System.err.println(msg);
  684. }
  685. }
  686. /**
  687. * Print an debugging message that may be significant to a developer.
  688. */
  689. static void debug(String msg, Throwable t) {
  690. if (debug) {
  691. t.printStackTrace();
  692. System.err.println(msg);
  693. }
  694. }
  695. }