From 384922118fdd820a859cab820e47c7f9b932de8f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 22 Oct 2020 14:39:18 +0200 Subject: [PATCH] index: sanitize fingerprint arg, extract_pubkey() returns with spaces The key fingerprint should be only hex digits, everything else can be discarded. That makes it easy to use this function various fingerprint formats, including the common, human-readable forms spaces between pairs or quartets. --- fdroidserver/index.py | 7 ++++++- tests/index.TestCase | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/fdroidserver/index.py b/fdroidserver/index.py index 9003ba57..aae0eb05 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -725,7 +725,11 @@ def download_repo_index(url_str, etag=None, verify_fingerprint=True, timeout=600 def get_index_from_jar(jarfile, fingerprint=None): """Returns the data, public key, and fingerprint from index-v1.jar + :param fingerprint is the SHA-256 fingerprint of signing key. Only + hex digits count, all other chars will can be discarded. + :raises: VerificationException() if the repository could not be verified + """ logging.debug(_('Verifying index signature:')) @@ -733,7 +737,8 @@ def get_index_from_jar(jarfile, fingerprint=None): with zipfile.ZipFile(jarfile) as jar: public_key, public_key_fingerprint = get_public_key_from_jar(jar) if fingerprint is not None: - if fingerprint.upper() != public_key_fingerprint: + fingerprint = re.sub(r'[^0-9A-F]', r'', fingerprint.upper()) + if fingerprint != public_key_fingerprint: raise VerificationException(_("The repository's fingerprint does not match.")) data = json.loads(jar.read('index-v1.json').decode()) return data, public_key, public_key_fingerprint diff --git a/tests/index.TestCase b/tests/index.TestCase index a260114a..131b3a1a 100755 --- a/tests/index.TestCase +++ b/tests/index.TestCase @@ -54,6 +54,10 @@ class IndexTest(unittest.TestCase): fdroidserver.common.config = config fdroidserver.signindex.config = config + if not os.path.exists('repo/index-v1.jar'): + fdroidserver.signindex.sign_index_v1(os.path.join(self.basedir, 'repo'), + 'index-v1.json') + def test_get_public_key_from_jar_succeeds(self): source_dir = os.path.join(self.basedir, 'signindex') for f in ('testy.jar', 'guardianproject.jar'): @@ -83,6 +87,25 @@ class IndexTest(unittest.TestCase): with self.assertRaises(requests.exceptions.RequestException): fdroidserver.index.download_repo_index("http://example.org?fingerprint=nope") + def test_get_repo_key_fingerprint(self): + pubkey, fingerprint = fdroidserver.index.extract_pubkey() + data, public_key, public_key_fingerprint = \ + fdroidserver.index.get_index_from_jar('repo/index-v1.jar', fingerprint) + self.assertIsNotNone(data) + self.assertIsNotNone(public_key) + self.assertIsNotNone(public_key_fingerprint) + + def test_get_index_from_jar_with_bad_fingerprint(self): + pubkey, fingerprint = fdroidserver.index.extract_pubkey() + fingerprint = fingerprint[:-1] + 'G' + with self.assertRaises(fdroidserver.exception.VerificationException): + fdroidserver.index.get_index_from_jar('repo/index-v1.jar', fingerprint) + + def test_get_index_from_jar_with_chars_to_be_stripped(self): + fingerprint = 'NOOOO F4 9A F3 F1 1E FD DF 20 DF FD 70 F5 E3 11 7B 99 76 67 41 67 AD CA 28 0E 6B 19 32 A0 60 1B 26 F6' + data, public_key, public_key_fingerprint = \ + fdroidserver.index.get_index_from_jar('repo/index-v1.jar', fingerprint) + @patch('requests.head') def test_download_repo_index_same_etag(self, head): url = 'http://example.org?fingerprint=test'