Skip to content

Commit

Permalink
fix: add Let's Encrypt ISRG Root X1 and ISRG Root X2 certificates
Browse files Browse the repository at this point in the history
These root certificates were explicitly added because Android versions
prior to 7.1.1 do not contain them. This is necessary for using a secure
https connection for sites with the new Let's Encrypt certificates.
https://letsencrypt.org/certificates/
  • Loading branch information
Gedsh committed Mar 22, 2024
1 parent 0467a23 commit 89ca5a1
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@

package pan.alexander.tordnscrypt.utils.web

import android.content.Context
import android.os.Build
import kotlinx.coroutines.*
import org.jetbrains.annotations.NotNull
import pan.alexander.tordnscrypt.di.CoroutinesModule
import pan.alexander.tordnscrypt.modules.ModulesStatus
import pan.alexander.tordnscrypt.settings.PathVars
Expand All @@ -44,6 +44,7 @@ import javax.net.ssl.HttpsURLConnection
import javax.net.ssl.SSLSession

class HttpsConnectionManager @Inject constructor(
private val context: Context,
private val pathVars: PathVars,
@Named(CoroutinesModule.DISPATCHER_IO)
private val dispatcherIo: CoroutineDispatcher
Expand Down Expand Up @@ -76,7 +77,6 @@ class HttpsConnectionManager @Inject constructor(
}
}

@NotNull
@Throws(IOException::class)
@Suppress("BlockingMethodInNonBlockingContext")
suspend fun get(url: String, data: Map<String, String>): List<String> =
Expand Down Expand Up @@ -151,7 +151,6 @@ class HttpsConnectionManager @Inject constructor(

}

@NotNull
@Throws(IOException::class)
fun post(url: String, data: Map<String, String>): List<String> {

Expand Down Expand Up @@ -243,7 +242,7 @@ class HttpsConnectionManager @Inject constructor(
}
}

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && url.startsWith("https")) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && url.startsWith("https")) {
tryGetCompatibleTlsSocketFactory()?.let {
httpsURLConnection.sslSocketFactory = it
}
Expand All @@ -253,7 +252,7 @@ class HttpsConnectionManager @Inject constructor(
}

private fun tryGetCompatibleTlsSocketFactory() = try {
TLSSocketFactory()
TLSSocketFactory(context)
} catch (e: Exception) {
loge("HttpsConnectionManager tryGetCompatibleTlsSocketFactory", e)
null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,37 @@

package pan.alexander.tordnscrypt.utils.web;

import android.content.Context;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import pan.alexander.tordnscrypt.R;

public class TLSSocketFactory extends SSLSocketFactory {

private final Context appContext;
private final SSLSocketFactory delegate;

public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
public TLSSocketFactory(Context appContext) throws KeyManagementException, NoSuchAlgorithmException,
CertificateException, KeyStoreException, IOException {
this.appContext = appContext;
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
context.init(null, getTrustManagerFactory().getTrustManagers(), null);
delegate = context.getSocketFactory();
}

Expand Down Expand Up @@ -85,4 +99,34 @@ private Socket enableTLSOnSocket(Socket socket) {
}
return socket;
}

public TrustManagerFactory getTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException {

CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate isgCertificateX1 = cf.generateCertificate(appContext.getResources().openRawResource(R.raw.isrg_root_x1));
Certificate isgCertificateX2 = cf.generateCertificate(appContext.getResources().openRawResource(R.raw.isrg_root_x2));

// Create a KeyStore containing our trusted CAs
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("isrg_root_x1", isgCertificateX1);
keyStore.setCertificateEntry("isrg_root_x2", isgCertificateX2);

//Default TrustManager to get device trusted CA
TrustManagerFactory defaultTmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
defaultTmf.init((KeyStore) null);

X509TrustManager trustManager = (X509TrustManager) defaultTmf.getTrustManagers()[0];
int number = 0;
for (Certificate cert : trustManager.getAcceptedIssuers()) {
keyStore.setCertificateEntry(Integer.toString(number), cert);
number++;
}

// Create a TrustManager that trusts the CAs in our KeyStore
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);

return tmf;
}
}
Binary file added tordnscrypt/src/main/res/raw/isrg_root_x1.der
Binary file not shown.
Binary file added tordnscrypt/src/main/res/raw/isrg_root_x2.der
Binary file not shown.
2 changes: 2 additions & 0 deletions tordnscrypt/src/main/res/xml/network_security_config.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="@raw/isrg_root_x2" />
<certificates src="@raw/isrg_root_x1" />
<certificates src="system" />
</trust-anchors>
</base-config>
Expand Down

0 comments on commit 89ca5a1

Please sign in to comment.