14ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon/*
24ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon * Copyright (C) 2014 The Android Open Source Project
34ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon *
44ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon * Licensed under the Apache License, Version 2.0 (the "License");
54ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon * you may not use this file except in compliance with the License.
64ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon * You may obtain a copy of the License at
74ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon *
84ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon *      http://www.apache.org/licenses/LICENSE-2.0
94ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon *
104ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon * Unless required by applicable law or agreed to in writing, software
114ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon * distributed under the License is distributed on an "AS IS" BASIS,
124ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon * See the License for the specific language governing permissions and
144ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon * limitations under the License.
154ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon */
164ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
174ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonpackage com.android.emailcommon.utility;
184ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
194ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport com.android.mail.utils.LogUtils;
204ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
214ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.io.IOException;
224ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.lang.reflect.Method;
234ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.net.InetAddress;
244ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.net.Socket;
254ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.net.UnknownHostException;
264ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.security.KeyManagementException;
274ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.security.NoSuchAlgorithmException;
284ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.util.ArrayList;
294ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.util.Arrays;
304ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.util.HashSet;
314ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.util.List;
324ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport java.util.Set;
334ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
344ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport javax.net.ssl.*;
354ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonimport javax.net.ssl.SSLSocketFactory;
364ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
374ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdonpublic class SSLSocketFactoryWrapper extends javax.net.ssl.SSLSocketFactory {
384ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    private final SSLSocketFactory mFactory;
394ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    private final boolean mSecure;
404ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    private final int mHandshakeTimeout;
414ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    private final String[] mDefaultCipherSuites;
424ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
434ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    private final String[] DEPRECATED_CIPHER_SUITES_TO_ENABLE = new String[] {
444ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
454ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
464ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
474ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
484ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
494ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "SSL_RSA_WITH_RC4_128_MD5",
504ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
514ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
524ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
534ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
544ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
554ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
564ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
574ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "TLS_ECDH_RSA_WITH_RC4_128_SHA",
584ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
594ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
604ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
614ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
624ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "SSL_DHE_DSS_WITH_DES_CBC_SHA",
634ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "SSL_DHE_RSA_WITH_DES_CBC_SHA",
644ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            "SSL_RSA_WITH_DES_CBC_SHA"
654ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    };
664ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
674ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    SSLSocketFactoryWrapper(final SSLSocketFactory factory, final boolean secure,
684ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon                            int handshakeTimeout) {
694ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        mFactory = factory;
704ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        mSecure = secure;
714ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        mHandshakeTimeout = handshakeTimeout;
724ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
734ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        // Find the base factory's list of defaultCipherSuites, and merge our extras with it.
744ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        // Remember that the order is important. We'll add our extras at the end, and only
754ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        // if they weren't already in the base factory's list.
764ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final String[] baseDefaultCipherSuites = mFactory.getDefaultCipherSuites();
774ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final List<String> fullCipherSuiteList = new ArrayList<String>(Arrays.asList(
784ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon                mFactory.getDefaultCipherSuites()));
794ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final Set<String> baseDefaultCipherSuiteSet = new HashSet<String>(fullCipherSuiteList);
804ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
814ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final String[] baseSupportedCipherSuites = mFactory.getSupportedCipherSuites();
824ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final Set<String> baseSupportedCipherSuiteSet = new HashSet<String>(Arrays.asList(
834ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon                mFactory.getSupportedCipherSuites()));
844ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
854ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        for (String cipherSuite : DEPRECATED_CIPHER_SUITES_TO_ENABLE) {
864ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            if (baseSupportedCipherSuiteSet.contains(cipherSuite) &&
874ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon                    !baseDefaultCipherSuiteSet.contains(cipherSuite)) {
884ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon                fullCipherSuiteList.add(cipherSuite);
894ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            }
904ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        }
914ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        mDefaultCipherSuites = new String[fullCipherSuiteList.size()];
924ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        fullCipherSuiteList.toArray(mDefaultCipherSuites);
934ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
944ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
954ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public static SSLSocketFactory getDefault(final KeyManager[] keyManagers, int handshakeTimeout)
964ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            throws NoSuchAlgorithmException, KeyManagementException{
974ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final SSLContext context = SSLContext.getInstance("TLS");
984ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        context.init(keyManagers, null, null);
994ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        return new SSLSocketFactoryWrapper(context.getSocketFactory(), true, handshakeTimeout);
1004ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
1014ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
1024ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public static SSLSocketFactory getInsecure(final KeyManager[] keyManagers,
1034ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon                                               final TrustManager[] trustManagers,
1044ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon                                               int handshakeTimeout)
1054ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            throws NoSuchAlgorithmException, KeyManagementException {
1064ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final SSLContext context = SSLContext.getInstance("TLS");
1074ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        context.init(keyManagers, trustManagers, null);
1084ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        return new SSLSocketFactoryWrapper(context.getSocketFactory(), false, handshakeTimeout);
1094ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
1104ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
1114ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public Socket createSocket()throws IOException {
1124ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        return mFactory.createSocket();
1134ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
1144ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
1154ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public Socket createSocket(final Socket socket, final String host, final int port,
1164ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon                        final boolean autoClose) throws IOException {
1174ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final SSLSocket sslSocket = (SSLSocket)mFactory.createSocket(socket, host, port, autoClose);
1184ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        setHandshakeTimeout(sslSocket, mHandshakeTimeout);
1194ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        sslSocket.setEnabledCipherSuites(mDefaultCipherSuites);
1204ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        if (mSecure) {
1214ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            verifyHostname(sslSocket, host);
1224ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        }
1234ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        return sslSocket;
1244ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
1254ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
1264ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    @Override
1274ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
1284ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final SSLSocket sslSocket = (SSLSocket)mFactory.createSocket(host, port);
1294ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        setHandshakeTimeout(sslSocket, mHandshakeTimeout);
1304ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        sslSocket.setEnabledCipherSuites(mDefaultCipherSuites);
1314ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        if (mSecure) {
1324ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            verifyHostname(sslSocket, host);
1334ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        }
1344ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        return sslSocket;
1354ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
1364ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
1374ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    @Override
1384ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public Socket createSocket(String host, int i, InetAddress inetAddress, int i2) throws
1394ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            IOException, UnknownHostException {
1404ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final SSLSocket sslSocket = (SSLSocket)mFactory.createSocket(host, i, inetAddress, i2);
1414ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        setHandshakeTimeout(sslSocket, mHandshakeTimeout);
1424ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        sslSocket.setEnabledCipherSuites(mDefaultCipherSuites);
1434ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        if (mSecure) {
1444ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            verifyHostname(sslSocket, host);
1454ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        }
1464ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        return sslSocket;
1474ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
1484ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
1494ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    @Override
1504ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
1514ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final SSLSocket sslSocket = (SSLSocket)mFactory.createSocket(inetAddress, i);
1524ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        setHandshakeTimeout(sslSocket, mHandshakeTimeout);
1534ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        sslSocket.setEnabledCipherSuites(mDefaultCipherSuites);
1544ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        return sslSocket;
1554ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
1564ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
1574ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    @Override
1584ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress2, int i2)
1594ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            throws IOException {
1604ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        final SSLSocket sslSocket = (SSLSocket)mFactory.createSocket(inetAddress, i, inetAddress2,
1614ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon                i2);
1624ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        setHandshakeTimeout(sslSocket, mHandshakeTimeout);
1634ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        sslSocket.setEnabledCipherSuites(mDefaultCipherSuites);
1644ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        return sslSocket;
1654ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
1664ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
1674ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public String[] getDefaultCipherSuites() {
1684ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        return mDefaultCipherSuites.clone();
1694ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
1704ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
1714ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public String[] getSupportedCipherSuites() {
1724ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        return mFactory.getSupportedCipherSuites();
1734ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
1744ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
1754ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    /**
1764ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * Attempt to set the hostname of the socket.
1774ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * @param sslSocket The SSLSocket
1784ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * @param hostname the hostname
1794ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * @return true if able to set the hostname, false if not.
1804ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     */
1814ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public static boolean potentiallyEnableSni(SSLSocket sslSocket, String hostname) {
1824ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        try {
1834ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // Many implementations of SSLSocket support setHostname, although it is not part of
1844ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // the class definition. We will attempt to setHostname using reflection. If the
1854ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // particular SSLSocket implementation we are using does not support this meethod,
1864ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // we'll fail and return false.
1874ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            sslSocket.getClass().getMethod("setHostname", String.class).invoke(sslSocket, hostname);
1884ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            return true;
1894ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        } catch (Exception ignored) {
1904ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            return false;
1914ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        }
1924ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
1934ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
1944ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    /**
1954ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * Attempt to enable session tickets.
1964ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * @param sslSocket the SSLSocket.
1974ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * @return true if able to enable session tickets, false otherwise.
1984ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     */
1994ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public static boolean potentiallyEnableSessionTickets(SSLSocket sslSocket) {
2004ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        try {
2014ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // Many implementations of SSLSocket support setUseSessionTickets, although it is not
2024ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // part of the class definition. We will attempt to setHostname using reflection. If the
2034ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // particular SSLSocket implementation we are using does not support this meethod,
2044ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // we'll fail and return false.
2054ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            sslSocket.getClass().getMethod("setUseSessionTickets", boolean.class)
2064ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon                    .invoke(sslSocket, true);
2074ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            return true;
2084ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        } catch (Exception e) {
2094ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            return false;
2104ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        }
2114ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
2124ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
2134ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    /**
2144ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * Verify the hostname of the certificate used by the other end of a
2154ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * connected socket.  You MUST call this if you did not supply a hostname
2164ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * to {@link #createSocket()}.  It is harmless to call this method
2174ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * redundantly if the hostname has already been verified.
2184ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     *
2194ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * @param socket An SSL socket which has been connected to a server
2204ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * @param hostname The expected hostname of the remote server
2214ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * @throws IOException if something goes wrong handshaking with the server
2224ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * @throws SSLPeerUnverifiedException if the server cannot prove its identity
2234ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     *
2244ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     * @hide
2254ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon     */
2264ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    public static void verifyHostname(Socket socket, String hostname) throws IOException {
2274ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        if (!(socket instanceof SSLSocket)) {
2284ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            throw new IllegalArgumentException("Attempt to verify non-SSL socket");
2294ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        }
2304ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
2314ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        // The code at the start of OpenSSLSocketImpl.startHandshake()
2324ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        // ensures that the call is idempotent, so we can safely call it.
2334ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        SSLSocket ssl = (SSLSocket) socket;
2344ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        ssl.startHandshake();
2354ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
2364ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        SSLSession session = ssl.getSession();
2374ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        if (session == null) {
2384ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            throw new SSLException("Cannot verify SSL socket without session");
2394ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        }
24093a9662d8db14e492da0cf4866265a0ddebda190Martin Hibdon        LogUtils.d(LogUtils.TAG, "using cipherSuite %s", session.getCipherSuite());
2414ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        if (!HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session)) {
2424ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            throw new SSLPeerUnverifiedException("Cannot verify hostname: " + hostname);
2434ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        }
2444ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
2454ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon
2464ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    private void setHandshakeTimeout(SSLSocket sslSocket, int timeout) {
2474ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        try {
2484ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // Most implementations of SSLSocket support setHandshakeTimeout(), but it is not
2494ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // actually part of the class definition. We will attempt to set it using reflection.
2504ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // If the particular implementation of SSLSocket we are using does not support this
2514ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            // function, then we will just have to use the default handshake timeout.
2524ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            sslSocket.getClass().getMethod("setHandshakeTimeout", int.class).invoke(sslSocket,
2534ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon                    timeout);
2544ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        } catch (Exception e) {
2554ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon            LogUtils.w(LogUtils.TAG, e, "unable to set handshake timeout");
2564ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon        }
2574ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon    }
2584ecd51a794c5a2af1a5a838f22997b4e361acb8bMartin Hibdon}
259