mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-30 05:02:26 -05:00
Merge into 'trunk'
r124@hotel-dan (orig r123): jessev | 2008-11-07 03:35:09 -0500 Branch for Bradley Young r126@hotel-dan (orig r125): young.bradley | 2008-11-08 17:27:30 -0500 Initial checkin of self signed certificates capability. Missing ability to save updated KeyStore. r127@hotel-dan (orig r126): young.bradley | 2008-11-10 13:04:49 -0500 Update to allow saving updated keys to keystore r17200@hotel-dan (orig r131): young.bradley | 2008-11-17 14:09:24 -0500 Updates to handle chains properly, and handle default behavior. r17206@hotel-dan (orig r137): young.bradley | 2008-11-29 14:14:25 -0500 Checkin for beta 2: this should be the release candidate.
This commit is contained in:
parent
9dbcae5eed
commit
194d673f91
@ -192,4 +192,8 @@
|
||||
<string name="status_network_error">Verbindungsfehler</string>
|
||||
<string name="status_sending">Senden\u2026</string>
|
||||
<string name="view_hide_details_action">Details anzeigen/ausblenden</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_title">Unrecognized Certificate</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_accept">Accept Key</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_reject">Reject Key</string>
|
||||
|
||||
</resources>
|
||||
|
@ -192,4 +192,8 @@
|
||||
<string name="status_network_error">Error de conexión</string>
|
||||
<string name="status_sending">Enviando\u2026</string>
|
||||
<string name="view_hide_details_action">Ver/ocultar detalles</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_title">Unrecognized Certificate</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_accept">Accept Key</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_reject">Reject Key</string>
|
||||
|
||||
</resources>
|
||||
|
@ -192,4 +192,7 @@
|
||||
<string name="status_network_error">Erreur de connexion</string>
|
||||
<string name="status_sending">Envoi\u2026</string>
|
||||
<string name="view_hide_details_action">Afficher/masquer les détails</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_title">Unrecognized Certificate</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_accept">Accept Key</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_reject">Reject Key</string>
|
||||
</resources>
|
||||
|
@ -192,4 +192,7 @@
|
||||
<string name="status_network_error">Errore di connessione</string>
|
||||
<string name="status_sending">Invio in corso\u2026</string>
|
||||
<string name="view_hide_details_action">Visualizza/Nascondi dettagli</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_title">Unrecognized Certificate</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_accept">Accept Key</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_reject">Reject Key</string>
|
||||
</resources>
|
||||
|
@ -192,4 +192,7 @@
|
||||
<string name="status_network_error">連線錯誤</string>
|
||||
<string name="status_sending">正在傳送\u2026</string>
|
||||
<string name="view_hide_details_action">檢視/隱藏詳細資料</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_title">Unrecognized Certificate</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_accept">Accept Key</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_reject">Reject Key</string>
|
||||
</resources>
|
||||
|
@ -251,6 +251,9 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
|
||||
<string name="account_settings_signature_label">Signature</string>
|
||||
<string name="account_settings_signature_summary">Append a signature to every message you send</string>
|
||||
|
||||
<string name="account_settings_sent_items_label">Sent Items Folder</string>
|
||||
<string name="account_settings_sent_items_summary">Save all sent messages to this folder</string>
|
||||
|
||||
<string name="account_delete_dlg_title">Remove</string>
|
||||
<string name="account_delete_dlg_instructions_fmt">The account \"<xliff:g id="account">%s</xliff:g>\" will be removed from Email.</string>
|
||||
|
||||
@ -260,4 +263,7 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
|
||||
your correct email address and password, you may not have a paid
|
||||
\"Plus\" account. Please launch the Web browser to gain access to
|
||||
these mail accounts.</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_title">Unrecognized Certificate</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_accept">Accept Key</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_reject">Reject Key</string>
|
||||
</resources>
|
||||
|
@ -1,6 +1,9 @@
|
||||
|
||||
package com.fsck.k9.activity.setup;
|
||||
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
@ -21,6 +24,7 @@ import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.Store;
|
||||
import com.fsck.k9.mail.Transport;
|
||||
import com.fsck.k9.mail.CertificateValidationException;
|
||||
import com.fsck.k9.mail.store.TrustManagerFactory;
|
||||
|
||||
/**
|
||||
* Checks the given settings to make sure that they can be used to send and
|
||||
@ -78,6 +82,7 @@ public class AccountSetupCheckSettings extends Activity implements OnClickListen
|
||||
|
||||
new Thread() {
|
||||
public void run() {
|
||||
Store store = null;
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
try {
|
||||
if (mDestroyed) {
|
||||
@ -89,7 +94,7 @@ public class AccountSetupCheckSettings extends Activity implements OnClickListen
|
||||
}
|
||||
if (mCheckIncoming) {
|
||||
setMessage(R.string.account_setup_check_settings_check_incoming_msg);
|
||||
Store store = Store.getInstance(mAccount.getStoreUri(), getApplication());
|
||||
store = Store.getInstance(mAccount.getStoreUri(), getApplication());
|
||||
store.checkSettings();
|
||||
}
|
||||
if (mDestroyed) {
|
||||
@ -120,15 +125,17 @@ public class AccountSetupCheckSettings extends Activity implements OnClickListen
|
||||
R.string.account_setup_failed_dlg_auth_message_fmt,
|
||||
afe.getMessage() == null ? "" : afe.getMessage());
|
||||
} catch (final CertificateValidationException cve) {
|
||||
showErrorDialog(
|
||||
acceptKeyDialog(
|
||||
R.string.account_setup_failed_dlg_certificate_message_fmt,
|
||||
cve.getMessage() == null ? "" : cve.getMessage());
|
||||
cve);
|
||||
//cve.getMessage() == null ? "" : cve.getMessage());
|
||||
} catch (final MessagingException me) {
|
||||
showErrorDialog(
|
||||
R.string.account_setup_failed_dlg_server_message_fmt,
|
||||
me.getMessage() == null ? "" : me.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}.start();
|
||||
}
|
||||
|
||||
@ -172,6 +179,85 @@ public class AccountSetupCheckSettings extends Activity implements OnClickListen
|
||||
}
|
||||
});
|
||||
}
|
||||
private void acceptKeyDialog(final int msgResId, final Object... args) {
|
||||
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) {
|
||||
exMessage = ex.getCause().getCause().getMessage();
|
||||
|
||||
} else {
|
||||
exMessage = ex.getCause().getMessage();
|
||||
}
|
||||
} else {
|
||||
exMessage = ex.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
mProgressBar.setIndeterminate(false);
|
||||
StringBuffer chainInfo = new StringBuffer(100);
|
||||
for (int i = 0; i < chain.length; i++)
|
||||
{
|
||||
// display certificate chain information
|
||||
chainInfo.append("Certificate chain[" + i + "]:\n");
|
||||
chainInfo.append("Subject: " + chain[i].getSubjectDN().toString() + "\n");
|
||||
chainInfo.append("Issuer: " + chain[i].getIssuerDN().toString() + "\n");
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(AccountSetupCheckSettings.this)
|
||||
.setTitle(getString(R.string.account_setup_failed_dlg_invalid_certificate_title))
|
||||
//.setMessage(getString(R.string.account_setup_failed_dlg_invalid_certificate)
|
||||
.setMessage(getString(msgResId,exMessage)
|
||||
+ " " + chainInfo.toString()
|
||||
)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(
|
||||
getString(R.string.account_setup_failed_dlg_invalid_certificate_accept),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
try {
|
||||
String alias = mAccount.getUuid();
|
||||
if (mCheckIncoming) {
|
||||
alias = alias + ".incoming";
|
||||
}
|
||||
if (mCheckOutgoing) {
|
||||
alias = alias + ".outgoing";
|
||||
}
|
||||
TrustManagerFactory.addCertificateChain(alias, chain);
|
||||
} catch (CertificateException e) {
|
||||
showErrorDialog(
|
||||
R.string.account_setup_failed_dlg_certificate_message_fmt,
|
||||
e.getMessage() == null ? "" : e.getMessage());
|
||||
}
|
||||
AccountSetupCheckSettings.actionCheckSettings(AccountSetupCheckSettings.this, mAccount,
|
||||
mCheckIncoming, mCheckOutgoing);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(
|
||||
getString(R.string.account_setup_failed_dlg_invalid_certificate_reject),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
finish();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onActivityResult(int reqCode, int resCode, Intent data) {
|
||||
setResult(resCode);
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
private void onCancel() {
|
||||
mCanceled = true;
|
||||
|
@ -17,6 +17,8 @@ import com.fsck.k9.service.BootReceiver;
|
||||
import com.fsck.k9.service.MailService;
|
||||
|
||||
public class k9 extends Application {
|
||||
public static Application app = null;
|
||||
|
||||
public static final String LOG_TAG = "k9";
|
||||
|
||||
public static File tempDirectory;
|
||||
@ -64,13 +66,14 @@ public class k9 extends Application {
|
||||
* The MIME type(s) of attachments we're willing to download to SD.
|
||||
*/
|
||||
public static final String[] ACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] {
|
||||
"*/*",
|
||||
"image/*",
|
||||
};
|
||||
|
||||
/**
|
||||
* The MIME type(s) of attachments we're not willing to download to SD.
|
||||
*/
|
||||
public static final String[] UNACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] {
|
||||
"image/gif",
|
||||
};
|
||||
|
||||
/**
|
||||
@ -87,7 +90,7 @@ public class k9 extends Application {
|
||||
public static final int DEFAULT_VISIBLE_LIMIT = 25;
|
||||
|
||||
/**
|
||||
* Number of additional messages to load when a user selectes "Load more messages..."
|
||||
* Number of additioanl messages to load when a user selectes "Load more messages..."
|
||||
*/
|
||||
public static final int VISIBLE_LIMIT_INCREMENT = 25;
|
||||
|
||||
@ -146,6 +149,7 @@ public class k9 extends Application {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
app = this;
|
||||
Preferences prefs = Preferences.getPreferences(this);
|
||||
DEBUG = prefs.geteEnableDebugLogging();
|
||||
DEBUG_SENSITIVE = prefs.getEnableSensitiveLogging();
|
||||
@ -156,13 +160,6 @@ public class k9 extends Application {
|
||||
* doesn't work in Android and MimeMessage does not have access to a Context.
|
||||
*/
|
||||
BinaryTempFileBody.setTempDirectory(getCacheDir());
|
||||
|
||||
/*
|
||||
* Enable background sync of messages
|
||||
*/
|
||||
|
||||
setServicesEnabled(this);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,13 @@
|
||||
package com.fsck.k9.mail.store;
|
||||
|
||||
import android.util.Log;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.net.http.DomainNameChecker;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.KeyStoreException;
|
||||
@ -13,11 +18,22 @@ import java.security.cert.CertificateException;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import javax.net.ssl.TrustManager;
|
||||
|
||||
import com.fsck.k9.k9;
|
||||
|
||||
public final class TrustManagerFactory {
|
||||
private static final String LOG_TAG = "TrustManagerFactory";
|
||||
|
||||
private static X509TrustManager sSecureTrustManager;
|
||||
private static X509TrustManager sUnsecureTrustManager;
|
||||
private static X509TrustManager defaultTrustManager;
|
||||
private static X509TrustManager unsecureTrustManager;
|
||||
private static X509TrustManager localTrustManager;
|
||||
|
||||
private static SecureX509TrustManager secureTrustManager;
|
||||
|
||||
private static X509Certificate[] lastCertChain = null;
|
||||
|
||||
private static File keyStoreFile;
|
||||
private static KeyStore keyStore;
|
||||
|
||||
|
||||
private static class SimpleX509TrustManager implements X509TrustManager {
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
||||
@ -34,62 +50,171 @@ public final class TrustManagerFactory {
|
||||
}
|
||||
|
||||
private static class SecureX509TrustManager implements X509TrustManager {
|
||||
private X509TrustManager mTrustManager;
|
||||
private String mHost;
|
||||
//private static X509TrustManager mTrustManager;
|
||||
//private static X509TrustManager mLocalTrustManager;
|
||||
private static String mHost;
|
||||
private static SecureX509TrustManager me;
|
||||
|
||||
SecureX509TrustManager(X509TrustManager trustManager, String host) {
|
||||
mTrustManager = trustManager;
|
||||
private SecureX509TrustManager() {
|
||||
}
|
||||
|
||||
public static X509TrustManager getInstance(String host) {
|
||||
mHost = host;
|
||||
if (me == null) {
|
||||
me = new SecureX509TrustManager();
|
||||
}
|
||||
return me;
|
||||
}
|
||||
|
||||
public static void setHost(String host){
|
||||
mHost = host;
|
||||
}
|
||||
|
||||
//
|
||||
// public static void updateTrustManager(X509TrustManager trustManager) {
|
||||
// mTrustManager = trustManager;
|
||||
// }
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
||||
throws CertificateException {
|
||||
mTrustManager.checkClientTrusted(chain, authType);
|
||||
defaultTrustManager.checkClientTrusted(chain, authType);
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
||||
throws CertificateException {
|
||||
|
||||
mTrustManager.checkServerTrusted(chain, authType);
|
||||
|
||||
TrustManagerFactory.setLastCertChain(chain);
|
||||
try {
|
||||
defaultTrustManager.checkServerTrusted(chain, authType);
|
||||
} catch (CertificateException e) {
|
||||
localTrustManager.checkServerTrusted(chain, authType);
|
||||
}
|
||||
if (!DomainNameChecker.match(chain[0], mHost)) {
|
||||
try {
|
||||
String dn = chain[0].getSubjectDN().toString();
|
||||
if ((dn != null) && (dn.equalsIgnoreCase(keyStore.getCertificateAlias(chain[0])))) {
|
||||
return;
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new CertificateException("Certificate cannot be verified; KeyStore Exception: " + e);
|
||||
}
|
||||
throw new CertificateException("Certificate domain name does not match "
|
||||
+ mHost);
|
||||
}
|
||||
}
|
||||
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return mTrustManager.getAcceptedIssuers();
|
||||
return defaultTrustManager.getAcceptedIssuers();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static {
|
||||
try {
|
||||
javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
|
||||
tmf.init((KeyStore) null);
|
||||
Application app = k9.app;
|
||||
keyStoreFile = new File(app.getDir("KeyStore", Context.MODE_PRIVATE) + File.separator + "KeyStore.bks");
|
||||
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
//TODO: read store from disk.
|
||||
java.io.FileInputStream fis;
|
||||
try {
|
||||
fis = new java.io.FileInputStream(keyStoreFile);
|
||||
} catch (FileNotFoundException e1) {
|
||||
fis = null;
|
||||
}
|
||||
try {
|
||||
keyStore.load(fis, "".toCharArray());
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, "KeyStore IOException while initializing TrustManagerFactory ", e);
|
||||
keyStore = null;
|
||||
} catch (CertificateException e) {
|
||||
Log.e(LOG_TAG, "KeyStore CertificateException while initializing TrustManagerFactory ", e);
|
||||
keyStore = null;
|
||||
}
|
||||
tmf.init(keyStore);
|
||||
TrustManager[] tms = tmf.getTrustManagers();
|
||||
if (tms != null) {
|
||||
for (TrustManager tm : tms) {
|
||||
if (tm instanceof X509TrustManager) {
|
||||
sSecureTrustManager = (X509TrustManager) tm;
|
||||
localTrustManager = (X509TrustManager)tm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
|
||||
tmf.init((KeyStore)null);
|
||||
tms = tmf.getTrustManagers();
|
||||
if (tms != null) {
|
||||
for (TrustManager tm : tms) {
|
||||
if (tm instanceof X509TrustManager) {
|
||||
defaultTrustManager = (X509TrustManager) tm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
|
||||
} catch (KeyStoreException e) {
|
||||
Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
|
||||
}
|
||||
|
||||
sUnsecureTrustManager = new SimpleX509TrustManager();
|
||||
unsecureTrustManager = new SimpleX509TrustManager();
|
||||
}
|
||||
|
||||
private TrustManagerFactory() {
|
||||
}
|
||||
|
||||
public static X509TrustManager get(String host, boolean secure) {
|
||||
return secure ? new SecureX509TrustManager(sSecureTrustManager, host) :
|
||||
sUnsecureTrustManager;
|
||||
return secure ? SecureX509TrustManager.getInstance(host) :
|
||||
unsecureTrustManager;
|
||||
}
|
||||
|
||||
public static KeyStore getKeyStore() {
|
||||
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");
|
||||
for (int i = 0; i < chain.length; i++)
|
||||
{
|
||||
keyStore.setCertificateEntry
|
||||
(chain[i].getSubjectDN().toString(), chain[i]);
|
||||
}
|
||||
|
||||
tmf.init(keyStore);
|
||||
TrustManager[] tms = tmf.getTrustManagers();
|
||||
if (tms != null) {
|
||||
for (TrustManager tm : tms) {
|
||||
if (tm instanceof X509TrustManager) {
|
||||
localTrustManager = (X509TrustManager) tm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
java.io.FileOutputStream keyStoreStream;
|
||||
try {
|
||||
keyStoreStream = new java.io.FileOutputStream(keyStoreFile);
|
||||
keyStore.store(keyStoreStream, "".toCharArray());
|
||||
keyStoreStream.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
|
||||
} catch (CertificateException e) {
|
||||
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
|
||||
}
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
|
||||
} catch (KeyStoreException e) {
|
||||
Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user