chiark / gitweb /
common function for fetching sha256 signing-key fingerprint
authorMichael Pöhn <michael.poehn@fsfe.org>
Sat, 23 Sep 2017 07:02:50 +0000 (09:02 +0200)
committerMichael Pöhn <michael.poehn@fsfe.org>
Tue, 26 Sep 2017 12:11:09 +0000 (14:11 +0200)
fdroidserver/common.py
tests/common.TestCase

index a51347faede35027f764befcbe20208fc10ccb74..887203f3d86a3a29cbdcf1cf3744cc99c45d7d8f 100644 (file)
@@ -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:
index 74fd4eb77aa0bc3ba806298b4f6d456fd9420e42..dee8b667701d27ac34b4b97c78b469f281693306 100755 (executable)
@@ -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()