Add one more error state to certificate process
When the KeyStore fails to give us back a certificate for any reason (it was removed from the keystore perhaps), propagate the error back up. Change-Id: I4f0ef783c1665589cc8ccb43d95da43a297a3e9a
This commit is contained in:
parent
8401dba404
commit
cb24e515b7
|
@ -63,7 +63,9 @@ public class MessagingException extends Exception {
|
|||
/** The server refused access */
|
||||
public static final int ATTACHMENT_NOT_FOUND = 15;
|
||||
/** A client SSL certificate is required for connections to the server */
|
||||
public static final int CLIENT_CERTIFICATE_ERROR = 16;
|
||||
public static final int CLIENT_CERTIFICATE_REQUIRED = 16;
|
||||
/** The client SSL certificate specified is invalid */
|
||||
public static final int CLIENT_CERTIFICATE_ERROR = 17;
|
||||
|
||||
protected int mExceptionType;
|
||||
// Exception type-specific data
|
||||
|
|
|
@ -37,4 +37,7 @@ public interface EmailServiceStatus {
|
|||
|
||||
// Maybe we should automatically retry these?
|
||||
public static final int CONNECTION_ERROR = 0x20;
|
||||
|
||||
// Client certificates used to authenticate cannot be retrieved from the system.
|
||||
public static final int CLIENT_CERTIFICATE_ERROR = 0x21;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@ import com.android.emailcommon.Logging;
|
|||
import com.android.emailcommon.utility.SSLUtils.KeyChainKeyManager;
|
||||
import com.android.emailcommon.utility.SSLUtils.TrackingKeyManager;
|
||||
|
||||
import org.apache.http.conn.ClientConnectionRequest;
|
||||
import org.apache.http.conn.routing.HttpRoute;
|
||||
import org.apache.http.conn.scheme.PlainSocketFactory;
|
||||
import org.apache.http.conn.scheme.Scheme;
|
||||
import org.apache.http.conn.scheme.SchemeRegistry;
|
||||
|
@ -33,6 +31,8 @@ import android.content.Context;
|
|||
import android.net.SSLCertificateSocketFactory;
|
||||
import android.util.Log;
|
||||
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
|
||||
/**
|
||||
|
@ -75,7 +75,8 @@ public class EmailClientConnectionManager extends ThreadSafeClientConnManager {
|
|||
* {@link #makeSchemeForClientCert(String, boolean)}.
|
||||
*/
|
||||
public synchronized void registerClientCert(
|
||||
Context context, String clientCertAlias, boolean trustAllServerCerts) {
|
||||
Context context, String clientCertAlias, boolean trustAllServerCerts)
|
||||
throws CertificateException {
|
||||
SchemeRegistry registry = getSchemeRegistry();
|
||||
String schemeName = makeSchemeForClientCert(clientCertAlias, trustAllServerCerts);
|
||||
Scheme existing = registry.get(schemeName);
|
||||
|
@ -85,12 +86,6 @@ public class EmailClientConnectionManager extends ThreadSafeClientConnManager {
|
|||
+ clientCertAlias + "]");
|
||||
}
|
||||
KeyManager keyManager = KeyChainKeyManager.fromAlias(context, clientCertAlias);
|
||||
if (keyManager == null) {
|
||||
// TODO: handle failing to retrieve credentials from the keystore.
|
||||
Log.e(Logging.LOG_TAG, "Unable to retrieve credentials for alias ["
|
||||
+ clientCertAlias + "]");
|
||||
return;
|
||||
}
|
||||
SSLCertificateSocketFactory underlying = SSLUtils.getSSLSocketFactory(
|
||||
trustAllServerCerts);
|
||||
underlying.setKeyManagers(new KeyManager[] { keyManager });
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.util.Log;
|
|||
import java.net.Socket;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -178,16 +179,17 @@ public class SSLUtils {
|
|||
* If for any reason retrieval of the credentials from the system {@link KeyChain} fails,
|
||||
* a {@code null} value will be returned.
|
||||
*/
|
||||
public static KeyChainKeyManager fromAlias(Context context, String alias) {
|
||||
public static KeyChainKeyManager fromAlias(Context context, String alias)
|
||||
throws CertificateException {
|
||||
X509Certificate[] certificateChain;
|
||||
try {
|
||||
certificateChain = KeyChain.getCertificateChain(context, alias);
|
||||
} catch (KeyChainException e) {
|
||||
logError(alias, "certificate chain", e);
|
||||
return null;
|
||||
throw new CertificateException(e);
|
||||
} catch (InterruptedException e) {
|
||||
logError(alias, "certificate chain", e);
|
||||
return null;
|
||||
throw new CertificateException(e);
|
||||
}
|
||||
|
||||
PrivateKey privateKey;
|
||||
|
@ -195,10 +197,15 @@ public class SSLUtils {
|
|||
privateKey = KeyChain.getPrivateKey(context, alias);
|
||||
} catch (KeyChainException e) {
|
||||
logError(alias, "private key", e);
|
||||
return null;
|
||||
throw new CertificateException(e);
|
||||
} catch (InterruptedException e) {
|
||||
logError(alias, "private key", e);
|
||||
return null;
|
||||
throw new CertificateException(e);
|
||||
}
|
||||
|
||||
if (certificateChain == null || privateKey == null) {
|
||||
throw new CertificateException(
|
||||
"Can't access certificate from keystore for alias [" + alias + "]");
|
||||
}
|
||||
|
||||
return new KeyChainKeyManager(alias, certificateChain, privateKey);
|
||||
|
|
|
@ -770,8 +770,12 @@ save attachment.</string>
|
|||
>Cannot safely connect to server.\n(<xliff:g id="error">%s</xliff:g>)</string>
|
||||
<!-- An error message presented to the user when the server requires a
|
||||
client certificate to connect [CHAR LIMIT=NONE] -->
|
||||
<string name="account_setup_failed_certificate_required">User certificate
|
||||
required to connect to server.</string>
|
||||
<string name="account_setup_failed_certificate_required"
|
||||
>User certificate required to connect to server.</string>
|
||||
<!-- An error message presented to the user when the certificate they
|
||||
specified for connecting to a server is inaccessible [CHAR LIMIT=NONE] -->
|
||||
<string name="account_setup_failed_certificate_inaccessible"
|
||||
>Certificate invalid or inaccessible.</string>
|
||||
|
||||
<!-- Dialog text for ambiguous setup failure; server error/bad credentials [CHAR LIMIT=none] -->
|
||||
<string name="account_setup_failed_check_credentials_message">
|
||||
|
|
|
@ -1609,6 +1609,9 @@ public class Controller {
|
|||
case EmailServiceStatus.ATTACHMENT_NOT_FOUND:
|
||||
return new MessagingException(MessagingException.ATTACHMENT_NOT_FOUND);
|
||||
|
||||
case EmailServiceStatus.CLIENT_CERTIFICATE_ERROR:
|
||||
return new MessagingException(MessagingException.CLIENT_CERTIFICATE_ERROR);
|
||||
|
||||
case EmailServiceStatus.MESSAGE_NOT_FOUND:
|
||||
case EmailServiceStatus.FOLDER_NOT_DELETED:
|
||||
case EmailServiceStatus.FOLDER_NOT_RENAMED:
|
||||
|
|
|
@ -49,6 +49,8 @@ public class MessagingExceptionStrings {
|
|||
return R.string.account_setup_failed_security;
|
||||
case MessagingException.ACCESS_DENIED:
|
||||
return R.string.account_setup_failed_access_denied;
|
||||
case MessagingException.CLIENT_CERTIFICATE_ERROR:
|
||||
return R.string.account_setup_failed_certificate_inaccessible;
|
||||
}
|
||||
return R.string.status_network_error; // default
|
||||
}
|
||||
|
|
|
@ -645,9 +645,12 @@ public class AccountCheckSettingsFragment extends Fragment {
|
|||
case MessagingException.GENERAL_SECURITY:
|
||||
id = R.string.account_setup_failed_security;
|
||||
break;
|
||||
case MessagingException.CLIENT_CERTIFICATE_ERROR:
|
||||
case MessagingException.CLIENT_CERTIFICATE_REQUIRED:
|
||||
id = R.string.account_setup_failed_certificate_required;
|
||||
break;
|
||||
case MessagingException.CLIENT_CERTIFICATE_ERROR:
|
||||
id = R.string.account_setup_failed_certificate_inaccessible;
|
||||
break;
|
||||
default:
|
||||
id = TextUtils.isEmpty(message)
|
||||
? R.string.account_setup_failed_dlg_server_message
|
||||
|
|
Loading…
Reference in New Issue