mirror of
https://github.com/f-droid/fdroidserver.git
synced 2025-09-13 14:32:28 +03:00
make signer_fingerprint() accept DER encoded certs
androguard's v2 signature methods return DER-encoded certificates. The DER- encoded certificates are parsed from JAR Signature's raw "Signature Block File".
This commit is contained in:
parent
4d68163175
commit
ea84014f9b
4 changed files with 24 additions and 21 deletions
|
@ -72,7 +72,7 @@ MINIMUM_AAPT_VERSION = '26.0.0'
|
||||||
VERCODE_OPERATION_RE = re.compile(r'^([ 0-9/*+-]|%c)+$')
|
VERCODE_OPERATION_RE = re.compile(r'^([ 0-9/*+-]|%c)+$')
|
||||||
|
|
||||||
# A signature block file with a .DSA, .RSA, or .EC extension
|
# A signature block file with a .DSA, .RSA, or .EC extension
|
||||||
CERT_PATH_REGEX = re.compile(r'^META-INF/.*\.(DSA|EC|RSA)$')
|
SIGNATURE_BLOCK_FILE_REGEX = re.compile(r'^META-INF/.*\.(DSA|EC|RSA)$')
|
||||||
APK_NAME_REGEX = re.compile(r'^([a-zA-Z][\w.]*)_(-?[0-9]+)_?([0-9a-f]{7})?\.apk')
|
APK_NAME_REGEX = re.compile(r'^([a-zA-Z][\w.]*)_(-?[0-9]+)_?([0-9a-f]{7})?\.apk')
|
||||||
APK_ID_TRIPLET_REGEX = re.compile(r"^package: name='(\w[^']*)' versionCode='([^']+)' versionName='([^']*)'")
|
APK_ID_TRIPLET_REGEX = re.compile(r"^package: name='(\w[^']*)' versionCode='([^']+)' versionName='([^']*)'")
|
||||||
STANDARD_FILE_NAME_REGEX = re.compile(r'^(\w[\w.]*)_(-?[0-9]+)\.\w+')
|
STANDARD_FILE_NAME_REGEX = re.compile(r'^(\w[\w.]*)_(-?[0-9]+)\.\w+')
|
||||||
|
@ -2492,20 +2492,20 @@ def place_srclib(root_dir, number, libpath):
|
||||||
APK_SIGNATURE_FILES = re.compile(r'META-INF/[0-9A-Za-z_\-]+\.(SF|RSA|DSA|EC)')
|
APK_SIGNATURE_FILES = re.compile(r'META-INF/[0-9A-Za-z_\-]+\.(SF|RSA|DSA|EC)')
|
||||||
|
|
||||||
|
|
||||||
def signer_fingerprint_short(sig):
|
def signer_fingerprint_short(cert_encoded):
|
||||||
"""Obtain shortened sha256 signing-key fingerprint for pkcs7 signature.
|
"""Obtain shortened sha256 signing-key fingerprint for pkcs7 DER certficate.
|
||||||
|
|
||||||
Extracts the first 7 hexadecimal digits of sha256 signing-key fingerprint
|
Extracts the first 7 hexadecimal digits of sha256 signing-key fingerprint
|
||||||
for a given pkcs7 signature.
|
for a given pkcs7 signature.
|
||||||
|
|
||||||
:param sig: Contents of an APK signing certificate.
|
:param cert_encoded: Contents of an APK signing certificate.
|
||||||
:returns: shortened signing-key fingerprint.
|
:returns: shortened signing-key fingerprint.
|
||||||
"""
|
"""
|
||||||
return signer_fingerprint(sig)[:7]
|
return signer_fingerprint(cert_encoded)[:7]
|
||||||
|
|
||||||
|
|
||||||
def signer_fingerprint(sig):
|
def signer_fingerprint(cert_encoded):
|
||||||
"""Obtain sha256 signing-key fingerprint for pkcs7 signature.
|
"""Obtain sha256 signing-key fingerprint for pkcs7 DER certificate.
|
||||||
|
|
||||||
Extracts hexadecimal sha256 signing-key fingerprint string
|
Extracts hexadecimal sha256 signing-key fingerprint string
|
||||||
for a given pkcs7 signature.
|
for a given pkcs7 signature.
|
||||||
|
@ -2513,7 +2513,6 @@ def signer_fingerprint(sig):
|
||||||
:param: Contents of an APK signature.
|
:param: Contents of an APK signature.
|
||||||
:returns: shortened signature fingerprint.
|
:returns: shortened signature fingerprint.
|
||||||
"""
|
"""
|
||||||
cert_encoded = get_certificate(sig)
|
|
||||||
return hashlib.sha256(cert_encoded).hexdigest()
|
return hashlib.sha256(cert_encoded).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
@ -2528,7 +2527,7 @@ def apk_signer_fingerprint(apk_path):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with zipfile.ZipFile(apk_path, 'r') as apk:
|
with zipfile.ZipFile(apk_path, 'r') as apk:
|
||||||
certs = [n for n in apk.namelist() if CERT_PATH_REGEX.match(n)]
|
certs = [n for n in apk.namelist() if SIGNATURE_BLOCK_FILE_REGEX.match(n)]
|
||||||
|
|
||||||
if len(certs) < 1:
|
if len(certs) < 1:
|
||||||
logging.error("Found no signing certificates on %s" % apk_path)
|
logging.error("Found no signing certificates on %s" % apk_path)
|
||||||
|
@ -2537,8 +2536,8 @@ def apk_signer_fingerprint(apk_path):
|
||||||
logging.error("Found multiple signing certificates on %s" % apk_path)
|
logging.error("Found multiple signing certificates on %s" % apk_path)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
cert = apk.read(certs[0])
|
cert_encoded = get_certificate(apk.read(certs[0]))
|
||||||
return signer_fingerprint(cert)
|
return signer_fingerprint(cert_encoded)
|
||||||
|
|
||||||
|
|
||||||
def apk_signer_fingerprint_short(apk_path):
|
def apk_signer_fingerprint_short(apk_path):
|
||||||
|
@ -2591,7 +2590,7 @@ def metadata_find_developer_signature(appid, vercode=None):
|
||||||
raise FDroidException('ambiguous signatures, please make sure there is only one signature in \'{}\'. (The signature has to be the App maintainers signature for version of the APK.)'.format(sigdir))
|
raise FDroidException('ambiguous signatures, please make sure there is only one signature in \'{}\'. (The signature has to be the App maintainers signature for version of the APK.)'.format(sigdir))
|
||||||
for sig in sigs:
|
for sig in sigs:
|
||||||
with open(sig, 'rb') as f:
|
with open(sig, 'rb') as f:
|
||||||
return signer_fingerprint(f.read())
|
return signer_fingerprint(get_certificate(f.read()))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@ -3071,13 +3070,17 @@ def get_cert_fingerprint(pubkey):
|
||||||
return " ".join(ret)
|
return " ".join(ret)
|
||||||
|
|
||||||
|
|
||||||
def get_certificate(certificate_file):
|
def get_certificate(signature_block_file):
|
||||||
|
"""Extracts a DER certificate from JAR Signature's "Signature Block File".
|
||||||
|
|
||||||
|
:param signature_block_file: file bytes (as string) representing the
|
||||||
|
certificate, as read directly out of the APK/ZIP
|
||||||
|
|
||||||
|
:return: A binary representation of the certificate's public key,
|
||||||
|
or None in case of error
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Extracts a certificate from the given file.
|
content = decoder.decode(signature_block_file, asn1Spec=rfc2315.ContentInfo())[0]
|
||||||
:param certificate_file: file bytes (as string) representing the certificate
|
|
||||||
:return: A binary representation of the certificate's public key, or None in case of error
|
|
||||||
"""
|
|
||||||
content = decoder.decode(certificate_file, asn1Spec=rfc2315.ContentInfo())[0]
|
|
||||||
if content.getComponentByName('contentType') != rfc2315.signedData:
|
if content.getComponentByName('contentType') != rfc2315.signedData:
|
||||||
return None
|
return None
|
||||||
content = decoder.decode(content.getComponentByName('content'),
|
content = decoder.decode(content.getComponentByName('content'),
|
||||||
|
|
|
@ -751,7 +751,7 @@ def get_public_key_from_jar(jar):
|
||||||
:return: the public key from the jar and its fingerprint
|
:return: the public key from the jar and its fingerprint
|
||||||
"""
|
"""
|
||||||
# extract certificate from jar
|
# extract certificate from jar
|
||||||
certs = [n for n in jar.namelist() if common.CERT_PATH_REGEX.match(n)]
|
certs = [n for n in jar.namelist() if common.SIGNATURE_BLOCK_FILE_REGEX.match(n)]
|
||||||
if len(certs) < 1:
|
if len(certs) < 1:
|
||||||
raise VerificationException(_("Found no signing certificates for repository."))
|
raise VerificationException(_("Found no signing certificates for repository."))
|
||||||
if len(certs) > 1:
|
if len(certs) > 1:
|
||||||
|
|
|
@ -280,7 +280,7 @@ def main():
|
||||||
signaturefile, signedfile, manifest = signingfiles
|
signaturefile, signedfile, manifest = signingfiles
|
||||||
|
|
||||||
with open(signaturefile, 'rb') as f:
|
with open(signaturefile, 'rb') as f:
|
||||||
devfp = common.signer_fingerprint_short(f.read())
|
devfp = common.signer_fingerprint_short(common.get_signature(f.read()))
|
||||||
devsigned = '{}_{}_{}.apk'.format(appid, vercode, devfp)
|
devsigned = '{}_{}_{}.apk'.format(appid, vercode, devfp)
|
||||||
devsignedtmp = os.path.join(tmp_dir, devsigned)
|
devsignedtmp = os.path.join(tmp_dir, devsigned)
|
||||||
shutil.copy(apkfile, devsignedtmp)
|
shutil.copy(apkfile, devsignedtmp)
|
||||||
|
|
|
@ -424,7 +424,7 @@ def getsig(apkpath):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with zipfile.ZipFile(apkpath, 'r') as apk:
|
with zipfile.ZipFile(apkpath, 'r') as apk:
|
||||||
certs = [n for n in apk.namelist() if common.CERT_PATH_REGEX.match(n)]
|
certs = [n for n in apk.namelist() if common.SIGNATURE_BLOCK_FILE_REGEX.match(n)]
|
||||||
|
|
||||||
if len(certs) < 1:
|
if len(certs) < 1:
|
||||||
logging.error(_("No signing certificates found in {path}").format(path=apkpath))
|
logging.error(_("No signing certificates found in {path}").format(path=apkpath))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue