/* * 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.email.Email; import org.apache.harmony.xnet.provider.jsse.SSLParameters; import android.net.http.DomainNameChecker; 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 (!DomainNameChecker.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; } } }