Java tutorial
/* * This software code is (c) 2010 T-Mobile USA, Inc. All Rights Reserved. * * Unauthorized redistribution or further use of this material is * prohibited without the express permission of T-Mobile USA, Inc. and * will be prosecuted to the fullest extent of the law. * * Removal or modification of these Terms and Conditions from the source * or binary code of this software is prohibited. In the event that * redistribution of the source or binary code for this software is * approved by T-Mobile USA, Inc., these Terms and Conditions and the * above copyright notice must be reproduced in their entirety and in all * circumstances. * * No name or trademarks of T-Mobile USA, Inc., or of its parent company, * Deutsche Telekom AG or any Deutsche Telekom or T-Mobile entity, may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED ON AN "AS IS" AND "WITH ALL FAULTS" BASIS * AND WITHOUT WARRANTIES OF ANY KIND. ALL EXPRESS OR IMPLIED * CONDITIONS, REPRESENTATIONS OR WARRANTIES, INCLUDING ANY IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR * NON-INFRINGEMENT CONCERNING THIS SOFTWARE, ITS SOURCE OR BINARY CODE * OR ANY DERIVATIVES THEREOF ARE HEREBY EXCLUDED. T-MOBILE USA, INC. * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE * OR ITS DERIVATIVES. IN NO EVENT WILL T-MOBILE USA, INC. OR ITS * LICENSORS BE LIABLE FOR LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, * HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT * OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF T-MOBILE USA, * INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * THESE TERMS AND CONDITIONS APPLY SOLELY AND EXCLUSIVELY TO THE USE, * MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE, ITS SOURCE OR BINARY * CODE OR ANY DERIVATIVES THEREOF, AND ARE SEPARATE FROM ANY WRITTEN * WARRANTY THAT MAY BE PROVIDED WITH A DEVICE YOU PURCHASE FROM T-MOBILE * USA, INC., AND TO THE EXTENT PERMITTED BY LAW. */ package javax.microedition.ims.core.xdm; import org.apache.http.conn.scheme.HostNameResolver; import org.apache.http.conn.scheme.LayeredSocketFactory; import org.apache.http.conn.ssl.AllowAllHostnameVerifier; import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier; import org.apache.http.conn.ssl.StrictHostnameVerifier; import org.apache.http.conn.ssl.X509HostnameVerifier; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; /** * Layered socket factory for TLS/SSL connections, based on JSSE. *. * <p> * SSLSocketFactory can be used to validate the identity of the HTTPS * server against a list of trusted certificates and to authenticate to * the HTTPS server using a private key. * </p> * * <p> * SSLSocketFactory will enable server authentication when supplied with * a {@link KeyStore truststore} file containg one or several trusted * certificates. The client secure socket will reject the connection during * the SSL session handshake if the target HTTPS server attempts to * authenticate itself with a non-trusted certificate. * </p> * * <p> * Use JDK keytool utility to import a trusted certificate and generate a truststore file: * <pre> * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore * </pre> * </p> * * <p> * SSLSocketFactory will enable client authentication when supplied with * a {@link KeyStore keystore} file containg a private key/public certificate * pair. The client secure socket will use the private key to authenticate * itself to the target HTTPS server during the SSL session handshake if * requested to do so by the server. * The target HTTPS server will in its turn verify the certificate presented * by the client in order to establish client's authenticity * </p> * * <p> * Use the following sequence of actions to generate a keystore file * </p> * <ul> * <li> * <p> * Use JDK keytool utility to generate a new key * <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre> * For simplicity use the same password for the key as that of the keystore * </p> * </li> * <li> * <p> * Issue a certificate signing request (CSR) * <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre> * </p> * </li> * <li> * <p> * Send the certificate request to the trusted Certificate Authority for signature. * One may choose to act as her own CA and sign the certificate request using a PKI * tool, such as OpenSSL. * </p> * </li> * <li> * <p> * Import the trusted CA root certificate * <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre> * </p> * </li> * <li> * <p> * Import the PKCS#7 file containg the complete certificate chain * <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre> * </p> * </li> * <li> * <p> * Verify the content the resultant keystore file * <pre>keytool -list -v -keystore my.keystore</pre> * </p> * </li> * </ul> * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> * @author Julius Davies */ public class CustomSSLSocketFactory implements LayeredSocketFactory { public static final String TLS = "TLS"; public static final String SSL = "SSL"; public static final String SSLV2 = "SSLv2"; public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER = new AllowAllHostnameVerifier(); public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER = new BrowserCompatHostnameVerifier(); public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER = new StrictHostnameVerifier(); /** * The factory using the default JVM settings for secure connections. */ private static final CustomSSLSocketFactory DEFAULT_FACTORY = new CustomSSLSocketFactory(); /** * Gets an singleton instance of the SSLProtocolSocketFactory. * @return a SSLProtocolSocketFactory */ public static CustomSSLSocketFactory getSocketFactory() { return DEFAULT_FACTORY; } private final SSLContext sslcontext; private final javax.net.ssl.SSLSocketFactory socketfactory; private final HostNameResolver nameResolver; private X509HostnameVerifier hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER; public CustomSSLSocketFactory(String algorithm, final KeyStore keystore, final String keystorePassword, final KeyStore truststore, final SecureRandom random, final HostNameResolver nameResolver) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(); if (algorithm == null) { algorithm = TLS; } KeyManager[] keymanagers = null; if (keystore != null) { keymanagers = createKeyManagers(keystore, keystorePassword); } TrustManager[] trustmanagers = null; if (truststore != null) { trustmanagers = createTrustManagers(truststore); } this.sslcontext = SSLContext.getInstance(algorithm); this.sslcontext.init(keymanagers, trustmanagers, random); this.socketfactory = this.sslcontext.getSocketFactory(); this.nameResolver = nameResolver; } public CustomSSLSocketFactory(final KeyStore keystore, final String keystorePassword, final KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { this(TLS, keystore, keystorePassword, truststore, null, null); } public CustomSSLSocketFactory(final KeyStore keystore, final String keystorePassword) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { this(TLS, keystore, keystorePassword, null, null, null); } public CustomSSLSocketFactory(final KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { this(TLS, null, null, truststore, null, null); } /** * Constructs an HttpClient SSLSocketFactory backed by the given JSSE * SSLSocketFactory. * * @hide */ public CustomSSLSocketFactory(javax.net.ssl.SSLSocketFactory socketfactory) { super(); this.sslcontext = null; this.socketfactory = socketfactory; this.nameResolver = null; } /** * Creates the default SSL socket factory. * This constructor is used exclusively to instantiate the factory for * {@link #getSocketFactory getSocketFactory}. */ private CustomSSLSocketFactory() { super(); this.sslcontext = null; this.socketfactory = HttpsURLConnection.getDefaultSSLSocketFactory(); this.nameResolver = null; } private static KeyManager[] createKeyManagers(final KeyStore keystore, final String password) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { if (keystore == null) { throw new IllegalArgumentException("Keystore may not be null"); } KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmfactory.init(keystore, password != null ? password.toCharArray() : null); return kmfactory.getKeyManagers(); } private static TrustManager[] createTrustManagers(final KeyStore keystore) throws KeyStoreException, NoSuchAlgorithmException { if (keystore == null) { throw new IllegalArgumentException("Keystore may not be null"); } TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmfactory.init(keystore); return tmfactory.getTrustManagers(); } // non-javadoc, see interface org.apache.http.conn.SocketFactory public Socket createSocket() throws IOException { // the cast makes sure that the factory is working as expected return (SSLSocket) this.socketfactory.createSocket(); } // non-javadoc, see interface org.apache.http.conn.SocketFactory public Socket connectSocket(final Socket sock, final String host, final int port, final InetAddress localAddress, int localPort, final HttpParams params) throws IOException { if (host == null) { throw new IllegalArgumentException("Target host may not be null."); } if (params == null) { throw new IllegalArgumentException("Parameters may not be null."); } SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket()); if ((localAddress != null) || (localPort > 0)) { // we need to bind explicitly if (localPort < 0) localPort = 0; // indicates "any" InetSocketAddress isa = new InetSocketAddress(localAddress, localPort); sslsock.bind(isa); } int connTimeout = HttpConnectionParams.getConnectionTimeout(params); int soTimeout = HttpConnectionParams.getSoTimeout(params); InetSocketAddress remoteAddress; if (this.nameResolver != null) { remoteAddress = new InetSocketAddress(this.nameResolver.resolve(host), port); } else { remoteAddress = new InetSocketAddress(host, port); } sslsock.connect(remoteAddress, connTimeout); sslsock.setSoTimeout(soTimeout); try { hostnameVerifier.verify(host, sslsock); // verifyHostName() didn't blowup - good! } catch (IOException iox) { // close the socket before re-throwing the exception try { sslsock.close(); } catch (Exception x) { /*ignore*/ } throw iox; } return sslsock; } /** * Checks whether a socket connection is secure. * This factory creates TLS/SSL socket connections * which, by default, are considered secure. * <br/> * Derived classes may override this method to perform * runtime checks, for example based on the cypher suite. * * @param sock the connected socket * * @return <code>true</code> * * @throws IllegalArgumentException if the argument is invalid */ public boolean isSecure(Socket sock) throws IllegalArgumentException { if (sock == null) { throw new IllegalArgumentException("Socket may not be null."); } // This instanceof check is in line with createSocket() above. if (!(sock instanceof SSLSocket)) { throw new IllegalArgumentException("Socket not created by this factory."); } // This check is performed last since it calls the argument object. if (sock.isClosed()) { throw new IllegalArgumentException("Socket is closed."); } return true; } // isSecure // non-javadoc, see interface LayeredSocketFactory public Socket createSocket(final Socket socket, final String host, final int port, final boolean autoClose) throws IOException, UnknownHostException { /* SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket( socket, host, port, autoClose ); */ SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(); sslSocket.connect(new InetSocketAddress(host, port)); ((SSLSocket) sslSocket).startHandshake(); hostnameVerifier.verify(host, sslSocket); // verifyHostName() didn't blowup - good! return sslSocket; } public void setHostnameVerifier(X509HostnameVerifier hostnameVerifier) { if (hostnameVerifier == null) { throw new IllegalArgumentException("Hostname verifier may not be null"); } this.hostnameVerifier = hostnameVerifier; } public X509HostnameVerifier getHostnameVerifier() { return hostnameVerifier; } }