1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.wss4j.common.crypto;
21
22 import java.lang.reflect.Field;
23 import java.security.AccessController;
24 import java.security.PrivilegedAction;
25 import java.security.PrivilegedExceptionAction;
26 import java.security.Provider;
27 import java.security.Security;
28
29 import org.apache.wss4j.common.util.FIPSUtils;
30 import org.apache.wss4j.common.util.Loader;
31 import org.apache.xml.security.utils.I18n;
32 import org.apache.xml.security.utils.XMLUtils;
33
34
35 /**
36 * Configure Crypto providers.
37 */
38 public final class WSProviderConfig {
39
40 private static final org.slf4j.Logger LOG =
41 org.slf4j.LoggerFactory.getLogger(WSProviderConfig.class);
42
43 /**
44 * a static boolean flag that determines whether default JCE providers
45 * should be added at the time of construction.
46 *
47 * These providers, and the order in which they are added, can interfere
48 * with some JVMs (such as IBMs).
49 */
50 private static boolean addJceProviders = true;
51
52 /**
53 * a boolean flag to record whether we have already been statically
54 * initialized. This flag prevents repeated and unnecessary calls
55 * to static initialization code at construction time.
56 */
57 private static boolean staticallyInitialized;
58
59 private static boolean santuarioProviderAdded;
60 private static boolean bcProviderAdded;
61 private static boolean tlProviderAdded;
62
63 private WSProviderConfig() {
64 // complete
65 }
66
67 public static synchronized void init() {
68 if (!staticallyInitialized) {
69 if (addJceProviders) {
70 initializeResourceBundles();
71 setXmlSecIgnoreLineBreak();
72 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
73 public Boolean run() {
74 addXMLDSigRIInternal();
75 return true;
76 }
77 });
78
79 santuarioProviderAdded = true;
80 bcProviderAdded = false;
81 tlProviderAdded = false;
82 }
83 if (FIPSUtils.isFIPSEnabled()) {
84 //So far the in-JDK security provider in FIPS mode
85 //doesn't support RSA-OAEP padding, try use the one
86 //from BC-FIPS as last resort
87 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
88 public Boolean run() {
89 addJceProvider("BCFIPS", "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider");
90 return true;
91 }
92 });
93 }
94 staticallyInitialized = true;
95 }
96 }
97
98 public static synchronized void init(boolean addXMLDSigRIInternalProv, boolean addBCProv, boolean addTLProv) {
99 if (!staticallyInitialized) {
100 initializeResourceBundles();
101 setXmlSecIgnoreLineBreak();
102 santuarioProviderAdded = addXMLDSigRIInternalProv;
103 if (addXMLDSigRIInternalProv) {
104 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
105 public Boolean run() {
106 addXMLDSigRIInternal();
107 return true;
108 }
109 });
110 }
111
112 bcProviderAdded = addBCProv;
113 if (addBCProv) {
114 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
115 public Boolean run() {
116 addJceProvider("BC", "org.bouncycastle.jce.provider.BouncyCastleProvider");
117 return true;
118 }
119 });
120 }
121 if (FIPSUtils.isFIPSEnabled()) {
122 //So far the in-JDK security provider in FIPS mode
123 //doesn't support RSA-OAEP padding, try use the one
124 //from BC-FIPS as last resort
125
126
127 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
128 public Boolean run() {
129 addJceProvider("BCFIPS", "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider");
130 return true;
131 }
132 });
133
134 }
135
136 tlProviderAdded = addTLProv;
137 if (addTLProv) {
138 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
139 public Boolean run() {
140 ThreadLocalSecurityProvider.install();
141 return true;
142 }
143 });
144 }
145 staticallyInitialized = true;
146 }
147 }
148
149 public static synchronized void cleanUp() {
150 if (staticallyInitialized) {
151 if (santuarioProviderAdded) {
152 Security.removeProvider("ApacheXMLDSig");
153 santuarioProviderAdded = false;
154 }
155 if (bcProviderAdded) {
156 Security.removeProvider("BC");
157 bcProviderAdded = false;
158 }
159 if (tlProviderAdded) {
160 Security.removeProvider("TLSP");
161 tlProviderAdded = false;
162 }
163
164 staticallyInitialized = false;
165 }
166 }
167
168 /**
169 * Set the value of the internal addJceProviders flag. This flag
170 * turns on (or off) automatic registration of known JCE providers
171 * that provide necessary cryptographic algorithms for use with WSS4J.
172 * By default, this flag is true. You may wish (or need) to initialize
173 * the JCE manually, e.g., in some JVMs.
174 */
175 public static void setAddJceProviders(boolean value) {
176 addJceProviders = value;
177 }
178
179 public static void setXmlSecIgnoreLineBreak() {
180 //really need to make sure ignoreLineBreaks is set to
181 boolean wasSet = false;
182 try {
183 // Don't override if it was set explicitly
184 wasSet = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
185 public Boolean run() {
186 String lineBreakPropName = "org.apache.xml.security.ignoreLineBreaks";
187 if (System.getProperty(lineBreakPropName) == null) {
188 System.setProperty(lineBreakPropName, "true");
189 return false;
190 }
191 return true;
192 }
193 });
194 } catch (Throwable t) { //NOPMD
195 //ignore
196 }
197 org.apache.xml.security.Init.init();
198 if (!wasSet) {
199 try {
200 AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
201 public Boolean run() throws Exception {
202 Field f = XMLUtils.class.getDeclaredField("ignoreLineBreaks");
203 f.setAccessible(true); //NOPMD
204 f.set(null, Boolean.TRUE);
205 return false;
206 }
207 });
208 } catch (Throwable t) { //NOPMD
209 //ignore
210 }
211 }
212 }
213
214 private static void addXMLDSigRIInternal() {
215 Security.removeProvider("ApacheXMLDSig");
216 addJceProvider("ApacheXMLDSig", SantuarioUtil.getSantuarioProvider());
217 }
218
219 private static void initializeResourceBundles() {
220 I18n.init(new WSS4JResourceBundle());
221 }
222
223 /**
224 * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
225 * either the name of the previously loaded provider, the name of the new loaded provider, or
226 * null if there's an exception in loading the provider.
227 *
228 * @param name
229 * The name string of the provider (this may not be the real name of the provider)
230 * @param className
231 * Name of the class the implements the provider. This class must
232 * be a subclass of <code>java.security.Provider</code>
233 *
234 * @return Returns the actual name of the provider that was loaded
235 */
236 public static String addJceProvider(String name, String className) {
237 Provider currentProvider = Security.getProvider(name);
238 if (currentProvider == null) {
239 try {
240 Class<? extends Provider> clazz = Loader.loadClass(className, false, Provider.class);
241 Provider provider = clazz.getDeclaredConstructor().newInstance();
242 return addJceProvider(name, provider);
243 } catch (Throwable t) {
244 if (LOG.isDebugEnabled()) {
245 LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
246 }
247 return null;
248 }
249 }
250 return currentProvider.getName();
251 }
252
253 /**
254 * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
255 * either the name of the previously loaded provider, the name of the new loaded provider, or
256 * null if there's an exception in loading the provider.
257 *
258 * @param name
259 * The name string of the provider (this may not be the real name of the provider)
260 * @param provider
261 * A subclass of <code>java.security.Provider</code>
262 *
263 * @return Returns the actual name of the provider that was loaded
264 */
265 public static String addJceProvider(String name, Provider provider) {
266 Provider currentProvider = Security.getProvider(name);
267 if (currentProvider == null) {
268 try {
269 int ret = Security.addProvider(provider);
270 if (LOG.isDebugEnabled()) {
271 LOG.debug(
272 "The provider " + provider.getName() + " - "
273 + provider.getVersionStr() + " was added at position: " + ret
274 );
275 }
276 return provider.getName();
277 } catch (Throwable t) {
278 if (LOG.isDebugEnabled()) {
279 LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
280 }
281 return null;
282 }
283 }
284 return currentProvider.getName();
285 }
286
287
288 /**
289 * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
290 * either the name of the previously loaded provider, the name of the new loaded provider, or
291 * null if there's an exception in loading the provider. Append the provider to the provider
292 * list.
293 *
294 * @param name
295 * The name string of the provider (this may not be the real name of the provider)
296 * @param className
297 * Name of the class the implements the provider. This class must
298 * be a subclass of <code>java.security.Provider</code>
299 *
300 * @return Returns the actual name of the provider that was loaded
301 */
302 public static String appendJceProvider(String name, String className) {
303 Provider currentProvider = Security.getProvider(name);
304 if (currentProvider == null) {
305 try {
306 Class<? extends Provider> clazz = Loader.loadClass(className, false, Provider.class);
307 Provider provider = clazz.getDeclaredConstructor().newInstance();
308
309 int ret = Security.addProvider(provider);
310 LOG.debug(
311 "The provider {} was added at position: {}",
312 provider.getName(), ret
313 );
314 return provider.getName();
315 } catch (Throwable t) {
316 if (LOG.isDebugEnabled()) {
317 LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
318 }
319 return null;
320 }
321 }
322 return currentProvider.getName();
323 }
324
325 /**
326 * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
327 * either the name of the previously loaded provider, the name of the new loaded provider, or
328 * null if there's an exception in loading the provider. Append the provider to the provider
329 * list.
330 *
331 * @param name
332 * The name string of the provider (this may not be the real name of the provider)
333 * @param provider
334 * A subclass of <code>java.security.Provider</code>
335 *
336 * @return Returns the actual name of the provider that was loaded
337 */
338 public static String appendJceProvider(String name, Provider provider) {
339 Provider currentProvider = Security.getProvider(name);
340 if (currentProvider == null) {
341 try {
342 int ret = Security.addProvider(provider);
343 LOG.debug(
344 "The provider {} was added at position: {}",
345 provider.getName(), ret
346 );
347 return provider.getName();
348 } catch (Throwable t) {
349 if (LOG.isDebugEnabled()) {
350 LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
351 }
352 return null;
353 }
354 }
355 return currentProvider.getName();
356 }
357
358 }