Merge pull request #2671 from nextcloud/fix-trust-manager

Split different exception scopes / Use own OkHttp client for coil
This commit is contained in:
Marcel Hibbe 2023-03-14 19:59:09 +01:00 committed by GitHub
commit 4c64503cc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 73 additions and 62 deletions

View File

@ -36,7 +36,7 @@ import com.nextcloud.talk.events.CertificateEvent
import com.nextcloud.talk.ui.theme.ViewThemeUtils
import com.nextcloud.talk.utils.SecurityUtils
import com.nextcloud.talk.utils.preferences.AppPreferences
import com.nextcloud.talk.utils.ssl.MagicTrustManager
import com.nextcloud.talk.utils.ssl.TrustManager
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@ -81,7 +81,7 @@ open class BaseActivity : AppCompatActivity() {
fun showCertificateDialog(
cert: X509Certificate,
magicTrustManager: MagicTrustManager,
trustManager: TrustManager,
sslErrorHandler: SslErrorHandler?
) {
val formatter = DateFormat.getDateInstance(DateFormat.LONG)
@ -121,7 +121,7 @@ open class BaseActivity : AppCompatActivity() {
.setTitle(R.string.nc_certificate_dialog_title)
.setMessage(dialogText)
.setPositiveButton(R.string.nc_yes) { _, _ ->
magicTrustManager.addCertInTrustStore(cert)
trustManager.addCertInTrustStore(cert)
sslErrorHandler?.proceed()
}
.setNegativeButton(R.string.nc_no) { _, _ ->

View File

@ -255,6 +255,8 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
imageLoaderBuilder.logger(DebugLogger())
}
imageLoaderBuilder.okHttpClient(okHttpClient)
return imageLoaderBuilder.build()
}

View File

@ -52,7 +52,7 @@ public class ReadFilesystemOperation {
okHttpClientBuilder.followRedirects(false);
okHttpClientBuilder.followSslRedirects(false);
okHttpClientBuilder.authenticator(
new RestModule.MagicAuthenticator(
new RestModule.HttpAuthenticator(
ApiUtils.getCredentials(
currentUser.getUsername(),
currentUser.getToken()

View File

@ -40,7 +40,7 @@ import com.nextcloud.talk.components.filebrowser.models.properties.NCPreview
import com.nextcloud.talk.components.filebrowser.models.properties.OCFavorite
import com.nextcloud.talk.components.filebrowser.models.properties.OCId
import com.nextcloud.talk.components.filebrowser.models.properties.OCSize
import com.nextcloud.talk.dagger.modules.RestModule.MagicAuthenticator
import com.nextcloud.talk.dagger.modules.RestModule.HttpAuthenticator
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem
import com.nextcloud.talk.utils.ApiUtils
@ -61,7 +61,7 @@ class ReadFolderListingOperation(okHttpClient: OkHttpClient, currentUser: User,
okHttpClientBuilder.followRedirects(false)
okHttpClientBuilder.followSslRedirects(false)
okHttpClientBuilder.authenticator(
MagicAuthenticator(
HttpAuthenticator(
ApiUtils.getCredentials(
currentUser.username,
currentUser.token

View File

@ -64,7 +64,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ORIGINAL_PROTOCOL
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USERNAME
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
import com.nextcloud.talk.utils.ssl.MagicTrustManager
import com.nextcloud.talk.utils.ssl.TrustManager
import de.cotech.hw.fido.WebViewFidoBridge
import io.reactivex.disposables.Disposable
import org.greenrobot.eventbus.EventBus
@ -88,7 +88,7 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
lateinit var userManager: UserManager
@Inject
lateinit var magicTrustManager: MagicTrustManager
lateinit var trustManager: TrustManager
@Inject
lateinit var eventBus: EventBus
@ -288,10 +288,10 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
handler.cancel()
} else {
try {
magicTrustManager.checkServerTrusted(arrayOf(cert), "generic")
trustManager.checkServerTrusted(arrayOf(cert), "generic")
handler.proceed()
} catch (exception: CertificateException) {
eventBus.post(CertificateEvent(cert, magicTrustManager, handler))
eventBus.post(CertificateEvent(cert, trustManager, handler))
}
}
} catch (exception: Exception) {

View File

@ -32,9 +32,9 @@ import com.nextcloud.talk.users.UserManager;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.LoggingUtils;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import com.nextcloud.talk.utils.ssl.MagicKeyManager;
import com.nextcloud.talk.utils.ssl.MagicTrustManager;
import com.nextcloud.talk.utils.ssl.KeyManager;
import com.nextcloud.talk.utils.ssl.SSLSocketFactoryCompat;
import com.nextcloud.talk.utils.ssl.TrustManager;
import java.io.IOException;
import java.net.CookieManager;
@ -121,13 +121,13 @@ public class RestModule {
@Singleton
@Provides
MagicTrustManager provideMagicTrustManager() {
return new MagicTrustManager();
TrustManager provideTrustManager() {
return new TrustManager();
}
@Singleton
@Provides
MagicKeyManager provideKeyManager(AppPreferences appPreferences, UserManager userManager) {
KeyManager provideKeyManager(AppPreferences appPreferences, UserManager userManager) {
KeyStore keyStore = null;
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
@ -135,7 +135,7 @@ public class RestModule {
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, null);
X509KeyManager origKm = (X509KeyManager) kmf.getKeyManagers()[0];
return new MagicKeyManager(origKm, userManager, appPreferences);
return new KeyManager(origKm, userManager, appPreferences);
} catch (KeyStoreException e) {
Log.e(TAG, "KeyStoreException " + e.getLocalizedMessage());
} catch (CertificateException e) {
@ -153,9 +153,9 @@ public class RestModule {
@Singleton
@Provides
SSLSocketFactoryCompat provideSslSocketFactoryCompat(MagicKeyManager keyManager, MagicTrustManager
magicTrustManager) {
return new SSLSocketFactoryCompat(keyManager, magicTrustManager);
SSLSocketFactoryCompat provideSslSocketFactoryCompat(KeyManager keyManager, TrustManager
trustManager) {
return new SSLSocketFactoryCompat(keyManager, trustManager);
}
@Singleton
@ -184,7 +184,7 @@ public class RestModule {
@Singleton
@Provides
OkHttpClient provideHttpClient(Proxy proxy, AppPreferences appPreferences,
MagicTrustManager magicTrustManager,
TrustManager trustManager,
SSLSocketFactoryCompat sslSocketFactoryCompat, Cache cache,
CookieManager cookieManager, Dispatcher dispatcher) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
@ -198,9 +198,9 @@ public class RestModule {
httpClient.cache(cache);
// Trust own CA and all self-signed certs
httpClient.sslSocketFactory(sslSocketFactoryCompat, magicTrustManager);
httpClient.sslSocketFactory(sslSocketFactoryCompat, trustManager);
httpClient.retryOnConnectionFailure(true);
httpClient.hostnameVerifier(magicTrustManager.getHostnameVerifier(OkHostnameVerifier.INSTANCE));
httpClient.hostnameVerifier(trustManager.getHostnameVerifier(OkHostnameVerifier.INSTANCE));
httpClient.dispatcher(dispatcher);
if (!Proxy.NO_PROXY.equals(proxy)) {
@ -209,7 +209,7 @@ public class RestModule {
if (appPreferences.getProxyCredentials() &&
!TextUtils.isEmpty(appPreferences.getProxyUsername()) &&
!TextUtils.isEmpty(appPreferences.getProxyPassword())) {
httpClient.proxyAuthenticator(new MagicAuthenticator(Credentials.basic(
httpClient.proxyAuthenticator(new HttpAuthenticator(Credentials.basic(
appPreferences.getProxyUsername(),
appPreferences.getProxyPassword()), "Proxy-Authorization"));
}
@ -253,12 +253,12 @@ public class RestModule {
}
}
public static class MagicAuthenticator implements Authenticator {
public static class HttpAuthenticator implements Authenticator {
private String credentials;
private String authenticatorType;
public MagicAuthenticator(@NonNull String credentials, @NonNull String authenticatorType) {
public HttpAuthenticator(@NonNull String credentials, @NonNull String authenticatorType) {
this.credentials = credentials;
this.authenticatorType = authenticatorType;
}

View File

@ -21,21 +21,23 @@
package com.nextcloud.talk.events;
import android.webkit.SslErrorHandler;
import androidx.annotation.Nullable;
import com.nextcloud.talk.utils.ssl.MagicTrustManager;
import com.nextcloud.talk.utils.ssl.TrustManager;
import java.security.cert.X509Certificate;
import androidx.annotation.Nullable;
public class CertificateEvent {
private final X509Certificate x509Certificate;
private final MagicTrustManager magicTrustManager;
private final TrustManager trustManager;
@Nullable
private final SslErrorHandler sslErrorHandler;
public CertificateEvent(X509Certificate x509Certificate, MagicTrustManager magicTrustManager,
public CertificateEvent(X509Certificate x509Certificate, TrustManager trustManager,
@Nullable SslErrorHandler sslErrorHandler) {
this.x509Certificate = x509Certificate;
this.magicTrustManager = magicTrustManager;
this.trustManager = trustManager;
this.sslErrorHandler = sslErrorHandler;
}
@ -48,7 +50,7 @@ public class CertificateEvent {
return x509Certificate;
}
public MagicTrustManager getMagicTrustManager() {
return magicTrustManager;
public TrustManager getMagicTrustManager() {
return trustManager;
}
}

View File

@ -295,7 +295,7 @@ class ChunkedFileUploader(
// okHttpClientBuilder.readTimeout(Duration.ofMinutes(30)) // TODO set timeout
okHttpClientBuilder.protocols(listOf(Protocol.HTTP_1_1))
okHttpClientBuilder.authenticator(
RestModule.MagicAuthenticator(
RestModule.HttpAuthenticator(
ApiUtils.getCredentials(
currentUser.username,
currentUser.token

View File

@ -45,15 +45,15 @@ import javax.net.ssl.X509KeyManager;
import androidx.annotation.Nullable;
public class MagicKeyManager implements X509KeyManager {
private static final String TAG = "MagicKeyManager";
public class KeyManager implements X509KeyManager {
private static final String TAG = "KeyManager";
private final X509KeyManager keyManager;
private UserManager userManager;
private AppPreferences appPreferences;
private Context context;
public MagicKeyManager(X509KeyManager keyManager, UserManager userManager, AppPreferences appPreferences) {
public KeyManager(X509KeyManager keyManager, UserManager userManager, AppPreferences appPreferences) {
this.keyManager = keyManager;
this.userManager = userManager;
this.appPreferences = appPreferences;

View File

@ -38,29 +38,36 @@ import java.security.KeyStoreException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class MagicTrustManager implements X509TrustManager {
private static final String TAG = "MagicTrustManager";
public class TrustManager implements X509TrustManager {
private static final String TAG = "TrustManager";
private File keystoreFile;
private X509TrustManager systemTrustManager = null;
private KeyStore trustedKeyStore = null;
public MagicTrustManager() {
keystoreFile = new File(NextcloudTalkApplication.Companion.getSharedApplication().getDir("CertsKeystore",
Context.MODE_PRIVATE), "keystore.bks");
try (FileInputStream fileInputStream = new FileInputStream(keystoreFile)) {
public TrustManager() {
keystoreFile = new File(NextcloudTalkApplication.Companion.getSharedApplication()
.getDir("CertsKeystore", Context.MODE_PRIVATE),
"keystore.bks");
try {
trustedKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
} catch (KeyStoreException e) {
Log.e(TAG, "Trusted key store can't be created.", e);
}
if (keystoreFile.exists()) {
try (FileInputStream fileInputStream = new FileInputStream(keystoreFile)) {
trustedKeyStore.load(fileInputStream, null);
} catch (Exception exception) {
Log.e(TAG, "Error during opening the trusted key store.", exception);
}
} else {
try {
trustedKeyStore.load(null, null);
} catch (Exception e) {
@ -75,7 +82,7 @@ public class MagicTrustManager implements X509TrustManager {
trustManagerFactory.init((KeyStore) null);
for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
for (javax.net.ssl.TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
if (trustManager instanceof X509TrustManager) {
systemTrustManager = (X509TrustManager) trustManager;
break;
@ -88,8 +95,8 @@ public class MagicTrustManager implements X509TrustManager {
}
public HostnameVerifier getHostnameVerifier(HostnameVerifier defaultHostNameVerifier) {
return new MagicHostnameVerifier(defaultHostNameVerifier);
public javax.net.ssl.HostnameVerifier getHostnameVerifier(javax.net.ssl.HostnameVerifier defaultHostNameVerifier) {
return new HostnameVerifier(defaultHostNameVerifier);
}
private boolean isCertInTrustStore(X509Certificate[] x509Certificates, String s) {
@ -99,15 +106,15 @@ public class MagicTrustManager implements X509TrustManager {
systemTrustManager.checkServerTrusted(x509Certificates, s);
return true;
} catch (CertificateException e) {
if (!isCertInMagicTrustStore(x509Certificate)) {
if (!isCertInTrustStore(x509Certificate)) {
EventBus.getDefault().post(new CertificateEvent(x509Certificate, this,
null));
long startTime = System.currentTimeMillis();
while (!isCertInMagicTrustStore(x509Certificate) && System.currentTimeMillis() <=
while (!isCertInTrustStore(x509Certificate) && System.currentTimeMillis() <=
startTime + 15000) {
//do nothing
}
return isCertInMagicTrustStore(x509Certificate);
return isCertInTrustStore(x509Certificate);
} else {
return true;
}
@ -117,7 +124,7 @@ public class MagicTrustManager implements X509TrustManager {
return false;
}
private boolean isCertInMagicTrustStore(X509Certificate x509Certificate) {
private boolean isCertInTrustStore(X509Certificate x509Certificate) {
if (trustedKeyStore != null) {
try {
if (trustedKeyStore.getCertificateAlias(x509Certificate) != null) {
@ -159,11 +166,11 @@ public class MagicTrustManager implements X509TrustManager {
return systemTrustManager.getAcceptedIssuers();
}
private class MagicHostnameVerifier implements HostnameVerifier {
private static final String TAG = "MagicHostnameVerifier";
private HostnameVerifier defaultHostNameVerifier;
private class HostnameVerifier implements javax.net.ssl.HostnameVerifier {
private static final String TAG = "HostnameVerifier";
private javax.net.ssl.HostnameVerifier defaultHostNameVerifier;
private MagicHostnameVerifier(HostnameVerifier defaultHostNameVerifier) {
private HostnameVerifier(javax.net.ssl.HostnameVerifier defaultHostNameVerifier) {
this.defaultHostNameVerifier = defaultHostNameVerifier;
}

View File

@ -452,7 +452,7 @@ class WebSocketInstance internal constructor(
}
companion object {
private const val TAG = "MagicWebSocketInstance"
private const val TAG = "WebSocketInstance"
private const val NORMAL_CLOSURE = 1000
}
}