From edbd288ae875e08ac70e50b3e306f29415ae6b9f Mon Sep 17 00:00:00 2001 From: Andy Valdez Date: Wed, 28 Aug 2024 16:15:25 -0400 Subject: [PATCH 1/3] Attempt to load the new letsencrypt x1 and x2 certs. --- .../com/simperium/android/AndroidClient.java | 51 ++++++++++++++++++- Simperium/src/main/res/raw/isrgrootx1.pem | 31 +++++++++++ Simperium/src/main/res/raw/isrgrootx2.pem | 14 +++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 Simperium/src/main/res/raw/isrgrootx1.pem create mode 100644 Simperium/src/main/res/raw/isrgrootx2.pem diff --git a/Simperium/src/main/java/com/simperium/android/AndroidClient.java b/Simperium/src/main/java/com/simperium/android/AndroidClient.java index 7b09dc47..e1c60f62 100644 --- a/Simperium/src/main/java/com/simperium/android/AndroidClient.java +++ b/Simperium/src/main/java/com/simperium/android/AndroidClient.java @@ -10,14 +10,23 @@ import org.thoughtcrime.ssl.pinning.SystemKeyStore; import com.simperium.BuildConfig; +import com.simperium.R; import com.simperium.Version; import com.simperium.client.ClientFactory; import com.simperium.util.Uuid; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import android.util.Log; @@ -73,7 +82,11 @@ public AndroidClient(Context context){ mSessionId = String.format("%s-%s", Version.LIBRARY_NAME, sessionToken); - TrustManager[] trustManagers = new TrustManager[] { buildPinnedTrustManager(context) }; + TrustManager[] trustManagers = new TrustManager[] { + buildPinnedTrustManager(context), + loadCertificate(context, R.raw.isrgrootx1), + loadCertificate(context, R.raw.isrgrootx2) + }; mHttpClient.getSSLSocketMiddleware().setTrustManagers(trustManagers); } @@ -84,6 +97,42 @@ public static TrustManager buildPinnedTrustManager(Context context) { new String[] { BuildConfig.SIMPERIUM_COM_SPKI }, 0); } + private static TrustManager loadCertificate(Context context, final int resource) { + try { + // Load PEM file + InputStream inputStream = context.getResources().openRawResource(resource); + // Create CertificateFactory Instance + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + + // Generate the keystore instance. + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, null); + + // Iterate over the certificates in the pem file and add them to the keystore + while (inputStream.available() > 0) { + java.security.cert.Certificate cert = certificateFactory.generateCertificate(inputStream); + String alias = cert.toString(); + keyStore.setCertificateEntry(alias, cert); + } + + // Create a TrustedManagerFactory instance + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + + TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + return trustManagers[0]; + } catch (IOException e) { + Log.e(TAG, "Problem opening pem cert file", e); + } catch (CertificateException e) { + Log.e(TAG, "Problem getting instance of CertificateFactory", e); + } catch (KeyStoreException e) { + Log.e(TAG, "Problem getting a keystore instance", e); + } catch (NoSuchAlgorithmException e) { + Log.e(TAG, "Problem loading the keystore", e); + } + return null; + } + public static SharedPreferences sharedPreferences(Context context){ return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); } diff --git a/Simperium/src/main/res/raw/isrgrootx1.pem b/Simperium/src/main/res/raw/isrgrootx1.pem new file mode 100644 index 00000000..b85c8037 --- /dev/null +++ b/Simperium/src/main/res/raw/isrgrootx1.pem @@ -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----- diff --git a/Simperium/src/main/res/raw/isrgrootx2.pem b/Simperium/src/main/res/raw/isrgrootx2.pem new file mode 100644 index 00000000..7d903edc --- /dev/null +++ b/Simperium/src/main/res/raw/isrgrootx2.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- From ca2f3981ca397fc2488bfcc40b1a9c9a3fef4e33 Mon Sep 17 00:00:00 2001 From: Andy Valdez Date: Wed, 28 Aug 2024 17:10:05 -0400 Subject: [PATCH 2/3] First change didn't work. Take 2. --- .../com/simperium/android/AndroidClient.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Simperium/src/main/java/com/simperium/android/AndroidClient.java b/Simperium/src/main/java/com/simperium/android/AndroidClient.java index e1c60f62..e86adf50 100644 --- a/Simperium/src/main/java/com/simperium/android/AndroidClient.java +++ b/Simperium/src/main/java/com/simperium/android/AndroidClient.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.io.InputStream; +import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -25,6 +26,8 @@ import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; + +import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; @@ -82,11 +85,21 @@ public AndroidClient(Context context){ mSessionId = String.format("%s-%s", Version.LIBRARY_NAME, sessionToken); - TrustManager[] trustManagers = new TrustManager[] { - buildPinnedTrustManager(context), - loadCertificate(context, R.raw.isrgrootx1), - loadCertificate(context, R.raw.isrgrootx2) - }; + try { + final SSLContext sslContext = SSLContext.getInstance("TLS"); + final TrustManager[] customTrustManagers = new TrustManager[]{ + loadCertificate(context, R.raw.isrgrootx1), + loadCertificate(context, R.raw.isrgrootx2) + }; + sslContext.init(null, customTrustManagers, null); + mHttpClient.getSSLSocketMiddleware().setSSLContext(sslContext); + } catch (NoSuchAlgorithmException e) { + Log.e(TAG, "Problem getting instance of SSLContext"); + } catch (KeyManagementException e) { + Log.e(TAG, "Problem trying to init SSLContext"); + } + + TrustManager[] trustManagers = new TrustManager[] { buildPinnedTrustManager(context) }; mHttpClient.getSSLSocketMiddleware().setTrustManagers(trustManagers); } From 6690beb1dd6a31d06426dd56b19a3f41359d1ee5 Mon Sep 17 00:00:00 2001 From: Andy Valdez Date: Wed, 28 Aug 2024 17:36:33 -0400 Subject: [PATCH 3/3] Gate this change to versions less than 24, which are the affected version. --- .../com/simperium/android/AndroidClient.java | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Simperium/src/main/java/com/simperium/android/AndroidClient.java b/Simperium/src/main/java/com/simperium/android/AndroidClient.java index e86adf50..5180db05 100644 --- a/Simperium/src/main/java/com/simperium/android/AndroidClient.java +++ b/Simperium/src/main/java/com/simperium/android/AndroidClient.java @@ -31,6 +31,7 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; +import android.os.Build; import android.util.Log; /** @@ -85,18 +86,23 @@ public AndroidClient(Context context){ mSessionId = String.format("%s-%s", Version.LIBRARY_NAME, sessionToken); - try { - final SSLContext sslContext = SSLContext.getInstance("TLS"); - final TrustManager[] customTrustManagers = new TrustManager[]{ - loadCertificate(context, R.raw.isrgrootx1), - loadCertificate(context, R.raw.isrgrootx2) - }; - sslContext.init(null, customTrustManagers, null); - mHttpClient.getSSLSocketMiddleware().setSSLContext(sslContext); - } catch (NoSuchAlgorithmException e) { - Log.e(TAG, "Problem getting instance of SSLContext"); - } catch (KeyManagementException e) { - Log.e(TAG, "Problem trying to init SSLContext"); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) { + // This code manually adds two trusted certificates for SSL. + // See this for more info: https://letsencrypt.org/2023/07/10/cross-sign-expiration. + // I got the certificates directly from letsencrypt here: https://letsencrypt.org/certificates/. + try { + final SSLContext sslContext = SSLContext.getInstance("TLS"); + final TrustManager[] customTrustManagers = new TrustManager[]{ + loadCertificate(context, R.raw.isrgrootx1), + loadCertificate(context, R.raw.isrgrootx2) + }; + sslContext.init(null, customTrustManagers, null); + mHttpClient.getSSLSocketMiddleware().setSSLContext(sslContext); + } catch (NoSuchAlgorithmException e) { + Log.e(TAG, "Problem getting instance of SSLContext"); + } catch (KeyManagementException e) { + Log.e(TAG, "Problem trying to init SSLContext"); + } } TrustManager[] trustManagers = new TrustManager[] { buildPinnedTrustManager(context) };