KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > remoting > security > SSLSocketBuilder


1 /*
2  * JBoss, the OpenSource J2EE webOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.remoting.security;
8
9 import java.io.File JavaDoc;
10 import java.io.IOException JavaDoc;
11 import java.io.InputStream JavaDoc;
12 import java.net.MalformedURLException JavaDoc;
13 import java.net.URL JavaDoc;
14 import java.security.AccessController JavaDoc;
15 import java.security.InvalidParameterException JavaDoc;
16 import java.security.KeyManagementException JavaDoc;
17 import java.security.KeyStore JavaDoc;
18 import java.security.KeyStoreException JavaDoc;
19 import java.security.NoSuchAlgorithmException JavaDoc;
20 import java.security.PrivilegedAction JavaDoc;
21 import java.security.UnrecoverableKeyException JavaDoc;
22 import java.security.cert.CertificateException JavaDoc;
23 import javax.net.ServerSocketFactory;
24 import javax.net.SocketFactory;
25 import javax.net.ssl.KeyManager;
26 import javax.net.ssl.KeyManagerFactory;
27 import javax.net.ssl.SSLContext;
28 import javax.net.ssl.SSLServerSocketFactory;
29 import javax.net.ssl.SSLSocketFactory;
30 import javax.net.ssl.TrustManager;
31 import javax.net.ssl.TrustManagerFactory;
32
33 /**
34  * This builds SSL server socket factories and SSL socket factories.<p/>
35  * The main methods are createSSLServerSocketFactory() and createSSLSocketFactory().
36  * By default, these methods will use SSLServerSocketFactory.getDefault() and
37  * SSLSocketFactory.getDefault() and will require the proper system properties to
38  * be set. To use a custom configuration, will need to set either the useSSLServerSocketFactory or useSSLSocketFactory
39  * properties to be false.<p/>
40  * Some common errors seen are:<p/>
41  * <p/>
42  * 1. javax.net.ssl.SSLException: No available certificate corresponds to the SSL cipher suites which are enabled <p/>
43  * <p/>
44  * The 'javax.net.ssl.keyStore' system property has not been set and are using the default SSLServerSocketFactory.<p/>
45  * <p/>
46  * 2. java.net.SocketException: Default SSL context init failed: Cannot recover key <p/>
47  * <p/>
48  * The 'javax.net.ssl.keyStorePassword' system property has not been set and are using the default SSLServerSocketFactory. <p/>
49  * <p/>
50  * 3. java.io.IOException: Can not create SSL Server Socket Factory due to the url to the key store not being set. <p/>
51  * <p/>
52  * The default SSLServerSocketFactory is NOT being used (so custom configuration for the server socket factory) and the key store url has not been set. <p/>
53  * <p/>
54  * 4. java.lang.IllegalArgumentException: password can't be null <p/>
55  * <p/>
56  * The default SSLServerSocketFactory is NOT being used (so custom configuration for the server socket factory) and the key store password has not been set. <p/>
57  *
58  * @author <a HREF="mailto:tom.elrod@jboss.com">Tom Elrod</a>
59  */

60 public class SSLSocketBuilder implements SSLSocketBuilderMBean
61 {
62    /**
63     * Value is TLS (Transport Layer Security).
64     */

65    public static final String JavaDoc DEFAULT_SECURE_SOCKET_PROTOCOL = "TLS";
66    /**
67     * Value is SunX509.
68     */

69    public static final String JavaDoc DEFAULT_KEY_MANAGEMENT_ALGORITHM = "SunX509";
70    /**
71     * Value is JKS
72     */

73    public static final String JavaDoc DEFAULT_KEY_STORE_TYPE = "JKS";
74
75    /**
76     * Defaults to DEFAULT_SECURE_SOCKET_PROTOCOL. Some acceptable values are TLS, SSL, and SSLv3.
77     */

78    private String JavaDoc secureSocketProtocol = DEFAULT_SECURE_SOCKET_PROTOCOL;
79
80    /**
81     * Defaults to DEFAULT_KEY_MANAGEMENT_ALGORITHM.
82     */

83    private String JavaDoc keyManagementAlgorithm = DEFAULT_KEY_MANAGEMENT_ALGORITHM;
84
85    /**
86     * Defaults to DEFAULT_KEY_STORE_TYPE. Some acceptable values are JKS (Java Keystore - Sun's keystore format),
87     * JCEKS (Java Cryptography Extension keystore - More secure version of JKS), and
88     * PKCS12 (Public-Key Cryptography Standards #12 keystore - RSA's Personal Information Exchange Syntax Standard).
89     * These are not case sensitive.
90     */

91    private String JavaDoc keyStoreType = DEFAULT_KEY_STORE_TYPE;
92
93    private boolean useSSLServerSocketFactory = true;
94    private boolean useSSLSocketFactory = true;
95    private char[] keyStorePassword = null;
96    private char[] keyPassword = null;
97    private URL JavaDoc keyStoreURL = null;
98    private URL JavaDoc trustStoreURL = null;
99
100    public SSLSocketBuilder()
101    {
102    }
103
104    /**
105     * Will indicate if should use the SSLServerSocketFactory.getDefault() for getting the ServerSocketFactory
106     * to use (when calling createSSLServerSocketFactory()).
107     * If true, will allow for setting key store location (via javax.net.ssl.keyStore system property) and
108     * setting of the key store password (via javax.net.ssl.keyStorePassword system property) and no other
109     * configuration is needed (none of the other setters will need to be called and are in fact ignored). If set to
110     * false, will allow the custom setting of secure socket protocol, key management algorithm, key store type,
111     * key store url, key store password, and key password.<p/>
112     * The default value is true.<p/>
113     * <b>NOTE: If this is not explicitly set to false, no customizations can be made and the default implementation
114     * provided by the JVM vendor being used will be executed.</b>
115     *
116     * @param shouldUse
117     */

118    public void setUseSSLServerSocketFactory(boolean shouldUse)
119    {
120       this.useSSLServerSocketFactory = shouldUse;
121    }
122
123    /**
124     * Return whether SSLServerSocketFactory.getDefault() will be used or not. See setUseSSLServerSocketFactory() for more
125     * information on what this means.
126     *
127     * @return
128     */

129    public boolean getUseSSLServerSocketFactory()
130    {
131       return useSSLServerSocketFactory;
132    }
133
134    /**
135     * Will indicate if should use the SSLSocketFactory.getDefault() for getting the SocketFactory
136     * to use (when calling createSSLSocketFactory()).
137     * If true, will allow for setting trust store location (via Djavax.net.ssl.trustStore system property) and no other
138     * configuration is needed (none of the other setters will need to be called and are in fact ignored). If set to
139     * false, will allow the custom setting of secure socket protocol, key management algorithm, key store type,
140     * ant trust store url.<p/>
141     * The default value is true.<p/>
142     * <b>NOTE: If this is not explicitly set to false, no customizations can be made and the default implementation
143     * provided by the JVM vendor being used will be executed.</b>
144     *
145     * @param shouldUse
146     */

147    public void setUseSSLSocketFactory(boolean shouldUse)
148    {
149       this.useSSLSocketFactory = shouldUse;
150    }
151
152    /**
153     * Return whether SSLSocketFactory.getDefault() will be used or not. See setUseSSLSocketFactory() for more
154     * information on what this means.
155     *
156     * @return
157     */

158    public boolean getUseSSLSocketFactory()
159    {
160       return useSSLSocketFactory;
161    }
162
163    /**
164     * The protocol for the SSLContext. Some acceptable values are TLS, SSL, and SSLv3.
165     * Defaults to DEFAULT_SECURE_SOCKET_PROTOCOL.
166     */

167    public String JavaDoc getSecureSocketProtocol()
168    {
169       return secureSocketProtocol;
170    }
171
172    /**
173     * The protocol for the SSLContext. Some acceptable values are TLS, SSL, and SSLv3.
174     * Defaults to DEFAULT_SECURE_SOCKET_PROTOCOL.
175     */

176    public void setSecureSocketProtocol(String JavaDoc secureSocketProtocol)
177    {
178       this.secureSocketProtocol = secureSocketProtocol;
179    }
180
181    /**
182     * The algorithm for the key manager factory.
183     * Defaults to DEFAULT_KEY_MANAGEMENT_ALGORITHM.
184     */

185    public String JavaDoc getKeyManagementAlgorithm()
186    {
187       return keyManagementAlgorithm;
188    }
189
190    /**
191     * The algorithm for the key manager factory.
192     * Defaults to DEFAULT_KEY_MANAGEMENT_ALGORITHM.
193     */

194    public void setKeyManagementAlgorithm(String JavaDoc keyManagementAlgorithm)
195    {
196       this.keyManagementAlgorithm = keyManagementAlgorithm;
197    }
198
199    /**
200     * The type to be used for the key store.
201     * Defaults to DEFAULT_KEY_STORE_TYPE. Some acceptable values are JKS (Java Keystore - Sun's keystore format),
202     * JCEKS (Java Cryptography Extension keystore - More secure version of JKS), and
203     * PKCS12 (Public-Key Cryptography Standards #12 keystore - RSA's Personal Information Exchange Syntax Standard).
204     * These are not case sensitive.
205     */

206    public String JavaDoc getKeyStoreType()
207    {
208       return keyStoreType;
209    }
210
211    /**
212     * The type to be used for the key store.
213     * Defaults to DEFAULT_KEY_STORE_TYPE. Some acceptable values are JKS (Java Keystore - Sun's keystore format),
214     * JCEKS (Java Cryptography Extension keystore - More secure version of JKS), and
215     * PKCS12 (Public-Key Cryptography Standards #12 keystore - RSA's Personal Information Exchange Syntax Standard).
216     * These are not case sensitive.
217     */

218    public void setKeyStoreType(String JavaDoc keyStoreType)
219    {
220       this.keyStoreType = keyStoreType;
221    }
222
223    /**
224     * Sets the password to use for the key store. This only needs to be set if setUseSSLServerSocketFactory() is set
225     * to false (otherwise will be ignored). The value passed will also be used for the key password if it is not
226     * explicitly set.
227     *
228     * @param passphrase
229     */

230    public void setKeyStorePassword(String JavaDoc passphrase)
231    {
232       if(passphrase != null && passphrase.length() > 0)
233       {
234          keyStorePassword = passphrase.toCharArray();
235       }
236       else
237       {
238          throw new InvalidParameterException JavaDoc("Must enter a non null key store passphrase with at least one character.");
239       }
240    }
241
242    /**
243     * Sets the password to use for the keys within the key store. This only needs to be set if setUseSSLServerSocketFactory()
244     * is set to false (otherwise will be ignored). If this value is not set, but the key store password is, it will use
245     * that value for the key password.
246     *
247     * @param passphrase
248     */

249    public void setKeyPassword(String JavaDoc passphrase)
250    {
251       if(passphrase != null && passphrase.length() > 0)
252       {
253          keyPassword = passphrase.toCharArray();
254       }
255       else
256       {
257          throw new InvalidParameterException JavaDoc("Must enter a non null key passphrase with at least one character.");
258       }
259    }
260
261    /**
262     * Will create a SSLServerSocketFactory. If the useSSLServerSocketFactory property is set to true (which is the default),
263     * it will use SSLServerSocketFactory.getDefault() to get the server socket factory. Otherwise, if property is false,
264     * will use all the other custom properties that have been set to create a custom server socket factory.
265     *
266     * @return
267     * @throws IOException
268     * @throws NoSuchAlgorithmException
269     * @throws KeyStoreException
270     * @throws CertificateException
271     * @throws UnrecoverableKeyException
272     * @throws KeyManagementException
273     */

274    public ServerSocketFactory createSSLServerSocketFactory()
275          throws IOException JavaDoc, NoSuchAlgorithmException JavaDoc, KeyStoreException JavaDoc,
276                 CertificateException JavaDoc, UnrecoverableKeyException JavaDoc, KeyManagementException JavaDoc
277    {
278       ServerSocketFactory ssf = null;
279
280       if(useSSLServerSocketFactory)
281       {
282          ssf = SSLServerSocketFactory.getDefault();
283       }
284       else
285       {
286          ssf = createCustomServerSocketFactory();
287       }
288
289       return ssf;
290    }
291
292    /**
293     * This is the full on custom ssl server socket configuration. The only thing not allowed at this point
294     * is the changing of providers. Everything else, including the protocol, algorithm, and key store type
295     * can be customized.
296     *
297     * @return
298     * @throws NoSuchAlgorithmException
299     * @throws KeyStoreException
300     * @throws IOException
301     * @throws CertificateException
302     * @throws UnrecoverableKeyException
303     * @throws KeyManagementException
304     */

305    private ServerSocketFactory createCustomServerSocketFactory()
306          throws NoSuchAlgorithmException JavaDoc, KeyStoreException JavaDoc, IOException JavaDoc,
307                 CertificateException JavaDoc, UnrecoverableKeyException JavaDoc, KeyManagementException JavaDoc
308    {
309       ServerSocketFactory ssf = null;
310
311       SSLContext sslContext = SSLContext.getInstance(secureSocketProtocol);
312       KeyManagerFactory keyMgrFactory = getKeyManagerFactory();
313
314       KeyManager[] keyManagers = keyMgrFactory.getKeyManagers();
315       sslContext.init(keyManagers, null, null);
316       ssf = sslContext.getServerSocketFactory();
317
318       return ssf;
319    }
320
321    /**
322     * Will create a SSLSocketFactory. If the useSSLSocketFactory property is set to true (which is the default),
323     * it will use SSLSocketFactory.getDefault() to get the socket factory. Otherwise, if property is false,
324     * will use all the other custom properties that have been set to create a custom server socket factory.
325     *
326     * @return
327     * @throws IOException
328     * @throws NoSuchAlgorithmException
329     * @throws KeyStoreException
330     * @throws CertificateException
331     * @throws KeyManagementException
332     */

333    public SocketFactory createSSLSocketFactory()
334          throws IOException JavaDoc, NoSuchAlgorithmException JavaDoc, KeyStoreException JavaDoc,
335                 CertificateException JavaDoc, KeyManagementException JavaDoc
336    {
337       SocketFactory sf = null;
338
339       if(useSSLSocketFactory)
340       {
341          sf = SSLSocketFactory.getDefault();
342       }
343       else
344       {
345          sf = createCustomSocketFactory();
346       }
347
348       return sf;
349    }
350
351
352    private SocketFactory createCustomSocketFactory()
353          throws NoSuchAlgorithmException JavaDoc, IOException JavaDoc, CertificateException JavaDoc, KeyStoreException JavaDoc, KeyManagementException JavaDoc
354    {
355       SocketFactory sf = null;
356
357       SSLContext sslContext = SSLContext.getInstance(secureSocketProtocol);
358       TrustManagerFactory trustMgrFactory = getTrustManagerFactory();
359
360       TrustManager[] trustManagers = trustMgrFactory.getTrustManagers();
361       sslContext.init(null, trustManagers, null);
362       sf = sslContext.getSocketFactory();
363
364       return sf;
365    }
366
367    private TrustManagerFactory getTrustManagerFactory()
368          throws NoSuchAlgorithmException JavaDoc, IOException JavaDoc, CertificateException JavaDoc, KeyStoreException JavaDoc
369    {
370       TrustManagerFactory truestMgrFactory = null;
371
372       truestMgrFactory = TrustManagerFactory.getInstance(keyManagementAlgorithm);
373       KeyStore JavaDoc keyStore = getKeyStore(trustStoreURL);
374       truestMgrFactory.init(keyStore);
375
376       return truestMgrFactory;
377
378    }
379
380    private KeyManagerFactory getKeyManagerFactory()
381          throws NoSuchAlgorithmException JavaDoc, KeyStoreException JavaDoc, IOException JavaDoc, CertificateException JavaDoc, UnrecoverableKeyException JavaDoc
382    {
383       KeyManagerFactory keyMgrFactory = null;
384
385       keyMgrFactory = KeyManagerFactory.getInstance(keyManagementAlgorithm);
386       KeyStore JavaDoc keyStore = getKeyStore(keyStoreURL);
387       keyMgrFactory.init(keyStore, keyPassword);
388
389       return keyMgrFactory;
390
391    }
392
393    private KeyStore JavaDoc getKeyStore(URL JavaDoc storeURL) throws KeyStoreException JavaDoc, IOException JavaDoc, NoSuchAlgorithmException JavaDoc, CertificateException JavaDoc
394    {
395       KeyStore JavaDoc keyStore = KeyStore.getInstance(keyStoreType);
396       if(storeURL == null)
397       {
398          throw new IOException JavaDoc("Can not create SSL Server Socket Factory due to the url to the key store not being set.");
399       }
400       InputStream JavaDoc is = storeURL.openStream();
401       keyStore.load(is, keyStorePassword);
402
403       // if key password not set, just try the key store password
404
if(keyPassword == null || keyPassword.length > 0)
405       {
406          keyPassword = keyStorePassword;
407       }
408
409       return keyStore;
410
411    }
412
413    /**
414     * This is the url string to the key store to use. If UseSSLServerSocketFactory is true, this will be ignored
415     * and will use the value set by the javax.net.ssl.keyStore system property. Otherwise, if UseSSLServerSocketFactory
416     * is false, this must be set.
417     *
418     * @param storeURL
419     * @throws IOException
420     */

421    public void setKeyStoreURL(String JavaDoc storeURL) throws IOException JavaDoc
422    {
423       this.keyStoreURL = this.validateStoreURL(storeURL);
424    }
425
426    /**
427     * This is the url string to the trust store to use. If UseSSLSocketFactory is true, this will be ignored
428     * and will use the value set by the javax.net.ssl.trustStore system property. Otherwise, if UseSSLSocketFactory
429     * is false, this must be set.
430     *
431     * @param storeURL
432     * @throws IOException
433     */

434    public void setTrustStoreURL(String JavaDoc storeURL) throws IOException JavaDoc
435    {
436       this.trustStoreURL = this.validateStoreURL(storeURL);
437    }
438
439    private URL JavaDoc validateStoreURL(String JavaDoc storeURL) throws IOException JavaDoc
440    {
441       URL JavaDoc url = null;
442       // First see if this is a URL
443
try
444       {
445          url = new URL JavaDoc(storeURL);
446       }
447       catch(MalformedURLException JavaDoc e)
448       {
449          // Not a URL or a protocol without a handler
450
}
451
452       // Next try to locate this as file path
453
if(url == null)
454       {
455          File JavaDoc tst = new File JavaDoc(storeURL);
456          if(tst.exists() == true)
457          {
458             url = tst.toURL();
459          }
460       }
461
462       // Last try to locate this as a classpath resource
463
if(url == null)
464       {
465          ClassLoader JavaDoc loader = getContextClassLoader();
466          url = loader.getResource(storeURL);
467       }
468
469       // Fail if no valid key store was located
470
if(url == null)
471       {
472          String JavaDoc msg = "Failed to find url=" + storeURL + " as a URL, file or resource";
473          throw new MalformedURLException JavaDoc(msg);
474       }
475       return url;
476    }
477
478    /****************************************************************************************************************
479     * The following are just needed in order to make it a service mbean. They are just NOOPs (no implementation). *
480     ****************************************************************************************************************/

481
482    /**
483     * create the service, do expensive operations etc
484     */

485    public void create() throws Exception JavaDoc
486    {
487       //NOOP - nothing to do here. Just needed for mbean service api
488
}
489
490    /**
491     * start the service, create is already called
492     */

493    public void start() throws Exception JavaDoc
494    {
495       //NOOP - nothing to do here. Just needed for mbean service api
496
}
497
498    /**
499     * stop the service
500     */

501    public void stop()
502    {
503       //NOOP - nothing to do here. Just needed for mbean service api
504
}
505
506    /**
507     * destroy the service, tear down
508     */

509    public void destroy()
510    {
511       //NOOP - nothing to do here. Just needed for mbean service api
512
}
513
514
515    // TODO: -TME getContextClassLoader() and GetTCLAction were both taken from org.jboss.security.plugins package
516
static ClassLoader JavaDoc getContextClassLoader()
517    {
518       ClassLoader JavaDoc loader = (ClassLoader JavaDoc) AccessController.doPrivileged(GetTCLAction.ACTION);
519       return loader;
520    }
521
522    private static class GetTCLAction implements PrivilegedAction JavaDoc
523    {
524       static PrivilegedAction JavaDoc ACTION = new GetTCLAction();
525
526       public Object JavaDoc run()
527       {
528          ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
529          return loader;
530       }
531    }
532
533 }
Popular Tags