0N/A/*
3909N/A * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.security;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.util.*;
0N/Aimport static java.util.Locale.ENGLISH;
0N/Aimport java.lang.ref.*;
0N/Aimport java.lang.reflect.*;
0N/A
0N/Aimport java.security.cert.CertStoreParameters;
0N/Aimport javax.security.auth.login.Configuration;
0N/A
0N/A/**
0N/A * This class represents a "provider" for the
0N/A * Java Security API, where a provider implements some or all parts of
0N/A * Java Security. Services that a provider may implement include:
0N/A *
0N/A * <ul>
0N/A *
0N/A * <li>Algorithms (such as DSA, RSA, MD5 or SHA-1).
0N/A *
0N/A * <li>Key generation, conversion, and management facilities (such as for
0N/A * algorithm-specific keys).
0N/A *
0N/A *</ul>
0N/A *
0N/A * <p>Each provider has a name and a version number, and is configured
0N/A * in each runtime it is installed in.
0N/A *
0N/A * <p>See <a href =
0N/A * "../../../technotes/guides/security/crypto/CryptoSpec.html#Provider">The Provider Class</a>
0N/A * in the "Java Cryptography Architecture API Specification &amp; Reference"
0N/A * for information about how a particular type of provider, the
0N/A * cryptographic service provider, works and is installed. However,
0N/A * please note that a provider can be used to implement any security
0N/A * service in Java that uses a pluggable architecture with a choice
0N/A * of implementations that fit underneath.
0N/A *
0N/A * <p>Some provider implementations may encounter unrecoverable internal
0N/A * errors during their operation, for example a failure to communicate with a
0N/A * security token. A {@link ProviderException} should be used to indicate
0N/A * such errors.
0N/A *
0N/A * <p>The service type <code>Provider</code> is reserved for use by the
0N/A * security framework. Services of this type cannot be added, removed,
0N/A * or modified by applications.
0N/A * The following attributes are automatically placed in each Provider object:
0N/A * <table cellspacing=4>
0N/A * <tr><th>Name</th><th>Value</th>
0N/A * <tr><td><code>Provider.id name</code></td>
0N/A * <td><code>String.valueOf(provider.getName())</code></td>
0N/A * <tr><td><code>Provider.id version</code></td>
0N/A * <td><code>String.valueOf(provider.getVersion())</code></td>
0N/A * <tr><td><code>Provider.id info</code></td>
0N/A <td><code>String.valueOf(provider.getInfo())</code></td>
0N/A * <tr><td><code>Provider.id className</code></td>
0N/A * <td><code>provider.getClass().getName()</code></td>
0N/A * </table>
0N/A *
0N/A * @author Benjamin Renaud
0N/A * @author Andreas Sterbenz
0N/A */
0N/Apublic abstract class Provider extends Properties {
0N/A
0N/A // Declare serialVersionUID to be compatible with JDK1.1
0N/A static final long serialVersionUID = -4298000515446427739L;
0N/A
0N/A private static final sun.security.util.Debug debug =
0N/A sun.security.util.Debug.getInstance
0N/A ("provider", "Provider");
0N/A
0N/A /**
0N/A * The provider name.
0N/A *
0N/A * @serial
0N/A */
0N/A private String name;
0N/A
0N/A /**
0N/A * A description of the provider and its services.
0N/A *
0N/A * @serial
0N/A */
0N/A private String info;
0N/A
0N/A /**
0N/A * The provider version number.
0N/A *
0N/A * @serial
0N/A */
0N/A private double version;
0N/A
0N/A
0N/A private transient Set<Map.Entry<Object,Object>> entrySet = null;
0N/A private transient int entrySetCallCount = 0;
0N/A
0N/A private transient boolean initialized;
0N/A
0N/A /**
0N/A * Constructs a provider with the specified name, version number,
0N/A * and information.
0N/A *
0N/A * @param name the provider name.
0N/A *
0N/A * @param version the provider version number.
0N/A *
0N/A * @param info a description of the provider and its services.
0N/A */
0N/A protected Provider(String name, double version, String info) {
0N/A this.name = name;
0N/A this.version = version;
0N/A this.info = info;
0N/A putId();
0N/A initialized = true;
0N/A }
0N/A
0N/A /**
0N/A * Returns the name of this provider.
0N/A *
0N/A * @return the name of this provider.
0N/A */
0N/A public String getName() {
0N/A return name;
0N/A }
0N/A
0N/A /**
0N/A * Returns the version number for this provider.
0N/A *
0N/A * @return the version number for this provider.
0N/A */
0N/A public double getVersion() {
0N/A return version;
0N/A }
0N/A
0N/A /**
0N/A * Returns a human-readable description of the provider and its
0N/A * services. This may return an HTML page, with relevant links.
0N/A *
0N/A * @return a description of the provider and its services.
0N/A */
0N/A public String getInfo() {
0N/A return info;
0N/A }
0N/A
0N/A /**
0N/A * Returns a string with the name and the version number
0N/A * of this provider.
0N/A *
0N/A * @return the string with the name and the version number
0N/A * for this provider.
0N/A */
0N/A public String toString() {
0N/A return name + " version " + version;
0N/A }
0N/A
0N/A /*
0N/A * override the following methods to ensure that provider
0N/A * information can only be changed if the caller has the appropriate
0N/A * permissions.
0N/A */
0N/A
0N/A /**
0N/A * Clears this provider so that it no longer contains the properties
0N/A * used to look up facilities implemented by the provider.
0N/A *
0N/A * <p>First, if there is a security manager, its
0N/A * <code>checkSecurityAccess</code> method is called with the string
0N/A * <code>"clearProviderProperties."+name</code> (where <code>name</code>
0N/A * is the provider name) to see if it's ok to clear this provider.
0N/A * If the default implementation of <code>checkSecurityAccess</code>
0N/A * is used (that is, that method is not overriden), then this results in
0N/A * a call to the security manager's <code>checkPermission</code> method
0N/A * with a <code>SecurityPermission("clearProviderProperties."+name)</code>
0N/A * permission.
0N/A *
0N/A * @throws SecurityException
0N/A * if a security manager exists and its <code>{@link
0N/A * java.lang.SecurityManager#checkSecurityAccess}</code> method
0N/A * denies access to clear this provider
0N/A *
0N/A * @since 1.2
0N/A */
0N/A public synchronized void clear() {
0N/A check("clearProviderProperties."+name);
0N/A if (debug != null) {
0N/A debug.println("Remove " + name + " provider properties");
0N/A }
0N/A implClear();
0N/A }
0N/A
0N/A /**
0N/A * Reads a property list (key and element pairs) from the input stream.
0N/A *
0N/A * @param inStream the input stream.
0N/A * @exception IOException if an error occurred when reading from the
0N/A * input stream.
0N/A * @see java.util.Properties#load
0N/A */
0N/A public synchronized void load(InputStream inStream) throws IOException {
0N/A check("putProviderProperty."+name);
0N/A if (debug != null) {
0N/A debug.println("Load " + name + " provider properties");
0N/A }
0N/A Properties tempProperties = new Properties();
0N/A tempProperties.load(inStream);
0N/A implPutAll(tempProperties);
0N/A }
0N/A
0N/A /**
0N/A * Copies all of the mappings from the specified Map to this provider.
0N/A * These mappings will replace any properties that this provider had
0N/A * for any of the keys currently in the specified Map.
0N/A *
0N/A * @since 1.2
0N/A */
0N/A public synchronized void putAll(Map<?,?> t) {
0N/A check("putProviderProperty."+name);
0N/A if (debug != null) {
0N/A debug.println("Put all " + name + " provider properties");
0N/A }
0N/A implPutAll(t);
0N/A }
0N/A
0N/A /**
0N/A * Returns an unmodifiable Set view of the property entries contained
0N/A * in this Provider.
0N/A *
0N/A * @see java.util.Map.Entry
0N/A * @since 1.2
0N/A */
0N/A public synchronized Set<Map.Entry<Object,Object>> entrySet() {
0N/A checkInitialized();
0N/A if (entrySet == null) {
0N/A if (entrySetCallCount++ == 0) // Initial call
0N/A entrySet = Collections.unmodifiableMap(this).entrySet();
0N/A else
0N/A return super.entrySet(); // Recursive call
0N/A }
0N/A
0N/A // This exception will be thrown if the implementation of
0N/A // Collections.unmodifiableMap.entrySet() is changed such that it
0N/A // no longer calls entrySet() on the backing Map. (Provider's
0N/A // entrySet implementation depends on this "implementation detail",
0N/A // which is unlikely to change.
0N/A if (entrySetCallCount != 2)
0N/A throw new RuntimeException("Internal error.");
0N/A
0N/A return entrySet;
0N/A }
0N/A
0N/A /**
0N/A * Returns an unmodifiable Set view of the property keys contained in
0N/A * this provider.
0N/A *
0N/A * @since 1.2
0N/A */
0N/A public Set<Object> keySet() {
0N/A checkInitialized();
0N/A return Collections.unmodifiableSet(super.keySet());
0N/A }
0N/A
0N/A /**
0N/A * Returns an unmodifiable Collection view of the property values
0N/A * contained in this provider.
0N/A *
0N/A * @since 1.2
0N/A */
0N/A public Collection<Object> values() {
0N/A checkInitialized();
0N/A return Collections.unmodifiableCollection(super.values());
0N/A }
0N/A
0N/A /**
0N/A * Sets the <code>key</code> property to have the specified
0N/A * <code>value</code>.
0N/A *
0N/A * <p>First, if there is a security manager, its
0N/A * <code>checkSecurityAccess</code> method is called with the string
0N/A * <code>"putProviderProperty."+name</code>, where <code>name</code> is the
0N/A * provider name, to see if it's ok to set this provider's property values.
0N/A * If the default implementation of <code>checkSecurityAccess</code>
0N/A * is used (that is, that method is not overriden), then this results in
0N/A * a call to the security manager's <code>checkPermission</code> method
0N/A * with a <code>SecurityPermission("putProviderProperty."+name)</code>
0N/A * permission.
0N/A *
0N/A * @param key the property key.
0N/A *
0N/A * @param value the property value.
0N/A *
0N/A * @return the previous value of the specified property
0N/A * (<code>key</code>), or null if it did not have one.
0N/A *
0N/A * @throws SecurityException
0N/A * if a security manager exists and its <code>{@link
0N/A * java.lang.SecurityManager#checkSecurityAccess}</code> method
0N/A * denies access to set property values.
0N/A *
0N/A * @since 1.2
0N/A */
0N/A public synchronized Object put(Object key, Object value) {
0N/A check("putProviderProperty."+name);
0N/A if (debug != null) {
0N/A debug.println("Set " + name + " provider property [" +
0N/A key + "/" + value +"]");
0N/A }
0N/A return implPut(key, value);
0N/A }
0N/A
0N/A /**
0N/A * Removes the <code>key</code> property (and its corresponding
0N/A * <code>value</code>).
0N/A *
0N/A * <p>First, if there is a security manager, its
0N/A * <code>checkSecurityAccess</code> method is called with the string
0N/A * <code>"removeProviderProperty."+name</code>, where <code>name</code> is
0N/A * the provider name, to see if it's ok to remove this provider's
0N/A * properties. If the default implementation of
0N/A * <code>checkSecurityAccess</code> is used (that is, that method is not
0N/A * overriden), then this results in a call to the security manager's
0N/A * <code>checkPermission</code> method with a
0N/A * <code>SecurityPermission("removeProviderProperty."+name)</code>
0N/A * permission.
0N/A *
0N/A * @param key the key for the property to be removed.
0N/A *
0N/A * @return the value to which the key had been mapped,
0N/A * or null if the key did not have a mapping.
0N/A *
0N/A * @throws SecurityException
0N/A * if a security manager exists and its <code>{@link
0N/A * java.lang.SecurityManager#checkSecurityAccess}</code> method
0N/A * denies access to remove this provider's properties.
0N/A *
0N/A * @since 1.2
0N/A */
0N/A public synchronized Object remove(Object key) {
0N/A check("removeProviderProperty."+name);
0N/A if (debug != null) {
0N/A debug.println("Remove " + name + " provider property " + key);
0N/A }
0N/A return implRemove(key);
0N/A }
0N/A
0N/A // let javadoc show doc from superclass
0N/A public Object get(Object key) {
0N/A checkInitialized();
0N/A return super.get(key);
0N/A }
0N/A
0N/A // let javadoc show doc from superclass
0N/A public Enumeration<Object> keys() {
0N/A checkInitialized();
0N/A return super.keys();
0N/A }
0N/A
0N/A // let javadoc show doc from superclass
0N/A public Enumeration<Object> elements() {
0N/A checkInitialized();
0N/A return super.elements();
0N/A }
0N/A
0N/A // let javadoc show doc from superclass
0N/A public String getProperty(String key) {
0N/A checkInitialized();
0N/A return super.getProperty(key);
0N/A }
0N/A
0N/A private void checkInitialized() {
0N/A if (!initialized) {
0N/A throw new IllegalStateException();
0N/A }
0N/A }
0N/A
0N/A private void check(String directive) {
0N/A checkInitialized();
0N/A SecurityManager security = System.getSecurityManager();
0N/A if (security != null) {
0N/A security.checkSecurityAccess(directive);
0N/A }
0N/A }
0N/A
0N/A // legacy properties changed since last call to any services method?
0N/A private transient boolean legacyChanged;
0N/A // serviceMap changed since last call to getServices()
0N/A private transient boolean servicesChanged;
0N/A
0N/A // Map<String,String>
0N/A private transient Map<String,String> legacyStrings;
0N/A
0N/A // Map<ServiceKey,Service>
0N/A // used for services added via putService(), initialized on demand
0N/A private transient Map<ServiceKey,Service> serviceMap;
0N/A
0N/A // Map<ServiceKey,Service>
0N/A // used for services added via legacy methods, init on demand
0N/A private transient Map<ServiceKey,Service> legacyMap;
0N/A
0N/A // Set<Service>
0N/A // Unmodifiable set of all services. Initialized on demand.
0N/A private transient Set<Service> serviceSet;
0N/A
0N/A // register the id attributes for this provider
0N/A // this is to ensure that equals() and hashCode() do not incorrectly
0N/A // report to different provider objects as the same
0N/A private void putId() {
0N/A // note: name and info may be null
0N/A super.put("Provider.id name", String.valueOf(name));
0N/A super.put("Provider.id version", String.valueOf(version));
0N/A super.put("Provider.id info", String.valueOf(info));
0N/A super.put("Provider.id className", this.getClass().getName());
0N/A }
0N/A
0N/A private void readObject(ObjectInputStream in)
0N/A throws IOException, ClassNotFoundException {
3381N/A Map<Object,Object> copy = new HashMap<>();
0N/A for (Map.Entry<Object,Object> entry : super.entrySet()) {
0N/A copy.put(entry.getKey(), entry.getValue());
0N/A }
0N/A defaults = null;
0N/A in.defaultReadObject();
0N/A implClear();
0N/A initialized = true;
0N/A putAll(copy);
0N/A }
0N/A
0N/A /**
0N/A * Copies all of the mappings from the specified Map to this provider.
0N/A * Internal method to be called AFTER the security check has been
0N/A * performed.
0N/A */
0N/A private void implPutAll(Map t) {
0N/A for (Map.Entry e : ((Map<?,?>)t).entrySet()) {
0N/A implPut(e.getKey(), e.getValue());
0N/A }
0N/A }
0N/A
0N/A private Object implRemove(Object key) {
0N/A if (key instanceof String) {
0N/A String keyString = (String)key;
0N/A if (keyString.startsWith("Provider.")) {
0N/A return null;
0N/A }
0N/A legacyChanged = true;
0N/A if (legacyStrings == null) {
0N/A legacyStrings = new LinkedHashMap<String,String>();
0N/A }
0N/A legacyStrings.remove(keyString);
0N/A }
0N/A return super.remove(key);
0N/A }
0N/A
0N/A private Object implPut(Object key, Object value) {
0N/A if ((key instanceof String) && (value instanceof String)) {
0N/A String keyString = (String)key;
0N/A if (keyString.startsWith("Provider.")) {
0N/A return null;
0N/A }
0N/A legacyChanged = true;
0N/A if (legacyStrings == null) {
0N/A legacyStrings = new LinkedHashMap<String,String>();
0N/A }
0N/A legacyStrings.put(keyString, (String)value);
0N/A }
0N/A return super.put(key, value);
0N/A }
0N/A
0N/A private void implClear() {
0N/A if (legacyStrings != null) {
0N/A legacyStrings.clear();
0N/A }
0N/A if (legacyMap != null) {
0N/A legacyMap.clear();
0N/A }
0N/A if (serviceMap != null) {
0N/A serviceMap.clear();
0N/A }
0N/A legacyChanged = false;
0N/A servicesChanged = false;
0N/A serviceSet = null;
0N/A super.clear();
0N/A putId();
0N/A }
0N/A
0N/A // used as key in the serviceMap and legacyMap HashMaps
0N/A private static class ServiceKey {
0N/A private final String type;
0N/A private final String algorithm;
0N/A private final String originalAlgorithm;
0N/A private ServiceKey(String type, String algorithm, boolean intern) {
0N/A this.type = type;
0N/A this.originalAlgorithm = algorithm;
0N/A algorithm = algorithm.toUpperCase(ENGLISH);
0N/A this.algorithm = intern ? algorithm.intern() : algorithm;
0N/A }
0N/A public int hashCode() {
0N/A return type.hashCode() + algorithm.hashCode();
0N/A }
0N/A public boolean equals(Object obj) {
0N/A if (this == obj) {
0N/A return true;
0N/A }
0N/A if (obj instanceof ServiceKey == false) {
0N/A return false;
0N/A }
0N/A ServiceKey other = (ServiceKey)obj;
0N/A return this.type.equals(other.type)
0N/A && this.algorithm.equals(other.algorithm);
0N/A }
0N/A boolean matches(String type, String algorithm) {
0N/A return (this.type == type) && (this.originalAlgorithm == algorithm);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Ensure all the legacy String properties are fully parsed into
0N/A * service objects.
0N/A */
0N/A private void ensureLegacyParsed() {
0N/A if ((legacyChanged == false) || (legacyStrings == null)) {
0N/A return;
0N/A }
0N/A serviceSet = null;
0N/A if (legacyMap == null) {
0N/A legacyMap = new LinkedHashMap<ServiceKey,Service>();
0N/A } else {
0N/A legacyMap.clear();
0N/A }
0N/A for (Map.Entry<String,String> entry : legacyStrings.entrySet()) {
0N/A parseLegacyPut(entry.getKey(), entry.getValue());
0N/A }
0N/A removeInvalidServices(legacyMap);
0N/A legacyChanged = false;
0N/A }
0N/A
0N/A /**
0N/A * Remove all invalid services from the Map. Invalid services can only
0N/A * occur if the legacy properties are inconsistent or incomplete.
0N/A */
0N/A private void removeInvalidServices(Map<ServiceKey,Service> map) {
0N/A for (Iterator t = map.entrySet().iterator(); t.hasNext(); ) {
0N/A Map.Entry entry = (Map.Entry)t.next();
0N/A Service s = (Service)entry.getValue();
0N/A if (s.isValid() == false) {
0N/A t.remove();
0N/A }
0N/A }
0N/A }
0N/A
0N/A private String[] getTypeAndAlgorithm(String key) {
0N/A int i = key.indexOf(".");
0N/A if (i < 1) {
0N/A if (debug != null) {
0N/A debug.println("Ignoring invalid entry in provider "
0N/A + name + ":" + key);
0N/A }
0N/A return null;
0N/A }
0N/A String type = key.substring(0, i);
0N/A String alg = key.substring(i + 1);
0N/A return new String[] {type, alg};
0N/A }
0N/A
0N/A private final static String ALIAS_PREFIX = "Alg.Alias.";
0N/A private final static String ALIAS_PREFIX_LOWER = "alg.alias.";
0N/A private final static int ALIAS_LENGTH = ALIAS_PREFIX.length();
0N/A
0N/A private void parseLegacyPut(String name, String value) {
0N/A if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
0N/A // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
0N/A // aliasKey ~ MessageDigest.SHA
0N/A String stdAlg = value;
0N/A String aliasKey = name.substring(ALIAS_LENGTH);
0N/A String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
0N/A if (typeAndAlg == null) {
0N/A return;
0N/A }
0N/A String type = getEngineName(typeAndAlg[0]);
0N/A String aliasAlg = typeAndAlg[1].intern();
0N/A ServiceKey key = new ServiceKey(type, stdAlg, true);
0N/A Service s = legacyMap.get(key);
0N/A if (s == null) {
0N/A s = new Service(this);
0N/A s.type = type;
0N/A s.algorithm = stdAlg;
0N/A legacyMap.put(key, s);
0N/A }
0N/A legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
0N/A s.addAlias(aliasAlg);
0N/A } else {
0N/A String[] typeAndAlg = getTypeAndAlgorithm(name);
0N/A if (typeAndAlg == null) {
0N/A return;
0N/A }
0N/A int i = typeAndAlg[1].indexOf(' ');
0N/A if (i == -1) {
0N/A // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
0N/A String type = getEngineName(typeAndAlg[0]);
0N/A String stdAlg = typeAndAlg[1].intern();
0N/A String className = value;
0N/A ServiceKey key = new ServiceKey(type, stdAlg, true);
0N/A Service s = legacyMap.get(key);
0N/A if (s == null) {
0N/A s = new Service(this);
0N/A s.type = type;
0N/A s.algorithm = stdAlg;
0N/A legacyMap.put(key, s);
0N/A }
0N/A s.className = className;
0N/A } else { // attribute
0N/A // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
0N/A String attributeValue = value;
0N/A String type = getEngineName(typeAndAlg[0]);
0N/A String attributeString = typeAndAlg[1];
0N/A String stdAlg = attributeString.substring(0, i).intern();
0N/A String attributeName = attributeString.substring(i + 1);
0N/A // kill additional spaces
0N/A while (attributeName.startsWith(" ")) {
0N/A attributeName = attributeName.substring(1);
0N/A }
0N/A attributeName = attributeName.intern();
0N/A ServiceKey key = new ServiceKey(type, stdAlg, true);
0N/A Service s = legacyMap.get(key);
0N/A if (s == null) {
0N/A s = new Service(this);
0N/A s.type = type;
0N/A s.algorithm = stdAlg;
0N/A legacyMap.put(key, s);
0N/A }
0N/A s.addAttribute(attributeName, attributeValue);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Get the service describing this Provider's implementation of the
0N/A * specified type of this algorithm or alias. If no such
0N/A * implementation exists, this method returns null. If there are two
0N/A * matching services, one added to this provider using
0N/A * {@link #putService putService()} and one added via {@link #put put()},
0N/A * the service added via {@link #putService putService()} is returned.
0N/A *
0N/A * @param type the type of {@link Service service} requested
0N/A * (for example, <code>MessageDigest</code>)
0N/A * @param algorithm the case insensitive algorithm name (or alternate
0N/A * alias) of the service requested (for example, <code>SHA-1</code>)
0N/A *
0N/A * @return the service describing this Provider's matching service
0N/A * or null if no such service exists
0N/A *
0N/A * @throws NullPointerException if type or algorithm is null
0N/A *
0N/A * @since 1.5
0N/A */
0N/A public synchronized Service getService(String type, String algorithm) {
0N/A checkInitialized();
0N/A // avoid allocating a new key object if possible
0N/A ServiceKey key = previousKey;
0N/A if (key.matches(type, algorithm) == false) {
0N/A key = new ServiceKey(type, algorithm, false);
0N/A previousKey = key;
0N/A }
0N/A if (serviceMap != null) {
0N/A Service service = serviceMap.get(key);
0N/A if (service != null) {
0N/A return service;
0N/A }
0N/A }
0N/A ensureLegacyParsed();
0N/A return (legacyMap != null) ? legacyMap.get(key) : null;
0N/A }
0N/A
0N/A // ServiceKey from previous getService() call
0N/A // by re-using it if possible we avoid allocating a new object
0N/A // and the toUpperCase() call.
0N/A // re-use will occur e.g. as the framework traverses the provider
0N/A // list and queries each provider with the same values until it finds
0N/A // a matching service
0N/A private static volatile ServiceKey previousKey =
0N/A new ServiceKey("", "", false);
0N/A
0N/A /**
0N/A * Get an unmodifiable Set of all services supported by
0N/A * this Provider.
0N/A *
0N/A * @return an unmodifiable Set of all services supported by
0N/A * this Provider
0N/A *
0N/A * @since 1.5
0N/A */
0N/A public synchronized Set<Service> getServices() {
0N/A checkInitialized();
0N/A if (legacyChanged || servicesChanged) {
0N/A serviceSet = null;
0N/A }
0N/A if (serviceSet == null) {
0N/A ensureLegacyParsed();
3381N/A Set<Service> set = new LinkedHashSet<>();
0N/A if (serviceMap != null) {
0N/A set.addAll(serviceMap.values());
0N/A }
0N/A if (legacyMap != null) {
0N/A set.addAll(legacyMap.values());
0N/A }
0N/A serviceSet = Collections.unmodifiableSet(set);
0N/A servicesChanged = false;
0N/A }
0N/A return serviceSet;
0N/A }
0N/A
0N/A /**
0N/A * Add a service. If a service of the same type with the same algorithm
0N/A * name exists and it was added using {@link #putService putService()},
0N/A * it is replaced by the new service.
0N/A * This method also places information about this service
0N/A * in the provider's Hashtable values in the format described in the
0N/A * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
0N/A * Java Cryptography Architecture API Specification &amp; Reference </a>.
0N/A *
0N/A * <p>Also, if there is a security manager, its
0N/A * <code>checkSecurityAccess</code> method is called with the string
0N/A * <code>"putProviderProperty."+name</code>, where <code>name</code> is
0N/A * the provider name, to see if it's ok to set this provider's property
0N/A * values. If the default implementation of <code>checkSecurityAccess</code>
0N/A * is used (that is, that method is not overriden), then this results in
0N/A * a call to the security manager's <code>checkPermission</code> method with
0N/A * a <code>SecurityPermission("putProviderProperty."+name)</code>
0N/A * permission.
0N/A *
0N/A * @param s the Service to add
0N/A *
0N/A * @throws SecurityException
0N/A * if a security manager exists and its <code>{@link
0N/A * java.lang.SecurityManager#checkSecurityAccess}</code> method denies
0N/A * access to set property values.
0N/A * @throws NullPointerException if s is null
0N/A *
0N/A * @since 1.5
0N/A */
0N/A protected synchronized void putService(Service s) {
0N/A check("putProviderProperty." + name);
0N/A if (debug != null) {
0N/A debug.println(name + ".putService(): " + s);
0N/A }
0N/A if (s == null) {
0N/A throw new NullPointerException();
0N/A }
0N/A if (s.getProvider() != this) {
0N/A throw new IllegalArgumentException
0N/A ("service.getProvider() must match this Provider object");
0N/A }
0N/A if (serviceMap == null) {
0N/A serviceMap = new LinkedHashMap<ServiceKey,Service>();
0N/A }
0N/A servicesChanged = true;
0N/A String type = s.getType();
0N/A String algorithm = s.getAlgorithm();
0N/A ServiceKey key = new ServiceKey(type, algorithm, true);
0N/A // remove existing service
0N/A implRemoveService(serviceMap.get(key));
0N/A serviceMap.put(key, s);
0N/A for (String alias : s.getAliases()) {
0N/A serviceMap.put(new ServiceKey(type, alias, true), s);
0N/A }
0N/A putPropertyStrings(s);
0N/A }
0N/A
0N/A /**
0N/A * Put the string properties for this Service in this Provider's
0N/A * Hashtable.
0N/A */
0N/A private void putPropertyStrings(Service s) {
0N/A String type = s.getType();
0N/A String algorithm = s.getAlgorithm();
0N/A // use super() to avoid permission check and other processing
0N/A super.put(type + "." + algorithm, s.getClassName());
0N/A for (String alias : s.getAliases()) {
0N/A super.put(ALIAS_PREFIX + type + "." + alias, algorithm);
0N/A }
0N/A for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
0N/A String key = type + "." + algorithm + " " + entry.getKey();
0N/A super.put(key, entry.getValue());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Remove the string properties for this Service from this Provider's
0N/A * Hashtable.
0N/A */
0N/A private void removePropertyStrings(Service s) {
0N/A String type = s.getType();
0N/A String algorithm = s.getAlgorithm();
0N/A // use super() to avoid permission check and other processing
0N/A super.remove(type + "." + algorithm);
0N/A for (String alias : s.getAliases()) {
0N/A super.remove(ALIAS_PREFIX + type + "." + alias);
0N/A }
0N/A for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
0N/A String key = type + "." + algorithm + " " + entry.getKey();
0N/A super.remove(key);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Remove a service previously added using
0N/A * {@link #putService putService()}. The specified service is removed from
0N/A * this provider. It will no longer be returned by
0N/A * {@link #getService getService()} and its information will be removed
0N/A * from this provider's Hashtable.
0N/A *
0N/A * <p>Also, if there is a security manager, its
0N/A * <code>checkSecurityAccess</code> method is called with the string
0N/A * <code>"removeProviderProperty."+name</code>, where <code>name</code> is
0N/A * the provider name, to see if it's ok to remove this provider's
0N/A * properties. If the default implementation of
0N/A * <code>checkSecurityAccess</code> is used (that is, that method is not
0N/A * overriden), then this results in a call to the security manager's
0N/A * <code>checkPermission</code> method with a
0N/A * <code>SecurityPermission("removeProviderProperty."+name)</code>
0N/A * permission.
0N/A *
0N/A * @param s the Service to be removed
0N/A *
0N/A * @throws SecurityException
0N/A * if a security manager exists and its <code>{@link
0N/A * java.lang.SecurityManager#checkSecurityAccess}</code> method denies
0N/A * access to remove this provider's properties.
0N/A * @throws NullPointerException if s is null
0N/A *
0N/A * @since 1.5
0N/A */
0N/A protected synchronized void removeService(Service s) {
0N/A check("removeProviderProperty." + name);
0N/A if (debug != null) {
0N/A debug.println(name + ".removeService(): " + s);
0N/A }
0N/A if (s == null) {
0N/A throw new NullPointerException();
0N/A }
0N/A implRemoveService(s);
0N/A }
0N/A
0N/A private void implRemoveService(Service s) {
0N/A if ((s == null) || (serviceMap == null)) {
0N/A return;
0N/A }
0N/A String type = s.getType();
0N/A String algorithm = s.getAlgorithm();
0N/A ServiceKey key = new ServiceKey(type, algorithm, false);
0N/A Service oldService = serviceMap.get(key);
0N/A if (s != oldService) {
0N/A return;
0N/A }
0N/A servicesChanged = true;
0N/A serviceMap.remove(key);
0N/A for (String alias : s.getAliases()) {
0N/A serviceMap.remove(new ServiceKey(type, alias, false));
0N/A }
0N/A removePropertyStrings(s);
0N/A }
0N/A
0N/A // Wrapped String that behaves in a case insensitive way for equals/hashCode
0N/A private static class UString {
0N/A final String string;
0N/A final String lowerString;
0N/A
0N/A UString(String s) {
0N/A this.string = s;
0N/A this.lowerString = s.toLowerCase(ENGLISH);
0N/A }
0N/A
0N/A public int hashCode() {
0N/A return lowerString.hashCode();
0N/A }
0N/A
0N/A public boolean equals(Object obj) {
0N/A if (this == obj) {
0N/A return true;
0N/A }
0N/A if (obj instanceof UString == false) {
0N/A return false;
0N/A }
0N/A UString other = (UString)obj;
0N/A return lowerString.equals(other.lowerString);
0N/A }
0N/A
0N/A public String toString() {
0N/A return string;
0N/A }
0N/A }
0N/A
0N/A // describe relevant properties of a type of engine
0N/A private static class EngineDescription {
0N/A final String name;
0N/A final boolean supportsParameter;
0N/A final String constructorParameterClassName;
0N/A private volatile Class constructorParameterClass;
0N/A
0N/A EngineDescription(String name, boolean sp, String paramName) {
0N/A this.name = name;
0N/A this.supportsParameter = sp;
0N/A this.constructorParameterClassName = paramName;
0N/A }
0N/A Class getConstructorParameterClass() throws ClassNotFoundException {
0N/A Class clazz = constructorParameterClass;
0N/A if (clazz == null) {
0N/A clazz = Class.forName(constructorParameterClassName);
0N/A constructorParameterClass = clazz;
0N/A }
0N/A return clazz;
0N/A }
0N/A }
0N/A
0N/A // built in knowledge of the engine types shipped as part of the JDK
0N/A private static final Map<String,EngineDescription> knownEngines;
0N/A
0N/A private static void addEngine(String name, boolean sp, String paramName) {
0N/A EngineDescription ed = new EngineDescription(name, sp, paramName);
0N/A // also index by canonical name to avoid toLowerCase() for some lookups
0N/A knownEngines.put(name.toLowerCase(ENGLISH), ed);
0N/A knownEngines.put(name, ed);
0N/A }
0N/A
0N/A static {
0N/A knownEngines = new HashMap<String,EngineDescription>();
0N/A // JCA
0N/A addEngine("AlgorithmParameterGenerator", false, null);
0N/A addEngine("AlgorithmParameters", false, null);
0N/A addEngine("KeyFactory", false, null);
0N/A addEngine("KeyPairGenerator", false, null);
0N/A addEngine("KeyStore", false, null);
0N/A addEngine("MessageDigest", false, null);
0N/A addEngine("SecureRandom", false, null);
0N/A addEngine("Signature", true, null);
0N/A addEngine("CertificateFactory", false, null);
0N/A addEngine("CertPathBuilder", false, null);
0N/A addEngine("CertPathValidator", false, null);
0N/A addEngine("CertStore", false,
0N/A "java.security.cert.CertStoreParameters");
0N/A // JCE
0N/A addEngine("Cipher", true, null);
0N/A addEngine("ExemptionMechanism", false, null);
0N/A addEngine("Mac", true, null);
0N/A addEngine("KeyAgreement", true, null);
0N/A addEngine("KeyGenerator", false, null);
0N/A addEngine("SecretKeyFactory", false, null);
0N/A // JSSE
0N/A addEngine("KeyManagerFactory", false, null);
0N/A addEngine("SSLContext", false, null);
0N/A addEngine("TrustManagerFactory", false, null);
0N/A // JGSS
0N/A addEngine("GssApiMechanism", false, null);
0N/A // SASL
0N/A addEngine("SaslClientFactory", false, null);
0N/A addEngine("SaslServerFactory", false, null);
0N/A // POLICY
0N/A addEngine("Policy", false,
0N/A "java.security.Policy$Parameters");
0N/A // CONFIGURATION
0N/A addEngine("Configuration", false,
0N/A "javax.security.auth.login.Configuration$Parameters");
0N/A // XML DSig
0N/A addEngine("XMLSignatureFactory", false, null);
0N/A addEngine("KeyInfoFactory", false, null);
0N/A addEngine("TransformService", false, null);
0N/A // Smart Card I/O
0N/A addEngine("TerminalFactory", false,
0N/A "java.lang.Object");
0N/A }
0N/A
0N/A // get the "standard" (mixed-case) engine name for arbitary case engine name
0N/A // if there is no known engine by that name, return s
0N/A private static String getEngineName(String s) {
0N/A // try original case first, usually correct
0N/A EngineDescription e = knownEngines.get(s);
0N/A if (e == null) {
0N/A e = knownEngines.get(s.toLowerCase(ENGLISH));
0N/A }
0N/A return (e == null) ? s : e.name;
0N/A }
0N/A
0N/A /**
0N/A * The description of a security service. It encapsulates the properties
0N/A * of a service and contains a factory method to obtain new implementation
0N/A * instances of this service.
0N/A *
0N/A * <p>Each service has a provider that offers the service, a type,
0N/A * an algorithm name, and the name of the class that implements the
0N/A * service. Optionally, it also includes a list of alternate algorithm
0N/A * names for this service (aliases) and attributes, which are a map of
0N/A * (name, value) String pairs.
0N/A *
0N/A * <p>This class defines the methods {@link #supportsParameter
0N/A * supportsParameter()} and {@link #newInstance newInstance()}
0N/A * which are used by the Java security framework when it searches for
0N/A * suitable services and instantes them. The valid arguments to those
0N/A * methods depend on the type of service. For the service types defined
0N/A * within Java SE, see the
0N/A * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
0N/A * Java Cryptography Architecture API Specification &amp; Reference </a>
0N/A * for the valid values.
0N/A * Note that components outside of Java SE can define additional types of
0N/A * services and their behavior.
0N/A *
0N/A * <p>Instances of this class are immutable.
0N/A *
0N/A * @since 1.5
0N/A */
0N/A public static class Service {
0N/A
0N/A private String type, algorithm, className;
0N/A private final Provider provider;
0N/A private List<String> aliases;
0N/A private Map<UString,String> attributes;
0N/A
0N/A // Reference to the cached implementation Class object
0N/A private volatile Reference<Class> classRef;
0N/A
0N/A // flag indicating whether this service has its attributes for
0N/A // supportedKeyFormats or supportedKeyClasses set
0N/A // if null, the values have not been initialized
0N/A // if TRUE, at least one of supportedFormats/Classes is non null
0N/A private volatile Boolean hasKeyAttributes;
0N/A
0N/A // supported encoding formats
0N/A private String[] supportedFormats;
0N/A
0N/A // names of the supported key (super) classes
0N/A private Class[] supportedClasses;
0N/A
0N/A // whether this service has been registered with the Provider
0N/A private boolean registered;
0N/A
0N/A private static final Class[] CLASS0 = new Class[0];
0N/A
0N/A // this constructor and these methods are used for parsing
0N/A // the legacy string properties.
0N/A
0N/A private Service(Provider provider) {
0N/A this.provider = provider;
0N/A aliases = Collections.<String>emptyList();
0N/A attributes = Collections.<UString,String>emptyMap();
0N/A }
0N/A
0N/A private boolean isValid() {
0N/A return (type != null) && (algorithm != null) && (className != null);
0N/A }
0N/A
0N/A private void addAlias(String alias) {
0N/A if (aliases.isEmpty()) {
0N/A aliases = new ArrayList<String>(2);
0N/A }
0N/A aliases.add(alias);
0N/A }
0N/A
0N/A void addAttribute(String type, String value) {
0N/A if (attributes.isEmpty()) {
0N/A attributes = new HashMap<UString,String>(8);
0N/A }
0N/A attributes.put(new UString(type), value);
0N/A }
0N/A
0N/A /**
0N/A * Construct a new service.
0N/A *
0N/A * @param provider the provider that offers this service
0N/A * @param type the type of this service
0N/A * @param algorithm the algorithm name
0N/A * @param className the name of the class implementing this service
0N/A * @param aliases List of aliases or null if algorithm has no aliases
0N/A * @param attributes Map of attributes or null if this implementation
0N/A * has no attributes
0N/A *
0N/A * @throws NullPointerException if provider, type, algorithm, or
0N/A * className is null
0N/A */
0N/A public Service(Provider provider, String type, String algorithm,
0N/A String className, List<String> aliases,
0N/A Map<String,String> attributes) {
0N/A if ((provider == null) || (type == null) ||
0N/A (algorithm == null) || (className == null)) {
0N/A throw new NullPointerException();
0N/A }
0N/A this.provider = provider;
0N/A this.type = getEngineName(type);
0N/A this.algorithm = algorithm;
0N/A this.className = className;
0N/A if (aliases == null) {
0N/A this.aliases = Collections.<String>emptyList();
0N/A } else {
0N/A this.aliases = new ArrayList<String>(aliases);
0N/A }
0N/A if (attributes == null) {
0N/A this.attributes = Collections.<UString,String>emptyMap();
0N/A } else {
0N/A this.attributes = new HashMap<UString,String>();
0N/A for (Map.Entry<String,String> entry : attributes.entrySet()) {
0N/A this.attributes.put(new UString(entry.getKey()), entry.getValue());
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Get the type of this service. For example, <code>MessageDigest</code>.
0N/A *
0N/A * @return the type of this service
0N/A */
0N/A public final String getType() {
0N/A return type;
0N/A }
0N/A
0N/A /**
0N/A * Return the name of the algorithm of this service. For example,
0N/A * <code>SHA-1</code>.
0N/A *
0N/A * @return the algorithm of this service
0N/A */
0N/A public final String getAlgorithm() {
0N/A return algorithm;
0N/A }
0N/A
0N/A /**
0N/A * Return the Provider of this service.
0N/A *
0N/A * @return the Provider of this service
0N/A */
0N/A public final Provider getProvider() {
0N/A return provider;
0N/A }
0N/A
0N/A /**
0N/A * Return the name of the class implementing this service.
0N/A *
0N/A * @return the name of the class implementing this service
0N/A */
0N/A public final String getClassName() {
0N/A return className;
0N/A }
0N/A
0N/A // internal only
0N/A private final List<String> getAliases() {
0N/A return aliases;
0N/A }
0N/A
0N/A /**
0N/A * Return the value of the specified attribute or null if this
0N/A * attribute is not set for this Service.
0N/A *
0N/A * @param name the name of the requested attribute
0N/A *
0N/A * @return the value of the specified attribute or null if the
0N/A * attribute is not present
0N/A *
0N/A * @throws NullPointerException if name is null
0N/A */
0N/A public final String getAttribute(String name) {
0N/A if (name == null) {
0N/A throw new NullPointerException();
0N/A }
0N/A return attributes.get(new UString(name));
0N/A }
0N/A
0N/A /**
0N/A * Return a new instance of the implementation described by this
0N/A * service. The security provider framework uses this method to
0N/A * construct implementations. Applications will typically not need
0N/A * to call it.
0N/A *
0N/A * <p>The default implementation uses reflection to invoke the
0N/A * standard constructor for this type of service.
0N/A * Security providers can override this method to implement
0N/A * instantiation in a different way.
0N/A * For details and the values of constructorParameter that are
0N/A * valid for the various types of services see the
0N/A * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
0N/A * Java Cryptography Architecture API Specification &amp;
0N/A * Reference</a>.
0N/A *
0N/A * @param constructorParameter the value to pass to the constructor,
0N/A * or null if this type of service does not use a constructorParameter.
0N/A *
0N/A * @return a new implementation of this service
0N/A *
0N/A * @throws InvalidParameterException if the value of
0N/A * constructorParameter is invalid for this type of service.
0N/A * @throws NoSuchAlgorithmException if instantation failed for
0N/A * any other reason.
0N/A */
0N/A public Object newInstance(Object constructorParameter)
0N/A throws NoSuchAlgorithmException {
0N/A if (registered == false) {
0N/A if (provider.getService(type, algorithm) != this) {
0N/A throw new NoSuchAlgorithmException
0N/A ("Service not registered with Provider "
0N/A + provider.getName() + ": " + this);
0N/A }
0N/A registered = true;
0N/A }
0N/A try {
0N/A EngineDescription cap = knownEngines.get(type);
0N/A if (cap == null) {
0N/A // unknown engine type, use generic code
0N/A // this is the code path future for non-core
0N/A // optional packages
0N/A return newInstanceGeneric(constructorParameter);
0N/A }
0N/A if (cap.constructorParameterClassName == null) {
0N/A if (constructorParameter != null) {
0N/A throw new InvalidParameterException
0N/A ("constructorParameter not used with " + type
0N/A + " engines");
0N/A }
0N/A Class clazz = getImplClass();
0N/A return clazz.newInstance();
0N/A } else {
0N/A Class paramClass = cap.getConstructorParameterClass();
0N/A if (constructorParameter != null) {
0N/A Class argClass = constructorParameter.getClass();
0N/A if (paramClass.isAssignableFrom(argClass) == false) {
0N/A throw new InvalidParameterException
0N/A ("constructorParameter must be instanceof "
0N/A + cap.constructorParameterClassName.replace('$', '.')
0N/A + " for engine type " + type);
0N/A }
0N/A }
0N/A Class clazz = getImplClass();
0N/A Constructor cons = clazz.getConstructor(paramClass);
0N/A return cons.newInstance(constructorParameter);
0N/A }
0N/A } catch (NoSuchAlgorithmException e) {
0N/A throw e;
0N/A } catch (InvocationTargetException e) {
0N/A throw new NoSuchAlgorithmException
0N/A ("Error constructing implementation (algorithm: "
0N/A + algorithm + ", provider: " + provider.getName()
0N/A + ", class: " + className + ")", e.getCause());
0N/A } catch (Exception e) {
0N/A throw new NoSuchAlgorithmException
0N/A ("Error constructing implementation (algorithm: "
0N/A + algorithm + ", provider: " + provider.getName()
0N/A + ", class: " + className + ")", e);
0N/A }
0N/A }
0N/A
0N/A // return the implementation Class object for this service
0N/A private Class getImplClass() throws NoSuchAlgorithmException {
0N/A try {
0N/A Reference<Class> ref = classRef;
0N/A Class clazz = (ref == null) ? null : ref.get();
0N/A if (clazz == null) {
0N/A ClassLoader cl = provider.getClass().getClassLoader();
0N/A if (cl == null) {
0N/A clazz = Class.forName(className);
0N/A } else {
0N/A clazz = cl.loadClass(className);
0N/A }
0N/A classRef = new WeakReference<Class>(clazz);
0N/A }
0N/A return clazz;
0N/A } catch (ClassNotFoundException e) {
0N/A throw new NoSuchAlgorithmException
0N/A ("class configured for " + type + "(provider: " +
0N/A provider.getName() + ")" + "cannot be found.", e);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Generic code path for unknown engine types. Call the
0N/A * no-args constructor if constructorParameter is null, otherwise
0N/A * use the first matching constructor.
0N/A */
0N/A private Object newInstanceGeneric(Object constructorParameter)
0N/A throws Exception {
0N/A Class clazz = getImplClass();
0N/A if (constructorParameter == null) {
0N/A Object o = clazz.newInstance();
0N/A return o;
0N/A }
0N/A Class argClass = constructorParameter.getClass();
0N/A Constructor[] cons = clazz.getConstructors();
0N/A // find first public constructor that can take the
0N/A // argument as parameter
0N/A for (int i = 0; i < cons.length; i++) {
0N/A Constructor con = cons[i];
0N/A Class[] paramTypes = con.getParameterTypes();
0N/A if (paramTypes.length != 1) {
0N/A continue;
0N/A }
0N/A if (paramTypes[0].isAssignableFrom(argClass) == false) {
0N/A continue;
0N/A }
0N/A Object o = con.newInstance(new Object[] {constructorParameter});
0N/A return o;
0N/A }
0N/A throw new NoSuchAlgorithmException("No constructor matching "
0N/A + argClass.getName() + " found in class " + className);
0N/A }
0N/A
0N/A /**
0N/A * Test whether this Service can use the specified parameter.
0N/A * Returns false if this service cannot use the parameter. Returns
0N/A * true if this service can use the parameter, if a fast test is
0N/A * infeasible, or if the status is unknown.
0N/A *
0N/A * <p>The security provider framework uses this method with
0N/A * some types of services to quickly exclude non-matching
0N/A * implementations for consideration.
0N/A * Applications will typically not need to call it.
0N/A *
0N/A * <p>For details and the values of parameter that are valid for the
0N/A * various types of services see the top of this class and the
0N/A * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
0N/A * Java Cryptography Architecture API Specification &amp;
0N/A * Reference</a>.
0N/A * Security providers can override it to implement their own test.
0N/A *
0N/A * @param parameter the parameter to test
0N/A *
0N/A * @return false if this this service cannot use the specified
0N/A * parameter; true if it can possibly use the parameter
0N/A *
0N/A * @throws InvalidParameterException if the value of parameter is
0N/A * invalid for this type of service or if this method cannot be
0N/A * used with this type of service
0N/A */
0N/A public boolean supportsParameter(Object parameter) {
0N/A EngineDescription cap = knownEngines.get(type);
0N/A if (cap == null) {
0N/A // unknown engine type, return true by default
0N/A return true;
0N/A }
0N/A if (cap.supportsParameter == false) {
0N/A throw new InvalidParameterException("supportsParameter() not "
0N/A + "used with " + type + " engines");
0N/A }
0N/A // allow null for keys without attributes for compatibility
0N/A if ((parameter != null) && (parameter instanceof Key == false)) {
0N/A throw new InvalidParameterException
0N/A ("Parameter must be instanceof Key for engine " + type);
0N/A }
0N/A if (hasKeyAttributes() == false) {
0N/A return true;
0N/A }
0N/A if (parameter == null) {
0N/A return false;
0N/A }
0N/A Key key = (Key)parameter;
0N/A if (supportsKeyFormat(key)) {
0N/A return true;
0N/A }
0N/A if (supportsKeyClass(key)) {
0N/A return true;
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Return whether this service has its Supported* properties for
0N/A * keys defined. Parses the attributes if not yet initialized.
0N/A */
0N/A private boolean hasKeyAttributes() {
0N/A Boolean b = hasKeyAttributes;
0N/A if (b == null) {
0N/A synchronized (this) {
0N/A String s;
0N/A s = getAttribute("SupportedKeyFormats");
0N/A if (s != null) {
0N/A supportedFormats = s.split("\\|");
0N/A }
0N/A s = getAttribute("SupportedKeyClasses");
0N/A if (s != null) {
0N/A String[] classNames = s.split("\\|");
0N/A List<Class> classList =
3381N/A new ArrayList<>(classNames.length);
0N/A for (String className : classNames) {
0N/A Class clazz = getKeyClass(className);
0N/A if (clazz != null) {
0N/A classList.add(clazz);
0N/A }
0N/A }
0N/A supportedClasses = classList.toArray(CLASS0);
0N/A }
0N/A boolean bool = (supportedFormats != null)
0N/A || (supportedClasses != null);
0N/A b = Boolean.valueOf(bool);
0N/A hasKeyAttributes = b;
0N/A }
0N/A }
0N/A return b.booleanValue();
0N/A }
0N/A
0N/A // get the key class object of the specified name
0N/A private Class getKeyClass(String name) {
0N/A try {
0N/A return Class.forName(name);
0N/A } catch (ClassNotFoundException e) {
0N/A // ignore
0N/A }
0N/A try {
0N/A ClassLoader cl = provider.getClass().getClassLoader();
0N/A if (cl != null) {
0N/A return cl.loadClass(name);
0N/A }
0N/A } catch (ClassNotFoundException e) {
0N/A // ignore
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A private boolean supportsKeyFormat(Key key) {
0N/A if (supportedFormats == null) {
0N/A return false;
0N/A }
0N/A String format = key.getFormat();
0N/A if (format == null) {
0N/A return false;
0N/A }
0N/A for (String supportedFormat : supportedFormats) {
0N/A if (supportedFormat.equals(format)) {
0N/A return true;
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A private boolean supportsKeyClass(Key key) {
0N/A if (supportedClasses == null) {
0N/A return false;
0N/A }
0N/A Class keyClass = key.getClass();
0N/A for (Class clazz : supportedClasses) {
0N/A if (clazz.isAssignableFrom(keyClass)) {
0N/A return true;
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Return a String representation of this service.
0N/A *
0N/A * @return a String representation of this service.
0N/A */
0N/A public String toString() {
0N/A String aString = aliases.isEmpty()
0N/A ? "" : "\r\n aliases: " + aliases.toString();
0N/A String attrs = attributes.isEmpty()
0N/A ? "" : "\r\n attributes: " + attributes.toString();
0N/A return provider.getName() + ": " + type + "." + algorithm
0N/A + " -> " + className + aString + attrs + "\r\n";
0N/A }
0N/A
0N/A }
0N/A
0N/A}