chiark / gitweb /
index: always use jarsigner for verifying JAR signatures
authorHans-Christoph Steiner <hans@eds.org>
Tue, 19 Sep 2017 13:07:19 +0000 (15:07 +0200)
committerHans-Christoph Steiner <hans@eds.org>
Tue, 19 Sep 2017 18:13:36 +0000 (20:13 +0200)
apksigner v0.7 (build-tools 26.0.1), Google made it require that the
AndroidManifest.xml was present in the archive before it verifies the
signature.  So this needs to stick with the jarsigner hack for JARs.

fdroidserver/common.py
fdroidserver/index.py
tests/index.TestCase
tests/run-tests

index 4d897653555f079c69047b3e20764668ba6930de..807974d6013a9f942231c19f75d4d3522a44ec5c 100644 (file)
@@ -50,7 +50,7 @@ from distutils.util import strtobool
 
 import fdroidserver.metadata
 from fdroidserver import _
-from fdroidserver.exception import FDroidException, VCSException, BuildException
+from fdroidserver.exception import FDroidException, VCSException, BuildException, VerificationException
 from .asynchronousfilereader import AsynchronousFileReader
 
 
@@ -2077,24 +2077,41 @@ def verify_apks(signed_apk, unsigned_apk, tmp_dir):
     return None
 
 
-def verify_apk_signature(apk, jar=False):
+def verify_jar_signature(jar):
+    """Verifies the signature of a given JAR file.
+
+    jarsigner is very shitty: unsigned JARs pass as "verified"! So
+    this has to turn on -strict then check for result 4, since this
+    does not expect the signature to be from a CA-signed certificate.
+
+    :raises: VerificationException() if the JAR's signature could not be verified
+
+    """
+
+    if subprocess.call([config['jarsigner'], '-strict', '-verify', jar]) != 4:
+        raise VerificationException(_("The repository's index could not be verified."))
+
+
+def verify_apk_signature(apk, min_sdk_version=None):
     """verify the signature on an APK
 
     Try to use apksigner whenever possible since jarsigner is very
-    shitty: unsigned APKs pass as "verified"! So this has to turn on
-    -strict then check for result 4.
-
-    You can set :param: jar to True if you want to use this method
-    to verify jar signatures.
+    shitty: unsigned APKs pass as "verified"!  Warning, this does
+    not work on JARs with apksigner >= 0.7 (build-tools 26.0.1)
     """
     if set_command_in_config('apksigner'):
         args = [config['apksigner'], 'verify']
-        if jar:
-            args += ['--min-sdk-version=1']
+        if min_sdk_version:
+            args += ['--min-sdk-version=' + min_sdk_version]
         return subprocess.call(args + [apk]) == 0
     else:
         logging.warning("Using Java's jarsigner, not recommended for verifying APKs! Use apksigner")
-        return subprocess.call([config['jarsigner'], '-strict', '-verify', apk]) == 4
+        try:
+            verify_jar_signature(apk)
+            return True
+        except:
+            pass
+    return False
 
 
 def verify_old_apk_signature(apk):
index 59139e17f70b0492aaa903c141dac4590ebebd82..79322d55185da1c472b01eecabd10e5e21c6688f 100644 (file)
@@ -632,7 +632,7 @@ def download_repo_index(url_str, etag=None, verify_fingerprint=True):
         jar = zipfile.ZipFile(fp)
 
         # verify that the JAR signature is valid
-        verify_jar_signature(fp.name)
+        common.verify_jar_signature(fp.name)
 
         # get public key and its fingerprint from JAR
         public_key, public_key_fingerprint = get_public_key_from_jar(jar)
@@ -652,16 +652,6 @@ def download_repo_index(url_str, etag=None, verify_fingerprint=True):
         return index, new_etag
 
 
-def verify_jar_signature(file):
-    """
-    Verifies the signature of a given JAR file.
-
-    :raises: VerificationException() if the JAR's signature could not be verified
-    """
-    if not common.verify_apk_signature(file, jar=True):
-        raise VerificationException(_("The repository's index could not be verified."))
-
-
 def get_public_key_from_jar(jar):
     """
     Get the public key and its fingerprint from a JAR file.
index 2798e7818d41a96b41578ac84064da2662d79cc9..315935237ac395dc8584852e7a6b4bc24e96cd08 100755 (executable)
@@ -39,14 +39,14 @@ class IndexTest(unittest.TestCase):
         source_dir = os.path.join(basedir, 'signindex')
         for f in ('testy.jar', 'guardianproject.jar'):
             testfile = os.path.join(source_dir, f)
-            fdroidserver.index.verify_jar_signature(testfile)
+            fdroidserver.common.verify_jar_signature(testfile)
 
     def test_verify_jar_signature_fails(self):
         basedir = os.path.dirname(__file__)
         source_dir = os.path.join(basedir, 'signindex')
         testfile = os.path.join(source_dir, 'unsigned.jar')
         with self.assertRaises(fdroidserver.index.VerificationException):
-            fdroidserver.index.verify_jar_signature(testfile)
+            fdroidserver.common.verify_jar_signature(testfile)
 
     def test_get_public_key_from_jar_succeeds(self):
         basedir = os.path.dirname(__file__)
index 608c1e2eec45a6322c430e6887a6769d89c7c369..c58942bdd14cf1bb42e2af62ccb8640d472a82fa 100755 (executable)
@@ -266,6 +266,7 @@ cp $WORKSPACE/tests/urzip.apk \
 sed -i 's,archive_older = [0-9],archive_older = 3,' config.py
 
 $fdroid update --pretty --nosign
+echo "This will fail when jarsigner allows MD5 for APK signatures"
 test `grep '<package>' archive/index.xml | wc -l` -eq 5
 test `grep '<package>' repo/index.xml | wc -l` -eq 7