[Libguestfs] [PATCH] builder: allow Sigchecker to import keys from file

Richard W.M. Jones rjones at redhat.com
Fri Feb 21 15:54:08 UTC 2014


On Fri, Feb 21, 2014 at 03:23:44PM +0100, Pino Toscano wrote:
> Extend Sigchecker so it allows both fingerprints (to be imported from
> user's keyring, as before) and keys stored in files. To simplify this
> process (and have the fingerprint always around), the key is imported
> on Sigchecker.create time, instead of lazily at the first verification.
> ---
>  builder/builder.ml     |   3 +-
>  builder/sigchecker.ml  | 120 ++++++++++++++++++++++++++++---------------------
>  builder/sigchecker.mli |   6 ++-
>  3 files changed, 76 insertions(+), 53 deletions(-)
> 
> diff --git a/builder/builder.ml b/builder/builder.ml
> index 7fa3cc7..80ccef7 100644
> --- a/builder/builder.ml
> +++ b/builder/builder.ml
> @@ -141,7 +141,8 @@ let main () =
>        List.map (
>          fun (source, fingerprint) ->
>            let sigchecker =
> -            Sigchecker.create ~debug ~gpg ~fingerprint ~check_signature in
> +            Sigchecker.create ~debug ~gpg ~check_signature
> +              ~gpgkey:(Sigchecker.Fingerprint fingerprint) in
>            Index_parser.get_index ~prog ~debug ~downloader ~sigchecker source
>        ) sources
>      ) in
> diff --git a/builder/sigchecker.ml b/builder/sigchecker.ml
> index 10e342e..7459e4b 100644
> --- a/builder/sigchecker.ml
> +++ b/builder/sigchecker.ml
> @@ -96,41 +96,97 @@ ZvXkQ3FVJwZoLmHw47vvlVpLD/4gi1SuHWieRvZ+UdDq00E348pm
>  -----END PGP PUBLIC KEY BLOCK-----
>  "
>  
> +type gpgkey_type =
> +  | Fingerprint of string
> +  | KeyFile of string
> +
>  type t = {
>    debug : bool;
>    gpg : string;
>    fingerprint : string;
>    check_signature : bool;
>    gpghome : string;
> -  mutable key_imported : bool;
>  }
>  
> -let create ~debug ~gpg ~fingerprint ~check_signature =
> -  (* Create a temporary directory for gnupg. *)
> -  let tmpdir = Mkdtemp.mkdtemp (Filename.temp_dir_name // "vb.gpghome.XXXXXX") in
> -  rmdir_on_exit tmpdir;
> -  (* Run gpg once, so it can setup its own home directory, failing
> -   * if it cannot.
> -   *)
> -  let cmd = sprintf "%s --homedir %s --list-keys%s"
> -    gpg tmpdir (if debug then "" else " >/dev/null 2>&1") in
> +(* Import the specified key file. *)
> +let import_keyfile ~gpg ~gpghome ~debug keyfile =
> +  let status_file = Filename.temp_file "vbstat" ".txt" in
> +  unlink_on_exit status_file;
> +  let cmd = sprintf "%s --homedir %s --status-file %s --import %s%s"
> +    gpg gpghome (quote status_file) (quote keyfile)
> +    (if debug then "" else " >/dev/null 2>&1") in
>    if debug then eprintf "%s\n%!" cmd;
>    let r = Sys.command cmd in
>    if r <> 0 then (
> -    eprintf (f_"virt-builder: error: GPG failure: could not run GPG the first time\nUse the '-v' option and look for earlier error messages.\n");
> +    eprintf (f_"virt-builder: error: could not import public key\nUse the '-v' option and look for earlier error messages.\n");
>      exit 1
>    );
> +  status_file
> +
> +let rec create ~debug ~gpg ~gpgkey ~check_signature =
> +  (* Create a temporary directory for gnupg. *)
> +  let tmpdir = Mkdtemp.mkdtemp (Filename.temp_dir_name // "vb.gpghome.XXXXXX") in
> +  rmdir_on_exit tmpdir;
> +  let fingerprint =
> +    if check_signature then (
> +      (* Run gpg so it can setup its own home directory, failing if it
> +       * cannot.
> +       *)
> +      let cmd = sprintf "%s --homedir %s --list-keys%s"
> +        gpg tmpdir (if debug then "" else " >/dev/null 2>&1") in
> +      if debug then eprintf "%s\n%!" cmd;
> +      let r = Sys.command cmd in
> +      if r <> 0 then (
> +        eprintf (f_"virt-builder: error: GPG failure: could not run GPG the first time\nUse the '-v' option and look for earlier error messages.\n");
> +        exit 1
> +      );
> +      match gpgkey with
> +      | KeyFile kf ->
> +        let status_file = import_keyfile gpg tmpdir debug kf in
> +        let status = read_whole_file status_file in
> +        let status = string_nsplit "\n" status in
> +        let fingerprint = ref "" in
> +        List.iter (
> +          fun line ->
> +            let line = string_nsplit " " line in
> +            match line with
> +            | "[GNUPG:]" :: "IMPORT_OK" :: _ :: fp :: _ -> fingerprint := fp
> +            | _ -> ()
> +        ) status;
> +        !fingerprint
> +      | Fingerprint fp when equal_fingerprints default_fingerprint fp ->
> +        let filename, chan = Filename.open_temp_file "vbpubkey" ".asc" in
> +        unlink_on_exit filename;
> +        output_string chan default_pubkey;
> +        close_out chan;
> +        ignore (import_keyfile gpg tmpdir debug filename);
> +        fp
> +      | Fingerprint fp ->
> +        let filename = Filename.temp_file "vbpubkey" ".asc" in
> +        unlink_on_exit filename;
> +        let cmd = sprintf "%s --yes --armor --output %s --export %s%s"
> +          gpg (quote filename) (quote fp)
> +          (if debug then "" else " >/dev/null 2>&1") in
> +        if debug then eprintf "%s\n%!" cmd;
> +        let r = Sys.command cmd in
> +        if r <> 0 then (
> +          eprintf (f_"virt-builder: error: could not export public key\nUse the '-v' option and look for earlier error messages.\n");
> +          exit 1
> +        );
> +        ignore (import_keyfile gpg tmpdir debug filename);
> +        fp
> +    ) else
> +      "" in
>    {
>      debug = debug;
>      gpg = gpg;
>      fingerprint = fingerprint;
>      check_signature = check_signature;
>      gpghome = tmpdir;
> -    key_imported = false;
>    }
>  
>  (* Compare two strings of hex digits ignoring whitespace and case. *)
> -let rec equal_fingerprints fp1 fp2 =
> +and equal_fingerprints fp1 fp2 =
>    let len1 = String.length fp1 and len2 = String.length fp2 in
>    let rec loop i j =
>      if i = len1 && j = len2 then true (* match! *)
> @@ -171,8 +227,6 @@ and verify_detached t filename sigfile =
>    )
>  
>  and do_verify t args =
> -  import_key t;
> -
>    let status_file = Filename.temp_file "vbstat" ".txt" in
>    unlink_on_exit status_file;
>    let cmd =
> @@ -206,42 +260,6 @@ and do_verify t args =
>      exit 1
>    )
>  
> -(* Import the requested public key. *)
> -and import_key t =
> -  if not t.key_imported then (
> -    let keyfile = ref "" in
> -    if equal_fingerprints default_fingerprint t.fingerprint then (
> -      let filename, chan = Filename.open_temp_file "vbpubkey" ".asc" in
> -      unlink_on_exit filename;
> -      output_string chan default_pubkey;
> -      close_out chan;
> -      keyfile := filename
> -    ) else (
> -      let filename = Filename.temp_file "vbpubkey" ".asc" in
> -      unlink_on_exit filename;
> -      let cmd = sprintf "%s --yes --armor --output %s --export %s%s"
> -        t.gpg (quote filename) (quote t.fingerprint)
> -        (if t.debug then "" else " >/dev/null 2>&1") in
> -      if t.debug then eprintf "%s\n%!" cmd;
> -      let r = Sys.command cmd in
> -      if r <> 0 then (
> -        eprintf (f_"virt-builder: error: could not export public key\nUse the '-v' option and look for earlier error messages.\n");
> -        exit 1
> -      );
> -      keyfile := filename
> -    );
> -
> -    let cmd = sprintf "%s --homedir %s --import %s%s"
> -      t.gpg t.gpghome (quote !keyfile)
> -      (if t.debug then "" else " >/dev/null 2>&1") in
> -    let r = Sys.command cmd in
> -    if r <> 0 then (
> -      eprintf (f_"virt-builder: error: could not import public key\nUse the '-v' option and look for earlier error messages.\n");
> -      exit 1
> -    );
> -    t.key_imported <- true
> -  )
> -
>  type csum_t = SHA512 of string
>  
>  let verify_checksum t (SHA512 csum) filename =
> diff --git a/builder/sigchecker.mli b/builder/sigchecker.mli
> index cdd800e..f4e817e 100644
> --- a/builder/sigchecker.mli
> +++ b/builder/sigchecker.mli
> @@ -20,7 +20,11 @@ val default_fingerprint : string
>  
>  type t
>  
> -val create : debug:bool -> gpg:string -> fingerprint:string -> check_signature:bool -> t
> +type gpgkey_type =
> +  | Fingerprint of string
> +  | KeyFile of string
> +
> +val create : debug:bool -> gpg:string -> gpgkey:gpgkey_type -> check_signature:bool -> t
>  
>  val verify : t -> string -> unit
>  (** Verify the file is signed (if check_signature is true). *)

ACK.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine.  Supports Linux and Windows.
http://people.redhat.com/~rjones/virt-df/




More information about the Libguestfs mailing list