wks: New option --check for gpg-wks-client.
authorWerner Koch <wk@gnupg.org>
Thu, 8 Dec 2016 15:57:21 +0000 (16:57 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 8 Dec 2016 15:59:12 +0000 (16:59 +0100)
* tools/call-dirmngr.c (wkd_get_key): New.
* tools/gpg-wks-client.c (aCheck): New constant.
(opts): New option "--check".
(main): Call command_check.
(command_check): New.
--

GnuPG-bug-id: 2866
Signed-off-by: Werner Koch <wk@gnupg.org>
tools/call-dirmngr.c
tools/call-dirmngr.h
tools/gpg-wks-client.c

index c5ee244..51f1fa1 100644 (file)
@@ -258,3 +258,55 @@ wkd_get_policy_flags (const char *addrspec, estream_t *r_buffer)
   assuan_release (ctx);
   return err;
 }
+
+
+/* Ask the dirmngr for the key for ADDRSPEC.  On success a stream with
+ * the key is stored at R_KEY.  */
+gpg_error_t
+wkd_get_key (const char *addrspec, estream_t *r_key)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+  struct wkd_get_parm_s parm;
+  char *line = NULL;
+
+  memset (&parm, 0, sizeof parm);
+  *r_key = NULL;
+
+  err = connect_dirmngr (&ctx);
+  if (err)
+    return err;
+
+  line = es_bsprintf ("WKD_GET -- %s", addrspec);
+  if (!line)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  if (strlen (line) + 2 >= ASSUAN_LINELENGTH)
+    {
+      err = gpg_error (GPG_ERR_TOO_LARGE);
+      goto leave;
+    }
+
+  parm.memfp = es_fopenmem (0, "rwb");
+  if (!parm.memfp)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = assuan_transact (ctx, line, wkd_get_data_cb, &parm,
+                         NULL, NULL, wkd_get_status_cb, &parm);
+  if (err)
+    goto leave;
+
+  es_rewind (parm.memfp);
+  *r_key = parm.memfp;
+  parm.memfp = NULL;
+
+ leave:
+  es_fclose (parm.memfp);
+  xfree (line);
+  assuan_release (ctx);
+  return err;
+}
index 83ebd2c..32486b1 100644 (file)
@@ -25,5 +25,7 @@ gpg_error_t wkd_get_submission_address (const char *addrspec,
                                         char **r_addrspec);
 gpg_error_t wkd_get_policy_flags (const char *addrspec, estream_t *r_buffer);
 
+gpg_error_t wkd_get_key (const char *addrspec, estream_t *r_key);
+
 
 #endif /*GNUPG_TOOLS_CALL_DIRMNGR_H*/
index 9bf5403..1a53f39 100644 (file)
@@ -50,6 +50,7 @@ enum cmd_and_opt_values
     oDebug      = 500,
 
     aSupported,
+    aCheck,
     aCreate,
     aReceive,
     aRead,
@@ -68,6 +69,8 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_c (aSupported, "supported",
               ("check whether provider supports WKS")),
+  ARGPARSE_c (aCheck, "check",
+              ("check whether a key is available")),
   ARGPARSE_c (aCreate,   "create",
               ("create a publication request")),
   ARGPARSE_c (aReceive,   "receive",
@@ -111,6 +114,7 @@ const char *fake_submission_addr;
 
 static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
 static gpg_error_t command_supported (char *userid);
+static gpg_error_t command_check (char *userid);
 static gpg_error_t command_send (const char *fingerprint, char *userid);
 static gpg_error_t encrypt_response (estream_t *r_output, estream_t input,
                                      const char *addrspec,
@@ -198,6 +202,7 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
        case aCreate:
        case aReceive:
        case aRead:
+        case aCheck:
           cmd = pargs->r_opt;
           break;
 
@@ -290,6 +295,12 @@ main (int argc, char **argv)
         log_error ("processing mail failed: %s\n", gpg_strerror (err));
       break;
 
+    case aCheck:
+      if (argc != 1)
+        wrong_args ("--check USER-ID");
+      command_check (argv[0]);
+      break;
+
     default:
       usage (1);
       break;
@@ -532,6 +543,96 @@ command_supported (char *userid)
 
 
 \f
+/* Check whether the key for USERID is available in the WKD.  */
+static gpg_error_t
+command_check (char *userid)
+{
+  gpg_error_t err;
+  char *addrspec = NULL;
+  estream_t key = NULL;
+  char *fpr = NULL;
+  strlist_t mboxes = NULL;
+  strlist_t sl;
+  int found = 0;
+
+  addrspec = mailbox_from_userid (userid);
+  if (!addrspec)
+    {
+      log_error (_("\"%s\" is not a proper mail address\n"), userid);
+      err = gpg_error (GPG_ERR_INV_USER_ID);
+      goto leave;
+    }
+
+  /* Get the submission address.  */
+  err = wkd_get_key (addrspec, &key);
+  switch (gpg_err_code (err))
+    {
+    case 0:
+      if (opt.verbose)
+        log_info ("public key for '%s' found via WKD\n", addrspec);
+      /* Fixme: Check that the key contains the user id.  */
+      break;
+
+    case GPG_ERR_NO_DATA: /* No such key.  */
+      if (opt.verbose)
+        log_info ("public key for '%s' NOT found via WKD\n", addrspec);
+      err = gpg_error (GPG_ERR_NO_PUBKEY);
+      log_inc_errorcount ();
+      break;
+
+    case GPG_ERR_UNKNOWN_HOST:
+      if (opt.verbose)
+        log_info ("error looking up '%s' via WKD: %s\n",
+                  addrspec, gpg_strerror (err));
+      err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+      break;
+
+    default:
+      log_error ("error looking up '%s' via WKD: %s\n",
+                 addrspec, gpg_strerror (err));
+      break;
+    }
+
+  if (err)
+    goto leave;
+
+  /* Look closer at the key.  */
+  err = wks_list_key (key, &fpr, &mboxes);
+  if (err || !fpr)
+    {
+      log_error ("error parsing key: %s\n",
+                 err? gpg_strerror (err) : "no fingerprint found");
+      err = gpg_error (GPG_ERR_NO_PUBKEY);
+      goto leave;
+    }
+
+  if (opt.verbose)
+    log_info ("fingerprint: %s\n", fpr);
+
+  for (sl = mboxes; sl; sl = sl->next)
+    {
+      if (!strcmp (sl->d, addrspec))
+        found = 1;
+      if (opt.verbose)
+        log_info ("  addr-spec: %s\n", sl->d);
+    }
+  if (!found)
+    {
+      log_error ("public key for '%s' has no user id with the mail address\n",
+                 addrspec);
+      err = gpg_error (GPG_ERR_CERT_REVOKED);
+    }
+
+ leave:
+  xfree (fpr);
+  free_strlist (mboxes);
+  es_fclose (key);
+  xfree (addrspec);
+  return err;
+}
+
+
+\f
 /* Locate the key by fingerprint and userid and send a publication
  * request.  */
 static gpg_error_t