After adding the library freeRASP Android (version 8.3.0) to our project, when trying to call a secure endpoint, we get SSLException from Retrofit/OkHttp or KeyStore Exception and our api calls fail. We tried updating to 9.0.0 but that didn't fix the problem.
javax.net.ssl.SSLHandshakeException: Read error: ssl=0xb400007aa9f06888: Failure in SSL library, usually a protocol error
error:04000044:RSA routines:OPENSSL_internal:internal error (external/conscrypt/common/src/jni/main/cpp/conscrypt/native_crypto.cc:732 0x7aa3ed3791:0x00000000)
Tested with the following device
App configuration:
Happen also with all other test devices we have from Android 10 to 14 (Samsung, Pixel, Huawei, OnePlus, Fairphone)
For the record in our project we have the following libraries Retrofit 2.10.0, Moshi 1.15.1, Koin 3.5.3 , OkHttp 4.12.0, BouncyCastle, we have proguard, SSL pinning in the app via .certificatePinner
on the OkHttpClient
and we also have a custom sslSocketFactory
with TLS protocol.
Moreover, we also get the following issue when trying to log in to the app.
Preferred provider doesn't support key:
java.security.InvalidKeyException: Keystore operation failed
at android.security.keystore2.KeyStoreCryptoOperationUtils.getInvalidKeyException(KeyStoreCryptoOperationUtils.java:128)
at android.security.keystore2.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:152)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:360)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:188)
at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2985)
at javax.crypto.Cipher.tryCombinations(Cipher.java:2892)
at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2797)
at javax.crypto.Cipher.chooseProvider(Cipher.java:774)
at javax.crypto.Cipher.init(Cipher.java:1144)
at javax.crypto.Cipher.init(Cipher.java:1085)
at com.android.org.conscrypt.CryptoUpcalls.rsaOpWithPrivateKey(CryptoUpcalls.java:180)
at com.android.org.conscrypt.CryptoUpcalls.rsaSignDigestWithPrivateKey(CryptoUpcalls.java:139)
at com.android.org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(Native Method)
at com.android.org.conscrypt.NativeSsl.readDirectByteBuffer(NativeSsl.java:568)
at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataDirect(ConscryptEngine.java:1095)
at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1079)
at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:876)
at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:747)
at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:712)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:896)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.-$$Nest$mprocessDataFromSocket(Unknown Source:0)
at com.android.org.conscrypt.ConscryptEngineSocket.doHandshake(ConscryptEngineSocket.java:236)
at com.android.org.conscrypt.ConscryptEngineSocket.startHandshake(ConscryptEngineSocket.java:218)
at jD.k.g(Unknown Source:105)
at jD.k.c(Unknown Source:168)
at jD.e.a(Unknown Source:708)
at jD.a.a(Unknown Source:57)
at kD.f.b(Unknown Source:125)
at hD.a.a(Unknown Source:142)
at kD.f.b(Unknown Source:125)
at kD.a.a(Unknown Source:176)
at kD.f.b(Unknown Source:125)
at kD.g.a(Unknown Source:144)
at kD.f.b(Unknown Source:125)
at jD.i.f(Unknown Source:100)
at jD.f.run(Unknown Source:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at java.lang.Thread.run(Thread.java:1012)
Caused by: android.security.KeyStoreException: Incompatible purpose (internal Keystore code: -3 message: system/security/keystore2/src/security_level.rs:310
Caused by:
0: system/security/keystore2/src/enforcements.rs:563: the purpose is not authorized.
1: Error::Km(r#INCOMPATIBLE_PURPOSE)) (public error code: 13 internal Keystore code: -3)
at android.security.KeyStore2.getKeyStoreException(KeyStore2.java:416)
at android.security.KeyStoreSecurityLevel.createOperation(KeyStoreSecurityLevel.java:122)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:355)
... 36 more
Could not find provider for algorithm: RSA/ECB/NoPadding
We have a certificate-based authentication in our app. During log in/enrolment, we create the certificate and store it to the KeyStore. Then, we use the certificate through OkHttp etc...
Removing the RASP library fixes our issue with secure endpoints. Here is the code for initialization:
SecurityDetectionHelper.kt
package com.xxx.lib.security.presentation
import android.content.Context
import com.aheaditec.talsec_security.security.api.Talsec
import com.aheaditec.talsec_security.security.api.TalsecConfig
import com.aheaditec.talsec_security.security.api.ThreatListener
import com.xxx.lib.BuildConfig.ANDROID_SUPPORT_MAIL
import com.xxx.lib.security.presentation.SecurityThreatDetectedError.Reason.DEBUGGER_DETECTED
import com.xxx.lib.security.presentation.SecurityThreatDetectedError.Reason.EMULATOR_DETECTED
import com.xxx.lib.security.presentation.SecurityThreatDetectedError.Reason.HOOK_DETECTED
import com.xxx.lib.security.presentation.SecurityThreatDetectedError.Reason.OBFUSCATION_ISSUES_DETECTED
import com.xxx.lib.security.presentation.SecurityThreatDetectedError.Reason.ROOT_DETECTED
import com.xxx.lib.security.presentation.SecurityThreatDetectedError.Reason.TAMPER_DETECTED
import com.xxx.lib.security.presentation.SecurityThreatDetectedError.Reason.UNTRUSTED_INSTALLATION_SOURCE_DETECTED
class SecurityDetectionHelper(
private val context: Context,
) : ThreatListener.ThreatDetected, SecurityDetectionHelperInterface {
private var onThreatDetected: (error: SecurityThreatDetectedError) -> Unit = {}
private var isEnabled: Boolean = false
private val supportedAlternativeStores = arrayOf(
"dev.firebase.appdistribution",
)
private val expectedSigningCertificateHashBase64 = arrayOf(
// App signing
"xxx",
// Upload key certificate
"xxx",
// Internal test certificate
"xxx",
)
private val config: TalsecConfig
get() = TalsecConfig(
PACKAGE_NAME,
expectedSigningCertificateHashBase64,
ANDROID_SUPPORT_MAIL,
supportedAlternativeStores,
isEnabled,
)
override fun onRootDetected() {
onThreatDetected(SecurityThreatDetectedError(ROOT_DETECTED))
}
override fun onDebuggerDetected() {
onThreatDetected(SecurityThreatDetectedError(DEBUGGER_DETECTED))
}
override fun onEmulatorDetected() {
onThreatDetected(SecurityThreatDetectedError(EMULATOR_DETECTED))
}
override fun onTamperDetected() {
onThreatDetected(SecurityThreatDetectedError(TAMPER_DETECTED))
}
override fun onUntrustedInstallationSourceDetected() {
onThreatDetected(SecurityThreatDetectedError(UNTRUSTED_INSTALLATION_SOURCE_DETECTED))
}
override fun onHookDetected() {
onThreatDetected(SecurityThreatDetectedError(HOOK_DETECTED))
}
override fun onDeviceBindingDetected() {
// do nothing
}
override fun onObfuscationIssuesDetected() {
onThreatDetected(SecurityThreatDetectedError(OBFUSCATION_ISSUES_DETECTED))
}
override fun initSecurityDetection(isEnabled: Boolean, onThreatDetected: (error: SecurityThreatDetectedError) -> Unit) {
this.onThreatDetected = onThreatDetected
this.isEnabled = isEnabled
ThreatListener(this).registerListener(context)
Talsec.start(context, config)
}
companion object {
private const val PACKAGE_NAME = "xxx"
}
}
MainActivity.kt
class MainActivity : BaseActivity(R.layout.xxx_activity_main) {
...
private val securityDetectionHelper: SecurityDetectionHelperInterface by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
securityDetectionHelper.initSecurityDetection(THREAT_DETECTION_ENABLED, ::showAppBlockedDialog)
....
}
...
}
I tried to:
Security.insertProviderAt(BouncyCastleProvider(), 1)
implementation (libs.talsecSecurityCommunity) {
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
exclude group: 'org.bouncycastle'
}
freeRASP identified and resolved a conflict between their device binding detection control and TLS/SSL. They discovered an issue with the AndroidKeyStore, which could lead to device binding detection errors. As a temporary solution, they released a special version of their software with device binding disabled.
Please, use the following dependency:
implementation 'com.aheaditec.talsec.security:TalsecSecurity-Community:9.6.0-NO_DB'
see https://github.com/talsec/Free-RASP-Android/issues/31 for details