BraveNewPipeLegacy: Integrate TLSSocketFactory and missing CAs

- TLS 1.3 and 1.2 activated only
- TrustManager with CA's for rumble and framatube
This commit is contained in:
evermind 2024-03-01 22:36:22 +01:00
parent fdef0046d9
commit d7518c9d5d
5 changed files with 328 additions and 0 deletions

View file

@ -12,6 +12,7 @@ import org.schabi.newpipe.extractor.downloader.Request;
import org.schabi.newpipe.extractor.downloader.Response;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.util.InfoCache;
import org.schabi.newpipe.util.BraveOkHttpTlsHelper;
import java.io.IOException;
import java.util.Arrays;
@ -51,6 +52,7 @@ public final class DownloaderImpl extends Downloader {
// 16 * 1024 * 1024))
BraveDownloaderImplUtils.addOrRemoveInterceptors(theBuilder);
BraveDownloaderImplUtils.addCookieManager(theBuilder);
BraveOkHttpTlsHelper.enableModernTLS(theBuilder);
this.client = theBuilder.build();
}

View file

@ -0,0 +1,154 @@
package org.schabi.newpipe.util;
import android.content.Context;
import android.os.Build;
import org.schabi.newpipe.App;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
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 java.util.Arrays;
import java.util.List;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
import static org.schabi.newpipe.MainActivity.DEBUG;
public final class BraveOkHttpTlsHelper {
private BraveOkHttpTlsHelper() {
}
/**
* Enable TLS 1.3 and 1.2 on Android Kitkat. This function is mostly taken
* from the documentation of OkHttpClient.Builder.sslSocketFactory(_,_).
*
* The keystore part is inspired by https://stackoverflow.com/a/65395783/4116659
* <p>
* If there is an error, the function will safely fall back to doing nothing
* and printing the error to the console.
* </p>
*
* @param builder The HTTPClient Builder on which TLS is enabled on (will be modified in-place)
* @return the same builder that was supplied. So the method can be chained.
*/
public static OkHttpClient.Builder enableModernTLS(final OkHttpClient.Builder builder) {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
try {
final KeyStore customCAsKeystore = createKeystoreWithCustomCAsAndSystemCAs();
final TrustManagerFactory trustManagerFactory =
getTrustManagerFactory(customCAsKeystore);
final SSLContext context = SSLContext.getInstance("TLS");
context.init(null, trustManagerFactory.getTrustManagers(), null);
final SSLSocketFactory sslSocketFactory =
new BraveTLSSocketFactory(trustManagerFactory);
builder.sslSocketFactory(sslSocketFactory,
(X509TrustManager) trustManagerFactory.getTrustManagers()[0]);
} catch (final KeyManagementException | NoSuchAlgorithmException | KeyStoreException
| IOException | CertificateException e) {
if (DEBUG) {
e.printStackTrace();
}
}
}
return builder;
}
public static TrustManagerFactory getTrustManagerFactory(
final KeyStore keyStore)
throws NoSuchAlgorithmException, KeyStoreException {
final TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// Tell TrustManager to trust the CAs in our KeyStore
trustManagerFactory.init(keyStore);
// only allow one TrustManager
final TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
return trustManagerFactory;
}
/**
* Add our trusted CAs for rumble.com and framatube.org to keystore.
*
* @return custom CA keystore with our added CAs
* @throws KeyStoreException
* @throws CertificateException
* @throws IOException
* @throws NoSuchAlgorithmException
*/
private static KeyStore createKeystoreWithCustomCAsAndSystemCAs()
throws KeyStoreException, CertificateException,
IOException, NoSuchAlgorithmException {
final List<String> rawCertFiles = Arrays.asList("ca_digicert_global_g2", "ca_lets_encrypt");
final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
for (final String rawCertFile : rawCertFiles) {
final Certificate cert = readCertificateFromFile(rawCertFile);
keyStore.setCertificateEntry(rawCertFile, cert);
}
addSystemCAsToKeystore(keyStore);
return keyStore;
}
private static void addSystemCAsToKeystore(
final KeyStore keyStore) throws NoSuchAlgorithmException, KeyStoreException {
// Default TrustManager to get device trusted CA's
final TrustManagerFactory defaultTrustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
defaultTrustManagerFactory.init((KeyStore) null);
final X509TrustManager trustManager =
(X509TrustManager) defaultTrustManagerFactory.getTrustManagers()[0];
int idx = 0;
for (final Certificate cert : trustManager.getAcceptedIssuers()) {
keyStore.setCertificateEntry(Integer.toString(idx), cert);
idx++;
}
}
private static Certificate readCertificateFromFile(
final String rawFile)
throws IOException, CertificateException {
final Context context = App.getApp().getApplicationContext();
final InputStream inputStream = context.getResources().openRawResource(
context.getResources().getIdentifier(rawFile,
"raw", context.getPackageName()));
final byte[] rawBytes = new byte[inputStream.available()];
inputStream.read(rawBytes);
inputStream.close();
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
return cf.generateCertificate(new ByteArrayInputStream(rawBytes));
}
}

View file

@ -0,0 +1,113 @@
package org.schabi.newpipe.util;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import android.util.Log;
/**
* This is an extension of the SSLSocketFactory which enables TLS 1.2 and 1.1.
* Created for usage on Android 4.1-4.4 devices, which haven't enabled those by default.
*/
public class BraveTLSSocketFactory extends SSLSocketFactory {
private static final String TAG = "TLSSocketFactoryCom";
private static BraveTLSSocketFactory instance = null;
private final SSLSocketFactory internalSSLSocketFactory;
public BraveTLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
final SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
internalSSLSocketFactory = context.getSocketFactory();
}
public BraveTLSSocketFactory(
final TrustManagerFactory trustManagerFactory)
throws NoSuchAlgorithmException, KeyManagementException {
final SSLContext context = SSLContext.getInstance("TLS");
context.init(null, trustManagerFactory.getTrustManagers(), null);
internalSSLSocketFactory = context.getSocketFactory();
}
public static BraveTLSSocketFactory getInstance()
throws NoSuchAlgorithmException, KeyManagementException {
if (instance != null) {
return instance;
}
instance = new BraveTLSSocketFactory();
return instance;
}
public static void setAsDefault() {
try {
HttpsURLConnection.setDefaultSSLSocketFactory(getInstance());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
Log.e(TAG, "Unable to setAsDefault", e);
}
}
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
}
@Override
public Socket createSocket(final Socket s, final String host, final int port,
final boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(final String host, final int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(final String host, final int port, final InetAddress localHost,
final int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(
host, port, localHost, localPort));
}
@Override
public Socket createSocket(final InetAddress host, final int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(final InetAddress address, final int port,
final InetAddress localAddress, final int localPort)
throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(
address, port, localAddress, localPort));
}
private Socket enableTLSOnSocket(final Socket socket) {
if (socket instanceof SSLSocket) {
((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1.2", "TLSv1.3"});
}
return socket;
}
}

View file

@ -0,0 +1,28 @@
-----BEGIN CERTIFICATE-----
MIIEyDCCA7CgAwIBAgIQDPW9BitWAvR6uFAsI8zwZjANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
MjAeFw0yMTAzMzAwMDAwMDBaFw0zMTAzMjkyMzU5NTlaMFkxCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMzAxBgNVBAMTKkRpZ2lDZXJ0IEdsb2Jh
bCBHMiBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAMz3EGJPprtjb+2QUlbFbSd7ehJWivH0+dbn4Y+9lavyYEEV
cNsSAPonCrVXOFt9slGTcZUOakGUWzUb+nv6u8W+JDD+Vu/E832X4xT1FE3LpxDy
FuqrIvAxIhFhaZAmunjZlx/jfWardUSVc8is/+9dCopZQ+GssjoP80j812s3wWPc
3kbW20X+fSP9kOhRBx5Ro1/tSUZUfyyIxfQTnJcVPAPooTncaQwywa8WV0yUR0J8
osicfebUTVSvQpmowQTCd5zWSOTOEeAqgJnwQ3DPP3Zr0UxJqyRewg2C/Uaoq2yT
zGJSQnWS+Jr6Xl6ysGHlHx+5fwmY6D36g39HaaECAwEAAaOCAYIwggF+MBIGA1Ud
EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHSFgMBmx9833s+9KTeqAx2+7c0XMB8G
A1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA4GA1UdDwEB/wQEAwIBhjAd
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYIKwYBBQUHAQEEajBoMCQG
CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQAYIKwYBBQUHMAKG
NGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RH
Mi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29t
L0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDA9BgNVHSAENjA0MAsGCWCGSAGG/WwC
ATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgGBmeBDAECAzANBgkqhkiG
9w0BAQsFAAOCAQEAkPFwyyiXaZd8dP3A+iZ7U6utzWX9upwGnIrXWkOH7U1MVl+t
wcW1BSAuWdH/SvWgKtiwla3JLko716f2b4gp/DA/JIS7w7d7kwcsr4drdjPtAFVS
slme5LnQ89/nD/7d+MS5EHKBCQRfz5eeLjJ1js+aWNJXMX43AYGyZm0pGrFmCW3R
bpD0ufovARTFXFZkAdl9h6g4U5+LXUZtXMYnhIHUfoyMo5tS58aI7Dd8KvvwVVo4
chDYABPPTHPbqjc1qCmBaZx2vN4Ye5DUys/vZwP9BFohFrH/6j/f3IL16/RZkiMN
JCqVJUzKoZHm1Lesh3Sz8W2jmdv51b2EQJ8HmA==
-----END CERTIFICATE-----

View file

@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----