View Javadoc
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.mina.filter.ssl;
21  
22  import java.security.KeyStore;
23  import java.security.SecureRandom;
24  
25  import javax.net.ssl.KeyManager;
26  import javax.net.ssl.KeyManagerFactory;
27  import javax.net.ssl.ManagerFactoryParameters;
28  import javax.net.ssl.SSLContext;
29  import javax.net.ssl.SSLSessionContext;
30  import javax.net.ssl.TrustManager;
31  import javax.net.ssl.TrustManagerFactory;
32  
33  /**
34   * A factory that creates and configures a new {@link SSLContext}.
35   * <p>
36   * If no properties are set the returned {@link SSLContext} will
37   * be equivalent to what the following creates:
38   * <pre>
39   *      SSLContext c = SSLContext.getInstance( "TLS" );
40   *      c.init(null, null, null);
41   * </pre>
42   * </p>
43   * <p>
44   * Use the properties prefixed with <code>keyManagerFactory</code> to control
45   * the creation of the {@link KeyManager} to be used.
46   * </p>
47   * <p>
48   * Use the properties prefixed with <code>trustManagerFactory</code> to control
49   * the creation of the {@link TrustManagerFactory} to be used.
50   * </p>
51   *
52   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
53   */
54  public class SslContextFactory {
55  
56      private String provider = null;
57  
58      private String protocol = "TLS";
59  
60      private SecureRandom secureRandom = null;
61  
62      private KeyStore keyManagerFactoryKeyStore = null;
63  
64      private char[] keyManagerFactoryKeyStorePassword = null;
65  
66      private KeyManagerFactory keyManagerFactory = null;
67  
68      private String keyManagerFactoryAlgorithm = null;
69  
70      private String keyManagerFactoryProvider = null;
71  
72      private boolean keyManagerFactoryAlgorithmUseDefault = true;
73  
74      private KeyStore trustManagerFactoryKeyStore = null;
75  
76      private TrustManagerFactory trustManagerFactory = null;
77  
78      private String trustManagerFactoryAlgorithm = null;
79  
80      private String trustManagerFactoryProvider = null;
81  
82      private boolean trustManagerFactoryAlgorithmUseDefault = true;
83  
84      private ManagerFactoryParameters trustManagerFactoryParameters = null;
85  
86      private int clientSessionCacheSize = -1;
87  
88      private int clientSessionTimeout = -1;
89  
90      private int serverSessionCacheSize = -1;
91  
92      private int serverSessionTimeout = -1;
93  
94      public SSLContext newInstance() throws Exception {
95          KeyManagerFactory kmf = this.keyManagerFactory;
96          TrustManagerFactory tmf = this.trustManagerFactory;
97  
98          if (kmf == null) {
99              String algorithm = keyManagerFactoryAlgorithm;
100             if (algorithm == null && keyManagerFactoryAlgorithmUseDefault) {
101                 algorithm = KeyManagerFactory.getDefaultAlgorithm();
102             }
103             if (algorithm != null) {
104                 if (keyManagerFactoryProvider == null) {
105                     kmf = KeyManagerFactory.getInstance(algorithm);
106                 } else {
107                     kmf = KeyManagerFactory.getInstance(algorithm, keyManagerFactoryProvider);
108                 }
109             }
110         }
111 
112         if (tmf == null) {
113             String algorithm = trustManagerFactoryAlgorithm;
114             if (algorithm == null && trustManagerFactoryAlgorithmUseDefault) {
115                 algorithm = TrustManagerFactory.getDefaultAlgorithm();
116             }
117             if (algorithm != null) {
118                 if (trustManagerFactoryProvider == null) {
119                     tmf = TrustManagerFactory.getInstance(algorithm);
120                 } else {
121                     tmf = TrustManagerFactory.getInstance(algorithm, trustManagerFactoryProvider);
122                 }
123             }
124         }
125 
126         KeyManager[] keyManagers = null;
127         if (kmf != null) {
128             kmf.init(keyManagerFactoryKeyStore, keyManagerFactoryKeyStorePassword);
129             keyManagers = kmf.getKeyManagers();
130         }
131         TrustManager[] trustManagers = null;
132         if (tmf != null) {
133             if (trustManagerFactoryParameters != null) {
134                 tmf.init(trustManagerFactoryParameters);
135             } else {
136                 tmf.init(trustManagerFactoryKeyStore);
137             }
138             trustManagers = tmf.getTrustManagers();
139         }
140 
141         SSLContext context = null;
142         if (provider == null) {
143             context = SSLContext.getInstance(protocol);
144         } else {
145             context = SSLContext.getInstance(protocol, provider);
146         }
147 
148         context.init(keyManagers, trustManagers, secureRandom);
149 
150         if (clientSessionCacheSize >= 0) {
151             context.getClientSessionContext().setSessionCacheSize(clientSessionCacheSize);
152         }
153 
154         if (clientSessionTimeout >= 0) {
155             context.getClientSessionContext().setSessionTimeout(clientSessionTimeout);
156         }
157 
158         if (serverSessionCacheSize >= 0) {
159             context.getServerSessionContext().setSessionCacheSize(serverSessionCacheSize);
160         }
161 
162         if (serverSessionTimeout >= 0) {
163             context.getServerSessionContext().setSessionTimeout(serverSessionTimeout);
164         }
165 
166         return context;
167     }
168 
169     /**
170      * Sets the provider of the new {@link SSLContext}. The default value is
171      * <tt>null</tt>, which means the default provider will be used.
172      * 
173      * @param provider the name of the {@link SSLContext} provider
174      */
175     public void setProvider(String provider) {
176         this.provider = provider;
177     }
178 
179     /**
180      * Sets the protocol to use when creating the {@link SSLContext}. The
181      * default is <code>TLS</code>.
182      *
183      * @param protocol the name of the protocol.
184      */
185     public void setProtocol(String protocol) {
186         if (protocol == null) {
187             throw new IllegalArgumentException("protocol");
188         }
189         this.protocol = protocol;
190     }
191 
192     /**
193      * If this is set to <code>true</code> while no {@link KeyManagerFactory}
194      * has been set using {@link #setKeyManagerFactory(KeyManagerFactory)} and
195      * no algorithm has been set using
196      * {@link #setKeyManagerFactoryAlgorithm(String)} the default algorithm
197      * return by {@link KeyManagerFactory#getDefaultAlgorithm()} will be used.
198      * The default value of this property is <tt>true</tt>.
199      *
200      * @param useDefault
201      *            <code>true</code> or <code>false</code>.
202      */
203     public void setKeyManagerFactoryAlgorithmUseDefault(boolean useDefault) {
204         this.keyManagerFactoryAlgorithmUseDefault = useDefault;
205     }
206 
207     /**
208      * If this is set to <code>true</code> while no {@link TrustManagerFactory}
209      * has been set using {@link #setTrustManagerFactory(TrustManagerFactory)} and
210      * no algorithm has been set using
211      * {@link #setTrustManagerFactoryAlgorithm(String)} the default algorithm
212      * return by {@link TrustManagerFactory#getDefaultAlgorithm()} will be used.
213      * The default value of this property is <tt>true</tt>.
214      *
215      * @param useDefault <code>true</code> or <code>false</code>.
216      */
217     public void setTrustManagerFactoryAlgorithmUseDefault(boolean useDefault) {
218         this.trustManagerFactoryAlgorithmUseDefault = useDefault;
219     }
220 
221     /**
222      * Sets the {@link KeyManagerFactory} to use. If this is set the properties
223      * which are used by this factory bean to create a {@link KeyManagerFactory}
224      * will all be ignored.
225      *
226      * @param factory the factory.
227      */
228     public void setKeyManagerFactory(KeyManagerFactory factory) {
229         this.keyManagerFactory = factory;
230     }
231 
232     /**
233      * Sets the algorithm to use when creating the {@link KeyManagerFactory}
234      * using {@link KeyManagerFactory#getInstance(java.lang.String)} or
235      * {@link KeyManagerFactory#getInstance(java.lang.String, java.lang.String)}.
236      * <p>
237      * This property will be ignored if a {@link KeyManagerFactory} has been
238      * set directly using {@link #setKeyManagerFactory(KeyManagerFactory)}.
239      * </p>
240      * <p>
241      * If this property isn't set while no {@link KeyManagerFactory} has been
242      * set using {@link #setKeyManagerFactory(KeyManagerFactory)} and
243      * {@link #setKeyManagerFactoryAlgorithmUseDefault(boolean)} has been set to
244      * <code>true</code> the value returned
245      * by {@link KeyManagerFactory#getDefaultAlgorithm()} will be used instead.
246      * </p>
247      *
248      * @param algorithm the algorithm to use.
249      */
250     public void setKeyManagerFactoryAlgorithm(String algorithm) {
251         this.keyManagerFactoryAlgorithm = algorithm;
252     }
253 
254     /**
255      * Sets the provider to use when creating the {@link KeyManagerFactory}
256      * using
257      * {@link KeyManagerFactory#getInstance(java.lang.String, java.lang.String)}.
258      * <p>
259      * This property will be ignored if a {@link KeyManagerFactory} has been
260      * set directly using {@link #setKeyManagerFactory(KeyManagerFactory)}.
261      * </p>
262      * <p>
263      * If this property isn't set and no {@link KeyManagerFactory} has been set
264      * using {@link #setKeyManagerFactory(KeyManagerFactory)}
265      * {@link KeyManagerFactory#getInstance(java.lang.String)} will be used
266      * to create the {@link KeyManagerFactory}.
267      * </p>
268      *
269      * @param provider the name of the provider.
270      */
271     public void setKeyManagerFactoryProvider(String provider) {
272         this.keyManagerFactoryProvider = provider;
273     }
274 
275     /**
276      * Sets the {@link KeyStore} which will be used in the call to
277      * {@link KeyManagerFactory#init(java.security.KeyStore, char[])} when
278      * the {@link SSLContext} is created.
279      *
280      * @param keyStore the key store.
281      */
282     public void setKeyManagerFactoryKeyStore(KeyStore keyStore) {
283         this.keyManagerFactoryKeyStore = keyStore;
284     }
285 
286     /**
287      * Sets the password which will be used in the call to
288      * {@link KeyManagerFactory#init(java.security.KeyStore, char[])} when
289      * the {@link SSLContext} is created.
290      *
291      * @param password the password. Use <code>null</code> to disable password.
292      */
293     public void setKeyManagerFactoryKeyStorePassword(String password) {
294         if (password != null) {
295             this.keyManagerFactoryKeyStorePassword = password.toCharArray();
296         } else {
297             this.keyManagerFactoryKeyStorePassword = null;
298         }
299     }
300 
301     /**
302      * Sets the {@link TrustManagerFactory} to use. If this is set the
303      * properties which are used by this factory bean to create a
304      * {@link TrustManagerFactory} will all be ignored.
305      *
306      * @param factory
307      *            the factory.
308      */
309     public void setTrustManagerFactory(TrustManagerFactory factory) {
310         this.trustManagerFactory = factory;
311     }
312 
313     /**
314      * Sets the algorithm to use when creating the {@link TrustManagerFactory}
315      * using {@link TrustManagerFactory#getInstance(java.lang.String)} or
316      * {@link TrustManagerFactory#getInstance(java.lang.String, java.lang.String)}.
317      * <p>
318      * This property will be ignored if a {@link TrustManagerFactory} has been
319      * set directly using {@link #setTrustManagerFactory(TrustManagerFactory)}.
320      * </p>
321      * <p>
322      * If this property isn't set while no {@link TrustManagerFactory} has been
323      * set using {@link #setTrustManagerFactory(TrustManagerFactory)} and
324      * {@link #setTrustManagerFactoryAlgorithmUseDefault(boolean)} has been set to
325      * <code>true</code> the value returned
326      * by {@link TrustManagerFactory#getDefaultAlgorithm()} will be used instead.
327      * </p>
328      *
329      * @param algorithm the algorithm to use.
330      */
331     public void setTrustManagerFactoryAlgorithm(String algorithm) {
332         this.trustManagerFactoryAlgorithm = algorithm;
333     }
334 
335     /**
336      * Sets the {@link KeyStore} which will be used in the call to
337      * {@link TrustManagerFactory#init(java.security.KeyStore)} when
338      * the {@link SSLContext} is created.
339      * <p>
340      * This property will be ignored if {@link ManagerFactoryParameters} has been
341      * set directly using {@link #setTrustManagerFactoryParameters(ManagerFactoryParameters)}.
342      * </p>
343      *
344      * @param keyStore the key store.
345      */
346     public void setTrustManagerFactoryKeyStore(KeyStore keyStore) {
347         this.trustManagerFactoryKeyStore = keyStore;
348     }
349 
350     /**
351      * Sets the {@link ManagerFactoryParameters} which will be used in the call to
352      * {@link TrustManagerFactory#init(javax.net.ssl.ManagerFactoryParameters)} when
353      * the {@link SSLContext} is created.
354      *
355      * @param parameters describing provider-specific trust material.
356      */
357     public void setTrustManagerFactoryParameters(ManagerFactoryParameters parameters) {
358         this.trustManagerFactoryParameters = parameters;
359     }
360 
361     /**
362      * Sets the provider to use when creating the {@link TrustManagerFactory}
363      * using
364      * {@link TrustManagerFactory#getInstance(java.lang.String, java.lang.String)}.
365      * <p>
366      * This property will be ignored if a {@link TrustManagerFactory} has been
367      * set directly using {@link #setTrustManagerFactory(TrustManagerFactory)}.
368      * </p>
369      * <p>
370      * If this property isn't set and no {@link TrustManagerFactory} has been set
371      * using {@link #setTrustManagerFactory(TrustManagerFactory)}
372      * {@link TrustManagerFactory#getInstance(java.lang.String)} will be used
373      * to create the {@link TrustManagerFactory}.
374      * </p>
375      *
376      * @param provider the name of the provider.
377      */
378     public void setTrustManagerFactoryProvider(String provider) {
379         this.trustManagerFactoryProvider = provider;
380     }
381 
382     /**
383      * Sets the {@link SecureRandom} to use when initializing the
384      * {@link SSLContext}. The JVM's default will be used if this isn't set.
385      *
386      * @param secureRandom the {@link SecureRandom} or <code>null</code> if the
387      *        JVM's default should be used.
388      * @see SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], java.security.SecureRandom)
389      */
390     public void setSecureRandom(SecureRandom secureRandom) {
391         this.secureRandom = secureRandom;
392     }
393 
394     /**
395      * Sets the SSLSession cache size for the {@link SSLSessionContext} for use in client mode.
396      *
397      * @param size the new session cache size limit; zero means there is no limit.
398      * @see SSLSessionContext#setSessionCacheSize(int size)
399      */
400     public void setClientSessionCacheSize(int size) {
401         this.clientSessionCacheSize = size;
402     }
403 
404     /**
405      * Set the SSLSession timeout limit for the {@link SSLSessionContext} for use in client mode.
406      *
407      * @param seconds the new session timeout limit in seconds; zero means there is no limit.
408      * @see SSLSessionContext#setSessionTimeout(int seconds)
409      */
410     public void setClientSessionTimeout(int seconds) {
411         this.clientSessionTimeout = seconds;
412     }
413 
414     /**
415      * Sets the SSLSession cache size for the {@link SSLSessionContext} for use in server mode.
416      *
417      * @param serverSessionCacheSize the new session cache size limit; zero means there is no limit.
418      * @see SSLSessionContext#setSessionCacheSize(int)
419      */
420     public void setServerSessionCacheSize(int serverSessionCacheSize) {
421         this.serverSessionCacheSize = serverSessionCacheSize;
422     }
423 
424     /**
425      * Set the SSLSession timeout limit for the {@link SSLSessionContext} for use in server mode.
426      *
427      * @param serverSessionTimeout the new session timeout limit in seconds; zero means there is no limit.
428      * @see SSLSessionContext#setSessionTimeout(int)
429      */
430     public void setServerSessionTimeout(int serverSessionTimeout) {
431         this.serverSessionTimeout = serverSessionTimeout;
432     }
433 }