Skip to contentSkip to conversation

IPK signing for the gpg_sign module

PATCH Superseded Ioan-Adrian Ratiu 2 participants 9 messages Mar 2, 2016 – Mar 3, 2016

v7 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v7 cover IPK signing for the gpg_sign module

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

Changes since v6:
* Added pubkey to signing_keys.bb and rebased on top of Randy's work
* Made gpg version detection logic more robust
* Simplified detach_sign() gpg communication (no more os.pipe)

Ioan-Adrian Ratiu (5):
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
signing-keys: create ipk package
package_manager: sign IPK package feeds

 meta/classes/package_ipk.bbclass       |  5 +++
 meta/classes/sign_ipk.bbclass          | 52 ++++++++++++++++++++++++++++
 meta/classes/sign_package_feed.bbclass | 17 ++++++++-
 meta/lib/oe/gpg_sign.py                | 63 ++++++++++++++++++++++++++--------
 meta/lib/oe/package_manager.py         | 17 +++++++--
 meta/recipes-core/meta/signing-keys.bb | 15 +++++++-
 6 files changed, 151 insertions(+), 18 deletions(-)
 create mode 100644 meta/classes/sign_ipk.bbclass
Signature · 1 line
2.7.1
#1 lore raw

PATCH v7 1/5 gpg_sign: add local ipk package signing functionality

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.

---
 meta/classes/package_ipk.bbclass |  5 ++++
 meta/classes/sign_ipk.bbclass    | 52 ++++++++++++++++++++++++++++++++++++++++
 meta/lib/oe/gpg_sign.py          | 41 +++++++++++++++++++++----------
 3 files changed, 86 insertions(+), 12 deletions(-)
 create mode 100644 meta/classes/sign_ipk.bbclass
meta/classes/package_ipk.bbclass +5 -0
index 51bee28..f1ad1d5 100644
@@ -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', True), d.getVar('PKGR', True))
+            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)
 
meta/classes/sign_ipk.bbclass new file +52 -0

52 lines not on this page · raw message

meta/lib/oe/gpg_sign.py +29 -12

62 lines not on this page · raw message

Signature · 1 line
2.7.1
#2 lore raw

Re: [PATCH v7 1/5] gpg_sign: add local ipk package signing functionality

Quoted 150 lines · Ioan-Adrian Ratiu

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.

---

meta/classes/package_ipk.bbclass |  5 ++++
meta/classes/sign_ipk.bbclass    | 52 ++++++++++++++++++++++++++++++++++++++++
meta/lib/oe/gpg_sign.py          | 41 +++++++++++++++++++++----------
3 files changed, 86 insertions(+), 12 deletions(-)

create mode 100644 meta/classes/sign_ipk.bbclass

meta/classes/package_ipk.bbclass +5 -0
index 51bee28..f1ad1d5 100644
@@ -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', True), d.getVar('PKGR', True))
+            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)
 
meta/classes/sign_ipk.bbclass new file +52 -0
new file mode 100644
index 0000000..a481f6d
@@ -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)
meta/lib/oe/gpg_sign.py +0 -0
index ada1b2f..1406f17 100644
@@ -1,5 +1,6 @@

"""Helper module for GPG signing"""
import os
+import sys

import bb
import oe.utils

meta/lib/oe/gpg_sign.py +17 -12
@@ -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
@@ -58,22 +60,37 @@ class LocalSigner(object):
            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']
+               '--passphrase-fd', '0', '-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))
+
+        cmd += [input_file]
+
+        try:
+            if passphrase_file:
+                with open(passphrase_file) as fobj:
+                    passphrase = fobj.readline();
+
+            job = subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
+            (_, stderr) = job.communicate(passphrase)
+
+            if job.returncode:
+                raise bb.build.FuncFailed("GPG exited with code %d: %s" %
+                                          (job.returncode, stderr))

meta/lib/oe/gpg_sign.py class LocalSigner(object): · line 92

Quoted 10 lines
meta/lib/oe/gpg_sign.py +10 -0
+
+        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)

Still one nitpick :) I would move the except clauses before the if statement. Otherwise the general "except:" is masking the bb.build.FuncFailed exception.

Thanks,
Markus

Quoted 4 lines
meta/lib/oe/gpg_sign.py +1 -0
+
 
    def verify(self, sig_file):
        """Verify signature"""
#3 lore raw

PATCH v7 2/5 gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor

In reply to Ioan-Adrian Ratiu

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

---
 meta/lib/oe/gpg_sign.py | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
meta/lib/oe/gpg_sign.py +16 -0
index 1406f17..5d9ad49 100644
@@ -67,6 +67,13 @@ 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
+        dots = self.get_gpg_version().split('.')
+        assert len(dots) >= 2
+        if int(dots[0]) >= 2 and int(dots[1]) >= 1:
+            cmd += ['--pinentry-mode', 'loopback']
+
         cmd += [input_file]
 
         try:
@@ -92,6 +99,15 @@ class LocalSigner(object):
             raise Exception("Failed to sign '%s'" % input_file)
 
 
+    def get_gpg_version(self):
+        """Return the gpg version"""
+        import subprocess
+        try:
+            return subprocess.check_output((self.gpg_bin, "--version")).split()[2]
+        except subprocess.CalledProcessError as e:
+            raise bb.build.FuncFailed("Could not get gpg version: %s" % e)
+
+
     def verify(self, sig_file):
         """Verify signature"""
         cmd = self.gpg_bin + " --verify "
Signature · 1 line
2.7.1
#4 lore raw

Re: [PATCH v7 2/5] gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor

Quoted 35 lines · Ioan-Adrian Ratiu

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

---
meta/lib/oe/gpg_sign.py | 16 ++++++++++++++++

1 file changed, 16 insertions(+)
meta/lib/oe/gpg_sign.py +7 -0
index 1406f17..5d9ad49 100644
@@ -67,6 +67,13 @@ 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
+        dots = self.get_gpg_version().split('.')
+        assert len(dots) >= 2
+        if int(dots[0]) >= 2 and int(dots[1]) >= 1:
+            cmd += ['--pinentry-mode', 'loopback']
+
        cmd += [input_file]
 
        try:

meta/lib/oe/gpg_sign.py class LocalSigner(object): · line 99

Quoted 1 line
meta/lib/oe/gpg_sign.py +0 -0
@@ -92,6 +99,15 @@ class LocalSigner(object):
            raise Exception("Failed to sign '%s'" % input_file)

Another nitpick: missing a line feed here(?)

Thanks,
Markus

Quoted 17 lines
meta/lib/oe/gpg_sign.py +9 -0
+    def get_gpg_version(self):
+        """Return the gpg version"""
+        import subprocess
+        try:
+            return subprocess.check_output((self.gpg_bin, "--version")).split()[2]
+        except subprocess.CalledProcessError as e:
+            raise bb.build.FuncFailed("Could not get gpg version: %s" % e)
+
+
    def verify(self, sig_file):
        """Verify signature"""
        cmd = self.gpg_bin + " --verify "
Signature · 1 line
2.7.1
#5 lore raw

PATCH v7 3/5 gpg_sign: export_pubkey: add signature type support

In reply to Ioan-Adrian Ratiu

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.

---
 meta/lib/oe/gpg_sign.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
meta/lib/oe/gpg_sign.py +4 -2
index 5d9ad49..1caba50 100644
@@ -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:
Signature · 1 line
2.7.1
#6 lore raw

PATCH v7 4/5 signing-keys: create ipk package

In reply to Ioan-Adrian Ratiu

Store the ascii armored pubkey generated using gpg_sign.export_pubkey() in its own package.

---
 meta/recipes-core/meta/signing-keys.bb | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)
meta/recipes-core/meta/signing-keys.bb +14 -1
index 1d0e834..e843301 100644
@@ -12,9 +12,10 @@ inherit allarch deploy
 EXCLUDE_FROM_WORLD = "1"
 INHIBIT_DEFAULT_DEPS = "1"
 
-PACKAGES =+ "${PN}-rpm ${PN}-packagefeed"
+PACKAGES =+ "${PN}-ipk ${PN}-rpm ${PN}-packagefeed"
 
 FILES_${PN}-rpm = "${sysconfdir}/pki/rpm-gpg"
+FILES_${PN}-ipk = "${sysconfdir}/pki/ipk-gpg"
 FILES_${PN}-packagefeed = "${sysconfdir}/pki/packagefeed-gpg"
 
 python do_get_public_keys () {
@@ -26,6 +27,12 @@ python do_get_public_keys () {
         signer.export_pubkey(os.path.join(d.expand('${B}'), 'rpm-key'),
                              d.getVar('RPM_GPG_NAME', True))
 
+    if d.getVar("IPK_SIGN_PACKAGES", True):
+        # Export public key of the ipk signing key
+        signer = get_signer(d, d.getVar('IPK_GPG_BACKEND', True))
+        signer.export_pubkey(os.path.join(d.expand('${B}'), 'ipk-key'),
+                             d.getVar('IPK_GPG_NAME', True))
+
     if d.getVar('PACKAGE_FEED_SIGN', True) == '1':
         # Export public key of the feed signing key
         signer = get_signer(d, d.getVar('PACKAGE_FEED_GPG_BACKEND', True))
@@ -39,6 +46,9 @@ do_install () {
     if [ -f "${B}/rpm-key" ]; then
         install -D -m 0644 "${B}/rpm-key" "${D}${sysconfdir}/pki/rpm-gpg/RPM-GPG-KEY-${DISTRO_VERSION}"
     fi
+    if [ -f "${B}/ipk-key" ]; then
+        install -D -m 0644 "${B}/ipk-key" "${D}${sysconfdir}/pki/ipk-gpg/IPK-GPG-KEY-${DISTRO_VERSION}"
+    fi
     if [ -f "${B}/pf-key" ]; then
         install -D -m 0644 "${B}/pf-key" "${D}${sysconfdir}/pki/packagefeed-gpg/PACKAGEFEED-GPG-KEY-${DISTRO_VERSION}"
     fi
@@ -52,6 +62,9 @@ do_deploy () {
     if [ -f "${B}/rpm-key" ]; then
         install -D -m 0644 "${B}/rpm-key" "${DEPLOYDIR}/RPM-GPG-KEY-${DISTRO_VERSION}"
     fi
+    if [ -f "${B}/ipk-key" ]; then
+        install -D -m 0644 "${B}/ipk-key" "${DEPLOYDIR}/IPK-GPG-KEY-${DISTRO_VERSION}"
+    fi
     if [ -f "${B}/pf-key" ]; then
         install -D -m 0644 "${B}/pf-key" "${DEPLOYDIR}/PACKAGEFEED-GPG-KEY-${DISTRO_VERSION}"
     fi
Signature · 1 line
2.7.1
#7 lore raw

PATCH v7 5/5 package_manager: sign IPK package feeds

In reply to Ioan-Adrian Ratiu

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

---
 meta/classes/sign_package_feed.bbclass | 17 ++++++++++++++++-
 meta/lib/oe/package_manager.py         | 17 +++++++++++++++--
 2 files changed, 31 insertions(+), 3 deletions(-)
meta/classes/sign_package_feed.bbclass +16 -1
index e1ec82e..ddb6ac5 100644
@@ -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,13 +26,22 @@ inherit sanity
 
 PACKAGE_FEED_SIGN = '1'
 PACKAGE_FEED_GPG_BACKEND ?= 'local'
-
+PACKAGE_FEED_GPG_SIGNATURE_TYPE ?= 'ASC'
 
 python () {
     # Check sanity of configuration
     for var in ('PACKAGE_FEED_GPG_NAME', 'PACKAGE_FEED_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("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),
+                                   'PACKAGE-FEED-GPG-PUBKEY'))
 }
 
 do_package_index[depends] += "signing-keys:do_deploy"
meta/lib/oe/package_manager.py +15 -2
index 5cd43e9..7e3baef 100644
@@ -153,11 +153,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:
@@ -176,6 +181,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
@@ -183,9 +190,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):
Signature · 1 line
2.7.1
#8 lore raw

Re: [PATCH v7 5/5] package_manager: sign IPK package feeds

Quoted 37 lines · Ioan-Adrian Ratiu

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

---
meta/classes/sign_package_feed.bbclass | 17 ++++++++++++++++-
meta/lib/oe/package_manager.py | 17 +++++++++++++++--

2 files changed, 31 insertions(+), 3 deletions(-)
meta/classes/sign_package_feed.bbclass +6 -0
index e1ec82e..ddb6ac5 100644
@@ -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,13 +26,22 @@ inherit sanity
 

PACKAGE_FEED_SIGN = '1'
PACKAGE_FEED_GPG_BACKEND ?= 'local'

meta/classes/sign_package_feed.bbclass +1 -1
-
+PACKAGE_FEED_GPG_SIGNATURE_TYPE ?= 'ASC'

python () {
# Check sanity of configuration
for var in ('PACKAGE_FEED_GPG_NAME', 'PACKAGE_FEED_GPG_PASSPHRASE_FILE'):
if not d.getVar(var, True):
raise_sanity_error("You need to define %s in the config" % var, d)

meta/classes/sign_package_feed.bbclass inherit sanity · line 44

Quoted 9 lines
meta/classes/sign_package_feed.bbclass +9 -0
+
+    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),
+                                   'PACKAGE-FEED-GPG-PUBKEY'))

We just got rid of the PACKAGE_FEED_GPG_PUBKEY variable in a recent patch from Randy Witt. There should be no reason to re-introduce it.

Thanks,
Markus

Quoted 54 lines

}

do_package_index[depends] += "signing-keys:do_deploy"

meta/lib/oe/package_manager.py +15 -2
index 5cd43e9..7e3baef 100644
@@ -153,11 +153,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:
@@ -176,6 +181,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
@@ -183,9 +190,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):

Signature · 1 line
2.7.1