diff options
author | Tom Marshall <tdm@cyngn.com> | 2015-03-12 21:07:21 -0700 |
---|---|---|
committer | Tom Marshall <tdm@cyngn.com> | 2015-03-12 21:07:21 -0700 |
commit | ebaa41f541f99745b5b4884cbe6c71123ec3c3ba (patch) | |
tree | 156e860c9f1062f25a2af9cf74d28a2daad910e7 /emailcommon/src | |
parent | 8c50ed4589a5cd8f0e9be40ee0cfe71adbd61b10 (diff) | |
parent | a2acc75c6bd263b97656ea8410568e7d38b4040c (diff) | |
download | android_packages_apps_Email-ebaa41f541f99745b5b4884cbe6c71123ec3c3ba.tar.gz android_packages_apps_Email-ebaa41f541f99745b5b4884cbe6c71123ec3c3ba.tar.bz2 android_packages_apps_Email-ebaa41f541f99745b5b4884cbe6c71123ec3c3ba.zip |
Merge tag 'android-5.1.0_r1' into merge-5.1staging/cm-12.1
Android 5.1.0 release 1
Conflicts:
provider_src/com/android/email/provider/AccountReconciler.java
provider_src/com/android/email/provider/EmailProvider.java
Change-Id: I5b67dce2cbafd7899202c461c607a4fc412d8e62
Diffstat (limited to 'emailcommon/src')
9 files changed, 374 insertions, 49 deletions
diff --git a/emailcommon/src/com/android/emailcommon/provider/Account.java b/emailcommon/src/com/android/emailcommon/provider/Account.java index 513390b69..5a3ab7f3a 100755 --- a/emailcommon/src/com/android/emailcommon/provider/Account.java +++ b/emailcommon/src/com/android/emailcommon/provider/Account.java @@ -225,11 +225,17 @@ public final class Account extends EmailContent implements Parcelable { new String[] {AccountColumns._ID}, AccountColumns.EMAIL_ADDRESS + "=?", new String[] {emailAddress}, null); - if (c == null || !c.moveToFirst()) { - return null; + try { + if (c == null || !c.moveToFirst()) { + return null; + } + final long id = c.getLong(c.getColumnIndex(AccountColumns._ID)); + return restoreAccountWithId(context, id, observer); + } finally { + if (c != null) { + c.close(); + } } - final long id = c.getLong(c.getColumnIndex(AccountColumns._ID)); - return restoreAccountWithId(context, id, observer); } @Override diff --git a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java index 4b2f7b73d..f1fcb0dcf 100755 --- a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java +++ b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java @@ -35,10 +35,10 @@ import android.os.Parcelable; import android.os.RemoteException; import android.provider.BaseColumns; -import com.android.emailcommon.utility.TextUtilities; -import com.android.emailcommon.utility.Utility; import com.android.emailcommon.Logging; import com.android.emailcommon.R; +import com.android.emailcommon.utility.TextUtilities; +import com.android.emailcommon.utility.Utility; import com.android.mail.providers.UIProvider; import com.android.mail.utils.LogUtils; import com.google.common.annotations.VisibleForTesting; @@ -96,9 +96,12 @@ public abstract class EmailContent { public static final int SYNC_STATUS_USER = UIProvider.SyncStatus.USER_REFRESH; public static final int SYNC_STATUS_BACKGROUND = UIProvider.SyncStatus.BACKGROUND_SYNC; public static final int SYNC_STATUS_LIVE = UIProvider.SyncStatus.LIVE_QUERY; + public static final int SYNC_STATUS_INITIAL_SYNC_NEEDED = + UIProvider.SyncStatus.INITIAL_SYNC_NEEDED; public static final int LAST_SYNC_RESULT_SUCCESS = UIProvider.LastSyncResult.SUCCESS; public static final int LAST_SYNC_RESULT_AUTH_ERROR = UIProvider.LastSyncResult.AUTH_ERROR; + public static final int LAST_SYNC_RESULT_SERVER_ERROR = UIProvider.LastSyncResult.SERVER_ERROR; public static final int LAST_SYNC_RESULT_SECURITY_ERROR = UIProvider.LastSyncResult.SECURITY_ERROR; public static final int LAST_SYNC_RESULT_CONNECTION_ERROR = @@ -491,9 +494,6 @@ public abstract class EmailContent { public static final int CONTENT_SOURCE_KEY_COLUMN = 4; public static final int CONTENT_QUOTED_TEXT_START_POS_COLUMN = 5; - private static final String[] PROJECTION_SOURCE_KEY = - new String[] {BaseColumns._ID, BodyColumns.SOURCE_MESSAGE_KEY}; - public long mMessageKey; public String mHtmlContent; public String mTextContent; @@ -575,7 +575,7 @@ public abstract class EmailContent { @VisibleForTesting public static long restoreBodySourceKey(Context context, long messageId) { return Utility.getFirstRowLong(context, Body.CONTENT_URI, - Body.PROJECTION_SOURCE_KEY, + new String[] {BodyColumns.SOURCE_MESSAGE_KEY}, BodyColumns.MESSAGE_KEY + "=?", new String[] {Long.toString(messageId)}, null, 0, 0L); } diff --git a/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java b/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java index 1c1f0ebc9..36a0d336e 100644 --- a/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java +++ b/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java @@ -65,13 +65,13 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService { private final boolean isRemote; // Standard debugging - public static final int DEBUG_BIT = 1; + public static final int DEBUG_BIT = 0x01; // Verbose (parser) logging - public static final int DEBUG_VERBOSE_BIT = 2; + public static final int DEBUG_EXCHANGE_BIT = 0x02; // File (SD card) logging - public static final int DEBUG_FILE_BIT = 4; + public static final int DEBUG_FILE_BIT = 0x04; // Enable strict mode - public static final int DEBUG_ENABLE_STRICT_MODE = 8; + public static final int DEBUG_ENABLE_STRICT_MODE = 0x08; // The first two constructors are used with local services that can be referenced by class public EmailServiceProxy(Context _context, Class<?> _class) { diff --git a/emailcommon/src/com/android/emailcommon/service/EmailServiceStatus.java b/emailcommon/src/com/android/emailcommon/service/EmailServiceStatus.java index 44922221b..88e5dd29a 100644 --- a/emailcommon/src/com/android/emailcommon/service/EmailServiceStatus.java +++ b/emailcommon/src/com/android/emailcommon/service/EmailServiceStatus.java @@ -33,6 +33,7 @@ import android.os.Bundle; public abstract class EmailServiceStatus { public static final int SUCCESS = 0; public static final int IN_PROGRESS = 1; + public static final int FAILURE = 2; public static final int MESSAGE_NOT_FOUND = 0x10; public static final int ATTACHMENT_NOT_FOUND = 0x11; diff --git a/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl b/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl index c284292e0..2c2c9903a 100755 --- a/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl +++ b/emailcommon/src/com/android/emailcommon/service/IPolicyService.aidl @@ -25,4 +25,5 @@ interface IPolicyService { // New version void setAccountPolicy2(long accountId, in Policy policy, String securityKey, boolean notify); oneway void remoteWipe(); + boolean canDisableCamera(); }
\ No newline at end of file diff --git a/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java b/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java index fcd916f25..c5dd6c180 100755 --- a/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java +++ b/emailcommon/src/com/android/emailcommon/service/PolicyServiceProxy.java @@ -85,6 +85,24 @@ public class PolicyServiceProxy extends ServiceProxy implements IPolicyService { waitForCompletion(); } + public boolean canDisableCamera() throws RemoteException { + setTask(new ProxyTask() { + @Override + public void run() throws RemoteException { + mReturn = mService.canDisableCamera(); + } + }, "canDisableCamera"); + waitForCompletion(); + if (mReturn == null) { + // This is not a great situation, but it's better to act like the policy isn't enforced + // rather than crash. + LogUtils.e(TAG, "PolicyService unavailable in canDisableCamera; assuming false"); + return false; + } else { + return (Boolean)mReturn; + } + } + @Override public void remoteWipe() throws RemoteException { setTask(new ProxyTask() { @@ -145,5 +163,13 @@ public class PolicyServiceProxy extends ServiceProxy implements IPolicyService { } throw new IllegalStateException("PolicyService transaction failed"); } + + public static boolean canDisableCamera(Context context) { + try { + return new PolicyServiceProxy(context).canDisableCamera(); + } catch (RemoteException e) { + } + return false; + } } diff --git a/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java b/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java index 1c4f3b6bb..3669345c1 100644 --- a/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java +++ b/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java @@ -114,19 +114,24 @@ public abstract class ServiceProxy { try { mTask.run(); } catch (RemoteException e) { - } - try { - // Each ServiceProxy handles just one task, so we unbind after we're - // done with our work. - mContext.unbindService(mConnection); - } catch (RuntimeException e) { - // The exceptions that are thrown here look like IllegalStateException, - // IllegalArgumentException and RuntimeException. Catching RuntimeException - // which get them all. Reasons for these exceptions include services that - // have already been stopped or unbound. This can happen if the user ended - // the activity that was using the service. This is harmless, but we've got - // to catch it. - LogUtils.e(mTag, e, "RuntimeException when trying to unbind from service"); + LogUtils.e(mTag, e, "RemoteException thrown running mTask!"); + } finally { + // Make sure that we unbind the mConnection even on exceptions in the + // task provided by the subclass. + try { + // Each ServiceProxy handles just one task, so we unbind after we're + // done with our work. + mContext.unbindService(mConnection); + } catch (RuntimeException e) { + // The exceptions that are thrown here look like IllegalStateException, + // IllegalArgumentException and RuntimeException. Catching + // RuntimeException which get them all. Reasons for these exceptions + // include services that have already been stopped or unbound. This can + // happen if the user ended the activity that was using the service. + // This is harmless, but we've got to catch it. + LogUtils.e(mTag, e, + "RuntimeException when trying to unbind from service"); + } } mTaskCompleted = true; synchronized(mConnection) { diff --git a/emailcommon/src/com/android/emailcommon/utility/SSLSocketFactoryWrapper.java b/emailcommon/src/com/android/emailcommon/utility/SSLSocketFactoryWrapper.java new file mode 100644 index 000000000..66b596bff --- /dev/null +++ b/emailcommon/src/com/android/emailcommon/utility/SSLSocketFactoryWrapper.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.emailcommon.utility; + +import com.android.mail.utils.LogUtils; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.net.ssl.*; +import javax.net.ssl.SSLSocketFactory; + +public class SSLSocketFactoryWrapper extends javax.net.ssl.SSLSocketFactory { + private final SSLSocketFactory mFactory; + private final boolean mSecure; + private final int mHandshakeTimeout; + private final String[] mDefaultCipherSuites; + + private final String[] DEPRECATED_CIPHER_SUITES_TO_ENABLE = new String[] { + "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_RC4_128_MD5", + "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", + "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDH_RSA_WITH_RC4_128_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_RSA_WITH_DES_CBC_SHA" + }; + + SSLSocketFactoryWrapper(final SSLSocketFactory factory, final boolean secure, + int handshakeTimeout) { + mFactory = factory; + mSecure = secure; + mHandshakeTimeout = handshakeTimeout; + + // Find the base factory's list of defaultCipherSuites, and merge our extras with it. + // Remember that the order is important. We'll add our extras at the end, and only + // if they weren't already in the base factory's list. + final String[] baseDefaultCipherSuites = mFactory.getDefaultCipherSuites(); + final List<String> fullCipherSuiteList = new ArrayList<String>(Arrays.asList( + mFactory.getDefaultCipherSuites())); + final Set<String> baseDefaultCipherSuiteSet = new HashSet<String>(fullCipherSuiteList); + + final String[] baseSupportedCipherSuites = mFactory.getSupportedCipherSuites(); + final Set<String> baseSupportedCipherSuiteSet = new HashSet<String>(Arrays.asList( + mFactory.getSupportedCipherSuites())); + + for (String cipherSuite : DEPRECATED_CIPHER_SUITES_TO_ENABLE) { + if (baseSupportedCipherSuiteSet.contains(cipherSuite) && + !baseDefaultCipherSuiteSet.contains(cipherSuite)) { + fullCipherSuiteList.add(cipherSuite); + } + } + mDefaultCipherSuites = new String[fullCipherSuiteList.size()]; + fullCipherSuiteList.toArray(mDefaultCipherSuites); + } + + public static SSLSocketFactory getDefault(final KeyManager[] keyManagers, int handshakeTimeout) + throws NoSuchAlgorithmException, KeyManagementException{ + final SSLContext context = SSLContext.getInstance("TLS"); + context.init(keyManagers, null, null); + return new SSLSocketFactoryWrapper(context.getSocketFactory(), true, handshakeTimeout); + } + + public static SSLSocketFactory getInsecure(final KeyManager[] keyManagers, + final TrustManager[] trustManagers, + int handshakeTimeout) + throws NoSuchAlgorithmException, KeyManagementException { + final SSLContext context = SSLContext.getInstance("TLS"); + context.init(keyManagers, trustManagers, null); + return new SSLSocketFactoryWrapper(context.getSocketFactory(), false, handshakeTimeout); + } + + public Socket createSocket()throws IOException { + return mFactory.createSocket(); + } + + public Socket createSocket(final Socket socket, final String host, final int port, + final boolean autoClose) throws IOException { + final SSLSocket sslSocket = (SSLSocket)mFactory.createSocket(socket, host, port, autoClose); + setHandshakeTimeout(sslSocket, mHandshakeTimeout); + sslSocket.setEnabledCipherSuites(mDefaultCipherSuites); + if (mSecure) { + verifyHostname(sslSocket, host); + } + return sslSocket; + } + + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException { + final SSLSocket sslSocket = (SSLSocket)mFactory.createSocket(host, port); + setHandshakeTimeout(sslSocket, mHandshakeTimeout); + sslSocket.setEnabledCipherSuites(mDefaultCipherSuites); + if (mSecure) { + verifyHostname(sslSocket, host); + } + return sslSocket; + } + + @Override + public Socket createSocket(String host, int i, InetAddress inetAddress, int i2) throws + IOException, UnknownHostException { + final SSLSocket sslSocket = (SSLSocket)mFactory.createSocket(host, i, inetAddress, i2); + setHandshakeTimeout(sslSocket, mHandshakeTimeout); + sslSocket.setEnabledCipherSuites(mDefaultCipherSuites); + if (mSecure) { + verifyHostname(sslSocket, host); + } + return sslSocket; + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i) throws IOException { + final SSLSocket sslSocket = (SSLSocket)mFactory.createSocket(inetAddress, i); + setHandshakeTimeout(sslSocket, mHandshakeTimeout); + sslSocket.setEnabledCipherSuites(mDefaultCipherSuites); + return sslSocket; + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress2, int i2) + throws IOException { + final SSLSocket sslSocket = (SSLSocket)mFactory.createSocket(inetAddress, i, inetAddress2, + i2); + setHandshakeTimeout(sslSocket, mHandshakeTimeout); + sslSocket.setEnabledCipherSuites(mDefaultCipherSuites); + return sslSocket; + } + + public String[] getDefaultCipherSuites() { + return mDefaultCipherSuites.clone(); + } + + public String[] getSupportedCipherSuites() { + return mFactory.getSupportedCipherSuites(); + } + + /** + * Attempt to set the hostname of the socket. + * @param sslSocket The SSLSocket + * @param hostname the hostname + * @return true if able to set the hostname, false if not. + */ + public static boolean potentiallyEnableSni(SSLSocket sslSocket, String hostname) { + try { + // Many implementations of SSLSocket support setHostname, although it is not part of + // the class definition. We will attempt to setHostname using reflection. If the + // particular SSLSocket implementation we are using does not support this meethod, + // we'll fail and return false. + sslSocket.getClass().getMethod("setHostname", String.class).invoke(sslSocket, hostname); + return true; + } catch (Exception ignored) { + return false; + } + } + + /** + * Attempt to enable session tickets. + * @param sslSocket the SSLSocket. + * @return true if able to enable session tickets, false otherwise. + */ + public static boolean potentiallyEnableSessionTickets(SSLSocket sslSocket) { + try { + // Many implementations of SSLSocket support setUseSessionTickets, although it is not + // part of the class definition. We will attempt to setHostname using reflection. If the + // particular SSLSocket implementation we are using does not support this meethod, + // we'll fail and return false. + sslSocket.getClass().getMethod("setUseSessionTickets", boolean.class) + .invoke(sslSocket, true); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * Verify the hostname of the certificate used by the other end of a + * connected socket. You MUST call this if you did not supply a hostname + * to {@link #createSocket()}. It is harmless to call this method + * redundantly if the hostname has already been verified. + * + * @param socket An SSL socket which has been connected to a server + * @param hostname The expected hostname of the remote server + * @throws IOException if something goes wrong handshaking with the server + * @throws SSLPeerUnverifiedException if the server cannot prove its identity + * + * @hide + */ + public static void verifyHostname(Socket socket, String hostname) throws IOException { + if (!(socket instanceof SSLSocket)) { + throw new IllegalArgumentException("Attempt to verify non-SSL socket"); + } + + // The code at the start of OpenSSLSocketImpl.startHandshake() + // ensures that the call is idempotent, so we can safely call it. + SSLSocket ssl = (SSLSocket) socket; + ssl.startHandshake(); + + SSLSession session = ssl.getSession(); + if (session == null) { + throw new SSLException("Cannot verify SSL socket without session"); + } + LogUtils.d(LogUtils.TAG, "using cipherSuite %s", session.getCipherSuite()); + if (!HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session)) { + throw new SSLPeerUnverifiedException("Cannot verify hostname: " + hostname); + } + } + + private void setHandshakeTimeout(SSLSocket sslSocket, int timeout) { + try { + // Most implementations of SSLSocket support setHandshakeTimeout(), but it is not + // actually part of the class definition. We will attempt to set it using reflection. + // If the particular implementation of SSLSocket we are using does not support this + // function, then we will just have to use the default handshake timeout. + sslSocket.getClass().getMethod("setHandshakeTimeout", int.class).invoke(sslSocket, + timeout); + } catch (Exception e) { + LogUtils.w(LogUtils.TAG, e, "unable to set handshake timeout"); + } + } +} diff --git a/emailcommon/src/com/android/emailcommon/utility/SSLUtils.java b/emailcommon/src/com/android/emailcommon/utility/SSLUtils.java index 33ddde7dc..49963bc3c 100644 --- a/emailcommon/src/com/android/emailcommon/utility/SSLUtils.java +++ b/emailcommon/src/com/android/emailcommon/utility/SSLUtils.java @@ -20,7 +20,6 @@ import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; -import android.net.SSLCertificateSocketFactory; import android.security.KeyChain; import android.security.KeyChainException; @@ -33,6 +32,8 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.security.PrivateKey; import java.security.PublicKey; @@ -49,7 +50,7 @@ import javax.net.ssl.X509TrustManager; public class SSLUtils { // All secure factories are the same; all insecure factories are associated with HostAuth's - private static SSLCertificateSocketFactory sSecureFactory; + private static javax.net.ssl.SSLSocketFactory sSecureFactory; private static final boolean LOG_ENABLED = false; private static final String TAG = "Email.Ssl"; @@ -137,40 +138,67 @@ public class SSLUtils { } } + public static abstract class ExternalSecurityProviderInstaller { + abstract public void installIfNeeded(final Context context); + } + + private static ExternalSecurityProviderInstaller sExternalSecurityProviderInstaller; + + public static void setExternalSecurityProviderInstaller ( + ExternalSecurityProviderInstaller installer) { + sExternalSecurityProviderInstaller = installer; + } + /** * Returns a {@link javax.net.ssl.SSLSocketFactory}. * Optionally bypass all SSL certificate checks. * * @param insecure if true, bypass all SSL certificate checks */ - public synchronized static SSLCertificateSocketFactory getSSLSocketFactory(Context context, - HostAuth hostAuth, boolean insecure) { - if (insecure) { - SSLCertificateSocketFactory insecureFactory = (SSLCertificateSocketFactory) - SSLCertificateSocketFactory.getInsecure(SSL_HANDSHAKE_TIMEOUT, null); - insecureFactory.setTrustManagers( - new TrustManager[] { - new SameCertificateCheckingTrustManager(context, hostAuth)}); - return insecureFactory; - } else { - if (sSecureFactory == null) { - sSecureFactory = (SSLCertificateSocketFactory) - SSLCertificateSocketFactory.getDefault(SSL_HANDSHAKE_TIMEOUT, null); + public synchronized static javax.net.ssl.SSLSocketFactory getSSLSocketFactory( + final Context context, final HostAuth hostAuth, final KeyManager keyManager, + final boolean insecure) { + // If we have an external security provider installer, then install. This will + // potentially replace the default implementation of SSLSocketFactory. + if (sExternalSecurityProviderInstaller != null) { + sExternalSecurityProviderInstaller.installIfNeeded(context); + } + try { + final KeyManager[] keyManagers = (keyManager == null ? null : + new KeyManager[]{keyManager}); + if (insecure) { + final TrustManager[] trustManagers = new TrustManager[]{ + new SameCertificateCheckingTrustManager(context, hostAuth)}; + SSLSocketFactoryWrapper insecureFactory = + (SSLSocketFactoryWrapper) SSLSocketFactoryWrapper.getInsecure( + keyManagers, trustManagers, SSL_HANDSHAKE_TIMEOUT); + return insecureFactory; + } else { + if (sSecureFactory == null) { + SSLSocketFactoryWrapper secureFactory = + (SSLSocketFactoryWrapper) SSLSocketFactoryWrapper.getDefault( + keyManagers, SSL_HANDSHAKE_TIMEOUT); + sSecureFactory = secureFactory; + } + return sSecureFactory; } - return sSecureFactory; + } catch (NoSuchAlgorithmException e) { + LogUtils.wtf(TAG, e, "Unable to acquire SSLSocketFactory"); + // TODO: what can we do about this? + } catch (KeyManagementException e) { + LogUtils.wtf(TAG, e, "Unable to acquire SSLSocketFactory"); + // TODO: what can we do about this? } + return null; } /** - * Returns a {@link org.apache.http.conn.ssl.SSLSocketFactory SSLSocketFactory} for use with the - * Apache HTTP stack. + * Returns a com.android.emailcommon.utility.SSLSocketFactory */ public static SSLSocketFactory getHttpSocketFactory(Context context, HostAuth hostAuth, KeyManager keyManager, boolean insecure) { - SSLCertificateSocketFactory underlying = getSSLSocketFactory(context, hostAuth, insecure); - if (keyManager != null) { - underlying.setKeyManagers(new KeyManager[] { keyManager }); - } + javax.net.ssl.SSLSocketFactory underlying = getSSLSocketFactory(context, hostAuth, + keyManager, insecure); SSLSocketFactory wrapped = new SSLSocketFactory(underlying); if (insecure) { wrapped.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); |