]> git.ipfire.org Git - pakfire.git/commitdiff
Add concept of a host key and sign all packages with it.
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 23 Mar 2012 15:35:31 +0000 (16:35 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 23 Mar 2012 15:35:31 +0000 (16:35 +0100)
python/pakfire/builder.py
python/pakfire/cli.py
python/pakfire/keyring.py

index ac8a0f1db63088a4a2522fae003fd6ea4aac6d7d..d595a10b8bafd0f816e9fcab6b4c30bf0d14d4d0 100644 (file)
@@ -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 = [
index df8cb061944d351bdc09ef293cfcfe1678bc6f28..04c7b8a27ad9fc0a65a8ddff1101eea59d9ca1d3 100644 (file)
@@ -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]
index e2a1db889715ae6811f114f4765353b95845d883..bfa1d127f4f3c1e424128c97953060e1db206910 100644 (file)
@@ -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 = """
                        <GnupgKeyParms format="internal">
                                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
                        </GnupgKeyParms>
-               """ % (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