src/java.base/share/classes/sun/security/jca/ProviderConfig.java

Print this page
7191662: JCE providers should be located via ServiceLoader

*** 1,7 **** /* ! * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 25,42 **** package sun.security.jca; import java.io.File; import java.lang.reflect.*; import java.security.*; import sun.security.util.PropertyExpander; /** ! * Class representing a configured provider. Encapsulates configuration ! * (className plus optional argument), the provider loading logic, and * the loaded Provider object itself. * * @author Andreas Sterbenz * @since 1.5 */ --- 25,43 ---- package sun.security.jca; import java.io.File; import java.lang.reflect.*; + import java.util.*; import java.security.*; import sun.security.util.PropertyExpander; /** ! * Class representing a configured provider which encapsulates configuration ! * (className + optional argument), the provider loading logic, and * the loaded Provider object itself. * * @author Andreas Sterbenz * @since 1.5 */
*** 54,72 **** "${java.home}/conf/security/sunpkcs11-solaris.cfg"; // maximum number of times to try loading a provider before giving up private final static int MAX_LOAD_TRIES = 30; - // parameters for the Provider(String) constructor, - // use by doLoadProvider() - private final static Class<?>[] CL_STRING = { String.class }; - // name of the provider class private final String className; ! // argument to the provider constructor, ! // empty string indicates no-arg constructor private final String argument; // number of times we have already tried to load this provider private int tries; --- 55,68 ---- "${java.home}/conf/security/sunpkcs11-solaris.cfg"; // maximum number of times to try loading a provider before giving up private final static int MAX_LOAD_TRIES = 30; // name of the provider class private final String className; ! // argument to the Provider.configure() call, never null private final String argument; // number of times we have already tried to load this provider private int tries;
*** 170,179 **** --- 166,186 ---- return p; } if (shouldLoad() == false) { return null; } + + // Create providers which are in java.base directly + if (className.equals("sun.security.provider.Sun")) { + p = new sun.security.provider.Sun(); + } else if (className.equals("sun.security.rsa.SunRsaSign")) { + p = new sun.security.rsa.SunRsaSign(); + } else if (className.equals("com.sun.crypto.provider.SunJCE")) { + p = new com.sun.crypto.provider.SunJCE(); + } else if (className.equals("com.sun.net.ssl.internal.ssl.Provider")) { + p = new com.sun.net.ssl.internal.ssl.Provider(); + } else { if (isLoading) { // because this method is synchronized, this can only // happen if there is recursion. if (debug != null) { debug.println("Recursion loading provider: " + this);
*** 186,195 **** --- 193,203 ---- tries++; p = doLoadProvider(); } finally { isLoading = false; } + } provider = p; return p; } /**
*** 206,270 **** return AccessController.doPrivileged(new PrivilegedAction<Provider>() { public Provider run() { if (debug != null) { debug.println("Loading provider: " + ProviderConfig.this); } try { ! ClassLoader cl = ClassLoader.getSystemClassLoader(); ! Class<?> provClass; ! if (cl != null) { ! provClass = cl.loadClass(className); ! } else { ! provClass = Class.forName(className); } - Object obj; - if (hasArgument() == false) { - obj = provClass.newInstance(); - } else { - Constructor<?> cons = provClass.getConstructor(CL_STRING); - obj = cons.newInstance(argument); - } - if (obj instanceof Provider) { if (debug != null) { ! debug.println("Loaded provider " + obj); } - return (Provider)obj; } else { if (debug != null) { ! debug.println(className + " is not a provider"); } disableLoad(); - return null; } } catch (Exception e) { ! Throwable t; ! if (e instanceof InvocationTargetException) { ! t = ((InvocationTargetException)e).getCause(); } else { - t = e; - } if (debug != null) { ! debug.println("Error loading provider " + ProviderConfig.this); ! t.printStackTrace(); } - // provider indicates fatal error, pass through exception - if (t instanceof ProviderException) { - throw (ProviderException)t; - } - // provider indicates that loading should not be retried - if (t instanceof UnsupportedOperationException) { disableLoad(); - } return null; - } catch (ExceptionInInitializerError err) { - // no sufficient permission to initialize provider class - if (debug != null) { - debug.println("Error loading provider " + ProviderConfig.this); - err.printStackTrace(); } - disableLoad(); - return null; } } }); } --- 214,252 ---- return AccessController.doPrivileged(new PrivilegedAction<Provider>() { public Provider run() { if (debug != null) { debug.println("Loading provider: " + ProviderConfig.this); } + ProviderLoader pl = new ProviderLoader(); try { ! Provider p = pl.load(className); ! if (p != null) { ! if (hasArgument()) { ! p = p.configure(argument); } if (debug != null) { ! debug.println("Loaded provider " + p.getName()); } } else { if (debug != null) { ! debug.println("Error loading " + className); } disableLoad(); } + return p; } catch (Exception e) { ! if (e instanceof ProviderException) { ! // pass up ! throw e; } else { if (debug != null) { ! debug.println("Error loading " + className); ! e.printStackTrace(); } disableLoad(); return null; } } } }); }
*** 287,292 **** --- 269,388 ---- } } }); } + // Inner class for loading security providers listed in java.security file + private static final class ProviderLoader { + ServiceLoader<Provider> services; + + ProviderLoader() { + // VM should already been booted at this point, if not + // - Only providers in java.base should be loaded, don't use + // ServiceLoader + // - ClassLoader.getSystemClassLoader() will throw InternalError + services = ServiceLoader.load(java.security.Provider.class, + ClassLoader.getSystemClassLoader()); + } + + /** + * Loads the provider with the specified class name. + * + * @param name the name of the provider class + * @return the Provider, or null if it cannot be found or loaded + * @throws ProviderException all other exceptions are ignored + */ + public Provider load(String classname) { + if (debug != null) { + debug.println("Attempt to load " + classname + " using SL"); + } + Iterator<Provider> iter = services.iterator(); + while (iter.hasNext()) { + try { + Provider p = iter.next(); + if (debug != null) { + debug.println("Found SL Provider named " + p.getName()); + } + if (p.getClass().getName().equals(classname)) { + return p; + } + } catch (SecurityException | ServiceConfigurationError | + InvalidParameterException ex) { + // if provider loading fail due to security permission, + // log it and move on to next provider + if (debug != null) { + debug.println("Encountered " + ex + + " while iterating through SL, ignore and move on"); + ex.printStackTrace(); + } + } + } + // No success with ServiceLoader. Try loading provider the legacy, + // i.e. pre-module, way via reflection + try { + return legacyLoad(classname); + } catch (ProviderException pe) { + // pass through + throw pe; + } catch (Exception ex) { + // logged and ignored + if (debug != null) { + debug.println("Encountered " + ex + + " during legacy load of " + classname); + ex.printStackTrace(); + } + return null; + } + } + + private Provider legacyLoad(String classname) { + + if (debug != null) { + debug.println("Loading legacy provider: " + classname); + } + + try { + Class<?> provClass = + ClassLoader.getSystemClassLoader().loadClass(classname); + + // only continue if the specified class extends Provider + if (!Provider.class.isAssignableFrom(provClass)) { + if (debug != null) { + debug.println(classname + " is not a provider"); + } + return null; + } + + Provider p = AccessController.doPrivileged + (new PrivilegedExceptionAction<Provider>() { + public Provider run() throws Exception { + return (Provider) provClass.newInstance(); + } + }); + return p; + } catch (Exception e) { + Throwable t; + if (e instanceof InvocationTargetException) { + t = ((InvocationTargetException)e).getCause(); + } else { + t = e; + } + if (debug != null) { + debug.println("Error loading legacy provider " + classname); + t.printStackTrace(); + } + // provider indicates fatal error, pass through exception + if (t instanceof ProviderException) { + throw (ProviderException) t; + } + return null; + } catch (ExceptionInInitializerError | NoClassDefFoundError err) { + // no sufficient permission to access/initialize provider class + if (debug != null) { + debug.println("Error loading legacy provider " + classname); + err.printStackTrace(); + } + return null; + } + } + } }