1 /*
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
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
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.security.jca;
27
28 import java.io.File;
29 import java.lang.reflect.*;
30
31 import java.security.*;
32
33 import sun.security.util.PropertyExpander;
34
35 /**
36 * Class representing a configured provider. Encapsulates configuration
37 * (className plus optional argument), the provider loading logic, and
38 * the loaded Provider object itself.
39 *
40 * @author Andreas Sterbenz
41 * @since 1.5
42 */
43 final class ProviderConfig {
44
45 private final static sun.security.util.Debug debug =
46 sun.security.util.Debug.getInstance("jca", "ProviderConfig");
47
48 // classname of the SunPKCS11-Solaris provider
49 private static final String P11_SOL_NAME =
50 "sun.security.pkcs11.SunPKCS11";
51
52 // config file argument of the SunPKCS11-Solaris provider
53 private static final String P11_SOL_ARG =
54 "${java.home}/conf/security/sunpkcs11-solaris.cfg";
55
56 // maximum number of times to try loading a provider before giving up
57 private final static int MAX_LOAD_TRIES = 30;
58
59 // parameters for the Provider(String) constructor,
60 // use by doLoadProvider()
61 private final static Class<?>[] CL_STRING = { String.class };
62
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;
69
70 // number of times we have already tried to load this provider
71 private int tries;
72
73 // Provider object, if loaded
74 private volatile Provider provider;
75
76 // flag indicating if we are currently trying to load the provider
77 // used to detect recursion
78 private boolean isLoading;
79
80 ProviderConfig(String className, String argument) {
81 if (className.equals(P11_SOL_NAME) && argument.equals(P11_SOL_ARG)) {
82 checkSunPKCS11Solaris();
83 }
84 this.className = className;
85 this.argument = expand(argument);
86 }
87
88 ProviderConfig(String className) {
89 this(className, "");
90 }
91
92 ProviderConfig(Provider provider) {
93 this.className = provider.getClass().getName();
94 this.argument = "";
95 this.provider = provider;
96 }
97
98 // check if we should try to load the SunPKCS11-Solaris provider
99 // avoid if not available (pre Solaris 10) to reduce startup time
100 // or if disabled via system property
101 private void checkSunPKCS11Solaris() {
102 Boolean o = AccessController.doPrivileged(
103 new PrivilegedAction<Boolean>() {
104 public Boolean run() {
105 File file = new File("/usr/lib/libpkcs11.so");
106 if (file.exists() == false) {
107 return Boolean.FALSE;
108 }
109 if ("false".equalsIgnoreCase(System.getProperty
110 ("sun.security.pkcs11.enable-solaris"))) {
111 return Boolean.FALSE;
112 }
113 return Boolean.TRUE;
127 return (tries < MAX_LOAD_TRIES);
128 }
129
130 // do not try to load this provider again
131 private void disableLoad() {
132 tries = MAX_LOAD_TRIES;
133 }
134
135 boolean isLoaded() {
136 return (provider != null);
137 }
138
139 public boolean equals(Object obj) {
140 if (this == obj) {
141 return true;
142 }
143 if (obj instanceof ProviderConfig == false) {
144 return false;
145 }
146 ProviderConfig other = (ProviderConfig)obj;
147 return this.className.equals(other.className)
148 && this.argument.equals(other.argument);
149 }
150
151 public int hashCode() {
152 return className.hashCode() + argument.hashCode();
153 }
154
155 public String toString() {
156 if (hasArgument()) {
157 return className + "('" + argument + "')";
158 } else {
159 return className;
160 }
161 }
162
163 /**
164 * Get the provider object. Loads the provider if it is not already loaded.
165 */
166 synchronized Provider getProvider() {
167 // volatile variable load
168 Provider p = provider;
169 if (p != null) {
170 return p;
171 }
172 if (shouldLoad() == false) {
173 return null;
174 }
175 if (isLoading) {
176 // because this method is synchronized, this can only
177 // happen if there is recursion.
178 if (debug != null) {
179 debug.println("Recursion loading provider: " + this);
180 new Exception("Call trace").printStackTrace();
181 }
182 return null;
183 }
184 try {
185 isLoading = true;
186 tries++;
187 p = doLoadProvider();
188 } finally {
189 isLoading = false;
190 }
191 provider = p;
192 return p;
193 }
194
195 /**
196 * Load and instantiate the Provider described by this class.
197 *
198 * NOTE use of doPrivileged().
199 *
200 * @return null if the Provider could not be loaded
201 *
202 * @throws ProviderException if executing the Provider's constructor
203 * throws a ProviderException. All other Exceptions are ignored.
204 */
205 private Provider doLoadProvider() {
206 return AccessController.doPrivileged(new PrivilegedAction<Provider>() {
207 public Provider run() {
208 if (debug != null) {
209 debug.println("Loading provider: " + ProviderConfig.this);
210 }
211 try {
212 ClassLoader cl = ClassLoader.getSystemClassLoader();
213 Class<?> provClass;
214 if (cl != null) {
215 provClass = cl.loadClass(className);
216 } else {
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) {
228 debug.println("Loaded provider " + obj);
229 }
230 return (Provider)obj;
231 } else {
232 if (debug != null) {
233 debug.println(className + " is not a provider");
234 }
235 disableLoad();
236 return null;
237 }
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) {
259 // no sufficient permission to initialize provider class
260 if (debug != null) {
261 debug.println("Error loading provider " + ProviderConfig.this);
262 err.printStackTrace();
263 }
264 disableLoad();
265 return null;
266 }
267 }
268 });
269 }
270
271 /**
272 * Perform property expansion of the provider value.
273 *
274 * NOTE use of doPrivileged().
275 */
276 private static String expand(final String value) {
277 // shortcut if value does not contain any properties
278 if (value.contains("${") == false) {
279 return value;
280 }
281 return AccessController.doPrivileged(new PrivilegedAction<String>() {
282 public String run() {
283 try {
284 return PropertyExpander.expand(value);
285 } catch (GeneralSecurityException e) {
286 throw new ProviderException(e);
287 }
288 }
289 });
290 }
291
292 }
|
1 /*
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.
4 *
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
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.security.jca;
27
28 import java.io.File;
29 import java.lang.reflect.*;
30 import java.util.*;
31
32 import java.security.*;
33
34 import sun.security.util.PropertyExpander;
35
36 /**
37 * Class representing a configured provider which encapsulates configuration
38 * (provider name + optional argument), the provider loading logic, and
39 * the loaded Provider object itself.
40 *
41 * @author Andreas Sterbenz
42 * @since 1.5
43 */
44 final class ProviderConfig {
45
46 private final static sun.security.util.Debug debug =
47 sun.security.util.Debug.getInstance("jca", "ProviderConfig");
48
49 // suffix for identifying the SunPKCS11-Solaris provider
50 private static final String P11_SOL_NAME = "SunPKCS11";
51
52 // config file argument of the SunPKCS11-Solaris provider
53 private static final String P11_SOL_ARG =
54 "${java.home}/conf/security/sunpkcs11-solaris.cfg";
55
56 // maximum number of times to try loading a provider before giving up
57 private final static int MAX_LOAD_TRIES = 30;
58
59 // could be provider name (module) or provider class name (legacy)
60 private final String provName;
61
62 // argument to the Provider.configure() call, never null
63 private final String argument;
64
65 // number of times we have already tried to load this provider
66 private int tries;
67
68 // Provider object, if loaded
69 private volatile Provider provider;
70
71 // flag indicating if we are currently trying to load the provider
72 // used to detect recursion
73 private boolean isLoading;
74
75 ProviderConfig(String provName, String argument) {
76 if (provName.endsWith(P11_SOL_NAME) && argument.equals(P11_SOL_ARG)) {
77 checkSunPKCS11Solaris();
78 }
79 this.provName = provName;
80 this.argument = expand(argument);
81 }
82
83 ProviderConfig(String provName) {
84 this(provName, "");
85 }
86
87 ProviderConfig(Provider provider) {
88 this.provName = provider.getName();
89 this.argument = "";
90 this.provider = provider;
91 }
92
93 // check if we should try to load the SunPKCS11-Solaris provider
94 // avoid if not available (pre Solaris 10) to reduce startup time
95 // or if disabled via system property
96 private void checkSunPKCS11Solaris() {
97 Boolean o = AccessController.doPrivileged(
98 new PrivilegedAction<Boolean>() {
99 public Boolean run() {
100 File file = new File("/usr/lib/libpkcs11.so");
101 if (file.exists() == false) {
102 return Boolean.FALSE;
103 }
104 if ("false".equalsIgnoreCase(System.getProperty
105 ("sun.security.pkcs11.enable-solaris"))) {
106 return Boolean.FALSE;
107 }
108 return Boolean.TRUE;
122 return (tries < MAX_LOAD_TRIES);
123 }
124
125 // do not try to load this provider again
126 private void disableLoad() {
127 tries = MAX_LOAD_TRIES;
128 }
129
130 boolean isLoaded() {
131 return (provider != null);
132 }
133
134 public boolean equals(Object obj) {
135 if (this == obj) {
136 return true;
137 }
138 if (obj instanceof ProviderConfig == false) {
139 return false;
140 }
141 ProviderConfig other = (ProviderConfig)obj;
142 return this.provName.equals(other.provName)
143 && this.argument.equals(other.argument);
144
145 }
146
147 public int hashCode() {
148 return provName.hashCode() + argument.hashCode();
149 }
150
151 public String toString() {
152 if (hasArgument()) {
153 return provName + "('" + argument + "')";
154 } else {
155 return provName;
156 }
157 }
158
159 /**
160 * Get the provider object. Loads the provider if it is not already loaded.
161 */
162 synchronized Provider getProvider() {
163 // volatile variable load
164 Provider p = provider;
165 if (p != null) {
166 return p;
167 }
168 if (shouldLoad() == false) {
169 return null;
170 }
171
172 // Create providers which are in java.base directly
173 if (provName.equals("SUN")) {
174 p = new sun.security.provider.Sun();
175 } else if (provName.equals("SunRsaSign")) {
176 p = new sun.security.rsa.SunRsaSign();
177 } else if (provName.equals("SunJCE")) {
178 p = new com.sun.crypto.provider.SunJCE();
179 } else if (provName.equals("SunJSSE")) {
180 p = new com.sun.net.ssl.internal.ssl.Provider();
181 } else {
182 if (isLoading) {
183 // because this method is synchronized, this can only
184 // happen if there is recursion.
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 }
198 }
199 provider = p;
200 return p;
201 }
202
203 /**
204 * Load and instantiate the Provider described by this class.
205 *
206 * NOTE use of doPrivileged().
207 *
208 * @return null if the Provider could not be loaded
209 *
210 * @throws ProviderException if executing the Provider's constructor
211 * throws a ProviderException. All other Exceptions are ignored.
212 */
213 private Provider doLoadProvider() {
214 return AccessController.doPrivileged(new PrivilegedAction<Provider>() {
215 public Provider run() {
216 if (debug != null) {
217 debug.println("Loading provider " + ProviderConfig.this);
218 }
219 ProviderLoader pl = new ProviderLoader();
220 try {
221 Provider p = pl.load(provName);
222 if (p != null) {
223 if (hasArgument()) {
224 p = p.configure(argument);
225 }
226 if (debug != null) {
227 debug.println("Loaded provider " + p.getName());
228 }
229 } else {
230 if (debug != null) {
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();
246 }
247 disableLoad();
248 return null;
249 }
250 } catch (ExceptionInInitializerError err) {
251 // no sufficient permission to initialize provider class
252 if (debug != null) {
253 debug.println("Error loading provider " + ProviderConfig.this);
254 err.printStackTrace();
255 }
256 disableLoad();
257 return null;
258 }
259 }
260 });
261 }
262
263 /**
264 * Perform property expansion of the provider value.
265 *
266 * NOTE use of doPrivileged().
267 */
268 private static String expand(final String value) {
269 // shortcut if value does not contain any properties
270 if (value.contains("${") == false) {
271 return value;
272 }
273 return AccessController.doPrivileged(new PrivilegedAction<String>() {
274 public String run() {
275 try {
276 return PropertyExpander.expand(value);
277 } catch (GeneralSecurityException e) {
278 throw new ProviderException(e);
279 }
280 }
281 });
282 }
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 }
399 }
|