Skip to content

Instantly share code, notes, and snippets.

@Nimrodda
Last active November 17, 2020 09:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nimrodda/4d559bb39c07a3b4bfd57e26eb1db0de to your computer and use it in GitHub Desktop.
Save Nimrodda/4d559bb39c07a3b4bfd57e26eb1db0de to your computer and use it in GitHub Desktop.
App signing verification
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