From c6b89434b018c9b3ca3c13fb78bab20981fee6e6 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Sat, 28 Jul 2012 17:14:31 -0400 Subject: Fix typos: the the -> the (closes: #679432) --- apt/progress/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apt') diff --git a/apt/progress/base.py b/apt/progress/base.py index ab57dd82..2c80ae29 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -65,7 +65,7 @@ class AcquireProgress(object): def media_change(self, media, drive): """Prompt the user to change the inserted removable media. - The parameter 'media' decribes the name of the the media type that + The parameter 'media' decribes the name of the media type that should be changed, whereas the parameter 'drive' should be the identifying name of the drive whose media should be changed. -- cgit v1.2.3 From f1b280f6e21d257411e63cbfdf6ccf0085689f9a Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Mon, 30 Jul 2012 13:23:53 +0200 Subject: apt/auth.py: Do not merge stdout and stderr (Closes: #678706) --- apt/auth.py | 10 +++++----- debian/changelog | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'apt') diff --git a/apt/auth.py b/apt/auth.py index 5d4b1cd6..c52ec3a6 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -69,7 +69,7 @@ def _call_apt_key_script(*args, **kwargs): proc = subprocess.Popen(cmd, env=env, universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + stderr=subprocess.PIPE) content = kwargs.get("stdin", None) if isinstance(content, unicode): @@ -77,12 +77,12 @@ def _call_apt_key_script(*args, **kwargs): output, stderr = proc.communicate(content) - assert stderr == None - if proc.returncode: raise SystemError("The apt-key script failed with return code %s:\n" - "%s\n%s" % (proc.returncode, " ".join(cmd), - output)) + "%s\n" + "stdout: %s\n" + "stderr: %s" % (proc.returncode, " ".join(cmd), + output,stderr)) return output.strip() finally: if conf is not None: diff --git a/debian/changelog b/debian/changelog index c5e03d1b..56c20582 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,9 @@ python-apt (0.8.7) UNRELEASED; urgency=low [ Jakub Wilk ] * Fix typos: the the -> the (closes: #679432) + [ Julian Andres Klode ] + * apt/auth.py: Do not merge stdout and stderr (Closes: #678706) + -- David Prévot Sat, 30 Jun 2012 16:50:03 -0400 python-apt (0.8.6) unstable; urgency=low -- cgit v1.2.3 From 33a8850f6463f6b96e03c475d37aaccb2a834129 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Mon, 30 Jul 2012 13:28:19 +0200 Subject: apt/auth.py: Forward stderr from apt-key to our stderr if non-empty --- apt/auth.py | 4 ++++ debian/changelog | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'apt') diff --git a/apt/auth.py b/apt/auth.py index c52ec3a6..e088ae85 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -28,6 +28,7 @@ import atexit import os import os.path import subprocess +import sys import tempfile import apt_pkg @@ -83,6 +84,9 @@ def _call_apt_key_script(*args, **kwargs): "stdout: %s\n" "stderr: %s" % (proc.returncode, " ".join(cmd), output,stderr)) + elif stderr: + sys.stderr.write(stderr) # Forward stderr + return output.strip() finally: if conf is not None: diff --git a/debian/changelog b/debian/changelog index 56c20582..f908bcd1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,7 +8,9 @@ python-apt (0.8.7) UNRELEASED; urgency=low * Fix typos: the the -> the (closes: #679432) [ Julian Andres Klode ] - * apt/auth.py: Do not merge stdout and stderr (Closes: #678706) + * apt/auth.py: + - Do not merge stdout and stderr (Closes: #678706) + - Forward stderr from apt-key to our stderr if non-empty -- David Prévot Sat, 30 Jun 2012 16:50:03 -0400 -- cgit v1.2.3 From 06f7a9c25dff9dc6d5da1ecdfa0ab59d2cb0c3ab Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 1 Oct 2012 13:56:32 +0200 Subject: support only downloading long keyids (160bit) in add_key_from_keyserver() --- apt/auth.py | 12 +++++++++--- tests/test_auth.py | 3 ++- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'apt') diff --git a/apt/auth.py b/apt/auth.py index e088ae85..b523d36f 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -35,6 +35,10 @@ import apt_pkg from apt_pkg import gettext as _ +class AptKeyError(Exception): + pass + + class TrustedKey(object): """Represents a trusted key.""" @@ -79,7 +83,7 @@ def _call_apt_key_script(*args, **kwargs): output, stderr = proc.communicate(content) if proc.returncode: - raise SystemError("The apt-key script failed with return code %s:\n" + raise AptKeyError("The apt-key script failed with return code %s:\n" "%s\n" "stdout: %s\n" "stderr: %s" % (proc.returncode, " ".join(cmd), @@ -99,9 +103,9 @@ def add_key_from_file(filename): filename -- the absolute path to the public GnuPG key file """ if not os.path.abspath(filename): - raise SystemError("An absolute path is required: %s" % filename) + raise AptKeyError("An absolute path is required: %s" % filename) if not os.access(filename, os.R_OK): - raise SystemError("Key file cannot be accessed: %s" % filename) + raise AptKeyError("Key file cannot be accessed: %s" % filename) _call_apt_key_script("add", filename) def add_key_from_keyserver(keyid, keyserver): @@ -111,6 +115,8 @@ def add_key_from_keyserver(keyid, keyserver): keyid -- the identifier of the key, e.g. 0x0EB12DSA keyserver -- the URL or hostname of the key server """ + if len(keyid) < 160/8: + raise AptKeyError("Only v4 keyids (160bit) are supported") _call_apt_key_script("adv", "--quiet", "--keyserver", keyserver, "--recv", keyid) diff --git a/tests/test_auth.py b/tests/test_auth.py index 99c40db5..7c43d473 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -190,7 +190,8 @@ class TestAuthKeys(unittest.TestCase): self._start_keyserver() self.addCleanup(self._stop_keyserver) - apt.auth.add_key_from_keyserver("46925553", "hkp://localhost:19191") + apt.auth.add_key_from_keyserver( + "A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553", "hkp://localhost:19191") ret = apt.auth.list_keys() self.assertEqual(len(ret), 1) -- cgit v1.2.3 From f40644d4860dea6461e8eea7c363212eac58fd6a Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 1 Oct 2012 14:16:19 +0200 Subject: check fingerprint after downloading a key and before adding it --- apt/auth.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++--- tests/test_auth.py | 16 ++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) (limited to 'apt') diff --git a/apt/auth.py b/apt/auth.py index b523d36f..01c84635 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -27,6 +27,7 @@ import atexit import os import os.path +import shutil import subprocess import sys import tempfile @@ -112,13 +113,76 @@ def add_key_from_keyserver(keyid, keyserver): """Import a GnuPG key file to trust repositores signed by it. Keyword arguments: - keyid -- the identifier of the key, e.g. 0x0EB12DSA + keyid -- the long keyid (fingerprint) of the key, e.g. + A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553 keyserver -- the URL or hostname of the key server """ + tmp_keyring_dir = tempfile.mkdtemp() + try: + _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir) + except: + raise + finally: + print tmp_keyring_dir + shutil.rmtree(tmp_keyring_dir) + +def _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir): if len(keyid) < 160/8: - raise AptKeyError("Only v4 keyids (160bit) are supported") - _call_apt_key_script("adv", "--quiet", "--keyserver", keyserver, - "--recv", keyid) + raise AptKeyError("Only long keyids (v4, 160bit) are supported") + # create a temp keyring dir + tmp_secret_keyring = os.path.join(tmp_keyring_dir, "secring.gpg") + tmp_keyring = os.path.join(tmp_keyring_dir, "pubring.gpg") + # default options for gpg + gpg_default_options = [ + "gpg", + "--no-default-keyring", "--no-options", + "--homedir", tmp_keyring_dir, + ] + # download the key to a temp keyring first + res = subprocess.call(gpg_default_options + [ + "--secret-keyring", tmp_secret_keyring, + "--keyring", tmp_keyring, + "--keyserver", keyserver, + "--recv", keyid, + ]) + if res != 0: + raise AptKeyError("recv from '%s' failed for '%s'" % ( + keyserver, keyid)) + # now export again using the long key id (to ensure that there is + # really only this one key in our keyring) and not someone MITM us + tmp_export_keyring = os.path.join(tmp_keyring_dir, "export-keyring.gpg") + res = subprocess.call(gpg_default_options + [ + "--keyring", tmp_keyring, + "--output", tmp_export_keyring, + "--export", keyid, + ]) + if res != 0: + raise AptKeyError("export of '%s' failed", keyid) + # now verify the fingerprint, this is probably redundant as we + # exported by the fingerprint in the previous command but its + # still good paranoia + output = subprocess.Popen( + gpg_default_options + [ + "--keyring", tmp_export_keyring, + "--fingerprint", + "--batch", + "--with-colons", + ], + stdout=subprocess.PIPE, + universal_newlines=True).communicate()[0] + got_fingerprint=None + for line in output.splitlines(): + if line.startswith("fpr:"): + got_fingerprint = line.split(":")[9] + # stop after the first to ensure no subkey trickery + break + signing_key_fingerprint = keyid + if got_fingerprint != signing_key_fingerprint: + raise AptKeyError( + "Fingerprints do not match, not importing: '%s' != '%s'" % ( + signing_key_fingerprint, got_fingerprint)) + # finally add it + add_key_from_file(tmp_export_keyring) def add_key(content): """Import a GnuPG key to trust repositores signed by it. diff --git a/tests/test_auth.py b/tests/test_auth.py index 7c43d473..4e37b3d3 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -185,6 +185,22 @@ class TestAuthKeys(unittest.TestCase): self.assertEqual(key.keyid, "46925553") self.assertEqual(key.date, "2012-04-27") + def test_add_key_from_keyserver_too_short(self): + """Ensure that short keyids are not imported""" + with self.assertRaises(apt.auth.AptKeyError): + apt.auth.add_key_from_keyserver("46925553", "hkp://localhost:19191") + + def test_add_key_from_server_mitm(self): + """Verify that the key fingerprint is verified after download""" + self._start_keyserver() + self.addCleanup(self._stop_keyserver) + with self.assertRaises(apt.auth.AptKeyError) as cm: + apt.auth.add_key_from_keyserver( + "0101010178F7FE5C3E65D8AF8B48AD6246925553", + "hkp://localhost:19191") + self.assertTrue( + str(cm.exception).startswith("Fingerprints do not match")) + def testAddKeyFromServer(self): """Install a GnuPG key from a remote server.""" self._start_keyserver() -- cgit v1.2.3 From 649ae227b85f1d9d69cd186515589d47acd0ee46 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 1 Oct 2012 14:18:56 +0200 Subject: apt/auth.py: proper cleanup --- apt/auth.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'apt') diff --git a/apt/auth.py b/apt/auth.py index 01c84635..4d4d50e9 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -123,8 +123,7 @@ def add_key_from_keyserver(keyid, keyserver): except: raise finally: - print tmp_keyring_dir - shutil.rmtree(tmp_keyring_dir) + shutil.rmtree(tmp_keyring_dir) def _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir): if len(keyid) < 160/8: -- cgit v1.2.3 From 04ea8dd93af2c59fd58745e0aad6907307bb3047 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 1 Oct 2012 16:32:35 +0200 Subject: fix crash when a pkgname has no candidate --- apt/debfile.py | 1 + 1 file changed, 1 insertion(+) (limited to 'apt') diff --git a/apt/debfile.py b/apt/debfile.py index 2eb807b8..1ebbea32 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -104,6 +104,7 @@ class DebPackage(object): elif self._cache.is_virtual_package(pkgname): return pkgname elif (pkgname in self._cache and + self._cache[pkgname].candidate and self._cache[pkgname].candidate.architecture == "all"): return pkgname # now do the real multiarch checking -- cgit v1.2.3 From c117c260d1a652d5ebcc4c33a88945002fbb4364 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 2 Oct 2012 11:06:51 +0200 Subject: apt/auth.py: fix trailing whitespace --- apt/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apt') diff --git a/apt/auth.py b/apt/auth.py index 4d4d50e9..742b5cc2 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -123,7 +123,7 @@ def add_key_from_keyserver(keyid, keyserver): except: raise finally: - shutil.rmtree(tmp_keyring_dir) + shutil.rmtree(tmp_keyring_dir) def _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir): if len(keyid) < 160/8: -- cgit v1.2.3 From 4755c72601c11b800650f942f855cee286c50356 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 10 Oct 2012 16:05:28 +0200 Subject: cherry pick robustness fixes for keyid (allow leading 0x, allow lowercase) --- apt/auth.py | 4 +++- tests/test_auth.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'apt') diff --git a/apt/auth.py b/apt/auth.py index 742b5cc2..eff13b1a 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -175,7 +175,9 @@ def _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir): got_fingerprint = line.split(":")[9] # stop after the first to ensure no subkey trickery break - signing_key_fingerprint = keyid + # strip the leading "0x" is there is one and uppercase (as this is + # what gnupg is using) + signing_key_fingerprint = keyid.replace("0x", "").upper() if got_fingerprint != signing_key_fingerprint: raise AptKeyError( "Fingerprints do not match, not importing: '%s' != '%s'" % ( diff --git a/tests/test_auth.py b/tests/test_auth.py index 4e37b3d3..d742a471 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -207,7 +207,8 @@ class TestAuthKeys(unittest.TestCase): self.addCleanup(self._stop_keyserver) apt.auth.add_key_from_keyserver( - "A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553", "hkp://localhost:19191") + "0xa1bD8E9D78F7FE5C3E65D8AF8B48AD6246925553", + "hkp://localhost:19191") ret = apt.auth.list_keys() self.assertEqual(len(ret), 1) -- cgit v1.2.3