From 6e2d0a9e1eba6e4d65af239c372e7630b48e0e40 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20Mart=C3=AD?= Date: Fri, 29 Aug 2014 22:53:55 -0400 Subject: [PATCH] Replace getsig.java with a pure python implementation Special thanks to deki for helping out with the certificate encodings: https://gitlab.com/snippets/1842 fixes #5 https://gitlab.com/fdroid/fdroidserver/issues/5 --- MANIFEST.in | 3 -- fdroidserver/update.py | 65 ++++++++++++++++++++++++++++++++++-------- jenkins-build | 5 ---- setup.py | 10 ++----- tests/run-tests | 2 -- 5 files changed, 55 insertions(+), 30 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 29dd42e4..468d24ee 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -24,9 +24,6 @@ include examples/config.py include examples/fdroid-icon.png include examples/makebs.config.py include examples/opensc-fdroid.cfg -include fdroidserver/getsig/run.sh -include fdroidserver/getsig/make.sh -include fdroidserver/getsig/getsig.java include tests/run-tests include tests/urzip.apk include wp-fdroid/AndroidManifest.xml diff --git a/fdroidserver/update.py b/fdroidserver/update.py index e161764d..c618fc78 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -29,6 +29,11 @@ import pickle from xml.dom.minidom import Document from optparse import OptionParser import time +from pyasn1.error import PyAsn1Error +from pyasn1.codec.der import decoder, encoder +from pyasn1_modules import rfc2315 +from hashlib import md5 + from PIL import Image import logging @@ -322,6 +327,52 @@ def resize_all_icons(repodirs): resize_icon(iconpath, density) +cert_path_regex = re.compile(r'^META-INF/.*\.RSA$') + + +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. + + :param apkpath: path to the apk + :returns: A string containing the md5 of the signature of the apk or None + if an error occurred. + """ + + cert = None + + with zipfile.ZipFile(apkpath, '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" % apkpath) + return None + if len(certs) > 1: + logging.error("Found multiple signing certificates on %s" % apkpath) + return None + + cert = apk.read(certs[0]) + + content = decoder.decode(cert, asn1Spec=rfc2315.ContentInfo())[0] + if content.getComponentByName('contentType') != rfc2315.signedData: + logging.error("Unexpected format.") + return None + + content = decoder.decode(content.getComponentByName('content'), + asn1Spec=rfc2315.SignedData())[0] + try: + certificates = content.getComponentByName('certificates') + except PyAsn1Error: + logging.error("Certificates not found.") + return None + + cert_encoded = encoder.encode(certificates)[4:] + + return md5(cert_encoded.encode('hex')).hexdigest() + + def scan_apks(apps, apkcache, repodir, knownapks): """Scan the apks in the given repo directory. @@ -476,18 +527,8 @@ def scan_apks(apps, apkcache, repodir, knownapks): sys.exit(1) # Get the signature (or md5 of, to be precise)... - getsig_dir = os.path.join(os.path.dirname(__file__), 'getsig') - if not os.path.exists(getsig_dir + "/getsig.class"): - logging.critical("getsig.class not found. To fix: cd '%s' && ./make.sh" % getsig_dir) - sys.exit(1) - p = FDroidPopen(['java', '-cp', os.path.join(os.path.dirname(__file__), 'getsig'), - 'getsig', os.path.join(os.getcwd(), apkfile)]) - thisinfo['sig'] = None - for line in p.output.splitlines(): - if line.startswith('Result:'): - thisinfo['sig'] = line[7:].strip() - break - if p.returncode != 0 or not thisinfo['sig']: + thisinfo['sig'] = getsig(os.path.join(os.getcwd(), apkfile)) + if not thisinfo['sig']: logging.critical("Failed to get apk signature") sys.exit(1) diff --git a/jenkins-build b/jenkins-build index 4069d820..6e50b663 100755 --- a/jenkins-build +++ b/jenkins-build @@ -38,11 +38,6 @@ fi export PATH=/usr/lib/jvm/java-7-openjdk-amd64/bin:$PATH -#------------------------------------------------------------------------------# -# run local build -cd $WORKSPACE/fdroidserver/getsig -./make.sh - #------------------------------------------------------------------------------# # run local tests diff --git a/setup.py b/setup.py index 82936c39..669cfaee 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,8 @@ #!/usr/bin/env python2 from setuptools import setup -import os -import subprocess import sys -if not os.path.exists('fdroidserver/getsig/getsig.class'): - subprocess.check_output('cd fdroidserver/getsig && javac getsig.java', - shell=True) - setup(name='fdroidserver', version='0.2.1', description='F-Droid Server Tools', @@ -25,8 +19,6 @@ setup(name='fdroidserver', 'examples/makebs.config.py', 'examples/opensc-fdroid.cfg', 'examples/fdroid-icon.png']), - ('fdroidserver/getsig', - ['fdroidserver/getsig/getsig.class']), ], install_requires=[ 'mwclient', @@ -34,6 +26,8 @@ setup(name='fdroidserver', 'Pillow', 'python-magic', 'apache-libcloud >= 0.14.1', + 'pyasn1', + 'pyasn1-modules', ], classifiers=[ 'Development Status :: 3 - Alpha', diff --git a/tests/run-tests b/tests/run-tests index 90bfb873..1f0e7709 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -101,8 +101,6 @@ $python setup.py sdist REPOROOT=`create_test_dir` cd $REPOROOT tar xzf `ls -1 $WORKSPACE/dist/fdroidserver-*.tar.gz | sort -n | tail -1` -cd $REPOROOT/fdroidserver-*/fdroidserver/getsig -./make.sh cd $REPOROOT ./fdroidserver-*/fdroid init copy_apks_into_repo $REPOROOT -- 2.30.2