From 4f6ef43118d4f7f632d6d6cac06953802cd68e26 Mon Sep 17 00:00:00 2001 From: Marvin W Date: Fri, 16 Aug 2024 20:21:53 +0200 Subject: [PATCH] ProviderInstaller: Update for latest version --- .../security/ProviderInstallerImpl.java | 181 +-------------- .../dynamite/ModuleDescriptor.java | 14 ++ .../ProviderInstallerImpl.java | 218 ++++++++++++++++++ 3 files changed, 240 insertions(+), 173 deletions(-) create mode 100644 play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/providerinstaller/dynamite/ModuleDescriptor.java create mode 100644 play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/providerinstaller/ProviderInstallerImpl.java diff --git a/play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/common/security/ProviderInstallerImpl.java b/play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/common/security/ProviderInstallerImpl.java index 67a65f8605..7ee6701e4b 100644 --- a/play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/common/security/ProviderInstallerImpl.java +++ b/play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/common/security/ProviderInstallerImpl.java @@ -40,185 +40,20 @@ import static android.os.Build.VERSION.SDK_INT; import static com.google.android.gms.security.ProviderInstaller.PROVIDER_NAME; +/** + * This is the old entry point, the new one is at {@link com.google.android.gms.providerinstaller.ProviderInstallerImpl} + */ @Keep public class ProviderInstallerImpl { - private static final String TAG = "GmsProviderInstaller"; - private static final List DISABLED = Collections.unmodifiableList(Arrays.asList("com.bankid.bus")); - - private static final Object lock = new Object(); - private static Provider provider; - - private static String getRealSelfPackageName(Context context) { - String packageName = PackageUtils.packageFromProcessId(context, Process.myPid()); - if (packageName != null && packageName.contains(".")) return packageName; - try { - Method getBasePackageName = Context.class.getDeclaredMethod("getBasePackageName"); - packageName = (String) getBasePackageName.invoke(context); - if (packageName != null) return packageName; - } catch (Exception e) { - - } - if (SDK_INT >= 29) { - return context.getOpPackageName(); - } - Context applicationContext = context.getApplicationContext(); - if (applicationContext != null) { - return applicationContext.getPackageName(); - } - return context.getPackageName(); - } + private static final String TAG = "ProviderInstaller"; @Keep public static void insertProvider(Context context) { - String packageName = getRealSelfPackageName(context); - try { - if (DISABLED.contains(packageName)) { - Log.d(TAG, "Package " + packageName + " is excluded from usage of provider installer"); - return; - } - if (Security.getProvider(PROVIDER_NAME) != null) { - Log.d(TAG, "Provider already inserted in " + packageName); - return; - } - - synchronized (lock) { - initProvider(context, packageName); - - if (provider == null) { - Log.w(TAG, "Failed to initialize Conscrypt"); - return; - } - - int res = Security.insertProviderAt(provider, 1); - if (res == 1) { - Security.setProperty("ssl.SocketFactory.provider", "com.google.android.gms.org.conscrypt.OpenSSLSocketFactoryImpl"); - Security.setProperty("ssl.ServerSocketFactory.provider", "com.google.android.gms.org.conscrypt.OpenSSLServerSocketFactoryImpl"); - - SSLContext sslContext = SSLContext.getInstance("Default"); - SSLContext.setDefault(sslContext); - HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); - - Log.d(TAG, "Installed default security provider " + PROVIDER_NAME); - } else { - throw new SecurityException("Failed to install security provider " + PROVIDER_NAME + ", result: " + res); - } - } - } catch (Throwable e) { - Log.w(TAG, e); - } - } - - public void reportRequestStats(Context context, long a, long b) { - // Ignore stats - } - - private static void initProvider(Context context, String packageName) { - Log.d(TAG, "Initializing provider for " + packageName); - - try { - provider = Conscrypt.newProviderBuilder().setName(PROVIDER_NAME).defaultTlsProtocol("TLSv1.2").build(); - } catch (UnsatisfiedLinkError e) { - Log.w(TAG, "Could not link conscrypt via default loader, trying manual loading"); - - try { - loadConscryptDirect(context, packageName); - provider = Conscrypt.newProviderBuilder().setName(PROVIDER_NAME).defaultTlsProtocol("TLSv1.2").build(); - } catch (Exception e2) { - Log.w(TAG, e2); - } - } - } - - private static void loadConscryptDirect(Context context, String packageName) throws Exception { - ApplicationInfo otherAppInfo = context.getPackageManager().getApplicationInfo(packageName, 0); - - // TODO: Move manual loading into helper function (as it is also used in both maps implementations) - String primaryCpuAbi = (String) ApplicationInfo.class.getField("primaryCpuAbi").get(otherAppInfo); - if (primaryCpuAbi != null) { - String path = "lib/" + primaryCpuAbi + "/libconscrypt_gmscore_jni.so"; - File cacheFile = new File(context.createPackageContext(packageName, 0).getCacheDir().getAbsolutePath() + "/.gmscore/" + path); - cacheFile.getParentFile().mkdirs(); - File apkFile = new File(context.getPackageCodePath()); - if (!cacheFile.exists() || cacheFile.lastModified() < apkFile.lastModified()) { - ZipFile zipFile = new ZipFile(apkFile); - ZipEntry entry = zipFile.getEntry(path); - if (entry != null) { - copyInputStream(zipFile.getInputStream(entry), new FileOutputStream(cacheFile)); - } else { - Log.d(TAG, "Can't load native library: " + path + " does not exist in " + apkFile); - } - } - Log.d(TAG, "Loading conscrypt_gmscore_jni from " + cacheFile.getPath()); - System.load(cacheFile.getAbsolutePath()); - - Class clazz = NativeCrypto.class; - - Field loadError = clazz.getDeclaredField("loadError"); - loadError.setAccessible(true); - loadError.set(null, null); - - Method clinit = clazz.getDeclaredMethod("clinit"); - clinit.setAccessible(true); - - Method get_cipher_names = clazz.getDeclaredMethod("get_cipher_names", String.class); - get_cipher_names.setAccessible(true); - - Method cipherSuiteToJava = clazz.getDeclaredMethod("cipherSuiteToJava", String.class); - cipherSuiteToJava.setAccessible(true); - - Method EVP_has_aes_hardware = clazz.getDeclaredMethod("EVP_has_aes_hardware"); - EVP_has_aes_hardware.setAccessible(true); - - Field f = clazz.getDeclaredField("SUPPORTED_TLS_1_2_CIPHER_SUITES_SET"); - f.setAccessible(true); - - Set SUPPORTED_TLS_1_2_CIPHER_SUITES_SET = (Set) f.get(null); - f = clazz.getDeclaredField("SUPPORTED_LEGACY_CIPHER_SUITES_SET"); - f.setAccessible(true); - - Set SUPPORTED_LEGACY_CIPHER_SUITES_SET = (Set) f.get(null); - f = clazz.getDeclaredField("SUPPORTED_TLS_1_2_CIPHER_SUITES"); - f.setAccessible(true); - - try { - clinit.invoke(null); - - String[] allCipherSuites = (String[]) get_cipher_names.invoke(null, "ALL:!DHE"); - int size = allCipherSuites.length; - - String[] SUPPORTED_TLS_1_2_CIPHER_SUITES = new String[size / 2 + 2]; - for (int i = 0; i < size; i += 2) { - String cipherSuite = (String) cipherSuiteToJava.invoke(null, allCipherSuites[i]); - - SUPPORTED_TLS_1_2_CIPHER_SUITES[i / 2] = cipherSuite; - SUPPORTED_TLS_1_2_CIPHER_SUITES_SET.add(cipherSuite); - - SUPPORTED_LEGACY_CIPHER_SUITES_SET.add(allCipherSuites[i + 1]); - } - SUPPORTED_TLS_1_2_CIPHER_SUITES[size / 2] = "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"; - SUPPORTED_TLS_1_2_CIPHER_SUITES[size / 2 + 1] = "TLS_FALLBACK_SCSV"; - f.set(null, SUPPORTED_TLS_1_2_CIPHER_SUITES); - - f = clazz.getDeclaredField("HAS_AES_HARDWARE"); - f.setAccessible(true); - f.set(null, (int) EVP_has_aes_hardware.invoke(null) == 1); - - } catch (InvocationTargetException inner) { - if (inner.getTargetException() instanceof UnsatisfiedLinkError) { - loadError.set(null, inner.getTargetException()); - } - } - } + com.google.android.gms.providerinstaller.ProviderInstallerImpl.insertProvider(context); } - private static final void copyInputStream(InputStream in, OutputStream out) throws IOException { - byte[] buffer = new byte[1024]; - int len; - - while ((len = in.read(buffer)) >= 0) - out.write(buffer, 0, len); - - in.close(); - out.close(); + @Keep + public void reportRequestStats(Context context, long elapsedRealtimeBeforeLoad, long elapsedRealtimeAfterLoad) { + com.google.android.gms.providerinstaller.ProviderInstallerImpl.reportRequestStats(context, elapsedRealtimeBeforeLoad, elapsedRealtimeAfterLoad); } } diff --git a/play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/providerinstaller/dynamite/ModuleDescriptor.java b/play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/providerinstaller/dynamite/ModuleDescriptor.java new file mode 100644 index 0000000000..1bfcd41f76 --- /dev/null +++ b/play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/providerinstaller/dynamite/ModuleDescriptor.java @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: 2024 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.dynamite.descriptors.com.google.android.gms.providerinstaller.dynamite; + +import androidx.annotation.Keep; + +@Keep +public class ModuleDescriptor { + public static final String MODULE_ID = "com.google.android.gms.providerinstaller.dynamite"; + public static final int MODULE_VERSION = 1; +} diff --git a/play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/providerinstaller/ProviderInstallerImpl.java b/play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/providerinstaller/ProviderInstallerImpl.java new file mode 100644 index 0000000000..175efc6046 --- /dev/null +++ b/play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/providerinstaller/ProviderInstallerImpl.java @@ -0,0 +1,218 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.providerinstaller; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.os.Process; +import android.util.Log; +import androidx.annotation.Keep; +import com.google.android.gms.org.conscrypt.Conscrypt; +import com.google.android.gms.org.conscrypt.NativeCrypto; +import org.microg.gms.common.PackageUtils; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import java.io.*; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.Provider; +import java.security.Security; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import static android.os.Build.VERSION.SDK_INT; +import static com.google.android.gms.security.ProviderInstaller.PROVIDER_NAME; + +@Keep +public class ProviderInstallerImpl { + private static final String TAG = "ProviderInstaller"; + private static final List DISABLED = Collections.unmodifiableList(Arrays.asList("com.bankid.bus")); + + private static final Object lock = new Object(); + private static Provider provider; + + private static String getRealSelfPackageName(Context context) { + String packageName = PackageUtils.packageFromProcessId(context, Process.myPid()); + if (packageName != null && packageName.contains(".")) return packageName; + try { + Method getBasePackageName = Context.class.getDeclaredMethod("getBasePackageName"); + packageName = (String) getBasePackageName.invoke(context); + if (packageName != null) return packageName; + } catch (Exception e) { + + } + if (SDK_INT >= 29) { + return context.getOpPackageName(); + } + Context applicationContext = context.getApplicationContext(); + if (applicationContext != null) { + return applicationContext.getPackageName(); + } + return context.getPackageName(); + } + + @Keep + public static void insertProvider(Context context) { + String packageName = getRealSelfPackageName(context); + try { + if (DISABLED.contains(packageName)) { + Log.d(TAG, "Package " + packageName + " is excluded from usage of provider installer"); + return; + } + if (Security.getProvider(PROVIDER_NAME) != null) { + Log.d(TAG, "Provider already inserted in " + packageName); + return; + } + + synchronized (lock) { + initProvider(context, packageName); + + if (provider == null) { + Log.w(TAG, "Failed to initialize Conscrypt"); + return; + } + + int res = Security.insertProviderAt(provider, 1); + if (res == 1) { + Security.setProperty("ssl.SocketFactory.provider", "com.google.android.gms.org.conscrypt.OpenSSLSocketFactoryImpl"); + Security.setProperty("ssl.ServerSocketFactory.provider", "com.google.android.gms.org.conscrypt.OpenSSLServerSocketFactoryImpl"); + + SSLContext sslContext = SSLContext.getInstance("Default"); + SSLContext.setDefault(sslContext); + HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); + + Log.d(TAG, "Installed default security provider " + PROVIDER_NAME); + } else { + throw new SecurityException("Failed to install security provider " + PROVIDER_NAME + ", result: " + res); + } + } + } catch (Throwable e) { + Log.w(TAG, e); + } + } + + @Keep + public static void reportRequestStats(Context context, long elapsedRealtimeBeforeLoad, long elapsedRealtimeAfterLoad) { + Log.d(TAG, "reportRequestStats: " + elapsedRealtimeBeforeLoad + " " + elapsedRealtimeAfterLoad); + // Ignore stats + } + + private static void initProvider(Context context, String packageName) { + Log.d(TAG, "Initializing provider for " + packageName); + + try { + provider = Conscrypt.newProviderBuilder().setName(PROVIDER_NAME).defaultTlsProtocol("TLSv1.2").build(); + } catch (UnsatisfiedLinkError e) { + Log.w(TAG, "Could not link conscrypt via default loader, trying manual loading"); + + try { + loadConscryptDirect(context, packageName); + provider = Conscrypt.newProviderBuilder().setName(PROVIDER_NAME).defaultTlsProtocol("TLSv1.2").build(); + } catch (Exception e2) { + Log.w(TAG, e2); + } + } + } + + private static void loadConscryptDirect(Context context, String packageName) throws Exception { + ApplicationInfo otherAppInfo = context.getPackageManager().getApplicationInfo(packageName, 0); + + // TODO: Move manual loading into helper function (as it is also used in both maps implementations) + String primaryCpuAbi = (String) ApplicationInfo.class.getField("primaryCpuAbi").get(otherAppInfo); + if (primaryCpuAbi != null) { + String path = "lib/" + primaryCpuAbi + "/libconscrypt_gmscore_jni.so"; + File cacheFile = new File(context.createPackageContext(packageName, 0).getCacheDir().getAbsolutePath() + "/.gmscore/" + path); + cacheFile.getParentFile().mkdirs(); + File apkFile = new File(context.getPackageCodePath()); + if (!cacheFile.exists() || cacheFile.lastModified() < apkFile.lastModified()) { + ZipFile zipFile = new ZipFile(apkFile); + ZipEntry entry = zipFile.getEntry(path); + if (entry != null) { + copyInputStream(zipFile.getInputStream(entry), new FileOutputStream(cacheFile)); + } else { + Log.d(TAG, "Can't load native library: " + path + " does not exist in " + apkFile); + } + } + Log.d(TAG, "Loading conscrypt_gmscore_jni from " + cacheFile.getPath()); + System.load(cacheFile.getAbsolutePath()); + + Class clazz = NativeCrypto.class; + + Field loadError = clazz.getDeclaredField("loadError"); + loadError.setAccessible(true); + loadError.set(null, null); + + Method clinit = clazz.getDeclaredMethod("clinit"); + clinit.setAccessible(true); + + Method get_cipher_names = clazz.getDeclaredMethod("get_cipher_names", String.class); + get_cipher_names.setAccessible(true); + + Method cipherSuiteToJava = clazz.getDeclaredMethod("cipherSuiteToJava", String.class); + cipherSuiteToJava.setAccessible(true); + + Method EVP_has_aes_hardware = clazz.getDeclaredMethod("EVP_has_aes_hardware"); + EVP_has_aes_hardware.setAccessible(true); + + Field f = clazz.getDeclaredField("SUPPORTED_TLS_1_2_CIPHER_SUITES_SET"); + f.setAccessible(true); + + Set SUPPORTED_TLS_1_2_CIPHER_SUITES_SET = (Set) f.get(null); + f = clazz.getDeclaredField("SUPPORTED_LEGACY_CIPHER_SUITES_SET"); + f.setAccessible(true); + + Set SUPPORTED_LEGACY_CIPHER_SUITES_SET = (Set) f.get(null); + f = clazz.getDeclaredField("SUPPORTED_TLS_1_2_CIPHER_SUITES"); + f.setAccessible(true); + + try { + clinit.invoke(null); + + String[] allCipherSuites = (String[]) get_cipher_names.invoke(null, "ALL:!DHE"); + int size = allCipherSuites.length; + + String[] SUPPORTED_TLS_1_2_CIPHER_SUITES = new String[size / 2 + 2]; + for (int i = 0; i < size; i += 2) { + String cipherSuite = (String) cipherSuiteToJava.invoke(null, allCipherSuites[i]); + + SUPPORTED_TLS_1_2_CIPHER_SUITES[i / 2] = cipherSuite; + SUPPORTED_TLS_1_2_CIPHER_SUITES_SET.add(cipherSuite); + + SUPPORTED_LEGACY_CIPHER_SUITES_SET.add(allCipherSuites[i + 1]); + } + SUPPORTED_TLS_1_2_CIPHER_SUITES[size / 2] = "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"; + SUPPORTED_TLS_1_2_CIPHER_SUITES[size / 2 + 1] = "TLS_FALLBACK_SCSV"; + f.set(null, SUPPORTED_TLS_1_2_CIPHER_SUITES); + + f = clazz.getDeclaredField("HAS_AES_HARDWARE"); + f.setAccessible(true); + f.set(null, (int) EVP_has_aes_hardware.invoke(null) == 1); + + } catch (InvocationTargetException inner) { + if (inner.getTargetException() instanceof UnsatisfiedLinkError) { + loadError.set(null, inner.getTargetException()); + } + } + } + } + + private static final void copyInputStream(InputStream in, OutputStream out) throws IOException { + byte[] buffer = new byte[1024]; + int len; + + while ((len = in.read(buffer)) >= 0) + out.write(buffer, 0, len); + + in.close(); + out.close(); + } +}