gpg: Try Signer's User ID sub-packet with --auto-key-retrieve.
authorWerner Koch <wk@gnupg.org>
Mon, 13 Jun 2016 08:40:34 +0000 (10:40 +0200)
committerWerner Koch <wk@gnupg.org>
Mon, 13 Jun 2016 08:40:34 +0000 (10:40 +0200)
* g10/packet.h (PKT_signature): Add field 'signers_uid'.
* g10/parse-packet.c (parse_signature): Set this field.
* g10/free-packet.c (free_seckey_enc): Free field.
(copy_signature): Copy field.
* g10/mainproc.c (akl_has_wkd_method): New.
(check_sig_and_print): Extend NEWSIG status.  If WKD is enabled try to
locate a missing key via the signature's Signer's User ID sub-packet.
Do this right before trying a keyserver lookup.
--

Signed-off-by: Werner Koch <wk@gnupg.org>
doc/DETAILS
g10/free-packet.c
g10/mainproc.c
g10/packet.h
g10/parse-packet.c

index d2df9ac..2fcdb28 100644 (file)
@@ -341,10 +341,12 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
   arguments in future versions.
 
 ** General status codes
-*** NEWSIG
+*** NEWSIG [<signers_uid>]
     Is issued right before a signature verification starts.  This is
-    useful to define a context for parsing ERROR status messages.  No
-    arguments are currently defined.
+    useful to define a context for parsing ERROR status messages.
+    arguments are currently defined.  If SIGNERS_UID is given and is
+    not "-" this is the percent escape value of the OpenPGP Signer's
+    User ID signature sub-packet.
 
 *** GOODSIG  <long_keyid_or_fpr>  <username>
     The signature with the keyid is good.  For each signature only one
index 8176e36..3883f87 100644 (file)
@@ -82,6 +82,7 @@ free_seckey_enc( PKT_signature *sig )
       xfree (sig->pka_info->uri);
       xfree (sig->pka_info);
     }
+  xfree (sig->signers_uid);
 
   xfree(sig);
 }
@@ -258,6 +259,8 @@ copy_signature( PKT_signature *d, PKT_signature *s )
     d->pka_info = s->pka_info? cp_pka_info (s->pka_info) : NULL;
     d->hashed = cp_subpktarea (s->hashed);
     d->unhashed = cp_subpktarea (s->unhashed);
+    if (s->signers_uid)
+      d->signers_uid = xstrdup (s->signers_uid);
     if(s->numrevkeys)
       {
        d->revkey=NULL;
index 15dc4b9..7033de7 100644 (file)
@@ -1541,6 +1541,19 @@ pka_uri_from_sig (CTX c, PKT_signature *sig)
 }
 
 
+/* Return true if the AKL has the WKD method specified.  */
+static int
+akl_has_wkd_method (void)
+{
+  struct akl *akl;
+
+  for (akl = opt.auto_key_locate; akl; akl = akl->next)
+    if (akl->type == AKL_WKD)
+      return 1;
+  return 0;
+}
+
+
 static void
 print_good_bad_signature (int statno, const char *keyid_str, kbnode_t un,
                           PKT_signature *sig, int rc)
@@ -1697,7 +1710,11 @@ check_sig_and_print (CTX c, kbnode_t node)
       }
   }
 
-  write_status_text (STATUS_NEWSIG, NULL);
+  if (sig->signers_uid)
+    write_status_buffer (STATUS_NEWSIG,
+                         sig->signers_uid, strlen (sig->signers_uid), 0);
+  else
+    write_status_text (STATUS_NEWSIG, NULL);
 
   astr = openpgp_pk_algo_name ( sig->pubkey_algo );
   if (keystrlen () > 8)
@@ -1713,8 +1730,7 @@ check_sig_and_print (CTX c, kbnode_t node)
 
   rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
 
-  /* If the key isn't found, check for a preferred keyserver */
-
+  /* If the key isn't found, check for a preferred keyserver.  */
   if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks)
     {
       const byte *p;
@@ -1755,8 +1771,8 @@ check_sig_and_print (CTX c, kbnode_t node)
         }
     }
 
-  /* If the preferred keyserver thing above didn't work, our second
-     try is to use the URI from a DNS PKA record. */
+  /* If the avove methods didn't work, our next try is to use the URI
+   * from a DNS PKA record.  */
   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))
@@ -1775,17 +1791,54 @@ check_sig_and_print (CTX c, kbnode_t node)
             {
               glo_ctrl.in_auto_key_retrieve++;
               res = keyserver_import_keyid (c->ctrl, sig->keyid, spec);
-                glo_ctrl.in_auto_key_retrieve--;
-                free_keyserver_spec (spec);
-                if (!res)
-                  rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
+              glo_ctrl.in_auto_key_retrieve--;
+              free_keyserver_spec (spec);
+              if (!res)
+                rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
             }
         }
     }
 
-  /* If the preferred keyserver thing above didn't work and we got
-       no information from the DNS PKA, this is a third try. */
+  /* If the above methods didn't work, our next try is to use 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.  */
+  /* if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY */
+  /*     && signature_hash_full_fingerprint (sig) */
+  /*     && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) */
+  /*     && keyserver_any_configured (c->ctrl)) */
+  /*   { */
+  /*     int res; */
+
+  /*     glo_ctrl.in_auto_key_retrieve++; */
+  /*     res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver ); */
+  /*     glo_ctrl.in_auto_key_retrieve--; */
+  /*     if (!res) */
+  /*       rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey ); */
+  /*   } */
+
+  /* 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)
+      && akl_has_wkd_method ()
+      && sig->signers_uid)
+    {
+      int res;
+
+      glo_ctrl.in_auto_key_retrieve++;
+      res = keyserver_import_wkd (c->ctrl, sig->signers_uid, 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, NULL, &is_expkey, &is_revkey );
+    }
 
+  /* 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)
       && keyserver_any_configured (c->ctrl))
@@ -1793,7 +1846,7 @@ check_sig_and_print (CTX c, kbnode_t node)
       int res;
 
       glo_ctrl.in_auto_key_retrieve++;
-      res=keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver );
+      res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver );
       glo_ctrl.in_auto_key_retrieve--;
       if (!res)
         rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
index 6ea2f83..8fb6fc4 100644 (file)
@@ -230,6 +230,8 @@ typedef struct
   int numrevkeys;
   pka_info_t *pka_info;      /* Malloced PKA data or NULL if not
                                 available.  See also flags.pka_tried. */
+  char *signers_uid;         /* Malloced value of the SIGNERS_UID
+                              * subpacket.  */
   subpktarea_t *hashed;      /* All subpackets with hashed data (v4 only). */
   subpktarea_t *unhashed;    /* Ditto for unhashed data. */
   /* First 2 bytes of the digest.  (Serialized.  Note: this is not
index c77e409..c30abcb 100644 (file)
@@ -1915,6 +1915,20 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
       if (p)
        sig->flags.pref_ks = 1;
 
+      p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIGNERS_UID, &len);
+      if (p && len)
+        {
+          sig->signers_uid = xtrymalloc (len+1);
+          if (!sig->signers_uid)
+            {
+              rc = gpg_error_from_syserror ();
+              goto leave;
+            }
+          /* Note that we don't care about binary zeroes in the value.  */
+          memcpy (sig->signers_uid, p, len);
+          sig->signers_uid[len] = 0;
+        }
+
       p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION, NULL);
       if (p)
        sig->flags.notation = 1;