1
0
mirror of https://github.com/etesync/android synced 2024-11-22 16:08:13 +00:00

Use cert4android instead of MemorizingTrustManager

* use cert4android instead of MemorizingTrustManager
* new app setting: distrust system certificates
* add network security config to manifest so that user-installed CAs will be accepted in Android 7 again
* update gradle
This commit is contained in:
Ricki Hirner 2016-09-01 22:03:38 +02:00
parent ac940b3a12
commit 19ab4a14ce
18 changed files with 140 additions and 71 deletions

7
.gitmodules vendored
View File

@ -7,7 +7,6 @@
[submodule "vcard4android"]
path = vcard4android
url = ../vcard4android.git
[submodule "MemorizingTrustManager"]
path = MemorizingTrustManager
url = https://github.com/ge0rg/MemorizingTrustManager
ignore = dirty
[submodule "cert4android"]
path = cert4android
url = ../cert4android.git

@ -1 +0,0 @@
Subproject commit b6a3d558e4b78cd9ad5e8ad5246e44f04c854137

View File

@ -17,15 +17,15 @@ android {
minSdkVersion 14
targetSdkVersion 24
versionCode 112
versionCode 113
buildConfigField "long", "buildTime", System.currentTimeMillis() + "L"
buildConfigField "boolean", "useMTM", "true"
buildConfigField "boolean", "customCerts", "true"
}
productFlavors {
standard {
versionName "1.2.3-ose"
versionName "1.3-ose"
}
}
@ -72,7 +72,7 @@ dependencies {
compile 'com.android.support:preference-v14:24.+'
compile 'com.github.yukuku:ambilwarna:2.0.1'
compile project(':MemorizingTrustManager')
compile project(':cert4android')
compile 'dnsjava:dnsjava:2.1.7'
compile 'org.apache.commons:commons-lang3:3.4'

View File

@ -16,7 +16,7 @@ import java.net.Socket;
import javax.net.ssl.SSLSocket;
import de.duenndns.ssl.MemorizingTrustManager;
import at.bitfire.cert4android.CustomCertManager;
import okhttp3.mockwebserver.MockWebServer;
public class SSLSocketFactoryCompatTest extends InstrumentationTestCase {
@ -26,7 +26,7 @@ public class SSLSocketFactoryCompatTest extends InstrumentationTestCase {
@Override
protected void setUp() throws Exception {
factory = new SSLSocketFactoryCompat(new MemorizingTrustManager(getInstrumentation().getTargetContext().getApplicationContext()));
factory = new SSLSocketFactoryCompat(new CustomCertManager(getInstrumentation().getTargetContext().getApplicationContext(), true));
server.start();
}

View File

@ -53,6 +53,7 @@
android:name=".App"
android:allowBackup="true"
android:fullBackupContent="false"
android:networkSecurityConfig="@xml/network_security_config"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
@ -192,11 +193,6 @@
android:label="@string/debug_info_title">
</activity>
<!-- MemorizingTrustManager -->
<activity
android:name="de.duenndns.ssl.MemorizingActivity"
android:theme="@android:style/Theme.Holo.Light.Dialog.NoActionBar"/>
</application>
</manifest>

View File

@ -34,11 +34,11 @@ import java.util.logging.Logger;
import javax.net.ssl.HostnameVerifier;
import at.bitfire.cert4android.CustomCertManager;
import at.bitfire.davdroid.log.LogcatHandler;
import at.bitfire.davdroid.log.PlainTextFormatter;
import at.bitfire.davdroid.model.ServiceDB;
import at.bitfire.davdroid.model.Settings;
import de.duenndns.ssl.MemorizingTrustManager;
import lombok.Cleanup;
import lombok.Getter;
import okhttp3.internal.tls.OkHostnameVerifier;
@ -46,10 +46,12 @@ import okhttp3.internal.tls.OkHostnameVerifier;
public class App extends Application {
public static final String FLAVOR_GOOGLE_PLAY = "gplay";
public static final String LOG_TO_EXTERNAL_STORAGE = "logToExternalStorage";
public static final String
DISTRUST_SYSTEM_CERTIFICATES = "distrustSystemCerts",
LOG_TO_EXTERNAL_STORAGE = "logToExternalStorage";
@Getter
private static MemorizingTrustManager memorizingTrustManager;
private static CustomCertManager certManager;
@Getter
private static SSLSocketFactoryCompat sslSocketFactoryCompat;
@ -60,21 +62,30 @@ public class App extends Application {
public final static Logger log = Logger.getLogger("davdroid");
static {
at.bitfire.dav4android.Constants.log = Logger.getLogger("davdroid.dav4android");
at.bitfire.cert4android.Constants.log = Logger.getLogger("davdroid.cert4android");
}
@Override
public void onCreate() {
super.onCreate();
// initialize MemorizingTrustManager
memorizingTrustManager = new MemorizingTrustManager(this);
sslSocketFactoryCompat = new SSLSocketFactoryCompat(memorizingTrustManager);
hostnameVerifier = memorizingTrustManager.wrapHostnameVerifier(OkHostnameVerifier.INSTANCE);
// initializer logger
reinitCertManager();
reinitLogger();
}
public void reinitCertManager() {
if (BuildConfig.customCerts) {
if (certManager != null)
certManager.close();
@Cleanup ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(this);
Settings settings = new Settings(dbHelper.getReadableDatabase());
certManager = new CustomCertManager(this, !settings.getBoolean(DISTRUST_SYSTEM_CERTIFICATES, false));
sslSocketFactoryCompat = new SSLSocketFactoryCompat(certManager);
hostnameVerifier = certManager.hostnameVerifier(OkHostnameVerifier.INSTANCE);
}
}
public void reinitLogger() {
// don't use Android default logging, we have our own handlers
log.setUseParentHandlers(false);

View File

@ -69,8 +69,8 @@ public class HttpClient {
OkHttpClient.Builder builder = client.newBuilder();
// use MemorizingTrustManager to manage self-signed certificates
if (App.getSslSocketFactoryCompat() != null)
builder.sslSocketFactory(App.getSslSocketFactoryCompat(), App.getMemorizingTrustManager());
if (App.getSslSocketFactoryCompat() != null && App.getCertManager() != null)
builder.sslSocketFactory(App.getSslSocketFactoryCompat(), App.getCertManager());
if (App.getHostnameVerifier() != null)
builder.hostnameVerifier(App.getHostnameVerifier());

View File

@ -27,7 +27,6 @@ import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import de.duenndns.ssl.MemorizingTrustManager;
import lombok.Cleanup;
public class SSLSocketFactoryCompat extends SSLSocketFactory {
@ -99,10 +98,10 @@ public class SSLSocketFactoryCompat extends SSLSocketFactory {
}
}
public SSLSocketFactoryCompat(@NonNull MemorizingTrustManager mtm) {
public SSLSocketFactoryCompat(@NonNull X509TrustManager trustManager) {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new X509TrustManager[] { mtm }, null);
sslContext.init(null, new X509TrustManager[] { trustManager }, null);
delegate = sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw new AssertionError(); // The system has no TLS. Just give up.

View File

@ -62,6 +62,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import at.bitfire.cert4android.CustomCertManager;
import at.bitfire.davdroid.App;
import at.bitfire.davdroid.DavService;
import at.bitfire.davdroid.R;
@ -110,6 +111,22 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
getLoaderManager().initLoader(0, getIntent().getExtras(), this);
}
@Override
protected void onPause() {
super.onPause();
CustomCertManager certManager = App.getCertManager();
if (certManager != null)
certManager.appInForeground = false;
}
@Override
protected void onResume() {
super.onResume();
CustomCertManager certManager = App.getCertManager();
if (certManager != null)
certManager.appInForeground = true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_account, menu);

View File

@ -16,15 +16,10 @@ import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.support.v7.preference.SwitchPreferenceCompat;
import java.security.KeyStoreException;
import java.util.Enumeration;
import java.util.logging.Level;
import at.bitfire.davdroid.App;
import at.bitfire.davdroid.R;
import at.bitfire.davdroid.model.ServiceDB;
import at.bitfire.davdroid.model.Settings;
import de.duenndns.ssl.MemorizingTrustManager;
import lombok.Cleanup;
public class AppSettingsActivity extends AppCompatActivity {
@ -42,19 +37,43 @@ public class AppSettingsActivity extends AppCompatActivity {
public static class SettingsFragment extends PreferenceFragmentCompat {
Preference prefResetHints,
prefResetCertificates;
SwitchPreferenceCompat prefLogToExternalStorage;
ServiceDB.OpenHelper dbHelper;
Settings settings;
Preference
prefResetHints,
prefResetCertificates;
SwitchPreferenceCompat
prefDistrustSystemCerts,
prefLogToExternalStorage;
@Override
public void onCreate(Bundle savedInstanceState) {
dbHelper = new ServiceDB.OpenHelper(getContext());
settings = new Settings(dbHelper.getReadableDatabase());
super.onCreate(savedInstanceState);
}
@Override
public void onDestroy() {
super.onDestroy();
dbHelper.close();
}
@Override
public void onCreatePreferences(Bundle bundle, String s) {
addPreferencesFromResource(R.xml.settings_app);
prefResetHints = findPreference("reset_hints");
prefResetCertificates = findPreference("reset_certificates");
@Cleanup ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
Settings settings = new Settings(dbHelper.getReadableDatabase());
prefDistrustSystemCerts = (SwitchPreferenceCompat)findPreference("distrust_system_certs");
prefDistrustSystemCerts.setChecked(settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, false));
prefResetCertificates = findPreference("reset_certificates");
if (App.getCertManager() == null)
prefResetCertificates.setVisible(false);
prefLogToExternalStorage = (SwitchPreferenceCompat)findPreference("log_to_external_storage");
prefLogToExternalStorage.setChecked(settings.getBoolean(App.LOG_TO_EXTERNAL_STORAGE, false));
}
@ -63,6 +82,8 @@ public class AppSettingsActivity extends AppCompatActivity {
public boolean onPreferenceTreeClick(Preference preference) {
if (preference == prefResetHints)
resetHints();
else if (preference == prefDistrustSystemCerts)
setDistrustSystemCerts(((SwitchPreferenceCompat)preference).isChecked());
else if (preference == prefResetCertificates)
resetCertificates();
else if (preference == prefLogToExternalStorage)
@ -73,31 +94,25 @@ public class AppSettingsActivity extends AppCompatActivity {
}
private void resetHints() {
@Cleanup ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
Settings settings = new Settings(dbHelper.getWritableDatabase());
settings.remove(StartupDialogFragment.HINT_BATTERY_OPTIMIZATIONS);
settings.remove(StartupDialogFragment.HINT_OPENTASKS_NOT_INSTALLED);
Snackbar.make(getView(), R.string.app_settings_reset_hints_success, Snackbar.LENGTH_LONG).show();
}
private void resetCertificates() {
MemorizingTrustManager mtm = App.getMemorizingTrustManager();
private void setDistrustSystemCerts(boolean distrust) {
settings.putBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, distrust);
int deleted = 0;
Enumeration<String> iterator = mtm.getCertificates();
while (iterator.hasMoreElements())
try {
mtm.deleteCertificate(iterator.nextElement());
deleted++;
} catch (KeyStoreException e) {
App.log.log(Level.SEVERE, "Couldn't distrust certificate", e);
}
Snackbar.make(getView(), getResources().getQuantityString(R.plurals.app_settings_reset_trusted_certificates_success, deleted, deleted), Snackbar.LENGTH_LONG).show();
// re-initialize certificate manager
App app = (App)getContext().getApplicationContext();
app.reinitCertManager();
}
private void resetCertificates() {
App.getCertManager().resetCertificates();
Snackbar.make(getView(), getString(R.string.app_settings_reset_certificates_success), Snackbar.LENGTH_LONG).show();
}
private void setExternalLogging(boolean externalLogging) {
@Cleanup ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
Settings settings = new Settings(dbHelper.getWritableDatabase());
settings.putBoolean(App.LOG_TO_EXTERNAL_STORAGE, externalLogging);
// reinitialize logger of default process

View File

@ -14,6 +14,7 @@ import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import at.bitfire.davdroid.App;
import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.R;
@ -53,6 +54,20 @@ public class LoginActivity extends AppCompatActivity {
}
@Override
protected void onResume() {
super.onResume();
if (App.getCertManager() != null)
App.getCertManager().appInForeground = true;
}
@Override
protected void onPause() {
super.onPause();
if (App.getCertManager() != null)
App.getCertManager().appInForeground = false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_login, menu);

View File

@ -73,12 +73,12 @@
<string name="app_settings_reset_hints_summary">Re-enables hints which have been dismissed previously</string>
<string name="app_settings_reset_hints_success">All hints will be shown again</string>
<string name="app_settings_security">Security</string>
<string name="app_settings_reset_trusted_certificates">Reset trusted certificates</string>
<string name="app_settings_reset_trusted_certificates_summary">Forgets all certificates which have been accepted previously</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="one">Distrusted one certificate</item>
<item quantity="other">Distrusted %d certificates</item>
</plurals>
<string name="app_settings_distrust_system_certs">Distrust system certificates</string>
<string name="app_settings_distrust_system_certs_on">System and user-added CAs won\'t be trusted</string>
<string name="app_settings_distrust_system_certs_off">System and user-added CAs will be trusted</string>
<string name="app_settings_reset_certificates">Reset (un)trusted certificates</string>
<string name="app_settings_reset_certificates_summary">Resets trust of all custom certificates</string>
<string name="app_settings_reset_certificates_success">All custom certificates have been cleared</string>
<string name="app_settings_debug">Debugging</string>
<string name="app_settings_log_to_external_storage">Log to external file</string>
<string name="app_settings_log_to_external_storage_on">Logging to external storage (if available)</string>
@ -261,4 +261,8 @@
</string-array>
<string name="sync_error_unauthorized">User name/password wrong</string>
<!-- cert4android -->
<string name="certificate_notification_connection_security">DAVdroid: Connection security</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroid has encountered an unknown certificate. Do you want to trust it?</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system"/>
<certificates src="user"/>
</trust-anchors>
</base-config>
</network-security-config>

View File

@ -17,10 +17,15 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/app_settings_security">
<SwitchPreferenceCompat
android:key="distrust_system_certs"
android:title="@string/app_settings_distrust_system_certs"
android:summaryOn="@string/app_settings_distrust_system_certs_on"
android:summaryOff="@string/app_settings_distrust_system_certs_off"/>
<Preference
android:key="reset_certificates"
android:title="@string/app_settings_reset_trusted_certificates"
android:summary="@string/app_settings_reset_trusted_certificates_summary"/>
android:title="@string/app_settings_reset_certificates"
android:summary="@string/app_settings_reset_certificates_summary"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/app_settings_debug">

View File

@ -12,7 +12,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'com.android.tools.build:gradle:2.+'
}
}

1
cert4android Submodule

@ -0,0 +1 @@
Subproject commit c342cbd81185d7f6bd2cd25eea55bd0ecf94c1cc

View File

@ -1,6 +1,6 @@
#Sat Apr 09 22:18:11 CEST 2016
#Tue Aug 23 16:42:17 CEST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip

View File

@ -10,5 +10,4 @@ include ':app'
include ':dav4android'
include ':ical4android'
include ':vcard4android'
include ':MemorizingTrustManager'
include ':cert4android'