diff options
author | Markus Lehtonen <markus.lehtonen@linux.intel.com> | 2016-01-25 14:21:34 +0200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-01-26 22:31:58 +0000 |
commit | bb971577ab308caf7177d4bda290d1fe5ab842db (patch) | |
tree | 49c1811106a9b58717dcfd3c6fe4e4810341c1b3 /meta/lib/oe/gpg_sign.py | |
parent | aadb879e5b302e405e05443f56611c17868d10b6 (diff) | |
download | poky-bb971577ab308caf7177d4bda290d1fe5ab842db.tar.gz |
meta/lib: new module for handling GPG signing
Add a new Python module (oe.gpg_sign) for handling GPG signing
operations, i.e. currently package and package feed signing. The purpose
is to be able to more easily support various signing backends and to be
able to centralise signing functionality into one place (e.g. package
signing and sstate signing). Currently, only local signing with gpg is
implemented.
[YOCTO #8755]
(From OE-Core rev: 9b3dc1bd4b8336423a3f8f7db0ab5fa6fa0e7257)
Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
Signed-off-by: Ross Burton <ross.burton@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib/oe/gpg_sign.py')
-rw-r--r-- | meta/lib/oe/gpg_sign.py | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/meta/lib/oe/gpg_sign.py b/meta/lib/oe/gpg_sign.py new file mode 100644 index 0000000000..55abad8ffc --- /dev/null +++ b/meta/lib/oe/gpg_sign.py | |||
@@ -0,0 +1,76 @@ | |||
1 | """Helper module for GPG signing""" | ||
2 | import os | ||
3 | |||
4 | import bb | ||
5 | import oe.utils | ||
6 | |||
7 | class LocalSigner(object): | ||
8 | """Class for handling local (on the build host) signing""" | ||
9 | def __init__(self, d, keyid, passphrase_file): | ||
10 | self.keyid = keyid | ||
11 | self.passphrase_file = passphrase_file | ||
12 | self.gpg_bin = d.getVar('GPG_BIN', True) or \ | ||
13 | bb.utils.which(os.getenv('PATH'), 'gpg') | ||
14 | self.gpg_path = d.getVar('GPG_PATH', True) | ||
15 | self.rpm_bin = bb.utils.which(os.getenv('PATH'), "rpm") | ||
16 | |||
17 | def export_pubkey(self, output_file): | ||
18 | """Export GPG public key to a file""" | ||
19 | cmd = '%s --batch --yes --export --armor -o %s ' % \ | ||
20 | (self.gpg_bin, output_file) | ||
21 | if self.gpg_path: | ||
22 | cmd += "--homedir %s " % self.gpg_path | ||
23 | cmd += self.keyid | ||
24 | status, output = oe.utils.getstatusoutput(cmd) | ||
25 | if status: | ||
26 | raise bb.build.FuncFailed('Failed to export gpg public key (%s): %s' % | ||
27 | (self.keyid, output)) | ||
28 | |||
29 | def sign_rpms(self, files): | ||
30 | """Sign RPM files""" | ||
31 | import pexpect | ||
32 | |||
33 | cmd = self.rpm_bin + " --addsign --define '_gpg_name %s' " % self.keyid | ||
34 | if self.gpg_bin: | ||
35 | cmd += "--define '%%__gpg %s' " % self.gpg_bin | ||
36 | if self.gpg_path: | ||
37 | cmd += "--define '_gpg_path %s' " % self.gpg_path | ||
38 | cmd += ' '.join(files) | ||
39 | |||
40 | # Need to use pexpect for feeding the passphrase | ||
41 | proc = pexpect.spawn(cmd) | ||
42 | try: | ||
43 | proc.expect_exact('Enter pass phrase:', timeout=15) | ||
44 | with open(self.passphrase_file) as fobj: | ||
45 | proc.sendline(fobj.readline().rstrip('\n')) | ||
46 | proc.expect(pexpect.EOF, timeout=900) | ||
47 | proc.close() | ||
48 | except pexpect.TIMEOUT as err: | ||
49 | bb.error('rpmsign timeout: %s' % err) | ||
50 | proc.terminate() | ||
51 | if os.WEXITSTATUS(proc.status) or not os.WIFEXITED(proc.status): | ||
52 | bb.error('rpmsign failed: %s' % proc.before.strip()) | ||
53 | raise bb.build.FuncFailed("Failed to sign RPM packages") | ||
54 | |||
55 | def detach_sign(self, input_file): | ||
56 | """Create a detached signature of a file""" | ||
57 | cmd = "%s --detach-sign --armor --batch --no-tty --yes " \ | ||
58 | "--passphrase-file '%s' -u '%s' " % \ | ||
59 | (self.gpg_bin, self.passphrase_file, self.keyid) | ||
60 | if self.gpg_path: | ||
61 | gpg_cmd += "--homedir %s " % self.gpg_path | ||
62 | cmd += input_file | ||
63 | status, output = oe.utils.getstatusoutput(cmd) | ||
64 | if status: | ||
65 | raise bb.build.FuncFailed("Failed to create signature for '%s': %s" % | ||
66 | (input_file, output)) | ||
67 | |||
68 | |||
69 | def get_signer(d, backend, keyid, passphrase_file): | ||
70 | """Get signer object for the specified backend""" | ||
71 | # Use local signing by default | ||
72 | if backend == 'local': | ||
73 | return LocalSigner(d, keyid, passphrase_file) | ||
74 | else: | ||
75 | bb.fatal("Unsupported signing backend '%s'" % backend) | ||
76 | |||