* [PATCH v5 0/3] IPK signing for the gpg_sign module
@ 2016-02-17 15:41 Ioan-Adrian Ratiu
2016-02-17 15:41 ` [PATCH v5 1/3] gpg_sign: add local ipk package signing functionality Ioan-Adrian Ratiu
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Ioan-Adrian Ratiu @ 2016-02-17 15:41 UTC (permalink / raw)
To: openembedded-core
This patch series extends the gpg_sign module to support ipk signing.
v5 is a rebase on top of Markus' refactoring of the gpg_sign module.
Most notably signature types have been reworked to function parameters
with default values in accordance with the refactoring.
Ioan-Adrian Ratiu (3):
gpg_sign: add local ipk package signing functionality
gpg_sign: detached_sign: add signature type support
package_manager: sign IPK package feeds
meta/classes/package_ipk.bbclass | 6 ++++
meta/classes/sign_ipk.bbclass | 55 ++++++++++++++++++++++++++++++++++
meta/classes/sign_package_feed.bbclass | 10 ++++++-
meta/lib/oe/gpg_sign.py | 45 ++++++++++++++++++++++++++--
meta/lib/oe/package_manager.py | 17 +++++++++--
5 files changed, 128 insertions(+), 5 deletions(-)
create mode 100644 meta/classes/sign_ipk.bbclass
--
2.7.1
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v5 1/3] gpg_sign: add local ipk package signing functionality 2016-02-17 15:41 [PATCH v5 0/3] IPK signing for the gpg_sign module Ioan-Adrian Ratiu @ 2016-02-17 15:41 ` Ioan-Adrian Ratiu 2016-02-18 9:04 ` Markus Lehtonen 2016-02-17 15:41 ` [PATCH v5 2/3] gpg_sign: detached_sign: add signature type support Ioan-Adrian Ratiu 2016-02-17 15:41 ` [PATCH v5 3/3] package_manager: sign IPK package feeds Ioan-Adrian Ratiu 2 siblings, 1 reply; 11+ messages in thread From: Ioan-Adrian Ratiu @ 2016-02-17 15:41 UTC (permalink / raw) To: openembedded-core Implement local ipk signing logic inside the gpg backend and add a new bbclass which configures signing similar to how rpm does it. The ipk signing process is a bit different from rpm: - Signatures are stored outside ipk files; opkg connects to a feed server and downloads them to verify a package. - Signatures are of two types (both supported by opkg): binary or ascii armoured. By default we sign using ascii armoured. - Public keys are stored on targets to verify ipks using the opkg-keyrings recipe. Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com> --- meta/classes/package_ipk.bbclass | 6 +++++ meta/classes/sign_ipk.bbclass | 55 ++++++++++++++++++++++++++++++++++++++++ meta/lib/oe/gpg_sign.py | 39 ++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 meta/classes/sign_ipk.bbclass diff --git a/meta/classes/package_ipk.bbclass b/meta/classes/package_ipk.bbclass index 51bee28..4f5bbd0 100644 --- a/meta/classes/package_ipk.bbclass +++ b/meta/classes/package_ipk.bbclass @@ -246,6 +246,12 @@ python do_package_ipk () { bb.utils.unlockfile(lf) raise bb.build.FuncFailed("opkg-build execution failed") + if d.getVar('IPK_SIGN_PACKAGES', True) == '1': + ipkver = "%s-%s" % (d.getVar('PKGV'), d.getVar('PKGR')) + ipk_to_sign = "%s/%s_%s_%s.ipk" % (pkgoutdir, pkgname, ipkver, d.getVar('PACKAGE_ARCH', True)) + d.setVar('IPK_TO_SIGN', ipk_to_sign) + bb.build.exec_func("sign_ipk", d) + cleanupcontrol(root) bb.utils.unlockfile(lf) diff --git a/meta/classes/sign_ipk.bbclass b/meta/classes/sign_ipk.bbclass new file mode 100644 index 0000000..cb22bb4 --- /dev/null +++ b/meta/classes/sign_ipk.bbclass @@ -0,0 +1,55 @@ +# 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) +} + +python sign_ipk () { + from oe.gpg_sign import get_signer + + ipk_file = d.getVar('IPK_TO_SIGN') + bb.debug(1, 'Signing ipk: %s' % ipk_file) + + 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.sign_ipk(ipk_file, + d.getVar('IPK_GPG_NAME', True), + d.getVar('IPK_GPG_PASSPHRASE_FILE', True), + is_ascii_sig) +} diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py index ada1b2f..138499b 100644 --- a/meta/lib/oe/gpg_sign.py +++ b/meta/lib/oe/gpg_sign.py @@ -1,5 +1,6 @@ """Helper module for GPG signing""" import os +import sys import bb import oe.utils @@ -50,6 +51,44 @@ class LocalSigner(object): bb.error('rpmsign failed: %s' % proc.before.strip()) raise bb.build.FuncFailed("Failed to sign RPM packages") + def sign_ipk(self, ipkfile, keyid, passphrase_file, armor=True): + """Sign IPK files""" + import subprocess + from subprocess import Popen + + cmd = [self.gpg_bin, "-q", "--batch", "--yes", "-b", "-u", keyid] + if self.gpg_path: + cmd += ["--homedir", self.gpg_path] + if armor: + cmd += ["--armor"] + + try: + keypipe = os.pipe() + + # Need to add '\n' in case the passfile does not have it + with open(passphrase_file) as fobj: + os.write(keypipe[1], fobj.readline() + '\n') + + cmd += ["--passphrase-fd", str(keypipe[0])] + cmd += [ipkfile] + + gpg_proc = Popen(cmd, stdin=subprocess.PIPE) + gpg_proc.wait() + + os.close(keypipe[1]); + os.close(keypipe[0]); + + except IOError as e: + bb.error("IO error ({0}): {1}".format(e.errno, e.strerror)) + raise bb.build.FuncFailed("Failed to sign IPK packages") + except OSError as e: + bb.error("OS error ({0}): {1}".format(e.errno, e.strerror)) + raise bb.build.FuncFailed("Failed to sign IPK packages") + except: + bb.error("Unexpected error: {1}".format(sys.exc_info()[0])) + raise bb.build.FuncFailed("Failed to sign IPK packages") + + def detach_sign(self, input_file, keyid, passphrase_file, passphrase=None, armor=True): """Create a detached signature of a file""" import subprocess -- 2.7.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v5 1/3] gpg_sign: add local ipk package signing functionality 2016-02-17 15:41 ` [PATCH v5 1/3] gpg_sign: add local ipk package signing functionality Ioan-Adrian Ratiu @ 2016-02-18 9:04 ` Markus Lehtonen 2016-02-18 9:28 ` Ioan-Adrian Ratiu 0 siblings, 1 reply; 11+ messages in thread From: Markus Lehtonen @ 2016-02-18 9:04 UTC (permalink / raw) To: Ioan-Adrian Ratiu, openembedded-core Hi, On 17/02/16 17:41, "Ioan-Adrian Ratiu" <openembedded-core-bounces@lists.openembedded.org on behalf of adrian.ratiu@ni.com> wrote: >Implement local ipk signing logic inside the gpg backend and add a new >bbclass which configures signing similar to how rpm does it. > >The ipk signing process is a bit different from rpm: > - Signatures are stored outside ipk files; opkg connects to a feed >server and downloads them to verify a package. > - Signatures are of two types (both supported by opkg): binary or >ascii armoured. By default we sign using ascii armoured. > - Public keys are stored on targets to verify ipks using the >opkg-keyrings recipe. > >Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com> >--- > meta/classes/package_ipk.bbclass | 6 +++++ > meta/classes/sign_ipk.bbclass | 55 ++++++++++++++++++++++++++++++++++++++++ > meta/lib/oe/gpg_sign.py | 39 ++++++++++++++++++++++++++++ > 3 files changed, 100 insertions(+) > create mode 100644 meta/classes/sign_ipk.bbclass > >diff --git a/meta/classes/package_ipk.bbclass b/meta/classes/package_ipk.bbclass >index 51bee28..4f5bbd0 100644 >--- a/meta/classes/package_ipk.bbclass >+++ b/meta/classes/package_ipk.bbclass >@@ -246,6 +246,12 @@ python do_package_ipk () { > bb.utils.unlockfile(lf) > raise bb.build.FuncFailed("opkg-build execution failed") > >+ if d.getVar('IPK_SIGN_PACKAGES', True) == '1': >+ ipkver = "%s-%s" % (d.getVar('PKGV'), d.getVar('PKGR')) >+ ipk_to_sign = "%s/%s_%s_%s.ipk" % (pkgoutdir, pkgname, ipkver, d.getVar('PACKAGE_ARCH', True)) >+ d.setVar('IPK_TO_SIGN', ipk_to_sign) >+ bb.build.exec_func("sign_ipk", d) >+ > cleanupcontrol(root) > bb.utils.unlockfile(lf) > >diff --git a/meta/classes/sign_ipk.bbclass b/meta/classes/sign_ipk.bbclass >new file mode 100644 >index 0000000..cb22bb4 >--- /dev/null >+++ b/meta/classes/sign_ipk.bbclass >@@ -0,0 +1,55 @@ >+# 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) >+} >+ >+python sign_ipk () { >+ from oe.gpg_sign import get_signer >+ >+ ipk_file = d.getVar('IPK_TO_SIGN') >+ bb.debug(1, 'Signing ipk: %s' % ipk_file) >+ >+ 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.sign_ipk(ipk_file, >+ d.getVar('IPK_GPG_NAME', True), >+ d.getVar('IPK_GPG_PASSPHRASE_FILE', True), >+ is_ascii_sig) >+} To me, it would be seem more straightforward to not circulate ipk_to_sign through 'd'. Just define a regular python function like def sign_ipk(d, ipk_to_sign): ... And then in package_ipk.bbclass just do "sign_ipk(d, ipk_to_sign)" instead of bb.build.exec_func("sign_ipk", d)" >diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py >index ada1b2f..138499b 100644 >--- a/meta/lib/oe/gpg_sign.py >+++ b/meta/lib/oe/gpg_sign.py >@@ -1,5 +1,6 @@ > """Helper module for GPG signing""" > import os >+import sys > > import bb > import oe.utils >@@ -50,6 +51,44 @@ class LocalSigner(object): > bb.error('rpmsign failed: %s' % proc.before.strip()) > raise bb.build.FuncFailed("Failed to sign RPM packages") > >+ def sign_ipk(self, ipkfile, keyid, passphrase_file, armor=True): >+ """Sign IPK files""" >+ import subprocess >+ from subprocess import Popen >+ >+ cmd = [self.gpg_bin, "-q", "--batch", "--yes", "-b", "-u", keyid] >+ if self.gpg_path: >+ cmd += ["--homedir", self.gpg_path] >+ if armor: >+ cmd += ["--armor"] >+ >+ try: >+ keypipe = os.pipe() >+ >+ # Need to add '\n' in case the passfile does not have it >+ with open(passphrase_file) as fobj: >+ os.write(keypipe[1], fobj.readline() + '\n') >+ >+ cmd += ["--passphrase-fd", str(keypipe[0])] >+ cmd += [ipkfile] >+ >+ gpg_proc = Popen(cmd, stdin=subprocess.PIPE) >+ gpg_proc.wait() >+ >+ os.close(keypipe[1]); >+ os.close(keypipe[0]); >+ >+ except IOError as e: >+ bb.error("IO error ({0}): {1}".format(e.errno, e.strerror)) >+ raise bb.build.FuncFailed("Failed to sign IPK packages") >+ except OSError as e: >+ bb.error("OS error ({0}): {1}".format(e.errno, e.strerror)) >+ raise bb.build.FuncFailed("Failed to sign IPK packages") >+ except: >+ bb.error("Unexpected error: {1}".format(sys.exc_info()[0])) >+ raise bb.build.FuncFailed("Failed to sign IPK packages") >+ >+ > def detach_sign(self, input_file, keyid, passphrase_file, passphrase=None, armor=True): > """Create a detached signature of a file""" > import subprocess Couldn't you just use detach_sign() instead of introducing sign_ipk(). To me the functionality seems identical. Thanks, Markus ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v5 1/3] gpg_sign: add local ipk package signing functionality 2016-02-18 9:04 ` Markus Lehtonen @ 2016-02-18 9:28 ` Ioan-Adrian Ratiu 2016-02-18 15:26 ` Markus Lehtonen 2016-02-19 11:18 ` Ioan-Adrian Ratiu 0 siblings, 2 replies; 11+ messages in thread From: Ioan-Adrian Ratiu @ 2016-02-18 9:28 UTC (permalink / raw) To: Markus Lehtonen; +Cc: openembedded-core Hello On Thu, 18 Feb 2016 11:04:22 +0200 Markus Lehtonen <markus.lehtonen@linux.intel.com> wrote: > Hi, > > > > On 17/02/16 17:41, "Ioan-Adrian Ratiu" <openembedded-core-bounces@lists.openembedded.org on behalf of adrian.ratiu@ni.com> wrote: > > >Implement local ipk signing logic inside the gpg backend and add a new > >bbclass which configures signing similar to how rpm does it. > > > >The ipk signing process is a bit different from rpm: > > - Signatures are stored outside ipk files; opkg connects to a feed > >server and downloads them to verify a package. > > - Signatures are of two types (both supported by opkg): binary or > >ascii armoured. By default we sign using ascii armoured. > > - Public keys are stored on targets to verify ipks using the > >opkg-keyrings recipe. > > > >Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com> > >--- > > meta/classes/package_ipk.bbclass | 6 +++++ > > meta/classes/sign_ipk.bbclass | 55 ++++++++++++++++++++++++++++++++++++++++ > > meta/lib/oe/gpg_sign.py | 39 ++++++++++++++++++++++++++++ > > 3 files changed, 100 insertions(+) > > create mode 100644 meta/classes/sign_ipk.bbclass > > > >diff --git a/meta/classes/package_ipk.bbclass b/meta/classes/package_ipk.bbclass > >index 51bee28..4f5bbd0 100644 > >--- a/meta/classes/package_ipk.bbclass > >+++ b/meta/classes/package_ipk.bbclass > >@@ -246,6 +246,12 @@ python do_package_ipk () { > > bb.utils.unlockfile(lf) > > raise bb.build.FuncFailed("opkg-build execution failed") > > > >+ if d.getVar('IPK_SIGN_PACKAGES', True) == '1': > >+ ipkver = "%s-%s" % (d.getVar('PKGV'), d.getVar('PKGR')) > >+ ipk_to_sign = "%s/%s_%s_%s.ipk" % (pkgoutdir, pkgname, ipkver, d.getVar('PACKAGE_ARCH', True)) > >+ d.setVar('IPK_TO_SIGN', ipk_to_sign) > >+ bb.build.exec_func("sign_ipk", d) > >+ > > cleanupcontrol(root) > > bb.utils.unlockfile(lf) > > > >diff --git a/meta/classes/sign_ipk.bbclass b/meta/classes/sign_ipk.bbclass > >new file mode 100644 > >index 0000000..cb22bb4 > >--- /dev/null > >+++ b/meta/classes/sign_ipk.bbclass > >@@ -0,0 +1,55 @@ > >+# 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) > >+} > >+ > >+python sign_ipk () { > >+ from oe.gpg_sign import get_signer > >+ > >+ ipk_file = d.getVar('IPK_TO_SIGN') > >+ bb.debug(1, 'Signing ipk: %s' % ipk_file) > >+ > >+ 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.sign_ipk(ipk_file, > >+ d.getVar('IPK_GPG_NAME', True), > >+ d.getVar('IPK_GPG_PASSPHRASE_FILE', True), > >+ is_ascii_sig) > >+} > > To me, it would be seem more straightforward to not circulate ipk_to_sign through 'd'. Just define a regular python function like > def sign_ipk(d, ipk_to_sign): > ... > > And then in package_ipk.bbclass just do "sign_ipk(d, ipk_to_sign)" instead of bb.build.exec_func("sign_ipk", d)" > > > > > >diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py > >index ada1b2f..138499b 100644 > >--- a/meta/lib/oe/gpg_sign.py > >+++ b/meta/lib/oe/gpg_sign.py > >@@ -1,5 +1,6 @@ > > """Helper module for GPG signing""" > > import os > >+import sys > > > > import bb > > import oe.utils > >@@ -50,6 +51,44 @@ class LocalSigner(object): > > bb.error('rpmsign failed: %s' % proc.before.strip()) > > raise bb.build.FuncFailed("Failed to sign RPM packages") > > > >+ def sign_ipk(self, ipkfile, keyid, passphrase_file, armor=True): > >+ """Sign IPK files""" > >+ import subprocess > >+ from subprocess import Popen > >+ > >+ cmd = [self.gpg_bin, "-q", "--batch", "--yes", "-b", "-u", keyid] > >+ if self.gpg_path: > >+ cmd += ["--homedir", self.gpg_path] > >+ if armor: > >+ cmd += ["--armor"] > >+ > >+ try: > >+ keypipe = os.pipe() > >+ > >+ # Need to add '\n' in case the passfile does not have it > >+ with open(passphrase_file) as fobj: > >+ os.write(keypipe[1], fobj.readline() + '\n') > >+ > >+ cmd += ["--passphrase-fd", str(keypipe[0])] > >+ cmd += [ipkfile] > >+ > >+ gpg_proc = Popen(cmd, stdin=subprocess.PIPE) > >+ gpg_proc.wait() > >+ > >+ os.close(keypipe[1]); > >+ os.close(keypipe[0]); > >+ > >+ except IOError as e: > >+ bb.error("IO error ({0}): {1}".format(e.errno, e.strerror)) > >+ raise bb.build.FuncFailed("Failed to sign IPK packages") > >+ except OSError as e: > >+ bb.error("OS error ({0}): {1}".format(e.errno, e.strerror)) > >+ raise bb.build.FuncFailed("Failed to sign IPK packages") > >+ except: > >+ bb.error("Unexpected error: {1}".format(sys.exc_info()[0])) > >+ raise bb.build.FuncFailed("Failed to sign IPK packages") > >+ > >+ > > def detach_sign(self, input_file, keyid, passphrase_file, passphrase=None, armor=True): > > """Create a detached signature of a file""" > > import subprocess > > Couldn't you just use detach_sign() instead of introducing sign_ipk(). To me the functionality seems identical. The functionality is almost identical, yes, and consolidating it into one function is a very good idea. I'll do it but I have one question. The only diference between them is the usage in detach-sign of gpg's "--with-passphrase" arg, and that arg seems to cause some errors on my system: "gpg: signing failed: Inappropriate ioctl for device" I have not managed to reliably reproduce and find the cause of this issue. However, if we always open the file in python and read directly in a pipe which we always pass to gpg using "--passphrase-fd", the error goes away. Is using something like the following in detach_sign() ok with you? with open(passphrase_file) as fobj: os.write(keypipe[1], fobj.readline() + '\n') cmd += ["--passphrase-fd", str(keypipe[0])] > > > Thanks, > Markus > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v5 1/3] gpg_sign: add local ipk package signing functionality 2016-02-18 9:28 ` Ioan-Adrian Ratiu @ 2016-02-18 15:26 ` Markus Lehtonen 2016-02-19 11:18 ` Ioan-Adrian Ratiu 1 sibling, 0 replies; 11+ messages in thread From: Markus Lehtonen @ 2016-02-18 15:26 UTC (permalink / raw) To: Ioan-Adrian Ratiu; +Cc: openembedded-core On 18/02/16 11:28, "Ioan-Adrian Ratiu" <adrian.ratiu@ni.com> wrote: >Hello > >On Thu, 18 Feb 2016 11:04:22 +0200 >Markus Lehtonen <markus.lehtonen@linux.intel.com> wrote: > >> Hi, >> >> >> >> On 17/02/16 17:41, "Ioan-Adrian Ratiu" <openembedded-core-bounces@lists.openembedded.org on behalf of adrian.ratiu@ni.com> wrote: >> >> >Implement local ipk signing logic inside the gpg backend and add a new >> >bbclass which configures signing similar to how rpm does it. >> > >> >The ipk signing process is a bit different from rpm: >> > - Signatures are stored outside ipk files; opkg connects to a feed >> >server and downloads them to verify a package. >> > - Signatures are of two types (both supported by opkg): binary or >> >ascii armoured. By default we sign using ascii armoured. >> > - Public keys are stored on targets to verify ipks using the >> >opkg-keyrings recipe. >> > >> >Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com> >> >--- >> > meta/classes/package_ipk.bbclass | 6 +++++ >> > meta/classes/sign_ipk.bbclass | 55 ++++++++++++++++++++++++++++++++++++++++ >> > meta/lib/oe/gpg_sign.py | 39 ++++++++++++++++++++++++++++ >> > 3 files changed, 100 insertions(+) >> > create mode 100644 meta/classes/sign_ipk.bbclass >> > >> >diff --git a/meta/classes/package_ipk.bbclass b/meta/classes/package_ipk.bbclass >> >index 51bee28..4f5bbd0 100644 >> >--- a/meta/classes/package_ipk.bbclass >> >+++ b/meta/classes/package_ipk.bbclass >> >@@ -246,6 +246,12 @@ python do_package_ipk () { >> > bb.utils.unlockfile(lf) >> > raise bb.build.FuncFailed("opkg-build execution failed") >> > >> >+ if d.getVar('IPK_SIGN_PACKAGES', True) == '1': >> >+ ipkver = "%s-%s" % (d.getVar('PKGV'), d.getVar('PKGR')) >> >+ ipk_to_sign = "%s/%s_%s_%s.ipk" % (pkgoutdir, pkgname, ipkver, d.getVar('PACKAGE_ARCH', True)) >> >+ d.setVar('IPK_TO_SIGN', ipk_to_sign) >> >+ bb.build.exec_func("sign_ipk", d) >> >+ >> > cleanupcontrol(root) >> > bb.utils.unlockfile(lf) >> > >> >diff --git a/meta/classes/sign_ipk.bbclass b/meta/classes/sign_ipk.bbclass >> >new file mode 100644 >> >index 0000000..cb22bb4 >> >--- /dev/null >> >+++ b/meta/classes/sign_ipk.bbclass >> >@@ -0,0 +1,55 @@ >> >+# 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) >> >+} >> >+ >> >+python sign_ipk () { >> >+ from oe.gpg_sign import get_signer >> >+ >> >+ ipk_file = d.getVar('IPK_TO_SIGN') >> >+ bb.debug(1, 'Signing ipk: %s' % ipk_file) >> >+ >> >+ 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.sign_ipk(ipk_file, >> >+ d.getVar('IPK_GPG_NAME', True), >> >+ d.getVar('IPK_GPG_PASSPHRASE_FILE', True), >> >+ is_ascii_sig) >> >+} >> >> To me, it would be seem more straightforward to not circulate ipk_to_sign through 'd'. Just define a regular python function like >> def sign_ipk(d, ipk_to_sign): >> ... >> >> And then in package_ipk.bbclass just do "sign_ipk(d, ipk_to_sign)" instead of bb.build.exec_func("sign_ipk", d)" >> >> >> >> >> >diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py >> >index ada1b2f..138499b 100644 >> >--- a/meta/lib/oe/gpg_sign.py >> >+++ b/meta/lib/oe/gpg_sign.py >> >@@ -1,5 +1,6 @@ >> > """Helper module for GPG signing""" >> > import os >> >+import sys >> > >> > import bb >> > import oe.utils >> >@@ -50,6 +51,44 @@ class LocalSigner(object): >> > bb.error('rpmsign failed: %s' % proc.before.strip()) >> > raise bb.build.FuncFailed("Failed to sign RPM packages") >> > >> >+ def sign_ipk(self, ipkfile, keyid, passphrase_file, armor=True): >> >+ """Sign IPK files""" >> >+ import subprocess >> >+ from subprocess import Popen >> >+ >> >+ cmd = [self.gpg_bin, "-q", "--batch", "--yes", "-b", "-u", keyid] >> >+ if self.gpg_path: >> >+ cmd += ["--homedir", self.gpg_path] >> >+ if armor: >> >+ cmd += ["--armor"] >> >+ >> >+ try: >> >+ keypipe = os.pipe() >> >+ >> >+ # Need to add '\n' in case the passfile does not have it >> >+ with open(passphrase_file) as fobj: >> >+ os.write(keypipe[1], fobj.readline() + '\n') >> >+ >> >+ cmd += ["--passphrase-fd", str(keypipe[0])] >> >+ cmd += [ipkfile] >> >+ >> >+ gpg_proc = Popen(cmd, stdin=subprocess.PIPE) >> >+ gpg_proc.wait() >> >+ >> >+ os.close(keypipe[1]); >> >+ os.close(keypipe[0]); >> >+ >> >+ except IOError as e: >> >+ bb.error("IO error ({0}): {1}".format(e.errno, e.strerror)) >> >+ raise bb.build.FuncFailed("Failed to sign IPK packages") >> >+ except OSError as e: >> >+ bb.error("OS error ({0}): {1}".format(e.errno, e.strerror)) >> >+ raise bb.build.FuncFailed("Failed to sign IPK packages") >> >+ except: >> >+ bb.error("Unexpected error: {1}".format(sys.exc_info()[0])) >> >+ raise bb.build.FuncFailed("Failed to sign IPK packages") >> >+ >> >+ >> > def detach_sign(self, input_file, keyid, passphrase_file, passphrase=None, armor=True): >> > """Create a detached signature of a file""" >> > import subprocess >> >> Couldn't you just use detach_sign() instead of introducing sign_ipk(). To me the functionality seems identical. > >The functionality is almost identical, yes, and consolidating it into one function is a very good idea. I'll do it but I have one question. > >The only diference between them is the usage in detach-sign of gpg's "--with-passphrase" arg, and that arg seems to cause some errors on my system: >"gpg: signing failed: Inappropriate ioctl for device" You mean the "--passphrase-file" option? I don't see any "--with-passphrase" option anywhere. The problem sounds really strange. What host OS and gpg version do you have? I'd like to understand what is happening there. >I have not managed to reliably reproduce and find the cause of this issue. However, if we always open the file in python and read directly in a pipe which >we always pass to gpg using "--passphrase-fd", the error goes away. > >Is using something like the following in detach_sign() ok with you? > >with open(passphrase_file) as fobj: > os.write(keypipe[1], fobj.readline() + '\n') > >cmd += ["--passphrase-fd", str(keypipe[0])] If we need to do this, why do you want to use pipes? Why not just something like with open(passphrase_file) as fobj: job.communicate(fobj.readline() + '\n') Thanks, Markus ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v5 1/3] gpg_sign: add local ipk package signing functionality 2016-02-18 9:28 ` Ioan-Adrian Ratiu 2016-02-18 15:26 ` Markus Lehtonen @ 2016-02-19 11:18 ` Ioan-Adrian Ratiu 2016-02-19 13:42 ` Ioan-Adrian Ratiu 1 sibling, 1 reply; 11+ messages in thread From: Ioan-Adrian Ratiu @ 2016-02-19 11:18 UTC (permalink / raw) To: Markus Lehtonen; +Cc: openembedded-core On Thu, 18 Feb 2016 11:28:58 +0200 Ioan-Adrian Ratiu <adrian.ratiu@ni.com> wrote: > Hello > > On Thu, 18 Feb 2016 11:04:22 +0200 > Markus Lehtonen <markus.lehtonen@linux.intel.com> wrote: > > > Hi, > > > > > > > > On 17/02/16 17:41, "Ioan-Adrian Ratiu" <openembedded-core-bounces@lists.openembedded.org on behalf of adrian.ratiu@ni.com> wrote: > > > > >Implement local ipk signing logic inside the gpg backend and add a new > > >bbclass which configures signing similar to how rpm does it. > > > > > >The ipk signing process is a bit different from rpm: > > > - Signatures are stored outside ipk files; opkg connects to a feed > > >server and downloads them to verify a package. > > > - Signatures are of two types (both supported by opkg): binary or > > >ascii armoured. By default we sign using ascii armoured. > > > - Public keys are stored on targets to verify ipks using the > > >opkg-keyrings recipe. > > > > > >Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com> > > >--- > > > meta/classes/package_ipk.bbclass | 6 +++++ > > > meta/classes/sign_ipk.bbclass | 55 ++++++++++++++++++++++++++++++++++++++++ > > > meta/lib/oe/gpg_sign.py | 39 ++++++++++++++++++++++++++++ > > > 3 files changed, 100 insertions(+) > > > create mode 100644 meta/classes/sign_ipk.bbclass > > > > > >diff --git a/meta/classes/package_ipk.bbclass b/meta/classes/package_ipk.bbclass > > >index 51bee28..4f5bbd0 100644 > > >--- a/meta/classes/package_ipk.bbclass > > >+++ b/meta/classes/package_ipk.bbclass > > >@@ -246,6 +246,12 @@ python do_package_ipk () { > > > bb.utils.unlockfile(lf) > > > raise bb.build.FuncFailed("opkg-build execution failed") > > > > > >+ if d.getVar('IPK_SIGN_PACKAGES', True) == '1': > > >+ ipkver = "%s-%s" % (d.getVar('PKGV'), d.getVar('PKGR')) > > >+ ipk_to_sign = "%s/%s_%s_%s.ipk" % (pkgoutdir, pkgname, ipkver, d.getVar('PACKAGE_ARCH', True)) > > >+ d.setVar('IPK_TO_SIGN', ipk_to_sign) > > >+ bb.build.exec_func("sign_ipk", d) > > >+ > > > cleanupcontrol(root) > > > bb.utils.unlockfile(lf) > > > > > >diff --git a/meta/classes/sign_ipk.bbclass b/meta/classes/sign_ipk.bbclass > > >new file mode 100644 > > >index 0000000..cb22bb4 > > >--- /dev/null > > >+++ b/meta/classes/sign_ipk.bbclass > > >@@ -0,0 +1,55 @@ > > >+# 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) > > >+} > > >+ > > >+python sign_ipk () { > > >+ from oe.gpg_sign import get_signer > > >+ > > >+ ipk_file = d.getVar('IPK_TO_SIGN') > > >+ bb.debug(1, 'Signing ipk: %s' % ipk_file) > > >+ > > >+ 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.sign_ipk(ipk_file, > > >+ d.getVar('IPK_GPG_NAME', True), > > >+ d.getVar('IPK_GPG_PASSPHRASE_FILE', True), > > >+ is_ascii_sig) > > >+} > > > > To me, it would be seem more straightforward to not circulate ipk_to_sign through 'd'. Just define a regular python function like > > def sign_ipk(d, ipk_to_sign): > > ... > > > > And then in package_ipk.bbclass just do "sign_ipk(d, ipk_to_sign)" instead of bb.build.exec_func("sign_ipk", d)" > > > > > > > > > > >diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py > > >index ada1b2f..138499b 100644 > > >--- a/meta/lib/oe/gpg_sign.py > > >+++ b/meta/lib/oe/gpg_sign.py > > >@@ -1,5 +1,6 @@ > > > """Helper module for GPG signing""" > > > import os > > >+import sys > > > > > > import bb > > > import oe.utils > > >@@ -50,6 +51,44 @@ class LocalSigner(object): > > > bb.error('rpmsign failed: %s' % proc.before.strip()) > > > raise bb.build.FuncFailed("Failed to sign RPM packages") > > > > > >+ def sign_ipk(self, ipkfile, keyid, passphrase_file, armor=True): > > >+ """Sign IPK files""" > > >+ import subprocess > > >+ from subprocess import Popen > > >+ > > >+ cmd = [self.gpg_bin, "-q", "--batch", "--yes", "-b", "-u", keyid] > > >+ if self.gpg_path: > > >+ cmd += ["--homedir", self.gpg_path] > > >+ if armor: > > >+ cmd += ["--armor"] > > >+ > > >+ try: > > >+ keypipe = os.pipe() > > >+ > > >+ # Need to add '\n' in case the passfile does not have it > > >+ with open(passphrase_file) as fobj: > > >+ os.write(keypipe[1], fobj.readline() + '\n') > > >+ > > >+ cmd += ["--passphrase-fd", str(keypipe[0])] > > >+ cmd += [ipkfile] > > >+ > > >+ gpg_proc = Popen(cmd, stdin=subprocess.PIPE) > > >+ gpg_proc.wait() > > >+ > > >+ os.close(keypipe[1]); > > >+ os.close(keypipe[0]); > > >+ > > >+ except IOError as e: > > >+ bb.error("IO error ({0}): {1}".format(e.errno, e.strerror)) > > >+ raise bb.build.FuncFailed("Failed to sign IPK packages") > > >+ except OSError as e: > > >+ bb.error("OS error ({0}): {1}".format(e.errno, e.strerror)) > > >+ raise bb.build.FuncFailed("Failed to sign IPK packages") > > >+ except: > > >+ bb.error("Unexpected error: {1}".format(sys.exc_info()[0])) > > >+ raise bb.build.FuncFailed("Failed to sign IPK packages") > > >+ > > >+ > > > def detach_sign(self, input_file, keyid, passphrase_file, passphrase=None, armor=True): > > > """Create a detached signature of a file""" > > > import subprocess > > > > Couldn't you just use detach_sign() instead of introducing sign_ipk(). To me the functionality seems identical. > > The functionality is almost identical, yes, and consolidating it into one function is a very good idea. I'll do it but I have one question. > > The only diference between them is the usage in detach-sign of gpg's "--with-passphrase" arg, and that arg seems to cause some errors on my system: > "gpg: signing failed: Inappropriate ioctl for device" > > I have not managed to reliably reproduce and find the cause of this issue. However, if we always open the file in python and read directly in a pipe which > we always pass to gpg using "--passphrase-fd", the error goes away. > > Is using something like the following in detach_sign() ok with you? > > with open(passphrase_file) as fobj: > os.write(keypipe[1], fobj.readline() + '\n') > > cmd += ["--passphrase-fd", str(keypipe[0])] Good news: I managed to reproduce and find the cause of the problem: pinentry mode. Gpg has a parameter "--pinentry-mode" which by default is set to ask, but when doing batch singing and sending the passphrases through pipes it needs to be set to cancel. So now both methods work! :) I'll go with your method of using --passphrase-file and --passphrase-fd 0 because it is more clearer. > > > > > > > Thanks, > > Markus > > > > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v5 1/3] gpg_sign: add local ipk package signing functionality 2016-02-19 11:18 ` Ioan-Adrian Ratiu @ 2016-02-19 13:42 ` Ioan-Adrian Ratiu 0 siblings, 0 replies; 11+ messages in thread From: Ioan-Adrian Ratiu @ 2016-02-19 13:42 UTC (permalink / raw) To: Markus Lehtonen; +Cc: openembedded-core On Fri, 19 Feb 2016 13:18:12 +0200 Ioan-Adrian Ratiu <adrian.ratiu@ni.com> wrote: > On Thu, 18 Feb 2016 11:28:58 +0200 > Ioan-Adrian Ratiu <adrian.ratiu@ni.com> wrote: > > > Hello > > > > On Thu, 18 Feb 2016 11:04:22 +0200 > > Markus Lehtonen <markus.lehtonen@linux.intel.com> wrote: > > > > > Hi, > > > > > > > > > > > > On 17/02/16 17:41, "Ioan-Adrian Ratiu" <openembedded-core-bounces@lists.openembedded.org on behalf of adrian.ratiu@ni.com> wrote: > > > > > > >Implement local ipk signing logic inside the gpg backend and add a new > > > >bbclass which configures signing similar to how rpm does it. > > > > > > > >The ipk signing process is a bit different from rpm: > > > > - Signatures are stored outside ipk files; opkg connects to a feed > > > >server and downloads them to verify a package. > > > > - Signatures are of two types (both supported by opkg): binary or > > > >ascii armoured. By default we sign using ascii armoured. > > > > - Public keys are stored on targets to verify ipks using the > > > >opkg-keyrings recipe. > > > > > > > >Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com> > > > >--- > > > > meta/classes/package_ipk.bbclass | 6 +++++ > > > > meta/classes/sign_ipk.bbclass | 55 ++++++++++++++++++++++++++++++++++++++++ > > > > meta/lib/oe/gpg_sign.py | 39 ++++++++++++++++++++++++++++ > > > > 3 files changed, 100 insertions(+) > > > > create mode 100644 meta/classes/sign_ipk.bbclass > > > > > > > >diff --git a/meta/classes/package_ipk.bbclass b/meta/classes/package_ipk.bbclass > > > >index 51bee28..4f5bbd0 100644 > > > >--- a/meta/classes/package_ipk.bbclass > > > >+++ b/meta/classes/package_ipk.bbclass > > > >@@ -246,6 +246,12 @@ python do_package_ipk () { > > > > bb.utils.unlockfile(lf) > > > > raise bb.build.FuncFailed("opkg-build execution failed") > > > > > > > >+ if d.getVar('IPK_SIGN_PACKAGES', True) == '1': > > > >+ ipkver = "%s-%s" % (d.getVar('PKGV'), d.getVar('PKGR')) > > > >+ ipk_to_sign = "%s/%s_%s_%s.ipk" % (pkgoutdir, pkgname, ipkver, d.getVar('PACKAGE_ARCH', True)) > > > >+ d.setVar('IPK_TO_SIGN', ipk_to_sign) > > > >+ bb.build.exec_func("sign_ipk", d) > > > >+ > > > > cleanupcontrol(root) > > > > bb.utils.unlockfile(lf) > > > > > > > >diff --git a/meta/classes/sign_ipk.bbclass b/meta/classes/sign_ipk.bbclass > > > >new file mode 100644 > > > >index 0000000..cb22bb4 > > > >--- /dev/null > > > >+++ b/meta/classes/sign_ipk.bbclass > > > >@@ -0,0 +1,55 @@ > > > >+# 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) > > > >+} > > > >+ > > > >+python sign_ipk () { > > > >+ from oe.gpg_sign import get_signer > > > >+ > > > >+ ipk_file = d.getVar('IPK_TO_SIGN') > > > >+ bb.debug(1, 'Signing ipk: %s' % ipk_file) > > > >+ > > > >+ 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.sign_ipk(ipk_file, > > > >+ d.getVar('IPK_GPG_NAME', True), > > > >+ d.getVar('IPK_GPG_PASSPHRASE_FILE', True), > > > >+ is_ascii_sig) > > > >+} > > > > > > To me, it would be seem more straightforward to not circulate ipk_to_sign through 'd'. Just define a regular python function like > > > def sign_ipk(d, ipk_to_sign): > > > ... > > > > > > And then in package_ipk.bbclass just do "sign_ipk(d, ipk_to_sign)" instead of bb.build.exec_func("sign_ipk", d)" > > > > > > > > > > > > > > > >diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py > > > >index ada1b2f..138499b 100644 > > > >--- a/meta/lib/oe/gpg_sign.py > > > >+++ b/meta/lib/oe/gpg_sign.py > > > >@@ -1,5 +1,6 @@ > > > > """Helper module for GPG signing""" > > > > import os > > > >+import sys > > > > > > > > import bb > > > > import oe.utils > > > >@@ -50,6 +51,44 @@ class LocalSigner(object): > > > > bb.error('rpmsign failed: %s' % proc.before.strip()) > > > > raise bb.build.FuncFailed("Failed to sign RPM packages") > > > > > > > >+ def sign_ipk(self, ipkfile, keyid, passphrase_file, armor=True): > > > >+ """Sign IPK files""" > > > >+ import subprocess > > > >+ from subprocess import Popen > > > >+ > > > >+ cmd = [self.gpg_bin, "-q", "--batch", "--yes", "-b", "-u", keyid] > > > >+ if self.gpg_path: > > > >+ cmd += ["--homedir", self.gpg_path] > > > >+ if armor: > > > >+ cmd += ["--armor"] > > > >+ > > > >+ try: > > > >+ keypipe = os.pipe() > > > >+ > > > >+ # Need to add '\n' in case the passfile does not have it > > > >+ with open(passphrase_file) as fobj: > > > >+ os.write(keypipe[1], fobj.readline() + '\n') > > > >+ > > > >+ cmd += ["--passphrase-fd", str(keypipe[0])] > > > >+ cmd += [ipkfile] > > > >+ > > > >+ gpg_proc = Popen(cmd, stdin=subprocess.PIPE) > > > >+ gpg_proc.wait() > > > >+ > > > >+ os.close(keypipe[1]); > > > >+ os.close(keypipe[0]); > > > >+ > > > >+ except IOError as e: > > > >+ bb.error("IO error ({0}): {1}".format(e.errno, e.strerror)) > > > >+ raise bb.build.FuncFailed("Failed to sign IPK packages") > > > >+ except OSError as e: > > > >+ bb.error("OS error ({0}): {1}".format(e.errno, e.strerror)) > > > >+ raise bb.build.FuncFailed("Failed to sign IPK packages") > > > >+ except: > > > >+ bb.error("Unexpected error: {1}".format(sys.exc_info()[0])) > > > >+ raise bb.build.FuncFailed("Failed to sign IPK packages") > > > >+ > > > >+ > > > > def detach_sign(self, input_file, keyid, passphrase_file, passphrase=None, armor=True): > > > > """Create a detached signature of a file""" > > > > import subprocess > > > > > > Couldn't you just use detach_sign() instead of introducing sign_ipk(). To me the functionality seems identical. > > > > The functionality is almost identical, yes, and consolidating it into one function is a very good idea. I'll do it but I have one question. > > > > The only diference between them is the usage in detach-sign of gpg's "--with-passphrase" arg, and that arg seems to cause some errors on my system: > > "gpg: signing failed: Inappropriate ioctl for device" > > > > I have not managed to reliably reproduce and find the cause of this issue. However, if we always open the file in python and read directly in a pipe which > > we always pass to gpg using "--passphrase-fd", the error goes away. > > > > Is using something like the following in detach_sign() ok with you? > > > > with open(passphrase_file) as fobj: > > os.write(keypipe[1], fobj.readline() + '\n') > > > > cmd += ["--passphrase-fd", str(keypipe[0])] > > Good news: I managed to reproduce and find the cause of the problem: pinentry mode. > Gpg has a parameter "--pinentry-mode" which by default is set to ask, but when doing > batch singing and sending the passphrases through pipes it needs to be set to cancel. > > So now both methods work! :) I'll go with your method of using --passphrase-file and > --passphrase-fd 0 because it is more clearer. *facepalm* I mistyped the value of the pinentry-mode parameter it's loopback not cancel. More info at https://wiki.archlinux.org/index.php/GnuPG#Unattended_passphrase > > > > > > > > > > > > Thanks, > > > Markus > > > > > > > > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v5 2/3] gpg_sign: detached_sign: add signature type support 2016-02-17 15:41 [PATCH v5 0/3] IPK signing for the gpg_sign module Ioan-Adrian Ratiu 2016-02-17 15:41 ` [PATCH v5 1/3] gpg_sign: add local ipk package signing functionality Ioan-Adrian Ratiu @ 2016-02-17 15:41 ` Ioan-Adrian Ratiu 2016-02-18 9:06 ` Markus Lehtonen 2016-02-17 15:41 ` [PATCH v5 3/3] package_manager: sign IPK package feeds Ioan-Adrian Ratiu 2 siblings, 1 reply; 11+ messages in thread From: Ioan-Adrian Ratiu @ 2016-02-17 15:41 UTC (permalink / raw) To: openembedded-core Add support for multiple types of signatures (binary or ascii) in export_pubkey(). There is no change in behaviour for the function, the previous implicit default is the new parameter "armor" default. Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com> --- meta/lib/oe/gpg_sign.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py index 138499b..14888c0 100644 --- a/meta/lib/oe/gpg_sign.py +++ b/meta/lib/oe/gpg_sign.py @@ -13,12 +13,14 @@ class LocalSigner(object): self.gpg_path = d.getVar('GPG_PATH', True) self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm") - def export_pubkey(self, output_file, keyid): + def export_pubkey(self, output_file, keyid, armor=True): """Export GPG public key to a file""" - cmd = '%s --batch --yes --export --armor -o %s ' % \ + cmd = '%s --batch --yes --export -o %s ' % \ (self.gpg_bin, output_file) if self.gpg_path: cmd += "--homedir %s " % self.gpg_path + if armor: + cmd += "--armor " cmd += keyid status, output = oe.utils.getstatusoutput(cmd) if status: -- 2.7.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v5 2/3] gpg_sign: detached_sign: add signature type support 2016-02-17 15:41 ` [PATCH v5 2/3] gpg_sign: detached_sign: add signature type support Ioan-Adrian Ratiu @ 2016-02-18 9:06 ` Markus Lehtonen 0 siblings, 0 replies; 11+ messages in thread From: Markus Lehtonen @ 2016-02-18 9:06 UTC (permalink / raw) To: Ioan-Adrian Ratiu, openembedded-core On 17/02/16 17:41, "Ioan-Adrian Ratiu" <openembedded-core-bounces@lists.openembedded.org on behalf of adrian.ratiu@ni.com> wrote: >Add support for multiple types of signatures (binary or ascii) >in export_pubkey(). There is no change in behaviour for the function, >the previous implicit default is the new parameter "armor" default. > >Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com> >--- > meta/lib/oe/gpg_sign.py | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > >diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py >index 138499b..14888c0 100644 >--- a/meta/lib/oe/gpg_sign.py >+++ b/meta/lib/oe/gpg_sign.py >@@ -13,12 +13,14 @@ class LocalSigner(object): > self.gpg_path = d.getVar('GPG_PATH', True) > self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm") > >- def export_pubkey(self, output_file, keyid): >+ def export_pubkey(self, output_file, keyid, armor=True): > """Export GPG public key to a file""" >- cmd = '%s --batch --yes --export --armor -o %s ' % \ >+ cmd = '%s --batch --yes --export -o %s ' % \ > (self.gpg_bin, output_file) > if self.gpg_path: > cmd += "--homedir %s " % self.gpg_path >+ if armor: >+ cmd += "--armor " > cmd += keyid > status, output = oe.utils.getstatusoutput(cmd) > if status: Just change "detached_sign" in the commit subject to "export_pubkey" Thanks, Markus ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v5 3/3] package_manager: sign IPK package feeds 2016-02-17 15:41 [PATCH v5 0/3] IPK signing for the gpg_sign module Ioan-Adrian Ratiu 2016-02-17 15:41 ` [PATCH v5 1/3] gpg_sign: add local ipk package signing functionality Ioan-Adrian Ratiu 2016-02-17 15:41 ` [PATCH v5 2/3] gpg_sign: detached_sign: add signature type support Ioan-Adrian Ratiu @ 2016-02-17 15:41 ` Ioan-Adrian Ratiu 2016-02-18 9:09 ` Markus Lehtonen 2 siblings, 1 reply; 11+ messages in thread From: Ioan-Adrian Ratiu @ 2016-02-17 15:41 UTC (permalink / raw) To: openembedded-core Create gpg signed ipk package feeds using the gpg backend if configured. Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com> --- meta/classes/sign_package_feed.bbclass | 10 +++++++++- meta/lib/oe/package_manager.py | 17 +++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/meta/classes/sign_package_feed.bbclass b/meta/classes/sign_package_feed.bbclass index 63ca02f..2b0548a 100644 --- a/meta/classes/sign_package_feed.bbclass +++ b/meta/classes/sign_package_feed.bbclass @@ -10,6 +10,10 @@ # 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) # GPG_BIN # Optional variable for specifying the gpg binary/wrapper to use for # signing. @@ -20,7 +24,7 @@ inherit sanity PACKAGE_FEED_SIGN = '1' PACKAGE_FEED_GPG_BACKEND ?= 'local' - +PACKAGE_FEED_GPG_SIGNATURE_TYPE ?= 'ASC' python () { # Check sanity of configuration @@ -28,6 +32,10 @@ python () { if not d.getVar(var, True): raise_sanity_error("You need to define %s in the config" % var, d) + sigtype = d.getVar("PACKAGE_FEED_GPG_SIGNATURE_TYPE", True) + if sigtype.upper() != "ASC" and sigtype.upper() != "BIN": + raise_sanity_error("Bad value for PACKAGE_FEED_GPG_SIGNATURE_TYPE (%s), use either ASC or BIN" % sigtype) + # Set expected location of the public key d.setVar('PACKAGE_FEED_GPG_PUBKEY', os.path.join(d.getVar('STAGING_ETCDIR_NATIVE', False), diff --git a/meta/lib/oe/package_manager.py b/meta/lib/oe/package_manager.py index b30a4da..606ba24 100644 --- a/meta/lib/oe/package_manager.py +++ b/meta/lib/oe/package_manager.py @@ -163,11 +163,16 @@ class OpkgIndexer(Indexer): "MULTILIB_ARCHS"] opkg_index_cmd = bb.utils.which(os.getenv('PATH'), "opkg-make-index") + if self.d.getVar('PACKAGE_FEED_SIGN', True) == '1': + signer = get_signer(self.d, self.d.getVar('PACKAGE_FEED_GPG_BACKEND', True)) + else: + signer = None if not os.path.exists(os.path.join(self.deploy_dir, "Packages")): open(os.path.join(self.deploy_dir, "Packages"), "w").close() index_cmds = [] + index_sign_files = [] for arch_var in arch_vars: archs = self.d.getVar(arch_var, True) if archs is None: @@ -186,6 +191,8 @@ class OpkgIndexer(Indexer): index_cmds.append('%s -r %s -p %s -m %s' % (opkg_index_cmd, pkgs_file, pkgs_file, pkgs_dir)) + index_sign_files.append(pkgs_file) + if len(index_cmds) == 0: bb.note("There are no packages in %s!" % self.deploy_dir) return @@ -193,9 +200,15 @@ class OpkgIndexer(Indexer): result = oe.utils.multiprocess_exec(index_cmds, create_index) if result: bb.fatal('%s' % ('\n'.join(result))) - if self.d.getVar('PACKAGE_FEED_SIGN', True) == '1': - raise NotImplementedError('Package feed signing not implementd for ipk') + if signer: + feed_sig_type = self.d.getVar('PACKAGE_FEED_GPG_SIGNATURE_TYPE', True) + is_ascii_sig = (feed_sig_type.upper() != "BIN") + for f in index_sign_files: + signer.detach_sign(f, + self.d.getVar('PACKAGE_FEED_GPG_NAME', True), + self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE', True), + armor=is_ascii_sig) class DpkgIndexer(Indexer): -- 2.7.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v5 3/3] package_manager: sign IPK package feeds 2016-02-17 15:41 ` [PATCH v5 3/3] package_manager: sign IPK package feeds Ioan-Adrian Ratiu @ 2016-02-18 9:09 ` Markus Lehtonen 0 siblings, 0 replies; 11+ messages in thread From: Markus Lehtonen @ 2016-02-18 9:09 UTC (permalink / raw) To: Ioan-Adrian Ratiu, openembedded-core On 17/02/16 17:41, "Ioan-Adrian Ratiu" <openembedded-core-bounces@lists.openembedded.org on behalf of adrian.ratiu@ni.com> wrote: >Create gpg signed ipk package feeds using the gpg backend if configured. > >Signed-off-by: Ioan-Adrian Ratiu <adrian.ratiu@ni.com> >--- > meta/classes/sign_package_feed.bbclass | 10 +++++++++- > meta/lib/oe/package_manager.py | 17 +++++++++++++++-- > 2 files changed, 24 insertions(+), 3 deletions(-) > >diff --git a/meta/classes/sign_package_feed.bbclass b/meta/classes/sign_package_feed.bbclass >index 63ca02f..2b0548a 100644 >--- a/meta/classes/sign_package_feed.bbclass >+++ b/meta/classes/sign_package_feed.bbclass >@@ -10,6 +10,10 @@ > # 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) I'd add a note that PACKAGE_FEED_GPG_SIGNATURE_TYPE is only supported for ipk feeds. This setting is ignored for RPM feeds and afaiu only .asc signatures are supported in rpm-md repositories. Thanks, Markus > # GPG_BIN > # Optional variable for specifying the gpg binary/wrapper to use for > # signing. >@@ -20,7 +24,7 @@ inherit sanity > > PACKAGE_FEED_SIGN = '1' > PACKAGE_FEED_GPG_BACKEND ?= 'local' >- >+PACKAGE_FEED_GPG_SIGNATURE_TYPE ?= 'ASC' > > python () { > # Check sanity of configuration >@@ -28,6 +32,10 @@ python () { > if not d.getVar(var, True): > raise_sanity_error("You need to define %s in the config" % var, d) > >+ sigtype = d.getVar("PACKAGE_FEED_GPG_SIGNATURE_TYPE", True) >+ if sigtype.upper() != "ASC" and sigtype.upper() != "BIN": >+ raise_sanity_error("Bad value for PACKAGE_FEED_GPG_SIGNATURE_TYPE (%s), use either ASC or BIN" % sigtype) >+ > # Set expected location of the public key > d.setVar('PACKAGE_FEED_GPG_PUBKEY', > os.path.join(d.getVar('STAGING_ETCDIR_NATIVE', False), >diff --git a/meta/lib/oe/package_manager.py b/meta/lib/oe/package_manager.py >index b30a4da..606ba24 100644 >--- a/meta/lib/oe/package_manager.py >+++ b/meta/lib/oe/package_manager.py >@@ -163,11 +163,16 @@ class OpkgIndexer(Indexer): > "MULTILIB_ARCHS"] > > opkg_index_cmd = bb.utils.which(os.getenv('PATH'), "opkg-make-index") >+ if self.d.getVar('PACKAGE_FEED_SIGN', True) == '1': >+ signer = get_signer(self.d, self.d.getVar('PACKAGE_FEED_GPG_BACKEND', True)) >+ else: >+ signer = None > > if not os.path.exists(os.path.join(self.deploy_dir, "Packages")): > open(os.path.join(self.deploy_dir, "Packages"), "w").close() > > index_cmds = [] >+ index_sign_files = [] > for arch_var in arch_vars: > archs = self.d.getVar(arch_var, True) > if archs is None: >@@ -186,6 +191,8 @@ class OpkgIndexer(Indexer): > index_cmds.append('%s -r %s -p %s -m %s' % > (opkg_index_cmd, pkgs_file, pkgs_file, pkgs_dir)) > >+ index_sign_files.append(pkgs_file) >+ > if len(index_cmds) == 0: > bb.note("There are no packages in %s!" % self.deploy_dir) > return >@@ -193,9 +200,15 @@ class OpkgIndexer(Indexer): > result = oe.utils.multiprocess_exec(index_cmds, create_index) > if result: > bb.fatal('%s' % ('\n'.join(result))) >- if self.d.getVar('PACKAGE_FEED_SIGN', True) == '1': >- raise NotImplementedError('Package feed signing not implementd for ipk') > >+ if signer: >+ feed_sig_type = self.d.getVar('PACKAGE_FEED_GPG_SIGNATURE_TYPE', True) >+ is_ascii_sig = (feed_sig_type.upper() != "BIN") >+ for f in index_sign_files: >+ signer.detach_sign(f, >+ self.d.getVar('PACKAGE_FEED_GPG_NAME', True), >+ self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE', True), >+ armor=is_ascii_sig) > > > class DpkgIndexer(Indexer): ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2016-02-19 13:42 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-02-17 15:41 [PATCH v5 0/3] IPK signing for the gpg_sign module Ioan-Adrian Ratiu 2016-02-17 15:41 ` [PATCH v5 1/3] gpg_sign: add local ipk package signing functionality Ioan-Adrian Ratiu 2016-02-18 9:04 ` Markus Lehtonen 2016-02-18 9:28 ` Ioan-Adrian Ratiu 2016-02-18 15:26 ` Markus Lehtonen 2016-02-19 11:18 ` Ioan-Adrian Ratiu 2016-02-19 13:42 ` Ioan-Adrian Ratiu 2016-02-17 15:41 ` [PATCH v5 2/3] gpg_sign: detached_sign: add signature type support Ioan-Adrian Ratiu 2016-02-18 9:06 ` Markus Lehtonen 2016-02-17 15:41 ` [PATCH v5 3/3] package_manager: sign IPK package feeds Ioan-Adrian Ratiu 2016-02-18 9:09 ` Markus Lehtonen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox