switched to mtm

iNPUTmice created

Change summary

.gitmodules                                                    |  3 
AndroidManifest.xml                                            |  1 
libs/MemorizingTrustManager                                    |  1 
project.properties                                             |  1 
src/eu/siacs/conversations/services/XmppConnectionService.java | 34 -
src/eu/siacs/conversations/ui/ManageAccountActivity.java       | 54 --
src/eu/siacs/conversations/xmpp/XmppConnection.java            | 81 ---
7 files changed, 33 insertions(+), 142 deletions(-)

Detailed changes

.gitmodules 🔗

@@ -5,3 +5,6 @@
 [submodule "libs/openpgp-api-lib"]
 	path = libs/openpgp-api-lib
 	url = https://github.com/open-keychain/openpgp-api-lib.git
+[submodule "libs/MemorizingTrustManager"]
+	path = libs/MemorizingTrustManager
+	url = https://github.com/ge0rg/MemorizingTrustManager

AndroidManifest.xml 🔗

@@ -105,6 +105,7 @@
                 <data android:mimeType="image/*" />
             </intent-filter>
         </activity>
+        <activity android:name="de.duenndns.ssl.MemorizingActivity" />
     </application>
 
 </manifest>

project.properties 🔗

@@ -14,3 +14,4 @@
 target=android-19
 android.library.reference.1=libs/minidns
 android.library.reference.2=libs/openpgp-api-lib
+android.library.reference.3=libs/MemorizingTrustManager

src/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -15,6 +15,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
 import org.openintents.openpgp.util.OpenPgpApi;
 import org.openintents.openpgp.util.OpenPgpServiceConnection;
 
+import de.duenndns.ssl.MemorizingTrustManager;
+
 import net.java.otr4j.OtrException;
 import net.java.otr4j.session.Session;
 import net.java.otr4j.session.SessionStatus;
@@ -90,6 +92,8 @@ public class XmppConnectionService extends Service {
 	public static final long CARBON_GRACE_PERIOD = 60000L;
 
 	private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
+	
+	private MemorizingTrustManager mMemorizingTrustManager;
 
 	private MessageParser mMessageParser = new MessageParser(this);
 	private PresenceParser mPresenceParser = new PresenceParser(this);
@@ -106,7 +110,6 @@ public class XmppConnectionService extends Service {
 	private int convChangedListenerCount = 0;
 	private OnAccountUpdate mOnAccountUpdate = null;
 	private OnRosterUpdate mOnRosterUpdate = null;
-	private OnTLSExceptionReceived tlsException = null;
 	public OnContactStatusChanged onContactStatusChanged = new OnContactStatusChanged() {
 
 		@Override
@@ -121,11 +124,6 @@ public class XmppConnectionService extends Service {
 		}
 	};
 
-	public void setOnTLSExceptionReceivedListener(
-			OnTLSExceptionReceived listener) {
-		tlsException = listener;
-	}
-
 	private SecureRandom mRandom;
 
 	private ContentObserver contactObserver = new ContentObserver(null) {
@@ -368,6 +366,9 @@ public class XmppConnectionService extends Service {
 		ExceptionHelper.init(getApplicationContext());
 		PRNGFixes.apply();
 		this.mRandom = new SecureRandom();
+		this.mMemorizingTrustManager = new MemorizingTrustManager(getApplicationContext());
+		this.mMemorizingTrustManager.wrapHostnameVerifier(
+				new org.apache.http.conn.ssl.StrictHostnameVerifier());
 		this.databaseBackend = DatabaseBackend
 				.getInstance(getApplicationContext());
 		this.fileBackend = new FileBackend(getApplicationContext());
@@ -467,19 +468,6 @@ public class XmppConnectionService extends Service {
 		connection
 				.setOnUnregisteredIqPacketReceivedListener(this.mIqParser);
 		connection.setOnJinglePacketReceivedListener(this.jingleListener);
-		connection
-				.setOnTLSExceptionReceivedListener(new OnTLSExceptionReceived() {
-
-					@Override
-					public void onTLSExceptionReceived(String fingerprint,
-							Account account) {
-						Log.d(LOGTAG, "tls exception arrived in service");
-						if (tlsException != null) {
-							tlsException.onTLSExceptionReceived(fingerprint,
-									account);
-						}
-					}
-				});
 		connection.setOnBindListener(this.mOnBindListener);
 		return connection;
 	}
@@ -1214,10 +1202,6 @@ public class XmppConnectionService extends Service {
 		this.databaseBackend.updateConversation(conversation);
 	}
 
-	public void removeOnTLSExceptionReceivedListener() {
-		this.tlsException = null;
-	}
-
 	public void reconnectAccount(final Account account, final boolean force) {
 		new Thread(new Runnable() {
 
@@ -1338,6 +1322,10 @@ public class XmppConnectionService extends Service {
 	public SecureRandom getRNG() {
 		return this.mRandom;
 	}
+	
+	public MemorizingTrustManager getMemorizingTrustManager() {
+		return this.mMemorizingTrustManager;
+	}
 
 	public PowerManager getPowerManager() {
 		return this.pm;

src/eu/siacs/conversations/ui/ManageAccountActivity.java 🔗

@@ -59,57 +59,6 @@ public class ManageAccountActivity extends XmppActivity {
 		}
 	};
 
-	protected OnTLSExceptionReceived tlsExceptionReceived = new OnTLSExceptionReceived() {
-
-		@Override
-		public void onTLSExceptionReceived(final String fingerprint,
-				final Account account) {
-			activity.runOnUiThread(new Runnable() {
-
-				@Override
-				public void run() {
-					AlertDialog.Builder builder = new AlertDialog.Builder(
-							activity);
-					builder.setTitle(getString(R.string.account_status_error));
-					builder.setIconAttribute(android.R.attr.alertDialogIcon);
-					View view = (View) getLayoutInflater().inflate(
-							R.layout.cert_warning, null);
-					TextView sha = (TextView) view.findViewById(R.id.sha);
-					TextView hint = (TextView) view.findViewById(R.id.hint);
-					StringBuilder humanReadableSha = new StringBuilder();
-					humanReadableSha.append(fingerprint);
-					for (int i = 2; i < 59; i += 3) {
-						if ((i == 14) || (i == 29) || (i == 44)) {
-							humanReadableSha.insert(i, "\n");
-						} else {
-							humanReadableSha.insert(i, ":");
-						}
-
-					}
-					hint.setText(getString(R.string.untrusted_cert_hint,
-							account.getServer()));
-					sha.setText(humanReadableSha.toString());
-					builder.setView(view);
-					builder.setNegativeButton(
-							getString(R.string.certif_no_trust), null);
-					builder.setPositiveButton(getString(R.string.certif_trust),
-							new OnClickListener() {
-
-								@Override
-								public void onClick(DialogInterface dialog,
-										int which) {
-									account.setSSLCertFingerprint(fingerprint);
-									activity.xmppConnectionService
-											.updateAccount(account);
-								}
-							});
-					builder.create().show();
-				}
-			});
-
-		}
-	};
-
 	@Override
 	protected void onCreate(Bundle savedInstanceState) {
 
@@ -471,7 +420,6 @@ public class ManageAccountActivity extends XmppActivity {
 	protected void onStop() {
 		if (xmppConnectionServiceBound) {
 			xmppConnectionService.removeOnAccountListChangedListener();
-			xmppConnectionService.removeOnTLSExceptionReceivedListener();
 		}
 		super.onStop();
 	}
@@ -479,8 +427,6 @@ public class ManageAccountActivity extends XmppActivity {
 	@Override
 	void onBackendConnected() {
 		xmppConnectionService.setOnAccountListChangedListener(accountChanged);
-		xmppConnectionService
-				.setOnTLSExceptionReceivedListener(tlsExceptionReceived);
 		this.accountList.clear();
 		this.accountList.addAll(xmppConnectionService.getAccounts());
 		accountListViewAdapter.notifyDataSetChanged();

src/eu/siacs/conversations/xmpp/XmppConnection.java 🔗

@@ -21,6 +21,7 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.Map.Entry;
 
+import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
@@ -28,8 +29,12 @@ import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
+import org.bouncycastle.pqc.math.linearalgebra.GoppaCode.MaMaPe;
 import org.xmlpull.v1.XmlPullParserException;
 
+import de.duenndns.ssl.MemorizingTrustManager;
+
+import android.content.Context;
 import android.os.Bundle;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
@@ -97,11 +102,12 @@ public class XmppConnection implements Runnable {
 	private OnIqPacketReceived unregisteredIqListener = null;
 	private OnMessagePacketReceived messageListener = null;
 	private OnStatusChanged statusListener = null;
-	private OnTLSExceptionReceived tlsListener = null;
 	private OnBindListener bindListener = null;
+	private MemorizingTrustManager mMemorizingTrustManager;
 
 	public XmppConnection(Account account, XmppConnectionService service) {
 		this.mRandom = service.getRNG();
+		this.mMemorizingTrustManager = service.getMemorizingTrustManager();
 		this.account = account;
 		this.wakeLock = service.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
 				account.getJid());
@@ -440,67 +446,19 @@ public class XmppConnection implements Runnable {
 		tagReader.readTag();
 		try {
 			SSLContext sc = SSLContext.getInstance("TLS");
-			TrustManagerFactory tmf = TrustManagerFactory
-					.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-			try {
-				tmf.init((KeyStore) null);
-			} catch (KeyStoreException e1) {
-				e1.printStackTrace();
-			}
-
-			TrustManager[] trustManagers = tmf.getTrustManagers();
-			final X509TrustManager origTrustmanager = (X509TrustManager) trustManagers[0];
-
-			TrustManager[] wrappedTrustManagers = new TrustManager[] { new X509TrustManager() {
-
-				@Override
-				public void checkClientTrusted(X509Certificate[] chain,
-						String authType) throws CertificateException {
-					origTrustmanager.checkClientTrusted(chain, authType);
-				}
-
-				@Override
-				public void checkServerTrusted(X509Certificate[] chain,
-						String authType) throws CertificateException {
-					try {
-						origTrustmanager.checkServerTrusted(chain, authType);
-					} catch (CertificateException e) {
-						if (e.getCause() instanceof CertPathValidatorException) {
-							String sha;
-							try {
-								MessageDigest sha1 = MessageDigest
-										.getInstance("SHA1");
-								sha1.update(chain[0].getEncoded());
-								sha = CryptoHelper.bytesToHex(sha1.digest());
-								if (!sha.equals(account.getSSLFingerprint())) {
-									changeStatus(Account.STATUS_TLS_ERROR);
-									if (tlsListener != null) {
-										tlsListener.onTLSExceptionReceived(sha,
-												account);
-									}
-									throw new CertificateException();
-								}
-							} catch (NoSuchAlgorithmException e1) {
-								// TODO Auto-generated catch block
-								e1.printStackTrace();
-							}
-						} else {
-							throw new CertificateException();
-						}
-					}
-				}
-
-				@Override
-				public X509Certificate[] getAcceptedIssuers() {
-					return origTrustmanager.getAcceptedIssuers();
-				}
-
-			} };
-			sc.init(null, wrappedTrustManagers, null);
+			sc.init(null, new X509TrustManager[] { this.mMemorizingTrustManager }, mRandom);
 			SSLSocketFactory factory = sc.getSocketFactory();
+			
+			HostnameVerifier verifier = this.mMemorizingTrustManager.wrapHostnameVerifier(new org.apache.http.conn.ssl.StrictHostnameVerifier());
 			SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket,
 					socket.getInetAddress().getHostAddress(), socket.getPort(),
 					true);
+			
+			if (verifier != null && !verifier.verify(account.getServer(), sslSocket.getSession())) {
+				Log.d(LOGTAG, account.getJid() + ": host mismatch in TLS connection");
+				sslSocket.close();
+				throw new IOException();
+			}
 			tagReader.setInputStream(sslSocket.getInputStream());
 			tagWriter.setOutputStream(sslSocket.getOutputStream());
 			sendStartStream();
@@ -508,10 +466,8 @@ public class XmppConnection implements Runnable {
 			processStream(tagReader.readTag());
 			sslSocket.close();
 		} catch (NoSuchAlgorithmException e1) {
-			// TODO Auto-generated catch block
 			e1.printStackTrace();
 		} catch (KeyManagementException e) {
-			// TODO Auto-generated catch block
 			e.printStackTrace();
 		}
 	}
@@ -844,11 +800,6 @@ public class XmppConnection implements Runnable {
 		this.statusListener = listener;
 	}
 
-	public void setOnTLSExceptionReceivedListener(
-			OnTLSExceptionReceived listener) {
-		this.tlsListener = listener;
-	}
-
 	public void setOnBindListener(OnBindListener listener) {
 		this.bindListener = listener;
 	}