wks: Fix program names in the usage diagnostics.
[gnupg.git] / tools / gpg-wks-client.c
1 /* gpg-wks-client.c - A client for the Web Key Service protocols.
2  * Copyright (C) 2016 Werner Koch
3  * Copyright (C) 2016 Bundesamt für Sicherheit in der Informationstechnik
4  *
5  * This file is part of GnuPG.
6  *
7  * This file is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, see <https://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "../common/util.h"
27 #include "../common/status.h"
28 #include "../common/i18n.h"
29 #include "../common/sysutils.h"
30 #include "../common/init.h"
31 #include "../common/asshelp.h"
32 #include "../common/userids.h"
33 #include "../common/ccparray.h"
34 #include "../common/exectool.h"
35 #include "../common/mbox-util.h"
36 #include "../common/name-value.h"
37 #include "call-dirmngr.h"
38 #include "mime-maker.h"
39 #include "send-mail.h"
40 #include "gpg-wks.h"
41
42
43 /* Constants to identify the commands and options. */
44 enum cmd_and_opt_values
45   {
46     aNull = 0,
47
48     oQuiet      = 'q',
49     oVerbose    = 'v',
50     oOutput     = 'o',
51
52     oDebug      = 500,
53
54     aSupported,
55     aCheck,
56     aCreate,
57     aReceive,
58     aRead,
59
60     oGpgProgram,
61     oSend,
62     oFakeSubmissionAddr,
63     oStatusFD,
64
65     oDummy
66   };
67
68
69 /* The list of commands and options. */
70 static ARGPARSE_OPTS opts[] = {
71   ARGPARSE_group (300, ("@Commands:\n ")),
72
73   ARGPARSE_c (aSupported, "supported",
74               ("check whether provider supports WKS")),
75   ARGPARSE_c (aCheck, "check",
76               ("check whether a key is available")),
77   ARGPARSE_c (aCreate,   "create",
78               ("create a publication request")),
79   ARGPARSE_c (aReceive,   "receive",
80               ("receive a MIME confirmation request")),
81   ARGPARSE_c (aRead,      "read",
82               ("receive a plain text confirmation request")),
83
84   ARGPARSE_group (301, ("@\nOptions:\n ")),
85
86   ARGPARSE_s_n (oVerbose, "verbose", ("verbose")),
87   ARGPARSE_s_n (oQuiet, "quiet",  ("be somewhat more quiet")),
88   ARGPARSE_s_s (oDebug, "debug", "@"),
89   ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
90   ARGPARSE_s_n (oSend, "send", "send the mail using sendmail"),
91   ARGPARSE_s_s (oOutput, "output", "|FILE|write the mail to FILE"),
92   ARGPARSE_s_i (oStatusFD, "status-fd", N_("|FD|write status info to this FD")),
93
94   ARGPARSE_s_s (oFakeSubmissionAddr, "fake-submission-addr", "@"),
95
96   ARGPARSE_end ()
97 };
98
99
100 /* The list of supported debug flags.  */
101 static struct debug_flags_s debug_flags [] =
102   {
103     { DBG_MIME_VALUE   , "mime"    },
104     { DBG_PARSER_VALUE , "parser"  },
105     { DBG_CRYPTO_VALUE , "crypto"  },
106     { DBG_MEMORY_VALUE , "memory"  },
107     { DBG_MEMSTAT_VALUE, "memstat" },
108     { DBG_IPC_VALUE    , "ipc"     },
109     { DBG_EXTPROG_VALUE, "extprog" },
110     { 0, NULL }
111   };
112
113
114
115 /* Value of the option --fake-submission-addr.  */
116 const char *fake_submission_addr;
117
118
119 static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
120 static gpg_error_t command_supported (char *userid);
121 static gpg_error_t command_check (char *userid);
122 static gpg_error_t command_send (const char *fingerprint, char *userid);
123 static gpg_error_t encrypt_response (estream_t *r_output, estream_t input,
124                                      const char *addrspec,
125                                      const char *fingerprint);
126 static gpg_error_t read_confirmation_request (estream_t msg);
127 static gpg_error_t command_receive_cb (void *opaque,
128                                        const char *mediatype, estream_t fp,
129                                        unsigned int flags);
130
131
132 \f
133 /* Print usage information and provide strings for help. */
134 static const char *
135 my_strusage( int level )
136 {
137   const char *p;
138
139   switch (level)
140     {
141     case 11: p = "gpg-wks-client"; break;
142     case 12: p = "@GNUPG@"; break;
143     case 13: p = VERSION; break;
144     case 17: p = PRINTABLE_OS_NAME; break;
145     case 19: p = ("Please report bugs to <@EMAIL@>.\n"); break;
146
147     case 1:
148     case 40:
149       p = ("Usage: gpg-wks-client [command] [options] [args] (-h for help)");
150       break;
151     case 41:
152       p = ("Syntax: gpg-wks-client [command] [options] [args]\n"
153            "Client for the Web Key Service\n");
154       break;
155
156     default: p = NULL; break;
157     }
158   return p;
159 }
160
161
162 static void
163 wrong_args (const char *text)
164 {
165   es_fprintf (es_stderr, _("usage: %s [options] %s\n"), strusage (11), text);
166   exit (2);
167 }
168
169
170 \f
171 /* Command line parsing.  */
172 static enum cmd_and_opt_values
173 parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
174 {
175   enum cmd_and_opt_values cmd = 0;
176   int no_more_options = 0;
177
178   while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
179     {
180       switch (pargs->r_opt)
181         {
182         case oQuiet:     opt.quiet = 1; break;
183         case oVerbose:   opt.verbose++; break;
184         case oDebug:
185           if (parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags))
186             {
187               pargs->r_opt = ARGPARSE_INVALID_ARG;
188               pargs->err = ARGPARSE_PRINT_ERROR;
189             }
190           break;
191
192         case oGpgProgram:
193           opt.gpg_program = pargs->r.ret_str;
194           break;
195         case oSend:
196           opt.use_sendmail = 1;
197           break;
198         case oOutput:
199           opt.output = pargs->r.ret_str;
200           break;
201         case oFakeSubmissionAddr:
202           fake_submission_addr = pargs->r.ret_str;
203           break;
204         case oStatusFD:
205           wks_set_status_fd (translate_sys2libc_fd_int (pargs->r.ret_int, 1));
206           break;
207
208         case aSupported:
209         case aCreate:
210         case aReceive:
211         case aRead:
212         case aCheck:
213           cmd = pargs->r_opt;
214           break;
215
216         default: pargs->err = 2; break;
217         }
218     }
219
220   return cmd;
221 }
222
223
224 \f
225 /* gpg-wks-client main. */
226 int
227 main (int argc, char **argv)
228 {
229   gpg_error_t err;
230   ARGPARSE_ARGS pargs;
231   enum cmd_and_opt_values cmd;
232
233   gnupg_reopen_std ("gpg-wks-client");
234   set_strusage (my_strusage);
235   log_set_prefix ("gpg-wks-client", GPGRT_LOG_WITH_PREFIX);
236
237   /* Make sure that our subsystems are ready.  */
238   i18n_init();
239   init_common_subsystems (&argc, &argv);
240
241   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
242   setup_libassuan_logging (&opt.debug, NULL);
243
244   /* Parse the command line. */
245   pargs.argc  = &argc;
246   pargs.argv  = &argv;
247   pargs.flags = ARGPARSE_FLAG_KEEP;
248   cmd = parse_arguments (&pargs, opts);
249
250   if (log_get_errorcount (0))
251     exit (2);
252
253   /* Print a warning if an argument looks like an option.  */
254   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
255     {
256       int i;
257
258       for (i=0; i < argc; i++)
259         if (argv[i][0] == '-' && argv[i][1] == '-')
260           log_info (("NOTE: '%s' is not considered an option\n"), argv[i]);
261     }
262
263   /* Set defaults for non given options.  */
264   if (!opt.gpg_program)
265     opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
266
267   /* Tell call-dirmngr what options we want.  */
268   set_dirmngr_options (opt.verbose, (opt.debug & DBG_IPC_VALUE), 1);
269
270   /* Run the selected command.  */
271   switch (cmd)
272     {
273     case aSupported:
274       if (argc != 1)
275         wrong_args ("--supported USER-ID");
276       err = command_supported (argv[0]);
277       if (err && gpg_err_code (err) != GPG_ERR_FALSE)
278         log_error ("checking support failed: %s\n", gpg_strerror (err));
279       break;
280
281     case aCreate:
282       if (argc != 2)
283         wrong_args ("--create FINGERPRINT USER-ID");
284       err = command_send (argv[0], argv[1]);
285       if (err)
286         log_error ("creating request failed: %s\n", gpg_strerror (err));
287       break;
288
289     case aReceive:
290       if (argc)
291         wrong_args ("--receive < MIME-DATA");
292       err = wks_receive (es_stdin, command_receive_cb, NULL);
293       if (err)
294         log_error ("processing mail failed: %s\n", gpg_strerror (err));
295       break;
296
297     case aRead:
298       if (argc)
299         wrong_args ("--read < WKS-DATA");
300       err = read_confirmation_request (es_stdin);
301       if (err)
302         log_error ("processing mail failed: %s\n", gpg_strerror (err));
303       break;
304
305     case aCheck:
306       if (argc != 1)
307         wrong_args ("--check USER-ID");
308       err = command_check (argv[0]);
309       break;
310
311     default:
312       usage (1);
313       err = 0;
314       break;
315     }
316
317   if (err)
318     wks_write_status (STATUS_FAILURE, "- %u", err);
319   else if (log_get_errorcount (0))
320     wks_write_status (STATUS_FAILURE, "- %u", GPG_ERR_GENERAL);
321   else
322     wks_write_status (STATUS_SUCCESS, NULL);
323   return log_get_errorcount (0)? 1:0;
324 }
325
326
327 \f
328 struct get_key_status_parm_s
329 {
330   const char *fpr;
331   int found;
332   int count;
333 };
334
335 static void
336 get_key_status_cb (void *opaque, const char *keyword, char *args)
337 {
338   struct get_key_status_parm_s *parm = opaque;
339
340   /*log_debug ("%s: %s\n", keyword, args);*/
341   if (!strcmp (keyword, "EXPORTED"))
342     {
343       parm->count++;
344       if (!ascii_strcasecmp (args, parm->fpr))
345         parm->found = 1;
346     }
347 }
348
349
350 /* Get a key by fingerprint from gpg's keyring and make sure that the
351  * mail address ADDRSPEC is included in the key.  The key is returned
352  * as a new memory stream at R_KEY.
353  *
354  * Fixme: After we have implemented import and export filters for gpg
355  * this function shall only return a key with just this user id.  */
356 static gpg_error_t
357 get_key (estream_t *r_key, const char *fingerprint, const char *addrspec)
358 {
359   gpg_error_t err;
360   ccparray_t ccp;
361   const char **argv = NULL;
362   estream_t key = NULL;
363   struct get_key_status_parm_s parm;
364   char *filterexp = NULL;
365
366   memset (&parm, 0, sizeof parm);
367
368   *r_key = NULL;
369
370   key = es_fopenmem (0, "w+b");
371   if (!key)
372     {
373       err = gpg_error_from_syserror ();
374       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
375       goto leave;
376     }
377
378   /* Prefix the key with the MIME content type.  */
379   es_fputs ("Content-Type: application/pgp-keys\n"
380             "\n", key);
381
382   filterexp = es_bsprintf ("keep-uid=mbox = %s", addrspec);
383   if (!filterexp)
384     {
385       err = gpg_error_from_syserror ();
386       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
387       goto leave;
388     }
389
390   ccparray_init (&ccp, 0);
391
392   ccparray_put (&ccp, "--no-options");
393   if (!opt.verbose)
394     ccparray_put (&ccp, "--quiet");
395   else if (opt.verbose > 1)
396     ccparray_put (&ccp, "--verbose");
397   ccparray_put (&ccp, "--batch");
398   ccparray_put (&ccp, "--status-fd=2");
399   ccparray_put (&ccp, "--always-trust");
400   ccparray_put (&ccp, "--armor");
401   ccparray_put (&ccp, "--export-options=export-minimal");
402   ccparray_put (&ccp, "--export-filter");
403   ccparray_put (&ccp, filterexp);
404   ccparray_put (&ccp, "--export");
405   ccparray_put (&ccp, "--");
406   ccparray_put (&ccp, fingerprint);
407
408   ccparray_put (&ccp, NULL);
409   argv = ccparray_get (&ccp, NULL);
410   if (!argv)
411     {
412       err = gpg_error_from_syserror ();
413       goto leave;
414     }
415   parm.fpr = fingerprint;
416   err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
417                                 NULL, key,
418                                 get_key_status_cb, &parm);
419   if (!err && parm.count > 1)
420     err = gpg_error (GPG_ERR_TOO_MANY);
421   else if (!err && !parm.found)
422     err = gpg_error (GPG_ERR_NOT_FOUND);
423   if (err)
424     {
425       log_error ("export failed: %s\n", gpg_strerror (err));
426       goto leave;
427     }
428
429   es_rewind (key);
430   *r_key = key;
431   key = NULL;
432
433  leave:
434   es_fclose (key);
435   xfree (argv);
436   xfree (filterexp);
437   return err;
438 }
439
440
441 \f
442 struct decrypt_stream_parm_s
443 {
444   char *fpr;
445   char *mainfpr;
446   int  otrust;
447 };
448
449 static void
450 decrypt_stream_status_cb (void *opaque, const char *keyword, char *args)
451 {
452   struct decrypt_stream_parm_s *decinfo = opaque;
453
454   if (DBG_CRYPTO)
455     log_debug ("gpg status: %s %s\n", keyword, args);
456   if (!strcmp (keyword, "DECRYPTION_KEY") && !decinfo->fpr)
457     {
458       char *fields[3];
459
460       if (split_fields (args, fields, DIM (fields)) >= 3)
461         {
462           decinfo->fpr = xstrdup (fields[0]);
463           decinfo->mainfpr = xstrdup (fields[1]);
464           decinfo->otrust = *fields[2];
465         }
466     }
467 }
468
469 /* Decrypt the INPUT stream to a new stream which is stored at success
470  * at R_OUTPUT.  */
471 static gpg_error_t
472 decrypt_stream (estream_t *r_output, struct decrypt_stream_parm_s *decinfo,
473                 estream_t input)
474 {
475   gpg_error_t err;
476   ccparray_t ccp;
477   const char **argv;
478   estream_t output;
479
480   *r_output = NULL;
481   memset (decinfo, 0, sizeof *decinfo);
482
483   output = es_fopenmem (0, "w+b");
484   if (!output)
485     {
486       err = gpg_error_from_syserror ();
487       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
488       return err;
489     }
490
491   ccparray_init (&ccp, 0);
492
493   ccparray_put (&ccp, "--no-options");
494   /* We limit the output to 64 KiB to avoid DoS using compression
495    * tricks.  A regular client will anyway only send a minimal key;
496    * that is one w/o key signatures and attribute packets.  */
497   ccparray_put (&ccp, "--max-output=0x10000");
498   if (!opt.verbose)
499     ccparray_put (&ccp, "--quiet");
500   else if (opt.verbose > 1)
501     ccparray_put (&ccp, "--verbose");
502   ccparray_put (&ccp, "--batch");
503   ccparray_put (&ccp, "--status-fd=2");
504   ccparray_put (&ccp, "--decrypt");
505   ccparray_put (&ccp, "--");
506
507   ccparray_put (&ccp, NULL);
508   argv = ccparray_get (&ccp, NULL);
509   if (!argv)
510     {
511       err = gpg_error_from_syserror ();
512       goto leave;
513     }
514   err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
515                                 NULL, output,
516                                 decrypt_stream_status_cb, decinfo);
517   if (!err && (!decinfo->fpr || !decinfo->mainfpr || !decinfo->otrust))
518     err = gpg_error (GPG_ERR_INV_ENGINE);
519   if (err)
520     {
521       log_error ("decryption failed: %s\n", gpg_strerror (err));
522       goto leave;
523     }
524   else if (opt.verbose)
525     log_info ("decryption succeeded\n");
526
527   es_rewind (output);
528   *r_output = output;
529   output = NULL;
530
531  leave:
532   if (err)
533     {
534       xfree (decinfo->fpr);
535       xfree (decinfo->mainfpr);
536       memset (decinfo, 0, sizeof *decinfo);
537     }
538   es_fclose (output);
539   xfree (argv);
540   return err;
541 }
542
543
544
545 \f
546 /* Check whether the  provider supports the WKS protocol.  */
547 static gpg_error_t
548 command_supported (char *userid)
549 {
550   gpg_error_t err;
551   char *addrspec = NULL;
552   char *submission_to = NULL;
553
554   addrspec = mailbox_from_userid (userid);
555   if (!addrspec)
556     {
557       log_error (_("\"%s\" is not a proper mail address\n"), userid);
558       err = gpg_error (GPG_ERR_INV_USER_ID);
559       goto leave;
560     }
561
562   /* Get the submission address.  */
563   err = wkd_get_submission_address (addrspec, &submission_to);
564   if (err)
565     {
566       if (gpg_err_code (err) == GPG_ERR_NO_DATA
567           || gpg_err_code (err) == GPG_ERR_UNKNOWN_HOST)
568         {
569           if (opt.verbose)
570             log_info ("provider for '%s' does NOT support WKS (%s)\n",
571                       addrspec, gpg_strerror (err));
572           err = gpg_error (GPG_ERR_FALSE);
573           log_inc_errorcount ();
574         }
575       goto leave;
576     }
577   if (opt.verbose)
578     log_info ("provider for '%s' supports WKS\n", addrspec);
579
580  leave:
581   xfree (submission_to);
582   xfree (addrspec);
583   return err;
584 }
585
586
587 \f
588 /* Check whether the key for USERID is available in the WKD.  */
589 static gpg_error_t
590 command_check (char *userid)
591 {
592   gpg_error_t err;
593   char *addrspec = NULL;
594   estream_t key = NULL;
595   char *fpr = NULL;
596   strlist_t mboxes = NULL;
597   strlist_t sl;
598   int found = 0;
599
600   addrspec = mailbox_from_userid (userid);
601   if (!addrspec)
602     {
603       log_error (_("\"%s\" is not a proper mail address\n"), userid);
604       err = gpg_error (GPG_ERR_INV_USER_ID);
605       goto leave;
606     }
607
608   /* Get the submission address.  */
609   err = wkd_get_key (addrspec, &key);
610   switch (gpg_err_code (err))
611     {
612     case 0:
613       if (opt.verbose)
614         log_info ("public key for '%s' found via WKD\n", addrspec);
615       /* Fixme: Check that the key contains the user id.  */
616       break;
617
618     case GPG_ERR_NO_DATA: /* No such key.  */
619       if (opt.verbose)
620         log_info ("public key for '%s' NOT found via WKD\n", addrspec);
621       err = gpg_error (GPG_ERR_NO_PUBKEY);
622       log_inc_errorcount ();
623       break;
624
625     case GPG_ERR_UNKNOWN_HOST:
626       if (opt.verbose)
627         log_info ("error looking up '%s' via WKD: %s\n",
628                   addrspec, gpg_strerror (err));
629       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
630       break;
631
632     default:
633       log_error ("error looking up '%s' via WKD: %s\n",
634                  addrspec, gpg_strerror (err));
635       break;
636     }
637
638   if (err)
639     goto leave;
640
641   /* Look closer at the key.  */
642   err = wks_list_key (key, &fpr, &mboxes);
643   if (err || !fpr)
644     {
645       log_error ("error parsing key: %s\n",
646                  err? gpg_strerror (err) : "no fingerprint found");
647       err = gpg_error (GPG_ERR_NO_PUBKEY);
648       goto leave;
649     }
650
651   if (opt.verbose)
652     log_info ("fingerprint: %s\n", fpr);
653
654   for (sl = mboxes; sl; sl = sl->next)
655     {
656       if (!strcmp (sl->d, addrspec))
657         found = 1;
658       if (opt.verbose)
659         log_info ("  addr-spec: %s\n", sl->d);
660     }
661   if (!found)
662     {
663       log_error ("public key for '%s' has no user id with the mail address\n",
664                  addrspec);
665       err = gpg_error (GPG_ERR_CERT_REVOKED);
666     }
667
668  leave:
669   xfree (fpr);
670   free_strlist (mboxes);
671   es_fclose (key);
672   xfree (addrspec);
673   return err;
674 }
675
676
677 \f
678 /* Locate the key by fingerprint and userid and send a publication
679  * request.  */
680 static gpg_error_t
681 command_send (const char *fingerprint, char *userid)
682 {
683   gpg_error_t err;
684   KEYDB_SEARCH_DESC desc;
685   char *addrspec = NULL;
686   estream_t key = NULL;
687   estream_t keyenc = NULL;
688   char *submission_to = NULL;
689   mime_maker_t mime = NULL;
690   struct policy_flags_s policy;
691
692   memset (&policy, 0, sizeof policy);
693
694   if (classify_user_id (fingerprint, &desc, 1)
695       || !(desc.mode == KEYDB_SEARCH_MODE_FPR
696            || desc.mode == KEYDB_SEARCH_MODE_FPR20))
697     {
698       log_error (_("\"%s\" is not a fingerprint\n"), fingerprint);
699       err = gpg_error (GPG_ERR_INV_NAME);
700       goto leave;
701     }
702   addrspec = mailbox_from_userid (userid);
703   if (!addrspec)
704     {
705       log_error (_("\"%s\" is not a proper mail address\n"), userid);
706       err = gpg_error (GPG_ERR_INV_USER_ID);
707       goto leave;
708     }
709   err = get_key (&key, fingerprint, addrspec);
710   if (err)
711     goto leave;
712
713   /* Get the submission address.  */
714   if (fake_submission_addr)
715     {
716       submission_to = xstrdup (fake_submission_addr);
717       err = 0;
718     }
719   else
720     err = wkd_get_submission_address (addrspec, &submission_to);
721   if (err)
722     {
723       char *domain = strchr (addrspec, '@');
724       if (domain)
725         domain = domain + 1;
726       log_error (_("looking up WKS submission address for %s: %s\n"),
727                  domain ? domain : addrspec, gpg_strerror (err));
728       if (gpg_err_code (err) == GPG_ERR_NO_DATA)
729         log_error (_("this domain probably doesn't support WKS.\n"));
730       goto leave;
731     }
732   log_info ("submitting request to '%s'\n", submission_to);
733
734   /* Get the policy flags.  */
735   if (!fake_submission_addr)
736     {
737       estream_t mbuf;
738
739       err = wkd_get_policy_flags (addrspec, &mbuf);
740       if (err && gpg_err_code (err) != GPG_ERR_NO_DATA)
741         {
742           log_error ("error reading policy flags for '%s': %s\n",
743                      submission_to, gpg_strerror (err));
744           goto leave;
745         }
746       if (mbuf)
747         {
748           err = wks_parse_policy (&policy, mbuf, 1);
749           es_fclose (mbuf);
750           if (err)
751             goto leave;
752         }
753     }
754
755   if (policy.auth_submit)
756     log_info ("no confirmation required for '%s'\n", addrspec);
757
758   /* Encrypt the key part.  */
759   es_rewind (key);
760   err = encrypt_response (&keyenc, key, submission_to, fingerprint);
761   if (err)
762     goto leave;
763   es_fclose (key);
764   key = NULL;
765
766
767   /* Send the key.  */
768   err = mime_maker_new (&mime, NULL);
769   if (err)
770     goto leave;
771   err = mime_maker_add_header (mime, "From", addrspec);
772   if (err)
773     goto leave;
774   err = mime_maker_add_header (mime, "To", submission_to);
775   if (err)
776     goto leave;
777   err = mime_maker_add_header (mime, "Subject", "Key publishing request");
778   if (err)
779     goto leave;
780
781   /* Tell server which draft we support.  */
782   err = mime_maker_add_header (mime, "Wks-Draft-Version",
783                                STR2(WKS_DRAFT_VERSION));
784   if (err)
785     goto leave;
786
787   err = mime_maker_add_header (mime, "Content-Type",
788                                "multipart/encrypted; "
789                                "protocol=\"application/pgp-encrypted\"");
790   if (err)
791     goto leave;
792   err = mime_maker_add_container (mime);
793   if (err)
794     goto leave;
795
796   err = mime_maker_add_header (mime, "Content-Type",
797                                "application/pgp-encrypted");
798   if (err)
799     goto leave;
800   err = mime_maker_add_body (mime, "Version: 1\n");
801   if (err)
802     goto leave;
803   err = mime_maker_add_header (mime, "Content-Type",
804                                "application/octet-stream");
805   if (err)
806     goto leave;
807
808   err = mime_maker_add_stream (mime, &keyenc);
809   if (err)
810     goto leave;
811
812   err = wks_send_mime (mime);
813
814  leave:
815   mime_maker_release (mime);
816   xfree (submission_to);
817   es_fclose (keyenc);
818   es_fclose (key);
819   xfree (addrspec);
820   return err;
821 }
822
823
824 \f
825 static void
826 encrypt_response_status_cb (void *opaque, const char *keyword, char *args)
827 {
828   gpg_error_t *failure = opaque;
829   char *fields[2];
830
831   if (DBG_CRYPTO)
832     log_debug ("gpg status: %s %s\n", keyword, args);
833
834   if (!strcmp (keyword, "FAILURE"))
835     {
836       if (split_fields (args, fields, DIM (fields)) >= 2
837           && !strcmp (fields[0], "encrypt"))
838         *failure = strtoul (fields[1], NULL, 10);
839     }
840
841 }
842
843
844 /* Encrypt the INPUT stream to a new stream which is stored at success
845  * at R_OUTPUT.  Encryption is done for ADDRSPEC and for FINGERPRINT
846  * (so that the sent message may later be inspected by the user).  We
847  * currently retrieve that key from the WKD, DANE, or from "local".
848  * "local" is last to prefer the latest key version but use a local
849  * copy in case we are working offline.  It might be useful for the
850  * server to send the fingerprint of its encryption key - or even the
851  * entire key back.  */
852 static gpg_error_t
853 encrypt_response (estream_t *r_output, estream_t input, const char *addrspec,
854                   const char *fingerprint)
855 {
856   gpg_error_t err;
857   ccparray_t ccp;
858   const char **argv;
859   estream_t output;
860   gpg_error_t gpg_err = 0;
861
862   *r_output = NULL;
863
864   output = es_fopenmem (0, "w+b");
865   if (!output)
866     {
867       err = gpg_error_from_syserror ();
868       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
869       return err;
870     }
871
872   ccparray_init (&ccp, 0);
873
874   ccparray_put (&ccp, "--no-options");
875   if (!opt.verbose)
876     ccparray_put (&ccp, "--quiet");
877   else if (opt.verbose > 1)
878     ccparray_put (&ccp, "--verbose");
879   ccparray_put (&ccp, "--batch");
880   ccparray_put (&ccp, "--status-fd=2");
881   ccparray_put (&ccp, "--always-trust");
882   ccparray_put (&ccp, "--armor");
883   if (fake_submission_addr)
884     ccparray_put (&ccp, "--auto-key-locate=clear,local");
885   else
886     ccparray_put (&ccp, "--auto-key-locate=clear,wkd,dane,local");
887   ccparray_put (&ccp, "--recipient");
888   ccparray_put (&ccp, addrspec);
889   ccparray_put (&ccp, "--recipient");
890   ccparray_put (&ccp, fingerprint);
891   ccparray_put (&ccp, "--encrypt");
892   ccparray_put (&ccp, "--");
893
894   ccparray_put (&ccp, NULL);
895   argv = ccparray_get (&ccp, NULL);
896   if (!argv)
897     {
898       err = gpg_error_from_syserror ();
899       goto leave;
900     }
901   err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
902                                 NULL, output,
903                                 encrypt_response_status_cb, &gpg_err);
904   if (err)
905     {
906       if (gpg_err)
907         err = gpg_err;
908       log_error ("encryption failed: %s\n", gpg_strerror (err));
909       goto leave;
910     }
911
912   es_rewind (output);
913   *r_output = output;
914   output = NULL;
915
916  leave:
917   es_fclose (output);
918   xfree (argv);
919   return err;
920 }
921
922
923 static gpg_error_t
924 send_confirmation_response (const char *sender, const char *address,
925                             const char *nonce, int encrypt,
926                             const char *fingerprint)
927 {
928   gpg_error_t err;
929   estream_t body = NULL;
930   estream_t bodyenc = NULL;
931   mime_maker_t mime = NULL;
932
933   body = es_fopenmem (0, "w+b");
934   if (!body)
935     {
936       err = gpg_error_from_syserror ();
937       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
938       return err;
939     }
940
941   /* It is fine to use 8 bit encoding because that is encrypted and
942    * only our client will see it.  */
943   if (encrypt)
944     {
945       es_fputs ("Content-Type: application/vnd.gnupg.wks\n"
946                 "Content-Transfer-Encoding: 8bit\n"
947                 "\n",
948                 body);
949     }
950
951   es_fprintf (body, ("type: confirmation-response\n"
952                      "sender: %s\n"
953                      "address: %s\n"
954                      "nonce: %s\n"),
955               sender,
956               address,
957               nonce);
958
959   es_rewind (body);
960   if (encrypt)
961     {
962       err = encrypt_response (&bodyenc, body, sender, fingerprint);
963       if (err)
964         goto leave;
965       es_fclose (body);
966       body = NULL;
967     }
968
969   err = mime_maker_new (&mime, NULL);
970   if (err)
971     goto leave;
972   err = mime_maker_add_header (mime, "From", address);
973   if (err)
974     goto leave;
975   err = mime_maker_add_header (mime, "To", sender);
976   if (err)
977     goto leave;
978   err = mime_maker_add_header (mime, "Subject", "Key publication confirmation");
979   if (err)
980     goto leave;
981   err = mime_maker_add_header (mime, "Wks-Draft-Version",
982                                STR2(WKS_DRAFT_VERSION));
983   if (err)
984     goto leave;
985
986   if (encrypt)
987     {
988       err = mime_maker_add_header (mime, "Content-Type",
989                                    "multipart/encrypted; "
990                                    "protocol=\"application/pgp-encrypted\"");
991       if (err)
992         goto leave;
993       err = mime_maker_add_container (mime);
994       if (err)
995         goto leave;
996
997       err = mime_maker_add_header (mime, "Content-Type",
998                                    "application/pgp-encrypted");
999       if (err)
1000         goto leave;
1001       err = mime_maker_add_body (mime, "Version: 1\n");
1002       if (err)
1003         goto leave;
1004       err = mime_maker_add_header (mime, "Content-Type",
1005                                    "application/octet-stream");
1006       if (err)
1007         goto leave;
1008
1009       err = mime_maker_add_stream (mime, &bodyenc);
1010       if (err)
1011         goto leave;
1012     }
1013   else
1014     {
1015       err = mime_maker_add_header (mime, "Content-Type",
1016                                    "application/vnd.gnupg.wks");
1017       if (err)
1018         goto leave;
1019       err = mime_maker_add_stream (mime, &body);
1020       if (err)
1021         goto leave;
1022     }
1023
1024   err = wks_send_mime (mime);
1025
1026  leave:
1027   mime_maker_release (mime);
1028   es_fclose (bodyenc);
1029   es_fclose (body);
1030   return err;
1031 }
1032
1033
1034 /* Reply to a confirmation request.  The MSG has already been
1035  * decrypted and we only need to send the nonce back.  MAINFPR is
1036  * either NULL or the primary key fingerprint of the key used to
1037  * decrypt the request.  */
1038 static gpg_error_t
1039 process_confirmation_request (estream_t msg, const char *mainfpr)
1040 {
1041   gpg_error_t err;
1042   nvc_t nvc;
1043   nve_t item;
1044   const char *value, *sender, *address, *fingerprint, *nonce;
1045
1046   err = nvc_parse (&nvc, NULL, msg);
1047   if (err)
1048     {
1049       log_error ("parsing the WKS message failed: %s\n", gpg_strerror (err));
1050       goto leave;
1051     }
1052
1053   if (DBG_MIME)
1054     {
1055       log_debug ("request follows:\n");
1056       nvc_write (nvc, log_get_stream ());
1057     }
1058
1059   /* Check that this is a confirmation request.  */
1060   if (!((item = nvc_lookup (nvc, "type:")) && (value = nve_value (item))
1061         && !strcmp (value, "confirmation-request")))
1062     {
1063       if (item && value)
1064         log_error ("received unexpected wks message '%s'\n", value);
1065       else
1066         log_error ("received invalid wks message: %s\n", "'type' missing");
1067       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1068       goto leave;
1069     }
1070
1071   /* Get the fingerprint.  */
1072   if (!((item = nvc_lookup (nvc, "fingerprint:"))
1073         && (value = nve_value (item))
1074         && strlen (value) >= 40))
1075     {
1076       log_error ("received invalid wks message: %s\n",
1077                  "'fingerprint' missing or invalid");
1078       err = gpg_error (GPG_ERR_INV_DATA);
1079       goto leave;
1080     }
1081   fingerprint = value;
1082
1083   /* Check that the fingerprint matches the key used to decrypt the
1084    * message.  In --read mode or with the old format we don't have the
1085    * decryption key; thus we can't bail out.  */
1086   if (!mainfpr || ascii_strcasecmp (mainfpr, fingerprint))
1087     {
1088       log_info ("target fingerprint: %s\n", fingerprint);
1089       log_info ("but decrypted with: %s\n", mainfpr);
1090       log_error ("confirmation request not decrypted with target key\n");
1091       if (mainfpr)
1092         {
1093           err = gpg_error (GPG_ERR_INV_DATA);
1094           goto leave;
1095         }
1096     }
1097
1098   /* Get the address.  */
1099   if (!((item = nvc_lookup (nvc, "address:")) && (value = nve_value (item))
1100         && is_valid_mailbox (value)))
1101     {
1102       log_error ("received invalid wks message: %s\n",
1103                  "'address' missing or invalid");
1104       err = gpg_error (GPG_ERR_INV_DATA);
1105       goto leave;
1106     }
1107   address = value;
1108   /* FIXME: Check that the "address" matches the User ID we want to
1109    * publish.  */
1110
1111   /* Get the sender.  */
1112   if (!((item = nvc_lookup (nvc, "sender:")) && (value = nve_value (item))
1113         && is_valid_mailbox (value)))
1114     {
1115       log_error ("received invalid wks message: %s\n",
1116                  "'sender' missing or invalid");
1117       err = gpg_error (GPG_ERR_INV_DATA);
1118       goto leave;
1119     }
1120   sender = value;
1121   /* FIXME: Check that the "sender" matches the From: address.  */
1122
1123   /* Get the nonce.  */
1124   if (!((item = nvc_lookup (nvc, "nonce:")) && (value = nve_value (item))
1125         && strlen (value) > 16))
1126     {
1127       log_error ("received invalid wks message: %s\n",
1128                  "'nonce' missing or too short");
1129       err = gpg_error (GPG_ERR_INV_DATA);
1130       goto leave;
1131     }
1132   nonce = value;
1133
1134   /* Send the confirmation.  If no key was found, try again without
1135    * encryption.  */
1136   err = send_confirmation_response (sender, address, nonce, 1, fingerprint);
1137   if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1138     {
1139       log_info ("no encryption key found - sending response in the clear\n");
1140       err = send_confirmation_response (sender, address, nonce, 0, NULL);
1141     }
1142
1143  leave:
1144   nvc_release (nvc);
1145   return err;
1146 }
1147
1148
1149 /* Read a confirmation request and decrypt it if needed.  This
1150  * function may not be used with a mail or MIME message but only with
1151  * the actual encrypted or plaintext WKS data.  */
1152 static gpg_error_t
1153 read_confirmation_request (estream_t msg)
1154 {
1155   gpg_error_t err;
1156   int c;
1157   estream_t plaintext = NULL;
1158
1159   /* We take a really simple approach to check whether MSG is
1160    * encrypted: We know that an encrypted message is always armored
1161    * and thus starts with a few dashes.  It is even sufficient to
1162    * check for a single dash, because that can never be a proper first
1163    * WKS data octet.  We need to skip leading spaces, though. */
1164   while ((c = es_fgetc (msg)) == ' ' || c == '\t' || c == '\r' || c == '\n')
1165     ;
1166   if (c == EOF)
1167     {
1168       log_error ("can't process an empty message\n");
1169       return gpg_error (GPG_ERR_INV_DATA);
1170     }
1171   if (es_ungetc (c, msg) != c)
1172     {
1173       log_error ("error ungetting octet from message\n");
1174       return gpg_error (GPG_ERR_INTERNAL);
1175     }
1176
1177   if (c != '-')
1178     err = process_confirmation_request (msg, NULL);
1179   else
1180     {
1181       struct decrypt_stream_parm_s decinfo;
1182
1183       err = decrypt_stream (&plaintext, &decinfo, msg);
1184       if (err)
1185         log_error ("decryption failed: %s\n", gpg_strerror (err));
1186       else if (decinfo.otrust != 'u')
1187         {
1188           err = gpg_error (GPG_ERR_WRONG_SECKEY);
1189           log_error ("key used to decrypt the confirmation request"
1190                      " was not generated by us\n");
1191         }
1192       else
1193         err = process_confirmation_request (plaintext, decinfo.mainfpr);
1194       xfree (decinfo.fpr);
1195       xfree (decinfo.mainfpr);
1196     }
1197
1198   es_fclose (plaintext);
1199   return err;
1200 }
1201
1202
1203 /* Called from the MIME receiver to process the plain text data in MSG.  */
1204 static gpg_error_t
1205 command_receive_cb (void *opaque, const char *mediatype,
1206                     estream_t msg, unsigned int flags)
1207 {
1208   gpg_error_t err;
1209
1210   (void)opaque;
1211   (void)flags;
1212
1213   if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
1214     err = read_confirmation_request (msg);
1215   else
1216     {
1217       log_info ("ignoring unexpected message of type '%s'\n", mediatype);
1218       err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
1219     }
1220
1221   return err;
1222 }