From: Michael Pöhn Date: Sat, 23 Sep 2017 07:02:50 +0000 (+0200) Subject: common function for fetching sha256 signing-key fingerprint X-Git-Tag: 0.9~65^2~15 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=c196f7dd7a42cdc3703419e0ea8f65355f904649;p=fdroidserver.git common function for fetching sha256 signing-key fingerprint --- diff --git a/fdroidserver/common.py b/fdroidserver/common.py index a51347fa..887203f3 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -34,6 +34,7 @@ import logging import hashlib import socket import base64 +import zipfile import xml.etree.ElementTree as XMLElementTree from binascii import hexlify @@ -2014,6 +2015,43 @@ def place_srclib(root_dir, number, libpath): apk_sigfile = re.compile(r'META-INF/[0-9A-Za-z]+\.(SF|RSA|DSA|EC)') +def signer_fingerprint(sig): + """Obtain sha256 signing-key fingerprint for pkcs7 signature. + + Extracts hexadecimal sha256 signing-key fingerprint string + for a given pkcs7 signature. + + :param: Contents of an APK signature. + :returns: shortened signature fingerprint. + """ + cert_encoded = get_certificate(sig) + return hashlib.sha256(cert_encoded).hexdigest() + + +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 + :returns: signature fingerprint + """ + + with zipfile.ZipFile(apk_path, 'r') as apk: + certs = [n for n in apk.namelist() if CERT_PATH_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 = apk.read(certs[0]) + return signer_fingerprint(cert) + + def metadata_get_sigdir(appid, vercode=None): """Get signature directory for app""" if vercode: diff --git a/tests/common.TestCase b/tests/common.TestCase index 74fd4eb7..dee8b667 100755 --- a/tests/common.TestCase +++ b/tests/common.TestCase @@ -376,6 +376,20 @@ class CommonTest(unittest.TestCase): for name in bad: self.assertIsNone(fdroidserver.common.STANDARD_FILE_NAME_REGEX.match(name)) + def test_apk_signer_fingerprint(self): + + # fingerprints fetched with: keytool -printcert -file ____.RSA + testapks = (('repo/obb.main.oldversion_1444412523.apk', + '818e469465f96b704e27be2fee4c63ab9f83ddf30e7a34c7371a4728d83b0bc1'), + ('repo/obb.main.twoversions_1101613.apk', + '32a23624c201b949f085996ba5ed53d40f703aca4989476949cae891022e0ed6'), + ('repo/obb.main.twoversions_1101617.apk', + '32a23624c201b949f085996ba5ed53d40f703aca4989476949cae891022e0ed6')) + + for apkfile, keytoolcertfingerprint in testapks: + self.assertEqual(keytoolcertfingerprint, + fdroidserver.common.apk_signer_fingerprint(apkfile)) + if __name__ == "__main__": parser = optparse.OptionParser()