From 1389d9d59e1b24f19edae90d1f6a411fcd085440 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Fri, 23 Mar 2012 16:35:31 +0100 Subject: [PATCH] Add concept of a host key and sign all packages with it. --- python/pakfire/builder.py | 76 +++++++++++++++++++++++++++++++++++++++ python/pakfire/cli.py | 6 +--- python/pakfire/keyring.py | 75 +++++++++++++++++++++++++++++++++----- 3 files changed, 144 insertions(+), 13 deletions(-) diff --git a/python/pakfire/builder.py b/python/pakfire/builder.py index ac8a0f1db..d595a10b8 100644 --- a/python/pakfire/builder.py +++ b/python/pakfire/builder.py @@ -192,6 +192,7 @@ class BuildEnviron(object): "enable_loop_devices" : True, "enable_ccache" : True, "enable_icecream" : False, + "sign_packages" : True, } #self.settings.update(settings) @@ -244,6 +245,20 @@ class BuildEnviron(object): "build_time" : self.build_time, } + @property + def keyring(self): + """ + Shortcut to access the pakfire keyring. + + (Makes also sure that it is properly initialized.) + """ + assert self.pakfire + + if not self.pakfire.keyring.initialized: + self.pakfire.keyring.init() + + return self.pakfire.keyring + def lock(self): filename = os.path.join(self.path, ".lock") @@ -391,6 +406,9 @@ class BuildEnviron(object): # Dependency errors when trying to install the result packages are build errors. except DependencyError, e: + # Dump all packages (for debugging). + self.dump() + raise BuildError, e def chrootPath(self, *args): @@ -699,10 +717,21 @@ class BuildEnviron(object): raise BuildError, _("The build command failed. See logfile for details.") + # Sign all built packages with the host key (if available). + if self.settings.get("sign_packages"): + host_key = self.keyring.get_host_key() + assert host_key + + # Do the signing... + self.sign(host_key) + # Perform install test. if install_test: self.install_test() + # Dump package information. + self.dump() + def shell(self, args=[]): if not util.cli_is_interactive(): self.log.warning("Cannot run shell on non-interactive console.") @@ -730,6 +759,53 @@ class BuildEnviron(object): shell = os.system(command) return os.WEXITSTATUS(shell) + def sign(self, keyfp): + assert self.keyring.get_key(keyfp), "Key for signing does not exist" + + # Find all files to process. + files = self.find_result_packages() + + # Create a progressbar. + p = util.make_progress(_("Signing files (%s)") % keyfp, len(files)) + i = 0 + + for file in files: + # Update progressbar. + if p: + i += 1 + p.update(i) + + # Open package file. + pkg = packages.open(self.pakfire, None, file) + + # Sign it. + pkg.sign(keyfp) + + # Close progressbar. + if p: + p.finish() + + def dump(self): + pkgs = [] + + for file in self.find_result_packages(): + pkg = packages.open(self.pakfire, None, file) + pkgs.append(pkg) + + # If there are no packages, there is nothing to do. + if not pkgs: + return + + pkgs.sort() + + self.log.info(_("Dumping package information:")) + for pkg in pkgs: + dump = pkg.dump(long=True) + + for line in dump.splitlines(): + self.log.info(" %s" % line) + self.log.info("") # Empty line. + @property def cache_file(self): comps = [ diff --git a/python/pakfire/cli.py b/python/pakfire/cli.py index df8cb0619..04c7b8a27 100644 --- a/python/pakfire/cli.py +++ b/python/pakfire/cli.py @@ -1256,11 +1256,7 @@ class CliKey(Cli): print # Generate the key. - fpr = pakfire.key_generate(realname, email, **self.pakfire_args) - - # Dump all information about the new key. - for line in self.dump_key(fpr): - print line + pakfire.key_generate(realname, email, **self.pakfire_args) def handle_import(self): filename = self.args.filename[0] diff --git a/python/pakfire/keyring.py b/python/pakfire/keyring.py index e2a1db889..bfa1d127f 100644 --- a/python/pakfire/keyring.py +++ b/python/pakfire/keyring.py @@ -63,11 +63,25 @@ class Keyring(object): f.close() # XXX chmod 600 + @property + def initialized(self): + """ + Returns true if the local keyring was already initialized. + """ + if self.get_host_key(): + return True + + return False + def init(self): + # If the host key is already present, we break up. + if self.initialized: + log.error(_("The local keyring is already initialized. Aborting.")) + return + log.info(_("Initializing local keyring...")) hostname, domainname = system.hostname.split(".", 1) - self.gen_key(system.hostname, "%s@%s" % (hostname, domainname)) def dump_key(self, keyfp): @@ -105,6 +119,15 @@ class Keyring(object): return ret + def get_keys(self): + """ + Returns all keys that are known to the system. + """ + + ctx = gpgme.Context() + + return [k.subkeys[0].keyid for k in ctx.keylist(None, True)] + def get_key(self, keyid): ctx = gpgme.Context() @@ -113,17 +136,40 @@ class Keyring(object): except gpgme.GpgmeError: return None + def get_host_key(self): + key = None + + for fpr in self.get_keys(): + k = self.get_key(fpr) + + for uid in k.uids: + if not uid.name == system.hostname: + continue + + key = fpr + break + + return key + def gen_key(self, realname, email): + args = { + "realname" : realname, + "email" : email, + } + params = """ Key-Type: RSA Key-Usage: sign - Key-Length: 2048 - Name-Real: %s - Name-Email: %s + Key-Length: 4096 + Name-Real: %(realname)s + Name-Email: %(email)s Expire-Date: 0 - """ % (realname, email) + """ % args + + log.info(_("Generating new key for %(realname)s <%(email)s>...") % args) + log.info(_("This may take a while...")) # Create a new context. ctx = gpgme.Context() @@ -131,6 +177,10 @@ class Keyring(object): # Generate the key. result = ctx.genkey(params) + # Dump the recently generated key. + for line in self.dump_key(result.fpr): + log.info(line) + # Return the fingerprint of the generated key. return result.fpr @@ -165,11 +215,20 @@ class Keyring(object): def list_keys(self): ret = [] - ctx = gpgme.Context() + # Search for the host key and show it. + host_key = self.get_host_key() + if host_key: + ret.append(_("Host key:")) + ret += [" %s" % l for l in self.dump_key(host_key)] + else: + ret.append(_("No host key available.")) - keys = [k.subkeys[0].keyid for k in ctx.keylist(None, True)] + # List all other keys. + for key in self.get_keys(): + # Skip the host key. + if key == host_key: + continue - for key in keys: ret += self.dump_key(key) return ret -- 2.39.5