only extract cert from JAR signature on minSdkVersion < 30

This brings the behavior closer to apksigner.  But this should still be
replaced by a complete, tested implementation #94
This commit is contained in:
Hans-Christoph Steiner 2024-04-09 11:59:10 +02:00
parent 5e76b2dab5
commit 7d9cbf2f70
1 changed files with 22 additions and 4 deletions

View File

@ -3148,15 +3148,33 @@ def signer_fingerprint(cert_encoded):
def get_first_signer_certificate(apkpath):
"""Get the first signing certificate from the APK, DER-encoded."""
class FDict(dict):
"""Get the first signing certificate from the APK, DER-encoded.
Starting with SDK 30, APK v2 Signatures are required.
https://developer.android.com/about/versions/11/behavior-changes-11#minimum-signature-scheme
When a APK v2 signature is present, the certificate in the JAR
signature is ignored. The verifier parses the signers from the v2
signature and does not seem to look at the JAR signature.
https://source.android.com/docs/security/features/apksigning/v2#apk-signature-scheme-v2-block
https://android.googlesource.com/platform/tools/apksig/+/refs/tags/android-13.0.0_r3/src/main/java/com/android/apksig/ApkVerifier.java#270
apksigner checks that the signers from all the APK signatures match:
https://android.googlesource.com/platform/tools/apksig/+/refs/tags/android-13.0.0_r3/src/main/java/com/android/apksig/ApkVerifier.java#383
NoOverwriteDict is a workaround for:
https://github.com/androguard/androguard/issues/1030
"""
class NoOverwriteDict(dict):
def __setitem__(self, k, v):
if k not in self:
super().__setitem__(k, v)
cert_encoded = None
apkobject = _get_androguard_APK(apkpath)
apkobject._v2_blocks = FDict()
apkobject._v2_blocks = NoOverwriteDict()
certs = apkobject.get_certificates_der_v3()
if len(certs) > 0:
logging.debug(_('Using APK Signature v3'))
@ -3167,7 +3185,7 @@ def get_first_signer_certificate(apkpath):
logging.debug(_('Using APK Signature v2'))
cert_encoded = certs[0]
if not cert_encoded:
if not cert_encoded and get_min_sdk_version(apkobject) < 30:
with zipfile.ZipFile(apkpath, 'r') as apk:
cert_files = [n for n in apk.namelist() if SIGNATURE_BLOCK_FILE_REGEX.match(n)]
if len(cert_files) > 1: