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