All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] Support remote RPM signing
@ 2016-01-11 16:13 Markus Lehtonen
  2016-01-11 16:13 ` [PATCH 1/3] sign_rpm.bbclass: fix task dependencies Markus Lehtonen
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Markus Lehtonen @ 2016-01-11 16:13 UTC (permalink / raw)
  To: openembedded-core

This patchset enables remote signing of RPM packages and package feeds using
the obs-signd signing server from openSUSE.
https://github.com/openSUSE/obs-sign
https://en.opensuse.org/openSUSE:Build_Service_Signer

Other remote signing methods should be easy to add, later.

The first patch of the series is a generic task dependency bugfix for rpm
signing.


The following changes since commit 95fced137a46dc98863fe5af7be5cbce708602f2:

  udev-extraconf: introduce multiple blacklist files for more complex setups (2016-01-05 17:55:05 +0000)

are available in the git repository at:

  git://git.openembedded.org/openembedded-core-contrib marquiz/rpmsign

for you to fetch changes up to 3ac8c3e5ab0dd6cab1438efd4484e0e313e55d8d:

  oe.gpg_sign: support obs-signd (2016-01-11 18:00:19 +0200)

Markus Lehtonen (3):
  sign_rpm.bbclass: fix task dependencies
  New lib module for handling GPG signing
  oe.gpg_sign: support obs-signd

 meta/classes/sign_package_feed.bbclass |  11 ++-
 meta/classes/sign_rpm.bbclass          |  53 +++++---------
 meta/lib/oe/gpg_sign.py                | 124 +++++++++++++++++++++++++++++++++
 meta/lib/oe/package_manager.py         |  31 +++------
 meta/recipes-core/meta/signing-keys.bb |  26 ++++---
 5 files changed, 173 insertions(+), 72 deletions(-)
 create mode 100644 meta/lib/oe/gpg_sign.py

-- 
2.1.4



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

* [PATCH 1/3] sign_rpm.bbclass: fix task dependencies
  2016-01-11 16:13 [PATCH 0/3] Support remote RPM signing Markus Lehtonen
@ 2016-01-11 16:13 ` Markus Lehtonen
  2016-01-11 16:13 ` [PATCH 2/3] New lib module for handling GPG signing Markus Lehtonen
  2016-01-11 16:13 ` [PATCH 3/3] oe.gpg_sign: support obs-signd Markus Lehtonen
  2 siblings, 0 replies; 12+ messages in thread
From: Markus Lehtonen @ 2016-01-11 16:13 UTC (permalink / raw)
  To: openembedded-core

do_rootfs task needs to depend on signing-keys:do_export_public_keys.
The rpm signing public key needs to be present in order to prevent a
crash because it is imported into the rootfs rpmdb before rootfs
creation starts.

Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
---
 meta/classes/sign_rpm.bbclass | 1 +
 1 file changed, 1 insertion(+)

diff --git a/meta/classes/sign_rpm.bbclass b/meta/classes/sign_rpm.bbclass
index bc916a7..7906b64 100644
--- a/meta/classes/sign_rpm.bbclass
+++ b/meta/classes/sign_rpm.bbclass
@@ -71,3 +71,4 @@ python sign_rpm () {
 }
 
 do_package_index[depends] += "signing-keys:do_export_public_keys"
+do_rootfs[depends] += "signing-keys:do_export_public_keys"
-- 
2.1.4



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

* [PATCH 2/3] New lib module for handling GPG signing
  2016-01-11 16:13 [PATCH 0/3] Support remote RPM signing Markus Lehtonen
  2016-01-11 16:13 ` [PATCH 1/3] sign_rpm.bbclass: fix task dependencies Markus Lehtonen
@ 2016-01-11 16:13 ` Markus Lehtonen
  2016-01-11 16:13 ` [PATCH 3/3] oe.gpg_sign: support obs-signd Markus Lehtonen
  2 siblings, 0 replies; 12+ messages in thread
From: Markus Lehtonen @ 2016-01-11 16:13 UTC (permalink / raw)
  To: openembedded-core

Add a new Python module (oe.gpg_sign) for handling GPG signing
operations, i.e. currently package and package feed signing. The
purpose is to be able to more easily support various signing backends.
Currently, only local on-the-build-host signing is implemented.

[YOCTO #8755]

Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
---
 meta/classes/sign_package_feed.bbclass |  6 +++
 meta/classes/sign_rpm.bbclass          | 47 +++++----------------
 meta/lib/oe/gpg_sign.py                | 76 ++++++++++++++++++++++++++++++++++
 meta/lib/oe/package_manager.py         | 31 +++++---------
 meta/recipes-core/meta/signing-keys.bb | 26 ++++++------
 5 files changed, 116 insertions(+), 70 deletions(-)
 create mode 100644 meta/lib/oe/gpg_sign.py

diff --git a/meta/classes/sign_package_feed.bbclass b/meta/classes/sign_package_feed.bbclass
index d89bc0b..d5df8af 100644
--- a/meta/classes/sign_package_feed.bbclass
+++ b/meta/classes/sign_package_feed.bbclass
@@ -6,6 +6,10 @@
 #           Path to a file containing the passphrase of the signing key.
 # PACKAGE_FEED_GPG_NAME
 #           Name of the key to sign with. May be key id or key name.
+# PACKAGE_FEED_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.
 # GPG_BIN
 #           Optional variable for specifying the gpg binary/wrapper to use for
 #           signing.
@@ -15,6 +19,8 @@
 inherit sanity
 
 PACKAGE_FEED_SIGN = '1'
+PACKAGE_FEED_GPG_BACKEND ?= 'local'
+
 
 python () {
     # Check sanity of configuration
diff --git a/meta/classes/sign_rpm.bbclass b/meta/classes/sign_rpm.bbclass
index 7906b64..8bcabee 100644
--- a/meta/classes/sign_rpm.bbclass
+++ b/meta/classes/sign_rpm.bbclass
@@ -5,6 +5,10 @@
 #           Path to a file containing the passphrase of the signing key.
 # RPM_GPG_NAME
 #           Name of the key to sign with. May be key id or key name.
+# RPM_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.
 # GPG_BIN
 #           Optional variable for specifying the gpg binary/wrapper to use for
 #           signing.
@@ -14,6 +18,7 @@
 inherit sanity
 
 RPM_SIGN_PACKAGES='1'
+RPM_GPG_BACKEND ?= 'local'
 
 
 python () {
@@ -27,47 +32,17 @@ python () {
                                             'RPM-GPG-PUBKEY'))
 }
 
-
-def rpmsign_wrapper(d, files, passphrase, gpg_name=None):
-    import pexpect
-
-    # Find the correct rpm binary
-    rpm_bin_path = d.getVar('STAGING_BINDIR_NATIVE', True) + '/rpm'
-    cmd = rpm_bin_path + " --addsign --define '_gpg_name %s' " % gpg_name
-    if d.getVar('GPG_BIN', True):
-        cmd += "--define '%%__gpg %s' " % d.getVar('GPG_BIN', True)
-    if d.getVar('GPG_PATH', True):
-        cmd += "--define '_gpg_path %s' " % d.getVar('GPG_PATH', True)
-    cmd += ' '.join(files)
-
-    # Need to use pexpect for feeding the passphrase
-    proc = pexpect.spawn(cmd)
-    try:
-        proc.expect_exact('Enter pass phrase:', timeout=15)
-        proc.sendline(passphrase)
-        proc.expect(pexpect.EOF, timeout=900)
-        proc.close()
-    except pexpect.TIMEOUT as err:
-        bb.warn('rpmsign timeout: %s' % err)
-        proc.terminate()
-    else:
-        if os.WEXITSTATUS(proc.status) or not os.WIFEXITED(proc.status):
-            bb.warn('rpmsign failed: %s' % proc.before.strip())
-    return proc.exitstatus
-
-
 python sign_rpm () {
     import glob
+    from oe.gpg_sign import get_signer
 
-    with open(d.getVar("RPM_GPG_PASSPHRASE_FILE", True)) as fobj:
-        rpm_gpg_passphrase = fobj.readlines()[0].rstrip('\n')
-
-    rpm_gpg_name = (d.getVar("RPM_GPG_NAME", True) or "")
-
+    signer = get_signer(d,
+                        d.getVar('RPM_GPG_BACKEND', True),
+                        d.getVar('RPM_GPG_NAME', True),
+                        d.getVar('RPM_GPG_PASSPHRASE_FILE', True))
     rpms = glob.glob(d.getVar('RPM_PKGWRITEDIR', True) + '/*')
 
-    if rpmsign_wrapper(d, rpms, rpm_gpg_passphrase, rpm_gpg_name) != 0:
-        raise bb.build.FuncFailed("RPM signing failed")
+    signer.sign_rpms(rpms)
 }
 
 do_package_index[depends] += "signing-keys:do_export_public_keys"
diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
new file mode 100644
index 0000000..55abad8
--- /dev/null
+++ b/meta/lib/oe/gpg_sign.py
@@ -0,0 +1,76 @@
+"""Helper module for GPG signing"""
+import os
+
+import bb
+import oe.utils
+
+class LocalSigner(object):
+    """Class for handling local (on the build host) signing"""
+    def __init__(self, d, keyid, passphrase_file):
+        self.keyid = keyid
+        self.passphrase_file = passphrase_file
+        self.gpg_bin = d.getVar('GPG_BIN', True) or \
+                  bb.utils.which(os.getenv('PATH'), 'gpg')
+        self.gpg_path = d.getVar('GPG_PATH', True)
+        self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm")
+
+    def export_pubkey(self, output_file):
+        """Export GPG public key to a file"""
+        cmd = '%s --batch --yes --export --armor -o %s ' % \
+                (self.gpg_bin, output_file)
+        if self.gpg_path:
+            cmd += "--homedir %s " % self.gpg_path
+        cmd += self.keyid
+        status, output = oe.utils.getstatusoutput(cmd)
+        if status:
+            raise bb.build.FuncFailed('Failed to export gpg public key (%s): %s' %
+                                      (self.keyid, output))
+
+    def sign_rpms(self, files):
+        """Sign RPM files"""
+        import pexpect
+
+        cmd = self.rpm_bin + " --addsign --define '_gpg_name %s' " % self.keyid
+        if self.gpg_bin:
+            cmd += "--define '%%__gpg %s' " % self.gpg_bin
+        if self.gpg_path:
+            cmd += "--define '_gpg_path %s' " % self.gpg_path
+        cmd += ' '.join(files)
+
+        # Need to use pexpect for feeding the passphrase
+        proc = pexpect.spawn(cmd)
+        try:
+            proc.expect_exact('Enter pass phrase:', timeout=15)
+            with open(self.passphrase_file) as fobj:
+                proc.sendline(fobj.readline().rstrip('\n'))
+            proc.expect(pexpect.EOF, timeout=900)
+            proc.close()
+        except pexpect.TIMEOUT as err:
+            bb.error('rpmsign timeout: %s' % err)
+            proc.terminate()
+        if os.WEXITSTATUS(proc.status) or not os.WIFEXITED(proc.status):
+            bb.error('rpmsign failed: %s' % proc.before.strip())
+            raise bb.build.FuncFailed("Failed to sign RPM packages")
+
+    def detach_sign(self, input_file):
+        """Create a detached signature of a file"""
+        cmd = "%s --detach-sign --armor --batch --no-tty --yes " \
+                  "--passphrase-file '%s' -u '%s' " % \
+                  (self.gpg_bin, self.passphrase_file, self.keyid)
+        if self.gpg_path:
+            gpg_cmd += "--homedir %s " % self.gpg_path
+        cmd += input_file
+        status, output = oe.utils.getstatusoutput(cmd)
+        if status:
+            raise bb.build.FuncFailed("Failed to create signature for '%s': %s" %
+                                      (input_file, output))
+
+
+def get_signer(d, backend, keyid, passphrase_file):
+    """Get signer object for the specified backend"""
+    # Use local signing by default
+    if backend == 'local':
+        return LocalSigner(d, keyid, passphrase_file)
+    else:
+        bb.fatal("Unsupported signing backend '%s'" % backend)
+
diff --git a/meta/lib/oe/package_manager.py b/meta/lib/oe/package_manager.py
index 32afeaf..c7df4bc 100644
--- a/meta/lib/oe/package_manager.py
+++ b/meta/lib/oe/package_manager.py
@@ -9,6 +9,7 @@ import bb
 import tempfile
 import oe.utils
 import string
+from oe.gpg_sign import get_signer
 
 # this can be used by all PM backends to create the index files in parallel
 def create_index(arg):
@@ -109,16 +110,14 @@ class RpmIndexer(Indexer):
 
         rpm_createrepo = bb.utils.which(os.getenv('PATH'), "createrepo")
         if self.d.getVar('PACKAGE_FEED_SIGN', True) == '1':
-            pkgfeed_gpg_name = self.d.getVar('PACKAGE_FEED_GPG_NAME', True)
-            pkgfeed_gpg_pass = self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE', True)
+            signer = get_signer(self.d,
+                                self.d.getVar('PACKAGE_FEED_GPG_BACKEND', True),
+                                self.d.getVar('PACKAGE_FEED_GPG_NAME', True),
+                                self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE', True))
         else:
-            pkgfeed_gpg_name = None
-            pkgfeed_gpg_pass = None
-        gpg_bin = self.d.getVar('GPG_BIN', True) or \
-                  bb.utils.which(os.getenv('PATH'), "gpg")
-
+            signer = None
         index_cmds = []
-        repo_sign_cmds = []
+        repomd_files = []
         rpm_dirs_found = False
         for arch in archs:
             dbpath = os.path.join(self.d.getVar('WORKDIR', True), 'rpmdb', arch)
@@ -130,15 +129,7 @@ class RpmIndexer(Indexer):
 
             index_cmds.append("%s --dbpath %s --update -q %s" % \
                              (rpm_createrepo, dbpath, arch_dir))
-            if pkgfeed_gpg_name:
-                repomd_file = os.path.join(arch_dir, 'repodata', 'repomd.xml')
-                gpg_cmd = "%s --detach-sign --armor --batch --no-tty --yes " \
-                          "--passphrase-file '%s' -u '%s' " % \
-                          (gpg_bin, pkgfeed_gpg_pass, pkgfeed_gpg_name)
-                if self.d.getVar('GPG_PATH', True):
-                    gpg_cmd += "--homedir %s " % self.d.getVar('GPG_PATH', True)
-                gpg_cmd += repomd_file
-                repo_sign_cmds.append(gpg_cmd)
+            repomd_files.append(os.path.join(arch_dir, 'repodata', 'repomd.xml'))
 
             rpm_dirs_found = True
 
@@ -151,9 +142,9 @@ class RpmIndexer(Indexer):
         if result:
             bb.fatal('%s' % ('\n'.join(result)))
         # Sign repomd
-        result = oe.utils.multiprocess_exec(repo_sign_cmds, create_index)
-        if result:
-            bb.fatal('%s' % ('\n'.join(result)))
+        if signer:
+            for repomd in repomd_files:
+                signer.detach_sign(repomd)
         # Copy pubkey(s) to repo
         distro_version = self.d.getVar('DISTRO_VERSION', True) or "oe.0"
         if self.d.getVar('RPM_SIGN_PACKAGES', True) == '1':
diff --git a/meta/recipes-core/meta/signing-keys.bb b/meta/recipes-core/meta/signing-keys.bb
index cc401f3..d7aa79d 100644
--- a/meta/recipes-core/meta/signing-keys.bb
+++ b/meta/recipes-core/meta/signing-keys.bb
@@ -20,26 +20,24 @@ do_populate_sysroot[noexec] = "1"
 
 EXCLUDE_FROM_WORLD = "1"
 
-def export_gpg_pubkey(d, keyid, path):
-    import bb
-    gpg_bin = d.getVar('GPG_BIN', True) or \
-              bb.utils.which(os.getenv('PATH'), "gpg")
-    cmd = '%s --batch --yes --export --armor -o %s %s' % \
-          (gpg_bin, path, keyid)
-    status, output = oe.utils.getstatusoutput(cmd)
-    if status:
-        raise bb.build.FuncFailed('Failed to export gpg public key (%s): %s' %
-                                  (keyid, output))
 
 python do_export_public_keys () {
+    from oe.gpg_sign import get_signer
+
     if d.getVar("RPM_SIGN_PACKAGES", True):
         # Export public key of the rpm signing key
-        export_gpg_pubkey(d, d.getVar("RPM_GPG_NAME", True),
-                          d.getVar('RPM_GPG_PUBKEY', True))
+        signer = get_signer(d,
+                            d.getVar('RPM_GPG_BACKEND', True),
+                            d.getVar('RPM_GPG_NAME', True),
+                            d.getVar('RPM_GPG_PASSPHRASE_FILE', True))
+        signer.export_pubkey(d.getVar('RPM_GPG_PUBKEY', True))
 
     if d.getVar('PACKAGE_FEED_SIGN', True) == '1':
         # Export public key of the feed signing key
-        export_gpg_pubkey(d, d.getVar("PACKAGE_FEED_GPG_NAME", True),
-                          d.getVar('PACKAGE_FEED_GPG_PUBKEY', True))
+        signer = get_signer(d,
+                            d.getVar('PACKAGE_FEED_GPG_BACKEND', True),
+                            d.getVar('PACKAGE_FEED_GPG_NAME', True),
+                            d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE', True))
+        signer.export_pubkey(d.getVar('PACKAGE_FEED_GPG_PUBKEY', True))
 }
 addtask do_export_public_keys before do_build
-- 
2.1.4



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

* [PATCH 3/3] oe.gpg_sign: support obs-signd
  2016-01-11 16:13 [PATCH 0/3] Support remote RPM signing Markus Lehtonen
  2016-01-11 16:13 ` [PATCH 1/3] sign_rpm.bbclass: fix task dependencies Markus Lehtonen
  2016-01-11 16:13 ` [PATCH 2/3] New lib module for handling GPG signing Markus Lehtonen
@ 2016-01-11 16:13 ` Markus Lehtonen
  2016-01-11 16:33   ` Mark Hatle
  2 siblings, 1 reply; 12+ messages in thread
From: Markus Lehtonen @ 2016-01-11 16:13 UTC (permalink / raw)
  To: openembedded-core

Implement support for remote signing using obs-signd. It is now possible
to sign both RPM packages and package feeds with this method. The user
just needs to set RPM_GPG_BACKEND and/or PACKAGE_FEED_GPG_BACKEND
variables to 'obssign' in the bitbake config. Of course, in addition,
one needs to setup the signing server and the configure the 'sign'
client command on the build host. The *_PASSPHRASE_FILE settings are not
used when the obssign backend is enabled.

[YOCTO #8755]

Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
---
 meta/classes/sign_package_feed.bbclass |  5 +++-
 meta/classes/sign_rpm.bbclass          |  5 +++-
 meta/lib/oe/gpg_sign.py                | 48 ++++++++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/meta/classes/sign_package_feed.bbclass b/meta/classes/sign_package_feed.bbclass
index d5df8af..953fa85 100644
--- a/meta/classes/sign_package_feed.bbclass
+++ b/meta/classes/sign_package_feed.bbclass
@@ -24,7 +24,10 @@ PACKAGE_FEED_GPG_BACKEND ?= 'local'
 
 python () {
     # Check sanity of configuration
-    for var in ('PACKAGE_FEED_GPG_NAME', 'PACKAGE_FEED_GPG_PASSPHRASE_FILE'):
+    required = ['PACKAGE_FEED_GPG_NAME']
+    if d.getVar('PACKAGE_FEED_GPG_BACKEND', True) != 'obssign':
+        required.append('PACKAGE_FEED_GPG_PASSPHRASE_FILE')
+    for var in required:
         if not d.getVar(var, True):
             raise_sanity_error("You need to define %s in the config" % var, d)
 
diff --git a/meta/classes/sign_rpm.bbclass b/meta/classes/sign_rpm.bbclass
index 8bcabee..8be1c35 100644
--- a/meta/classes/sign_rpm.bbclass
+++ b/meta/classes/sign_rpm.bbclass
@@ -23,7 +23,10 @@ RPM_GPG_BACKEND ?= 'local'
 
 python () {
     # Check configuration
-    for var in ('RPM_GPG_NAME', 'RPM_GPG_PASSPHRASE_FILE'):
+    required = ['RPM_GPG_NAME']
+    if d.getVar('RPM_GPG_BACKEND', True) != 'obssign':
+        required.append('RPM_GPG_PASSPHRASE_FILE')
+    for var in required:
         if not d.getVar(var, True):
             raise_sanity_error("You need to define %s in the config" % var, d)
 
diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
index 55abad8..d8ab816 100644
--- a/meta/lib/oe/gpg_sign.py
+++ b/meta/lib/oe/gpg_sign.py
@@ -66,11 +66,59 @@ class LocalSigner(object):
                                       (input_file, output))
 
 
+class ObsSigner(object):
+    """Class for handling signing with obs-signd"""
+    def __init__(self, keyid):
+        self.keyid = keyid
+        self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm")
+
+    def export_pubkey(self, output_file):
+        """Export GPG public key to a file"""
+        cmd = "sign -u '%s' -p" % self.keyid
+        status, output = oe.utils.getstatusoutput(cmd)
+        if status:
+            raise bb.build.FuncFailed('Failed to export gpg public key (%s): %s' %
+                                      (self.keyid, output))
+        with open(output_file, 'w') as fobj:
+            fobj.write(output)
+            fobj.write('\n')
+
+    def sign_rpms(self, files):
+        """Sign RPM files"""
+        import pexpect
+
+        # Remove existing signatures
+        cmd = "%s --delsign %s" % (self.rpm_bin, ' '.join(files))
+        status, output = oe.utils.getstatusoutput(cmd)
+        if status:
+            raise bb.build.FuncFailed("Failed to remove RPM signatures: %s" %
+                                      output)
+        # Sign packages
+        cmd = "sign -u '%s' -r %s" % (self.keyid, ' '.join(files))
+        status, output = oe.utils.getstatusoutput(cmd)
+        if status:
+            raise bb.build.FuncFailed("Failed to sign RPM packages: %s" %
+                                      output)
+
+    def detach_sign(self, input_file):
+        """Create a detached signature of a file"""
+        cmd = "sign -u '%s' -d %s" % (self.keyid, input_file)
+        status, output = oe.utils.getstatusoutput(cmd)
+        if status:
+            raise bb.build.FuncFailed("Failed to create signature for '%s': %s" %
+                                      (input_file, output))
+
+
 def get_signer(d, backend, keyid, passphrase_file):
     """Get signer object for the specified backend"""
     # Use local signing by default
     if backend == 'local':
         return LocalSigner(d, keyid, passphrase_file)
+    elif backend == 'obssign':
+        if passphrase_file:
+            bb.note("GPG passphrase file setting not used when 'obssign' "
+                    "backend is used.")
+        return ObsSigner(keyid)
     else:
         bb.fatal("Unsupported signing backend '%s'" % backend)
 
-- 
2.1.4



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

* Re: [PATCH 3/3] oe.gpg_sign: support obs-signd
  2016-01-11 16:13 ` [PATCH 3/3] oe.gpg_sign: support obs-signd Markus Lehtonen
@ 2016-01-11 16:33   ` Mark Hatle
  2016-01-12 16:24     ` Markus Lehtonen
  0 siblings, 1 reply; 12+ messages in thread
From: Mark Hatle @ 2016-01-11 16:33 UTC (permalink / raw)
  To: Markus Lehtonen, openembedded-core

On 1/11/16 10:13 AM, Markus Lehtonen wrote:
> Implement support for remote signing using obs-signd. It is now possible
> to sign both RPM packages and package feeds with this method. The user
> just needs to set RPM_GPG_BACKEND and/or PACKAGE_FEED_GPG_BACKEND
> variables to 'obssign' in the bitbake config. Of course, in addition,
> one needs to setup the signing server and the configure the 'sign'
> client command on the build host. The *_PASSPHRASE_FILE settings are not
> used when the obssign backend is enabled.
> 
> [YOCTO #8755]
> 
> Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
> ---
>  meta/classes/sign_package_feed.bbclass |  5 +++-
>  meta/classes/sign_rpm.bbclass          |  5 +++-
>  meta/lib/oe/gpg_sign.py                | 48 ++++++++++++++++++++++++++++++++++
>  3 files changed, 56 insertions(+), 2 deletions(-)
> 
> diff --git a/meta/classes/sign_package_feed.bbclass b/meta/classes/sign_package_feed.bbclass
> index d5df8af..953fa85 100644
> --- a/meta/classes/sign_package_feed.bbclass
> +++ b/meta/classes/sign_package_feed.bbclass
> @@ -24,7 +24,10 @@ PACKAGE_FEED_GPG_BACKEND ?= 'local'
>  
>  python () {
>      # Check sanity of configuration
> -    for var in ('PACKAGE_FEED_GPG_NAME', 'PACKAGE_FEED_GPG_PASSPHRASE_FILE'):
> +    required = ['PACKAGE_FEED_GPG_NAME']
> +    if d.getVar('PACKAGE_FEED_GPG_BACKEND', True) != 'obssign':
> +        required.append('PACKAGE_FEED_GPG_PASSPHRASE_FILE')
> +    for var in required:
>          if not d.getVar(var, True):
>              raise_sanity_error("You need to define %s in the config" % var, d)
>  
> diff --git a/meta/classes/sign_rpm.bbclass b/meta/classes/sign_rpm.bbclass
> index 8bcabee..8be1c35 100644
> --- a/meta/classes/sign_rpm.bbclass
> +++ b/meta/classes/sign_rpm.bbclass
> @@ -23,7 +23,10 @@ RPM_GPG_BACKEND ?= 'local'
>  
>  python () {
>      # Check configuration
> -    for var in ('RPM_GPG_NAME', 'RPM_GPG_PASSPHRASE_FILE'):
> +    required = ['RPM_GPG_NAME']
> +    if d.getVar('RPM_GPG_BACKEND', True) != 'obssign':
> +        required.append('RPM_GPG_PASSPHRASE_FILE')
> +    for var in required:
>          if not d.getVar(var, True):
>              raise_sanity_error("You need to define %s in the config" % var, d)
>  
> diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
> index 55abad8..d8ab816 100644
> --- a/meta/lib/oe/gpg_sign.py
> +++ b/meta/lib/oe/gpg_sign.py
> @@ -66,11 +66,59 @@ class LocalSigner(object):
>                                        (input_file, output))
>  
>  
> +class ObsSigner(object):
> +    """Class for handling signing with obs-signd"""
> +    def __init__(self, keyid):
> +        self.keyid = keyid
> +        self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm")
> +
> +    def export_pubkey(self, output_file):
> +        """Export GPG public key to a file"""
> +        cmd = "sign -u '%s' -p" % self.keyid
> +        status, output = oe.utils.getstatusoutput(cmd)
> +        if status:
> +            raise bb.build.FuncFailed('Failed to export gpg public key (%s): %s' %
> +                                      (self.keyid, output))
> +        with open(output_file, 'w') as fobj:
> +            fobj.write(output)
> +            fobj.write('\n')
> +
> +    def sign_rpms(self, files):
> +        """Sign RPM files"""
> +        import pexpect
> +
> +        # Remove existing signatures
> +        cmd = "%s --delsign %s" % (self.rpm_bin, ' '.join(files))

Why are you removing existing signatures?  I believe for many cases this is
actually incorrect.

RPM (5) has the ability to have an endless number of signatures within a given
package.  The package SHOULD included the internal non-repudiable signature...

(to refresh memory) all RPM 5 packages include an internal non-repudiable
signature.  Think of this as an extended md5sum, sha256sum, etc.  It doesn't
change that a package is 'authentic' in any way (often the purpose of signatures
like what this code is doing), but instead keeps a high reliability way to sign
and verify the package is signed properly.

This is used for validation if the system doing the install does not have the
public key that the package was signed with.

... as well as one or more repudiable signatures that can be used to verify that
it's "authentic" in some way.  A system could very easily have OSV, OEM, and ISV
keys install on them.  You can program RPM in such a way that it will refused to
install packages with unknown authentication keys or the non-repudiable key as well.

So, I believe running delsign is wrong.  If the obs-signd can't handle ADDING
signatures to packages, then I'd say it is broken and should be fixed in some
way -- or at least the signature deletion code should be optional.

> +        status, output = oe.utils.getstatusoutput(cmd)
> +        if status:
> +            raise bb.build.FuncFailed("Failed to remove RPM signatures: %s" %
> +                                      output)
> +        # Sign packages
> +        cmd = "sign -u '%s' -r %s" % (self.keyid, ' '.join(files))
> +        status, output = oe.utils.getstatusoutput(cmd)
> +        if status:
> +            raise bb.build.FuncFailed("Failed to sign RPM packages: %s" %
> +                                      output)
> +
> +    def detach_sign(self, input_file):
> +        """Create a detached signature of a file"""
> +        cmd = "sign -u '%s' -d %s" % (self.keyid, input_file)
> +        status, output = oe.utils.getstatusoutput(cmd)
> +        if status:
> +            raise bb.build.FuncFailed("Failed to create signature for '%s': %s" %
> +                                      (input_file, output))
> +
> +
>  def get_signer(d, backend, keyid, passphrase_file):
>      """Get signer object for the specified backend"""
>      # Use local signing by default
>      if backend == 'local':
>          return LocalSigner(d, keyid, passphrase_file)
> +    elif backend == 'obssign':
> +        if passphrase_file:
> +            bb.note("GPG passphrase file setting not used when 'obssign' "
> +                    "backend is used.")
> +        return ObsSigner(keyid)
>      else:
>          bb.fatal("Unsupported signing backend '%s'" % backend)
>  
> 



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

* Re: [PATCH 3/3] oe.gpg_sign: support obs-signd
  2016-01-11 16:33   ` Mark Hatle
@ 2016-01-12 16:24     ` Markus Lehtonen
  2016-01-13 10:28       ` Markus Lehtonen
  0 siblings, 1 reply; 12+ messages in thread
From: Markus Lehtonen @ 2016-01-12 16:24 UTC (permalink / raw)
  To: Mark Hatle; +Cc: openembedded-core

Hi Mark,

Thank you for your review! Comments below.

On Mon, 2016-01-11 at 10:33 -0600, Mark Hatle wrote:
> On 1/11/16 10:13 AM, Markus Lehtonen wrote:
> > Implement support for remote signing using obs-signd. It is now possible
> > to sign both RPM packages and package feeds with this method. The user
> > just needs to set RPM_GPG_BACKEND and/or PACKAGE_FEED_GPG_BACKEND
> > variables to 'obssign' in the bitbake config. Of course, in addition,
> > one needs to setup the signing server and the configure the 'sign'
> > client command on the build host. The *_PASSPHRASE_FILE settings are not
> > used when the obssign backend is enabled.
> > 
> > [YOCTO #8755]
> > 
> > Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
> > ---
> >  meta/classes/sign_package_feed.bbclass |  5 +++-
> >  meta/classes/sign_rpm.bbclass          |  5 +++-
> >  meta/lib/oe/gpg_sign.py                | 48 ++++++++++++++++++++++++++++++++++
> >  3 files changed, 56 insertions(+), 2 deletions(-)
> > 
> > diff --git a/meta/classes/sign_package_feed.bbclass b/meta/classes/sign_package_feed.bbclass
> > index d5df8af..953fa85 100644
> > --- a/meta/classes/sign_package_feed.bbclass
> > +++ b/meta/classes/sign_package_feed.bbclass
> > @@ -24,7 +24,10 @@ PACKAGE_FEED_GPG_BACKEND ?= 'local'
> >  
> >  python () {
> >      # Check sanity of configuration
> > -    for var in ('PACKAGE_FEED_GPG_NAME', 'PACKAGE_FEED_GPG_PASSPHRASE_FILE'):
> > +    required = ['PACKAGE_FEED_GPG_NAME']
> > +    if d.getVar('PACKAGE_FEED_GPG_BACKEND', True) != 'obssign':
> > +        required.append('PACKAGE_FEED_GPG_PASSPHRASE_FILE')
> > +    for var in required:
> >          if not d.getVar(var, True):
> >              raise_sanity_error("You need to define %s in the config" % var, d)
> >  
> > diff --git a/meta/classes/sign_rpm.bbclass b/meta/classes/sign_rpm.bbclass
> > index 8bcabee..8be1c35 100644
> > --- a/meta/classes/sign_rpm.bbclass
> > +++ b/meta/classes/sign_rpm.bbclass
> > @@ -23,7 +23,10 @@ RPM_GPG_BACKEND ?= 'local'
> >  
> >  python () {
> >      # Check configuration
> > -    for var in ('RPM_GPG_NAME', 'RPM_GPG_PASSPHRASE_FILE'):
> > +    required = ['RPM_GPG_NAME']
> > +    if d.getVar('RPM_GPG_BACKEND', True) != 'obssign':
> > +        required.append('RPM_GPG_PASSPHRASE_FILE')
> > +    for var in required:
> >          if not d.getVar(var, True):
> >              raise_sanity_error("You need to define %s in the config" % var, d)
> >  
> > diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
> > index 55abad8..d8ab816 100644
> > --- a/meta/lib/oe/gpg_sign.py
> > +++ b/meta/lib/oe/gpg_sign.py
> > @@ -66,11 +66,59 @@ class LocalSigner(object):
> >                                        (input_file, output))
> >  
> >  
> > +class ObsSigner(object):
> > +    """Class for handling signing with obs-signd"""
> > +    def __init__(self, keyid):
> > +        self.keyid = keyid
> > +        self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm")
> > +
> > +    def export_pubkey(self, output_file):
> > +        """Export GPG public key to a file"""
> > +        cmd = "sign -u '%s' -p" % self.keyid
> > +        status, output = oe.utils.getstatusoutput(cmd)
> > +        if status:
> > +            raise bb.build.FuncFailed('Failed to export gpg public key (%s): %s' %
> > +                                      (self.keyid, output))
> > +        with open(output_file, 'w') as fobj:
> > +            fobj.write(output)
> > +            fobj.write('\n')
> > +
> > +    def sign_rpms(self, files):
> > +        """Sign RPM files"""
> > +        import pexpect
> > +
> > +        # Remove existing signatures
> > +        cmd = "%s --delsign %s" % (self.rpm_bin, ' '.join(files))
> 
> Why are you removing existing signatures?  I believe for many cases this is
> actually incorrect.
> 
> RPM (5) has the ability to have an endless number of signatures within a given
> package.  The package SHOULD included the internal non-repudiable signature...
> 
> (to refresh memory) all RPM 5 packages include an internal non-repudiable
> signature.  Think of this as an extended md5sum, sha256sum, etc.  It doesn't
> change that a package is 'authentic' in any way (often the purpose of signatures
> like what this code is doing), but instead keeps a high reliability way to sign
> and verify the package is signed properly.
> 
> This is used for validation if the system doing the install does not have the
> public key that the package was signed with.
> 
> ... as well as one or more repudiable signatures that can be used to verify that
> it's "authentic" in some way.  A system could very easily have OSV, OEM, and ISV
> keys install on them.  You can program RPM in such a way that it will refused to
> install packages with unknown authentication keys or the non-repudiable key as well.
> 
> So, I believe running delsign is wrong.  If the obs-signd can't handle ADDING
> signatures to packages, then I'd say it is broken and should be fixed in some
> way -- or at least the signature deletion code should be optional.

Yes, unfortunately this is currently the limitation of obs-signd. It
refuses to sign if there are signatures present in the rpm package.
Using --delsign is "unfortunate" consequence of this and that should've
probably been described in a comment. Making signature deletion a
configurable setting is hopefully a decent resolution for now. I will
send a new version of the patchset later.


Thanks,
   Markus



> > +        status, output = oe.utils.getstatusoutput(cmd)
> > +        if status:
> > +            raise bb.build.FuncFailed("Failed to remove RPM signatures: %s" %
> > +                                      output)
> > +        # Sign packages
> > +        cmd = "sign -u '%s' -r %s" % (self.keyid, ' '.join(files))
> > +        status, output = oe.utils.getstatusoutput(cmd)
> > +        if status:
> > +            raise bb.build.FuncFailed("Failed to sign RPM packages: %s" %
> > +                                      output)
> > +
> > +    def detach_sign(self, input_file):
> > +        """Create a detached signature of a file"""
> > +        cmd = "sign -u '%s' -d %s" % (self.keyid, input_file)
> > +        status, output = oe.utils.getstatusoutput(cmd)
> > +        if status:
> > +            raise bb.build.FuncFailed("Failed to create signature for '%s': %s" %
> > +                                      (input_file, output))
> > +
> > +
> >  def get_signer(d, backend, keyid, passphrase_file):
> >      """Get signer object for the specified backend"""
> >      # Use local signing by default
> >      if backend == 'local':
> >          return LocalSigner(d, keyid, passphrase_file)
> > +    elif backend == 'obssign':
> > +        if passphrase_file:
> > +            bb.note("GPG passphrase file setting not used when 'obssign' "
> > +                    "backend is used.")
> > +        return ObsSigner(keyid)
> >      else:
> >          bb.fatal("Unsupported signing backend '%s'" % backend)
> >  
> > 
> 





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

* Re: [PATCH 3/3] oe.gpg_sign: support obs-signd
  2016-01-12 16:24     ` Markus Lehtonen
@ 2016-01-13 10:28       ` Markus Lehtonen
  2016-01-13 14:56         ` Mark Hatle
       [not found]         ` <1453375237.13987.27.camel@linux.intel.com>
  0 siblings, 2 replies; 12+ messages in thread
From: Markus Lehtonen @ 2016-01-13 10:28 UTC (permalink / raw)
  To: Mark Hatle; +Cc: openembedded-core

Hi,

On Tue, 2016-01-12 at 18:24 +0200, Markus Lehtonen wrote:
> Hi Mark,
> 
> Thank you for your review! Comments below.
> 
> On Mon, 2016-01-11 at 10:33 -0600, Mark Hatle wrote:
> > On 1/11/16 10:13 AM, Markus Lehtonen wrote:
> > > Implement support for remote signing using obs-signd. It is now possible
> > > to sign both RPM packages and package feeds with this method. The user
> > > just needs to set RPM_GPG_BACKEND and/or PACKAGE_FEED_GPG_BACKEND
> > > variables to 'obssign' in the bitbake config. Of course, in addition,
> > > one needs to setup the signing server and the configure the 'sign'
> > > client command on the build host. The *_PASSPHRASE_FILE settings are not
> > > used when the obssign backend is enabled.
> > > 
> > > [YOCTO #8755]
> > > 
> > > Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
> > > ---
> > >  meta/classes/sign_package_feed.bbclass |  5 +++-
> > >  meta/classes/sign_rpm.bbclass          |  5 +++-
> > >  meta/lib/oe/gpg_sign.py                | 48 ++++++++++++++++++++++++++++++++++
> > >  3 files changed, 56 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/meta/classes/sign_package_feed.bbclass b/meta/classes/sign_package_feed.bbclass
> > > index d5df8af..953fa85 100644
> > > --- a/meta/classes/sign_package_feed.bbclass
> > > +++ b/meta/classes/sign_package_feed.bbclass
> > > @@ -24,7 +24,10 @@ PACKAGE_FEED_GPG_BACKEND ?= 'local'
> > >  
> > >  python () {
> > >      # Check sanity of configuration
> > > -    for var in ('PACKAGE_FEED_GPG_NAME', 'PACKAGE_FEED_GPG_PASSPHRASE_FILE'):
> > > +    required = ['PACKAGE_FEED_GPG_NAME']
> > > +    if d.getVar('PACKAGE_FEED_GPG_BACKEND', True) != 'obssign':
> > > +        required.append('PACKAGE_FEED_GPG_PASSPHRASE_FILE')
> > > +    for var in required:
> > >          if not d.getVar(var, True):
> > >              raise_sanity_error("You need to define %s in the config" % var, d)
> > >  
> > > diff --git a/meta/classes/sign_rpm.bbclass b/meta/classes/sign_rpm.bbclass
> > > index 8bcabee..8be1c35 100644
> > > --- a/meta/classes/sign_rpm.bbclass
> > > +++ b/meta/classes/sign_rpm.bbclass
> > > @@ -23,7 +23,10 @@ RPM_GPG_BACKEND ?= 'local'
> > >  
> > >  python () {
> > >      # Check configuration
> > > -    for var in ('RPM_GPG_NAME', 'RPM_GPG_PASSPHRASE_FILE'):
> > > +    required = ['RPM_GPG_NAME']
> > > +    if d.getVar('RPM_GPG_BACKEND', True) != 'obssign':
> > > +        required.append('RPM_GPG_PASSPHRASE_FILE')
> > > +    for var in required:
> > >          if not d.getVar(var, True):
> > >              raise_sanity_error("You need to define %s in the config" % var, d)
> > >  
> > > diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
> > > index 55abad8..d8ab816 100644
> > > --- a/meta/lib/oe/gpg_sign.py
> > > +++ b/meta/lib/oe/gpg_sign.py
> > > @@ -66,11 +66,59 @@ class LocalSigner(object):
> > >                                        (input_file, output))
> > >  
> > >  
> > > +class ObsSigner(object):
> > > +    """Class for handling signing with obs-signd"""
> > > +    def __init__(self, keyid):
> > > +        self.keyid = keyid
> > > +        self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm")
> > > +
> > > +    def export_pubkey(self, output_file):
> > > +        """Export GPG public key to a file"""
> > > +        cmd = "sign -u '%s' -p" % self.keyid
> > > +        status, output = oe.utils.getstatusoutput(cmd)
> > > +        if status:
> > > +            raise bb.build.FuncFailed('Failed to export gpg public key (%s): %s' %
> > > +                                      (self.keyid, output))
> > > +        with open(output_file, 'w') as fobj:
> > > +            fobj.write(output)
> > > +            fobj.write('\n')
> > > +
> > > +    def sign_rpms(self, files):
> > > +        """Sign RPM files"""
> > > +        import pexpect
> > > +
> > > +        # Remove existing signatures
> > > +        cmd = "%s --delsign %s" % (self.rpm_bin, ' '.join(files))
> > 
> > Why are you removing existing signatures?  I believe for many cases this is
> > actually incorrect.
> > 
> > RPM (5) has the ability to have an endless number of signatures within a given
> > package.  The package SHOULD included the internal non-repudiable signature...
> > 
> > (to refresh memory) all RPM 5 packages include an internal non-repudiable
> > signature.  Think of this as an extended md5sum, sha256sum, etc.  It doesn't
> > change that a package is 'authentic' in any way (often the purpose of signatures
> > like what this code is doing), but instead keeps a high reliability way to sign
> > and verify the package is signed properly.
> > 
> > This is used for validation if the system doing the install does not have the
> > public key that the package was signed with.
> > 
> > ... as well as one or more repudiable signatures that can be used to verify that
> > it's "authentic" in some way.  A system could very easily have OSV, OEM, and ISV
> > keys install on them.  You can program RPM in such a way that it will refused to
> > install packages with unknown authentication keys or the non-repudiable key as well.
> > 
> > So, I believe running delsign is wrong.  If the obs-signd can't handle ADDING
> > signatures to packages, then I'd say it is broken and should be fixed in some
> > way -- or at least the signature deletion code should be optional.
> 
> Yes, unfortunately this is currently the limitation of obs-signd. It
> refuses to sign if there are signatures present in the rpm package.
> Using --delsign is "unfortunate" consequence of this and that should've
> probably been described in a comment. Making signature deletion a
> configurable setting is hopefully a decent resolution for now. I will
> send a new version of the patchset later.

Backing up a bit here. I did some quick testing and it seems that RPM5
does not support multiple signatures (anymore?). Doing --addsign seems
to overwrite the existing signatures similarly to --resign. Support for
multiple signatures were removed from RPM4 years ago.

In this light, doing --delsign should be ok. What do you think?


Thanks,
  Markus



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

* Re: [PATCH 3/3] oe.gpg_sign: support obs-signd
  2016-01-13 10:28       ` Markus Lehtonen
@ 2016-01-13 14:56         ` Mark Hatle
  2016-01-13 21:47           ` Mark Hatle
       [not found]         ` <1453375237.13987.27.camel@linux.intel.com>
  1 sibling, 1 reply; 12+ messages in thread
From: Mark Hatle @ 2016-01-13 14:56 UTC (permalink / raw)
  To: Markus Lehtonen; +Cc: openembedded-core

On 1/13/16 4:28 AM, Markus Lehtonen wrote:
> Hi,
> 
> On Tue, 2016-01-12 at 18:24 +0200, Markus Lehtonen wrote:
>> Hi Mark,
>>
>> Thank you for your review! Comments below.
>>
>> On Mon, 2016-01-11 at 10:33 -0600, Mark Hatle wrote:
>>> On 1/11/16 10:13 AM, Markus Lehtonen wrote:
>>>> Implement support for remote signing using obs-signd. It is now possible
>>>> to sign both RPM packages and package feeds with this method. The user
>>>> just needs to set RPM_GPG_BACKEND and/or PACKAGE_FEED_GPG_BACKEND
>>>> variables to 'obssign' in the bitbake config. Of course, in addition,
>>>> one needs to setup the signing server and the configure the 'sign'
>>>> client command on the build host. The *_PASSPHRASE_FILE settings are not
>>>> used when the obssign backend is enabled.
>>>>
>>>> [YOCTO #8755]
>>>>
>>>> Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
>>>> ---
>>>>  meta/classes/sign_package_feed.bbclass |  5 +++-
>>>>  meta/classes/sign_rpm.bbclass          |  5 +++-
>>>>  meta/lib/oe/gpg_sign.py                | 48 ++++++++++++++++++++++++++++++++++
>>>>  3 files changed, 56 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/meta/classes/sign_package_feed.bbclass b/meta/classes/sign_package_feed.bbclass
>>>> index d5df8af..953fa85 100644
>>>> --- a/meta/classes/sign_package_feed.bbclass
>>>> +++ b/meta/classes/sign_package_feed.bbclass
>>>> @@ -24,7 +24,10 @@ PACKAGE_FEED_GPG_BACKEND ?= 'local'
>>>>  
>>>>  python () {
>>>>      # Check sanity of configuration
>>>> -    for var in ('PACKAGE_FEED_GPG_NAME', 'PACKAGE_FEED_GPG_PASSPHRASE_FILE'):
>>>> +    required = ['PACKAGE_FEED_GPG_NAME']
>>>> +    if d.getVar('PACKAGE_FEED_GPG_BACKEND', True) != 'obssign':
>>>> +        required.append('PACKAGE_FEED_GPG_PASSPHRASE_FILE')
>>>> +    for var in required:
>>>>          if not d.getVar(var, True):
>>>>              raise_sanity_error("You need to define %s in the config" % var, d)
>>>>  
>>>> diff --git a/meta/classes/sign_rpm.bbclass b/meta/classes/sign_rpm.bbclass
>>>> index 8bcabee..8be1c35 100644
>>>> --- a/meta/classes/sign_rpm.bbclass
>>>> +++ b/meta/classes/sign_rpm.bbclass
>>>> @@ -23,7 +23,10 @@ RPM_GPG_BACKEND ?= 'local'
>>>>  
>>>>  python () {
>>>>      # Check configuration
>>>> -    for var in ('RPM_GPG_NAME', 'RPM_GPG_PASSPHRASE_FILE'):
>>>> +    required = ['RPM_GPG_NAME']
>>>> +    if d.getVar('RPM_GPG_BACKEND', True) != 'obssign':
>>>> +        required.append('RPM_GPG_PASSPHRASE_FILE')
>>>> +    for var in required:
>>>>          if not d.getVar(var, True):
>>>>              raise_sanity_error("You need to define %s in the config" % var, d)
>>>>  
>>>> diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
>>>> index 55abad8..d8ab816 100644
>>>> --- a/meta/lib/oe/gpg_sign.py
>>>> +++ b/meta/lib/oe/gpg_sign.py
>>>> @@ -66,11 +66,59 @@ class LocalSigner(object):
>>>>                                        (input_file, output))
>>>>  
>>>>  
>>>> +class ObsSigner(object):
>>>> +    """Class for handling signing with obs-signd"""
>>>> +    def __init__(self, keyid):
>>>> +        self.keyid = keyid
>>>> +        self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm")
>>>> +
>>>> +    def export_pubkey(self, output_file):
>>>> +        """Export GPG public key to a file"""
>>>> +        cmd = "sign -u '%s' -p" % self.keyid
>>>> +        status, output = oe.utils.getstatusoutput(cmd)
>>>> +        if status:
>>>> +            raise bb.build.FuncFailed('Failed to export gpg public key (%s): %s' %
>>>> +                                      (self.keyid, output))
>>>> +        with open(output_file, 'w') as fobj:
>>>> +            fobj.write(output)
>>>> +            fobj.write('\n')
>>>> +
>>>> +    def sign_rpms(self, files):
>>>> +        """Sign RPM files"""
>>>> +        import pexpect
>>>> +
>>>> +        # Remove existing signatures
>>>> +        cmd = "%s --delsign %s" % (self.rpm_bin, ' '.join(files))
>>>
>>> Why are you removing existing signatures?  I believe for many cases this is
>>> actually incorrect.
>>>
>>> RPM (5) has the ability to have an endless number of signatures within a given
>>> package.  The package SHOULD included the internal non-repudiable signature...
>>>
>>> (to refresh memory) all RPM 5 packages include an internal non-repudiable
>>> signature.  Think of this as an extended md5sum, sha256sum, etc.  It doesn't
>>> change that a package is 'authentic' in any way (often the purpose of signatures
>>> like what this code is doing), but instead keeps a high reliability way to sign
>>> and verify the package is signed properly.
>>>
>>> This is used for validation if the system doing the install does not have the
>>> public key that the package was signed with.
>>>
>>> ... as well as one or more repudiable signatures that can be used to verify that
>>> it's "authentic" in some way.  A system could very easily have OSV, OEM, and ISV
>>> keys install on them.  You can program RPM in such a way that it will refused to
>>> install packages with unknown authentication keys or the non-repudiable key as well.
>>>
>>> So, I believe running delsign is wrong.  If the obs-signd can't handle ADDING
>>> signatures to packages, then I'd say it is broken and should be fixed in some
>>> way -- or at least the signature deletion code should be optional.
>>
>> Yes, unfortunately this is currently the limitation of obs-signd. It
>> refuses to sign if there are signatures present in the rpm package.
>> Using --delsign is "unfortunate" consequence of this and that should've
>> probably been described in a comment. Making signature deletion a
>> configurable setting is hopefully a decent resolution for now. I will
>> send a new version of the patchset later.
> 
> Backing up a bit here. I did some quick testing and it seems that RPM5
> does not support multiple signatures (anymore?). Doing --addsign seems
> to overwrite the existing signatures similarly to --resign. Support for
> multiple signatures were removed from RPM4 years ago.
> 
> In this light, doing --delsign should be ok. What do you think?

I'll have to double check, but I used multiple signature support about 6 months
ago with the YP 2.0 (still current oe version) version of RPM.

Are you using the correct rpm signing tool?  If you sign using RPM4's tool, then
you can get the behavior you are talking about.

(The easiest way to verify the signing is 'multiple' was via a debug flag, I
don't remember if rpm -K -vvvv <package> was the right approach of if it was a
more specific one, but the debugging clearly showed it loading multiple signatures.)

--Mark

> 
> Thanks,
>   Markus
> 



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

* Re: [PATCH 3/3] oe.gpg_sign: support obs-signd
  2016-01-13 14:56         ` Mark Hatle
@ 2016-01-13 21:47           ` Mark Hatle
  2016-01-21 15:28             ` Mark Hatle
  0 siblings, 1 reply; 12+ messages in thread
From: Mark Hatle @ 2016-01-13 21:47 UTC (permalink / raw)
  To: Markus Lehtonen; +Cc: openembedded-core

On 1/13/16 8:56 AM, Mark Hatle wrote:
> On 1/13/16 4:28 AM, Markus Lehtonen wrote:
>> Hi,
>>
>> On Tue, 2016-01-12 at 18:24 +0200, Markus Lehtonen wrote:
>>> Hi Mark,
>>>
>>> Thank you for your review! Comments below.
>>>
>>> On Mon, 2016-01-11 at 10:33 -0600, Mark Hatle wrote:
>>>> On 1/11/16 10:13 AM, Markus Lehtonen wrote:
>>>>> Implement support for remote signing using obs-signd. It is now possible
>>>>> to sign both RPM packages and package feeds with this method. The user
>>>>> just needs to set RPM_GPG_BACKEND and/or PACKAGE_FEED_GPG_BACKEND
>>>>> variables to 'obssign' in the bitbake config. Of course, in addition,
>>>>> one needs to setup the signing server and the configure the 'sign'
>>>>> client command on the build host. The *_PASSPHRASE_FILE settings are not
>>>>> used when the obssign backend is enabled.
>>>>>
>>>>> [YOCTO #8755]
>>>>>
>>>>> Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
>>>>> ---
>>>>>  meta/classes/sign_package_feed.bbclass |  5 +++-
>>>>>  meta/classes/sign_rpm.bbclass          |  5 +++-
>>>>>  meta/lib/oe/gpg_sign.py                | 48 ++++++++++++++++++++++++++++++++++
>>>>>  3 files changed, 56 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/meta/classes/sign_package_feed.bbclass b/meta/classes/sign_package_feed.bbclass
>>>>> index d5df8af..953fa85 100644
>>>>> --- a/meta/classes/sign_package_feed.bbclass
>>>>> +++ b/meta/classes/sign_package_feed.bbclass
>>>>> @@ -24,7 +24,10 @@ PACKAGE_FEED_GPG_BACKEND ?= 'local'
>>>>>  
>>>>>  python () {
>>>>>      # Check sanity of configuration
>>>>> -    for var in ('PACKAGE_FEED_GPG_NAME', 'PACKAGE_FEED_GPG_PASSPHRASE_FILE'):
>>>>> +    required = ['PACKAGE_FEED_GPG_NAME']
>>>>> +    if d.getVar('PACKAGE_FEED_GPG_BACKEND', True) != 'obssign':
>>>>> +        required.append('PACKAGE_FEED_GPG_PASSPHRASE_FILE')
>>>>> +    for var in required:
>>>>>          if not d.getVar(var, True):
>>>>>              raise_sanity_error("You need to define %s in the config" % var, d)
>>>>>  
>>>>> diff --git a/meta/classes/sign_rpm.bbclass b/meta/classes/sign_rpm.bbclass
>>>>> index 8bcabee..8be1c35 100644
>>>>> --- a/meta/classes/sign_rpm.bbclass
>>>>> +++ b/meta/classes/sign_rpm.bbclass
>>>>> @@ -23,7 +23,10 @@ RPM_GPG_BACKEND ?= 'local'
>>>>>  
>>>>>  python () {
>>>>>      # Check configuration
>>>>> -    for var in ('RPM_GPG_NAME', 'RPM_GPG_PASSPHRASE_FILE'):
>>>>> +    required = ['RPM_GPG_NAME']
>>>>> +    if d.getVar('RPM_GPG_BACKEND', True) != 'obssign':
>>>>> +        required.append('RPM_GPG_PASSPHRASE_FILE')
>>>>> +    for var in required:
>>>>>          if not d.getVar(var, True):
>>>>>              raise_sanity_error("You need to define %s in the config" % var, d)
>>>>>  
>>>>> diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
>>>>> index 55abad8..d8ab816 100644
>>>>> --- a/meta/lib/oe/gpg_sign.py
>>>>> +++ b/meta/lib/oe/gpg_sign.py
>>>>> @@ -66,11 +66,59 @@ class LocalSigner(object):
>>>>>                                        (input_file, output))
>>>>>  
>>>>>  
>>>>> +class ObsSigner(object):
>>>>> +    """Class for handling signing with obs-signd"""
>>>>> +    def __init__(self, keyid):
>>>>> +        self.keyid = keyid
>>>>> +        self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm")
>>>>> +
>>>>> +    def export_pubkey(self, output_file):
>>>>> +        """Export GPG public key to a file"""
>>>>> +        cmd = "sign -u '%s' -p" % self.keyid
>>>>> +        status, output = oe.utils.getstatusoutput(cmd)
>>>>> +        if status:
>>>>> +            raise bb.build.FuncFailed('Failed to export gpg public key (%s): %s' %
>>>>> +                                      (self.keyid, output))
>>>>> +        with open(output_file, 'w') as fobj:
>>>>> +            fobj.write(output)
>>>>> +            fobj.write('\n')
>>>>> +
>>>>> +    def sign_rpms(self, files):
>>>>> +        """Sign RPM files"""
>>>>> +        import pexpect
>>>>> +
>>>>> +        # Remove existing signatures
>>>>> +        cmd = "%s --delsign %s" % (self.rpm_bin, ' '.join(files))
>>>>
>>>> Why are you removing existing signatures?  I believe for many cases this is
>>>> actually incorrect.
>>>>
>>>> RPM (5) has the ability to have an endless number of signatures within a given
>>>> package.  The package SHOULD included the internal non-repudiable signature...
>>>>
>>>> (to refresh memory) all RPM 5 packages include an internal non-repudiable
>>>> signature.  Think of this as an extended md5sum, sha256sum, etc.  It doesn't
>>>> change that a package is 'authentic' in any way (often the purpose of signatures
>>>> like what this code is doing), but instead keeps a high reliability way to sign
>>>> and verify the package is signed properly.
>>>>
>>>> This is used for validation if the system doing the install does not have the
>>>> public key that the package was signed with.
>>>>
>>>> ... as well as one or more repudiable signatures that can be used to verify that
>>>> it's "authentic" in some way.  A system could very easily have OSV, OEM, and ISV
>>>> keys install on them.  You can program RPM in such a way that it will refused to
>>>> install packages with unknown authentication keys or the non-repudiable key as well.
>>>>
>>>> So, I believe running delsign is wrong.  If the obs-signd can't handle ADDING
>>>> signatures to packages, then I'd say it is broken and should be fixed in some
>>>> way -- or at least the signature deletion code should be optional.
>>>
>>> Yes, unfortunately this is currently the limitation of obs-signd. It
>>> refuses to sign if there are signatures present in the rpm package.
>>> Using --delsign is "unfortunate" consequence of this and that should've
>>> probably been described in a comment. Making signature deletion a
>>> configurable setting is hopefully a decent resolution for now. I will
>>> send a new version of the patchset later.
>>
>> Backing up a bit here. I did some quick testing and it seems that RPM5
>> does not support multiple signatures (anymore?). Doing --addsign seems
>> to overwrite the existing signatures similarly to --resign. Support for
>> multiple signatures were removed from RPM4 years ago.
>>
>> In this light, doing --delsign should be ok. What do you think?
> 
> I'll have to double check, but I used multiple signature support about 6 months
> ago with the YP 2.0 (still current oe version) version of RPM.
> 
> Are you using the correct rpm signing tool?  If you sign using RPM4's tool, then
> you can get the behavior you are talking about.
> 
> (The easiest way to verify the signing is 'multiple' was via a debug flag, I
> don't remember if rpm -K -vvvv <package> was the right approach of if it was a
> more specific one, but the debugging clearly showed it loading multiple signatures.)

I got clarification from the RPM5 maintainer.

More or less there are slots for up to 3 signatures to be added.  Signatures may
include the ECDSA non-repudiable, RSA/DSA and another.  If the default signature
is already RSA/DSA it may be replaced -- from what I understand newer versions
of RPM5 default to an ECDSA non-repudiable signature.

The order of signature verification is first found.  So the -K behavior will
likely not quite match what is actually verified during a package installation.
 So comparing rpm -Kvv and rpm -qvvp will show the various signatures a package
has loaded and will verify.

(RPM5 should -always- have at least one signature that has a matching key known
to RPM.  This is used for validation purposes of the header.)

So short answer.  We still should avoid 'delsign' in the RPM5 case.  Let RPM
decide which slot to use and ensure that each package has either a repudiable or
non-repudiable signature (and included pubkey).

--Mark

> --Mark
> 
>>
>> Thanks,
>>   Markus
>>
> 



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

* Re: [PATCH 3/3] oe.gpg_sign: support obs-signd
  2016-01-13 21:47           ` Mark Hatle
@ 2016-01-21 15:28             ` Mark Hatle
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Hatle @ 2016-01-21 15:28 UTC (permalink / raw)
  To: Markus Lehtonen; +Cc: openembedded-core

On 1/13/16 3:47 PM, Mark Hatle wrote:
> On 1/13/16 8:56 AM, Mark Hatle wrote:
>> On 1/13/16 4:28 AM, Markus Lehtonen wrote:
>>> Hi,
>>>
>>> On Tue, 2016-01-12 at 18:24 +0200, Markus Lehtonen wrote:
>>>> Hi Mark,
>>>>
>>>> Thank you for your review! Comments below.
>>>>
>>>> On Mon, 2016-01-11 at 10:33 -0600, Mark Hatle wrote:
>>>>> On 1/11/16 10:13 AM, Markus Lehtonen wrote:
>>>>>> Implement support for remote signing using obs-signd. It is now possible
>>>>>> to sign both RPM packages and package feeds with this method. The user
>>>>>> just needs to set RPM_GPG_BACKEND and/or PACKAGE_FEED_GPG_BACKEND
>>>>>> variables to 'obssign' in the bitbake config. Of course, in addition,
>>>>>> one needs to setup the signing server and the configure the 'sign'
>>>>>> client command on the build host. The *_PASSPHRASE_FILE settings are not
>>>>>> used when the obssign backend is enabled.
>>>>>>
>>>>>> [YOCTO #8755]
>>>>>>
>>>>>> Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
>>>>>> ---
>>>>>>  meta/classes/sign_package_feed.bbclass |  5 +++-
>>>>>>  meta/classes/sign_rpm.bbclass          |  5 +++-
>>>>>>  meta/lib/oe/gpg_sign.py                | 48 ++++++++++++++++++++++++++++++++++
>>>>>>  3 files changed, 56 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/meta/classes/sign_package_feed.bbclass b/meta/classes/sign_package_feed.bbclass
>>>>>> index d5df8af..953fa85 100644
>>>>>> --- a/meta/classes/sign_package_feed.bbclass
>>>>>> +++ b/meta/classes/sign_package_feed.bbclass
>>>>>> @@ -24,7 +24,10 @@ PACKAGE_FEED_GPG_BACKEND ?= 'local'
>>>>>>  
>>>>>>  python () {
>>>>>>      # Check sanity of configuration
>>>>>> -    for var in ('PACKAGE_FEED_GPG_NAME', 'PACKAGE_FEED_GPG_PASSPHRASE_FILE'):
>>>>>> +    required = ['PACKAGE_FEED_GPG_NAME']
>>>>>> +    if d.getVar('PACKAGE_FEED_GPG_BACKEND', True) != 'obssign':
>>>>>> +        required.append('PACKAGE_FEED_GPG_PASSPHRASE_FILE')
>>>>>> +    for var in required:
>>>>>>          if not d.getVar(var, True):
>>>>>>              raise_sanity_error("You need to define %s in the config" % var, d)
>>>>>>  
>>>>>> diff --git a/meta/classes/sign_rpm.bbclass b/meta/classes/sign_rpm.bbclass
>>>>>> index 8bcabee..8be1c35 100644
>>>>>> --- a/meta/classes/sign_rpm.bbclass
>>>>>> +++ b/meta/classes/sign_rpm.bbclass
>>>>>> @@ -23,7 +23,10 @@ RPM_GPG_BACKEND ?= 'local'
>>>>>>  
>>>>>>  python () {
>>>>>>      # Check configuration
>>>>>> -    for var in ('RPM_GPG_NAME', 'RPM_GPG_PASSPHRASE_FILE'):
>>>>>> +    required = ['RPM_GPG_NAME']
>>>>>> +    if d.getVar('RPM_GPG_BACKEND', True) != 'obssign':
>>>>>> +        required.append('RPM_GPG_PASSPHRASE_FILE')
>>>>>> +    for var in required:
>>>>>>          if not d.getVar(var, True):
>>>>>>              raise_sanity_error("You need to define %s in the config" % var, d)
>>>>>>  
>>>>>> diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py
>>>>>> index 55abad8..d8ab816 100644
>>>>>> --- a/meta/lib/oe/gpg_sign.py
>>>>>> +++ b/meta/lib/oe/gpg_sign.py
>>>>>> @@ -66,11 +66,59 @@ class LocalSigner(object):
>>>>>>                                        (input_file, output))
>>>>>>  
>>>>>>  
>>>>>> +class ObsSigner(object):
>>>>>> +    """Class for handling signing with obs-signd"""
>>>>>> +    def __init__(self, keyid):
>>>>>> +        self.keyid = keyid
>>>>>> +        self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm")
>>>>>> +
>>>>>> +    def export_pubkey(self, output_file):
>>>>>> +        """Export GPG public key to a file"""
>>>>>> +        cmd = "sign -u '%s' -p" % self.keyid
>>>>>> +        status, output = oe.utils.getstatusoutput(cmd)
>>>>>> +        if status:
>>>>>> +            raise bb.build.FuncFailed('Failed to export gpg public key (%s): %s' %
>>>>>> +                                      (self.keyid, output))
>>>>>> +        with open(output_file, 'w') as fobj:
>>>>>> +            fobj.write(output)
>>>>>> +            fobj.write('\n')
>>>>>> +
>>>>>> +    def sign_rpms(self, files):
>>>>>> +        """Sign RPM files"""
>>>>>> +        import pexpect
>>>>>> +
>>>>>> +        # Remove existing signatures
>>>>>> +        cmd = "%s --delsign %s" % (self.rpm_bin, ' '.join(files))
>>>>>
>>>>> Why are you removing existing signatures?  I believe for many cases this is
>>>>> actually incorrect.
>>>>>
>>>>> RPM (5) has the ability to have an endless number of signatures within a given
>>>>> package.  The package SHOULD included the internal non-repudiable signature...
>>>>>
>>>>> (to refresh memory) all RPM 5 packages include an internal non-repudiable
>>>>> signature.  Think of this as an extended md5sum, sha256sum, etc.  It doesn't
>>>>> change that a package is 'authentic' in any way (often the purpose of signatures
>>>>> like what this code is doing), but instead keeps a high reliability way to sign
>>>>> and verify the package is signed properly.
>>>>>
>>>>> This is used for validation if the system doing the install does not have the
>>>>> public key that the package was signed with.
>>>>>
>>>>> ... as well as one or more repudiable signatures that can be used to verify that
>>>>> it's "authentic" in some way.  A system could very easily have OSV, OEM, and ISV
>>>>> keys install on them.  You can program RPM in such a way that it will refused to
>>>>> install packages with unknown authentication keys or the non-repudiable key as well.
>>>>>
>>>>> So, I believe running delsign is wrong.  If the obs-signd can't handle ADDING
>>>>> signatures to packages, then I'd say it is broken and should be fixed in some
>>>>> way -- or at least the signature deletion code should be optional.
>>>>
>>>> Yes, unfortunately this is currently the limitation of obs-signd. It
>>>> refuses to sign if there are signatures present in the rpm package.
>>>> Using --delsign is "unfortunate" consequence of this and that should've
>>>> probably been described in a comment. Making signature deletion a
>>>> configurable setting is hopefully a decent resolution for now. I will
>>>> send a new version of the patchset later.
>>>
>>> Backing up a bit here. I did some quick testing and it seems that RPM5
>>> does not support multiple signatures (anymore?). Doing --addsign seems
>>> to overwrite the existing signatures similarly to --resign. Support for
>>> multiple signatures were removed from RPM4 years ago.
>>>
>>> In this light, doing --delsign should be ok. What do you think?
>>
>> I'll have to double check, but I used multiple signature support about 6 months
>> ago with the YP 2.0 (still current oe version) version of RPM.
>>
>> Are you using the correct rpm signing tool?  If you sign using RPM4's tool, then
>> you can get the behavior you are talking about.
>>
>> (The easiest way to verify the signing is 'multiple' was via a debug flag, I
>> don't remember if rpm -K -vvvv <package> was the right approach of if it was a
>> more specific one, but the debugging clearly showed it loading multiple signatures.)
> 
> I got clarification from the RPM5 maintainer.
> 
> More or less there are slots for up to 3 signatures to be added.  Signatures may
> include the ECDSA non-repudiable, RSA/DSA and another.  If the default signature
> is already RSA/DSA it may be replaced -- from what I understand newer versions
> of RPM5 default to an ECDSA non-repudiable signature.
> 
> The order of signature verification is first found.  So the -K behavior will
> likely not quite match what is actually verified during a package installation.
>  So comparing rpm -Kvv and rpm -qvvp will show the various signatures a package
> has loaded and will verify.
> 
> (RPM5 should -always- have at least one signature that has a matching key known
> to RPM.  This is used for validation purposes of the header.)
> 
> So short answer.  We still should avoid 'delsign' in the RPM5 case.  Let RPM
> decide which slot to use and ensure that each package has either a repudiable or
> non-repudiable signature (and included pubkey).

Following up on this again.  I'm wondering if the best approach would be to
remove the RPM specific actions in this code.  Rename it away from 'obsigner' as
well as the existing.  And just invoke a script that can be provided with OE
itself.  In the scripts directory provide two versions of the signer script.
One that does the traditional signing and one that can do the --delsign and call
the obs-sign program.

If we did it that way it would simplify the 'bbclass' and other functions, and
should not adversely affect performance.  It would also support the two
use-cases you have, as well as easily permit new ones without having to further
change the functionality.

The only thing we'd need to do is come up with a reasonable set of inputs for
the 'script', so that it knew the right versions of GPG, the correct set of
options, and other special behaviors that may be required to perform a signing
operation.  Exporting these through the environment or as command line arguments
would likely make it easy to extend it if necessary in the future.

You might even be able to do something like:

RPM_PACKAGE_SIGNING_SCRIPT = "my-custom-sign.sh '${RPM_GPG_NAME}'
'${RPM_GPG_PASSPHRASE_FILE}'"

Simplifying the code further in that the RPM_PACKAGE_SIGNING_SCRIPT value would
contain all of the arguments necessary avoiding further special processing in
the bbclass...  The default behavior could be made compatible with the current
implementation, while secondary (OBS) behaviors could be added as documentation
how to change what happens.

--Mark

> --Mark
> 
>> --Mark
>>
>>>
>>> Thanks,
>>>   Markus
>>>
>>
> 



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

* Re: [PATCH 3/3] oe.gpg_sign: support obs-signd
       [not found]           ` <56A0F794.7060603@windriver.com>
@ 2016-01-22 10:43             ` Markus Lehtonen
  2016-01-22 14:09               ` Mark Hatle
  0 siblings, 1 reply; 12+ messages in thread
From: Markus Lehtonen @ 2016-01-22 10:43 UTC (permalink / raw)
  To: Mark Hatle; +Cc: openembedded-core

Hi Mark,



(CC'd the mailing list which was accidentally dropped from my previous email)

On 21/01/16 17:21, "Mark Hatle" <mark.hatle@windriver.com> wrote:

>On 1/21/16 5:20 AM, Markus Lehtonen wrote:
>> On Wed, 2016-01-13 at 12:28 +0200, Markus Lehtonen wrote:
>>> On Tue, 2016-01-12 at 18:24 +0200, Markus Lehtonen wrote:
>>>> Hi Mark,
>>>>
>>>> Thank you for your review! Comments below.
>>>>
>>>> On Mon, 2016-01-11 at 10:33 -0600, Mark Hatle wrote:
>> 
>> [...SNIP...]
>> 
>>>>>
>>>>> Why are you removing existing signatures?  I believe for many cases this is
>>>>> actually incorrect.
>>>>>
>>>>> RPM (5) has the ability to have an endless number of signatures within a given
>>>>> package.  The package SHOULD included the internal non-repudiable signature...
>>>>>
>>>>> (to refresh memory) all RPM 5 packages include an internal non-repudiable
>>>>> signature.  Think of this as an extended md5sum, sha256sum, etc.  It doesn't
>>>>> change that a package is 'authentic' in any way (often the purpose of signatures
>>>>> like what this code is doing), but instead keeps a high reliability way to sign
>>>>> and verify the package is signed properly.
>>>>>
>>>>> This is used for validation if the system doing the install does not have the
>>>>> public key that the package was signed with.
>>>>>
>>>>> ... as well as one or more repudiable signatures that can be used to verify that
>>>>> it's "authentic" in some way.  A system could very easily have OSV, OEM, and ISV
>>>>> keys install on them.  You can program RPM in such a way that it will refused to
>>>>> install packages with unknown authentication keys or the non-repudiable key as well.
>>>>>
>>>>> So, I believe running delsign is wrong.  If the obs-signd can't handle ADDING
>>>>> signatures to packages, then I'd say it is broken and should be fixed in some
>>>>> way -- or at least the signature deletion code should be optional.
>>>>
>>>> Yes, unfortunately this is currently the limitation of obs-signd. It
>>>> refuses to sign if there are signatures present in the rpm package.
>>>> Using --delsign is "unfortunate" consequence of this and that should've
>>>> probably been described in a comment. Making signature deletion a
>>>> configurable setting is hopefully a decent resolution for now. I will
>>>> send a new version of the patchset later.
>>>
>>> Backing up a bit here. I did some quick testing and it seems that RPM5
>>> does not support multiple signatures (anymore?). Doing --addsign seems
>>> to overwrite the existing signatures similarly to --resign. Support for
>>> multiple signatures were removed from RPM4 years ago.
>>>
>>> In this light, doing --delsign should be ok. What do you think?
>> 
>> Hi Mark. Do you have any comments to the above? I'd like to get this
>> patchset out of my hands :)
>
>RPM5 does have multiple signatures, but only allows one of each of the three
>types to be installed.  The delsign shouldn't be used as it might remove the
>wrong signature.

AFAIU, rpm only allows one signature so be present. The file format allows that, but, the rpm tool does not (anymore). For example, rpm --addsign will remove an existing DSA signature when adding an RSA signature. The SHA1 / MD5 digests are not touched by --delsign.


>(Three types are DSA/RSA, ECDSA, and simple SHA256 or similar.)

I didn't know that rpm(5?) supports ECDSA signatures.


>But making the --delsign optional I think is the best approach.  (It would be
>better to move it to the obs-sign script itself -- but I can live with doing it
>on the OE side since people are trying to use their owns systems.)

I still believe that making it optional is just worthless and complicates things because doing rpm --addsign has exactly the same effect.


>The alternative would be to not call the script 'obs-sign', but instead call an
>arbitrarily named (and defined in a bitbake variable) script.. Then THAT script
>can do the del and call the obs-sign.)

Hmm, I probably don't like this idea that much. This user-written script would need to be a bit more complex as a it needs to support multiple operations (signrpm, detach sign, export pubkey). Of course, I could write a default script and put it under scripts/ but somehow feels more complex than needed.


Thanks,
  Markus




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

* Re: [PATCH 3/3] oe.gpg_sign: support obs-signd
  2016-01-22 10:43             ` Markus Lehtonen
@ 2016-01-22 14:09               ` Mark Hatle
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Hatle @ 2016-01-22 14:09 UTC (permalink / raw)
  To: Markus Lehtonen; +Cc: openembedded-core

On 1/22/16 4:43 AM, Markus Lehtonen wrote:
> Hi Mark,
> 
> 
> 
> (CC'd the mailing list which was accidentally dropped from my previous email)
> 
> On 21/01/16 17:21, "Mark Hatle" <mark.hatle@windriver.com> wrote:
> 
>> On 1/21/16 5:20 AM, Markus Lehtonen wrote:
>>> On Wed, 2016-01-13 at 12:28 +0200, Markus Lehtonen wrote:
>>>> On Tue, 2016-01-12 at 18:24 +0200, Markus Lehtonen wrote:
>>>>> Hi Mark,
>>>>>
>>>>> Thank you for your review! Comments below.
>>>>>
>>>>> On Mon, 2016-01-11 at 10:33 -0600, Mark Hatle wrote:
>>>
>>> [...SNIP...]
>>>
>>>>>>
>>>>>> Why are you removing existing signatures?  I believe for many cases this is
>>>>>> actually incorrect.
>>>>>>
>>>>>> RPM (5) has the ability to have an endless number of signatures within a given
>>>>>> package.  The package SHOULD included the internal non-repudiable signature...
>>>>>>
>>>>>> (to refresh memory) all RPM 5 packages include an internal non-repudiable
>>>>>> signature.  Think of this as an extended md5sum, sha256sum, etc.  It doesn't
>>>>>> change that a package is 'authentic' in any way (often the purpose of signatures
>>>>>> like what this code is doing), but instead keeps a high reliability way to sign
>>>>>> and verify the package is signed properly.
>>>>>>
>>>>>> This is used for validation if the system doing the install does not have the
>>>>>> public key that the package was signed with.
>>>>>>
>>>>>> ... as well as one or more repudiable signatures that can be used to verify that
>>>>>> it's "authentic" in some way.  A system could very easily have OSV, OEM, and ISV
>>>>>> keys install on them.  You can program RPM in such a way that it will refused to
>>>>>> install packages with unknown authentication keys or the non-repudiable key as well.
>>>>>>
>>>>>> So, I believe running delsign is wrong.  If the obs-signd can't handle ADDING
>>>>>> signatures to packages, then I'd say it is broken and should be fixed in some
>>>>>> way -- or at least the signature deletion code should be optional.
>>>>>
>>>>> Yes, unfortunately this is currently the limitation of obs-signd. It
>>>>> refuses to sign if there are signatures present in the rpm package.
>>>>> Using --delsign is "unfortunate" consequence of this and that should've
>>>>> probably been described in a comment. Making signature deletion a
>>>>> configurable setting is hopefully a decent resolution for now. I will
>>>>> send a new version of the patchset later.
>>>>
>>>> Backing up a bit here. I did some quick testing and it seems that RPM5
>>>> does not support multiple signatures (anymore?). Doing --addsign seems
>>>> to overwrite the existing signatures similarly to --resign. Support for
>>>> multiple signatures were removed from RPM4 years ago.
>>>>
>>>> In this light, doing --delsign should be ok. What do you think?
>>>
>>> Hi Mark. Do you have any comments to the above? I'd like to get this
>>> patchset out of my hands :)
>>
>> RPM5 does have multiple signatures, but only allows one of each of the three
>> types to be installed.  The delsign shouldn't be used as it might remove the
>> wrong signature.
> 
> AFAIU, rpm only allows one signature so be present. The file format allows that, but, the rpm tool does not (anymore). For example, rpm --addsign will remove an existing DSA signature when adding an RSA signature. The SHA1 / MD5 digests are not touched by --delsign.
> 
> 
>> (Three types are DSA/RSA, ECDSA, and simple SHA256 or similar.)
> 
> I didn't know that rpm(5?) supports ECDSA signatures.
> 
> 
>> But making the --delsign optional I think is the best approach.  (It would be
>> better to move it to the obs-sign script itself -- but I can live with doing it
>> on the OE side since people are trying to use their owns systems.)
> 
> I still believe that making it optional is just worthless and complicates things because doing rpm --addsign has exactly the same effect.
> 
> 
>> The alternative would be to not call the script 'obs-sign', but instead call an
>> arbitrarily named (and defined in a bitbake variable) script.. Then THAT script
>> can do the del and call the obs-sign.)
> 
> Hmm, I probably don't like this idea that much. This user-written script would need to be a bit more complex as a it needs to support multiple operations (signrpm, detach sign, export pubkey). Of course, I could write a default script and put it under scripts/ but somehow feels more complex than needed.

The more I look at this, the more I think that makes sense.

I've had some of my (WR Linux) release guys look at this, and the obs-sign
mechanism will not work for us.  So we're going to have to write some custom
signing code anyway.  It will be much easier if there is a generic interface.
The previous thought was to use the obs-sign "interface", but write our own...
but at that point OBS has nothing to do with it.. It's just really being used as
a signing interface.

I'm assuming at this point that we're not alone in this need.  I've talked to a
variety of commercial people and they all have slightly different signing
policies and mechanisms.  Everything from, we don't sign the packages but check
separate checksums -- to we sign locally with a local keyring key -- to we sign
locally with a special in-memory key -- to after every package is built we have
to upload the package to an (internal password protected) FTP/HTTP site and
trigger it to be signed, then once signed we download it.  (And of course OBS
specific signing...)

I think in this case an external script makes this all much easier for someone
to implement their specific policy and procedures, especially with a defined
API.  Including default scripts with this as useful runners or examples would
definitely be a part of the work in my mind.

--Mark

> 
> Thanks,
>   Markus
> 
> 



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

end of thread, other threads:[~2016-01-22 14:09 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-11 16:13 [PATCH 0/3] Support remote RPM signing Markus Lehtonen
2016-01-11 16:13 ` [PATCH 1/3] sign_rpm.bbclass: fix task dependencies Markus Lehtonen
2016-01-11 16:13 ` [PATCH 2/3] New lib module for handling GPG signing Markus Lehtonen
2016-01-11 16:13 ` [PATCH 3/3] oe.gpg_sign: support obs-signd Markus Lehtonen
2016-01-11 16:33   ` Mark Hatle
2016-01-12 16:24     ` Markus Lehtonen
2016-01-13 10:28       ` Markus Lehtonen
2016-01-13 14:56         ` Mark Hatle
2016-01-13 21:47           ` Mark Hatle
2016-01-21 15:28             ` Mark Hatle
     [not found]         ` <1453375237.13987.27.camel@linux.intel.com>
     [not found]           ` <56A0F794.7060603@windriver.com>
2016-01-22 10:43             ` Markus Lehtonen
2016-01-22 14:09               ` Mark Hatle

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.