IPK signing for the gpg_sign module
v6 cover IPK signing for the gpg_sign module
This patch series extends the gpg_sign module to support ipk signing.
v6 implements Markus' feedback. The most notable change is the sign_ipk and detach_sign merger, as they were almost identical in functionality. This also meant a refactoring for detach_sign and a bug fix for the STDIN file descriptor introduced in gpg > 2.1.
Technically that STDIN bug is a feature (meh) of gpg >2.1 which breaks existing behaviour so we have to work around it i.e. check the gpg version and use the loopback interface. This means that gpg-agent to which gpg >2.1 always connects needs to be running permanently.
Ioan-Adrian Ratiu (4):
gpg_sign: add local ipk package signing functionality
gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor
gpg_sign: export_pubkey: add signature type support
package_manager: sign IPK package feeds
meta/classes/package_ipk.bbclass | 5 +++ meta/classes/sign_ipk.bbclass | 52 ++++++++++++++++++++++++ meta/classes/sign_package_feed.bbclass | 12 +++++- meta/lib/oe/gpg_sign.py | 74 +++++++++++++++++++++++++++------- meta/lib/oe/package_manager.py | 17 +++++++- 5 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 meta/classes/sign_ipk.bbclass
Signature · 1 line
2.7.1
PATCH v6 1/4 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 | 50 ++++++++++++++++++++++++++++---------- 3 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 meta/classes/sign_ipk.bbclass
meta/classes/package_ipk.bbclass +5 -0
@@ -246,6 +246,11 @@ python do_package_ipk () { bb.utils.unlockfile(lf) raise bb.build.FuncFailed("opkg-build execution failed") + if d.getVar('IPK_SIGN_PACKAGES', True) == '1': + ipkver = "%s-%s" % (d.getVar('PKGV'), d.getVar('PKGR')) + ipk_to_sign = "%s/%s_%s_%s.ipk" % (pkgoutdir, pkgname, ipkver, d.getVar('PACKAGE_ARCH', True)) + sign_ipk(d, ipk_to_sign) + cleanupcontrol(root) bb.utils.unlockfile(lf)
meta/classes/sign_ipk.bbclass new file +52 -0
52 lines not on this page · raw message
meta/lib/oe/gpg_sign.py +37 -13
71 lines not on this page · raw message
Signature · 1 line
2.7.1
Re: [PATCH v6 1/4] gpg_sign: add local ipk package signing functionality
Hi,
Resending as my I got a strange "Only members may post to the list." error yesterday...
Quoted 174 lines · Ioan-Adrian Ratiu
Implement ipk signing inside the
sign_ipkbbclass using thegpg_signmodule and configure signing similar to how rpm does it.sign_ipkuses
gpg_sign'sdetach_signbecause its functionality is identical to package
feed signing.IPK signing process is a bit different from rpm:
- Signatures are stored outside ipk files; opkg connects to a
feed
server and downloads them to verify a package.
- Signatures are of two types (both supported by opkg): binary or
ascii armoured. By default we sign using ascii armoured.
- Public keys are stored on targets to verify ipks using the
opkg-keyrings recipe.Signed-off-by Ioan-Adrian Ratiu <[email protected]>--- meta/classes/package_ipk.bbclass | 5 ++++ meta/classes/sign_ipk.bbclass | 52 ++++++++++++++++++++++++++++++++++++++++ meta/lib/oe/gpg_sign.py | 50 ++++++++++++++++++++++++++++-- -------- 3 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 meta/classes/sign_ipk.bbclassmeta/classes/package_ipk.bbclass +5
-0@@ -246,6 +246,11 @@ python do_package_ipk () { bb.utils.unlockfile(lf) raise bb.build.FuncFailed("opkg-build execution failed") + if d.getVar('IPK_SIGN_PACKAGES', True) == '1': + ipkver = "%s-%s" % (d.getVar('PKGV'), d.getVar('PKGR')) + ipk_to_sign = "%s/%s_%s_%s.ipk" % (pkgoutdir, pkgname, ipkver, d.getVar('PACKAGE_ARCH', True)) + sign_ipk(d, ipk_to_sign) + cleanupcontrol(root) bb.utils.unlockfile(lf)meta/classes/sign_ipk.bbclass new file +5
-0@@ -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 signingkey.
meta/classes/sign_ipk.bbclass new file +4
-0+# IPK_GPG_NAME +# Name of the key to sign with. +# IPK_GPG_BACKEND +# Optional variable for specifying the backend to use forsigning.
+# Currently the only available option is 'local', i.e.
local signingmeta/classes/sign_ipk.bbclass new file +3
-0+# on the build host. +# IPK_GPG_SIGNATURE_TYPE +# Optional variable for specifying the type of gpgsignatures, can be:
meta/classes/sign_ipk.bbclass new file +4
-0+# 1. Ascii armored (ASC), default if not set +# 2. Binary (BIN) +# GPG_BIN +# Optional variable for specifying the gpg binary/wrapperto use for
meta/classes/sign_ipk.bbclass new file +3
-0+# signing. +# GPG_PATH +# Optional variable for specifying the gnupg "home"directory:
meta/classes/sign_ipk.bbclass new file +13
-0+# + +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)
meta/classes/sign_ipk.bbclass new file +4
-0+ + 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)
meta/classes/sign_ipk.bbclass new file +15
-0+} + +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 +2
-0@@ -1,5 +1,6 @@ """Helper module for GPG signing""" import os +import sys import bb import oe.utils@@ -50,6 +51,7 @@ class LocalSigner(object): bb.error('rpmsign failed: %s' % proc.before.strip()) raise bb.build.FuncFailed("Failed to sign RPM packages") + def detach_sign(self, input_file, keyid, passphrase_file,passphrase=None, armor=True):
"""Create a detached signature of a file""" import subprocessmeta/lib/oe/gpg_sign.py +1
-6@@ -57,23 +59,45 @@ class LocalSigner(object): if passphrase_file and passphrase: raise Exception("You should use either passphrase_file of passphrase, not both") - cmd = [self.gpg_bin, '--detach-sign', '--batch', '--no-tty', '--yes', - '-u', keyid] - if passphrase_file: - cmd += ['--passphrase-file', passphrase_file] - else: - cmd += ['--passphrase-fd', '0'] + cmd = [self.gpg_bin, '--detach-sign', '--batch', '--no-tty','--yes', '-u', keyid]
meta/lib/oe/gpg_sign.py +1
-2+ 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,
meta/lib/oe/gpg_sign.py +0
-4- stderr=subprocess.PIPE) - _, stderr = job.communicate(passphrase) - if job.returncode: - raise bb.build.FuncFailed("Failed to create signaturefor '%s': %s" %
meta/lib/oe/gpg_sign.py +14
-1- (input_file, stderr)) + + try: + keypipe = os.pipe() + + if passphrase_file: + with open(passphrase_file) as fobj: + os.write(keypipe[1], fobj.readline()); + else: + os.write(keypipe[1], passphrase) + + cmd += ["--passphrase-fd", str(keypipe[0])] + cmd += [input_file] + + job = subprocess.Popen(cmd, stdin=subprocess.PIPE,stderr=subprocess.PIPE)
meta/lib/oe/gpg_sign.py class LocalSigner(object): · line 85
Quoted 4 lines
meta/lib/oe/gpg_sign.py +4
-0+ (_, stderr) = job.communicate(passphrase) + + os.close(keypipe[1]) + os.close(keypipe[0])
I still fail to see why you want to complicate the code with os.pipe. Why not ditch pipe and just do something like:
if passphrase_file:
with open(passphrase_file) as fobj:
_, stderr = job.communicate(fobj.readline())
Thanks,
Markus
Quoted 20 lines
meta/lib/oe/gpg_sign.py +3
-0+ + if job.returncode: + raise bb.build.FuncFailed("GPG exited with code %d:%s" %
meta/lib/oe/gpg_sign.py +10
-0+ (job.returncode, stderr)) + + except IOError as e: + bb.error("IO error (%s): %s" % (e.errno, e.strerror)) + raise Exception("Failed to sign '%s'" % input_file) + except OSError as e: + bb.error("OS error (%s): %s" % (e.errno, e.strerror)) + raise Exception("Failed to sign '%s" % input_file) + except: + bb.error("Unexpected error (%s): %s" %(sys.exc_info()[0], sys.exc_info()[1]))
meta/lib/oe/gpg_sign.py +2
-0+ raise Exception("Failed to sign '%s'" % input_file) + def verify(self, sig_file): """Verify signature"""
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [OE-core][PATCH v6 1/4] gpg_sign: add local ipk package signing functionality
Hello
Quoted 177 lines · On Mon, 22 Feb 2016 15:33:43 +0200 Markus Lehtonen…
Quoted 176 lines · Ioan-Adrian Ratiu
Implement ipk signing inside the
sign_ipkbbclass using thegpg_signmodule and configure signing similar to how rpm does it.sign_ipkuses
gpg_sign'sdetach_signbecause its functionality is identical to package
feed signing.IPK signing process is a bit different from rpm:
- Signatures are stored outside ipk files; opkg connects to a
feed
server and downloads them to verify a package.
- Signatures are of two types (both supported by opkg): binary or
ascii armoured. By default we sign using ascii armoured.
- Public keys are stored on targets to verify ipks using the
opkg-keyrings recipe.Signed-off-by Ioan-Adrian Ratiu <[email protected]>--- meta/classes/package_ipk.bbclass | 5 ++++ meta/classes/sign_ipk.bbclass | 52 ++++++++++++++++++++++++++++++++++++++++ meta/lib/oe/gpg_sign.py | 50 ++++++++++++++++++++++++++++-- -------- 3 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 meta/classes/sign_ipk.bbclassmeta/classes/package_ipk.bbclass +5
-0@@ -246,6 +246,11 @@ python do_package_ipk () { bb.utils.unlockfile(lf) raise bb.build.FuncFailed("opkg-build execution failed") + if d.getVar('IPK_SIGN_PACKAGES', True) == '1': + ipkver = "%s-%s" % (d.getVar('PKGV'), d.getVar('PKGR')) + ipk_to_sign = "%s/%s_%s_%s.ipk" % (pkgoutdir, pkgname, ipkver, d.getVar('PACKAGE_ARCH', True)) + sign_ipk(d, ipk_to_sign) + cleanupcontrol(root) bb.utils.unlockfile(lf)meta/classes/sign_ipk.bbclass new file +5
-0@@ -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 signingkey.
meta/classes/sign_ipk.bbclass new file +4
-0+# IPK_GPG_NAME +# Name of the key to sign with. +# IPK_GPG_BACKEND +# Optional variable for specifying the backend to use forsigning.
+# Currently the only available option is 'local', i.e.
local signingmeta/classes/sign_ipk.bbclass new file +3
-0+# on the build host. +# IPK_GPG_SIGNATURE_TYPE +# Optional variable for specifying the type of gpgsignatures, can be:
meta/classes/sign_ipk.bbclass new file +4
-0+# 1. Ascii armored (ASC), default if not set +# 2. Binary (BIN) +# GPG_BIN +# Optional variable for specifying the gpg binary/wrapperto use for
meta/classes/sign_ipk.bbclass new file +3
-0+# signing. +# GPG_PATH +# Optional variable for specifying the gnupg "home"directory:
meta/classes/sign_ipk.bbclass new file +13
-0+# + +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)
meta/classes/sign_ipk.bbclass new file +4
-0+ + 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)
meta/classes/sign_ipk.bbclass new file +15
-0+} + +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 +2
-0@@ -1,5 +1,6 @@ """Helper module for GPG signing""" import os +import sys import bb import oe.utils@@ -50,6 +51,7 @@ class LocalSigner(object): bb.error('rpmsign failed: %s' % proc.before.strip()) raise bb.build.FuncFailed("Failed to sign RPM packages") + def detach_sign(self, input_file, keyid, passphrase_file,passphrase=None, armor=True):
"""Create a detached signature of a file""" import subprocessmeta/lib/oe/gpg_sign.py +1
-6@@ -57,23 +59,45 @@ class LocalSigner(object): if passphrase_file and passphrase: raise Exception("You should use either passphrase_file of passphrase, not both") - cmd = [self.gpg_bin, '--detach-sign', '--batch', '--no-tty', '--yes', - '-u', keyid] - if passphrase_file: - cmd += ['--passphrase-file', passphrase_file] - else: - cmd += ['--passphrase-fd', '0'] + cmd = [self.gpg_bin, '--detach-sign', '--batch', '--no-tty','--yes', '-u', keyid]
meta/lib/oe/gpg_sign.py +1
-2+ 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,
meta/lib/oe/gpg_sign.py +0
-4- stderr=subprocess.PIPE) - _, stderr = job.communicate(passphrase) - if job.returncode: - raise bb.build.FuncFailed("Failed to create signaturefor '%s': %s" %
meta/lib/oe/gpg_sign.py +14
-1- (input_file, stderr)) + + try: + keypipe = os.pipe() + + if passphrase_file: + with open(passphrase_file) as fobj: + os.write(keypipe[1], fobj.readline()); + else: + os.write(keypipe[1], passphrase) + + cmd += ["--passphrase-fd", str(keypipe[0])] + cmd += [input_file] + + job = subprocess.Popen(cmd, stdin=subprocess.PIPE,stderr=subprocess.PIPE)
meta/lib/oe/gpg_sign.py +2
-0+ (_, stderr) = job.communicate(passphrase) +
Quoted 9 lines
meta/lib/oe/gpg_sign.py class LocalSigner(object): · line 85
Quoted 2 lines
meta/lib/oe/gpg_sign.py +2
-0+ os.close(keypipe[1]) + os.close(keypipe[0])I still fail to see why you want to complicate the code with os.pipe. Why not ditch pipe and just do something like:
ifpassphrase_file:
withopen(passphrase_file)as fobj:
_, stderr = job.communicate(fobj.readline())
If I don't use os.pipe, gpg >2.1 errors out:
gpg: Sorry, we are in batchmode - can't get input
Most likely it has something to do with >2.1 gpg-agent loopback configuration but I can't seem to find its cause nor a workaround. Obviously removing batch mode and --no-term is not an option.
If I use os.pipe to send the passphrase, then everything works as expected. The internet is full of issues like this, but after some heavy googling still no fix to be found for this specific case.
Any ideas, anyone?
Thank you,
Adrian
Quoted 27 lines
Thanks,
MarkusQuoted 20 lines
meta/lib/oe/gpg_sign.py +3
-0+ + if job.returncode: + raise bb.build.FuncFailed("GPG exited with code %d:%s" %
meta/lib/oe/gpg_sign.py +10
-0+ (job.returncode, stderr)) + + except IOError as e: + bb.error("IO error (%s): %s" % (e.errno, e.strerror)) + raise Exception("Failed to sign '%s'" % input_file) + except OSError as e: + bb.error("OS error (%s): %s" % (e.errno, e.strerror)) + raise Exception("Failed to sign '%s" % input_file) + except: + bb.error("Unexpected error (%s): %s" %(sys.exc_info()[0], sys.exc_info()[1]))
meta/lib/oe/gpg_sign.py +2
-0+ raise Exception("Failed to sign '%s'" % input_file) + def verify(self, sig_file): """Verify signature"""
PATCH v6 2/4 gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor
In reply to Ioan-Adrian RatiuStarting 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 | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
meta/lib/oe/gpg_sign.py +20 -0
@@ -66,6 +66,12 @@ class LocalSigner(object): if armor: cmd += ['--armor'] + #gpg > 2.1 supports password pipes only through the loopback interface + #gpg < 2.1 errors out if given unknown parameters + gpg_ver = self.get_gpg_version() + if gpg_ver > 2.1: + cmd += ['--pinentry-mode', 'loopback'] + try: keypipe = os.pipe()
@@ -99,6 +105,20 @@ class LocalSigner(object): raise Exception("Failed to sign '%s'" % input_file) + def get_gpg_version(self): + """Return the gpg version""" + import subprocess + + job = subprocess.Popen([self.gpg_bin, "--version"], stdout=subprocess.PIPE) + (stdout, _) = job.communicate() + + if job.returncode: + raise bb.build.FuncFailed("Could not get gpg version (is %s installed?)" % + self.gpg_bin) + + return stdout.split()[2] + + def verify(self, sig_file): """Verify signature""" cmd = self.gpg_bin + " --verify "
Signature · 1 line
2.7.1
Re: [PATCH v6 2/4] gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor
Hi,
Resending as my I got a strange "Only members may post to the list." error yesterday...
Quoted 26 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
Signed-off-by Ioan-Adrian Ratiu <[email protected]>--- meta/lib/oe/gpg_sign.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)meta/lib/oe/gpg_sign.py +1
-0@@ -66,6 +66,12 @@ class LocalSigner(object): if armor: cmd += ['--armor'] + #gpg > 2.1 supports password pipes only through the loopbackinterface
meta/lib/oe/gpg_sign.py class LocalSigner(object): · line 74
Quoted 5 lines
meta/lib/oe/gpg_sign.py +5
-0+ #gpg < 2.1 errors out if given unknown parameters + gpg_ver = self.get_gpg_version() + if gpg_ver > 2.1: + cmd += ['--pinentry-mode', 'loopback'] +
As far as I can tell get_gpg_version returns a string. However, you compare that with a float. This should give more correct behavior:
+ if gpg_ver > "2.1":
Thanks,
Markus
Quoted 26 lines
try:
keypipe =os.pipe()meta/lib/oe/gpg_sign.py +9
-0@@ -99,6 +105,20 @@ class LocalSigner(object): raise Exception("Failed to sign '%s'" % input_file) + def get_gpg_version(self): + """Return the gpg version""" + import subprocess + + job = subprocess.Popen([self.gpg_bin, "--version"], stdout=subprocess.PIPE) + (stdout, _) = job.communicate() + + if job.returncode: + raise bb.build.FuncFailed("Could not get gpg version (is%s installed?)" %
meta/lib/oe/gpg_sign.py +5
-0+ self.gpg_bin) + + return stdout.split()[2] + + def verify(self, sig_file): """Verify signature""" cmd = self.gpg_bin + " --verify "
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [OE-core][PATCH v6 2/4] gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor
Quoted 4 lines · Markus Lehtonen
As far as I can tell
get_gpg_versionreturns a string. However, you compare that with a float. This should give more correct behavior:
+ ifgpg_ver> "2.1":
Not sure I'd trust that either, version comparison logic is painful. Something like this might be more resilient to interesting versioning:
dots = versionstring.split('.')
assert len(dots) >2
if int(dots[0]) >= 2 and int(dots[1])>= 1:
Also:
+ job = subprocess.Popen([self.gpg_bin, "--version"],
stdout=subprocess.PIPE)
+ (stdout, _) = job.communicate()
+
+ if job.returncode:
+ raise bb.build.FuncFailed("Could not get gpg version (is %s
installed?)" %
+ self.gpg_bin)
+ return stdout.split()[2]
That's a long-winded way of saying:
try:
return subprocess.check_output((self.gpg_bin, "version")).split()[2]
except CalledProcessExceptionOrWhateverThisExceptionIsCalled:
raise bb.build.FuncFailed("Could not get gpg version (%s). Called %s,
output %s" % (e, e.cmd, e.output))
Ross
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [OE-core][PATCH v6 2/4] gpg_sign: detach_sign: fix gpg > 2.1 STDIN file descriptor
Quoted 8 lines · Markus Lehtonen
Not sure I'd trust that either, version comparison logic is painful. Something like this might be more resilient to interesting versioning:
dots =
versionstring.split('.')
assert len(dots) >2
ifint(dots[0])>= 2 and int(dots[1])>= 1:
Quoted 5 lines
Even this doesn't work as e.g. I have gpg version 2.0.24. But, I agree that version comparison is tricky, e.g. "2.10" > "2.2" would return False. 2.1 is a nice version number in that sense ;) I don't know if gpg has had of will ever have any alphabets in its version number.
My assert should have been >=2, but surely it will work as your version would fail the test, as intended?
Quoted 10 lines
try:
returnsubprocess.check_output((self.gpg_bin, "version")).split()[2]
except CalledProcessExceptionOrWhateverThisExceptionIsCalled:
raise bb.build.FuncFailed("Could not get gpg version (%s). Called %s,
output %s" % (e, e.cmd, e.output))I guess you mean (with double dash before 'version'):
returnsubprocess.check_output((self.gpg_bin, "--version")).split()[2]
Yeah, that. :)
Ross
PATCH v6 3/4 gpg_sign: export_pubkey: add signature type support
In reply to Ioan-Adrian RatiuAdd 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
@@ -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
PATCH v6 4/4 package_manager: sign IPK package feeds
In reply to Ioan-Adrian RatiuCreate gpg signed ipk package feeds using the gpg backend if configured.
--- meta/classes/sign_package_feed.bbclass | 12 +++++++++++- meta/lib/oe/package_manager.py | 17 +++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-)
meta/classes/sign_package_feed.bbclass +11 -1
@@ -10,6 +10,12 @@ # Optional variable for specifying the backend to use for signing. # Currently the only available option is 'local', i.e. local signing # on the build host. +# PACKAGE_FEED_GPG_SIGNATURE_TYPE +# Optional variable for specifying the type of gpg signature, can be: +# 1. Ascii armored (ASC), default if not set +# 2. Binary (BIN) +# This variable is only available for IPK feeds. It is ignored on +# other packaging backends. # GPG_BIN # Optional variable for specifying the gpg binary/wrapper to use for # signing.
@@ -20,7 +26,7 @@ inherit sanity PACKAGE_FEED_SIGN = '1' PACKAGE_FEED_GPG_BACKEND ?= 'local' - +PACKAGE_FEED_GPG_SIGNATURE_TYPE ?= 'ASC' python () { # Check sanity of configuration
@@ -28,6 +34,10 @@ python () { if not d.getVar(var, True): raise_sanity_error("You need to define %s in the config" % var, d) + sigtype = d.getVar("PACKAGE_FEED_GPG_SIGNATURE_TYPE", True) + if sigtype.upper() != "ASC" and sigtype.upper() != "BIN": + raise_sanity_error("Bad value for PACKAGE_FEED_GPG_SIGNATURE_TYPE (%s), use either ASC or BIN" % sigtype) + # Set expected location of the public key d.setVar('PACKAGE_FEED_GPG_PUBKEY', os.path.join(d.getVar('STAGING_ETCDIR_NATIVE', False),
meta/lib/oe/package_manager.py +15 -2
@@ -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):
Signature · 1 line
2.7.1
Hi,
Resending as my I got a strange "Only members may post to the list." error yesterday...
Quoted 21 lines · Ioan-Adrian Ratiu
This patch series extends the
gpg_signmodule to support ipk signing.v6 implements Markus' feedback. The most notable change is the
sign_ipk
anddetach_signmerger, as they were almost identical in functionality.
This also meant a refactoring fordetach_signand a bug fix for the STDIN file descriptor introduced in gpg > 2.1.Technically that STDIN bug is a feature (meh) of gpg >2.1 which breaks
existing behaviour so we have to work around it i.e. check the gpg version and use the loopback interface. This means that gpg-agent to which gpg >2.1 always connects needs to be running permanently.Ioan-Adrian Ratiu (4):
gpg_sign: add local ipk package signing functionality
gpg_sign:detach_sign: fix gpg > 2.1 STDIN file descriptor
gpg_sign:export_pubkey: add signature type support
package_manager: sign IPK package feeds
Quoted 8 lines
meta/classes/package_ipk.bbclass | 5 +++ meta/classes/sign_ipk.bbclass | 52 ++++++++++++++++++++++++ meta/classes/sign_package_feed.bbclass | 12 +++++- meta/lib/oe/gpg_sign.py | 74 +++++++++++++++++++++++++++------- meta/lib/oe/package_manager.py | 17 +++++++- 5 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 meta/classes/sign_ipk.bbclass
I just realized that it would be good to add the ipk signing key to the signing_keys.bb recipe.
However, it'd probably be good to write it on top of Randy Witt's rework:
http://lists.openembedded.org/pipermail/openembedded-core/2016-February
/117791.html
Thanks,
Markus