001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.filter.ssl;
021
022import java.security.KeyStore;
023import java.security.SecureRandom;
024
025import javax.net.ssl.KeyManager;
026import javax.net.ssl.KeyManagerFactory;
027import javax.net.ssl.ManagerFactoryParameters;
028import javax.net.ssl.SSLContext;
029import javax.net.ssl.SSLSessionContext;
030import javax.net.ssl.TrustManager;
031import javax.net.ssl.TrustManagerFactory;
032
033/**
034 * A factory that creates and configures a new {@link SSLContext}.
035 * <p>
036 * If no properties are set the returned {@link SSLContext} will
037 * be equivalent to what the following creates:
038 * <pre>
039 *      SSLContext c = SSLContext.getInstance( "TLS" );
040 *      c.init(null, null, null);
041 * </pre>
042 * <p>
043 * Use the properties prefixed with <code>keyManagerFactory</code> to control
044 * the creation of the {@link KeyManager} to be used.
045 * <p>
046 * Use the properties prefixed with <code>trustManagerFactory</code> to control
047 * the creation of the {@link TrustManagerFactory} to be used.
048 *
049 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
050 */
051public class SslContextFactory {
052
053    private String provider = null;
054
055    private String protocol = "TLS";
056
057    private SecureRandom secureRandom = null;
058
059    private KeyStore keyManagerFactoryKeyStore = null;
060
061    private char[] keyManagerFactoryKeyStorePassword = null;
062
063    private KeyManagerFactory keyManagerFactory = null;
064
065    private String keyManagerFactoryAlgorithm = null;
066
067    private String keyManagerFactoryProvider = null;
068
069    private boolean keyManagerFactoryAlgorithmUseDefault = true;
070
071    private KeyStore trustManagerFactoryKeyStore = null;
072
073    private TrustManagerFactory trustManagerFactory = null;
074
075    private String trustManagerFactoryAlgorithm = null;
076
077    private String trustManagerFactoryProvider = null;
078
079    private boolean trustManagerFactoryAlgorithmUseDefault = true;
080
081    private ManagerFactoryParameters trustManagerFactoryParameters = null;
082
083    private int clientSessionCacheSize = -1;
084
085    private int clientSessionTimeout = -1;
086
087    private int serverSessionCacheSize = -1;
088
089    private int serverSessionTimeout = -1;
090
091    public SSLContext newInstance() throws Exception {
092        KeyManagerFactory kmf = this.keyManagerFactory;
093        TrustManagerFactory tmf = this.trustManagerFactory;
094
095        if (kmf == null) {
096            String algorithm = keyManagerFactoryAlgorithm;
097            if (algorithm == null && keyManagerFactoryAlgorithmUseDefault) {
098                algorithm = KeyManagerFactory.getDefaultAlgorithm();
099            }
100            if (algorithm != null) {
101                if (keyManagerFactoryProvider == null) {
102                    kmf = KeyManagerFactory.getInstance(algorithm);
103                } else {
104                    kmf = KeyManagerFactory.getInstance(algorithm, keyManagerFactoryProvider);
105                }
106            }
107        }
108
109        if (tmf == null) {
110            String algorithm = trustManagerFactoryAlgorithm;
111            if (algorithm == null && trustManagerFactoryAlgorithmUseDefault) {
112                algorithm = TrustManagerFactory.getDefaultAlgorithm();
113            }
114            if (algorithm != null) {
115                if (trustManagerFactoryProvider == null) {
116                    tmf = TrustManagerFactory.getInstance(algorithm);
117                } else {
118                    tmf = TrustManagerFactory.getInstance(algorithm, trustManagerFactoryProvider);
119                }
120            }
121        }
122
123        KeyManager[] keyManagers = null;
124        if (kmf != null) {
125            kmf.init(keyManagerFactoryKeyStore, keyManagerFactoryKeyStorePassword);
126            keyManagers = kmf.getKeyManagers();
127        }
128        TrustManager[] trustManagers = null;
129        if (tmf != null) {
130            if (trustManagerFactoryParameters != null) {
131                tmf.init(trustManagerFactoryParameters);
132            } else {
133                tmf.init(trustManagerFactoryKeyStore);
134            }
135            trustManagers = tmf.getTrustManagers();
136        }
137
138        SSLContext context = null;
139        if (provider == null) {
140            context = SSLContext.getInstance(protocol);
141        } else {
142            context = SSLContext.getInstance(protocol, provider);
143        }
144
145        context.init(keyManagers, trustManagers, secureRandom);
146
147        if (clientSessionCacheSize >= 0) {
148            context.getClientSessionContext().setSessionCacheSize(clientSessionCacheSize);
149        }
150
151        if (clientSessionTimeout >= 0) {
152            context.getClientSessionContext().setSessionTimeout(clientSessionTimeout);
153        }
154
155        if (serverSessionCacheSize >= 0) {
156            context.getServerSessionContext().setSessionCacheSize(serverSessionCacheSize);
157        }
158
159        if (serverSessionTimeout >= 0) {
160            context.getServerSessionContext().setSessionTimeout(serverSessionTimeout);
161        }
162
163        return context;
164    }
165
166    /**
167     * Sets the provider of the new {@link SSLContext}. The default value is
168     * <tt>null</tt>, which means the default provider will be used.
169     * 
170     * @param provider the name of the {@link SSLContext} provider
171     */
172    public void setProvider(String provider) {
173        this.provider = provider;
174    }
175
176    /**
177     * Sets the protocol to use when creating the {@link SSLContext}. The
178     * default is <code>TLS</code>.
179     *
180     * @param protocol the name of the protocol.
181     */
182    public void setProtocol(String protocol) {
183        if (protocol == null) {
184            throw new IllegalArgumentException("protocol");
185        }
186        this.protocol = protocol;
187    }
188
189    /**
190     * If this is set to <tt>true</tt> while no {@link KeyManagerFactory}
191     * has been set using {@link #setKeyManagerFactory(KeyManagerFactory)} and
192     * no algorithm has been set using
193     * {@link #setKeyManagerFactoryAlgorithm(String)} the default algorithm
194     * return by {@link KeyManagerFactory#getDefaultAlgorithm()} will be used.
195     * The default value of this property is <tt>true</tt>.
196     *
197     * @param useDefault
198     *            <tt>true</tt> or <tt>false</tt>.
199     */
200    public void setKeyManagerFactoryAlgorithmUseDefault(boolean useDefault) {
201        this.keyManagerFactoryAlgorithmUseDefault = useDefault;
202    }
203
204    /**
205     * If this is set to <tt>true</tt> while no {@link TrustManagerFactory}
206     * has been set using {@link #setTrustManagerFactory(TrustManagerFactory)} and
207     * no algorithm has been set using
208     * {@link #setTrustManagerFactoryAlgorithm(String)} the default algorithm
209     * return by {@link TrustManagerFactory#getDefaultAlgorithm()} will be used.
210     * The default value of this property is <tt>true</tt>.
211     *
212     * @param useDefault <tt>true</tt> or <tt>false</tt>.
213     */
214    public void setTrustManagerFactoryAlgorithmUseDefault(boolean useDefault) {
215        this.trustManagerFactoryAlgorithmUseDefault = useDefault;
216    }
217
218    /**
219     * Sets the {@link KeyManagerFactory} to use. If this is set the properties
220     * which are used by this factory bean to create a {@link KeyManagerFactory}
221     * will all be ignored.
222     *
223     * @param factory the factory.
224     */
225    public void setKeyManagerFactory(KeyManagerFactory factory) {
226        this.keyManagerFactory = factory;
227    }
228
229    /**
230     * Sets the algorithm to use when creating the {@link KeyManagerFactory}
231     * using {@link KeyManagerFactory#getInstance(java.lang.String)} or
232     * {@link KeyManagerFactory#getInstance(java.lang.String, java.lang.String)}.
233     * <p>
234     * This property will be ignored if a {@link KeyManagerFactory} has been
235     * set directly using {@link #setKeyManagerFactory(KeyManagerFactory)}.
236     * <p>
237     * If this property isn't set while no {@link KeyManagerFactory} has been
238     * set using {@link #setKeyManagerFactory(KeyManagerFactory)} and
239     * {@link #setKeyManagerFactoryAlgorithmUseDefault(boolean)} has been set to
240     * <tt>true</tt> the value returned
241     * by {@link KeyManagerFactory#getDefaultAlgorithm()} will be used instead.
242     *
243     * @param algorithm the algorithm to use.
244     */
245    public void setKeyManagerFactoryAlgorithm(String algorithm) {
246        this.keyManagerFactoryAlgorithm = algorithm;
247    }
248
249    /**
250     * Sets the provider to use when creating the {@link KeyManagerFactory}
251     * using
252     * {@link KeyManagerFactory#getInstance(java.lang.String, java.lang.String)}.
253     * <p>
254     * This property will be ignored if a {@link KeyManagerFactory} has been
255     * set directly using {@link #setKeyManagerFactory(KeyManagerFactory)}.
256     * <p>
257     * If this property isn't set and no {@link KeyManagerFactory} has been set
258     * using {@link #setKeyManagerFactory(KeyManagerFactory)}
259     * {@link KeyManagerFactory#getInstance(java.lang.String)} will be used
260     * to create the {@link KeyManagerFactory}.
261     *
262     * @param provider the name of the provider.
263     */
264    public void setKeyManagerFactoryProvider(String provider) {
265        this.keyManagerFactoryProvider = provider;
266    }
267
268    /**
269     * Sets the {@link KeyStore} which will be used in the call to
270     * {@link KeyManagerFactory#init(java.security.KeyStore, char[])} when
271     * the {@link SSLContext} is created.
272     *
273     * @param keyStore the key store.
274     */
275    public void setKeyManagerFactoryKeyStore(KeyStore keyStore) {
276        this.keyManagerFactoryKeyStore = keyStore;
277    }
278
279    /**
280     * Sets the password which will be used in the call to
281     * {@link KeyManagerFactory#init(java.security.KeyStore, char[])} when
282     * the {@link SSLContext} is created.
283     *
284     * @param password the password. Use <code>null</code> to disable password.
285     */
286    public void setKeyManagerFactoryKeyStorePassword(String password) {
287        if (password != null) {
288            this.keyManagerFactoryKeyStorePassword = password.toCharArray();
289        } else {
290            this.keyManagerFactoryKeyStorePassword = null;
291        }
292    }
293
294    /**
295     * Sets the {@link TrustManagerFactory} to use. If this is set the
296     * properties which are used by this factory bean to create a
297     * {@link TrustManagerFactory} will all be ignored.
298     *
299     * @param factory
300     *            the factory.
301     */
302    public void setTrustManagerFactory(TrustManagerFactory factory) {
303        this.trustManagerFactory = factory;
304    }
305
306    /**
307     * Sets the algorithm to use when creating the {@link TrustManagerFactory}
308     * using {@link TrustManagerFactory#getInstance(java.lang.String)} or
309     * {@link TrustManagerFactory#getInstance(java.lang.String, java.lang.String)}.
310     * <p>
311     * This property will be ignored if a {@link TrustManagerFactory} has been
312     * set directly using {@link #setTrustManagerFactory(TrustManagerFactory)}.
313     * <p>
314     * If this property isn't set while no {@link TrustManagerFactory} has been
315     * set using {@link #setTrustManagerFactory(TrustManagerFactory)} and
316     * {@link #setTrustManagerFactoryAlgorithmUseDefault(boolean)} has been set to
317     * <tt>true</tt> the value returned
318     * by {@link TrustManagerFactory#getDefaultAlgorithm()} will be used instead.
319     *
320     * @param algorithm the algorithm to use.
321     */
322    public void setTrustManagerFactoryAlgorithm(String algorithm) {
323        this.trustManagerFactoryAlgorithm = algorithm;
324    }
325
326    /**
327     * Sets the {@link KeyStore} which will be used in the call to
328     * {@link TrustManagerFactory#init(java.security.KeyStore)} when
329     * the {@link SSLContext} is created.
330     * <p>
331     * This property will be ignored if {@link ManagerFactoryParameters} has been
332     * set directly using {@link #setTrustManagerFactoryParameters(ManagerFactoryParameters)}.
333     *
334     * @param keyStore the key store.
335     */
336    public void setTrustManagerFactoryKeyStore(KeyStore keyStore) {
337        this.trustManagerFactoryKeyStore = keyStore;
338    }
339
340    /**
341     * Sets the {@link ManagerFactoryParameters} which will be used in the call to
342     * {@link TrustManagerFactory#init(javax.net.ssl.ManagerFactoryParameters)} when
343     * the {@link SSLContext} is created.
344     *
345     * @param parameters describing provider-specific trust material.
346     */
347    public void setTrustManagerFactoryParameters(ManagerFactoryParameters parameters) {
348        this.trustManagerFactoryParameters = parameters;
349    }
350
351    /**
352     * Sets the provider to use when creating the {@link TrustManagerFactory}
353     * using
354     * {@link TrustManagerFactory#getInstance(java.lang.String, java.lang.String)}.
355     * <p>
356     * This property will be ignored if a {@link TrustManagerFactory} has been
357     * set directly using {@link #setTrustManagerFactory(TrustManagerFactory)}.
358     * <p>
359     * If this property isn't set and no {@link TrustManagerFactory} has been set
360     * using {@link #setTrustManagerFactory(TrustManagerFactory)}
361     * {@link TrustManagerFactory#getInstance(java.lang.String)} will be used
362     * to create the {@link TrustManagerFactory}.
363     *
364     * @param provider the name of the provider.
365     */
366    public void setTrustManagerFactoryProvider(String provider) {
367        this.trustManagerFactoryProvider = provider;
368    }
369
370    /**
371     * Sets the {@link SecureRandom} to use when initializing the
372     * {@link SSLContext}. The JVM's default will be used if this isn't set.
373     *
374     * @param secureRandom the {@link SecureRandom} or <code>null</code> if the
375     *        JVM's default should be used.
376     * @see SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], java.security.SecureRandom)
377     */
378    public void setSecureRandom(SecureRandom secureRandom) {
379        this.secureRandom = secureRandom;
380    }
381
382    /**
383     * Sets the SSLSession cache size for the {@link SSLSessionContext} for use in client mode.
384     *
385     * @param size the new session cache size limit; zero means there is no limit.
386     * @see SSLSessionContext#setSessionCacheSize(int size)
387     */
388    public void setClientSessionCacheSize(int size) {
389        this.clientSessionCacheSize = size;
390    }
391
392    /**
393     * Set the SSLSession timeout limit for the {@link SSLSessionContext} for use in client mode.
394     *
395     * @param seconds the new session timeout limit in seconds; zero means there is no limit.
396     * @see SSLSessionContext#setSessionTimeout(int seconds)
397     */
398    public void setClientSessionTimeout(int seconds) {
399        this.clientSessionTimeout = seconds;
400    }
401
402    /**
403     * Sets the SSLSession cache size for the {@link SSLSessionContext} for use in server mode.
404     *
405     * @param serverSessionCacheSize the new session cache size limit; zero means there is no limit.
406     * @see SSLSessionContext#setSessionCacheSize(int)
407     */
408    public void setServerSessionCacheSize(int serverSessionCacheSize) {
409        this.serverSessionCacheSize = serverSessionCacheSize;
410    }
411
412    /**
413     * Set the SSLSession timeout limit for the {@link SSLSessionContext} for use in server mode.
414     *
415     * @param serverSessionTimeout the new session timeout limit in seconds; zero means there is no limit.
416     * @see SSLSessionContext#setSessionTimeout(int)
417     */
418    public void setServerSessionTimeout(int serverSessionTimeout) {
419        this.serverSessionTimeout = serverSessionTimeout;
420    }
421}