[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