
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;
    private boolean mNeedsUserAttention = false;

    public CertificateValidationException(String message) {
        super(message);
        scanForCause();
    }

    public CertificateValidationException(final String message, Throwable throwable) {
        super(message, throwable);
        scanForCause();
    }

    private void scanForCause() {
        Throwable throwable = getCause();

        /* user attention is required if the certificate was deemed invalid */
        while (throwable != null
                && !(throwable instanceof CertPathValidatorException)
                && !(throwable instanceof CertificateException)) {
            throwable = throwable.getCause();
        }

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

    public boolean needsUserAttention() {
        return mNeedsUserAttention;
    }

    /**
     * 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() {
        return mCertChain;
    }
}
@@ -167,16 +167,105 @@
 icate;%0A%0A
+import javax.net.ssl.SSLHandshakeException;%0A%0Aimport android.security.KeyChainException;%0A%0A
 public c
@@ -561,38 +561,191 @@
 e);%0A        
-scanForCause()
+/*%0A         * Instances created without a Throwable parameter as a cause are%0A         * presumed to need user attention.%0A         */%0A        mNeedsUserAttention = true
 ;%0A    %7D%0A%0A   
@@ -981,18 +981,29 @@
       /*
- u
+%0A         * U
 ser atte
@@ -1027,16 +1027,23 @@
  if the 
+server 
 certific
@@ -1060,16 +1060,1654 @@
 emed
- invalid
+%0A         * invalid or if there was a problem with a client certificate.%0A         *%0A         * A CertificateException is known to be thrown by the default%0A         * X509TrustManager.checkServerTrusted() if the server certificate%0A         * doesn't validate. The cause of the CertificateException will be a%0A         * CertPathValidatorException. However, it's unlikely those exceptions%0A         * will be encountered here, because they are caught in%0A         * SecureX509TrustManager.checkServerTrusted(), which throws a%0A         * CertificateChainException instead (an extension of%0A         * CertificateException).%0A         *%0A         * A CertificateChainException will likely result in (or, be the cause%0A         * of) an SSLHandshakeException (an extension of SSLException).%0A         *%0A         * The various mail protocol handlers (IMAP, POP3, ...) will catch an%0A         * SSLException and throw a CertificateValidationException (this class)%0A         * with the SSLException as the cause. (They may also throw a%0A         * CertificateValidationException when STARTTLS is not available, just%0A         * for the purpose of triggering a user notification.)%0A         *%0A         * SSLHandshakeException is also known to occur if the *client*%0A         * certificate was not accepted by the server (unknown CA, certificate%0A         * expired, etc.). In this case, the SSLHandshakeException will not have%0A         * a CertificateChainException as a cause.%0A         *%0A         * KeyChainException is known to occur if the device has no client%0A         * certificate that's associated with the alias stored in the server%0A         * settings.%0A        
  */%0A
@@ -2872,16 +2872,142 @@
 ception)
+%0A                && !(throwable instanceof KeyChainException)%0A                && !(throwable instanceof SSLHandshakeException)
 ) %7B%0A    
@@ -3136,24 +3136,386 @@
 ue;%0A
-            if (
+%0A            // See if there is a server certificate chain attached to the SSLHandshakeException%0A            if (throwable instanceof SSLHandshakeException) %7B%0A                while (throwable != null && !(throwable instanceof CertificateChainException)) %7B%0A                  throwable = throwable.getCause();%0A                %7D%0A            %7D%0A%0A            if (throwable != null && 
 thro

Update CertificateValidationException