CertUtil: Move certificate pinning logic to okhttpclientmodule
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -20,9 +20,11 @@
|
|||||||
package com.aurora.store.data.network
|
package com.aurora.store.data.network
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.util.Base64
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.data.model.Algorithm
|
||||||
import com.aurora.store.data.model.ProxyInfo
|
import com.aurora.store.data.model.ProxyInfo
|
||||||
import com.aurora.store.util.CertUtil
|
|
||||||
import com.aurora.store.util.Preferences
|
import com.aurora.store.util.Preferences
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_ENABLED
|
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_ENABLED
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_INFO
|
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_INFO
|
||||||
@@ -32,12 +34,17 @@ import dagger.Provides
|
|||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.InputStream
|
||||||
import okhttp3.CertificatePinner
|
import okhttp3.CertificatePinner
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import java.net.Authenticator
|
import java.net.Authenticator
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.net.PasswordAuthentication
|
import java.net.PasswordAuthentication
|
||||||
import java.net.Proxy
|
import java.net.Proxy
|
||||||
|
import java.security.MessageDigest
|
||||||
|
import java.security.cert.CertificateFactory
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@@ -47,6 +54,9 @@ object OkHttpClientModule {
|
|||||||
|
|
||||||
private const val TAG = "HttpClient"
|
private const val TAG = "HttpClient"
|
||||||
|
|
||||||
|
private const val CERT_BEGIN = "-----BEGIN CERTIFICATE-----"
|
||||||
|
private const val CERT_END = "-----END CERTIFICATE-----"
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun providesOkHttpClientInstance(certPinner: CertificatePinner, proxy: Proxy?): OkHttpClient {
|
fun providesOkHttpClientInstance(certPinner: CertificatePinner, proxy: Proxy?): OkHttpClient {
|
||||||
@@ -66,7 +76,7 @@ object OkHttpClientModule {
|
|||||||
@Singleton
|
@Singleton
|
||||||
fun providesCertificatePinnerInstance(@ApplicationContext context: Context): CertificatePinner {
|
fun providesCertificatePinnerInstance(@ApplicationContext context: Context): CertificatePinner {
|
||||||
// Google needs special handling, see: https://pki.goog/faq/#faq-27
|
// Google needs special handling, see: https://pki.goog/faq/#faq-27
|
||||||
val googleRootCerts = CertUtil.getGoogleRootCertHashes(context).map { "sha256/$it" }
|
val googleRootCerts = getGoogleRootCertHashes(context).map { "sha256/$it" }
|
||||||
.toTypedArray()
|
.toTypedArray()
|
||||||
|
|
||||||
return CertificatePinner.Builder()
|
return CertificatePinner.Builder()
|
||||||
@@ -108,4 +118,32 @@ object OkHttpClientModule {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getGoogleRootCertHashes(context: Context): List<String> {
|
||||||
|
return try {
|
||||||
|
val certs = getX509Certificates(context.resources.openRawResource(R.raw.google_roots_ca))
|
||||||
|
certs.map {
|
||||||
|
val messageDigest = MessageDigest.getInstance(Algorithm.SHA256.value)
|
||||||
|
messageDigest.update(it.publicKey.encoded)
|
||||||
|
Base64.encodeToString(messageDigest.digest(), Base64.NO_WRAP)
|
||||||
|
}
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
Log.e(TAG, "Failed to get SHA256 certificate hash", exception)
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getX509Certificates(inputStream: InputStream): List<X509Certificate> {
|
||||||
|
val certificateFactory = CertificateFactory.getInstance("X509")
|
||||||
|
val rawCerts = inputStream
|
||||||
|
.bufferedReader()
|
||||||
|
.use { it.readText() }
|
||||||
|
.split(CERT_END)
|
||||||
|
.map { it.substringAfter(CERT_BEGIN).substringBefore(CERT_END).replace("\n", "") }
|
||||||
|
.filterNot { it.isBlank() }
|
||||||
|
val decodedCerts = rawCerts.map { Base64.decode(it, Base64.DEFAULT) }
|
||||||
|
return decodedCerts.map {
|
||||||
|
certificateFactory.generateCertificate(ByteArrayInputStream(it)) as X509Certificate
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,22 +27,15 @@ import android.util.Log
|
|||||||
import com.aurora.extensions.generateX509Certificate
|
import com.aurora.extensions.generateX509Certificate
|
||||||
import com.aurora.extensions.getInstallerPackageNameCompat
|
import com.aurora.extensions.getInstallerPackageNameCompat
|
||||||
import com.aurora.extensions.isPAndAbove
|
import com.aurora.extensions.isPAndAbove
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.data.model.Algorithm
|
import com.aurora.store.data.model.Algorithm
|
||||||
import com.aurora.store.util.PackageUtil.getPackageInfo
|
import com.aurora.store.util.PackageUtil.getPackageInfo
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.cert.CertificateFactory
|
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
|
|
||||||
object CertUtil {
|
object CertUtil {
|
||||||
|
|
||||||
private val TAG = "CertUtil"
|
private val TAG = "CertUtil"
|
||||||
|
|
||||||
private const val CERT_BEGIN = "-----BEGIN CERTIFICATE-----"
|
|
||||||
private const val CERT_END = "-----END CERTIFICATE-----"
|
|
||||||
|
|
||||||
fun isFDroidApp(context: Context, packageName: String): Boolean {
|
fun isFDroidApp(context: Context, packageName: String): Boolean {
|
||||||
return isInstalledByFDroid(context, packageName) || isSignedByFDroid(context, packageName)
|
return isInstalledByFDroid(context, packageName) || isSignedByFDroid(context, packageName)
|
||||||
}
|
}
|
||||||
@@ -69,20 +62,6 @@ object CertUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGoogleRootCertHashes(context: Context): List<String> {
|
|
||||||
return try {
|
|
||||||
val certs = getX509Certificates(context.resources.openRawResource(R.raw.google_roots_ca))
|
|
||||||
certs.map {
|
|
||||||
val messageDigest = MessageDigest.getInstance(Algorithm.SHA256.value)
|
|
||||||
messageDigest.update(it.publicKey.encoded)
|
|
||||||
Base64.encodeToString(messageDigest.digest(), Base64.NO_WRAP)
|
|
||||||
}
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
Log.e(TAG, "Failed to get SHA256 certificate hash", exception)
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSignedByFDroid(context: Context, packageName: String): Boolean {
|
private fun isSignedByFDroid(context: Context, packageName: String): Boolean {
|
||||||
return try {
|
return try {
|
||||||
getX509Certificates(context, packageName).any { cert ->
|
getX509Certificates(context, packageName).any { cert ->
|
||||||
@@ -106,20 +85,6 @@ object CertUtil {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getX509Certificates(inputStream: InputStream): List<X509Certificate> {
|
|
||||||
val certificateFactory = CertificateFactory.getInstance("X509")
|
|
||||||
val rawCerts = inputStream
|
|
||||||
.bufferedReader()
|
|
||||||
.use { it.readText() }
|
|
||||||
.split(CERT_END)
|
|
||||||
.map { it.substringAfter(CERT_BEGIN).substringBefore(CERT_END).replace("\n", "") }
|
|
||||||
.filterNot { it.isBlank() }
|
|
||||||
val decodedCerts = rawCerts.map { Base64.decode(it, Base64.DEFAULT) }
|
|
||||||
return decodedCerts.map {
|
|
||||||
certificateFactory.generateCertificate(ByteArrayInputStream(it)) as X509Certificate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getX509Certificates(context: Context, packageName: String): List<X509Certificate> {
|
private fun getX509Certificates(context: Context, packageName: String): List<X509Certificate> {
|
||||||
return try {
|
return try {
|
||||||
val packageInfo = getPackageInfoWithSignature(context, packageName)
|
val packageInfo = getPackageInfoWithSignature(context, packageName)
|
||||||
|
|||||||
Reference in New Issue
Block a user