Openembedded Core Discussions
 help / color / mirror / Atom feed
* [PATCH v6 0/4] IPK signing for the gpg_sign module
@ 2016-02-19 15:45 Ioan-Adrian Ratiu
  2016-02-19 15:45 ` [PATCH v6 1/4] gpg_sign: add local ipk package signing functionality Ioan-Adrian Ratiu
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Ioan-Adrian Ratiu @ 2016-02-19 15:45 UTC (permalink / raw)
  To: openembedded-core

This patch series extends the gpg_sign module to support ipk signing.

v6 implements Markus' feedback. The most notable change is the sign_ipk
and detach_sign merger, as they were almost identical in functionality.
This also meant a refactoring for detach_sign and a bug fix for the
STDIN file descriptor introduced in gpg > 2.1.

Technically that STDIN bug is a feature (meh) of gpg >2.1 which breaks
existing behaviour so we have to work around it i.e. check the gpg
version and use the loopback interface. This means that gpg-agent to
which gpg >2.1 always connects needs to be running permanently.

Ioan-Adrian Ratiu (4):
  gpg_sign: add local ipk package signing functionality
  gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor
  gpg_sign: export_pubkey: add signature type support
  package_manager: sign IPK package feeds

 meta/classes/package_ipk.bbclass       |  5 +++
 meta/classes/sign_ipk.bbclass          | 52 ++++++++++++++++++++++++
 meta/classes/sign_package_feed.bbclass | 12 +++++-
 meta/lib/oe/gpg_sign.py                | 74 +++++++++++++++++++++++++++-------
 meta/lib/oe/package_manager.py         | 17 +++++++-
 5 files changed, 143 insertions(+), 17 deletions(-)
 create mode 100644 meta/classes/sign_ipk.bbclass

-- 
2.7.1



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v6 1/4] gpg_sign: add local ipk package signing functionality
  2016-02-19 15:45 [PATCH v6 0/4] IPK signing for the gpg_sign module Ioan-Adrian Ratiu
@ 2016-02-19 15:45 ` Ioan-Adrian Ratiu
  2016-02-23 10:25   ` Markus Lehtonen
  2016-02-19 15:45 ` [PATCH v6 2/4] gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor Ioan-Adrian Ratiu
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Ioan-Adrian Ratiu @ 2016-02-19 15:45 UTC (permalink / raw)
  To: openembedded-core

Implement ipk signing inside the sign_ipk bbclass using the gpg_sign
module and configure signing similar to how rpm does it. sign_ipk uses
gpg_sign's detach_sign because its functionality is identical to package
feed signing.

IPK signing process is a bit different from rpm:
    - Signatures are stored outside ipk files; opkg connects to a feed
server and downloads them to verify a package.
    - Signatures are of two types (both supported by opkg): binary or
ascii armoured. By default we sign using ascii armoured.
    - Public keys are stored on targets to verify ipks using the
opkg-keyrings recipe.

Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com>
---
 meta/classes/package_ipk.bbclass |  5 ++++
 meta/classes/sign_ipk.bbclass    | 52 ++++++++++++++++++++++++++++++++++++++++
 meta/lib/oe/gpg_sign.py          | 50 ++++++++++++++++++++++++++++----------
 3 files changed, 94 insertions(+), 13 deletions(-)
 create mode 100644 meta/classes/sign_ipk.bbclass

diff --git a/meta/classes/package_ipk.bbclass b/meta/classes/package_ipk.bbclass
index 51bee28..f64837a 100644
--- a/meta/classes/package_ipk.bbclass
+++ b/meta/classes/package_ipk.bbclass
@@ -246,6 +246,11 @@ python do_package_ipk () {
             bb.utils.unlockfile(lf)
             raise bb.build.FuncFailed("opkg-build execution failed")
 
+        if d.getVar('IPK_SIGN_PACKAGES', True) == '1':
+            ipkver = "%s-%s" % (d.getVar('PKGV'), d.getVar('PKGR'))
+            ipk_to_sign = "%s/%s_%s_%s.ipk" % (pkgoutdir, pkgname, ipkver, d.getVar('PACKAGE_ARCH', True))
+            sign_ipk(d, ipk_to_sign)
+
         cleanupcontrol(root)
         bb.utils.unlockfile(lf)
 
diff --git a/meta/classes/sign_ipk.bbclass b/meta/classes/sign_ipk.bbclass
new file mode 100644
index 0000000..a481f6d
--- /dev/null
+++ b/meta/classes/sign_ipk.bbclass
@@ -0,0 +1,52 @@
+# Class for generating signed IPK packages.
+#
+# Configuration variables used by this class:
+# IPK_GPG_PASSPHRASE_FILE
+#           Path to a file containing the passphrase of the signing key.
+# IPK_GPG_NAME
+#           Name of the key to sign with.
+# IPK_GPG_BACKEND
+#           Optional variable for specifying the backend to use for signing.
+#           Currently the only available option is 'local', i.e. local signing
+#           on the build host.
+# IPK_GPG_SIGNATURE_TYPE
+#           Optional variable for specifying the type of gpg signatures, can be:
+#                     1. Ascii armored (ASC), default if not set
+#                     2. Binary (BIN)
+# GPG_BIN
+#           Optional variable for specifying the gpg binary/wrapper to use for
+#           signing.
+# GPG_PATH
+#           Optional variable for specifying the gnupg "home" directory:
+#
+
+inherit sanity
+
+IPK_SIGN_PACKAGES = '1'
+IPK_GPG_BACKEND ?= 'local'
+IPK_GPG_SIGNATURE_TYPE ?= 'ASC'
+
+python () {
+    # Check configuration
+    for var in ('IPK_GPG_NAME', 'IPK_GPG_PASSPHRASE_FILE'):
+        if not d.getVar(var, True):
+            raise_sanity_error("You need to define %s in the config" % var, d)
+
+    sigtype = d.getVar("IPK_GPG_SIGNATURE_TYPE", True)
+    if sigtype.upper() != "ASC" and sigtype.upper() != "BIN":
+        raise_sanity_error("Bad value for IPK_GPG_SIGNATURE_TYPE (%s), use either ASC or BIN" % sigtype)
+}
+
+def sign_ipk(d, ipk_to_sign):
+    from oe.gpg_sign import get_signer
+
+    bb.debug(1, 'Signing ipk: %s' % ipk_to_sign)
+
+    signer = get_signer(d, d.getVar('IPK_GPG_BACKEND', True))
+    sig_type = d.getVar('IPK_GPG_SIGNATURE_TYPE', True)
+    is_ascii_sig = (sig_type.upper() != "BIN")
+
+    signer.detach_sign(ipk_to_sign,
+                       d.getVar('IPK_GPG_NAME', True),
+                       d.getVar('IPK_GPG_PASSPHRASE_FILE', True),
+                       armor=is_ascii_sig)
diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
index ada1b2f..ef47d1a 100644
--- a/meta/lib/oe/gpg_sign.py
+++ b/meta/lib/oe/gpg_sign.py
@@ -1,5 +1,6 @@
 """Helper module for GPG signing"""
 import os
+import sys
 
 import bb
 import oe.utils
@@ -50,6 +51,7 @@ class LocalSigner(object):
             bb.error('rpmsign failed: %s' % proc.before.strip())
             raise bb.build.FuncFailed("Failed to sign RPM packages")
 
+
     def detach_sign(self, input_file, keyid, passphrase_file, passphrase=None, armor=True):
         """Create a detached signature of a file"""
         import subprocess
@@ -57,23 +59,45 @@ class LocalSigner(object):
         if passphrase_file and passphrase:
             raise Exception("You should use either passphrase_file of passphrase, not both")
 
-        cmd = [self.gpg_bin, '--detach-sign', '--batch', '--no-tty', '--yes',
-               '-u', keyid]
-        if passphrase_file:
-            cmd += ['--passphrase-file', passphrase_file]
-        else:
-            cmd += ['--passphrase-fd', '0']
+        cmd = [self.gpg_bin, '--detach-sign', '--batch', '--no-tty', '--yes', '-u', keyid]
+
         if self.gpg_path:
             cmd += ['--homedir', self.gpg_path]
         if armor:
             cmd += ['--armor']
-        cmd.append(input_file)
-        job = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
-                               stderr=subprocess.PIPE)
-        _, stderr = job.communicate(passphrase)
-        if job.returncode:
-            raise bb.build.FuncFailed("Failed to create signature for '%s': %s" %
-                                      (input_file, stderr))
+
+        try:
+            keypipe = os.pipe()
+
+            if passphrase_file:
+                with open(passphrase_file) as fobj:
+                    os.write(keypipe[1], fobj.readline());
+            else:
+                os.write(keypipe[1], passphrase)
+
+            cmd += ["--passphrase-fd",  str(keypipe[0])]
+            cmd += [input_file]
+
+            job = subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
+            (_, stderr) = job.communicate(passphrase)
+
+            os.close(keypipe[1])
+            os.close(keypipe[0])
+
+            if job.returncode:
+                raise bb.build.FuncFailed("GPG exited with code %d: %s" %
+                                          (job.returncode, stderr))
+
+        except IOError as e:
+            bb.error("IO error (%s): %s" % (e.errno, e.strerror))
+            raise Exception("Failed to sign '%s'" % input_file)
+        except OSError as e:
+            bb.error("OS error (%s): %s" % (e.errno, e.strerror))
+            raise Exception("Failed to sign '%s" % input_file)
+        except:
+            bb.error("Unexpected error (%s): %s" % (sys.exc_info()[0], sys.exc_info()[1]))
+            raise Exception("Failed to sign '%s'" % input_file)
+
 
     def verify(self, sig_file):
         """Verify signature"""
-- 
2.7.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 2/4] gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor
  2016-02-19 15:45 [PATCH v6 0/4] IPK signing for the gpg_sign module Ioan-Adrian Ratiu
  2016-02-19 15:45 ` [PATCH v6 1/4] gpg_sign: add local ipk package signing functionality Ioan-Adrian Ratiu
@ 2016-02-19 15:45 ` Ioan-Adrian Ratiu
  2016-02-23 10:26   ` Markus Lehtonen
  2016-02-19 15:45 ` [PATCH v6 3/4] gpg_sign: export_pubkey: add signature type support Ioan-Adrian Ratiu
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Ioan-Adrian Ratiu @ 2016-02-19 15:45 UTC (permalink / raw)
  To: openembedded-core

Starting from v2.1 passing passwords directly to gpg does not work
anymore [1], instead a loopback interface must be used otherwise
gpg >2.1 will error out with:
"gpg: signing failed: Inappropriate ioctl for device"

gpg <2.1 does not work with the new --pinentry-mode arg and gives an
invalid option error, so we detect what is the running version of gpg
and pass it accordingly.

[1] https://wiki.archlinux.org/index.php/GnuPG#Unattended_passphrase

Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com>
---
 meta/lib/oe/gpg_sign.py | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
index ef47d1a..9f6b0f0 100644
--- a/meta/lib/oe/gpg_sign.py
+++ b/meta/lib/oe/gpg_sign.py
@@ -66,6 +66,12 @@ class LocalSigner(object):
         if armor:
             cmd += ['--armor']
 
+        #gpg > 2.1 supports password pipes only through the loopback interface
+        #gpg < 2.1 errors out if given unknown parameters
+        gpg_ver = self.get_gpg_version()
+        if gpg_ver > 2.1:
+            cmd += ['--pinentry-mode', 'loopback']
+
         try:
             keypipe = os.pipe()
 
@@ -99,6 +105,20 @@ class LocalSigner(object):
             raise Exception("Failed to sign '%s'" % input_file)
 
 
+    def get_gpg_version(self):
+        """Return the gpg version"""
+        import subprocess
+
+        job = subprocess.Popen([self.gpg_bin, "--version"], stdout=subprocess.PIPE)
+        (stdout, _) = job.communicate()
+
+        if job.returncode:
+            raise bb.build.FuncFailed("Could not get gpg version (is %s installed?)" %
+                                      self.gpg_bin)
+
+        return stdout.split()[2]
+
+
     def verify(self, sig_file):
         """Verify signature"""
         cmd = self.gpg_bin + " --verify "
-- 
2.7.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 3/4] gpg_sign: export_pubkey: add signature type support
  2016-02-19 15:45 [PATCH v6 0/4] IPK signing for the gpg_sign module Ioan-Adrian Ratiu
  2016-02-19 15:45 ` [PATCH v6 1/4] gpg_sign: add local ipk package signing functionality Ioan-Adrian Ratiu
  2016-02-19 15:45 ` [PATCH v6 2/4] gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor Ioan-Adrian Ratiu
@ 2016-02-19 15:45 ` Ioan-Adrian Ratiu
  2016-02-19 15:45 ` [PATCH v6 4/4] package_manager: sign IPK package feeds Ioan-Adrian Ratiu
  2016-02-23 10:28 ` [PATCH v6 0/4] IPK signing for the gpg_sign module Markus Lehtonen
  4 siblings, 0 replies; 8+ messages in thread
From: Ioan-Adrian Ratiu @ 2016-02-19 15:45 UTC (permalink / raw)
  To: openembedded-core

Add support for multiple types of signatures (binary or ascii)
in export_pubkey(). There is no change in behaviour for the function,
the previous implicit default is the new parameter "armor" default.

Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com>
---
 meta/lib/oe/gpg_sign.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
index 9f6b0f0..9b3864a 100644
--- a/meta/lib/oe/gpg_sign.py
+++ b/meta/lib/oe/gpg_sign.py
@@ -13,12 +13,14 @@ class LocalSigner(object):
         self.gpg_path = d.getVar('GPG_PATH', True)
         self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm")
 
-    def export_pubkey(self, output_file, keyid):
+    def export_pubkey(self, output_file, keyid, armor=True):
         """Export GPG public key to a file"""
-        cmd = '%s --batch --yes --export --armor -o %s ' % \
+        cmd = '%s --batch --yes --export -o %s ' % \
                 (self.gpg_bin, output_file)
         if self.gpg_path:
             cmd += "--homedir %s " % self.gpg_path
+        if armor:
+            cmd += "--armor "
         cmd += keyid
         status, output = oe.utils.getstatusoutput(cmd)
         if status:
-- 
2.7.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 4/4] package_manager: sign IPK package feeds
  2016-02-19 15:45 [PATCH v6 0/4] IPK signing for the gpg_sign module Ioan-Adrian Ratiu
                   ` (2 preceding siblings ...)
  2016-02-19 15:45 ` [PATCH v6 3/4] gpg_sign: export_pubkey: add signature type support Ioan-Adrian Ratiu
@ 2016-02-19 15:45 ` Ioan-Adrian Ratiu
  2016-02-23 10:28 ` [PATCH v6 0/4] IPK signing for the gpg_sign module Markus Lehtonen
  4 siblings, 0 replies; 8+ messages in thread
From: Ioan-Adrian Ratiu @ 2016-02-19 15:45 UTC (permalink / raw)
  To: openembedded-core

Create gpg signed ipk package feeds using the gpg backend if configured.

Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com>
---
 meta/classes/sign_package_feed.bbclass | 12 +++++++++++-
 meta/lib/oe/package_manager.py         | 17 +++++++++++++++--
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/meta/classes/sign_package_feed.bbclass b/meta/classes/sign_package_feed.bbclass
index 63ca02f..85c37f3 100644
--- a/meta/classes/sign_package_feed.bbclass
+++ b/meta/classes/sign_package_feed.bbclass
@@ -10,6 +10,12 @@
 #           Optional variable for specifying the backend to use for signing.
 #           Currently the only available option is 'local', i.e. local signing
 #           on the build host.
+# PACKAGE_FEED_GPG_SIGNATURE_TYPE
+#           Optional variable for specifying the type of gpg signature, can be:
+#               1. Ascii armored (ASC), default if not set
+#               2. Binary (BIN)
+#           This variable is only available for IPK feeds. It is ignored on
+#           other packaging backends.
 # GPG_BIN
 #           Optional variable for specifying the gpg binary/wrapper to use for
 #           signing.
@@ -20,7 +26,7 @@ inherit sanity
 
 PACKAGE_FEED_SIGN = '1'
 PACKAGE_FEED_GPG_BACKEND ?= 'local'
-
+PACKAGE_FEED_GPG_SIGNATURE_TYPE ?= 'ASC'
 
 python () {
     # Check sanity of configuration
@@ -28,6 +34,10 @@ python () {
         if not d.getVar(var, True):
             raise_sanity_error("You need to define %s in the config" % var, d)
 
+    sigtype = d.getVar("PACKAGE_FEED_GPG_SIGNATURE_TYPE", True)
+    if sigtype.upper() != "ASC" and sigtype.upper() != "BIN":
+        raise_sanity_error("Bad value for PACKAGE_FEED_GPG_SIGNATURE_TYPE (%s), use either ASC or BIN" % sigtype)
+
     # Set expected location of the public key
     d.setVar('PACKAGE_FEED_GPG_PUBKEY',
              os.path.join(d.getVar('STAGING_ETCDIR_NATIVE', False),
diff --git a/meta/lib/oe/package_manager.py b/meta/lib/oe/package_manager.py
index b30a4da..606ba24 100644
--- a/meta/lib/oe/package_manager.py
+++ b/meta/lib/oe/package_manager.py
@@ -163,11 +163,16 @@ class OpkgIndexer(Indexer):
                      "MULTILIB_ARCHS"]
 
         opkg_index_cmd = bb.utils.which(os.getenv('PATH'), "opkg-make-index")
+        if self.d.getVar('PACKAGE_FEED_SIGN', True) == '1':
+            signer = get_signer(self.d, self.d.getVar('PACKAGE_FEED_GPG_BACKEND', True))
+        else:
+            signer = None
 
         if not os.path.exists(os.path.join(self.deploy_dir, "Packages")):
             open(os.path.join(self.deploy_dir, "Packages"), "w").close()
 
         index_cmds = []
+        index_sign_files = []
         for arch_var in arch_vars:
             archs = self.d.getVar(arch_var, True)
             if archs is None:
@@ -186,6 +191,8 @@ class OpkgIndexer(Indexer):
                 index_cmds.append('%s -r %s -p %s -m %s' %
                                   (opkg_index_cmd, pkgs_file, pkgs_file, pkgs_dir))
 
+                index_sign_files.append(pkgs_file)
+
         if len(index_cmds) == 0:
             bb.note("There are no packages in %s!" % self.deploy_dir)
             return
@@ -193,9 +200,15 @@ class OpkgIndexer(Indexer):
         result = oe.utils.multiprocess_exec(index_cmds, create_index)
         if result:
             bb.fatal('%s' % ('\n'.join(result)))
-        if self.d.getVar('PACKAGE_FEED_SIGN', True) == '1':
-            raise NotImplementedError('Package feed signing not implementd for ipk')
 
+        if signer:
+            feed_sig_type = self.d.getVar('PACKAGE_FEED_GPG_SIGNATURE_TYPE', True)
+            is_ascii_sig = (feed_sig_type.upper() != "BIN")
+            for f in index_sign_files:
+                signer.detach_sign(f,
+                                   self.d.getVar('PACKAGE_FEED_GPG_NAME', True),
+                                   self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE', True),
+                                   armor=is_ascii_sig)
 
 
 class DpkgIndexer(Indexer):
-- 
2.7.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 1/4] gpg_sign: add local ipk package signing functionality
  2016-02-19 15:45 ` [PATCH v6 1/4] gpg_sign: add local ipk package signing functionality Ioan-Adrian Ratiu
@ 2016-02-23 10:25   ` Markus Lehtonen
  0 siblings, 0 replies; 8+ messages in thread
From: Markus Lehtonen @ 2016-02-23 10:25 UTC (permalink / raw)
  To: Ioan-Adrian Ratiu, openembedded-core

Hi,

Resending as my I got a strange "Only members may post to the list."
error yesterday...

On Fri, 2016-02-19 at 17:43 +0200, Ioan-Adrian Ratiu wrote:
> Implement ipk signing inside the sign_ipk bbclass using the gpg_sign
> module and configure signing similar to how rpm does it. sign_ipk
> uses
> gpg_sign's detach_sign because its functionality is identical to
> package
> feed signing.
> 
> IPK signing process is a bit different from rpm:
>     - Signatures are stored outside ipk files; opkg connects to a
> feed
> server and downloads them to verify a package.
>     - Signatures are of two types (both supported by opkg): binary or
> ascii armoured. By default we sign using ascii armoured.
>     - Public keys are stored on targets to verify ipks using the
> opkg-keyrings recipe.
> 
> Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com>
> ---
>  meta/classes/package_ipk.bbclass |  5 ++++
>  meta/classes/sign_ipk.bbclass    | 52
> ++++++++++++++++++++++++++++++++++++++++
>  meta/lib/oe/gpg_sign.py          | 50 ++++++++++++++++++++++++++++--
> --------
>  3 files changed, 94 insertions(+), 13 deletions(-)
>  create mode 100644 meta/classes/sign_ipk.bbclass
> 
> diff --git a/meta/classes/package_ipk.bbclass
> b/meta/classes/package_ipk.bbclass
> index 51bee28..f64837a 100644
> --- a/meta/classes/package_ipk.bbclass
> +++ b/meta/classes/package_ipk.bbclass
> @@ -246,6 +246,11 @@ python do_package_ipk () {
>              bb.utils.unlockfile(lf)
>              raise bb.build.FuncFailed("opkg-build execution failed")
>  
> +        if d.getVar('IPK_SIGN_PACKAGES', True) == '1':
> +            ipkver = "%s-%s" % (d.getVar('PKGV'), d.getVar('PKGR'))
> +            ipk_to_sign = "%s/%s_%s_%s.ipk" % (pkgoutdir, pkgname,
> ipkver, d.getVar('PACKAGE_ARCH', True))
> +            sign_ipk(d, ipk_to_sign)
> +
>          cleanupcontrol(root)
>          bb.utils.unlockfile(lf)
>  
> diff --git a/meta/classes/sign_ipk.bbclass
> b/meta/classes/sign_ipk.bbclass
> new file mode 100644
> index 0000000..a481f6d
> --- /dev/null
> +++ b/meta/classes/sign_ipk.bbclass
> @@ -0,0 +1,52 @@
> +# Class for generating signed IPK packages.
> +#
> +# Configuration variables used by this class:
> +# IPK_GPG_PASSPHRASE_FILE
> +#           Path to a file containing the passphrase of the signing
> key.
> +# IPK_GPG_NAME
> +#           Name of the key to sign with.
> +# IPK_GPG_BACKEND
> +#           Optional variable for specifying the backend to use for
> signing.
> +#           Currently the only available option is 'local', i.e.
> local signing
> +#           on the build host.
> +# IPK_GPG_SIGNATURE_TYPE
> +#           Optional variable for specifying the type of gpg
> signatures, can be:
> +#                     1. Ascii armored (ASC), default if not set
> +#                     2. Binary (BIN)
> +# GPG_BIN
> +#           Optional variable for specifying the gpg binary/wrapper
> to use for
> +#           signing.
> +# GPG_PATH
> +#           Optional variable for specifying the gnupg "home"
> directory:
> +#
> +
> +inherit sanity
> +
> +IPK_SIGN_PACKAGES = '1'
> +IPK_GPG_BACKEND ?= 'local'
> +IPK_GPG_SIGNATURE_TYPE ?= 'ASC'
> +
> +python () {
> +    # Check configuration
> +    for var in ('IPK_GPG_NAME', 'IPK_GPG_PASSPHRASE_FILE'):
> +        if not d.getVar(var, True):
> +            raise_sanity_error("You need to define %s in the config"
> % var, d)
> +
> +    sigtype = d.getVar("IPK_GPG_SIGNATURE_TYPE", True)
> +    if sigtype.upper() != "ASC" and sigtype.upper() != "BIN":
> +        raise_sanity_error("Bad value for IPK_GPG_SIGNATURE_TYPE
> (%s), use either ASC or BIN" % sigtype)
> +}
> +
> +def sign_ipk(d, ipk_to_sign):
> +    from oe.gpg_sign import get_signer
> +
> +    bb.debug(1, 'Signing ipk: %s' % ipk_to_sign)
> +
> +    signer = get_signer(d, d.getVar('IPK_GPG_BACKEND', True))
> +    sig_type = d.getVar('IPK_GPG_SIGNATURE_TYPE', True)
> +    is_ascii_sig = (sig_type.upper() != "BIN")
> +
> +    signer.detach_sign(ipk_to_sign,
> +                       d.getVar('IPK_GPG_NAME', True),
> +                       d.getVar('IPK_GPG_PASSPHRASE_FILE', True),
> +                       armor=is_ascii_sig)
> diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
> index ada1b2f..ef47d1a 100644
> --- a/meta/lib/oe/gpg_sign.py
> +++ b/meta/lib/oe/gpg_sign.py
> @@ -1,5 +1,6 @@
>  """Helper module for GPG signing"""
>  import os
> +import sys
>  
>  import bb
>  import oe.utils
> @@ -50,6 +51,7 @@ class LocalSigner(object):
>              bb.error('rpmsign failed: %s' % proc.before.strip())
>              raise bb.build.FuncFailed("Failed to sign RPM packages")
>  
> +
>      def detach_sign(self, input_file, keyid, passphrase_file,
> passphrase=None, armor=True):
>          """Create a detached signature of a file"""
>          import subprocess
> @@ -57,23 +59,45 @@ class LocalSigner(object):
>          if passphrase_file and passphrase:
>              raise Exception("You should use either passphrase_file
> of passphrase, not both")
>  
> -        cmd = [self.gpg_bin, '--detach-sign', '--batch', '--no-tty',
> '--yes',
> -               '-u', keyid]
> -        if passphrase_file:
> -            cmd += ['--passphrase-file', passphrase_file]
> -        else:
> -            cmd += ['--passphrase-fd', '0']
> +        cmd = [self.gpg_bin, '--detach-sign', '--batch', '--no-tty',
> '--yes', '-u', keyid]
> +
>          if self.gpg_path:
>              cmd += ['--homedir', self.gpg_path]
>          if armor:
>              cmd += ['--armor']
> -        cmd.append(input_file)
> -        job = subprocess.Popen(cmd, stdin=subprocess.PIPE,
> stdout=subprocess.PIPE,
> -                               stderr=subprocess.PIPE)
> -        _, stderr = job.communicate(passphrase)
> -        if job.returncode:
> -            raise bb.build.FuncFailed("Failed to create signature
> for '%s': %s" %
> -                                      (input_file, stderr))
> +
> +        try:
> +            keypipe = os.pipe()
> +
> +            if passphrase_file:
> +                with open(passphrase_file) as fobj:
> +                    os.write(keypipe[1], fobj.readline());
> +            else:
> +                os.write(keypipe[1], passphrase)
> +
> +            cmd += ["--passphrase-fd",  str(keypipe[0])]
> +            cmd += [input_file]
> +
> +            job = subprocess.Popen(cmd, stdin=subprocess.PIPE,
> stderr=subprocess.PIPE)
> +            (_, stderr) = job.communicate(passphrase)
> +
> +            os.close(keypipe[1])
> +            os.close(keypipe[0])

I still fail to see why you want to complicate the code with os.pipe.
Why not ditch pipe and just do something like:
    if passphrase_file:
        with open(passphrase_file) as fobj:
            _, stderr = job.communicate(fobj.readline())



Thanks,
  Markus



> +
> +            if job.returncode:
> +                raise bb.build.FuncFailed("GPG exited with code %d:
> %s" %
> +                                          (job.returncode, stderr))
> +
> +        except IOError as e:
> +            bb.error("IO error (%s): %s" % (e.errno, e.strerror))
> +            raise Exception("Failed to sign '%s'" % input_file)
> +        except OSError as e:
> +            bb.error("OS error (%s): %s" % (e.errno, e.strerror))
> +            raise Exception("Failed to sign '%s" % input_file)
> +        except:
> +            bb.error("Unexpected error (%s): %s" %
> (sys.exc_info()[0], sys.exc_info()[1]))
> +            raise Exception("Failed to sign '%s'" % input_file)
> +
>  
>      def verify(self, sig_file):
>          """Verify signature"""


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 2/4] gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor
  2016-02-19 15:45 ` [PATCH v6 2/4] gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor Ioan-Adrian Ratiu
@ 2016-02-23 10:26   ` Markus Lehtonen
  0 siblings, 0 replies; 8+ messages in thread
From: Markus Lehtonen @ 2016-02-23 10:26 UTC (permalink / raw)
  To: Ioan-Adrian Ratiu, openembedded-core

Hi,

Resending as my I got a strange "Only members may post to the list."
error yesterday...

On Fri, 2016-02-19 at 17:43 +0200, Ioan-Adrian Ratiu wrote:
> Starting from v2.1 passing passwords directly to gpg does not work
> anymore [1], instead a loopback interface must be used otherwise
> gpg >2.1 will error out with:
> "gpg: signing failed: Inappropriate ioctl for device"
> 
> gpg <2.1 does not work with the new --pinentry-mode arg and gives an
> invalid option error, so we detect what is the running version of gpg
> and pass it accordingly.
> 
> [1] https://wiki.archlinux.org/index.php/GnuPG#Unattended_passphrase
> 
> Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com>
> ---
>  meta/lib/oe/gpg_sign.py | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
> index ef47d1a..9f6b0f0 100644
> --- a/meta/lib/oe/gpg_sign.py
> +++ b/meta/lib/oe/gpg_sign.py
> @@ -66,6 +66,12 @@ class LocalSigner(object):
>          if armor:
>              cmd += ['--armor']
>  
> +        #gpg > 2.1 supports password pipes only through the loopback
> interface
> +        #gpg < 2.1 errors out if given unknown parameters
> +        gpg_ver = self.get_gpg_version()
> +        if gpg_ver > 2.1:
> +            cmd += ['--pinentry-mode', 'loopback']
> +

As far as I can tell get_gpg_version returns a string. However, you
compare that with a float. This should give more correct behavior:
+        if gpg_ver > "2.1":



Thanks,
  Markus


>          try:
>              keypipe = os.pipe()
>  
> @@ -99,6 +105,20 @@ class LocalSigner(object):
>              raise Exception("Failed to sign '%s'" % input_file)
>  
>  
> +    def get_gpg_version(self):
> +        """Return the gpg version"""
> +        import subprocess
> +
> +        job = subprocess.Popen([self.gpg_bin, "--version"],
> stdout=subprocess.PIPE)
> +        (stdout, _) = job.communicate()
> +
> +        if job.returncode:
> +            raise bb.build.FuncFailed("Could not get gpg version (is
> %s installed?)" %
> +                                      self.gpg_bin)
> +
> +        return stdout.split()[2]
> +
> +
>      def verify(self, sig_file):
>          """Verify signature"""
>          cmd = self.gpg_bin + " --verify "


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 0/4] IPK signing for the gpg_sign module
  2016-02-19 15:45 [PATCH v6 0/4] IPK signing for the gpg_sign module Ioan-Adrian Ratiu
                   ` (3 preceding siblings ...)
  2016-02-19 15:45 ` [PATCH v6 4/4] package_manager: sign IPK package feeds Ioan-Adrian Ratiu
@ 2016-02-23 10:28 ` Markus Lehtonen
  4 siblings, 0 replies; 8+ messages in thread
From: Markus Lehtonen @ 2016-02-23 10:28 UTC (permalink / raw)
  To: Ioan-Adrian Ratiu, openembedded-core

Hi,
Resending as my I got a strange "Only members may post to the list."
error yesterday...

On Fri, 2016-02-19 at 17:45 +0200, Ioan-Adrian Ratiu wrote:
> This patch series extends the gpg_sign module to support ipk signing.
> 
> v6 implements Markus' feedback. The most notable change is the
> sign_ipk
> and detach_sign merger, as they were almost identical in
> functionality.
> This also meant a refactoring for detach_sign and a bug fix for the
> STDIN file descriptor introduced in gpg > 2.1.
> 
> Technically that STDIN bug is a feature (meh) of gpg >2.1 which
> breaks
> existing behaviour so we have to work around it i.e. check the gpg
> version and use the loopback interface. This means that gpg-agent to
> which gpg >2.1 always connects needs to be running permanently.
> 
> Ioan-Adrian Ratiu (4):
>   gpg_sign: add local ipk package signing functionality
>   gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor
>   gpg_sign: export_pubkey: add signature type support
>   package_manager: sign IPK package feeds
> 
>  meta/classes/package_ipk.bbclass       |  5 +++
>  meta/classes/sign_ipk.bbclass          | 52 ++++++++++++++++++++++++
>  meta/classes/sign_package_feed.bbclass | 12 +++++-
>  meta/lib/oe/gpg_sign.py                | 74
> +++++++++++++++++++++++++++-------
>  meta/lib/oe/package_manager.py         | 17 +++++++-
>  5 files changed, 143 insertions(+), 17 deletions(-)
>  create mode 100644 meta/classes/sign_ipk.bbclass

I just realized that it would be good to add the ipk signing key to the
signing_keys.bb recipe.

However, it'd probably be good to write it on top of Randy Witt's
rework:
http://lists.openembedded.org/pipermail/openembedded-core/2016-February
/117791.html


Thanks,
 Markus


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-02-23 10:28 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-02-19 15:45 [PATCH v6 0/4] IPK signing for the gpg_sign module Ioan-Adrian Ratiu
2016-02-19 15:45 ` [PATCH v6 1/4] gpg_sign: add local ipk package signing functionality Ioan-Adrian Ratiu
2016-02-23 10:25   ` Markus Lehtonen
2016-02-19 15:45 ` [PATCH v6 2/4] gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor Ioan-Adrian Ratiu
2016-02-23 10:26   ` Markus Lehtonen
2016-02-19 15:45 ` [PATCH v6 3/4] gpg_sign: export_pubkey: add signature type support Ioan-Adrian Ratiu
2016-02-19 15:45 ` [PATCH v6 4/4] package_manager: sign IPK package feeds Ioan-Adrian Ratiu
2016-02-23 10:28 ` [PATCH v6 0/4] IPK signing for the gpg_sign module Markus Lehtonen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox