SSLCertificateSocketFactory.java revision 0dc59b00f28f4d5543cf31627eeec4e913ee0785
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.net; 18 19import com.android.internal.net.DomainNameValidator; 20 21import android.os.SystemProperties; 22import android.util.Config; 23import android.util.Log; 24 25 26import java.io.IOException; 27import java.net.InetAddress; 28import java.net.Socket; 29import java.security.GeneralSecurityException; 30import java.security.KeyManagementException; 31import java.security.KeyStore; 32import java.security.KeyStoreException; 33import java.security.NoSuchAlgorithmException; 34import java.security.cert.Certificate; 35import java.security.cert.X509Certificate; 36 37import javax.net.SocketFactory; 38import javax.net.ssl.SSLSocket; 39import javax.net.ssl.SSLSocketFactory; 40import javax.net.ssl.TrustManager; 41import javax.net.ssl.TrustManagerFactory; 42import javax.net.ssl.X509TrustManager; 43 44import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl; 45import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache; 46import org.apache.harmony.xnet.provider.jsse.SSLContextImpl; 47import org.apache.harmony.xnet.provider.jsse.SSLParameters; 48 49/** 50 * SSLSocketFactory implementation with several extra features: 51 * <ul> 52 * <li>Timeout specification for SSL handshake operations 53 * <li>Optional SSL session caching with {@link SSLSessionCache} 54 * <li>Optionally bypass all SSL certificate checks 55 * </ul> 56 * Note that the handshake timeout does not apply to actual connection. 57 * If you want a connection timeout as well, use {@link #createSocket()} and 58 * {@link Socket#connect(SocketAddress, int)}. 59 * <p> 60 * On development devices, "setprop socket.relaxsslcheck yes" bypasses all 61 * SSL certificate checks, for testing with development servers. 62 */ 63public class SSLCertificateSocketFactory extends SSLSocketFactory { 64 private static final String TAG = "SSLCertificateSocketFactory"; 65 66 private static final TrustManager[] INSECURE_TRUST_MANAGER = new TrustManager[] { 67 new X509TrustManager() { 68 public X509Certificate[] getAcceptedIssuers() { return null; } 69 public void checkClientTrusted(X509Certificate[] certs, String authType) { } 70 public void checkServerTrusted(X509Certificate[] certs, String authType) { } 71 } 72 }; 73 74 private SSLSocketFactory mInsecureFactory = null; 75 private SSLSocketFactory mSecureFactory = null; 76 77 private final int mHandshakeTimeoutMillis; 78 private final SSLClientSessionCache mSessionCache; 79 private final boolean mSecure; 80 81 /** @deprecated Use {@link #getDefault(int)} instead. */ 82 public SSLCertificateSocketFactory(int handshakeTimeoutMillis) { 83 this(handshakeTimeoutMillis, null, true); 84 } 85 86 private SSLCertificateSocketFactory( 87 int handshakeTimeoutMillis, SSLSessionCache cache, boolean secure) { 88 mHandshakeTimeoutMillis = handshakeTimeoutMillis; 89 mSessionCache = cache == null ? null : cache.mSessionCache; 90 mSecure = secure; 91 } 92 93 /** 94 * Returns a new socket factory instance with an optional handshake timeout. 95 * 96 * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0 97 * for none. The socket timeout is reset to 0 after the handshake. 98 * @return a new SocketFactory with the specified parameters 99 */ 100 public static SocketFactory getDefault(int handshakeTimeoutMillis) { 101 return new SSLCertificateSocketFactory(handshakeTimeoutMillis, null, true); 102 } 103 104 /** 105 * Returns a new socket factory instance with an optional handshake timeout 106 * and SSL session cache. 107 * 108 * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0 109 * for none. The socket timeout is reset to 0 after the handshake. 110 * @param cache The {@link SSLClientSessionCache} to use, or null for no cache. 111 * @return a new SocketFactory with the specified parameters 112 */ 113 public static SSLSocketFactory getDefault(int handshakeTimeoutMillis, SSLSessionCache cache) { 114 return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true); 115 } 116 117 /** 118 * Returns a new instance of a socket factory with all SSL security checks 119 * disabled, using an optional handshake timeout and SSL session cache. 120 * Sockets created using this factory are vulnerable to man-in-the-middle 121 * attacks! 122 * 123 * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0 124 * for none. The socket timeout is reset to 0 after the handshake. 125 * @param cache The {@link SSLClientSessionCache} to use, or null for no cache. 126 * @return an insecure SocketFactory with the specified parameters 127 */ 128 public static SSLSocketFactory getInsecure(int handshakeTimeoutMillis, SSLSessionCache cache) { 129 return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, false); 130 } 131 132 /** 133 * Returns a socket factory (also named SSLSocketFactory, but in a different 134 * namespace) for use with the Apache HTTP stack. 135 * 136 * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0 137 * for none. The socket timeout is reset to 0 after the handshake. 138 * @param cache The {@link SSLClientSessionCache} to use, or null for no cache. 139 * @return a new SocketFactory with the specified parameters 140 */ 141 public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory( 142 int handshakeTimeoutMillis, 143 SSLSessionCache cache) { 144 return new org.apache.http.conn.ssl.SSLSocketFactory( 145 new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true)); 146 } 147 148 private SSLSocketFactory makeSocketFactory(TrustManager[] trustManagers) { 149 try { 150 SSLContextImpl sslContext = new SSLContextImpl(); 151 sslContext.engineInit(null, trustManagers, null, mSessionCache, null); 152 return sslContext.engineGetSocketFactory(); 153 } catch (KeyManagementException e) { 154 Log.wtf(TAG, e); 155 return (SSLSocketFactory) SSLSocketFactory.getDefault(); // Fallback 156 } 157 } 158 159 private synchronized SSLSocketFactory getDelegate() { 160 // Relax the SSL check if instructed (for this factory, or systemwide) 161 if (!mSecure || ("1".equals(SystemProperties.get("ro.debuggable")) && 162 "yes".equals(SystemProperties.get("socket.relaxsslcheck")))) { 163 if (mInsecureFactory == null) { 164 if (mSecure) { 165 Log.w(TAG, "*** BYPASSING SSL SECURITY CHECKS (socket.relaxsslcheck=yes) ***"); 166 } else { 167 Log.w(TAG, "Bypassing SSL security checks at caller's request"); 168 } 169 mInsecureFactory = makeSocketFactory(INSECURE_TRUST_MANAGER); 170 } 171 return mInsecureFactory; 172 } else { 173 if (mSecureFactory == null) { 174 mSecureFactory = makeSocketFactory(null); 175 } 176 return mSecureFactory; 177 } 178 } 179 180 @Override 181 public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException { 182 OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close); 183 s.setHandshakeTimeout(mHandshakeTimeoutMillis); 184 return s; 185 } 186 187 @Override 188 public Socket createSocket() throws IOException { 189 OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(); 190 s.setHandshakeTimeout(mHandshakeTimeoutMillis); 191 return s; 192 } 193 194 @Override 195 public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, int localPort) 196 throws IOException { 197 OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket( 198 addr, port, localAddr, localPort); 199 s.setHandshakeTimeout(mHandshakeTimeoutMillis); 200 return s; 201 } 202 203 @Override 204 public Socket createSocket(InetAddress addr, int port) throws IOException { 205 OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port); 206 s.setHandshakeTimeout(mHandshakeTimeoutMillis); 207 return s; 208 } 209 210 @Override 211 public Socket createSocket(String host, int port, InetAddress localAddr, int localPort) 212 throws IOException { 213 OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket( 214 host, port, localAddr, localPort); 215 s.setHandshakeTimeout(mHandshakeTimeoutMillis); 216 return s; 217 } 218 219 @Override 220 public Socket createSocket(String host, int port) throws IOException { 221 OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port); 222 s.setHandshakeTimeout(mHandshakeTimeoutMillis); 223 return s; 224 } 225 226 @Override 227 public String[] getDefaultCipherSuites() { 228 return getDelegate().getSupportedCipherSuites(); 229 } 230 231 @Override 232 public String[] getSupportedCipherSuites() { 233 return getDelegate().getSupportedCipherSuites(); 234 } 235} 236