I have an MDM application for Android phones. I need to take the certificate from the Download folder and install it on Android.
I have written a function to install it (correct me if this is wrong). Now how do I get this certificate (I need it to work with it and also to access it from another app)?
I couldn’t find any example in the documentation on how to use it, and no article either. I wrote a function, but it doesn’t find the private key.
The certificate has the extension “.pfx” (PKCS12). The certificate is created by a certificate authority. The user will enter a password when installing the certificate.
Please note that this is a client certificate and I need a password to work with it
I tried installing it via intent. It crashes with an error. I need MDM to be able to install and select the certificates itself
override fun installCertificate(certificate: File, password: String) {
Log.i(TAG, "[installCertificate] Start install certificate certificate: $certificate | password: $password")
val keyStore = KeyStore.getInstance(KEY_STORE_TYPE)
FileInputStream(certificate).use { fis -> keyStore.load(fis, password.toCharArray()) }
val alias = keyStore.aliases().nextElement()
val key = keyStore.getKey(alias, password.toCharArray()) as PrivateKey
val certChain = keyStore.getCertificateChain(alias)
val dpm = activity.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val adminComponentName = LegacyUtils.getAdminComponentName(activity)
val certData = secretEncryptor.getCertificate(keyStore) as? X509Certificate ?: throw Exception()
val certificateAlias = certData.subjectX500Principal.name
val isOverwrite = dpm.installKeyPair(adminComponentName, key, certChain, alias, 0)
lastAlias = alias
Log.i(TAG,
"[installCertificate] Certificate $certificate installed | alias: $lastAlias | isOverwrite: $isOverwrite")
}
private fun getCertificate(alias: String) {
KeyChain.getPrivateKey(activity, alias)?.let { privateKey ->
KeyChain.getCertificateChain(activity, alias)?.let { certChain ->
val certificate = certChain.firstOrNull()
if (certificate != null) {
Log.i(TAG, "[getCertificate] Сертификат найден | alias: $alias")
// TODO: work with certificate
} else {
Log.e(TAG, "[getCertificate] Certificate not found | alias: $alias")
}
} ?: run {
Log.e(TAG, "[getCertificate] No certificate chain found | alias: $alias")
}
} ?: run {
Log.e(TAG, "[getCertificate] Private key not found | alias: $alias")
}
}
CoroutineScope(Dispatchers.IO).launch {
getCertificate(lastAlias)
}
[checkCertificatesAndInstallIfExist] certificates: [/storage/emulated/0/Download/cert.pfx]
2024-08-06 11:08:25.473 15588-15588 CertificatesManagerImp com.hmdm.launcher I [installCertificate] Start install certificate certificate: /storage/emulated/0/Download/cert.pfx | password: 1234
2024-08-06 11:08:26.375 15588-15588 CertificatesManagerImp com.hmdm.launcher I [installCertificate] Certificate /storage/emulated/0/Download/cert.pfx installed | alias: tq-70b931d7-cb80-4e2e-a617-c4d59435b8f4 | isOverwrite: true
2024-08-06 11:08:27.498 15588-15659 CertificatesManagerImp com.hmdm.launcher E [getCertificate] Private key not found | alias: tq-70b931d7-cb80-4e2e-a617-c4d59435b8f4
I also tried getting a certificate through KeyStore
. All calls return null and an exception in LogCat
private fun getCertificate(alias: String) {
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
val key1 = keyStore.getKey(alias, null)
val key2 = keyStore.getKey(alias, "1234".toCharArray())
val certificate1 = keyStore.getCertificateChain(alias)
val certificate2 = keyStore.getCertificate(alias)
val certificate3 = keyStore.getEntry(alias, null) as? KeyStore.PrivateKeyEntry
Log.i(TAG, "[getCertificate] Certificate $certificate3 | alias: $alias ")
}
2024-08-06 18:01:03.781 6289-6878 KeyStore com.hmdm.launcher W KeyStore exception
android.os.ServiceSpecificException: (code 7)
at android.os.Parcel.createException(Parcel.java:2085)
at android.os.Parcel.readException(Parcel.java:2039)
at android.os.Parcel.readException(Parcel.java:1987)
at android.security.keystore.IKeystoreService$Stub$Proxy.get(IKeystoreService.java:978)
at android.security.KeyStore.get(KeyStore.java:236)
at android.security.KeyStore.get(KeyStore.java:225)
at android.security.keystore.AndroidKeyStoreSpi.engineGetCertificate(AndroidKeyStoreSpi.java:165)
at java.security.KeyStore.getCertificate(KeyStore.java:1120)
at com.hmdm.launcher.certificates.CertificatesManagerImp.getCertificate(CertificatesManagerImp.kt:109)
at com.hmdm.launcher.certificates.CertificatesManagerImp.access$getCertificate(CertificatesManagerImp.kt:29)
at com.hmdm.launcher.certificates.CertificatesManagerImp$getAllCertificates$1.invokeSuspend(CertificatesManagerImp.kt:98)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)