Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parse APKv1 signatures with a cert chain like apksigner #1038

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 10 additions & 3 deletions androguard/core/apk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1446,16 +1446,23 @@ def is_androidtv(self):
return self.get_attribute_value('uses-feature', 'name', required="false", name="android.hardware.touchscreen") == "android.hardware.touchscreen"

def get_certificate_der(self, filename):
"""
Return the DER coded X.509 certificate from the signature file.
"""Return the DER coded X.509 certificate from the signature file.

Rarely, there is a certificate chain like in TLS (Microsoft
does this). In that case, this returns only the final
certificate, which is the one used to sign the manifest. This
will be the same certificate that will be printed by:

apksigner verify --print-certs com.microsoft.emmx.apk

:param filename: Signature filename in APK
:returns: DER coded X.509 certificate as binary

"""
pkcs7message = self.get_file(filename)

pkcs7obj = cms.ContentInfo.load(pkcs7message)
cert = pkcs7obj['content']['certificates'][0].chosen.dump()
cert = pkcs7obj['content']['certificates'][-1].chosen.dump()
return cert

def get_certificate(self, filename):
Expand Down
Binary file added tests/data/APK/CertChain.apk
Binary file not shown.
22 changes: 22 additions & 0 deletions tests/test_apk.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,28 @@ def testAPKCert(self):

self.assertEqual(binascii.hexlify(cert).decode("ascii").upper(), expected)

def testAPKCertChain(self):
"""Test that APK signatures with a cert chain are parsed like apksigner.

Microsoft signs their APKs with a X.509 certificate chain of
trust, so there are actually three certificates
included. apksigner only cares about the certificate that
actually signs the manifest and ignores the certificates that
just sign other certificates.

The correct value comes from:
apksigner verify --print-certs com.microsoft.emmx_242009005.apk | grep SHA-256

"""
a = APK(os.path.join(test_dir, 'data/APK/CertChain.apk'), skip_analysis=True)
cert_der = a.get_certificate_der(a.get_signature_name())
sha256 = hashlib.sha256()
sha256.update(cert_der)
self.assertEqual(
sha256.hexdigest(),
'01e1999710a82c2749b4d50c445dc85d670b6136089d0a766a73827c82a1eac9',
)

def testAPKCertFingerprint(self):
"""
Test if certificates are correctly unpacked from the SignatureBlock files
Expand Down