introduced blind trust before verification mode

Daniel Gultsch created

read more about the concept on https://gultsch.de/trust.html

Change summary

src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java     | 23 
src/main/java/eu/siacs/conversations/crypto/axolotl/FingerprintStatus.java  |  8 
src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java | 10 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java    |  4 
src/main/java/eu/siacs/conversations/ui/SettingsActivity.java               |  1 
src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java              | 15 
src/main/res/values/strings.xml                                             |  3 
src/main/res/xml/preferences.xml                                            |  5 
8 files changed, 62 insertions(+), 7 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java πŸ”—

@@ -112,6 +112,15 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
 		axolotlStore.preVerifyFingerprint(account, account.getJid().toBareJid().toPreppedString(), fingerprint);
 	}
 
+	public boolean hasVerifiedKeys(String name) {
+		for(XmppAxolotlSession session : this.sessions.getAll(new AxolotlAddress(name,0)).values()) {
+			if (session.getTrust().isVerified()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 	private static class AxolotlAddressMap<T> {
 		protected Map<String, Map<Integer, T>> map;
 		protected final Object MAP_LOCK = new Object();
@@ -226,6 +235,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
 		SUCCESS,
 		SUCCESS_VERIFIED,
 		TIMEOUT,
+		SUCCESS_TRUSTED,
 		ERROR
 	}
 
@@ -779,6 +789,8 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
 				report = FetchStatus.SUCCESS;
 			} else if (own.containsValue(FetchStatus.SUCCESS_VERIFIED) || remote.containsValue(FetchStatus.SUCCESS_VERIFIED)) {
 				report = FetchStatus.SUCCESS_VERIFIED;
+			} else if (own.containsValue(FetchStatus.SUCCESS_TRUSTED) || remote.containsValue(FetchStatus.SUCCESS_TRUSTED)) {
+				report = FetchStatus.SUCCESS_TRUSTED;
 			} else if (own.containsValue(FetchStatus.ERROR) || remote.containsValue(FetchStatus.ERROR)) {
 				report = FetchStatus.ERROR;
 			}
@@ -836,8 +848,15 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
 								verifySessionWithPEP(session);
 							} else {
 								FingerprintStatus status = getFingerprintTrust(bundle.getIdentityKey().getFingerprint().replaceAll("\\s",""));
-								boolean verified = status != null && status.isVerified();
-								fetchStatusMap.put(address, verified ? FetchStatus.SUCCESS_VERIFIED : FetchStatus.SUCCESS);
+								FetchStatus fetchStatus;
+								if (status != null && status.isVerified()) {
+									fetchStatus = FetchStatus.SUCCESS_VERIFIED;
+								} else if (status != null && status.isTrusted()) {
+									fetchStatus = FetchStatus.SUCCESS_TRUSTED;
+								} else {
+									fetchStatus = FetchStatus.SUCCESS;
+								}
+								fetchStatusMap.put(address, fetchStatus);
 								finishBuildingSessionsFromPEP(address);
 							}
 						} catch (UntrustedIdentityException | InvalidKeyException e) {

src/main/java/eu/siacs/conversations/crypto/axolotl/FingerprintStatus.java πŸ”—

@@ -63,6 +63,14 @@ public class FingerprintStatus implements Comparable<FingerprintStatus> {
         return status;
     }
 
+    public static FingerprintStatus createActiveTrusted() {
+        final FingerprintStatus status = new FingerprintStatus();
+        status.trust = Trust.TRUSTED;
+        status.active = true;
+        status.lastActivation = System.currentTimeMillis();
+        return status;
+    }
+
     public static FingerprintStatus createActiveVerified(boolean x509) {
         final FingerprintStatus status = new FingerprintStatus();
         status.trust = x509 ? Trust.VERIFIED_X509 : Trust.VERIFIED;

src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java πŸ”—

@@ -21,7 +21,10 @@ import java.util.Set;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.xmpp.jid.InvalidJidException;
+import eu.siacs.conversations.xmpp.jid.Jid;
 
 public class SQLiteAxolotlStore implements AxolotlStore {
 
@@ -191,7 +194,12 @@ public class SQLiteAxolotlStore implements AxolotlStore {
 			String fingerprint = identityKey.getFingerprint().replaceAll("\\s", "");
 			FingerprintStatus status = getFingerprintStatus(fingerprint);
 			if (status == null) {
-				status = FingerprintStatus.createActiveUndecided(); //default for new keys
+				if (mXmppConnectionService.blindTrustBeforeVerification() && !account.getAxolotlService().hasVerifiedKeys(name)) {
+					Log.d(Config.LOGTAG,account.getJid().toBareJid()+": blindly trusted "+fingerprint+" of "+name);
+					status = FingerprintStatus.createActiveTrusted();
+				} else {
+					status = FingerprintStatus.createActiveUndecided();
+				}
 			} else {
 				status = status.toActive();
 			}

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java πŸ”—

@@ -3666,6 +3666,10 @@ public class XmppConnectionService extends Service {
 		return verifiedSomething;
 	}
 
+	public boolean blindTrustBeforeVerification() {
+		return getPreferences().getBoolean(SettingsActivity.BLIND_TRUST_BEFORE_VERIFICATION, true);
+	}
+
 	public interface OnMamPreferencesFetched {
 		void onPreferencesFetched(Element prefs);
 		void onPreferencesFetchFailed();

src/main/java/eu/siacs/conversations/ui/SettingsActivity.java πŸ”—

@@ -39,6 +39,7 @@ public class SettingsActivity extends XmppActivity implements
 	public static final String AWAY_WHEN_SCREEN_IS_OFF = "away_when_screen_off";
 	public static final String TREAT_VIBRATE_AS_SILENT = "treat_vibrate_as_silent";
 	public static final String MANUALLY_CHANGE_PRESENCE = "manually_change_presence";
+	public static final String BLIND_TRUST_BEFORE_VERIFICATION = "btbv";
 
 	public static final int REQUEST_WRITE_LOGS = 0xbf8701;
 	private SettingsFragment mSettingsFragment;

src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java πŸ”—

@@ -73,6 +73,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 		}
 	};
 	private XmppUri mPendingFingerprintVerificationUri = null;
+	private Toast mUseCameraHintToast = null;
 
 	@Override
 	protected void refreshUiReal() {
@@ -114,10 +115,10 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 	@Override
 	public boolean onCreateOptionsMenu(Menu menu) {
 		getMenuInflater().inflate(R.menu.trust_keys, menu);
-		Toast toast = Toast.makeText(this,R.string.use_camera_icon_to_scan_barcode,Toast.LENGTH_LONG);
+		mUseCameraHintToast = Toast.makeText(this,R.string.use_camera_icon_to_scan_barcode,Toast.LENGTH_LONG);
 		ActionBar actionBar = getActionBar();
-		toast.setGravity(Gravity.TOP | Gravity.END, 0 ,actionBar == null ? 0 : actionBar.getHeight());
-		toast.show();
+		mUseCameraHintToast.setGravity(Gravity.TOP | Gravity.END, 0 ,actionBar == null ? 0 : actionBar.getHeight());
+		mUseCameraHintToast.show();
 		return super.onCreateOptionsMenu(menu);
 	}
 
@@ -307,15 +308,22 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 
 	@Override
 	public void onKeyStatusUpdated(final AxolotlService.FetchStatus report) {
+		final boolean keysToTrust = reloadFingerprints();
 		if (report != null) {
 			lastFetchReport = report;
 			runOnUiThread(new Runnable() {
 				@Override
 				public void run() {
+					if (mUseCameraHintToast != null && !keysToTrust) {
+						mUseCameraHintToast.cancel();
+					}
 					switch (report) {
 						case ERROR:
 							Toast.makeText(TrustKeysActivity.this,R.string.error_fetching_omemo_key,Toast.LENGTH_SHORT).show();
 							break;
+						case SUCCESS_TRUSTED:
+							Toast.makeText(TrustKeysActivity.this,R.string.blindly_trusted_omemo_keys,Toast.LENGTH_LONG).show();
+							break;
 						case SUCCESS_VERIFIED:
 							Toast.makeText(TrustKeysActivity.this,
 									Config.X509_VERIFICATION ? R.string.verified_omemo_key_with_certificate : R.string.all_omemo_keys_have_been_verified,
@@ -326,7 +334,6 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 			});
 
 		}
-		boolean keysToTrust = reloadFingerprints();
 		if (keysToTrust || hasPendingKeyFetches() || hasNoOtherTrustedKeys()) {
 			refreshUi();
 		} else {

src/main/res/values/strings.xml πŸ”—

@@ -710,4 +710,7 @@
 	<string name="share_as_barcode">Share as Barcode</string>
 	<string name="share_as_uri">Share as XMPP URI</string>
 	<string name="share_as_http">Share as HTTP link</string>
+	<string name="pref_blind_trust_before_verification">Blind Trust Before Verification</string>
+	<string name="pref_blind_trust_before_verification_summary">Automatically trust all new devices from contacts that haven’t been verified before.</string>
+	<string name="blindly_trusted_omemo_keys">Blindly trusted OMEMO keys</string>
 </resources>

src/main/res/xml/preferences.xml πŸ”—

@@ -164,6 +164,11 @@
             android:summary="@string/pref_expert_options_summary"
             android:title="@string/pref_expert_options">
             <PreferenceCategory android:title="@string/pref_security_settings">
+                <CheckBoxPreference
+                    android:defaultValue="true"
+                    android:key="btbv"
+                    android:title="@string/pref_blind_trust_before_verification"
+                    android:summary="@string/pref_blind_trust_before_verification_summary"/>
                 <CheckBoxPreference
                     android:defaultValue="false"
                     android:key="dont_save_encrypted"