Path: blob/master/src/java.base/share/classes/sun/security/jca/ProviderConfig.java
41159 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.jca;2627import java.io.File;28import java.lang.reflect.*;29import java.util.*;3031import java.security.*;3233import sun.security.util.PropertyExpander;3435/**36* Class representing a configured provider which encapsulates configuration37* (provider name + optional argument), the provider loading logic, and38* the loaded Provider object itself.39*40* @author Andreas Sterbenz41* @since 1.542*/43final class ProviderConfig {4445private static final sun.security.util.Debug debug =46sun.security.util.Debug.getInstance("jca", "ProviderConfig");4748// suffix for identifying the SunPKCS11-Solaris provider49private static final String P11_SOL_NAME = "SunPKCS11";5051// config file argument of the SunPKCS11-Solaris provider52private static final String P11_SOL_ARG =53"${java.home}/conf/security/sunpkcs11-solaris.cfg";5455// maximum number of times to try loading a provider before giving up56private static final int MAX_LOAD_TRIES = 30;5758// could be provider name (module) or provider class name (legacy)59private final String provName;6061// argument to the Provider.configure() call, never null62private final String argument;6364// number of times we have already tried to load this provider65private int tries;6667// Provider object, if loaded68private volatile Provider provider;6970// flag indicating if we are currently trying to load the provider71// used to detect recursion72private boolean isLoading;7374ProviderConfig(String provName, String argument) {75if (provName.endsWith(P11_SOL_NAME) && argument.equals(P11_SOL_ARG)) {76checkSunPKCS11Solaris();77}78this.provName = provName;79this.argument = expand(argument);80}8182ProviderConfig(String provName) {83this(provName, "");84}8586ProviderConfig(Provider provider) {87this.provName = provider.getName();88this.argument = "";89this.provider = provider;90}9192// check if we should try to load the SunPKCS11-Solaris provider93// avoid if not available (pre Solaris 10) to reduce startup time94// or if disabled via system property95private void checkSunPKCS11Solaris() {96@SuppressWarnings("removal")97Boolean o = AccessController.doPrivileged(98new PrivilegedAction<Boolean>() {99public Boolean run() {100File file = new File("/usr/lib/libpkcs11.so");101if (file.exists() == false) {102return Boolean.FALSE;103}104if ("false".equalsIgnoreCase(System.getProperty105("sun.security.pkcs11.enable-solaris"))) {106return Boolean.FALSE;107}108return Boolean.TRUE;109}110});111if (o == Boolean.FALSE) {112tries = MAX_LOAD_TRIES;113}114}115116private boolean hasArgument() {117return !argument.isEmpty();118}119120// should we try to load this provider?121private boolean shouldLoad() {122return (tries < MAX_LOAD_TRIES);123}124125// do not try to load this provider again126private void disableLoad() {127tries = MAX_LOAD_TRIES;128}129130boolean isLoaded() {131return (provider != null);132}133134public boolean equals(Object obj) {135if (this == obj) {136return true;137}138if (obj instanceof ProviderConfig == false) {139return false;140}141ProviderConfig other = (ProviderConfig)obj;142return this.provName.equals(other.provName)143&& this.argument.equals(other.argument);144145}146147public int hashCode() {148return provName.hashCode() + argument.hashCode();149}150151public String toString() {152if (hasArgument()) {153return provName + "('" + argument + "')";154} else {155return provName;156}157}158159/**160* Get the provider object. Loads the provider if it is not already loaded.161*/162@SuppressWarnings("deprecation")163Provider getProvider() {164// volatile variable load165Provider p = provider;166if (p != null) {167return p;168}169// DCL170synchronized (this) {171p = provider;172if (p != null) {173return p;174}175if (shouldLoad() == false) {176return null;177}178179// Create providers which are in java.base directly180if (provName.equals("SUN") || provName.equals("sun.security.provider.Sun")) {181p = new sun.security.provider.Sun();182} else if (provName.equals("SunRsaSign") || provName.equals("sun.security.rsa.SunRsaSign")) {183p = new sun.security.rsa.SunRsaSign();184} else if (provName.equals("SunJCE") || provName.equals("com.sun.crypto.provider.SunJCE")) {185p = new com.sun.crypto.provider.SunJCE();186} else if (provName.equals("SunJSSE")) {187p = new sun.security.ssl.SunJSSE();188} else if (provName.equals("Apple") || provName.equals("apple.security.AppleProvider")) {189// need to use reflection since this class only exists on MacOsx190@SuppressWarnings("removal")191var tmp = AccessController.doPrivileged(new PrivilegedAction<Provider>() {192public Provider run() {193try {194Class<?> c = Class.forName("apple.security.AppleProvider");195if (Provider.class.isAssignableFrom(c)) {196@SuppressWarnings("deprecation")197Object tmp = c.newInstance();198return (Provider) tmp;199} else {200return null;201}202} catch (Exception ex) {203if (debug != null) {204debug.println("Error loading provider Apple");205ex.printStackTrace();206}207return null;208}209}210});211p = tmp;212} else {213if (isLoading) {214// because this method is synchronized, this can only215// happen if there is recursion.216if (debug != null) {217debug.println("Recursion loading provider: " + this);218new Exception("Call trace").printStackTrace();219}220return null;221}222try {223isLoading = true;224tries++;225p = doLoadProvider();226} finally {227isLoading = false;228}229}230provider = p;231}232return p;233}234235/**236* Load and instantiate the Provider described by this class.237*238* NOTE use of doPrivileged().239*240* @return null if the Provider could not be loaded241*242* @throws ProviderException if executing the Provider's constructor243* throws a ProviderException. All other Exceptions are ignored.244*/245@SuppressWarnings("removal")246private Provider doLoadProvider() {247return AccessController.doPrivileged(new PrivilegedAction<Provider>() {248public Provider run() {249if (debug != null) {250debug.println("Loading provider " + ProviderConfig.this);251}252try {253Provider p = ProviderLoader.INSTANCE.load(provName);254if (p != null) {255if (hasArgument()) {256p = p.configure(argument);257}258if (debug != null) {259debug.println("Loaded provider " + p.getName());260}261} else {262if (debug != null) {263debug.println("Error loading provider " +264ProviderConfig.this);265}266disableLoad();267}268return p;269} catch (Exception e) {270if (e instanceof ProviderException) {271// pass up272throw e;273} else {274if (debug != null) {275debug.println("Error loading provider " +276ProviderConfig.this);277e.printStackTrace();278}279disableLoad();280return null;281}282} catch (ExceptionInInitializerError err) {283// no sufficient permission to initialize provider class284if (debug != null) {285debug.println("Error loading provider " + ProviderConfig.this);286err.printStackTrace();287}288disableLoad();289return null;290}291}292});293}294295/**296* Perform property expansion of the provider value.297*298* NOTE use of doPrivileged().299*/300@SuppressWarnings("removal")301private static String expand(final String value) {302// shortcut if value does not contain any properties303if (value.contains("${") == false) {304return value;305}306return AccessController.doPrivileged(new PrivilegedAction<String>() {307public String run() {308try {309return PropertyExpander.expand(value);310} catch (GeneralSecurityException e) {311throw new ProviderException(e);312}313}314});315}316317// Inner class for loading security providers listed in java.security file318private static final class ProviderLoader {319static final ProviderLoader INSTANCE = new ProviderLoader();320321private final ServiceLoader<Provider> services;322323private ProviderLoader() {324// VM should already been booted at this point, if not325// - Only providers in java.base should be loaded, don't use326// ServiceLoader327// - ClassLoader.getSystemClassLoader() will throw InternalError328services = ServiceLoader.load(java.security.Provider.class,329ClassLoader.getSystemClassLoader());330}331332/**333* Loads the provider with the specified class name.334*335* @param pn the name of the provider336* @return the Provider, or null if it cannot be found or loaded337* @throws ProviderException all other exceptions are ignored338*/339public Provider load(String pn) {340if (debug != null) {341debug.println("Attempt to load " + pn + " using SL");342}343Iterator<Provider> iter = services.iterator();344while (iter.hasNext()) {345try {346Provider p = iter.next();347String pName = p.getName();348if (debug != null) {349debug.println("Found SL Provider named " + pName);350}351if (pName.equals(pn)) {352return p;353}354} catch (SecurityException | ServiceConfigurationError |355InvalidParameterException ex) {356// if provider loading fail due to security permission,357// log it and move on to next provider358if (debug != null) {359debug.println("Encountered " + ex +360" while iterating through SL, ignore and move on");361ex.printStackTrace();362}363}364}365// No success with ServiceLoader. Try loading provider the legacy,366// i.e. pre-module, way via reflection367try {368return legacyLoad(pn);369} catch (ProviderException pe) {370// pass through371throw pe;372} catch (Exception ex) {373// logged and ignored374if (debug != null) {375debug.println("Encountered " + ex +376" during legacy load of " + pn);377ex.printStackTrace();378}379return null;380}381}382383private Provider legacyLoad(String classname) {384385if (debug != null) {386debug.println("Loading legacy provider: " + classname);387}388389try {390Class<?> provClass =391ClassLoader.getSystemClassLoader().loadClass(classname);392393// only continue if the specified class extends Provider394if (!Provider.class.isAssignableFrom(provClass)) {395if (debug != null) {396debug.println(classname + " is not a provider");397}398return null;399}400401@SuppressWarnings("removal")402Provider p = AccessController.doPrivileged403(new PrivilegedExceptionAction<Provider>() {404@SuppressWarnings("deprecation") // Class.newInstance405public Provider run() throws Exception {406return (Provider) provClass.newInstance();407}408});409return p;410} catch (Exception e) {411Throwable t;412if (e instanceof InvocationTargetException) {413t = ((InvocationTargetException)e).getCause();414} else {415t = e;416}417if (debug != null) {418debug.println("Error loading legacy provider " + classname);419t.printStackTrace();420}421// provider indicates fatal error, pass through exception422if (t instanceof ProviderException) {423throw (ProviderException) t;424}425return null;426} catch (ExceptionInInitializerError | NoClassDefFoundError err) {427// no sufficient permission to access/initialize provider class428if (debug != null) {429debug.println("Error loading legacy provider " + classname);430err.printStackTrace();431}432return null;433}434}435}436}437438439