Last active
November 17, 2020 09:53
-
-
Save Nimrodda/4d559bb39c07a3b4bfd57e26eb1db0de to your computer and use it in GitHub Desktop.
App signing verification
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object SecurityManager { | |
fun isPackageNameAllowed( | |
context: Context, | |
packageName: String, | |
allowedApps: Map<String, String> | |
): Boolean { | |
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { | |
isPackageNameAllowedApi27Down(context, packageName, allowedApps) | |
} else { | |
isPackageNameAllowedApi28Up(context, packageName, allowedApps) | |
} | |
} | |
@Suppress("DEPRECATION") | |
@SuppressLint("PackageManagerGetSignatures") | |
private fun isPackageNameAllowedApi27Down( | |
context: Context, | |
packageName: String, | |
allowedApps: Map<String, String> | |
): Boolean { | |
return try { | |
val packageInfo = context.packageManager.getPackageInfo( | |
packageName, | |
PackageManager.GET_SIGNATURES | |
) | |
isPackageNameAllowed(packageInfo.signatures, packageName, allowedApps) | |
} catch (e: Exception) { | |
false | |
} | |
} | |
@TargetApi(28) | |
private fun isPackageNameAllowedApi28Up( | |
context: Context, | |
packageName: String, | |
allowedApps: Map<String, String> | |
): Boolean { | |
val signingInfo = context.packageManager.getPackageInfo( | |
packageName, | |
PackageManager.GET_SIGNING_CERTIFICATES | |
).signingInfo | |
return if (signingInfo.hasMultipleSigners()) { | |
isPackageNameAllowed(signingInfo.apkContentsSigners, packageName, allowedApps) | |
} else { | |
isPackageNameAllowed(signingInfo.signingCertificateHistory, packageName, allowedApps) | |
} | |
} | |
private fun isPackageNameAllowed( | |
signatures: Array<Signature>?, | |
packageName: String, | |
allowedApps: Map<String, String> | |
): Boolean { | |
// Mitigation for vulnerability in pre API 28. check ALL signatures returned | |
// from the package manager and return false if any of them aren't in the | |
// allow list. See https://stackoverflow.com/a/56350358 for more info | |
return signatures?.any { signature -> | |
val digest = MessageDigest.getInstance("SHA1") | |
digest.update(signature.toByteArray()) | |
val certHash = digest.digest().toHexString() | |
allowedApps[packageName] != certHash | |
}?.not() ?: false | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment