diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 137563d7..701a9e03 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -72,7 +72,7 @@ MINIMUM_AAPT_VERSION = '26.0.0' VERCODE_OPERATION_RE = re.compile(r'^([ 0-9/*+-]|%c)+$') # 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_ID_TRIPLET_REGEX = re.compile(r"^package: name='(\w[^']*)' versionCode='([^']+)' versionName='([^']*)'") 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)') -def signer_fingerprint_short(sig): - """Obtain shortened sha256 signing-key fingerprint for pkcs7 signature. +def signer_fingerprint_short(cert_encoded): + """Obtain shortened sha256 signing-key fingerprint for pkcs7 DER certficate. Extracts the first 7 hexadecimal digits of sha256 signing-key fingerprint 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. """ - return signer_fingerprint(sig)[:7] + return signer_fingerprint(cert_encoded)[:7] -def signer_fingerprint(sig): - """Obtain sha256 signing-key fingerprint for pkcs7 signature. +def signer_fingerprint(cert_encoded): + """Obtain sha256 signing-key fingerprint for pkcs7 DER certificate. Extracts hexadecimal sha256 signing-key fingerprint string for a given pkcs7 signature. @@ -2513,7 +2513,6 @@ def signer_fingerprint(sig): :param: Contents of an APK signature. :returns: shortened signature fingerprint. """ - cert_encoded = get_certificate(sig) return hashlib.sha256(cert_encoded).hexdigest() @@ -2528,7 +2527,7 @@ def apk_signer_fingerprint(apk_path): """ 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: 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) return None - cert = apk.read(certs[0]) - return signer_fingerprint(cert) + cert_encoded = get_certificate(apk.read(certs[0])) + return signer_fingerprint(cert_encoded) 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)) for sig in sigs: with open(sig, 'rb') as f: - return signer_fingerprint(f.read()) + return signer_fingerprint(get_certificate(f.read())) return None @@ -3071,13 +3070,17 @@ def get_cert_fingerprint(pubkey): 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. - :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] + content = decoder.decode(signature_block_file, asn1Spec=rfc2315.ContentInfo())[0] if content.getComponentByName('contentType') != rfc2315.signedData: return None content = decoder.decode(content.getComponentByName('content'), diff --git a/fdroidserver/index.py b/fdroidserver/index.py index 7585563f..d8477dc5 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -751,7 +751,7 @@ def get_public_key_from_jar(jar): :return: the public key from the jar and its fingerprint """ # 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: raise VerificationException(_("Found no signing certificates for repository.")) if len(certs) > 1: diff --git a/fdroidserver/publish.py b/fdroidserver/publish.py index 6561a9b8..ac9a3f44 100644 --- a/fdroidserver/publish.py +++ b/fdroidserver/publish.py @@ -280,7 +280,7 @@ def main(): signaturefile, signedfile, manifest = signingfiles 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) devsignedtmp = os.path.join(tmp_dir, devsigned) shutil.copy(apkfile, devsignedtmp) diff --git a/fdroidserver/update.py b/fdroidserver/update.py index 8ae0c330..42be7e5c 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -424,7 +424,7 @@ def getsig(apkpath): """ 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: logging.error(_("No signing certificates found in {path}").format(path=apkpath))