Pino Toscano
2014-Feb-21 14:23 UTC
[Libguestfs] [PATCH] builder: allow Sigchecker to import keys from file
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). *) -- 1.8.3.1
Richard W.M. Jones
2014-Feb-21 15:54 UTC
Re: [Libguestfs] [PATCH] builder: allow Sigchecker to import keys from file
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/