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