Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20c4a97c authored by Jesse Vincent's avatar Jesse Vincent
Browse files

Merge pull request #365 from zjw/Issue_5886_misleading_ssl_errors

Fix erroneous SSL certificate warnings
parents 8e875fd0 604aa87c
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -159,11 +159,12 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
                } catch (final CertificateValidationException cve) {
                    Log.e(K9.LOG_TAG, "Error while testing settings", cve);

                    X509Certificate[] chain = cve.getCertChain();
                    // Avoid NullPointerException in acceptKeyDialog()
                    if (TrustManagerFactory.getLastCertChain() != null) {
                    if (chain != null) {
                        acceptKeyDialog(
                            R.string.account_setup_failed_dlg_certificate_message_fmt,
                            cve);
                            cve, chain);
                    } else {
                        showErrorDialog(
                                R.string.account_setup_failed_dlg_server_message_fmt,
@@ -232,16 +233,16 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
            }
        });
    }
    private void acceptKeyDialog(final int msgResId, final Object... args) {

    private void acceptKeyDialog(final int msgResId,
            final CertificateValidationException ex, final X509Certificate[] chain) {
        mHandler.post(new Runnable() {
            public void run() {
                if (mDestroyed) {
                    return;
                }
                final X509Certificate[] chain = TrustManagerFactory.getLastCertChain();
                String exMessage = "Unknown Error";

                Exception ex = ((Exception)args[0]);
                if (ex != null) {
                    if (ex.getCause() != null) {
                        if (ex.getCause().getCause() != null) {
+34 −0
Original line number Diff line number Diff line
package com.fsck.k9.mail;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * A {@link CertificateException} extension that provides access to
 * the pertinent certificate chain.
 *
 */
public class CertificateChainException extends CertificateException {

    private static final long serialVersionUID = 1103894512106650107L;
    private X509Certificate[] mCertChain;

    public CertificateChainException(String msg, X509Certificate[] chain) {
        super(msg);
        setCertChain(chain);
    }

    public CertificateChainException(CertificateException ce,
            X509Certificate[] chain) {
        super.initCause(ce);
        setCertChain(chain);
    }

    public void setCertChain(X509Certificate[] chain) {
        mCertChain = chain;
    }
    public X509Certificate[] getCertChain() {
        return mCertChain;
    }

}
+18 −0
Original line number Diff line number Diff line
@@ -3,9 +3,11 @@ package com.fsck.k9.mail;

import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class CertificateValidationException extends MessagingException {
    public static final long serialVersionUID = -1;
    private X509Certificate[] mCertChain;

    public CertificateValidationException(String message) {
        super(message);
@@ -25,6 +27,22 @@ public class CertificateValidationException extends MessagingException {
            throwable = throwable.getCause();
        }

        if (throwable instanceof CertificateChainException) {
            mCertChain = ((CertificateChainException) throwable).getCertChain();
        }
        return throwable != null;
    }

    /**
     * If the cause of this {@link CertificateValidationException} was a
     * {@link CertificateChainException}, then the offending chain is available
     * for return.
     * 
     * @return An {@link X509Certificate X509Certificate[]} containing the Cert.
     *         chain, or else null.
     */
    public X509Certificate[] getCertChain() {
        needsUserAttention();
        return mCertChain;
    }
}
 No newline at end of file
+11 −15
Original line number Diff line number Diff line
@@ -6,6 +6,8 @@ import android.content.Context;
import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.helper.DomainNameChecker;
import com.fsck.k9.mail.CertificateChainException;

import org.apache.commons.io.IOUtils;

import javax.net.ssl.TrustManager;
@@ -28,8 +30,6 @@ public final class TrustManagerFactory {
    private static X509TrustManager unsecureTrustManager;
    private static X509TrustManager localTrustManager;

    private static X509Certificate[] lastCertChain = null;

    private static File keyStoreFile;
    private static KeyStore keyStore;

@@ -77,13 +77,15 @@ public final class TrustManagerFactory {

        public void checkServerTrusted(X509Certificate[] chain, String authType)
        throws CertificateException {
            // FIXME: Using a static field to store the certificate chain is a bad idea. Instead
            // create a CertificateException subclass and store the chain there.
            TrustManagerFactory.setLastCertChain(chain);
            try {
                defaultTrustManager.checkServerTrusted(chain, authType);
            } catch (CertificateException e) {
                localTrustManager.checkServerTrusted(new X509Certificate[] {chain[0]}, authType);
                try {
                    localTrustManager.checkServerTrusted(
                            new X509Certificate[] { chain[0] }, authType);
                } catch (CertificateException ce) {
                    throw new CertificateChainException(ce, chain);
                }
            }
            if (!DomainNameChecker.match(chain[0], mHost)) {
                try {
@@ -94,8 +96,9 @@ public final class TrustManagerFactory {
                } catch (KeyStoreException e) {
                    throw new CertificateException("Certificate cannot be verified; KeyStore Exception: " + e);
                }
                throw new CertificateException("Certificate domain name does not match "
                                               + mHost);
                throw new CertificateChainException(
                        "Certificate domain name does not match " + mHost,
                        chain);
            }
        }

@@ -170,13 +173,6 @@ public final class TrustManagerFactory {
        return keyStore;
    }

    public static void setLastCertChain(X509Certificate[] chain) {
        lastCertChain = chain;
    }
    public static X509Certificate[] getLastCertChain() {
        return lastCertChain;
    }

    public static void addCertificateChain(String alias, X509Certificate[] chain) throws CertificateException {
        try {
            javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");