verify: ensure only a single signature is in compared APK

The ZIP format allows multiple entries with the exact same filename, and on
top of that, it does not allow deleting or updating entries.  To make the
`fdroid verify` procedure failsafe, it needs to create a new temporary APK
that is made up on the contents of the "unsigned APK" and the signature
from the "signed APK".  Since it would be possible to give a signed APK as
in the unsigned one's position, `fdroid verify` was not able to update the
signature since it was just adding the new signature to the end of the ZIP
file.  When reading a ZIP, the first entry is used.
This commit is contained in:
Hans-Christoph Steiner 2016-12-19 16:54:32 +01:00
parent 3c9eeff7f3
commit 998b6245e9
2 changed files with 71 additions and 15 deletions

View file

@ -10,6 +10,7 @@ import shutil
import sys
import tempfile
import unittest
from zipfile import ZipFile
localmodule = os.path.realpath(
os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..'))
@ -177,6 +178,46 @@ class CommonTest(unittest.TestCase):
# these should be resigned, and therefore different
self.assertNotEqual(open(sourcefile, 'rb').read(), open(testfile, 'rb').read())
def test_verify_apks(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__)
sourceapk = os.path.join(basedir, 'urzip.apk')
tmpdir = os.path.join(basedir, '..', '.testfiles')
if not os.path.exists(tmpdir):
os.makedirs(tmpdir)
testdir = tempfile.mkdtemp(prefix='test_verify_apks', dir=tmpdir)
print('testdir', testdir)
copyapk = os.path.join(testdir, 'urzip-copy.apk')
shutil.copy(sourceapk, copyapk)
self.assertTrue(fdroidserver.common.verify_apk_signature(copyapk))
self.assertIsNone(fdroidserver.common.verify_apks(sourceapk, copyapk, tmpdir))
unsignedapk = os.path.join(testdir, 'urzip-unsigned.apk')
with ZipFile(sourceapk, 'r') as apk:
with ZipFile(unsignedapk, 'w') as testapk:
for info in apk.infolist():
if not info.filename.startswith('META-INF/'):
testapk.writestr(info, apk.read(info.filename))
self.assertIsNone(fdroidserver.common.verify_apks(sourceapk, unsignedapk, tmpdir))
twosigapk = os.path.join(testdir, 'urzip-twosig.apk')
otherapk = ZipFile(os.path.join(basedir, 'urzip-release.apk'), 'r')
with ZipFile(sourceapk, 'r') as apk:
with ZipFile(twosigapk, 'w') as testapk:
for info in apk.infolist():
testapk.writestr(info, apk.read(info.filename))
if info.filename.startswith('META-INF/'):
testapk.writestr(info, otherapk.read(info.filename))
otherapk.close()
self.assertFalse(fdroidserver.common.verify_apk_signature(twosigapk))
self.assertIsNone(fdroidserver.common.verify_apks(sourceapk, twosigapk, tmpdir))
if __name__ == "__main__":
parser = optparse.OptionParser()