[elbe-devel] [PATCH v4 2/2] Replace gpgme with maintained gpg module

bage at linutronix.de bage at linutronix.de
Tue Feb 19 09:30:45 CET 2019


From: Bastian Germann <bage at linutronix.de>

The pygpgme project is abandoned for years and not
available in the upcoming Debian buster.

Replace pygpgme with the official gpgme Python wrapper
from GnuPG that is available as Debian's python-gpg.
Replace the package references in README and the Debian
build. Use the low-level op_* functions to also target
the wrapper's predecessor pyme (Debian jessie).

With this change, elbe can be installed on Debian buster.
This closes issue #192.

Signed-off-by: Bastian Germann <bage at linutronix.de>
---
 README.adoc              |  2 +-
 debian/control           |  2 --
 elbepack/debinstaller.py | 16 ++++++---
 elbepack/egpg.py         | 85 ++++++++++++++++++++++++++----------------------
 elbepack/finetuning.py   | 22 ++++++++-----
 5 files changed, 73 insertions(+), 54 deletions(-)

diff --git a/README.adoc b/README.adoc
index 397ba310..a28945dd 100644
--- a/README.adoc
+++ b/README.adoc
@@ -13,7 +13,7 @@ Software Dependencies
 ---------------------
 If using ELBE from git repository directly, you'll need following packages installed:
 
-    apt install python python-debian python-mako python-lxml python-apt python-gpgme python-pyme python-suds python-libvirt qemu-utils qemu-kvm p7zip-full make
+    apt install python python-debian python-mako python-lxml python-apt python-gpg python-suds python-libvirt qemu-utils qemu-kvm p7zip-full make
 
 
 Crash Course
diff --git a/debian/control b/debian/control
index a52a1305..f156e300 100644
--- a/debian/control
+++ b/debian/control
@@ -57,7 +57,6 @@ Depends: ${misc:Depends},
   python (>= 2.7~),
   python-lxml,
   python-apt,
-  python-gpgme,
   python-pyme|python-gpg,
   python-libvirt,
   wget,
@@ -73,7 +72,6 @@ Depends: ${misc:Depends},
   python3,
   python3-lxml,
   python3-apt,
-  python3-gpgme,
   python3-gpg,
   python3-libvirt,
   wget,
diff --git a/elbepack/debinstaller.py b/elbepack/debinstaller.py
index 1a46b353..6bd166ef 100644
--- a/elbepack/debinstaller.py
+++ b/elbepack/debinstaller.py
@@ -23,8 +23,12 @@ except ImportError:
     import urllib2
     urlopen = urllib2.urlopen
 
+try:
+    from gpg import core
+except ImportError:
+    from pyme import core
+
 from shutil import copyfileobj, copyfile
-from gpgme import Context
 
 from elbepack.filesystem import TmpdirFilesystem
 from elbepack.egpg import OverallStatus, check_signature
@@ -127,7 +131,7 @@ def download_release(tmp, base_url):
     # setup gpg context, for verifying
     # the Release.gpg signature.
     os.environ['GNUPGHOME'] = tmp.fname('/')
-    ctx = Context()
+    ctx = core.Context()
 
     # download the Relase file to a tmp file,
     # because we need it 2 times
@@ -144,14 +148,18 @@ def download_release(tmp, base_url):
             overall_status = OverallStatus()
 
             # verify detached signature
-            sigs = ctx.verify(sig, signed, None)
+            det_sign = core.Data(sig.read())
+            signed_data = core.Data(signed.read())
+            ctx.op_verify(det_sign, signed_data, None)
+            vres = ctx.op_verify_result()
 
-            for s in sigs:
+            for s in vres.signatures:
                 status = check_signature(ctx, s)
                 overall_status.add(status)
 
             if overall_status.to_exitcode():
                 raise InvalidSignature('Failed to verify Release file')
+
     finally:
         sig.close()
 
diff --git a/elbepack/egpg.py b/elbepack/egpg.py
index c56f22e5..019cdefa 100644
--- a/elbepack/egpg.py
+++ b/elbepack/egpg.py
@@ -9,7 +9,12 @@ from __future__ import print_function
 
 import os
 
-import gpgme
+try:
+    from gpg import core
+    from gpg.constants import sigsum, sig
+except ImportError:
+    from pyme import core
+    from pyme.constants import sigsum, sig
 
 from elbepack.filesystem import hostfs
 
@@ -34,7 +39,7 @@ class OverallStatus(object):
         self.sig_expired = False
         self.key_revoked = False
         self.key_missing = False
-        self.gpgme_error = False
+        self.gpg_error = False
 
     def add(self, to_add):
         self.invalid = self.invalid or to_add.invalid
@@ -42,10 +47,10 @@ class OverallStatus(object):
         self.sig_expired = self.sig_expired or to_add.sig_expired
         self.key_revoked = self.key_revoked or to_add.key_revoked
         self.key_missing = self.key_missing or to_add.key_missing
-        self.gpgme_error = self.gpgme_error or to_add.gpgme_error
+        self.gpg_error = self.gpg_error or to_add.gpg_error
 
     def to_exitcode(self):
-        if self.gpgme_error:    # critical GPG error
+        if self.gpg_error:      # critical GPG error
             return 20
         if self.invalid:        # invalid signature
             return 1
@@ -61,15 +66,15 @@ class OverallStatus(object):
 def check_signature(ctx, sig):
     status = OverallStatus()
 
-    if sig.summary & gpgme.SIGSUM_KEY_MISSING:
+    if sig.summary & sigsum.KEY_MISSING:
         print("Signature with unknown key: %s" % sig.fpr)
         status.key_missing = True
         return status
 
     # there should be a key
-    key = ctx.get_key(sig.fpr)
+    key = ctx.get_key(sig.fpr, 0)
     print("%s <%s> (%s):" % (key.uids[0].name, key.uids[0].email, sig.fpr))
-    if sig.summary & gpgme.SIGSUM_VALID == gpgme.SIGSUM_VALID:
+    if sig.summary & sigsum.VALID == sigsum.VALID:
         # signature fully valid and trusted
         print("VALID (Trusted)")
         return status
@@ -79,30 +84,30 @@ def check_signature(ctx, sig):
         # Signature is valid, but the key is not ultimately trusted,
         # see: http://www.gossamer-threads.com/lists/gnupg/users/52350
         print("VALID (Untrusted).")
-    if sig.summary & gpgme.SIGSUM_SIG_EXPIRED == gpgme.SIGSUM_SIG_EXPIRED:
+    if sig.summary & sigsum.SIG_EXPIRED == sigsum.SIG_EXPIRED:
         print("SIGNATURE EXPIRED!")
         status.sig_expired = True
-    if sig.summary & gpgme.SIGSUM_KEY_EXPIRED == gpgme.SIGSUM_KEY_EXPIRED:
+    if sig.summary & sigsum.KEY_EXPIRED == sigsum.KEY_EXPIRED:
         print("KEY EXPIRED!")
         status.key_expired = True
-    if sig.summary & gpgme.SIGSUM_KEY_REVOKED == gpgme.SIGSUM_KEY_REVOKED:
+    if sig.summary & sigsum.KEY_REVOKED == sigsum.KEY_REVOKED:
         print("KEY REVOKED!")
         status.key_revoked = True
-    if sig.summary & gpgme.SIGSUM_RED == gpgme.SIGSUM_RED:
+    if sig.summary & sigsum.RED == sigsum.RED:
         print("INVALID SIGNATURE!")
         status.invalid = True
-    if sig.summary & gpgme.SIGSUM_CRL_MISSING == gpgme.SIGSUM_CRL_MISSING:
+    if sig.summary & sigsum.CRL_MISSING == sigsum.CRL_MISSING:
         print("CRL MISSING!")
-        status.gpgme_error = True
-    if sig.summary & gpgme.SIGSUM_CRL_TOO_OLD == gpgme.SIGSUM_CRL_TOO_OLD:
+        status.gpg_error = True
+    if sig.summary & sigsum.CRL_TOO_OLD == sigsum.CRL_TOO_OLD:
         print("CRL TOO OLD!")
-        status.gpgme_error = True
-    if sig.summary & gpgme.SIGSUM_BAD_POLICY == gpgme.SIGSUM_BAD_POLICY:
+        status.gpg_error = True
+    if sig.summary & sigsum.BAD_POLICY == sigsum.BAD_POLICY:
         print("UNMET POLICY REQUIREMENT!")
-        status.gpgme_error = True
-    if sig.summary & gpgme.SIGSUM_SYS_ERROR == gpgme.SIGSUM_SYS_ERROR:
+        status.gpg_error = True
+    if sig.summary & sigsum.SYS_ERROR == sigsum.SYS_ERROR:
         print("SYSTEM ERROR!'")
-        status.gpgme_error = True
+        status.gpg_error = True
 
     return status
 
@@ -116,19 +121,20 @@ def unsign_file(fname):
     outfilename = fname[:len(fname) - 4]
 
     os.environ['GNUPGHOME'] = "/var/cache/elbe/gnupg"
-    ctx = gpgme.Context()
-    ctx.armor = False
+    ctx = core.Context()
+    ctx.set_armor(False)
 
     try:
         overall_status = OverallStatus()
 
-        with open(fname, 'r') as infile:
-            with open(outfilename, 'w') as outfile:
+        with core.Data(file=fname) as infile:
+            with core.Data(file=outfilename) as outfile:
 
                 # obtain signature and write unsigned file
-                sigs = ctx.verify(infile, None, outfile)
+                ctx.op_verify(infile, None, outfile)
+                vres = ctx.op_verify_result()
 
-                for sig in sigs:
+                for sig in vres.signatures:
                     status = check_signature(ctx, sig)
                     overall_status.add(status)
 
@@ -148,19 +154,21 @@ def unsign_file(fname):
 def sign(infile, outfile, fingerprint):
 
     os.environ['GNUPGHOME'] = "/var/cache/elbe/gnupg"
-    ctx = gpgme.Context()
+    ctx = core.Context()
     key = None
 
     try:
-        key = ctx.get_key(fingerprint)
-    except gpgme.GpgmeError as ex:
+        key = ctx.get_key(fingerprint, 0)
+    except Exception as ex:
         print("no key with fingerprint %s: %s" % (fingerprint, ex.message))
 
-    ctx.signers = [key]
-    ctx.armor = False
+    ctx.signers_add(key)
+    ctx.set_armor(False)
 
     try:
-        ctx.sign(infile, outfile, gpgme.SIG_MODE_NORMAL)
+        indata = core.Data(file=infile)
+        outdata = core.Data(file=outfile)
+        ctx.op_sign(indata, outdata, sig.mode.NORMAL)
     except Exception as ex:
         print("Error signing file %s" % ex.message)
 
@@ -178,8 +186,8 @@ def sign_file(fname, fingerprint):
 
 def get_fingerprints():
     os.environ['GNUPGHOME'] = "/var/cache/elbe/gnupg"
-    ctx = gpgme.Context()
-    keys = ctx.keylist()
+    ctx = core.Context()
+    keys = ctx.op_keylist_all(None, False)
     fingerprints = []
     for k in keys:
         fingerprints.append(k.subkeys[0].fpr)
@@ -189,19 +197,20 @@ def get_fingerprints():
 def generate_elbe_internal_key():
     hostfs.mkdir_p("/var/cache/elbe/gnupg")
     os.environ['GNUPGHOME'] = "/var/cache/elbe/gnupg"
-    ctx = gpgme.Context()
-    key = ctx.genkey(elbe_internal_key_param)
+    ctx = core.Context()
+    ctx.op_genkey(elbe_internal_key_param, None, None)
+    key = ctx.op_genkey_result()
 
     return key.fpr
 
 
 def export_key(fingerprint, outfile):
     os.environ['GNUPGHOME'] = "/var/cache/elbe/gnupg"
-    ctx = gpgme.Context()
-    ctx.armor = True
+    ctx = core.Context()
+    ctx.set_armor(True)
 
     try:
-        ctx.export(fingerprint, outfile)
+        ctx.op_export(fingerprint, 0, outfile)
     except Exception:
         print("Error exporting key %s" % (fingerprint))
 
diff --git a/elbepack/finetuning.py b/elbepack/finetuning.py
index 0d9a2824..14c57309 100644
--- a/elbepack/finetuning.py
+++ b/elbepack/finetuning.py
@@ -11,9 +11,11 @@ from __future__ import print_function
 import os
 
 from shutil import rmtree
-from io import BytesIO
 
-import gpgme
+try:
+    from gpg import core
+except ImportError:
+    from pyme import core
 
 from apt.package import FetchError
 
@@ -421,14 +423,16 @@ class UpdatedAction(FinetuningAction):
             log.printo("transfer gpg key to target: " + fp)
 
             os.environ['GNUPGHOME'] = "/var/cache/elbe/gnupg"
-            key = BytesIO()
-            ctx = gpgme.Context()
-            ctx.armor = True
-            ctx.export(fp, key)
-
-            log.printo(str(key.getvalue()))
+            gpgdata = core.Data()
+            ctx = core.Context()
+            ctx.set_armor(True)
+            ctx.op_export(fp, 0, gpgdata)
+            gpgdata.seek(0, os.SEEK_SET)
+            key = gpgdata.read()
+
+            log.printo(str(key))
             with open((target.path + '/pub.key'), 'wb') as tkey:
-                tkey.write(key.getvalue())
+                tkey.write(key)
 
             target.mkdir_p("/var/cache/elbe/gnupg", mode=0o700)
             with target:
-- 
2.11.0




More information about the elbe-devel mailing list