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:
parent
ac940b3a12
commit
19ab4a14ce
7
.gitmodules
vendored
7
.gitmodules
vendored
@ -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
|
@ -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'
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
ServiceDB.OpenHelper dbHelper;
|
||||
Settings settings;
|
||||
|
||||
Preference
|
||||
prefResetHints,
|
||||
prefResetCertificates;
|
||||
SwitchPreferenceCompat prefLogToExternalStorage;
|
||||
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);
|
||||
// re-initialize certificate manager
|
||||
App app = (App)getContext().getApplicationContext();
|
||||
app.reinitCertManager();
|
||||
}
|
||||
Snackbar.make(getView(), getResources().getQuantityString(R.plurals.app_settings_reset_trusted_certificates_success, deleted, deleted), Snackbar.LENGTH_LONG).show();
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
9
app/src/main/res/xml/network_security_config.xml
Normal file
9
app/src/main/res/xml/network_security_config.xml
Normal 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>
|
@ -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">
|
||||
|
@ -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
1
cert4android
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c342cbd81185d7f6bd2cd25eea55bd0ecf94c1cc
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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
|
||||
|
@ -10,5 +10,4 @@ include ':app'
|
||||
include ':dav4android'
|
||||
include ':ical4android'
|
||||
include ':vcard4android'
|
||||
|
||||
include ':MemorizingTrustManager'
|
||||
include ':cert4android'
|
||||
|
Loading…
Reference in New Issue
Block a user