add verify_jar_signature() to verify entry.jar

This commit is contained in:
Hans-Christoph Steiner 2023-03-08 11:26:29 +01:00
parent cfe399888b
commit dd16076651
No known key found for this signature in database
GPG Key ID: 3E177817BA1B9BFA
2 changed files with 62 additions and 1 deletions

View File

@ -3408,13 +3408,45 @@ def verify_apks(signed_apk, unsigned_apk, tmp_dir, v1_only=None):
return None
def verify_deprecated_jar_signature(jar):
def verify_jar_signature(jar):
"""Verify 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.
"""
error = _('JAR signature failed to verify: {path}').format(path=jar)
try:
output = subprocess.check_output(
[config['jarsigner'], '-strict', '-verify', jar], stderr=subprocess.STDOUT
)
raise VerificationException(error + '\n' + output.decode('utf-8'))
except subprocess.CalledProcessError as e:
if e.returncode == 4:
logging.debug(_('JAR signature verified: {path}').format(path=jar))
else:
raise VerificationException(error + '\n' + e.output.decode('utf-8')) from e
def verify_deprecated_jar_signature(jar):
"""Verify the signature of a given JAR file, allowing deprecated algorithms.
index.jar (v0) and index-v1.jar are both signed by MD5/SHA1 by
definition, so this method provides a way to verify those. Also,
apksigner has different deprecation rules than jarsigner, so this
is our current hack to try to represent the apksigner rules when
executing jarsigner.
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.
Also used to verify the signature on an archived APK, supporting deprecated
algorithms.

View File

@ -529,6 +529,35 @@ class CommonTest(unittest.TestCase):
self.assertRaises(VerificationException, fdroidserver.common.verify_deprecated_jar_signature, 'urzip-badsig.apk')
self.assertRaises(VerificationException, fdroidserver.common.verify_deprecated_jar_signature, 'urzip-release-unsigned.apk')
def test_verify_jar_signature(self):
"""Sign entry.jar and make sure it validates"""
config = fdroidserver.common.read_config(fdroidserver.common.options)
config['jarsigner'] = fdroidserver.common.find_sdk_tools_cmd('jarsigner')
config['keystore'] = os.path.join(self.basedir, 'keystore.jks')
config['repo_keyalias'] = 'sova'
config['keystorepass'] = 'r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI='
config['keypass'] = 'r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI='
fdroidserver.common.config = config
fdroidserver.signindex.config = config
repo_dir = Path(self.testdir) / 'repo'
repo_dir.mkdir()
shutil.copy('repo/entry.json', repo_dir)
shutil.copy('repo/index-v2.json', repo_dir)
os.chdir(self.testdir)
fdroidserver.signindex.sign_index('repo', 'entry.json')
fdroidserver.common.verify_jar_signature('repo/entry.jar')
def test_verify_jar_signature_fails(self):
"""Test verify_jar_signature fails on unsigned and deprecated algorithms"""
config = fdroidserver.common.read_config(fdroidserver.common.options)
config['jarsigner'] = fdroidserver.common.find_sdk_tools_cmd('jarsigner')
fdroidserver.common.config = config
source_dir = os.path.join(self.basedir, 'signindex')
for f in ('unsigned.jar', 'testy.jar', 'guardianproject.jar', 'guardianproject-v1.jar'):
testfile = os.path.join(source_dir, f)
with self.assertRaises(fdroidserver.index.VerificationException):
fdroidserver.common.verify_jar_signature(testfile)
def test_verify_deprecated_jar_signature(self):
config = fdroidserver.common.read_config(fdroidserver.common.options)
config['jarsigner'] = fdroidserver.common.find_sdk_tools_cmd('jarsigner')