mirror of
https://github.com/f-droid/fdroidserver.git
synced 2025-11-11 17:50:29 +03:00
support APK Signature V2 when apksigner is installed
This was done with much help from @uniqx. This is the first level of supporting APK Signatures v1, v2, and v3. This is enough to include APKs with any combo of v1/v2/v3 signatures. For this to work at all, apksigner and androguard 3.3.3+ must be installed. closes #399
This commit is contained in:
parent
ea84014f9b
commit
d96f5ff660
6 changed files with 98 additions and 33 deletions
|
|
@ -2516,28 +2516,45 @@ def signer_fingerprint(cert_encoded):
|
|||
return hashlib.sha256(cert_encoded).hexdigest()
|
||||
|
||||
|
||||
def get_first_signer_certificate(apkpath):
|
||||
"""Get the first signing certificate from the APK, DER-encoded"""
|
||||
certs = None
|
||||
cert_encoded = None
|
||||
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:
|
||||
logging.error(_("Found multiple JAR Signature Block Files in {path}").format(path=apkpath))
|
||||
return None
|
||||
elif len(cert_files) == 1:
|
||||
cert_encoded = get_certificate(apk.read(cert_files[0]))
|
||||
|
||||
if cert_encoded is None:
|
||||
apkobject = _get_androguard_APK(apkpath)
|
||||
certs = apkobject.get_certificates_der_v2()
|
||||
if len(certs) > 0:
|
||||
logging.info(_('Using APK v2 Signature'))
|
||||
cert_encoded = certs[0]
|
||||
|
||||
if not cert_encoded:
|
||||
logging.error(_("No signing certificates found in {path}").format(path=apkpath))
|
||||
return None
|
||||
return cert_encoded
|
||||
|
||||
|
||||
def apk_signer_fingerprint(apk_path):
|
||||
"""Obtain sha256 signing-key fingerprint for APK.
|
||||
|
||||
Extracts hexadecimal sha256 signing-key fingerprint string
|
||||
for a given APK.
|
||||
|
||||
:param apkpath: path to APK
|
||||
:param apk_path: path to APK
|
||||
:returns: signature fingerprint
|
||||
"""
|
||||
|
||||
with zipfile.ZipFile(apk_path, 'r') as apk:
|
||||
certs = [n for n in apk.namelist() if SIGNATURE_BLOCK_FILE_REGEX.match(n)]
|
||||
|
||||
if len(certs) < 1:
|
||||
logging.error("Found no signing certificates on %s" % apk_path)
|
||||
return None
|
||||
if len(certs) > 1:
|
||||
logging.error("Found multiple signing certificates on %s" % apk_path)
|
||||
return None
|
||||
|
||||
cert_encoded = get_certificate(apk.read(certs[0]))
|
||||
return signer_fingerprint(cert_encoded)
|
||||
cert_encoded = get_first_signer_certificate(apk_path)
|
||||
if not cert_encoded:
|
||||
return None
|
||||
return signer_fingerprint(cert_encoded)
|
||||
|
||||
|
||||
def apk_signer_fingerprint_short(apk_path):
|
||||
|
|
|
|||
|
|
@ -414,29 +414,26 @@ def resize_all_icons(repodirs):
|
|||
|
||||
|
||||
def getsig(apkpath):
|
||||
""" Get the signing certificate of an apk. To get the same md5 has that
|
||||
Android gets, we encode the .RSA certificate in a specific format and pass
|
||||
it hex-encoded to the md5 digest algorithm.
|
||||
"""Get the unique ID for the signing certificate of an APK.
|
||||
|
||||
This uses a strange algorithm that was devised at the very
|
||||
beginning of F-Droid. Since it is only used for checking
|
||||
signature compatibility, it does not matter much that it uses MD5.
|
||||
|
||||
To get the same MD5 has that fdroidclient gets, we encode the .RSA
|
||||
certificate in a specific format and pass it hex-encoded to the
|
||||
md5 digest algorithm. This is not the same as the standard X.509
|
||||
certificate fingerprint.
|
||||
|
||||
:param apkpath: path to the apk
|
||||
:returns: A string containing the md5 of the signature of the apk or None
|
||||
if an error occurred.
|
||||
|
||||
"""
|
||||
|
||||
with zipfile.ZipFile(apkpath, 'r') as apk:
|
||||
certs = [n for n in apk.namelist() if common.SIGNATURE_BLOCK_FILE_REGEX.match(n)]
|
||||
|
||||
if len(certs) < 1:
|
||||
logging.error(_("No signing certificates found in {path}").format(path=apkpath))
|
||||
return None
|
||||
if len(certs) > 1:
|
||||
logging.error(_("Found multiple signing certificates in {path}").format(path=apkpath))
|
||||
return None
|
||||
|
||||
cert = apk.read(certs[0])
|
||||
|
||||
cert_encoded = common.get_certificate(cert)
|
||||
|
||||
cert_encoded = common.get_first_signer_certificate(apkpath)
|
||||
if not cert_encoded:
|
||||
return None
|
||||
return hashlib.md5(hexlify(cert_encoded)).hexdigest() # nosec just used as ID for signing key
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue