1. /*
  2. * @(#)Provider.java 1.61 04/05/05
  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.io.*;
  9. import java.util.*;
  10. import java.lang.ref.*;
  11. import java.lang.reflect.*;
  12. import java.security.cert.CertStoreParameters;
  13. /**
  14. * This class represents a "provider" for the
  15. * Java Security API, where a provider implements some or all parts of
  16. * Java Security. Services that a provider may implement include:
  17. *
  18. * <ul>
  19. *
  20. * <li>Algorithms (such as DSA, RSA, MD5 or SHA-1).
  21. *
  22. * <li>Key generation, conversion, and management facilities (such as for
  23. * algorithm-specific keys).
  24. *
  25. *</ul>
  26. *
  27. * <p>Each provider has a name and a version number, and is configured
  28. * in each runtime it is installed in.
  29. *
  30. * <p>See <a href =
  31. * "../../../guide/security/CryptoSpec.html#Provider">The Provider Class</a>
  32. * in the "Java Cryptography Architecture API Specification & Reference"
  33. * for information about how a particular type of provider, the
  34. * cryptographic service provider, works and is installed. However,
  35. * please note that a provider can be used to implement any security
  36. * service in Java that uses a pluggable architecture with a choice
  37. * of implementations that fit underneath.
  38. *
  39. * <p>Some provider implementations may encounter unrecoverable internal
  40. * errors during their operation, for example a failure to communicate with a
  41. * security token. A {@link ProviderException} should be used to indicate
  42. * such errors.
  43. *
  44. * <p>The service type <code>Provider</code> is reserved for use by the
  45. * security framework. Services of this type cannot be added, removed,
  46. * or modified by applications.
  47. * The following attributes are automatically placed in each Provider object:
  48. * <table cellspacing=4>
  49. * <tr><th>Name</th><th>Value</th>
  50. * <tr><td><code>Provider.id name</code></td>
  51. * <td><code>String.valueOf(provider.getName())</code></td>
  52. * <tr><td><code>Provider.id version</code></td>
  53. * <td><code>String.valueOf(provider.getVersion())</code></td>
  54. * <tr><td><code>Provider.id info</code></td>
  55. <td><code>String.valueOf(provider.getInfo())</code></td>
  56. * <tr><td><code>Provider.id className</code></td>
  57. * <td><code>provider.getClass().getName()</code></td>
  58. * </table>
  59. *
  60. * @version 1.61, 05/05/04
  61. * @author Benjamin Renaud
  62. * @author Andreas Sterbenz
  63. */
  64. public abstract class Provider extends Properties {
  65. // Declare serialVersionUID to be compatible with JDK1.1
  66. static final long serialVersionUID = -4298000515446427739L;
  67. private static final sun.security.util.Debug debug =
  68. sun.security.util.Debug.getInstance
  69. ("provider", "Provider");
  70. /**
  71. * The provider name.
  72. *
  73. * @serial
  74. */
  75. private String name;
  76. /**
  77. * A description of the provider and its services.
  78. *
  79. * @serial
  80. */
  81. private String info;
  82. /**
  83. * The provider version number.
  84. *
  85. * @serial
  86. */
  87. private double version;
  88. private transient Set entrySet = null;
  89. private transient int entrySetCallCount = 0;
  90. /**
  91. * Constructs a provider with the specified name, version number,
  92. * and information.
  93. *
  94. * @param name the provider name.
  95. *
  96. * @param version the provider version number.
  97. *
  98. * @param info a description of the provider and its services.
  99. */
  100. protected Provider(String name, double version, String info) {
  101. this.name = name;
  102. this.version = version;
  103. this.info = info;
  104. putId();
  105. }
  106. /**
  107. * Returns the name of this provider.
  108. *
  109. * @return the name of this provider.
  110. */
  111. public String getName() {
  112. return name;
  113. }
  114. /**
  115. * Returns the version number for this provider.
  116. *
  117. * @return the version number for this provider.
  118. */
  119. public double getVersion() {
  120. return version;
  121. }
  122. /**
  123. * Returns a human-readable description of the provider and its
  124. * services. This may return an HTML page, with relevant links.
  125. *
  126. * @return a description of the provider and its services.
  127. */
  128. public String getInfo() {
  129. return info;
  130. }
  131. /**
  132. * Returns a string with the name and the version number
  133. * of this provider.
  134. *
  135. * @return the string with the name and the version number
  136. * for this provider.
  137. */
  138. public String toString() {
  139. return name + " version " + version;
  140. }
  141. /*
  142. * override the following methods to ensure that provider
  143. * information can only be changed if the caller has the appropriate
  144. * permissions.
  145. */
  146. /**
  147. * Clears this provider so that it no longer contains the properties
  148. * used to look up facilities implemented by the provider.
  149. *
  150. * <p>First, if there is a security manager, its
  151. * <code>checkSecurityAccess</code> method is called with the string
  152. * <code>"clearProviderProperties."+name</code> (where <code>name</code>
  153. * is the provider name) to see if it's ok to clear this provider.
  154. * If the default implementation of <code>checkSecurityAccess</code>
  155. * is used (that is, that method is not overriden), then this results in
  156. * a call to the security manager's <code>checkPermission</code> method
  157. * with a <code>SecurityPermission("clearProviderProperties."+name)</code>
  158. * permission.
  159. *
  160. * @throws SecurityException
  161. * if a security manager exists and its <code>{@link
  162. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  163. * denies access to clear this provider
  164. *
  165. * @since 1.2
  166. */
  167. public synchronized void clear() {
  168. check("clearProviderProperties."+name);
  169. if (debug != null) {
  170. debug.println("Remove " + name + " provider properties");
  171. }
  172. implClear();
  173. }
  174. /**
  175. * Reads a property list (key and element pairs) from the input stream.
  176. *
  177. * @param inStream the input stream.
  178. * @exception IOException if an error occurred when reading from the
  179. * input stream.
  180. * @see java.util.Properties#load
  181. */
  182. public synchronized void load(InputStream inStream) throws IOException {
  183. check("putProviderProperty."+name);
  184. if (debug != null) {
  185. debug.println("Load " + name + " provider properties");
  186. }
  187. Properties tempProperties = new Properties();
  188. tempProperties.load(inStream);
  189. implPutAll(tempProperties);
  190. }
  191. /**
  192. * Copies all of the mappings from the specified Map to this provider.
  193. * These mappings will replace any properties that this provider had
  194. * for any of the keys currently in the specified Map.
  195. *
  196. * @since 1.2
  197. */
  198. public synchronized void putAll(Map<?,?> t) {
  199. check("putProviderProperty."+name);
  200. if (debug != null) {
  201. debug.println("Put all " + name + " provider properties");
  202. }
  203. implPutAll(t);
  204. }
  205. /**
  206. * Returns an unmodifiable Set view of the property entries contained
  207. * in this Provider.
  208. *
  209. * @see java.util.Map.Entry
  210. * @since 1.2
  211. */
  212. public synchronized Set<Map.Entry<Object,Object>> entrySet() {
  213. if (entrySet == null) {
  214. if (entrySetCallCount++ == 0) // Initial call
  215. entrySet = Collections.unmodifiableMap(this).entrySet();
  216. else
  217. return super.entrySet(); // Recursive call
  218. }
  219. // This exception will be thrown if the implementation of
  220. // Collections.unmodifiableMap.entrySet() is changed such that it
  221. // no longer calls entrySet() on the backing Map. (Provider's
  222. // entrySet implementation depends on this "implementation detail",
  223. // which is unlikely to change.
  224. if (entrySetCallCount != 2)
  225. throw new RuntimeException("Internal error.");
  226. return entrySet;
  227. }
  228. /**
  229. * Returns an unmodifiable Set view of the property keys contained in
  230. * this provider.
  231. *
  232. * @since 1.2
  233. */
  234. public Set<Object> keySet() {
  235. return Collections.unmodifiableSet(super.keySet());
  236. }
  237. /**
  238. * Returns an unmodifiable Collection view of the property values
  239. * contained in this provider.
  240. *
  241. * @since 1.2
  242. */
  243. public Collection<Object> values() {
  244. return Collections.unmodifiableCollection(super.values());
  245. }
  246. /**
  247. * Sets the <code>key</code> property to have the specified
  248. * <code>value</code>.
  249. *
  250. * <p>First, if there is a security manager, its
  251. * <code>checkSecurityAccess</code> method is called with the string
  252. * <code>"putProviderProperty."+name</code>, where <code>name</code> is the
  253. * provider name, to see if it's ok to set this provider's property values.
  254. * If the default implementation of <code>checkSecurityAccess</code>
  255. * is used (that is, that method is not overriden), then this results in
  256. * a call to the security manager's <code>checkPermission</code> method
  257. * with a <code>SecurityPermission("putProviderProperty."+name)</code>
  258. * permission.
  259. *
  260. * @param key the property key.
  261. *
  262. * @param value the property value.
  263. *
  264. * @return the previous value of the specified property
  265. * (<code>key</code>), or null if it did not have one.
  266. *
  267. * @throws SecurityException
  268. * if a security manager exists and its <code>{@link
  269. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  270. * denies access to set property values.
  271. *
  272. * @since 1.2
  273. */
  274. public synchronized Object put(Object key, Object value) {
  275. check("putProviderProperty."+name);
  276. if (debug != null) {
  277. debug.println("Set " + name + " provider property [" +
  278. key + "/" + value +"]");
  279. }
  280. return implPut(key, value);
  281. }
  282. /**
  283. * Removes the <code>key</code> property (and its corresponding
  284. * <code>value</code>).
  285. *
  286. * <p>First, if there is a security manager, its
  287. * <code>checkSecurityAccess</code> method is called with the string
  288. * <code>"removeProviderProperty."+name</code>, where <code>name</code> is
  289. * the provider name, to see if it's ok to remove this provider's
  290. * properties. If the default implementation of
  291. * <code>checkSecurityAccess</code> is used (that is, that method is not
  292. * overriden), then this results in a call to the security manager's
  293. * <code>checkPermission</code> method with a
  294. * <code>SecurityPermission("removeProviderProperty."+name)</code>
  295. * permission.
  296. *
  297. * @param key the key for the property to be removed.
  298. *
  299. * @return the value to which the key had been mapped,
  300. * or null if the key did not have a mapping.
  301. *
  302. * @throws SecurityException
  303. * if a security manager exists and its <code>{@link
  304. * java.lang.SecurityManager#checkSecurityAccess}</code> method
  305. * denies access to remove this provider's properties.
  306. *
  307. * @since 1.2
  308. */
  309. public synchronized Object remove(Object key) {
  310. check("removeProviderProperty."+name);
  311. if (debug != null) {
  312. debug.println("Remove " + name + " provider property " + key);
  313. }
  314. return implRemove(key);
  315. }
  316. private static void check(String directive) {
  317. SecurityManager security = System.getSecurityManager();
  318. if (security != null) {
  319. security.checkSecurityAccess(directive);
  320. }
  321. }
  322. // legacy properties changed since last call to any services method?
  323. private transient boolean legacyChanged;
  324. // serviceMap changed since last call to getServices()
  325. private transient boolean servicesChanged;
  326. // Map<String,String>
  327. private transient Map<String,String> legacyStrings;
  328. // Map<ServiceKey,Service>
  329. // used for services added via putService(), initialized on demand
  330. private transient Map<ServiceKey,Service> serviceMap;
  331. // Map<ServiceKey,Service>
  332. // used for services added via legacy methods, init on demand
  333. private transient Map<ServiceKey,Service> legacyMap;
  334. // Set<Service>
  335. // set of all services. initialized on demand, cleared on modification
  336. private transient Set<Service> serviceSet;
  337. // register the id attributes for this provider
  338. // this is to ensure that equals() and hashCode() do not incorrectly
  339. // report to different provider objects as the same
  340. private void putId() {
  341. // note: name and info may be null
  342. super.put("Provider.id name", String.valueOf(name));
  343. super.put("Provider.id version", String.valueOf(version));
  344. super.put("Provider.id info", String.valueOf(info));
  345. super.put("Provider.id className", this.getClass().getName());
  346. }
  347. /**
  348. * Copies all of the mappings from the specified Map to this provider.
  349. * Internal method to be called AFTER the security check has been
  350. * performed.
  351. */
  352. private void implPutAll(Map t) {
  353. for (Map.Entry e : ((Map<?,?>)t).entrySet()) {
  354. implPut(e.getKey(), e.getValue());
  355. }
  356. }
  357. private Object implRemove(Object key) {
  358. if (key instanceof String) {
  359. String keyString = (String)key;
  360. if (keyString.startsWith("Provider.")) {
  361. return null;
  362. }
  363. legacyChanged = true;
  364. if (legacyStrings == null) {
  365. legacyStrings = new LinkedHashMap<String,String>();
  366. }
  367. legacyStrings.remove(keyString);
  368. }
  369. return super.remove(key);
  370. }
  371. private Object implPut(Object key, Object value) {
  372. if ((key instanceof String) && (value instanceof String)) {
  373. String keyString = (String)key;
  374. if (keyString.startsWith("Provider.")) {
  375. return null;
  376. }
  377. legacyChanged = true;
  378. if (legacyStrings == null) {
  379. legacyStrings = new LinkedHashMap<String,String>();
  380. }
  381. legacyStrings.put(keyString, (String)value);
  382. }
  383. return super.put(key, value);
  384. }
  385. private void implClear() {
  386. super.clear();
  387. putId();
  388. if (legacyStrings != null) {
  389. legacyStrings.clear();
  390. }
  391. if (legacyMap != null) {
  392. legacyMap.clear();
  393. }
  394. if (serviceMap != null) {
  395. serviceMap.clear();
  396. }
  397. legacyChanged = false;
  398. servicesChanged = false;
  399. serviceSet = null;
  400. }
  401. // used as key in the serviceMap and legacyMap HashMaps
  402. private static class ServiceKey {
  403. private final String type;
  404. private final String algorithm;
  405. private final String originalAlgorithm;
  406. private ServiceKey(String type, String algorithm, boolean intern) {
  407. this.type = type;
  408. this.originalAlgorithm = algorithm;
  409. algorithm = algorithm.toUpperCase();
  410. this.algorithm = intern ? algorithm.intern() : algorithm;
  411. }
  412. public int hashCode() {
  413. return type.hashCode() + algorithm.hashCode();
  414. }
  415. public boolean equals(Object obj) {
  416. if (this == obj) {
  417. return true;
  418. }
  419. if (obj instanceof ServiceKey == false) {
  420. return false;
  421. }
  422. ServiceKey other = (ServiceKey)obj;
  423. return this.type.equals(other.type)
  424. && this.algorithm.equals(other.algorithm);
  425. }
  426. boolean matches(String type, String algorithm) {
  427. return (this.type == type) && (this.originalAlgorithm == algorithm);
  428. }
  429. }
  430. /**
  431. * Ensure all the legacy String properties are fully parsed into
  432. * service objects.
  433. */
  434. private void ensureLegacyParsed() {
  435. if ((legacyChanged == false) || (legacyStrings == null)) {
  436. return;
  437. }
  438. serviceSet = null;
  439. if (legacyMap == null) {
  440. legacyMap = new LinkedHashMap<ServiceKey,Service>();
  441. } else {
  442. legacyMap.clear();
  443. }
  444. for (Map.Entry<String,String> entry : legacyStrings.entrySet()) {
  445. parseLegacyPut(entry.getKey(), entry.getValue());
  446. }
  447. removeInvalidServices(legacyMap);
  448. legacyChanged = false;
  449. }
  450. /**
  451. * Remove all invalid services from the Map. Invalid services can only
  452. * occur if the legacy properties are inconsistent or incomplete.
  453. */
  454. private void removeInvalidServices(Map<ServiceKey,Service> map) {
  455. for (Iterator t = map.entrySet().iterator(); t.hasNext(); ) {
  456. Map.Entry entry = (Map.Entry)t.next();
  457. Service s = (Service)entry.getValue();
  458. if (s.isValid() == false) {
  459. t.remove();
  460. }
  461. }
  462. }
  463. private String[] getTypeAndAlgorithm(String key) {
  464. int i = key.indexOf(".");
  465. if (i < 1) {
  466. if (debug != null) {
  467. debug.println("Ignoring invalid entry in provider "
  468. + name + ":" + key);
  469. }
  470. return null;
  471. }
  472. String type = key.substring(0, i);
  473. String alg = key.substring(i + 1);
  474. return new String[] {type, alg};
  475. }
  476. private final static String ALIAS_PREFIX = "Alg.Alias.";
  477. private final static int ALIAS_LENGTH = ALIAS_PREFIX.length();
  478. private void parseLegacyPut(String name, String value) {
  479. if (name.startsWith(ALIAS_PREFIX)) {
  480. // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
  481. // aliasKey ~ MessageDigest.SHA
  482. String stdAlg = value;
  483. String aliasKey = name.substring(ALIAS_LENGTH);
  484. String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
  485. if (typeAndAlg == null) {
  486. return;
  487. }
  488. String type = typeAndAlg[0].intern();
  489. String aliasAlg = typeAndAlg[1].intern();
  490. ServiceKey key = new ServiceKey(type, stdAlg, true);
  491. Service s = (Service)legacyMap.get(key);
  492. if (s == null) {
  493. s = new Service(this);
  494. s.type = type;
  495. s.algorithm = stdAlg;
  496. legacyMap.put(key, s);
  497. }
  498. legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
  499. s.addAlias(aliasAlg);
  500. } else {
  501. String[] typeAndAlg = getTypeAndAlgorithm(name);
  502. if (typeAndAlg == null) {
  503. return;
  504. }
  505. int i = typeAndAlg[1].indexOf(' ');
  506. if (i == -1) {
  507. // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
  508. String type = typeAndAlg[0].intern();
  509. String stdAlg = typeAndAlg[1].intern();
  510. String className = value;
  511. ServiceKey key = new ServiceKey(type, stdAlg, true);
  512. Service s = (Service)legacyMap.get(key);
  513. if (s == null) {
  514. s = new Service(this);
  515. s.type = type;
  516. s.algorithm = stdAlg;
  517. legacyMap.put(key, s);
  518. }
  519. s.className = className;
  520. } else { // attribute
  521. // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
  522. String attributeValue = value;
  523. String type = typeAndAlg[0].intern();
  524. String attributeString = typeAndAlg[1];
  525. String stdAlg = attributeString.substring(0, i).intern();
  526. String attributeName = attributeString.substring(i + 1);
  527. // kill additional spaces
  528. while (attributeName.startsWith(" ")) {
  529. attributeName = attributeName.substring(1);
  530. }
  531. attributeName = attributeName.intern();
  532. ServiceKey key = new ServiceKey(type, stdAlg, true);
  533. Service s = (Service)legacyMap.get(key);
  534. if (s == null) {
  535. s = new Service(this);
  536. s.type = type;
  537. s.algorithm = stdAlg;
  538. legacyMap.put(key, s);
  539. }
  540. s.addAttribute(attributeName, attributeValue);
  541. }
  542. }
  543. }
  544. /**
  545. * Get the service describing this Provider's implementation of the
  546. * specified type of this algorithm or alias. If no such
  547. * implementation exists, this method returns null. If there are two
  548. * matching services, one added to this provider using
  549. * {@link #putService putService()} and one added via {@link #put put()},
  550. * the service added via {@link #putService putService()} is returned.
  551. *
  552. * @param type the type of {@link Service service} requested
  553. * (for example, <code>MessageDigest</code>)
  554. * @param algorithm the case insensitive algorithm name (or alternate
  555. * alias) of the service requested (for example, <code>SHA-1</code>)
  556. *
  557. * @return the service describing this Provider's matching service
  558. * or null if no such service exists
  559. *
  560. * @throws NullPointerException if type or algorithm is null
  561. *
  562. * @since 1.5
  563. */
  564. public synchronized Service getService(String type, String algorithm) {
  565. // avoid allocating a new key object if possible
  566. ServiceKey key = previousKey;
  567. if (key.matches(type, algorithm) == false) {
  568. key = new ServiceKey(type, algorithm, false);
  569. previousKey = key;
  570. }
  571. if (serviceMap != null) {
  572. Service service = serviceMap.get(key);
  573. if (service != null) {
  574. return service;
  575. }
  576. }
  577. ensureLegacyParsed();
  578. return (legacyMap != null) ? legacyMap.get(key) : null;
  579. }
  580. // ServiceKey from previous getService() call
  581. // by re-using it if possible we avoid allocating a new object
  582. // and the toUpperCase() call.
  583. // re-use will occur e.g. as the framework traverses the provider
  584. // list and queries each provider with the same values until it finds
  585. // a matching service
  586. private static volatile ServiceKey previousKey =
  587. new ServiceKey("", "", false);
  588. /**
  589. * Get an unmodifiable Set of all services supported by
  590. * this Provider.
  591. *
  592. * @return an unmodifiable Set of all services supported by
  593. * this Provider
  594. *
  595. * @since 1.5
  596. */
  597. public synchronized Set<Service> getServices() {
  598. if (legacyChanged || servicesChanged) {
  599. serviceSet = null;
  600. } else if (serviceSet != null) {
  601. return serviceSet;
  602. }
  603. ensureLegacyParsed();
  604. serviceSet = new LinkedHashSet<Service>();
  605. if (serviceMap != null) {
  606. serviceSet.addAll(serviceMap.values());
  607. }
  608. if (legacyMap != null) {
  609. serviceSet.addAll(legacyMap.values());
  610. }
  611. servicesChanged = false;
  612. return serviceSet;
  613. }
  614. /**
  615. * Add a service. If a service of the same type with the same algorithm
  616. * name exists and it was added using {@link #putService putService()},
  617. * it is replaced by the new service.
  618. * This method also places information about this service
  619. * in the provider's Hashtable values in the format described in the
  620. * <a href="../../../guide/security/CryptoSpec.html">
  621. * Java Cryptography Architecture API Specification & Reference </a>.
  622. *
  623. * <p>Also, if there is a security manager, its
  624. * <code>checkSecurityAccess</code> method is called with the string
  625. * <code>"putProviderProperty."+name</code>, where <code>name</code> is
  626. * the provider name, to see if it's ok to set this provider's property
  627. * values. If the default implementation of <code>checkSecurityAccess</code>
  628. * is used (that is, that method is not overriden), then this results in
  629. * a call to the security manager's <code>checkPermission</code> method with
  630. * a <code>SecurityPermission("putProviderProperty."+name)</code>
  631. * permission.
  632. *
  633. * @param s the Service to add
  634. *
  635. * @throws SecurityException
  636. * if a security manager exists and its <code>{@link
  637. * java.lang.SecurityManager#checkSecurityAccess}</code> method denies
  638. * access to set property values.
  639. * @throws NullPointerException if s is null
  640. *
  641. * @since 1.5
  642. */
  643. protected synchronized void putService(Service s) {
  644. check("putProviderProperty." + name);
  645. if (debug != null) {
  646. debug.println(name + ".putService(): " + s);
  647. }
  648. if (s == null) {
  649. throw new NullPointerException();
  650. }
  651. if (serviceMap == null) {
  652. serviceMap = new LinkedHashMap<ServiceKey,Service>();
  653. }
  654. servicesChanged = true;
  655. String type = s.getType();
  656. String algorithm = s.getAlgorithm();
  657. ServiceKey key = new ServiceKey(type, algorithm, true);
  658. // remove existing service
  659. implRemoveService(serviceMap.get(key));
  660. serviceMap.put(key, s);
  661. for (String alias : s.getAliases()) {
  662. serviceMap.put(new ServiceKey(type, alias, true), s);
  663. }
  664. putPropertyStrings(s);
  665. }
  666. /**
  667. * Put the string properties for this Service in this Provider's
  668. * Hashtable.
  669. */
  670. private void putPropertyStrings(Service s) {
  671. String type = s.getType();
  672. String algorithm = s.getAlgorithm();
  673. // use super() to avoid permission check and other processing
  674. super.put(type + "." + algorithm, s.getClassName());
  675. for (String alias : s.getAliases()) {
  676. super.put(ALIAS_PREFIX + type + "." + alias, algorithm);
  677. }
  678. for (Map.Entry<String,String> entry : s.attributes.entrySet()) {
  679. String key = type + "." + algorithm + " " + entry.getKey();
  680. super.put(key, entry.getValue());
  681. }
  682. }
  683. /**
  684. * Remove the string properties for this Service from this Provider's
  685. * Hashtable.
  686. */
  687. private void removePropertyStrings(Service s) {
  688. String type = s.getType();
  689. String algorithm = s.getAlgorithm();
  690. // use super() to avoid permission check and other processing
  691. super.remove(type + "." + algorithm);
  692. for (String alias : s.getAliases()) {
  693. super.remove(ALIAS_PREFIX + type + "." + alias);
  694. }
  695. for (Map.Entry<String,String> entry : s.attributes.entrySet()) {
  696. String key = type + "." + algorithm + " " + entry.getKey();
  697. super.remove(key);
  698. }
  699. }
  700. /**
  701. * Remove a service previously added using
  702. * {@link #putService putService()}. The specified service is removed from
  703. * this provider. It will no longer be returned by
  704. * {@link #getService getService()} and its information will be removed
  705. * from this provider's Hashtable.
  706. *
  707. * <p>Also, if there is a security manager, its
  708. * <code>checkSecurityAccess</code> method is called with the string
  709. * <code>"removeProviderProperty."+name</code>, where <code>name</code> is
  710. * the provider name, to see if it's ok to remove this provider's
  711. * properties. If the default implementation of
  712. * <code>checkSecurityAccess</code> is used (that is, that method is not
  713. * overriden), then this results in a call to the security manager's
  714. * <code>checkPermission</code> method with a
  715. * <code>SecurityPermission("removeProviderProperty."+name)</code>
  716. * permission.
  717. *
  718. * @param s the Service to be removed
  719. *
  720. * @throws SecurityException
  721. * if a security manager exists and its <code>{@link
  722. * java.lang.SecurityManager#checkSecurityAccess}</code> method denies
  723. * access to remove this provider's properties.
  724. * @throws NullPointerException if s is null
  725. *
  726. * @since 1.5
  727. */
  728. protected synchronized void removeService(Service s) {
  729. check("removeProviderProperty." + name);
  730. if (debug != null) {
  731. debug.println(name + ".removeService(): " + s);
  732. }
  733. if (s == null) {
  734. throw new NullPointerException();
  735. }
  736. implRemoveService(s);
  737. }
  738. private void implRemoveService(Service s) {
  739. if ((s == null) || (serviceMap == null)) {
  740. return;
  741. }
  742. String type = s.getType();
  743. String algorithm = s.getAlgorithm();
  744. ServiceKey key = new ServiceKey(type, algorithm, false);
  745. Service oldService = serviceMap.get(key);
  746. if (s != oldService) {
  747. return;
  748. }
  749. servicesChanged = true;
  750. serviceMap.remove(key);
  751. for (String alias : s.getAliases()) {
  752. serviceMap.remove(new ServiceKey(type, alias, false));
  753. }
  754. removePropertyStrings(s);
  755. }
  756. /**
  757. * The description of a security service. It encapsulates the properties
  758. * of a service and contains a factory method to obtain new implementation
  759. * instances of this service.
  760. *
  761. * <p>Each service has a provider that offers the service, a type,
  762. * an algorithm name, and the name of the class that implements the
  763. * service. Optionally, it also includes a list of alternate algorithm
  764. * names for this service (aliases) and attributes, which are a map of
  765. * (name, value) String pairs.
  766. *
  767. * <p>This class defines the methods {@link #supportsParameter
  768. * supportsParameter()} and {@link #newInstance newInstance()}
  769. * which are used by the Java security framework when it searches for
  770. * suitable services and instantes them. The valid arguments to those
  771. * methods depend on the type of service. For the service types defined
  772. * within J2SE, see the
  773. * <a href="../../../guide/security/CryptoSpec.html">
  774. * Java Cryptography Architecture API Specification & Reference </a>
  775. * for the valid values.
  776. * Note that components outside of J2SE can define additional types of
  777. * services and their behavior.
  778. *
  779. * <p>Instances of this class are immutable.
  780. *
  781. * @since 1.5
  782. */
  783. public static class Service {
  784. private String type, algorithm, className;
  785. private final Provider provider;
  786. private List<String> aliases;
  787. private Map<String,String> attributes;
  788. // Reference to the cached implementation Class object
  789. private volatile Reference<Class> classRef;
  790. // flag indicating whether this service has its attributes for
  791. // supportedKeyFormats or supportedKeyClasses set
  792. // if null, the values have not been initialized
  793. // if TRUE, at least one of supportedFormats/Classes is non null
  794. private volatile Boolean hasKeyAttributes;
  795. // supported encoding formats
  796. private String[] supportedFormats;
  797. // names of the supported key (super) classes
  798. private Class[] supportedClasses;
  799. private static final Class[] CLASS0 = new Class[0];
  800. // this constructor and these methods are used for parsing
  801. // the legacy string properties.
  802. private Service(Provider provider) {
  803. this.provider = provider;
  804. aliases = Collections.<String>emptyList();
  805. attributes = Collections.<String,String>emptyMap();
  806. }
  807. private boolean isValid() {
  808. return (type != null) && (algorithm != null) && (className != null);
  809. }
  810. private void addAlias(String alias) {
  811. if (aliases == Collections.EMPTY_LIST) {
  812. aliases = new ArrayList<String>(2);
  813. }
  814. aliases.add(alias);
  815. }
  816. void addAttribute(String type, String value) {
  817. if (attributes == Collections.EMPTY_MAP) {
  818. attributes = new HashMap<String,String>(8);
  819. }
  820. attributes.put(type, value);
  821. }
  822. /**
  823. * Construct a new service.
  824. *
  825. * @param provider the provider that offers this service
  826. * @param type the type of this service
  827. * @param algorithm the algorithm name
  828. * @param className the name of the class implementing this service
  829. * @param aliases List of aliases or null if algorithm has no aliases
  830. * @param attributes Map of attributes or null if this implementation
  831. * has no attributes
  832. *
  833. * @throws NullPointerException if provider, type, algorithm, or
  834. * className is null
  835. */
  836. public Service(Provider provider, String type, String algorithm,
  837. String className, List<String> aliases,
  838. Map<String,String> attributes) {
  839. if ((provider == null) || (type == null) ||
  840. (algorithm == null) || (className == null)) {
  841. throw new NullPointerException();
  842. }
  843. this.provider = provider;
  844. this.type = type;
  845. this.algorithm = algorithm;
  846. this.className = className;
  847. if (aliases == null) {
  848. this.aliases = Collections.<String>emptyList();
  849. } else {
  850. this.aliases = new ArrayList<String>(aliases);
  851. }
  852. if (attributes == null) {
  853. this.attributes = Collections.<String,String>emptyMap();
  854. } else {
  855. this.attributes = new HashMap<String,String>(attributes);
  856. }
  857. }
  858. /**
  859. * Get the type of this service. For example, <code>MessageDigest</code>.
  860. *
  861. * @return the type of this service
  862. */
  863. public final String getType() {
  864. return type;
  865. }
  866. /**
  867. * Return the name of the algorithm of this service. For example,
  868. * <code>SHA-1</code>.
  869. *
  870. * @return the algorithm of this service
  871. */
  872. public final String getAlgorithm() {
  873. return algorithm;
  874. }
  875. /**
  876. * Return the Provider of this service.
  877. *
  878. * @return the Provider of this service
  879. */
  880. public final Provider getProvider() {
  881. return provider;
  882. }
  883. /**
  884. * Return the name of the class implementing this service.
  885. *
  886. * @return the name of the class implementing this service
  887. */
  888. public final String getClassName() {
  889. return className;
  890. }
  891. // internal only
  892. private final List<String> getAliases() {
  893. return aliases;
  894. }
  895. /**
  896. * Return the value of the specified attribute or null if this
  897. * attribute is not set for this Service.
  898. *
  899. * @param name the name of the requested attribute
  900. *
  901. * @return the value of the specified attribute or null if the
  902. * attribute is not present
  903. *
  904. * @throws NullPointerException if name is null
  905. */
  906. public final String getAttribute(String name) {
  907. if (name == null) {
  908. throw new NullPointerException();
  909. }
  910. return attributes.get(name);
  911. }
  912. // built in knowledge of the engine types shipped within J2SE
  913. // this is for the argument checks in the newInstance() and
  914. // supportsParameter() methods
  915. // Map<String,Object>
  916. private static final Map<String,Object> knownEngines;
  917. // use no-args constructor, supportsParameter() not used
  918. private static final Object S_NEITHER = "neither";
  919. // special constructor used, supportsParameter() not used
  920. private static final Object S_CONS = "constructor";
  921. // use no-args constructor, supportsParameter() IS used
  922. private static final Object S_SUPP = "supports";
  923. static {
  924. knownEngines = new HashMap<String,Object>();
  925. // JCA
  926. knownEngines.put("AlgorithmParameterGenerator", S_NEITHER);
  927. knownEngines.put("AlgorithmParameters", S_NEITHER);
  928. knownEngines.put("KeyFactory", S_NEITHER);
  929. knownEngines.put("KeyPairGenerator", S_NEITHER);
  930. knownEngines.put("KeyStore", S_NEITHER);
  931. knownEngines.put("MessageDigest", S_NEITHER);
  932. knownEngines.put("SecureRandom", S_NEITHER);
  933. knownEngines.put("Signature", S_SUPP);
  934. knownEngines.put("CertificateFactory", S_NEITHER);
  935. knownEngines.put("CertPathBuilder", S_NEITHER);
  936. knownEngines.put("CertPathValidator", S_NEITHER);
  937. knownEngines.put("CertStore", S_CONS);
  938. // JCE
  939. knownEngines.put("Cipher", S_SUPP);
  940. knownEngines.put("ExemptionMechanism", S_NEITHER);
  941. knownEngines.put("Mac", S_SUPP);
  942. knownEngines.put("KeyAgreement", S_SUPP);
  943. knownEngines.put("KeyGenerator", S_NEITHER);
  944. knownEngines.put("SecretKeyFactory", S_NEITHER);
  945. // JSSE
  946. knownEngines.put("KeyManagerFactory", S_NEITHER);
  947. knownEngines.put("SSLContext", S_NEITHER);
  948. knownEngines.put("TrustManagerFactory", S_NEITHER);
  949. // JGSS
  950. knownEngines.put("GssApiMechanism", S_NEITHER);
  951. // SASL
  952. knownEngines.put("SaslClientFactory", S_NEITHER);
  953. knownEngines.put("SaslServerFactory", S_NEITHER);
  954. }
  955. /**
  956. * Return a new instance of the implementation described by this
  957. * service. The security provider framework uses this method to
  958. * construct implementations. Applications will typically not need
  959. * to call it.
  960. *
  961. * <p>The default implementation uses reflection to invoke the
  962. * standard constructor for this type of service.
  963. * Security providers can override this method to implement
  964. * instantiation in a different way.
  965. * For details and the values of constructorParameter that are
  966. * valid for the various types of services see the
  967. * <a href="../../../guide/security/CryptoSpec.html">
  968. * Java Cryptography Architecture API Specification &
  969. * Reference</a>.
  970. *
  971. * @param constructorParameter the value to pass to the constructor,
  972. * or null if this type of service does not use a constructorParameter.
  973. *
  974. * @return a new implementation of this service
  975. *
  976. * @throws InvalidParameterException if the value of
  977. * constructorParameter is invalid for this type of service.
  978. * @throws NoSuchAlgorithmException if instantation failed for
  979. * any other reason.
  980. */
  981. public Object newInstance(Object constructorParameter)
  982. throws NoSuchAlgorithmException {
  983. try {
  984. Object cap = knownEngines.get(type);
  985. if (cap == null) {
  986. // unknown engine type, use generic code
  987. // this is the code path future for non-core
  988. // optional packages
  989. return newInstanceGeneric(constructorParameter);
  990. }
  991. if (cap != S_CONS) {
  992. if (constructorParameter != null) {
  993. throw new InvalidParameterException
  994. ("constructorParameter not used with " + type
  995. + " engines");
  996. }
  997. Class clazz = getImplClass();
  998. return clazz.newInstance();
  999. }
  1000. if (type.equals("CertStore") == false) {
  1001. throw new AssertionError("Unknown engine: " + type);
  1002. }
  1003. if (!(constructorParameter instanceof CertStoreParameters)) {
  1004. throw new InvalidParameterException
  1005. ("constructorParameter must be instanceof "
  1006. + "CertStoreParameters for CertStores");
  1007. }
  1008. Class clazz = getImplClass();
  1009. // use Class.forName() rather than .class to delay
  1010. // class loading
  1011. Constructor cons = clazz.getConstructor(new Class[]
  1012. { Class.forName("java.security.cert.CertStoreParameters") });
  1013. return cons.newInstance(new Object[] {constructorParameter});
  1014. } catch (NoSuchAlgorithmException e) {
  1015. throw e;
  1016. } catch (InvocationTargetException e) {
  1017. throw new NoSuchAlgorithmException
  1018. ("Error constructing implementation (algorithm: "
  1019. + algorithm + ", provider: " + provider.getName()
  1020. + ", class: " + className + ")", e.getCause());
  1021. } catch (Exception e) {
  1022. throw new NoSuchAlgorithmException
  1023. ("Error constructing implementation (algorithm: "
  1024. + algorithm + ", provider: " + provider.getName()
  1025. + ", class: " + className + ")", e);
  1026. }
  1027. }
  1028. // return the implementation Class object for this service
  1029. private Class getImplClass() throws NoSuchAlgorithmException {
  1030. try {
  1031. Reference<Class> ref = classRef;
  1032. Class clazz = (ref == null) ? null : ref.get();
  1033. if (clazz == null) {
  1034. ClassLoader cl = provider.getClass().getClassLoader();
  1035. if (cl == null) {
  1036. clazz = Class.forName(className);
  1037. } else {
  1038. clazz = cl.loadClass(className);
  1039. }
  1040. classRef = new WeakReference<Class>(clazz);
  1041. }
  1042. return clazz;
  1043. } catch (ClassNotFoundException e) {
  1044. throw new NoSuchAlgorithmException
  1045. ("class configured for " + type + "(provider: " +
  1046. provider.getName() + ")" + "cannot be found.", e);
  1047. }
  1048. }
  1049. /**
  1050. * Generic code path for unknown engine types. Call the
  1051. * no-args constructor if constructorParameter is null, otherwise
  1052. * use the first matching constructor.
  1053. */
  1054. private Object newInstanceGeneric(Object constructorParameter)
  1055. throws Exception {
  1056. Class clazz = getImplClass();
  1057. if (constructorParameter == null) {
  1058. Object o = clazz.newInstance();
  1059. return o;
  1060. }
  1061. Class argClass = constructorParameter.getClass();
  1062. Constructor[] cons = clazz.getConstructors();
  1063. // find first public constructor that can take the
  1064. // argument as parameter
  1065. for (int i = 0; i < cons.length; i++) {
  1066. Constructor con = cons[i];
  1067. Class[] paramTypes = con.getParameterTypes();
  1068. if (paramTypes.length != 1) {
  1069. continue;
  1070. }
  1071. if (paramTypes[0].isAssignableFrom(argClass) == false) {
  1072. continue;
  1073. }
  1074. Object o = con.newInstance(new Object[] {constructorParameter});
  1075. return o;
  1076. }
  1077. throw new NoSuchAlgorithmException("No constructor matching "
  1078. + argClass.getName() + " found in class " + className);
  1079. }
  1080. /**
  1081. * Test whether this Service can use the specified parameter.
  1082. * Returns false if this service cannot use the parameter. Returns
  1083. * true if this service can use the parameter, if a fast test is
  1084. * infeasible, or if the status is unknown.
  1085. *
  1086. * <p>The security provider framework uses this method with
  1087. * some types of services to quickly exclude non-matching
  1088. * implementations for consideration.
  1089. * Applications will typically not need to call it.
  1090. *
  1091. * <p>For details and the values of parameter that are valid for the
  1092. * various types of services see the top of this class and the
  1093. * <a href="../../../guide/security/CryptoSpec.html">
  1094. * Java Cryptography Architecture API Specification &
  1095. * Reference</a>.
  1096. * Security providers can override it to implement their own test.
  1097. *
  1098. * @param parameter the parameter to test
  1099. *
  1100. * @return false if this this service cannot use the specified
  1101. * parameter; true if it can possibly use the parameter
  1102. *
  1103. * @throws InvalidParameterException if the value of parameter is
  1104. * invalid for this type of service or if this method cannot be
  1105. * used with this type of service
  1106. */
  1107. public boolean supportsParameter(Object parameter) {
  1108. Object cap = knownEngines.get(type);
  1109. if (cap == null) {
  1110. // unknown engine type, return true by default
  1111. return true;
  1112. }
  1113. if (cap != S_SUPP) {
  1114. throw new InvalidParameterException("supportsParameter() not "
  1115. + "used with " + type + " engines");
  1116. }
  1117. // allow null for keys without attributes for compatibility
  1118. if ((parameter != null) && (parameter instanceof Key == false)) {
  1119. throw new InvalidParameterException
  1120. ("Parameter must be instanceof Key for engine " + type);
  1121. }
  1122. if (hasKeyAttributes() == false) {
  1123. return true;
  1124. }
  1125. if (parameter == null) {
  1126. return false;
  1127. }
  1128. Key key = (Key)parameter;
  1129. if (supportsKeyFormat(key)) {
  1130. return true;
  1131. }
  1132. if (supportsKeyClass(key)) {
  1133. return true;
  1134. }
  1135. return false;
  1136. }
  1137. /**
  1138. * Return whether this service has its Supported* properties for
  1139. * keys defined. Parses the attributes if not yet initialized.
  1140. */
  1141. private boolean hasKeyAttributes() {
  1142. Boolean b = hasKeyAttributes;
  1143. if (b == null) {
  1144. synchronized (this) {
  1145. String s;
  1146. s = getAttribute("SupportedKeyFormats");
  1147. if (s != null) {
  1148. supportedFormats = s.split("\\|");
  1149. }
  1150. s = getAttribute("SupportedKeyClasses");
  1151. if (s != null) {
  1152. String[] classNames = s.split("\\|");
  1153. List<Class> classList =
  1154. new ArrayList<Class>(classNames.length);
  1155. for (String className : classNames) {
  1156. Class clazz = getKeyClass(className);
  1157. if (clazz != null) {
  1158. classList.add(clazz);
  1159. }
  1160. }
  1161. supportedClasses = classList.toArray(CLASS0);
  1162. }
  1163. boolean bool = (supportedFormats != null)
  1164. || (supportedClasses != null);
  1165. b = Boolean.valueOf(bool);
  1166. hasKeyAttributes = b;
  1167. }
  1168. }
  1169. return b.booleanValue();
  1170. }
  1171. // get the key class object of the specified name
  1172. private Class getKeyClass(String name) {
  1173. try {
  1174. return Class.forName(name);
  1175. } catch (ClassNotFoundException e) {
  1176. // ignore
  1177. }
  1178. try {
  1179. ClassLoader cl = provider.getClass().getClassLoader();
  1180. if (cl != null) {
  1181. return cl.loadClass(name);
  1182. }
  1183. } catch (ClassNotFoundException e) {
  1184. // ignore
  1185. }
  1186. return null;
  1187. }
  1188. private boolean supportsKeyFormat(Key key) {
  1189. if (supportedFormats == null) {
  1190. return false;
  1191. }
  1192. String format = key.getFormat();
  1193. if (format == null) {
  1194. return false;
  1195. }
  1196. for (String supportedFormat : supportedFormats) {
  1197. if (supportedFormat.equals(format)) {
  1198. return true;
  1199. }
  1200. }
  1201. return false;
  1202. }
  1203. private boolean supportsKeyClass(Key key) {
  1204. if (supportedClasses == null) {
  1205. return false;
  1206. }
  1207. Class keyClass = key.getClass();
  1208. for (Class clazz : supportedClasses) {
  1209. if (clazz.isAssignableFrom(keyClass)) {
  1210. return true;
  1211. }
  1212. }
  1213. return false;
  1214. }
  1215. /**
  1216. * Return a String representation of this service.
  1217. *
  1218. * @return a String representation of this service.
  1219. */
  1220. public String toString() {
  1221. String aString = aliases.isEmpty()
  1222. ? "" : "\r\n aliases: " + aliases.toString();
  1223. String attrs = attributes.isEmpty()
  1224. ? "" : "\r\n attributes: " + attributes.toString();
  1225. return provider.getName() + ": " + type + "." + algorithm
  1226. + " -> " + className + aString + attrs + "\r\n";
  1227. }
  1228. }
  1229. }