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