From 685a5e1558b2252ac895637fb857f6f7bb85ea7b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 20 Feb 2018 15:23:19 +0100 Subject: [PATCH] wks: Add special mode to --install-key. * tools/gpg-wks-client.c (get_key_status_parm_s) (get_key_status_cb, get_key): Move to ... * tools/wks-util.c: ...here. (get_key): Rename to wks_get_key. * tools/gpg-wks-server.c: Include userids.h. (command_install_key): Allow use of a fingerprint. Signed-off-by: Werner Koch --- doc/wks.texi | 17 +++--- tools/gpg-wks-client.c | 117 +---------------------------------------- tools/gpg-wks-server.c | 37 +++++++++---- tools/gpg-wks.h | 2 + tools/wks-util.c | 114 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+), 134 deletions(-) diff --git a/doc/wks.texi b/doc/wks.texi index 2960c6717..6d622828f 100644 --- a/doc/wks.texi +++ b/doc/wks.texi @@ -224,7 +224,9 @@ the process returns failure; to suppress the diagnostic, use option The command @option{--install-key} manually installs a key into the WKD. The arguments are a file with the keyblock and the user-id to -install. +install. If the first argument resembles a fingerprint the key is +taken from the current keyring; to force the use of a file, prefix the +first argument with "./". The command @option{--remove-key} uninstalls a key from the WKD. The process returns success in this case; to also print a diagnostic, use @@ -330,7 +332,7 @@ the submission address: @example $ gpg --batch --passphrase '' --quick-gen-key key-submission@@example.net - $ gpg --with-wkd-hash -K key-submission@@example.net + $ gpg -K key-submission@@example.net @end example The output of the last command looks similar to this: @@ -339,21 +341,16 @@ The output of the last command looks similar to this: sec rsa2048 2016-08-30 [SC] C0FCF8642D830C53246211400346653590B3795B uid [ultimate] key-submission@@example.net - bxzcxpxk8h87z1k7bzk86xn5aj47intu@@example.net ssb rsa2048 2016-08-30 [E] @end example -Take the hash of the string "key-submission", which is -"bxzcxpxk8h87z1k7bzk86xn5aj47intu" and manually publish that key: +Take the fingerprint from that output and manually publish the key: @example - $ gpg --export-options export-minimal --export \ - > -o /var/lib/gnupg/wks/example.net/hu/bxzcxpxk8h87z1k7bzk86xn5aj47intu \ - > key-submission@@example.new + $ gpg-wks-server --install-key C0FCF8642D830C53246211400346653590B3795B \ + > key-submission@@example.net @end example -Make sure that the created file is world readable. - Finally that submission address needs to be redirected to a script running @command{gpg-wks-server}. The @command{procmail} command can be used for this: Redirect the submission address to the user "webkey" diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 3b19c765d..73945ff30 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -325,119 +325,6 @@ main (int argc, char **argv) -struct get_key_status_parm_s -{ - const char *fpr; - int found; - int count; -}; - -static void -get_key_status_cb (void *opaque, const char *keyword, char *args) -{ - struct get_key_status_parm_s *parm = opaque; - - /*log_debug ("%s: %s\n", keyword, args);*/ - if (!strcmp (keyword, "EXPORTED")) - { - parm->count++; - if (!ascii_strcasecmp (args, parm->fpr)) - parm->found = 1; - } -} - - -/* Get a key by fingerprint from gpg's keyring and make sure that the - * mail address ADDRSPEC is included in the key. If EXACT is set the - * returned user id must match Addrspec exactly and not just in the - * addr-spec (mailbox) part. The key is returned as a new memory - * stream at R_KEY. */ -static gpg_error_t -get_key (estream_t *r_key, const char *fingerprint, const char *addrspec, - int exact) -{ - gpg_error_t err; - ccparray_t ccp; - const char **argv = NULL; - estream_t key = NULL; - struct get_key_status_parm_s parm; - char *filterexp = NULL; - - memset (&parm, 0, sizeof parm); - - *r_key = NULL; - - key = es_fopenmem (0, "w+b"); - if (!key) - { - err = gpg_error_from_syserror (); - log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); - goto leave; - } - - /* Prefix the key with the MIME content type. */ - es_fputs ("Content-Type: application/pgp-keys\n" - "\n", key); - - filterexp = es_bsprintf ("keep-uid=%s=%s", exact? "uid":"mbox", addrspec); - if (!filterexp) - { - err = gpg_error_from_syserror (); - log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); - goto leave; - } - - ccparray_init (&ccp, 0); - - ccparray_put (&ccp, "--no-options"); - if (!opt.verbose) - ccparray_put (&ccp, "--quiet"); - else if (opt.verbose > 1) - ccparray_put (&ccp, "--verbose"); - ccparray_put (&ccp, "--batch"); - ccparray_put (&ccp, "--status-fd=2"); - ccparray_put (&ccp, "--always-trust"); - ccparray_put (&ccp, "--armor"); - ccparray_put (&ccp, "--export-options=export-minimal"); - ccparray_put (&ccp, "--export-filter"); - ccparray_put (&ccp, filterexp); - ccparray_put (&ccp, "--export"); - ccparray_put (&ccp, "--"); - ccparray_put (&ccp, fingerprint); - - ccparray_put (&ccp, NULL); - argv = ccparray_get (&ccp, NULL); - if (!argv) - { - err = gpg_error_from_syserror (); - goto leave; - } - parm.fpr = fingerprint; - err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL, - NULL, key, - get_key_status_cb, &parm); - if (!err && parm.count > 1) - err = gpg_error (GPG_ERR_TOO_MANY); - else if (!err && !parm.found) - err = gpg_error (GPG_ERR_NOT_FOUND); - if (err) - { - log_error ("export failed: %s\n", gpg_strerror (err)); - goto leave; - } - - es_rewind (key); - *r_key = key; - key = NULL; - - leave: - es_fclose (key); - xfree (argv); - xfree (filterexp); - return err; -} - - /* Add the user id UID to the key identified by FINGERPRINT. */ static gpg_error_t add_user_id (const char *fingerprint, const char *uid) @@ -767,7 +654,7 @@ command_send (const char *fingerprint, const char *userid) err = gpg_error (GPG_ERR_INV_USER_ID); goto leave; } - err = get_key (&key, fingerprint, addrspec, 0); + err = wks_get_key (&key, fingerprint, addrspec, 0); if (err) goto leave; @@ -897,7 +784,7 @@ command_send (const char *fingerprint, const char *userid) * the key again. */ es_fclose (key); key = NULL; - err = get_key (&key, fingerprint, addrspec, 1); + err = wks_get_key (&key, fingerprint, addrspec, 1); if (err) goto leave; } diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c index e2b830648..a5881557f 100644 --- a/tools/gpg-wks-server.c +++ b/tools/gpg-wks-server.c @@ -35,6 +35,7 @@ #include "../common/util.h" #include "../common/init.h" #include "../common/sysutils.h" +#include "../common/userids.h" #include "../common/ccparray.h" #include "../common/exectool.h" #include "../common/zb32.h" @@ -2002,7 +2003,8 @@ static gpg_error_t command_install_key (const char *fname, const char *userid) { gpg_error_t err; - estream_t fp; + KEYDB_SEARCH_DESC desc; + estream_t fp = NULL; char *addrspec = NULL; char *fpr = NULL; uidinfo_list_t uidlist = NULL; @@ -2011,14 +2013,6 @@ command_install_key (const char *fname, const char *userid) char *huname = NULL; int any; - fp = es_fopen (fname, "rb"); - if (!fp) - { - err = gpg_error_from_syserror (); - log_error ("error reading '%s': %s\n", fname, gpg_strerror (err)); - goto leave; - } - addrspec = mailbox_from_userid (userid); if (!addrspec) { @@ -2027,6 +2021,31 @@ command_install_key (const char *fname, const char *userid) goto leave; } + if (!classify_user_id (fname, &desc, 1) + && (desc.mode == KEYDB_SEARCH_MODE_FPR + || desc.mode == KEYDB_SEARCH_MODE_FPR20)) + { + /* FNAME looks like a fingerprint. Get the key from the + * standard keyring. */ + err = wks_get_key (&fp, fname, addrspec, 0); + if (err) + { + log_error ("error getting key '%s' (uid='%s'): %s\n", + fname, addrspec, gpg_strerror (err)); + goto leave; + } + } + else /* Take it from the file */ + { + fp = es_fopen (fname, "rb"); + if (!fp) + { + err = gpg_error_from_syserror (); + log_error ("error reading '%s': %s\n", fname, gpg_strerror (err)); + goto leave; + } + } + /* List the key so that we can figure out the newest UID with the * requested addrspec. */ err = wks_list_key (fp, &fpr, &uidlist); diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index a5a73c575..1b91b6504 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -86,6 +86,8 @@ typedef struct uidinfo_list_s *uidinfo_list_t; void wks_set_status_fd (int fd); void wks_write_status (int no, const char *format, ...) GPGRT_ATTR_PRINTF(2,3); void free_uidinfo_list (uidinfo_list_t list); +gpg_error_t wks_get_key (estream_t *r_key, const char *fingerprint, + const char *addrspec, int exact); gpg_error_t wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes); gpg_error_t wks_filter_uid (estream_t *r_newkey, estream_t key, diff --git a/tools/wks-util.c b/tools/wks-util.c index 33f1ae7dd..3fd824c1a 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -132,6 +132,120 @@ free_uidinfo_list (uidinfo_list_t list) } + +struct get_key_status_parm_s +{ + const char *fpr; + int found; + int count; +}; + + +static void +get_key_status_cb (void *opaque, const char *keyword, char *args) +{ + struct get_key_status_parm_s *parm = opaque; + + /*log_debug ("%s: %s\n", keyword, args);*/ + if (!strcmp (keyword, "EXPORTED")) + { + parm->count++; + if (!ascii_strcasecmp (args, parm->fpr)) + parm->found = 1; + } +} + +/* Get a key by fingerprint from gpg's keyring and make sure that the + * mail address ADDRSPEC is included in the key. If EXACT is set the + * returned user id must match Addrspec exactly and not just in the + * addr-spec (mailbox) part. The key is returned as a new memory + * stream at R_KEY. */ +gpg_error_t +wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec, + int exact) +{ + gpg_error_t err; + ccparray_t ccp; + const char **argv = NULL; + estream_t key = NULL; + struct get_key_status_parm_s parm; + char *filterexp = NULL; + + memset (&parm, 0, sizeof parm); + + *r_key = NULL; + + key = es_fopenmem (0, "w+b"); + if (!key) + { + err = gpg_error_from_syserror (); + log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); + goto leave; + } + + /* Prefix the key with the MIME content type. */ + es_fputs ("Content-Type: application/pgp-keys\n" + "\n", key); + + filterexp = es_bsprintf ("keep-uid=%s=%s", exact? "uid":"mbox", addrspec); + if (!filterexp) + { + err = gpg_error_from_syserror (); + log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); + goto leave; + } + + ccparray_init (&ccp, 0); + + ccparray_put (&ccp, "--no-options"); + if (!opt.verbose) + ccparray_put (&ccp, "--quiet"); + else if (opt.verbose > 1) + ccparray_put (&ccp, "--verbose"); + ccparray_put (&ccp, "--batch"); + ccparray_put (&ccp, "--status-fd=2"); + ccparray_put (&ccp, "--always-trust"); + ccparray_put (&ccp, "--armor"); + ccparray_put (&ccp, "--export-options=export-minimal"); + ccparray_put (&ccp, "--export-filter"); + ccparray_put (&ccp, filterexp); + ccparray_put (&ccp, "--export"); + ccparray_put (&ccp, "--"); + ccparray_put (&ccp, fingerprint); + + ccparray_put (&ccp, NULL); + argv = ccparray_get (&ccp, NULL); + if (!argv) + { + err = gpg_error_from_syserror (); + goto leave; + } + parm.fpr = fingerprint; + err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL, + NULL, key, + get_key_status_cb, &parm); + if (!err && parm.count > 1) + err = gpg_error (GPG_ERR_TOO_MANY); + else if (!err && !parm.found) + err = gpg_error (GPG_ERR_NOT_FOUND); + if (err) + { + log_error ("export failed: %s\n", gpg_strerror (err)); + goto leave; + } + + es_rewind (key); + *r_key = key; + key = NULL; + + leave: + es_fclose (key); + xfree (argv); + xfree (filterexp); + return err; +} + + /* Helper for wks_list_key and wks_filter_uid. */ static void