Merge "Use SSLCertificateSocketFactory to generate "insecure" ssl socket."

This commit is contained in:
Makoto Onuki 2010-02-16 18:19:47 -08:00 committed by Android (Google) Code Review
commit ea1eb7a231
4 changed files with 59 additions and 182 deletions

View File

@ -1,135 +0,0 @@
/*
* Copyright (C) 2008 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.email.mail.store;
import com.android.common.DomainNameValidator;
import com.android.email.Email;
import org.apache.harmony.xnet.provider.jsse.SSLParameters;
import android.util.Log;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/**
* This factory creates and returns two types of TrustManagers.
*
* The "secure" trust manager performs standard tests of certificates, and throws
* CertificateException when the tests fail.
*
* The "simple" trust manager performs no tests, effectively accepting all certificates.
*/
public final class TrustManagerFactory {
private static X509TrustManager sUnsecureTrustManager = new SimpleX509TrustManager();
/**
* This trust manager performs no tests, effectively accepting all certificates.
*/
private static class SimpleX509TrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) {
logCertificates(chain, "Trusting client", false);
}
public void checkServerTrusted(X509Certificate[] chain, String authType) {
logCertificates(chain, "Trusting server", false);
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
/**
* This trust manager performs full tests, requiring a valid, trusted certificate.
*/
private static class SecureX509TrustManager implements X509TrustManager {
private X509TrustManager mTrustManager;
private String mHost;
SecureX509TrustManager(X509TrustManager trustManager, String host) {
mTrustManager = trustManager;
mHost = host;
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
mTrustManager.checkClientTrusted(chain, authType);
} catch (CertificateException ce) {
logCertificates(chain, "Failed client", true);
throw ce;
}
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
mTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce) {
logCertificates(chain, "Failed server", true);
throw ce;
}
if (!DomainNameValidator.match(chain[0], mHost)) {
logCertificates(chain, "Failed domain name", true);
throw new CertificateException("Certificate domain name does not match " + mHost);
}
}
public X509Certificate[] getAcceptedIssuers() {
return mTrustManager.getAcceptedIssuers();
}
}
/**
* Logging of certificates, to help debugging trust issues. Logging strategy:
* Trusting a certificate: Lightweight log about it
* Fully checking: Silent if OK, verbose log it failure
*
* @param chain the certificate chain to dump
* @param caller a prefix that will be added to each log
* @param verbose if true, the issuer and dates will also be logged
*/
private static void logCertificates(X509Certificate[] chain, String caller, boolean verbose) {
if (Email.DEBUG) {
for (int i = 0; i < chain.length; ++i) {
Log.d(Email.LOG_TAG, caller + " Certificate #" + i);
Log.d(Email.LOG_TAG, " subject=" + chain[i].getSubjectDN());
if (verbose) {
Log.d(Email.LOG_TAG, " issuer=" + chain[i].getIssuerDN());
Log.d(Email.LOG_TAG, " dates=" + chain[i].getNotBefore()
+ " to " + chain[i].getNotAfter());
}
}
}
}
private TrustManagerFactory() {
}
public static X509TrustManager get(String host, boolean secure) {
if (secure) {
return new SecureX509TrustManager(SSLParameters.getDefaultTrustManager(), host) ;
} else {
return sUnsecureTrustManager;
}
}
}

View File

@ -20,7 +20,6 @@ import com.android.email.Email;
import com.android.email.mail.CertificateValidationException;
import com.android.email.mail.MessagingException;
import com.android.email.mail.Transport;
import com.android.email.mail.store.TrustManagerFactory;
import android.util.Config;
import android.util.Log;
@ -153,11 +152,7 @@ public class MailTransport implements Transport {
try {
SocketAddress socketAddress = new InetSocketAddress(getHost(), getPort());
if (canTrySslSecurity()) {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] {
TrustManagerFactory.get(getHost(), !canTrustAllCertificates())
}, new SecureRandom());
mSocket = sslContext.getSocketFactory().createSocket();
mSocket = SSLUtils.getSSLSocketFactory(canTrustAllCertificates()).createSocket();
} else {
mSocket = new Socket();
}
@ -170,11 +165,6 @@ public class MailTransport implements Transport {
Log.d(Email.LOG_TAG, e.toString());
}
throw new CertificateValidationException(e.getMessage(), e);
} catch (GeneralSecurityException gse) {
if (Config.LOGD && Email.DEBUG) {
Log.d(Email.LOG_TAG, gse.toString());
}
throw new MessagingException(MessagingException.GENERAL_SECURITY, gse.toString());
} catch (IOException ioe) {
if (Config.LOGD && Email.DEBUG) {
Log.d(Email.LOG_TAG, ioe.toString());
@ -190,12 +180,8 @@ public class MailTransport implements Transport {
*/
public void reopenTls() throws MessagingException {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] {
TrustManagerFactory.get(getHost(), !canTrustAllCertificates())
}, new SecureRandom());
mSocket = sslContext.getSocketFactory().createSocket(mSocket, getHost(), getPort(),
true);
mSocket = SSLUtils.getSSLSocketFactory(canTrustAllCertificates())
.createSocket(mSocket, getHost(), getPort(), true);
mSocket.setSoTimeout(SOCKET_READ_TIMEOUT);
mIn = new BufferedInputStream(mSocket.getInputStream(), 1024);
mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512);
@ -205,11 +191,6 @@ public class MailTransport implements Transport {
Log.d(Email.LOG_TAG, e.toString());
}
throw new CertificateValidationException(e.getMessage(), e);
} catch (GeneralSecurityException gse) {
if (Config.LOGD && Email.DEBUG) {
Log.d(Email.LOG_TAG, gse.toString());
}
throw new MessagingException(MessagingException.GENERAL_SECURITY, gse.toString());
} catch (IOException ioe) {
if (Config.LOGD && Email.DEBUG) {
Log.d(Email.LOG_TAG, ioe.toString());

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2010 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.email.mail.transport;
import android.net.SSLCertificateSocketFactory;
import javax.net.ssl.SSLSocketFactory;
public class SSLUtils {
private static SSLSocketFactory sInsecureFactory;
private static SSLSocketFactory sSecureFactory;
/**
* Returns a {@link SSLSocketFactory}. Optionally bypass all SSL certificate checks.
*
* @param insecure if true, bypass all SSL certificate checks
*/
public synchronized static final SSLSocketFactory getSSLSocketFactory(boolean insecure) {
if (insecure) {
if (sInsecureFactory == null) {
sInsecureFactory = SSLCertificateSocketFactory.getInsecure(0, null);
}
return sInsecureFactory;
} else {
if (sSecureFactory == null) {
sSecureFactory = SSLCertificateSocketFactory.getDefault(0, null);
}
return sSecureFactory;
}
}
}

View File

@ -21,7 +21,7 @@ import com.android.email.AccountBackupRestore;
import com.android.email.Email;
import com.android.email.SecurityPolicy;
import com.android.email.mail.MessagingException;
import com.android.email.mail.store.TrustManagerFactory;
import com.android.email.mail.transport.SSLUtils;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.Attachment;
@ -1054,30 +1054,16 @@ public class SyncManager extends Service implements Runnable {
PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
// Create a new SSLSocketFactory for our "trusted ssl"
// Get the unsecure trust manager from the factory
X509TrustManager trustManager = TrustManagerFactory.get(null, false);
TrustManager[] trustManagers = new TrustManager[] {trustManager};
SSLContext sslcontext;
try {
sslcontext = SSLContext.getInstance("TLS");
try {
sslcontext.init(null, trustManagers, null);
} catch (KeyManagementException e) {
throw new AssertionError(e);
}
// Ok, now make our factory
SSLSocketFactory sf = new SSLSocketFactory(sslcontext.getSocketFactory());
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
// Register the httpts scheme with our factory
registry.register(new Scheme("httpts", sf, 443));
// And create a ccm with our registry
HttpParams params = new BasicHttpParams();
params.setIntParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 25);
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, sConnPerRoute);
sClientConnectionManager = new ThreadSafeClientConnManager(params, registry);
} catch (NoSuchAlgorithmException e2) {
}
// Use "insecure" socket factory.
SSLSocketFactory sf = new SSLSocketFactory(SSLUtils.getSSLSocketFactory(true));
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
// Register the httpts scheme with our factory
registry.register(new Scheme("httpts", sf, 443));
// And create a ccm with our registry
HttpParams params = new BasicHttpParams();
params.setIntParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 25);
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, sConnPerRoute);
sClientConnectionManager = new ThreadSafeClientConnManager(params, registry);
}
// Null is a valid return result if we get an exception
return sClientConnectionManager;