gpg: Store key origin info for new DANE and WKD retrieved keys.
authorWerner Koch <wk@gnupg.org>
Mon, 24 Jul 2017 18:05:28 +0000 (20:05 +0200)
committerWerner Koch <wk@gnupg.org>
Mon, 24 Jul 2017 18:09:52 +0000 (20:09 +0200)
* g10/import.c (apply_meta_data): Remove arg 'merge'.  Add arg 'url'.
Implement WKD and DANE key origin.
(import_keys_internal): Add arg 'url' and change all callers.
(import_keys_es_stream): Ditto.
(import): Ditto.
(import_one): Ditto.
* g10/keylist.c (list_keyblock_print): Fix update URL printing.
* g10/call-dirmngr.c (gpg_dirmngr_wkd_get): Add arg 'r_url' to return
the SOURCE.  Pass ks_status_cb to assuan_transact.
* g10/keyserver.c (keyserver_import_wkd): Get that URL and pass it to
the import function.
--

Note that this only for new keys.  Merging this info will be added
soon.

Signed-off-by: Werner Koch <wk@gnupg.org>
g10/call-dirmngr.c
g10/call-dirmngr.h
g10/gpg.c
g10/import.c
g10/keylist.c
g10/keyserver.c
g10/main.h

index 76fa072..9bae59f 100644 (file)
@@ -41,7 +41,8 @@
 #include "call-dirmngr.h"
 
 
-/* Parameter structure used to gather status info.  */
+/* Parameter structure used to gather status info.  Note that it is
+ * also used for WKD requests.  */
 struct ks_status_parm_s
 {
   const char *keyword; /* Look for this keyword or NULL for "SOURCE". */
@@ -368,7 +369,7 @@ clear_context_flags (ctrl_t ctrl, assuan_context_t ctx)
 
 
 \f
-/* Status callback for ks_list, ks_get and ks_search.  */
+/* Status callback for ks_list, ks_get, ks_search, and wkd_get  */
 static gpg_error_t
 ks_status_cb (void *opaque, const char *line)
 {
@@ -1317,17 +1318,24 @@ gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid,
 \f
 /* Ask the dirmngr to retrieve a key via the Web Key Directory
  * protocol.  If QUICK is set the dirmngr is advised to use a shorter
- * timeout.  On success a new estream with the key is stored at R_KEY.
+ * timeout.  On success a new estream with the key stored at R_KEY and the
+ * url of the lookup (if any) stored at R_URL.  Note that
  */
 gpg_error_t
-gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, int quick, estream_t *r_key)
+gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, int quick,
+                     estream_t *r_key, char **r_url)
 {
   gpg_error_t err;
   assuan_context_t ctx;
-  struct dns_cert_parm_s parm;
+  struct ks_status_parm_s stparm = { NULL };
+  struct dns_cert_parm_s parm = { NULL };
   char *line = NULL;
 
-  memset (&parm, 0, sizeof parm);
+  if (r_key)
+    *r_key = NULL;
+
+  if (r_url)
+    *r_url = NULL;
 
   err = open_context (ctrl, &ctx);
   if (err)
@@ -1352,7 +1360,7 @@ gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, int quick, estream_t *r_key)
       goto leave;
     }
   err = assuan_transact (ctx, line, dns_cert_data_cb, &parm,
-                         NULL, NULL, NULL, &parm);
+                         NULL, NULL, ks_status_cb, &stparm);
   if (err)
     goto leave;
 
@@ -1363,7 +1371,14 @@ gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, int quick, estream_t *r_key)
       parm.memfp = NULL;
     }
 
+  if (r_url)
+    {
+      *r_url = stparm.source;
+      stparm.source = NULL;
+    }
+
  leave:
+  xfree (stparm.source);
   xfree (parm.fpr);
   xfree (parm.url);
   es_fclose (parm.memfp);
index 95a8c4a..285c4cb 100644 (file)
@@ -41,7 +41,7 @@ gpg_error_t gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid,
                                  unsigned char **r_fpr, size_t *r_fprlen,
                                  char **r_url);
 gpg_error_t gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, int quick,
-                                 estream_t *r_key);
+                                 estream_t *r_key, char **r_url);
 
 
 #endif /*GNUPG_G10_CALL_DIRMNGR_H*/
index e32e14a..7495e17 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -4515,7 +4515,7 @@ main (int argc, char **argv)
         opt.import_options |= IMPORT_FAST; /* fall through */
       case aImport:
        import_keys (ctrl, argc? argv:NULL, argc, NULL,
-                     opt.import_options, opt.key_origin);
+                     opt.import_options, opt.key_origin, NULL);
        break;
 
        /* TODO: There are a number of command that use this same
index c87f49b..e3c8c37 100644 (file)
@@ -97,7 +97,8 @@ struct import_filter_s import_filter;
 static int import (ctrl_t ctrl,
                    IOBUF inp, const char* fname, struct import_stats_s *stats,
                   unsigned char **fpr, size_t *fpr_len, unsigned int options,
-                  import_screener_t screener, void *screener_arg, int origin);
+                  import_screener_t screener, void *screener_arg,
+                   int origin, const char *url);
 static int read_block (IOBUF a, int with_meta,
                        PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys);
 static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
@@ -107,7 +108,7 @@ static int import_one (ctrl_t ctrl,
                        unsigned char **fpr, size_t *fpr_len,
                        unsigned int options, int from_sk, int silent,
                        import_screener_t screener, void *screener_arg,
-                       int origin);
+                       int origin, const char *url);
 static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
                               struct import_stats_s *stats, int batch,
                               unsigned int options, int for_migration,
@@ -432,7 +433,7 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
                       unsigned char **fpr, size_t *fpr_len,
                      unsigned int options,
                       import_screener_t screener, void *screener_arg,
-                      int origin)
+                      int origin, const char *url)
 {
   int i;
   int rc = 0;
@@ -444,7 +445,7 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
   if (inp)
     {
       rc = import (ctrl, inp, "[stream]", stats, fpr, fpr_len, options,
-                   screener, screener_arg, origin);
+                   screener, screener_arg, origin, url);
     }
   else
     {
@@ -469,7 +470,7 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
           else
             {
               rc = import (ctrl, inp2, fname, stats, fpr, fpr_len, options,
-                           screener, screener_arg, origin);
+                           screener, screener_arg, origin, url);
               iobuf_close (inp2);
               /* Must invalidate that ugly cache to actually close it. */
               iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
@@ -503,10 +504,11 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
 
 void
 import_keys (ctrl_t ctrl, char **fnames, int nnames,
-            import_stats_t stats_handle, unsigned int options, int origin)
+            import_stats_t stats_handle, unsigned int options,
+             int origin, const char *url)
 {
   import_keys_internal (ctrl, NULL, fnames, nnames, stats_handle,
-                        NULL, NULL, options, NULL, NULL, origin);
+                        NULL, NULL, options, NULL, NULL, origin, url);
 }
 
 
@@ -516,7 +518,7 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp,
                        unsigned char **fpr, size_t *fpr_len,
                        unsigned int options,
                        import_screener_t screener, void *screener_arg,
-                       int origin)
+                       int origin, const char *url)
 {
   int rc;
   iobuf_t inp;
@@ -531,7 +533,7 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp,
 
   rc = import_keys_internal (ctrl, inp, NULL, 0, stats_handle,
                              fpr, fpr_len, options,
-                             screener, screener_arg, origin);
+                             screener, screener_arg, origin, url);
 
   iobuf_close (inp);
   return rc;
@@ -541,7 +543,8 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp,
 static int
 import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
        unsigned char **fpr,size_t *fpr_len, unsigned int options,
-       import_screener_t screener, void *screener_arg, int origin)
+       import_screener_t screener, void *screener_arg,
+        int origin, const char *url)
 {
   PACKET *pending_pkt = NULL;
   kbnode_t keyblock = NULL;  /* Need to initialize because gcc can't
@@ -569,7 +572,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
       if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
         rc = import_one (ctrl, keyblock,
                          stats, fpr, fpr_len, options, 0, 0,
-                         screener, screener_arg, origin);
+                         screener, screener_arg, origin, url);
       else if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
         rc = import_secret_one (ctrl, keyblock, stats,
                                 opt.batch, options, 0,
@@ -1379,11 +1382,53 @@ apply_drop_sig_filter (ctrl_t ctrl, kbnode_t keyblock, recsel_expr_t selector)
 
 
 /* Apply meta data to KEYBLOCK.  This sets the origin of the key to
- * ORIGIN.  If MERGE is true KEYBLOCK has been updated and the meta
- * data is merged and not simply inserted.  */
+ * ORIGIN and the updateurl to URL.  Note that this function is only
+ * used for a new key, that is not when we are merging keys.  */
 static gpg_error_t
-apply_meta_data (kbnode_t keyblock, int merge, int origin)
+apply_meta_data (kbnode_t keyblock, int origin, const char *url)
 {
+  kbnode_t node;
+  u32 curtime = make_timestamp ();
+
+  for (node = keyblock; node; node = node->next)
+    {
+      if (is_deleted_kbnode (node))
+        ;
+      else if (node->pkt->pkttype == PKT_PUBLIC_KEY
+               && (origin == KEYORG_WKD || origin == KEYORG_DANE))
+        {
+          /* For WKD and DANE we insert origin information also for
+           * the key but we don't record the URL because we have have
+           * no use for that: An update using a keyserver has higher
+           * precedence and will thus update this origin info.  For
+           * refresh using WKD or DANE we need to go via the User ID
+           * anyway.  Recall that we are only inserting a new key. */
+          PKT_public_key *pk = node->pkt->pkt.public_key;
+
+          pk->keyorg = origin;
+          pk->keyupdate = curtime;
+        }
+      else if (node->pkt->pkttype == PKT_USER_ID
+               && (origin == KEYORG_WKD || origin == KEYORG_DANE))
+        {
+          /* We insert origin information on a UID only when we
+           * received them via the Web Key Directory or a DANE record.
+           * The key we receive here from the WKD has been filtered to
+           * contain only the user ID as looked up in the WKD.  For a
+           * DANE origin we this should also be the case.  Thus we
+           * will see here only one user id.  */
+          PKT_user_id *uid = node->pkt->pkt.user_id;
+
+          uid->keyorg = origin;
+          uid->keyupdate = curtime;
+          if (url)
+            {
+              uid->updateurl = xtrystrdup (url);
+              if (!uid->updateurl)
+                return gpg_error_from_syserror ();
+            }
+        }
+    }
 
   return 0;
 }
@@ -1395,7 +1440,7 @@ apply_meta_data (kbnode_t keyblock, int merge, int origin)
  * the internal errorcount, so that invalid input can be detected by
  * programs which called gpg.  If SILENT is no messages are printed -
  * even most error messages are suppressed.  ORIGIN is the origin of
- * the key (0 for unknown).
+ * the key (0 for unknown) and URL the corresponding URL.
  */
 static int
 import_one (ctrl_t ctrl,
@@ -1403,7 +1448,7 @@ import_one (ctrl_t ctrl,
            unsigned char **fpr, size_t *fpr_len, unsigned int options,
            int from_sk, int silent,
             import_screener_t screener, void *screener_arg,
-            int origin)
+            int origin, const char *url)
 {
   PKT_public_key *pk;
   PKT_public_key *pk_orig = NULL;
@@ -1627,7 +1672,7 @@ import_one (ctrl_t ctrl,
        * and thus the address of KEYBLOCK won't change.  */
       if ( !(options & IMPORT_RESTORE) )
         {
-          rc = apply_meta_data (keyblock, 0, origin);
+          rc = apply_meta_data (keyblock, origin, url);
           if (rc)
             {
               log_error ("apply_meta_data failed: %s\n", gpg_strerror (rc));
@@ -2313,7 +2358,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
         the secret keys.  FIXME?  */
       import_one (ctrl, pub_keyblock, stats,
                  NULL, NULL, options, 1, for_migration,
-                  screener, screener_arg, 0);
+                  screener, screener_arg, 0, NULL);
 
       /* Fixme: We should check for an invalid keyblock and
         cancel the secret key import in this case.  */
index 37a26dc..7203d16 100644 (file)
@@ -1012,9 +1012,9 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
                           key_origin_string (uid->keyorg),
                           mk_datestr (updatestr, sizeof updatestr,
                                       uid->keyupdate),
-                          pk->updateurl? "url=":"");
-              if (pk->updateurl)
-                print_utf8_string (es_stdout, pk->updateurl);
+                          uid->updateurl? "url=":"");
+              if (uid->updateurl)
+                print_utf8_string (es_stdout, uid->updateurl);
               es_putc ('\n', es_stdout);
             }
 
index a84961e..9586448 100644 (file)
@@ -1747,7 +1747,7 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
                              (opt.keyserver_options.import_options
                               | IMPORT_NO_SECKEY),
                              keyserver_retrieval_screener, &screenerarg,
-                             0 /* FIXME? */);
+                             0 /* FIXME? */, NULL);
     }
   es_fclose (datastream);
   xfree (source);
@@ -1878,7 +1878,7 @@ keyserver_fetch (ctrl_t ctrl, strlist_t urilist, int origin)
           stats_handle = import_new_stats_handle();
           import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL,
                                  opt.keyserver_options.import_options,
-                                 NULL, NULL, origin);
+                                 NULL, NULL, origin, NULL);
 
           import_print_stats (stats_handle);
           import_release_stats_handle (stats_handle);
@@ -1945,7 +1945,7 @@ keyserver_import_cert (ctrl_t ctrl, const char *name, int dane_mode,
               if (!err)
                 err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
                                              IMPORT_NO_SECKEY,
-                                             NULL, NULL, KEYORG_DANE);
+                                             NULL, NULL, KEYORG_DANE, NULL);
               restore_import_filter (save_filt);
             }
         }
@@ -1954,7 +1954,7 @@ keyserver_import_cert (ctrl_t ctrl, const char *name, int dane_mode,
           err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
                                        (opt.keyserver_options.import_options
                                         | IMPORT_NO_SECKEY),
-                                       NULL, NULL, 0);
+                                       NULL, NULL, 0, NULL);
         }
 
       opt.no_armor=armor_status;
@@ -2043,6 +2043,7 @@ keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick,
   gpg_error_t err;
   char *mbox;
   estream_t key;
+  char *url = NULL;
 
   /* We want to work on the mbox.  That is what dirmngr will do anyway
    * and we need the mbox for the import filter anyway.  */
@@ -2055,7 +2056,7 @@ keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick,
       return err;
     }
 
-  err = gpg_dirmngr_wkd_get (ctrl, mbox, quick, &key);
+  err = gpg_dirmngr_wkd_get (ctrl, mbox, quick, &key, &url);
   if (err)
     ;
   else if (key)
@@ -2078,7 +2079,7 @@ keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick,
           if (!err)
             err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
                                          IMPORT_NO_SECKEY,
-                                         NULL, NULL, KEYORG_WKD);
+                                         NULL, NULL, KEYORG_WKD, url);
 
         }
 
@@ -2089,6 +2090,7 @@ keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick,
       key = NULL;
     }
 
+  xfree (url);
   xfree (mbox);
   return err;
 }
index e69ed9d..87417ee 100644 (file)
@@ -352,13 +352,14 @@ void            restore_import_filter (import_filter_t filt);
 gpg_error_t read_key_from_file (ctrl_t ctrl, const char *fname,
                                 kbnode_t *r_keyblock);
 void import_keys (ctrl_t ctrl, char **fnames, int nnames,
-                 import_stats_t stats_hd, unsigned int options, int origin);
+                 import_stats_t stats_hd, unsigned int options,
+                  int origin, const char *url);
 int import_keys_es_stream (ctrl_t ctrl, estream_t fp,
                            import_stats_t stats_handle,
                            unsigned char **fpr, size_t *fpr_len,
                            unsigned int options,
                            import_screener_t screener, void *screener_arg,
-                           int origin);
+                           int origin, const char *url);
 gpg_error_t import_old_secring (ctrl_t ctrl, const char *fname);
 import_stats_t import_new_stats_handle (void);
 void import_release_stats_handle (import_stats_t hd);