jdk/src/java.base/share/classes/sun/security/jca/ProviderConfig.java
changeset 31270 e6470b24700d
parent 27565 729f9700483a
child 32229 181a18587d61
equal deleted inserted replaced
31269:14968253ce7e 31270:e6470b24700d
     1 /*
     1 /*
     2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    25 
    25 
    26 package sun.security.jca;
    26 package sun.security.jca;
    27 
    27 
    28 import java.io.File;
    28 import java.io.File;
    29 import java.lang.reflect.*;
    29 import java.lang.reflect.*;
       
    30 import java.util.*;
    30 
    31 
    31 import java.security.*;
    32 import java.security.*;
    32 
    33 
    33 import sun.security.util.PropertyExpander;
    34 import sun.security.util.PropertyExpander;
    34 
    35 
    35 /**
    36 /**
    36  * Class representing a configured provider. Encapsulates configuration
    37  * Class representing a configured provider which encapsulates configuration
    37  * (className plus optional argument), the provider loading logic, and
    38  * (provider name + optional argument), the provider loading logic, and
    38  * the loaded Provider object itself.
    39  * the loaded Provider object itself.
    39  *
    40  *
    40  * @author  Andreas Sterbenz
    41  * @author  Andreas Sterbenz
    41  * @since   1.5
    42  * @since   1.5
    42  */
    43  */
    43 final class ProviderConfig {
    44 final class ProviderConfig {
    44 
    45 
    45     private final static sun.security.util.Debug debug =
    46     private final static sun.security.util.Debug debug =
    46         sun.security.util.Debug.getInstance("jca", "ProviderConfig");
    47         sun.security.util.Debug.getInstance("jca", "ProviderConfig");
    47 
    48 
    48     // classname of the SunPKCS11-Solaris provider
    49     // suffix for identifying the SunPKCS11-Solaris provider
    49     private static final String P11_SOL_NAME =
    50     private static final String P11_SOL_NAME = "SunPKCS11";
    50         "sun.security.pkcs11.SunPKCS11";
       
    51 
    51 
    52     // config file argument of the SunPKCS11-Solaris provider
    52     // config file argument of the SunPKCS11-Solaris provider
    53     private static final String P11_SOL_ARG  =
    53     private static final String P11_SOL_ARG  =
    54         "${java.home}/conf/security/sunpkcs11-solaris.cfg";
    54         "${java.home}/conf/security/sunpkcs11-solaris.cfg";
    55 
    55 
    56     // maximum number of times to try loading a provider before giving up
    56     // maximum number of times to try loading a provider before giving up
    57     private final static int MAX_LOAD_TRIES = 30;
    57     private final static int MAX_LOAD_TRIES = 30;
    58 
    58 
    59     // parameters for the Provider(String) constructor,
    59     // could be provider name (module) or provider class name (legacy)
    60     // use by doLoadProvider()
    60     private final String provName;
    61     private final static Class<?>[] CL_STRING = { String.class };
    61 
    62 
    62     // argument to the Provider.configure() call, never null
    63     // name of the provider class
       
    64     private final String className;
       
    65 
       
    66     // argument to the provider constructor,
       
    67     // empty string indicates no-arg constructor
       
    68     private final String argument;
    63     private final String argument;
    69 
    64 
    70     // number of times we have already tried to load this provider
    65     // number of times we have already tried to load this provider
    71     private int tries;
    66     private int tries;
    72 
    67 
    75 
    70 
    76     // flag indicating if we are currently trying to load the provider
    71     // flag indicating if we are currently trying to load the provider
    77     // used to detect recursion
    72     // used to detect recursion
    78     private boolean isLoading;
    73     private boolean isLoading;
    79 
    74 
    80     ProviderConfig(String className, String argument) {
    75     ProviderConfig(String provName, String argument) {
    81         if (className.equals(P11_SOL_NAME) && argument.equals(P11_SOL_ARG)) {
    76         if (provName.endsWith(P11_SOL_NAME) && argument.equals(P11_SOL_ARG)) {
    82             checkSunPKCS11Solaris();
    77             checkSunPKCS11Solaris();
    83         }
    78         }
    84         this.className = className;
    79         this.provName = provName;
    85         this.argument = expand(argument);
    80         this.argument = expand(argument);
    86     }
    81     }
    87 
    82 
    88     ProviderConfig(String className) {
    83     ProviderConfig(String provName) {
    89         this(className, "");
    84         this(provName, "");
    90     }
    85     }
    91 
    86 
    92     ProviderConfig(Provider provider) {
    87     ProviderConfig(Provider provider) {
    93         this.className = provider.getClass().getName();
    88         this.provName = provider.getName();
    94         this.argument = "";
    89         this.argument = "";
    95         this.provider = provider;
    90         this.provider = provider;
    96     }
    91     }
    97 
    92 
    98     // check if we should try to load the SunPKCS11-Solaris provider
    93     // check if we should try to load the SunPKCS11-Solaris provider
   142         }
   137         }
   143         if (obj instanceof ProviderConfig == false) {
   138         if (obj instanceof ProviderConfig == false) {
   144             return false;
   139             return false;
   145         }
   140         }
   146         ProviderConfig other = (ProviderConfig)obj;
   141         ProviderConfig other = (ProviderConfig)obj;
   147         return this.className.equals(other.className)
   142         return this.provName.equals(other.provName)
   148             && this.argument.equals(other.argument);
   143             && this.argument.equals(other.argument);
       
   144 
   149     }
   145     }
   150 
   146 
   151     public int hashCode() {
   147     public int hashCode() {
   152         return className.hashCode() + argument.hashCode();
   148         return provName.hashCode() + argument.hashCode();
   153     }
   149     }
   154 
   150 
   155     public String toString() {
   151     public String toString() {
   156         if (hasArgument()) {
   152         if (hasArgument()) {
   157             return className + "('" + argument + "')";
   153             return provName + "('" + argument + "')";
   158         } else {
   154         } else {
   159             return className;
   155             return provName;
   160         }
   156         }
   161     }
   157     }
   162 
   158 
   163     /**
   159     /**
   164      * Get the provider object. Loads the provider if it is not already loaded.
   160      * Get the provider object. Loads the provider if it is not already loaded.
   170             return p;
   166             return p;
   171         }
   167         }
   172         if (shouldLoad() == false) {
   168         if (shouldLoad() == false) {
   173             return null;
   169             return null;
   174         }
   170         }
   175         if (isLoading) {
   171 
   176             // because this method is synchronized, this can only
   172         // Create providers which are in java.base directly
   177             // happen if there is recursion.
   173         if (provName.equals("SUN") || provName.equals("sun.security.provider.Sun")) {
   178             if (debug != null) {
   174             p = new sun.security.provider.Sun();
   179                 debug.println("Recursion loading provider: " + this);
   175         } else if (provName.equals("SunRsaSign") || provName.equals("sun.security.rsa.SunRsaSign")) {
   180                 new Exception("Call trace").printStackTrace();
   176             p = new sun.security.rsa.SunRsaSign();
   181             }
   177         } else if (provName.equals("SunJCE") || provName.equals("com.sun.crypto.provider.SunJCE")) {
   182             return null;
   178             p = new com.sun.crypto.provider.SunJCE();
   183         }
   179         } else if (provName.equals("SunJSSE") || provName.equals("com.sun.net.ssl.internal.ssl.Provider")) {
   184         try {
   180             p = new com.sun.net.ssl.internal.ssl.Provider();
   185             isLoading = true;
   181         } else {
   186             tries++;
   182             if (isLoading) {
   187             p = doLoadProvider();
   183                 // because this method is synchronized, this can only
   188         } finally {
   184                 // happen if there is recursion.
   189             isLoading = false;
   185                 if (debug != null) {
       
   186                     debug.println("Recursion loading provider: " + this);
       
   187                     new Exception("Call trace").printStackTrace();
       
   188                 }
       
   189                 return null;
       
   190             }
       
   191             try {
       
   192                 isLoading = true;
       
   193                 tries++;
       
   194                 p = doLoadProvider();
       
   195             } finally {
       
   196                 isLoading = false;
       
   197             }
   190         }
   198         }
   191         provider = p;
   199         provider = p;
   192         return p;
   200         return p;
   193     }
   201     }
   194 
   202 
   204      */
   212      */
   205     private Provider doLoadProvider() {
   213     private Provider doLoadProvider() {
   206         return AccessController.doPrivileged(new PrivilegedAction<Provider>() {
   214         return AccessController.doPrivileged(new PrivilegedAction<Provider>() {
   207             public Provider run() {
   215             public Provider run() {
   208                 if (debug != null) {
   216                 if (debug != null) {
   209                     debug.println("Loading provider: " + ProviderConfig.this);
   217                     debug.println("Loading provider " + ProviderConfig.this);
   210                 }
   218                 }
       
   219                 ProviderLoader pl = new ProviderLoader();
   211                 try {
   220                 try {
   212                     ClassLoader cl = ClassLoader.getSystemClassLoader();
   221                     Provider p = pl.load(provName);
   213                     Class<?> provClass;
   222                     if (p != null) {
   214                     if (cl != null) {
   223                         if (hasArgument()) {
   215                         provClass = cl.loadClass(className);
   224                             p = p.configure(argument);
   216                     } else {
   225                         }
   217                         provClass = Class.forName(className);
       
   218                     }
       
   219                     Object obj;
       
   220                     if (hasArgument() == false) {
       
   221                         obj = provClass.newInstance();
       
   222                     } else {
       
   223                         Constructor<?> cons = provClass.getConstructor(CL_STRING);
       
   224                         obj = cons.newInstance(argument);
       
   225                     }
       
   226                     if (obj instanceof Provider) {
       
   227                         if (debug != null) {
   226                         if (debug != null) {
   228                             debug.println("Loaded provider " + obj);
   227                             debug.println("Loaded provider " + p.getName());
   229                         }
   228                         }
   230                         return (Provider)obj;
       
   231                     } else {
   229                     } else {
   232                         if (debug != null) {
   230                         if (debug != null) {
   233                             debug.println(className + " is not a provider");
   231                             debug.println("Error loading provider " +
       
   232                                 ProviderConfig.this);
       
   233                         }
       
   234                         disableLoad();
       
   235                     }
       
   236                     return p;
       
   237                 } catch (Exception e) {
       
   238                     if (e instanceof ProviderException) {
       
   239                         // pass up
       
   240                         throw e;
       
   241                     } else {
       
   242                         if (debug != null) {
       
   243                             debug.println("Error loading provider " +
       
   244                                 ProviderConfig.this);
       
   245                             e.printStackTrace();
   234                         }
   246                         }
   235                         disableLoad();
   247                         disableLoad();
   236                         return null;
   248                         return null;
   237                     }
   249                     }
   238                 } catch (Exception e) {
       
   239                     Throwable t;
       
   240                     if (e instanceof InvocationTargetException) {
       
   241                         t = ((InvocationTargetException)e).getCause();
       
   242                     } else {
       
   243                         t = e;
       
   244                     }
       
   245                     if (debug != null) {
       
   246                         debug.println("Error loading provider " + ProviderConfig.this);
       
   247                         t.printStackTrace();
       
   248                     }
       
   249                     // provider indicates fatal error, pass through exception
       
   250                     if (t instanceof ProviderException) {
       
   251                         throw (ProviderException)t;
       
   252                     }
       
   253                     // provider indicates that loading should not be retried
       
   254                     if (t instanceof UnsupportedOperationException) {
       
   255                         disableLoad();
       
   256                     }
       
   257                     return null;
       
   258                 } catch (ExceptionInInitializerError err) {
   250                 } catch (ExceptionInInitializerError err) {
   259                     // no sufficient permission to initialize provider class
   251                     // no sufficient permission to initialize provider class
   260                     if (debug != null) {
   252                     if (debug != null) {
   261                         debug.println("Error loading provider " + ProviderConfig.this);
   253                         debug.println("Error loading provider " + ProviderConfig.this);
   262                         err.printStackTrace();
   254                         err.printStackTrace();
   287                 }
   279                 }
   288             }
   280             }
   289         });
   281         });
   290     }
   282     }
   291 
   283 
       
   284     // Inner class for loading security providers listed in java.security file
       
   285     private static final class ProviderLoader {
       
   286         private final ServiceLoader<Provider> services;
       
   287 
       
   288         ProviderLoader() {
       
   289             // VM should already been booted at this point, if not
       
   290             // - Only providers in java.base should be loaded, don't use
       
   291             //   ServiceLoader
       
   292             // - ClassLoader.getSystemClassLoader() will throw InternalError
       
   293             services = ServiceLoader.load(java.security.Provider.class,
       
   294                                           ClassLoader.getSystemClassLoader());
       
   295         }
       
   296 
       
   297         /**
       
   298          * Loads the provider with the specified class name.
       
   299          *
       
   300          * @param name the name of the provider
       
   301          * @return the Provider, or null if it cannot be found or loaded
       
   302          * @throws ProviderException all other exceptions are ignored
       
   303          */
       
   304         public Provider load(String pn) {
       
   305             if (debug != null) {
       
   306                 debug.println("Attempt to load " + pn + " using SL");
       
   307             }
       
   308             Iterator<Provider> iter = services.iterator();
       
   309             while (iter.hasNext()) {
       
   310                 try {
       
   311                     Provider p = iter.next();
       
   312                     String pName = p.getName();
       
   313                     if (debug != null) {
       
   314                         debug.println("Found SL Provider named " + pName);
       
   315                     }
       
   316                     if (pName.equals(pn)) {
       
   317                         return p;
       
   318                     }
       
   319                 } catch (SecurityException | ServiceConfigurationError |
       
   320                          InvalidParameterException ex) {
       
   321                     // if provider loading fail due to security permission,
       
   322                     // log it and move on to next provider
       
   323                     if (debug != null) {
       
   324                         debug.println("Encountered " + ex +
       
   325                             " while iterating through SL, ignore and move on");
       
   326                             ex.printStackTrace();
       
   327                     }
       
   328                 }
       
   329             }
       
   330             // No success with ServiceLoader. Try loading provider the legacy,
       
   331             // i.e. pre-module, way via reflection
       
   332             try {
       
   333                 return legacyLoad(pn);
       
   334             } catch (ProviderException pe) {
       
   335                 // pass through
       
   336                 throw pe;
       
   337             } catch (Exception ex) {
       
   338                 // logged and ignored
       
   339                 if (debug != null) {
       
   340                     debug.println("Encountered " + ex +
       
   341                         " during legacy load of " + pn);
       
   342                         ex.printStackTrace();
       
   343                 }
       
   344                 return null;
       
   345             }
       
   346         }
       
   347 
       
   348         private Provider legacyLoad(String classname) {
       
   349 
       
   350             if (debug != null) {
       
   351                 debug.println("Loading legacy provider: " + classname);
       
   352             }
       
   353 
       
   354             try {
       
   355                 Class<?> provClass =
       
   356                     ClassLoader.getSystemClassLoader().loadClass(classname);
       
   357 
       
   358                 // only continue if the specified class extends Provider
       
   359                 if (!Provider.class.isAssignableFrom(provClass)) {
       
   360                     if (debug != null) {
       
   361                         debug.println(classname + " is not a provider");
       
   362                     }
       
   363                     return null;
       
   364                 }
       
   365 
       
   366                 Provider p = AccessController.doPrivileged
       
   367                     (new PrivilegedExceptionAction<Provider>() {
       
   368                     public Provider run() throws Exception {
       
   369                         return (Provider) provClass.newInstance();
       
   370                     }
       
   371                 });
       
   372                 return p;
       
   373             } catch (Exception e) {
       
   374                 Throwable t;
       
   375                 if (e instanceof InvocationTargetException) {
       
   376                     t = ((InvocationTargetException)e).getCause();
       
   377                 } else {
       
   378                     t = e;
       
   379                 }
       
   380                 if (debug != null) {
       
   381                     debug.println("Error loading legacy provider " + classname);
       
   382                     t.printStackTrace();
       
   383                 }
       
   384                 // provider indicates fatal error, pass through exception
       
   385                 if (t instanceof ProviderException) {
       
   386                     throw (ProviderException) t;
       
   387                 }
       
   388                 return null;
       
   389             } catch (ExceptionInInitializerError | NoClassDefFoundError err) {
       
   390                 // no sufficient permission to access/initialize provider class
       
   391                 if (debug != null) {
       
   392                     debug.println("Error loading legacy provider " + classname);
       
   393                     err.printStackTrace();
       
   394                 }
       
   395                 return null;
       
   396             }
       
   397         }
       
   398     }
   292 }
   399 }