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 } |