2011-05-04 17:15:35 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2011 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;
|
|
|
|
|
2011-07-01 03:25:03 +00:00
|
|
|
import android.content.Context;
|
2013-11-15 20:43:40 +00:00
|
|
|
import android.text.TextUtils;
|
2011-07-01 03:25:03 +00:00
|
|
|
|
2011-05-04 17:15:35 +00:00
|
|
|
import com.android.emailcommon.Logging;
|
2012-06-28 17:40:46 +00:00
|
|
|
import com.android.emailcommon.provider.HostAuth;
|
2011-05-04 17:15:35 +00:00
|
|
|
import com.android.emailcommon.utility.SSLUtils.KeyChainKeyManager;
|
2011-06-16 00:54:45 +00:00
|
|
|
import com.android.emailcommon.utility.SSLUtils.TrackingKeyManager;
|
2013-05-26 04:32:32 +00:00
|
|
|
import com.android.mail.utils.LogUtils;
|
2011-05-04 17:15:35 +00:00
|
|
|
|
|
|
|
import org.apache.http.conn.scheme.PlainSocketFactory;
|
|
|
|
import org.apache.http.conn.scheme.Scheme;
|
|
|
|
import org.apache.http.conn.scheme.SchemeRegistry;
|
|
|
|
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
|
|
|
|
import org.apache.http.params.HttpParams;
|
|
|
|
|
2011-06-16 20:37:10 +00:00
|
|
|
import java.security.cert.CertificateException;
|
|
|
|
|
2011-05-04 17:15:35 +00:00
|
|
|
import javax.net.ssl.KeyManager;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A thread-safe client connection manager that manages the use of client certificates from the
|
|
|
|
* {@link android.security.KeyChain} for SSL connections.
|
|
|
|
*/
|
|
|
|
public class EmailClientConnectionManager extends ThreadSafeClientConnManager {
|
|
|
|
|
2012-06-28 17:40:46 +00:00
|
|
|
private static final int STANDARD_PORT = 80;
|
|
|
|
private static final int STANDARD_SSL_PORT = 443;
|
2011-05-04 17:15:35 +00:00
|
|
|
private static final boolean LOG_ENABLED = false;
|
|
|
|
|
2011-07-01 03:25:03 +00:00
|
|
|
/**
|
|
|
|
* A {@link KeyManager} to track client certificate requests from servers.
|
|
|
|
*/
|
|
|
|
private final TrackingKeyManager mTrackingKeyManager;
|
|
|
|
|
2011-05-04 17:15:35 +00:00
|
|
|
/**
|
|
|
|
* Not publicly instantiable except via {@link #newInstance(HttpParams)}
|
|
|
|
*/
|
2011-07-01 03:25:03 +00:00
|
|
|
private EmailClientConnectionManager(
|
|
|
|
HttpParams params, SchemeRegistry registry, TrackingKeyManager keyManager) {
|
2011-05-04 17:15:35 +00:00
|
|
|
super(params, registry);
|
2011-07-01 03:25:03 +00:00
|
|
|
mTrackingKeyManager = keyManager;
|
2011-05-04 17:15:35 +00:00
|
|
|
}
|
|
|
|
|
2012-07-31 22:47:49 +00:00
|
|
|
public static EmailClientConnectionManager newInstance(Context context, HttpParams params,
|
|
|
|
HostAuth hostAuth) {
|
2011-06-16 00:54:45 +00:00
|
|
|
TrackingKeyManager keyManager = new TrackingKeyManager();
|
2012-07-31 22:47:49 +00:00
|
|
|
boolean ssl = hostAuth.shouldUseSsl();
|
|
|
|
int port = hostAuth.mPort;
|
2011-06-16 00:54:45 +00:00
|
|
|
|
2011-05-04 17:15:35 +00:00
|
|
|
// Create a registry for our three schemes; http and https will use built-in factories
|
|
|
|
SchemeRegistry registry = new SchemeRegistry();
|
2012-06-28 17:40:46 +00:00
|
|
|
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(),
|
|
|
|
ssl ? STANDARD_PORT : port));
|
|
|
|
// Register https with the secure factory
|
2011-06-16 00:54:45 +00:00
|
|
|
registry.register(new Scheme("https",
|
2012-07-31 22:47:49 +00:00
|
|
|
SSLUtils.getHttpSocketFactory(context, hostAuth, keyManager, false),
|
|
|
|
ssl ? port : STANDARD_SSL_PORT));
|
2011-05-04 17:15:35 +00:00
|
|
|
// Register the httpts scheme with our insecure factory
|
|
|
|
registry.register(new Scheme("httpts",
|
2012-07-31 22:47:49 +00:00
|
|
|
SSLUtils.getHttpSocketFactory(context, hostAuth, keyManager, true),
|
2012-06-28 17:40:46 +00:00
|
|
|
ssl ? port : STANDARD_SSL_PORT));
|
2011-05-04 17:15:35 +00:00
|
|
|
|
2011-07-01 03:25:03 +00:00
|
|
|
return new EmailClientConnectionManager(params, registry, keyManager);
|
2011-05-04 17:15:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ensures that a client SSL certificate is known to be used for the specified connection
|
|
|
|
* manager.
|
|
|
|
* A {@link SchemeRegistry} is used to denote which client certificates to use for a given
|
|
|
|
* connection, so clients of this connection manager should use
|
|
|
|
* {@link #makeSchemeForClientCert(String, boolean)}.
|
|
|
|
*/
|
2012-06-28 17:40:46 +00:00
|
|
|
public synchronized void registerClientCert(Context context, HostAuth hostAuth)
|
2011-06-16 20:37:10 +00:00
|
|
|
throws CertificateException {
|
2013-11-15 20:43:40 +00:00
|
|
|
if (TextUtils.isEmpty(hostAuth.mClientCertAlias)) {
|
|
|
|
return;
|
|
|
|
}
|
2011-05-04 17:15:35 +00:00
|
|
|
SchemeRegistry registry = getSchemeRegistry();
|
2012-06-28 17:40:46 +00:00
|
|
|
String schemeName = makeSchemeForClientCert(hostAuth.mClientCertAlias,
|
|
|
|
hostAuth.shouldTrustAllServerCerts());
|
2011-05-04 17:15:35 +00:00
|
|
|
Scheme existing = registry.get(schemeName);
|
|
|
|
if (existing == null) {
|
|
|
|
if (LOG_ENABLED) {
|
2013-05-26 04:32:32 +00:00
|
|
|
LogUtils.i(Logging.LOG_TAG, "Registering socket factory for certificate alias ["
|
2012-06-28 17:40:46 +00:00
|
|
|
+ hostAuth.mClientCertAlias + "]");
|
2011-05-04 17:15:35 +00:00
|
|
|
}
|
2012-06-28 17:40:46 +00:00
|
|
|
KeyManager keyManager =
|
|
|
|
KeyChainKeyManager.fromAlias(context, hostAuth.mClientCertAlias);
|
2012-08-16 18:45:13 +00:00
|
|
|
boolean insecure = hostAuth.shouldTrustAllServerCerts();
|
|
|
|
SSLSocketFactory ssf =
|
|
|
|
SSLUtils.getHttpSocketFactory(context, hostAuth, keyManager, insecure);
|
|
|
|
registry.register(new Scheme(schemeName, ssf, hostAuth.mPort));
|
2011-05-04 17:15:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unregisters a custom connection type that uses a client certificate on the connection
|
|
|
|
* manager.
|
|
|
|
* @see #registerClientCert(Context, String, boolean)
|
|
|
|
*/
|
|
|
|
public synchronized void unregisterClientCert(
|
|
|
|
String clientCertAlias, boolean trustAllServerCerts) {
|
|
|
|
SchemeRegistry registry = getSchemeRegistry();
|
|
|
|
String schemeName = makeSchemeForClientCert(clientCertAlias, trustAllServerCerts);
|
|
|
|
Scheme existing = registry.get(schemeName);
|
|
|
|
if (existing != null) {
|
|
|
|
registry.unregister(schemeName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds a custom scheme name to be used in a connection manager according to the connection
|
|
|
|
* parameters.
|
|
|
|
*/
|
|
|
|
public static String makeScheme(
|
|
|
|
boolean useSsl, boolean trustAllServerCerts, String clientCertAlias) {
|
2014-08-07 19:42:40 +00:00
|
|
|
if (!TextUtils.isEmpty(clientCertAlias)) {
|
2011-05-04 17:15:35 +00:00
|
|
|
return makeSchemeForClientCert(clientCertAlias, trustAllServerCerts);
|
|
|
|
} else {
|
|
|
|
return useSsl ? (trustAllServerCerts ? "httpts" : "https") : "http";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds a unique scheme name for an SSL connection that uses a client user certificate.
|
|
|
|
*/
|
|
|
|
private static String makeSchemeForClientCert(
|
|
|
|
String clientCertAlias, boolean trustAllServerCerts) {
|
|
|
|
String safeAlias = SSLUtils.escapeForSchemeName(clientCertAlias);
|
|
|
|
return (trustAllServerCerts ? "httpts" : "https") + "+clientCert+" + safeAlias;
|
|
|
|
}
|
2011-07-01 03:25:03 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param since A timestamp in millis from epoch from which to check
|
|
|
|
* @return whether or not this connection manager has detected any unsatisfied requests for
|
|
|
|
* a client SSL certificate by any servers
|
|
|
|
*/
|
|
|
|
public synchronized boolean hasDetectedUnsatisfiedCertReq(long since) {
|
|
|
|
return mTrackingKeyManager.getLastCertReqTime() >= since;
|
|
|
|
}
|
2011-05-04 17:15:35 +00:00
|
|
|
}
|