launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #29136
[Merge] ~lgp171188/launchpad:gnupg2-xenial into launchpad:master
Guruprasad has proposed merging ~lgp171188/launchpad:gnupg2-xenial into launchpad:master.
Commit message:
Use `/usr/bin/gpg2` everywhere instead of `/usr/bin/gpg`
This enables GnuPG 2 support in Launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~lgp171188/launchpad/+git/launchpad/+merge/429507
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~lgp171188/launchpad:gnupg2-xenial into launchpad:master.
diff --git a/lib/lp/services/gpg/doc/gpg-encryption.rst b/lib/lp/services/gpg/doc/gpg-encryption.rst
index 4d6af02..a6bd329 100644
--- a/lib/lp/services/gpg/doc/gpg-encryption.rst
+++ b/lib/lp/services/gpg/doc/gpg-encryption.rst
@@ -117,3 +117,4 @@ What about a message encrypted for an unknown key.
>>> plain is None
True
+ >>> gpghandler.resetLocalState()
diff --git a/lib/lp/services/gpg/doc/gpg-signatures.rst b/lib/lp/services/gpg/doc/gpg-signatures.rst
index 9c3d285..99e61c0 100644
--- a/lib/lp/services/gpg/doc/gpg-signatures.rst
+++ b/lib/lp/services/gpg/doc/gpg-signatures.rst
@@ -231,5 +231,5 @@ itself.
89
[<gpgme.Signature object at ...>]
7
-
+ >>> gpghandler.resetLocalState()
>>> keyserver.tearDown()
diff --git a/lib/lp/services/gpg/doc/gpghandler.rst b/lib/lp/services/gpg/doc/gpghandler.rst
index 5d1b5d3..32285af 100644
--- a/lib/lp/services/gpg/doc/gpghandler.rst
+++ b/lib/lp/services/gpg/doc/gpghandler.rst
@@ -120,17 +120,8 @@ preamble.
...
lp.services.gpg.interfaces.GPGKeyNotFoundError: ...
-Apparently GPGME is able to import an incomplete public key:
-
- >>> key = gpghandler.importPublicKey(pubkey[:-300])
- >>> assert key is not None
- >>> verifyObject(IPymeKey, key)
- True
- >>> print(key.fingerprint)
- A419AE861E88BC9E04B9C26FBA2B9389DFD20543
-
-But we get an error if the damage is big:
-(what probably happened in bug #2547)
+We also get an error if we try to import an incomplete public key
+(which probably happened in bug #2547):
>>> key = gpghandler.importPublicKey(pubkey[:-500])
Traceback (most recent call last):
diff --git a/lib/lp/services/gpg/handler.py b/lib/lp/services/gpg/handler.py
index 5cce7ef..c4472ff 100644
--- a/lib/lp/services/gpg/handler.py
+++ b/lib/lp/services/gpg/handler.py
@@ -105,11 +105,19 @@ class GPGHandler:
with open(confpath, "w") as conf:
# Avoid wasting time verifying the local keyring's consistency.
conf.write("no-auto-check-trustdb\n")
+ # Use the loopback mode to allow using password callbacks.
+ conf.write("pinentry-mode loopback\n")
+ # Assume "yes" on most questions; this is needed to allow
+ # deletion of secret keys via GPGME.
+ conf.write("yes\n")
# Prefer a SHA-2 hash where possible, otherwise GPG will fall
# back to a hash it can use.
conf.write(
"personal-digest-preferences SHA512 SHA384 SHA256 SHA224\n"
)
+ agentconfpath = os.path.join(self.home, "gpg-agent.conf")
+ with open(agentconfpath, "w") as agentconf:
+ agentconf.write("allow-loopback-pinentry\n")
# create a local atexit handler to remove the configuration directory
# on normal termination.
@@ -126,11 +134,23 @@ class GPGHandler:
def resetLocalState(self):
"""See IGPGHandler."""
- # remove the public keyring, private keyring and the trust DB
- for filename in ["pubring.gpg", "secring.gpg", "trustdb.gpg"]:
+ # Remove the public keyring, private keyring and the trust DB.
+ for filename in (
+ "pubring.gpg",
+ "pubring.kbx",
+ "secring.gpg",
+ "private-keys-v1.d",
+ "trustdb.gpg",
+ ):
filename = os.path.join(self.home, filename)
if os.path.exists(filename):
- os.remove(filename)
+ if os.path.isdir(filename):
+ shutil.rmtree(filename)
+ else:
+ os.remove(filename)
+ # Kill any running gpg-agent for GnuPG 2
+ if shutil.which("gpgconf"):
+ subprocess.check_call(["gpgconf", "--kill", "gpg-agent"])
def getVerifiedSignatureResilient(self, content, signature=None):
"""See IGPGHandler."""
@@ -301,6 +321,11 @@ class GPGHandler:
del os.environ["GPG_AGENT_INFO"]
context = get_gpgme_context()
+
+ def passphrase_cb(uid_hint, passphrase_info, prev_was_bad, fd):
+ os.write(fd, b"\n")
+
+ context.passphrase_cb = passphrase_cb
newkey = BytesIO(content)
with gpgme_timeline("import", "new secret key"):
import_result = context.import_(newkey)
@@ -696,10 +721,13 @@ class PymeKey:
get_gpg_path(),
"--export-secret-keys",
"-a",
+ # This only works for keys with empty passphrase.
+ "--passphrase",
+ "",
self.fingerprint,
],
stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
+ stderr=subprocess.DEVNULL,
)
return p.stdout.read()
diff --git a/lib/lp/services/gpg/interfaces.py b/lib/lp/services/gpg/interfaces.py
index 90bf7e7..0668ea1 100644
--- a/lib/lp/services/gpg/interfaces.py
+++ b/lib/lp/services/gpg/interfaces.py
@@ -25,7 +25,6 @@ __all__ = [
]
import http.client
-import os.path
import re
from lazr.enum import DBEnumeratedType, DBItem
@@ -57,15 +56,8 @@ def valid_keyid(keyid):
def get_gpg_path():
- """Return the path to the GPG executable we prefer.
-
- We stick to GnuPG 1 until we've worked out how to get things working
- with GnuPG 2.
- """
- if os.path.exists("/usr/bin/gpg1"):
- return "/usr/bin/gpg1"
- else:
- return "/usr/bin/gpg"
+ """Return the path to the GPG executable we prefer."""
+ return "/usr/bin/gpg2"
def get_gpgme_context():
@@ -443,7 +435,7 @@ class IPymeKey(Interface):
Both public and secret keys are supported, although secret keys are
exported by calling `gpg` process while public ones use the native
- gpgme API.
+ gpgme API. Only secret keys with empty passphrases may be exported.
:return: a string containing the exported key.
"""
diff --git a/lib/lp/soyuz/tests/fakepackager.py b/lib/lp/soyuz/tests/fakepackager.py
index 162aa15..ebafbb8 100644
--- a/lib/lp/soyuz/tests/fakepackager.py
+++ b/lib/lp/soyuz/tests/fakepackager.py
@@ -22,7 +22,7 @@ from zope.component import getUtility
from lp.archiveuploader.nascentupload import NascentUpload
from lp.archiveuploader.uploadpolicy import findPolicyByName
from lp.registry.interfaces.distribution import IDistributionSet
-from lp.services.gpg.interfaces import IGPGHandler
+from lp.services.gpg.interfaces import IGPGHandler, get_gpg_path
from lp.services.log.logger import BufferLogger
from lp.soyuz.enums import PackageUploadStatus
from lp.testing.gpgkeys import import_secret_test_key
@@ -394,6 +394,7 @@ class FakePackager:
self.gpg_key_fingerprint is not None
), "Cannot build signed packages because the key is not set."
debuild_options.append("-k%s" % self.gpg_key_fingerprint)
+ debuild_options.append("-p%s" % get_gpg_path())
if include_orig:
debuild_options.append("-sa")
diff --git a/lib/lp/testing/gpgkeys/data/test@xxxxxxxxxxxxxxxxx b/lib/lp/testing/gpgkeys/data/test@xxxxxxxxxxxxxxxxx
index 4eacac1..ea3d992 100644
--- a/lib/lp/testing/gpgkeys/data/test@xxxxxxxxxxxxxxxxx
+++ b/lib/lp/testing/gpgkeys/data/test@xxxxxxxxxxxxxxxxx
@@ -1,5 +1,4 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
-Version: GnuPG v1.4.9 (GNU/Linux)
mQGiBEJdmOcRBADkNJPTBuCIefBdRAhvWyD9SSVHh8GHQWS7l9sRLEsirQkKz1yB
pjmskVK57sa9G8lamu15aj6nGOPf52oNIFjYcgrsbca65xOgP6KXHDDzv7rP27d/
@@ -12,18 +11,11 @@ pJQUChXxh3jDxMhNlNTxp9EKt8kI/mZGpzg3Q0oWQt7elSTCftVa97PYgLtPyh2b
mA5VAQ11NCzfp3ym2JQRI6RMl6twSHZS/Dy/dDCPTK1gCAQKw7QrU2FtcGxlIFBl
cnNvbiA8c2FtcGxlLnBlcnNvbkBjYW5vbmljYWwuY29tPoheBBMRAgAeBQJC0tXh
AhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJELork4nf0gVDKFMAoK2KaBBi+Y4V
-yReUQUo6ZK+qG+5LAJ9aO35LHBHYJkg52BSLsXNV5Bb/V4hGBBMRAgAGBQJDFWvr
-AAoJEI5+twhsZKjF3cUAoJu4yUtm6TXN1wzjl/RbhwaUL6lWAJ9wc9t92MpffbL1
-KfNM6LghI6ebZbQ2U2FtcGxlIFBlcnNvbiAocmV2b2tlZCkgPHNhbXBsZS5yZXZv
-a2VkQGNhbm9uaWNhbC5jb20+iEkEMBECAAkFAkLTAQ0CHSAACgkQuiuTid/SBUOR
-0QCgtLd3xoYpIHm3ansN4W1YrP1GvgMAnAvrmXORjansHdqoVbzab4r+OkhtiF4E
-ExECAB4FAkLS+rcCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQuiuTid/SBUNW
-IgCcCQgN2IL3nDSjQbZPiCRZPfxAgMcAnj2j7Pcv/lYPRh2f+6AjEv+8z3AVtCJT
-YW1wbGUgUGVyc29uIDx0ZXN0QGNhbm9uaWNhbC5jb20+iF4EExECAB4FAkJdmOcC
-GwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQuiuTid/SBUNH9wCdHos9BQYiJB2h
-XBU9erVtzEYFqpwAn1jD5TWgoa1ps1CxZf68SN9eohMBiEYEExECAAYFAkMVa+0A
-CgkQjn63CGxkqMWbagCgihA/L3W6ZQyJJlpIn7KeR+oFDxsAnjEgpY0vFH0tcKHX
-qK0GdDe1MfRviF4EExECAB4FAkJdmOcCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AA
+yReUQUo6ZK+qG+5LAJ9aO35LHBHYJkg52BSLsXNV5Bb/V7Q2U2FtcGxlIFBlcnNv
+biAocmV2b2tlZCkgPHNhbXBsZS5yZXZva2VkQGNhbm9uaWNhbC5jb20+iEkEMBEC
+AAkFAkLTAQ0CHSAACgkQuiuTid/SBUOR0QCgtLd3xoYpIHm3ansN4W1YrP1GvgMA
+nAvrmXORjansHdqoVbzab4r+OkhttCJTYW1wbGUgUGVyc29uIDx0ZXN0QGNhbm9u
+aWNhbC5jb20+iF4EExECAB4FAkJdmOcCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AA
CgkQuiuTid/SBUNH9wCdG+YqQqcC3g6VYH3fs1j+92euVWoAn2lwpWkyWlhDRmdt
HEaIupSOl/ZXuQENBEJdmOkQBADME8ONMc4DG5UcMKgv5zp5aXh8wjxQNi5Fs3Y0
emPpz8eBBQcaHVGOe8hlgwvNlYMx9UmK4QyFZz03KCKFC1yboDjLUljOTjL2VKVE
@@ -44,18 +36,6 @@ aLtFyrwxrc72M/ywGTwy6ld0gnk0ehierMQoiaw5Tz7DvZHyc3UNsCoefIu+42/4
r5jiwubQ7zebiJEEGBECAAkCGwIFAkle+W4AUkcgBBkRAgAGBQJC7YoZAAoJENsl
l1YCul72Kk4AnjK1epKVH9PULlNW+MBs2wk5WskDAKCtBcwsqSX1ioY3qfYDxp9H
r54A/wkQuiuTid/SBUOdtACfQOBN/qOqfd1RZUS2ClgskQ6Lj1gAn1PfyUE0IPyO
-vTCjK5DHonYE3RGYuQGiBEcE3OwRBAC6hpmpLoOt5I93ag2+TJB6kCS6M5bnxPOc
-78INa1907P/abfLOLLORlLy8fWWP3bsvooUxcmOVEGcqeGWPmDIiti4yBaOYyh73
-yhvRcwPSA5QItayLvmaxisEkeEzimCgpfO8Mn6nwV0sfNqGB+pfKhumj4HvChNtj
-0NjgaP85rwCgyFGhn+oyC6u8scemM7RbkM1B6JMD/iYh7rKna7br8/PIO6odeiCg
-6As/0FAsdIO2n9IT4My+HG7vTaHpFzjaRFCVv9AhtcEIZKbnfF84fckcVL0nDuEe
-jji03lnC5eGP8SO9V+xNNkGEKd4FKwSwHv2M0NyRTB3xzhsloNWH/u5ICFDbyF0Z
-JZAxkcBaCOayXiCsGjroBAC4Bxd+BZPxBNF1SMiwONS5i+hOPuTaOEaznOTATGw+
-aHwvSdYXq3U4n9wWZDNNLPlo5N0UAXOdDHAhc9dAeWqadExXTS8/r/ixK27Bheev
-x6ek5u1g+p72hFjGxRBtBIVOjKqXUVtVS1BYc1WBAOqk1h+wE4hm75y0g2BW4K5N
-64iRBBgRAgAJBQJHBNzsAhsCAFIJELork4nf0gVDRyAEGRECAAYFAkcE3OwACgkQ
-JGAU/m192yUzAQCgvh7ZenOdUeLO9ww+lZv62Hvy2Z4An3tUDMkgC5n+vfE7XbbF
-oC0u7EFkwAwAmgNfoEH3fcrpV0ZQxyDaTdlb4bL3AKCc4BDXu7gsrQ9F3gPEZ9GJ
-/GM63Q==
-=k5fr
+vTCjK5DHonYE3RGY
+=wc0B
-----END PGP PUBLIC KEY BLOCK-----
Follow ups