* certlist.c (gpgsm_cert_use_ocsp_p): New.
[gnupg.git] / sm / call-dirmngr.c
1 /* call-dirmngr.c - communication with the dromngr 
2  *      Copyright (C) 2002, 2003 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h> 
27 #include <time.h>
28 #include <assert.h>
29 #include <ctype.h>
30
31 #include "gpgsm.h"
32 #include <gcrypt.h>
33 #include <assuan.h>
34
35 #include "i18n.h"
36 #include "keydb.h"
37
38
39 struct membuf {
40   size_t len;
41   size_t size;
42   char *buf;
43   int out_of_core;
44 };
45
46
47
48 static ASSUAN_CONTEXT dirmngr_ctx = NULL;
49 static int force_pipe_server = 0;
50
51 struct inq_certificate_parm_s {
52   ASSUAN_CONTEXT ctx;
53   ksba_cert_t cert;
54   ksba_cert_t issuer_cert;
55 };
56
57 struct isvalid_status_parm_s {
58   int seen;
59   unsigned char fpr[20];
60 };
61
62
63 struct lookup_parm_s {
64   CTRL ctrl;
65   ASSUAN_CONTEXT ctx;
66   void (*cb)(void *, ksba_cert_t);
67   void *cb_value;
68   struct membuf data;
69   int error;
70 };
71
72 struct run_command_parm_s {
73   ASSUAN_CONTEXT ctx;
74 };
75
76
77 /* A simple implementation of a dynamic buffer.  Use init_membuf() to
78    create a buffer, put_membuf to append bytes and get_membuf to
79    release and return the buffer.  Allocation errors are detected but
80    only returned at the final get_membuf(), this helps not to clutter
81    the code with out of core checks.  */
82
83 static void
84 init_membuf (struct membuf *mb, int initiallen)
85 {
86   mb->len = 0;
87   mb->size = initiallen;
88   mb->out_of_core = 0;
89   mb->buf = xtrymalloc (initiallen);
90   if (!mb->buf)
91       mb->out_of_core = 1;
92 }
93
94 static void
95 put_membuf (struct membuf *mb, const void *buf, size_t len)
96 {
97   if (mb->out_of_core)
98     return;
99
100   if (mb->len + len >= mb->size)
101     {
102       char *p;
103       
104       mb->size += len + 1024;
105       p = xtryrealloc (mb->buf, mb->size);
106       if (!p)
107         {
108           mb->out_of_core = 1;
109           return;
110         }
111       mb->buf = p;
112     }
113   memcpy (mb->buf + mb->len, buf, len);
114   mb->len += len;
115 }
116
117 static void *
118 get_membuf (struct membuf *mb, size_t *len)
119 {
120   char *p;
121
122   if (mb->out_of_core)
123     {
124       xfree (mb->buf);
125       mb->buf = NULL;
126       return NULL;
127     }
128
129   p = mb->buf;
130   *len = mb->len;
131   mb->buf = NULL;
132   mb->out_of_core = 1; /* don't allow a reuse */
133   return p;
134 }
135
136
137
138
139 \f
140 /* Try to connect to the agent via socket or fork it off and work by
141    pipes.  Handle the server's initial greeting */
142 static int
143 start_dirmngr (void)
144 {
145   int rc;
146   char *infostr, *p;
147   ASSUAN_CONTEXT ctx;
148
149   if (dirmngr_ctx)
150     return 0; /* fixme: We need a context for each thread or serialize
151                  the access to the dirmngr */
152   /* Note: if you change this to multiple connections, you also need
153      to take care of the implicit option sending caching. */
154
155   infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
156   if (!infostr || !*infostr)
157     {
158       const char *pgmname;
159       const char *argv[3];
160       int no_close_list[3];
161       int i;
162
163       if (opt.verbose)
164         log_info (_("no running dirmngr - starting one\n"));
165       
166       if (fflush (NULL))
167         {
168           gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
169           log_error ("error flushing pending output: %s\n", strerror (errno));
170           return tmperr;
171         }
172
173       if (!opt.dirmngr_program || !*opt.dirmngr_program)
174         opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR;
175       if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
176         pgmname = opt.dirmngr_program;
177       else
178         pgmname++;
179
180       argv[0] = pgmname;
181       argv[1] = "--server";
182       argv[2] = NULL;
183
184       i=0;
185       if (log_get_fd () != -1)
186         no_close_list[i++] = log_get_fd ();
187       no_close_list[i++] = fileno (stderr);
188       no_close_list[i] = -1;
189
190       /* connect to the agent and perform initial handshaking */
191       rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, (char**)argv,
192                                 no_close_list);
193     }
194   else
195     {
196       int prot;
197       int pid;
198
199       infostr = xstrdup (infostr);
200       if ( !(p = strchr (infostr, ':')) || p == infostr)
201         {
202           log_error (_("malformed DIRMNGR_INFO environment variable\n"));
203           xfree (infostr);
204           force_pipe_server = 1;
205           return start_dirmngr ();
206         }
207       *p++ = 0;
208       pid = atoi (p);
209       while (*p && *p != ':')
210         p++;
211       prot = *p? atoi (p+1) : 0;
212       if (prot != 1)
213         {
214           log_error (_("dirmngr protocol version %d is not supported\n"),
215                      prot);
216           xfree (infostr);
217           force_pipe_server = 1;
218           return start_dirmngr ();
219         }
220
221       rc = assuan_socket_connect (&ctx, infostr, pid);
222       xfree (infostr);
223       if (rc == ASSUAN_Connect_Failed)
224         {
225           log_error (_("can't connect to the dirmngr - trying fall back\n"));
226           force_pipe_server = 1;
227           return start_dirmngr ();
228         }
229     }
230
231   if (rc)
232     {
233       log_error ("can't connect to the dirmngr: %s\n", assuan_strerror (rc));
234       return gpg_error (GPG_ERR_NO_DIRMNGR);
235     }
236   dirmngr_ctx = ctx;
237
238   if (DBG_ASSUAN)
239     log_debug ("connection to dirmngr established\n");
240   return 0;
241 }
242
243
244 \f
245 /* Handle a SENDCERT inquiry. */
246 static AssuanError
247 inq_certificate (void *opaque, const char *line)
248 {
249   struct inq_certificate_parm_s *parm = opaque;
250   AssuanError rc;
251   const unsigned char *der;
252   size_t derlen;
253   int issuer_mode = 0;
254
255   if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
256     {
257       line += 8;
258     }
259   else if (!strncmp (line, "SENDISSUERCERT", 14)
260            && (line[14] == ' ' || !line[14]))
261     {
262       line += 14;
263       issuer_mode = 1;
264     }
265   else
266     {
267       log_error ("unsupported inquiry `%s'\n", line);
268       return ASSUAN_Inquire_Unknown;
269     }
270
271   if (!*line)
272     { /* Send the current certificate. */
273       der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
274                                  &derlen);
275       if (!der)
276         rc = ASSUAN_Inquire_Error;
277       else
278         rc = assuan_send_data (parm->ctx, der, derlen);
279     }
280   else if (issuer_mode)
281     {
282       log_error ("sending specific issuer certificate back "
283                  "is not yet implemented\n");
284       rc = ASSUAN_Inquire_Error;
285     }
286   else 
287     { /* Send the given certificate. */
288       int err;
289       ksba_cert_t cert;
290
291
292       err = gpgsm_find_cert (line, &cert);
293       if (err)
294         {
295           log_error ("certificate not found: %s\n", gpg_strerror (err));
296           rc = ASSUAN_Inquire_Error;
297         }
298       else
299         {
300           der = ksba_cert_get_image (cert, &derlen);
301           if (!der)
302             rc = ASSUAN_Inquire_Error;
303           else
304             rc = assuan_send_data (parm->ctx, der, derlen);
305           ksba_cert_release (cert);
306         }
307     }
308
309   return rc; 
310 }
311
312
313 /* Take a 20 byte hexencoded string and put it into the the provided
314    20 byte buffer FPR in binary format. */
315 static int
316 unhexify_fpr (const char *hexstr, unsigned char *fpr)
317 {
318   const char *s;
319   int n;
320
321   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
322     ;
323   if (*s || (n != 40))
324     return 0; /* no fingerprint (invalid or wrong length). */
325   n /= 2;
326   for (s=hexstr, n=0; *s; s += 2, n++)
327     fpr[n] = xtoi_2 (s);
328   return 1; /* okay */
329 }
330
331
332 static assuan_error_t
333 isvalid_status_cb (void *opaque, const char *line)
334 {
335   struct isvalid_status_parm_s *parm = opaque;
336
337   if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24)
338       && (line[24]==' ' || !line[24]))
339     {
340       parm->seen++;
341       if (!line[24] || !unhexify_fpr (line+25, parm->fpr))
342         parm->seen++; /* Bumb it to indicate an error. */
343     }
344   return 0;
345 }
346
347
348
349 \f
350 /* Call the directory manager to check whether the certificate is valid
351    Returns 0 for valid or usually one of the errors:
352
353   GPG_ERR_CERTIFICATE_REVOKED
354   GPG_ERR_NO_CRL_KNOWN
355   GPG_ERR_CRL_TOO_OLD
356
357   With USE_OCSP set to true, the dirmngr is asked to do an OCSP
358   request first.
359  */
360 int
361 gpgsm_dirmngr_isvalid (ctrl_t ctrl,
362                        ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
363 {
364   static int did_options;
365   int rc;
366   char *certid;
367   char line[ASSUAN_LINELENGTH];
368   struct inq_certificate_parm_s parm;
369   struct isvalid_status_parm_s stparm;
370
371
372   rc = start_dirmngr ();
373   if (rc)
374     return rc;
375
376   if (use_ocsp)
377     {
378       certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
379     }
380   else
381     {
382       certid = gpgsm_get_certid (cert);
383       if (!certid)
384         {
385           log_error ("error getting the certificate ID\n");
386           return gpg_error (GPG_ERR_GENERAL);
387         }
388     }
389
390   if (opt.verbose > 1)
391     {
392       char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
393       log_info ("asking dirmngr about %s%s\n", fpr,
394                 use_ocsp? " (using OCSP)":"");
395       xfree (fpr);
396     }
397
398   parm.ctx = dirmngr_ctx;
399   parm.cert = cert;
400   parm.issuer_cert = issuer_cert;
401
402   stparm.seen = 0;
403   memset (stparm.fpr, 0, 20);
404
405   /* FIXME: If --disable-crl-checks has been set, we should pass an
406      option to dirmngr, so that no fallback CRL check is done after an
407      ocsp check. */
408
409   /* It is sufficient to send the options only once because we have
410      one connection per process only. */
411   if (!did_options)
412     {
413       if (opt.force_crl_refresh)
414         assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
415                          NULL, NULL, NULL, NULL, NULL, NULL);
416       did_options = 1;
417     }
418   snprintf (line, DIM(line)-1, "ISVALID %s", certid);
419   line[DIM(line)-1] = 0;
420   xfree (certid);
421
422   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
423                         inq_certificate, &parm,
424                         isvalid_status_cb, &stparm);
425   if (opt.verbose > 1)
426     log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
427   rc = map_assuan_err (rc);
428
429   if (!rc && stparm.seen)
430     {
431       /* Need to also check the certificate validity. */
432       if (stparm.seen != 1)
433         {
434           log_error ("communication problem with dirmngr detected\n");
435           rc = gpg_error (GPG_ERR_INV_CRL);
436         }
437       else
438         {
439           KEYDB_HANDLE kh;
440           ksba_cert_t rspcert = NULL;
441
442           /* Fixme: First try to get the certificate from the
443              dirmngr's cache - it should be there. */
444           kh = keydb_new (0);
445           if (!kh)
446             rc = gpg_error (GPG_ERR_ENOMEM);
447           if (!rc)
448             rc = keydb_search_fpr (kh, stparm.fpr);
449           if (!rc)
450             rc = keydb_get_cert (kh, &rspcert);
451           if (rc)
452             {
453               log_error ("unable to find the certificate used "
454                          "by the dirmngr: %s\n", gpg_strerror (rc));
455               rc = gpg_error (GPG_ERR_INV_CRL);
456             }
457           keydb_release (kh);
458
459           if (!rc)
460             {
461               rc = gpgsm_cert_use_ocsp_p (rspcert);
462               if (rc)
463                 rc = gpg_error (GPG_ERR_INV_CRL);
464               else
465                 {
466                   /* Note, the flag = 1: This avoids checking this
467                      certificate over and over again. */
468                   rc = gpgsm_validate_chain (ctrl, rspcert, NULL, 0, NULL, 1);
469                   if (rc)
470                     {
471                       log_error ("invalid certificate used for CRL/OCSP: %s\n",
472                                  gpg_strerror (rc));
473                       rc = gpg_error (GPG_ERR_INV_CRL);
474                     }
475                 }
476             }
477           ksba_cert_release (rspcert);
478         }
479     }
480   return rc;
481 }
482
483
484 \f
485 /* Lookup helpers*/
486 static AssuanError
487 lookup_cb (void *opaque, const void *buffer, size_t length)
488 {
489   struct lookup_parm_s *parm = opaque;
490   size_t len;
491   char *buf;
492   ksba_cert_t cert;
493   int rc;
494
495   if (parm->error)
496     return 0;
497
498   if (buffer)
499     {
500       put_membuf (&parm->data, buffer, length);
501       return 0;
502     }
503   /* END encountered - process what we have */
504   buf = get_membuf (&parm->data, &len);
505   if (!buf)
506     {
507       parm->error = gpg_error (GPG_ERR_ENOMEM);
508       return 0;
509     }
510
511   rc = ksba_cert_new (&cert);
512   if (rc)
513     {
514       parm->error = rc;
515       return 0;
516     }
517   rc = ksba_cert_init_from_mem (cert, buf, len);
518   if (rc)
519     {
520       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
521     }
522   else
523     {
524       parm->cb (parm->cb_value, cert);
525     }
526
527   ksba_cert_release (cert);
528   init_membuf (&parm->data, 4096);
529   return 0;
530 }
531
532 /* Return a properly escaped pattern from NAMES.  The only error
533    return is NULL to indicate a malloc failure. */
534 static char *
535 pattern_from_strlist (STRLIST names)
536 {
537   STRLIST sl;
538   int n;
539   const char *s;
540   char *pattern, *p;
541
542   for (n=0, sl=names; sl; sl = sl->next)
543     {
544       for (s=sl->d; *s; s++, n++)
545         {
546           if (*s == '%' || *s == ' ' || *s == '+')
547             n += 2;
548         }
549       n++;
550     }
551
552   p = pattern = xtrymalloc (n+1);
553   if (!pattern)
554     return NULL;
555
556   for (n=0, sl=names; sl; sl = sl->next)
557     {
558       for (s=sl->d; *s; s++)
559         {
560           switch (*s)
561             {
562             case '%':
563               *p++ = '%';
564               *p++ = '2';
565               *p++ = '5';
566               break;
567             case ' ':
568               *p++ = '%';
569               *p++ = '2';
570               *p++ = '0';
571               break;
572             case '+':
573               *p++ = '%';
574               *p++ = '2';
575               *p++ = 'B';
576               break;
577             default:
578               *p++ = *s;
579               break;
580             }
581         }
582       *p++ = ' ';
583     }
584   if (p == pattern)
585     *pattern = 0; /* is empty */
586   else
587     p[-1] = '\0'; /* remove trailing blank */
588   
589   return pattern;
590 }
591
592 static AssuanError
593 lookup_status_cb (void *opaque, const char *line)
594 {
595   struct lookup_parm_s *parm = opaque;
596
597   if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
598     {
599       if (parm->ctrl)
600         {
601           for (line +=9; *line == ' '; line++)
602             ;
603           gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
604         }
605     }
606   return 0;
607 }
608
609
610 /* Run the Directroy Managers lookup command using the pattern
611    compiled from the strings given in NAMES.  The caller must provide
612    the callback CB which will be passed cert by cert.  Note that CTRL
613    is optional. */
614 int 
615 gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names,
616                       void (*cb)(void*, ksba_cert_t), void *cb_value)
617
618   int rc;
619   char *pattern;
620   char line[ASSUAN_LINELENGTH];
621   struct lookup_parm_s parm;
622   size_t len;
623
624   rc = start_dirmngr ();
625   if (rc)
626     return rc;
627
628   pattern = pattern_from_strlist (names);
629   if (!pattern)
630     return OUT_OF_CORE (errno);
631   snprintf (line, DIM(line)-1, "LOOKUP %s", pattern);
632   line[DIM(line)-1] = 0;
633   xfree (pattern);
634
635   parm.ctrl = ctrl;
636   parm.ctx = dirmngr_ctx;
637   parm.cb = cb;
638   parm.cb_value = cb_value;
639   parm.error = 0;
640   init_membuf (&parm.data, 4096);
641
642   rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm,
643                         NULL, NULL, lookup_status_cb, &parm);
644   xfree (get_membuf (&parm.data, &len));
645   if (rc)
646     return map_assuan_err (rc);
647   return parm.error;
648 }
649
650
651 \f
652 /* Run Command helpers*/
653
654 /* Fairly simple callback to write all output of dirmngr to stdout. */
655 static AssuanError
656 run_command_cb (void *opaque, const void *buffer, size_t length)
657 {
658   if (buffer)
659     {
660       if ( fwrite (buffer, length, 1, stdout) != 1 )
661         log_error ("error writing to stdout: %s\n", strerror (errno));
662     }
663   return 0;
664 }
665
666 /* Handle inquiries from the dirmngr COMMAND. */
667 static AssuanError
668 run_command_inq_cb (void *opaque, const char *line)
669 {
670   struct run_command_parm_s *parm = opaque;
671   AssuanError rc = 0;
672
673   if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
674     { /* send the given certificate */
675       int err;
676       ksba_cert_t cert;
677       const unsigned char *der;
678       size_t derlen;
679
680       line += 8;
681       if (!*line)
682         return ASSUAN_Inquire_Error;
683
684       err = gpgsm_find_cert (line, &cert);
685       if (err)
686         {
687           log_error ("certificate not found: %s\n", gpg_strerror (err));
688           rc = ASSUAN_Inquire_Error;
689         }
690       else
691         {
692           der = ksba_cert_get_image (cert, &derlen);
693           if (!der)
694             rc = ASSUAN_Inquire_Error;
695           else
696             rc = assuan_send_data (parm->ctx, der, derlen);
697           ksba_cert_release (cert);
698         }
699     }
700   else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
701     { /* Simply show the message given in the argument. */
702       line += 9;
703       log_info ("dirmngr: %s\n", line);
704     }
705   else
706     {
707       log_error ("unsupported inquiry `%s'\n", line);
708       rc = ASSUAN_Inquire_Unknown;
709     }
710
711   return rc; 
712 }
713
714 static AssuanError
715 run_command_status_cb (void *opaque, const char *line)
716 {
717   if (opt.verbose)
718     {
719       log_info ("dirmngr status: %s\n", line);
720     }
721   return 0;
722 }
723
724
725
726 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
727    to stdout.  A couple of inquiries are defined (see above).  ARGC
728    arguments in ARGV are given to the Dirmngr.  Spaces, plus and
729    percent characters within the argument strings are percent escaped
730    so that blanks can act as delimiters. */
731 int
732 gpgsm_dirmngr_run_command (CTRL ctrl, const char *command,
733                            int argc, char **argv)
734
735   int rc;
736   int i;
737   const char *s;
738   char *line, *p;
739   size_t len;
740   struct run_command_parm_s parm;
741
742   rc = start_dirmngr ();
743   if (rc)
744     return rc;
745
746   parm.ctx = dirmngr_ctx;
747
748   len = strlen (command) + 1;
749   for (i=0; i < argc; i++)
750     len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
751   line = xtrymalloc (len);
752   if (!line)
753     return OUT_OF_CORE (errno);
754
755   p = stpcpy (line, command);
756   for (i=0; i < argc; i++)
757     {
758       *p++ = ' ';
759       for (s=argv[i]; *s; s++)
760         {
761           if (!isascii (*s))
762             *p++ = *s;
763           else if (*s == ' ')
764             *p++ = '+';
765           else if (!isprint (*s) || *s == '+')
766             {
767               sprintf (p, "%%%02X", *s);
768               p += 3;
769             }
770           else
771             *p++ = *s;
772         }
773     }
774   *p = 0;
775
776   rc = assuan_transact (dirmngr_ctx, line,
777                         run_command_cb, NULL,
778                         run_command_inq_cb, &parm,
779                         run_command_status_cb, NULL);
780   xfree (line);
781   log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
782   return map_assuan_err (rc);
783 }