diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 34267787..17ea4c2f 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -387,6 +387,29 @@ def write_password_file(pwtype, password=None): config[pwtype + 'file'] = filename +def signjar(jar): + ''' + sign a JAR file with Java's jarsigner. + + This does use old hashing algorithms, i.e. SHA1, but that's not + broken yet for file verification. This could be set to SHA256, + but then Android < 4.3 would not be able to verify it. + https://code.google.com/p/android/issues/detail?id=38321 + ''' + args = [config['jarsigner'], '-keystore', config['keystore'], + '-storepass:file', config['keystorepassfile'], + '-digestalg', 'SHA1', '-sigalg', 'SHA1withRSA', + jar, config['repo_keyalias']] + if config['keystore'] == 'NONE': + args += config['smartcardoptions'] + else: # smardcards never use -keypass + args += ['-keypass:file', config['keypassfile']] + p = FDroidPopen(args) + if p.returncode != 0: + logging.critical("Failed to sign %s!" % jar) + sys.exit(1) + + def get_local_metadata_files(): '''get any metadata files local to an app's source repo diff --git a/fdroidserver/signindex.py b/fdroidserver/signindex.py index caf9adb3..658d4cb8 100644 --- a/fdroidserver/signindex.py +++ b/fdroidserver/signindex.py @@ -22,7 +22,6 @@ from argparse import ArgumentParser import logging from . import common -from .common import FDroidPopen config = None options = None @@ -56,18 +55,7 @@ def main(): unsigned = os.path.join(output_dir, 'index_unsigned.jar') if os.path.exists(unsigned): - args = [config['jarsigner'], '-keystore', config['keystore'], - '-storepass:file', config['keystorepassfile'], - '-digestalg', 'SHA1', '-sigalg', 'SHA1withRSA', - unsigned, config['repo_keyalias']] - if config['keystore'] == 'NONE': - args += config['smartcardoptions'] - else: # smardcards never use -keypass - args += ['-keypass:file', config['keypassfile']] - p = FDroidPopen(args) - if p.returncode != 0: - logging.critical("Failed to sign index") - sys.exit(1) + common.signjar(unsigned) os.rename(unsigned, os.path.join(output_dir, 'index.jar')) logging.info('Signed index in ' + output_dir) signed += 1 diff --git a/fdroidserver/update.py b/fdroidserver/update.py index 47cdd915..19a13368 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -1287,7 +1287,7 @@ def make_index_v1(apps, packages, repodir, repodict, requestsdict): jar_file = os.path.join(repodir, 'index-v1.jar') with zipfile.ZipFile(jar_file, 'w', zipfile.ZIP_DEFLATED) as jar: jar.write(index_file, json_name) - signjar(jar_file) + common.signjar(jar_file) os.remove(index_file) @@ -1540,7 +1540,7 @@ def make_index_v0(apps, apks, repodir, repodict, requestsdict): if os.path.exists(signed): os.remove(signed) else: - signjar(signed) + common.signjar(signed) # Copy the repo icon into the repo directory... icon_dir = os.path.join(repodir, 'icons') @@ -1548,29 +1548,6 @@ def make_index_v0(apps, apks, repodir, repodict, requestsdict): shutil.copyfile(config['repo_icon'], iconfilename) -def signjar(jar): - ''' - sign a JAR file with Java's jarsigner. - - This does use old hashing algorithms, i.e. SHA1, but that's not - broken yet for file verification. This could be set to SHA256, - but then Android < 4.3 would not be able to verify it. - https://code.google.com/p/android/issues/detail?id=38321 - ''' - args = [config['jarsigner'], '-keystore', config['keystore'], - '-storepass:file', config['keystorepassfile'], - '-digestalg', 'SHA1', '-sigalg', 'SHA1withRSA', - jar, config['repo_keyalias']] - if config['keystore'] == 'NONE': - args += config['smartcardoptions'] - else: # smardcards never use -keypass - args += ['-keypass:file', config['keypassfile']] - p = FDroidPopen(args) - if p.returncode != 0: - logging.critical("Failed to sign index") - sys.exit(1) - - def make_categories_txt(repodir, categories): '''Write a category list in the repo to allow quick access''' catdata = '' diff --git a/tests/common.TestCase b/tests/common.TestCase index 9e00904f..98939985 100755 --- a/tests/common.TestCase +++ b/tests/common.TestCase @@ -157,6 +157,26 @@ class CommonTest(unittest.TestCase): p = fdroidserver.common.FDroidPopen(commands, stderr_to_stdout=False) self.assertEqual(p.output, 'stdout message\n') + def test_signjar(self): + fdroidserver.common.config = None + config = fdroidserver.common.read_config(fdroidserver.common.options) + config['jarsigner'] = fdroidserver.common.find_sdk_tools_cmd('jarsigner') + fdroidserver.common.config = config + + basedir = os.path.dirname(__file__) + tmpdir = os.path.join(basedir, '..', '.testfiles') + if not os.path.exists(tmpdir): + os.makedirs(tmpdir) + sourcedir = os.path.join(basedir, 'signindex') + testsdir = tempfile.mkdtemp(prefix='test_signjar', dir=tmpdir) + for f in ('testy.jar', 'guardianproject.jar',): + sourcefile = os.path.join(sourcedir, f) + testfile = os.path.join(testsdir, f) + shutil.copy(sourcefile, testsdir) + fdroidserver.common.signjar(testfile) + # these should be resigned, and therefore different + self.assertNotEqual(open(sourcefile, 'rb').read(), open(testfile, 'rb').read()) + if __name__ == "__main__": parser = optparse.OptionParser() diff --git a/tests/signindex/guardianproject.jar b/tests/signindex/guardianproject.jar new file mode 100644 index 00000000..946c69ac Binary files /dev/null and b/tests/signindex/guardianproject.jar differ diff --git a/tests/signindex/testy.jar b/tests/signindex/testy.jar new file mode 100644 index 00000000..6d7dd359 Binary files /dev/null and b/tests/signindex/testy.jar differ