From 96bf8f477805bae58cfb77af8ceba418ff8aaad9 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 5 Jul 2019 09:31:58 +0200 Subject: [PATCH] gpg: With --auto-key-retrieve prefer WKD over keyservers. * g10/mainproc.c (check_sig_and_print): Print a hint on how to make use of the preferred keyserver. Remove keyserver lookup just by the keyid. Try a WKD lookup before a keyserver lookup. -- The use of the the keyid for lookups does not make much sense anymore since for quite some time we do have the fingerprint as part of the signature. GnuPG-bug-id: 4595 Signed-off-by: Werner Koch --- doc/gpg.texi | 24 ++++++++-- g10/keyserver.c | 2 +- g10/mainproc.c | 116 ++++++++++++++++++++++++++---------------------- 3 files changed, 85 insertions(+), 57 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 9513a4e0f..80c7f48f5 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1814,10 +1814,26 @@ These options enable or disable the automatic retrieving of keys from a keyserver when verifying signatures made by keys that are not on the local keyring. The default is @option{--no-auto-key-retrieve}. -If the method "wkd" is included in the list of methods given to -@option{auto-key-locate}, the signer's user ID is part of the -signature, and the option @option{--disable-signer-uid} is not used, -the "wkd" method may also be used to retrieve a key. +The order of methods tried to lookup the key is: + +1. If a preferred keyserver is specified in the signature and the +option @option{honor-keyserver-url} is active (which is not the +default), that keyserver is tried. Note that the creator of the +signature uses the option @option{--sig-keyserver-url} to specify the +preferred keyserver for data signatures. + +2. If the signature has the Signer's UID set (e.g. using +@option{--sender} while creating the signature) a Web Key Directory +(WKD) lookup is done. This is the default configuration but can be +disabled by removing WKD from the auto-key-locate list or by using the +option @option{--disable-signer-uid}. + +3. If the option @option{honor-pka-record} is active, the legacy PKA +method is used. + +4. If any keyserver is configured and the Issuer Fingerprint is part +of the signature (since GnuPG 2.1.16), the configured keyservers are +tried. Note that this option makes a "web bug" like behavior possible. Keyserver or Web Key Directory operators can see which keys you diff --git a/g10/keyserver.c b/g10/keyserver.c index 3a6fe69a8..b07afb128 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -333,7 +333,7 @@ parse_keyserver_uri (const char *string,int require_scheme) { /* Three slashes means network path with a default host name. This is a hack because it does not crok all possible - combiantions. We should better repalce all code bythe parser + combinations. We should better replace all code by the parser from http.c. */ keyserver->path = xstrdup (uri+2); } diff --git a/g10/mainproc.c b/g10/mainproc.c index ba03de660..f44faf82d 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1843,7 +1843,6 @@ check_sig_and_print (CTX c, kbnode_t node) int is_revkey = 0; char *issuer_fpr = NULL; PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */ - int tried_ks_by_fpr; const void *extrahash = NULL; size_t extrahashlen = 0; @@ -2002,12 +2001,17 @@ check_sig_and_print (CTX c, kbnode_t node) rc = do_check_sig (c, node, extrahash, extrahashlen, NULL, &is_expkey, &is_revkey, &pk); - /* If the key isn't found, check for a preferred keyserver. */ - if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks) + /* If the key isn't found, check for a preferred keyserver. Note + * that this is only done if honor-keyserver-url has been set. We + * test for this in the loop so that we can show info about the + * preferred keyservers. */ + if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY + && sig->flags.pref_ks) { const byte *p; int seq = 0; size_t n; + int any_pref_ks = 0; while ((p=enum_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS,&n,&seq,NULL))) { @@ -2018,9 +2022,10 @@ check_sig_and_print (CTX c, kbnode_t node) log_info(_("Key available at: ") ); print_utf8_buffer (log_get_stream(), p, n); log_printf ("\n"); + any_pref_ks = 1; - if (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE - && opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL) + if ((opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) + && (opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL)) { struct keyserver_spec *spec; @@ -2029,6 +2034,10 @@ check_sig_and_print (CTX c, kbnode_t node) { int res; + if (DBG_LOOKUP) + log_debug ("trying auto-key-retrieve method %s\n", + "Pref-KS"); + free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; @@ -2037,6 +2046,9 @@ check_sig_and_print (CTX c, kbnode_t node) if (!res) rc = do_check_sig (c, node, extrahash, extrahashlen, NULL, &is_expkey, &is_revkey, &pk); + else if (DBG_LOOKUP) + log_debug ("lookup via %s failed: %s\n", "Pref-KS", + gpg_strerror (res)); free_keyserver_spec (spec); if (!rc) @@ -2044,10 +2056,44 @@ check_sig_and_print (CTX c, kbnode_t node) } } } + + if (any_pref_ks + && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) + && !(opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL)) + log_info (_("Note: Use '%s' to make use of this info\n"), + "--keyserver-option honor-keyserver-url"); + } + + /* If the above methods didn't work, our next try is to retrieve the + * key from the WKD. This requires that WKD is in the AKL and the + * Signer's UID is in the signature. */ + if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY + && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) + && !opt.flags.disable_signer_uid + && akl_has_wkd_method () + && sig->signers_uid) + { + int res; + + if (DBG_LOOKUP) + log_debug ("trying auto-key-retrieve method %s\n", "WKD"); + free_public_key (pk); + pk = NULL; + glo_ctrl.in_auto_key_retrieve++; + res = keyserver_import_wkd (c->ctrl, sig->signers_uid, 1, NULL, NULL); + glo_ctrl.in_auto_key_retrieve--; + /* Fixme: If the fingerprint is embedded in the signature, + * compare it to the fingerprint of the returned key. */ + if (!res) + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); + else if (DBG_LOOKUP) + log_debug ("lookup via %s failed: %s\n", "WKD", gpg_strerror (res)); } /* If the avove methods didn't work, our next try is to use the URI - * from a DNS PKA record. */ + * from a DNS PKA record. This is a legacy method which will + * eventually be removed. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) && (opt.keyserver_options.options & KEYSERVER_HONOR_PKA_RECORD)) @@ -2064,6 +2110,9 @@ check_sig_and_print (CTX c, kbnode_t node) spec = parse_keyserver_uri (uri, 1); if (spec) { + if (DBG_LOOKUP) + log_debug ("trying auto-key-retrieve method %s\n", "PKA"); + free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; @@ -2073,16 +2122,16 @@ check_sig_and_print (CTX c, kbnode_t node) if (!res) rc = do_check_sig (c, node, extrahash, extrahashlen, NULL, &is_expkey, &is_revkey, &pk); + else if (DBG_LOOKUP) + log_debug ("lookup via %s failed: %s\n", "PKA", + gpg_strerror (res)); } } } /* If the above methods didn't work, our next try is to locate * the key via its fingerprint from a keyserver. This requires - * that the signers fingerprint is encoded in the signature. We - * favor this over the WKD method (to be tried next), because an - * arbitrary keyserver is less subject to web bug like monitoring. */ - tried_ks_by_fpr = 0; + * that the signers fingerprint is encoded in the signature. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) && keyserver_any_configured (c->ctrl)) @@ -2094,60 +2143,23 @@ check_sig_and_print (CTX c, kbnode_t node) p = issuer_fpr_raw (sig, &n); if (p) { + if (DBG_LOOKUP) + log_debug ("trying auto-key-retrieve method %s\n", "KS"); + /* v4 or v5 packet with a SHA-1/256 fingerprint. */ free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_fprint (c->ctrl, p, n, opt.keyserver, 1); - tried_ks_by_fpr = 1; glo_ctrl.in_auto_key_retrieve--; if (!res) rc = do_check_sig (c, node, extrahash, extrahashlen, NULL, &is_expkey, &is_revkey, &pk); + else if (DBG_LOOKUP) + log_debug ("lookup via %s failed: %s\n", "KS", gpg_strerror (res)); } } - /* If the above methods didn't work, our next try is to retrieve the - * key from the WKD. */ - if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY - && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) - && !opt.flags.disable_signer_uid - && akl_has_wkd_method () - && sig->signers_uid) - { - int res; - - free_public_key (pk); - pk = NULL; - glo_ctrl.in_auto_key_retrieve++; - res = keyserver_import_wkd (c->ctrl, sig->signers_uid, 1, NULL, NULL); - glo_ctrl.in_auto_key_retrieve--; - /* Fixme: If the fingerprint is embedded in the signature, - * compare it to the fingerprint of the returned key. */ - if (!res) - rc = do_check_sig (c, node, extrahash, extrahashlen, - NULL, &is_expkey, &is_revkey, &pk); - } - - /* If the above methods did't work, our next try is to use a - * keyserver. */ - if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY - && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) - && !tried_ks_by_fpr - && keyserver_any_configured (c->ctrl)) - { - int res; - - free_public_key (pk); - pk = NULL; - glo_ctrl.in_auto_key_retrieve++; - res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver, 1); - glo_ctrl.in_auto_key_retrieve--; - if (!res) - rc = do_check_sig (c, node, extrahash, extrahashlen, - NULL, &is_expkey, &is_revkey, &pk); - } - if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE) { kbnode_t un, keyblock;